Compare commits
merge into: Leadfyy.co:dev
Leadfyy.co:ccb_pay
Leadfyy.co:ccb_pay2
Leadfyy.co:dev
Leadfyy.co:master
Leadfyy.co:sf_express
pull from: Leadfyy.co:ccb_pay2
Leadfyy.co:ccb_pay
Leadfyy.co:ccb_pay2
Leadfyy.co:dev
Leadfyy.co:master
Leadfyy.co:sf_express
24 Commits
20 changed files with 1898 additions and 33 deletions
-
1.gitignore
-
79MySQL_change.sql
-
218app/Controller/v3/CcbNotifyController.php
-
39app/Controller/v3/OrderOnlineController.php
-
223app/Controller/v3/SfExpressController.php
-
8app/Controller/v3/UserAddressController.php
-
12app/JsonRpc/OrderService.php
-
65app/Model/v3/CcbPayment.php
-
22app/Model/v3/Goods.php
-
22app/Model/v3/GoodsActivity.php
-
14app/Model/v3/SfExpressOrder.php
-
642app/Service/v3/CcbPaymentService.php
-
115app/Service/v3/Implementations/OrderOnlineService.php
-
63app/Service/v3/Implementations/UserAddressService.php
-
2app/Service/v3/Interfaces/UserAddressServiceInterface.php
-
262app/Service/v3/SfExpress.php
-
19config/autoload/ccb.php
-
22config/routes.php
-
100test/Cases/CCBTest.php
-
3小程序修改
@ -0,0 +1,79 @@ |
|||
# 2022-04-09 14:57 |
|||
ALTER TABLE `lanzu_order_main` |
|||
CHANGE COLUMN `shipping_type` `shipping_type` TINYINT(1) NOT NULL DEFAULT '1' COMMENT '配送方式:1服务站配送,2达达配送,3自提,4顺丰配送' AFTER `global_order_id`, |
|||
CHANGE COLUMN `delivery_time_note` `delivery_time_note` VARCHAR(100) NULL DEFAULT '' COMMENT '客户期望送达时间' COLLATE 'utf8mb4_general_ci' AFTER `shipping_name`; |
|||
|
|||
# 2022-04-11 23:50 |
|||
ALTER TABLE `lanzu_goods` |
|||
ADD COLUMN `weight` INT(11) NOT NULL DEFAULT '0' COMMENT '产品毛重,用于计算顺丰运费' AFTER `goods_unit`; |
|||
ALTER TABLE `lanzu_goods_activity` |
|||
ADD COLUMN `weight` INT(11) NOT NULL DEFAULT '0' COMMENT '产品毛重,用于计算顺丰运费' AFTER `goods_unit`; |
|||
|
|||
# 2022-04-17 23:41 |
|||
ALTER TABLE `lanzu_order_goods` |
|||
ADD COLUMN `weight` INT NULL DEFAULT 0 COMMENT '一件商品的重量(多个需要*number),单位:克' AFTER `note`; |
|||
|
|||
|
|||
# 顺丰订单记录 |
|||
CREATE TABLE `lanzu_sf_express_orders` ( |
|||
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, |
|||
`shop_order_id` BIGINT(20) NOT NULL COMMENT '商户订单号,即对应lanzu_order_main的global_order_id', |
|||
`sf_order_id` VARCHAR(50) NOT NULL COMMENT '顺丰订单号' COLLATE 'utf8mb4_unicode_ci', |
|||
`sf_bill_id` VARCHAR(100) NOT NULL DEFAULT '' COMMENT '顺丰运单号' COLLATE 'utf8mb4_unicode_ci', |
|||
`total_price` INT(10) UNSIGNED NOT NULL DEFAULT '0' COMMENT '配送费总额,单位:分', |
|||
`delivery_distance_meter` INT(10) UNSIGNED NOT NULL DEFAULT '0' COMMENT '顺丰返回的配送距离,单位:米', |
|||
`weight_gram` INT(10) UNSIGNED NOT NULL DEFAULT '0' COMMENT '商品重量,单位:克', |
|||
`start_time` INT(10) UNSIGNED NOT NULL DEFAULT '0' COMMENT '起送时间', |
|||
`expect_time` INT(10) UNSIGNED NOT NULL DEFAULT '0' COMMENT '预计送达时间', |
|||
`total_pay_money` INT(10) UNSIGNED NOT NULL DEFAULT '0' COMMENT '支付费用,单位:分', |
|||
`real_pay_money` INT(10) UNSIGNED NOT NULL DEFAULT '0' COMMENT '实际支付金额,单位:分(实际支付金额=总金额-优惠券总金额)', |
|||
`created_at` INT(10) UNSIGNED NULL DEFAULT NULL, |
|||
`updated_at` INT(10) UNSIGNED NULL DEFAULT NULL, |
|||
PRIMARY KEY (`id`) USING BTREE, |
|||
UNIQUE INDEX `shop_order_id` (`shop_order_id`) USING BTREE |
|||
) |
|||
COMMENT='顺丰同城订单记录' |
|||
COLLATE='utf8mb4_unicode_ci' |
|||
ENGINE=InnoDB; |
|||
|
|||
|
|||
|
|||
# 2022-8-21 12:25:35 门店表增加建行商户编号 |
|||
ALTER TABLE `lanzu_store` ADD `ccb_merchant_id` VARCHAR(40) NOT NULL DEFAULT '' COMMENT '建行商户编号' AFTER `cash_code_img`; |
|||
|
|||
# 2022-8-21 13:57:15 主订单表增加建行支付类型,增加是否已分润字段 |
|||
ALTER TABLE `lanzu_order_main` |
|||
CHANGE `pay_type` `pay_type` INT(11) NOT NULL DEFAULT '1' COMMENT '1.微信支付2.余额支付3.积分支付4.货到付款5.建行支付', |
|||
ADD `is_proft_sharing` TINYINT NOT NULL DEFAULT '0' COMMENT '是否已分润:0否,1是' AFTER `pay_time`; |
|||
|
|||
# 2022-8-21 15:38:35 建行支付订单表 |
|||
CREATE TABLE `lanzu_ccb_payment` ( |
|||
`id` bigint(20) NOT NULL AUTO_INCREMENT, |
|||
`order_main_id` bigint(20) NOT NULL COMMENT '主表订单id', |
|||
`main_ordr_no` varchar(50) CHARACTER SET utf8mb4 NOT NULL COMMENT '主订单编号', |
|||
`pymd_cd` char(2) CHARACTER SET utf8mb4 NOT NULL COMMENT '支付方式:03移动端H5页面,05微信小程序', |
|||
`clrg_dt` varchar(8) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '确认收货日期', |
|||
`sub_appid` varchar(50) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '小程序的appid', |
|||
`sub_openid` varchar(50) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '用户openid', |
|||
`py_ordr_tpcd` char(2) CHARACTER SET utf8mb4 NOT NULL COMMENT '订单类型:04普通订单', |
|||
`ordr_tamt` decimal(19,2) NOT NULL COMMENT '订单总金额', |
|||
`txn_tamt` decimal(19,2) NOT NULL COMMENT '消费者实付总金额', |
|||
`orderlist` json NOT NULL COMMENT '子订单列表(分账明细)', |
|||
`py_trn_no` varchar(50) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '银行支付流水号', |
|||
`prim_ordr_no` varchar(50) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '银行订单编号', |
|||
`ordr_gen_tm` char(14) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '订单生成时间', |
|||
`cshdk_url` varchar(300) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT 'H5收银台URL', |
|||
`rtn_par_data` json DEFAULT NULL COMMENT '小程序支付参数', |
|||
`ordr_stcd` varchar(2) CHARACTER SET utf8mb4 NOT NULL DEFAULT '0' COMMENT '主订单状态:0-初始 1-待支付 2-支付成功3-支付失败 4-全额退款 5-部分退款 6-订单失效 7-待退款', |
|||
`rtn_orderlist` json DEFAULT NULL COMMENT '返回的子订单列表', |
|||
`pay_time` varchar(14) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '支付时间', |
|||
`pay_type` varchar(20) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '支付方式', |
|||
`pay_channel` varchar(50) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '支付渠道', |
|||
`debit_credit_type` varchar(20) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '借贷记标识', |
|||
`created_at` timestamp NULL DEFAULT NULL COMMENT '创建时间', |
|||
`updated_at` timestamp NULL DEFAULT NULL COMMENT '更新时间', |
|||
PRIMARY KEY (`id`), |
|||
UNIQUE KEY `main_ordr_no` (`main_ordr_no`), |
|||
KEY `order_main_id` (`order_main_id`) |
|||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='建行支付订单'; |
|||
|
|||
@ -0,0 +1,218 @@ |
|||
<?php |
|||
|
|||
namespace App\Controller\v3; |
|||
|
|||
use App\Constants\v3\OrderState; |
|||
use App\Controller\BaseController; |
|||
use App\Exception\BusinessException; |
|||
use App\Model\v3\CcbPayment; |
|||
use App\Model\v3\Order; |
|||
use App\Service\v3\CcbPaymentService; |
|||
use App\Service\v3\Interfaces\BadgeServiceInterface; |
|||
use App\Service\v3\Interfaces\CouponRebateServiceInterface; |
|||
use App\Service\v3\Interfaces\DeviceServiceInterface; |
|||
use App\Service\v3\Interfaces\FeiePrintServiceInterface; |
|||
use App\Service\v3\Interfaces\MiniprogramServiceInterface; |
|||
use App\Service\v3\Interfaces\MqttServiceInterface; |
|||
use App\Service\v3\Interfaces\OrderOnlineServiceInterface; |
|||
use App\Service\v3\Interfaces\OrderStatisticsServiceInterface; |
|||
use App\Service\v3\Interfaces\SeparateAccountsServiceInterface; |
|||
use Hyperf\Di\Annotation\Inject; |
|||
use Hyperf\Logger\LoggerFactory; |
|||
use Hyperf\Utils\ApplicationContext; |
|||
|
|||
class CcbNotifyController extends BaseController |
|||
{ |
|||
/** |
|||
* @var \Psr\Log\LoggerInterface |
|||
*/ |
|||
private $logger; |
|||
|
|||
/** |
|||
* @Inject |
|||
* @var MqttServiceInterface |
|||
*/ |
|||
protected $mqttService; |
|||
|
|||
/** |
|||
* @Inject |
|||
* @var DeviceServiceInterface |
|||
*/ |
|||
protected $deviceService; |
|||
|
|||
/** |
|||
* @Inject |
|||
* @var MiniprogramServiceInterface |
|||
*/ |
|||
protected $miniprogramService; |
|||
|
|||
/** |
|||
* @Inject |
|||
* @var FeiePrintServiceInterface |
|||
*/ |
|||
protected $feiePrintService; |
|||
|
|||
/** |
|||
* @Inject |
|||
* @var CouponRebateServiceInterface |
|||
*/ |
|||
protected $couponRebateService; |
|||
|
|||
/** |
|||
* @Inject |
|||
* @var OrderOnlineServiceInterface |
|||
*/ |
|||
protected $orderOnlineService; |
|||
|
|||
/** |
|||
* @Inject |
|||
* @var SeparateAccountsServiceInterface |
|||
*/ |
|||
protected $separateAccountsService; |
|||
|
|||
/** |
|||
* @Inject |
|||
* @var BadgeServiceInterface |
|||
*/ |
|||
protected $badgeService; |
|||
|
|||
/** |
|||
* @Inject |
|||
* @var OrderStatisticsServiceInterface |
|||
*/ |
|||
protected $orderStatisticsService; |
|||
|
|||
public function __construct(LoggerFactory $loggerFactory) |
|||
{ |
|||
parent::__construct(); |
|||
$this->logger = $loggerFactory->get('ccb.notify'); |
|||
} |
|||
|
|||
private function saveLog($func, $content) |
|||
{ |
|||
$this->logger->info($func."\n".$content."\n"); |
|||
} |
|||
|
|||
public function pay() |
|||
{ |
|||
try { |
|||
$this->saveLog(__FUNCTION__, $this->request->getBody()->getContents()); |
|||
|
|||
$data = $this->request->all(); |
|||
if (!isset($data['Main_Ordr_No'], $data['Sign_Inf'])) { |
|||
throw new BusinessException(500, '缺少参数'); |
|||
} |
|||
|
|||
$ccb = ApplicationContext::getContainer()->get(CcbPaymentService::class); |
|||
|
|||
if (!$ccb->verifySign($ccb->createSign($data), $data['Sign_Inf'])) { |
|||
throw new BusinessException(500, '验签失败'); |
|||
} |
|||
|
|||
$model = CcbPayment::where('main_ordr_no', $data['Main_Ordr_No'])->first(); |
|||
if (!$model) { |
|||
throw new BusinessException(500, '下单记录不存在'); |
|||
} |
|||
|
|||
$payResult = $ccb->gatherEnquireOrder($data['Main_Ordr_No']); |
|||
if ($payResult['Ordr_Stcd'] != $data['Ordr_Stcd']) { |
|||
throw new BusinessException(500, '订单状态不一致'); |
|||
} |
|||
|
|||
// 状态已同步
|
|||
if ($model->ordr_stcd == $data['Ordr_Stcd']) { |
|||
return $this->response->json([ |
|||
'Svc_Rsp_St' => '00', |
|||
]); |
|||
} |
|||
|
|||
$model->ordr_stcd = $data['Ordr_Stcd']; |
|||
$model->pay_time = $data['Pay_Time']; |
|||
$model->pay_type = $data['TYPE']; |
|||
$model->pay_channel = $data['PAY_CHANNEL']; |
|||
$model->debit_credit_type = $data['DEBIT_CREDIT_TYPE']; |
|||
$model->save(); |
|||
|
|||
if ($payResult['Ordr_Stcd'] == '2') { |
|||
$orderMain = $model->orderMain; |
|||
|
|||
if ($orderMain->state != OrderState::UNPAID) { |
|||
throw new BusinessException(500, '订单状态异常'); |
|||
} |
|||
|
|||
$this->orderOnlineService->doByPaid($orderMain->global_order_id); |
|||
$this->separateAccountsService->orderOnlinePaid($orderMain->global_order_id); |
|||
|
|||
//记录当前市场的当天外卖订单数
|
|||
$this->orderStatisticsService->setForMarket($orderMain->market_id); |
|||
|
|||
// 优惠券返券
|
|||
$this->couponRebateService->couponRebateInTask($orderMain->global_order_id); |
|||
|
|||
// 喇叭通知,兼容旧音响,MQTT+IOT
|
|||
$res = $this->mqttService->speakToStore($orderMain->global_order_id); |
|||
$res = $this->deviceService->pubMsgToStoreByOrderMainId($orderMain->global_order_id); |
|||
|
|||
// 打印订单,自动打印
|
|||
$res = $this->feiePrintService->feiePrint($orderMain->global_order_id); |
|||
|
|||
// 记录badge
|
|||
$orderChildIds = Order::query()->where(['order_main_id' => $orderMain->global_order_id])->pluck('store_id'); |
|||
$this->badgeService->doByOrder($orderMain->user_id, $orderChildIds, $orderMain->global_order_id, OrderState::PAID); |
|||
|
|||
// 公众号模板消息
|
|||
$res = $this->miniprogramService->sendTemMsgForOnlineOrder($orderMain->global_order_id); |
|||
} |
|||
|
|||
return $this->response->json([ |
|||
'Svc_Rsp_St' => '00', |
|||
]); |
|||
|
|||
} catch (\Exception $e) { |
|||
return $this->response->json([ |
|||
'Svc_Rsp_St' => '01', |
|||
'Rsp_Inf' => $e instanceof BusinessException ? $e->getMessage() : '内部错误' |
|||
]); |
|||
} |
|||
} |
|||
|
|||
public function refund() |
|||
{ |
|||
$this->saveLog(__FUNCTION__, $this->request->getBody()->getContents()); |
|||
return $this->response->json([ |
|||
'Svc_Rsp_St' => '00', |
|||
]); |
|||
} |
|||
|
|||
public function merchant() |
|||
{ |
|||
$this->saveLog(__FUNCTION__, $this->request->getBody()->getContents()); |
|||
return $this->response->json([ |
|||
'Svc_Rsp_St' => '00', |
|||
]); |
|||
} |
|||
|
|||
public function accounting() |
|||
{ |
|||
$this->saveLog(__FUNCTION__, $this->request->getBody()->getContents()); |
|||
return $this->response->json([ |
|||
'Svc_Rsp_St' => '00', |
|||
]); |
|||
} |
|||
|
|||
public function bill() |
|||
{ |
|||
$this->saveLog(__FUNCTION__, $this->request->getBody()->getContents()); |
|||
return $this->response->json([ |
|||
'Svc_Rsp_St' => '00', |
|||
]); |
|||
} |
|||
|
|||
public function platform() |
|||
{ |
|||
$this->saveLog(__FUNCTION__, $this->request->getBody()->getContents()); |
|||
return $this->response->json([ |
|||
'Svc_Rsp_St' => '00', |
|||
]); |
|||
} |
|||
} |
|||
@ -0,0 +1,223 @@ |
|||
<?php |
|||
|
|||
namespace App\Controller\v3; |
|||
use App\Constants\v3\OrderState; |
|||
use App\Controller\BaseController; |
|||
use App\Model\v3\Order; |
|||
use App\Model\v3\OrderMain; |
|||
use Hyperf\DbConnection\Db; |
|||
use Psr\Http\Message\ResponseInterface; |
|||
|
|||
/** |
|||
* 顺丰同城回调 |
|||
*/ |
|||
class SfExpressController extends BaseController |
|||
{ |
|||
private string $dev_id; |
|||
private string $dev_key; |
|||
// private string $shop_id;
|
|||
|
|||
public function __construct() |
|||
{ |
|||
parent::__construct(); //此句不能少,否则$this->request和$this->response获取不到
|
|||
$this->dev_id = env('SF_EXPRESS_DEV_ID'); |
|||
$this->dev_key = env('SF_EXPRESS_DEV_KEY'); |
|||
// $this->shop_id = env('SF_EXPRESS_SHOP_ID');
|
|||
} |
|||
|
|||
/** |
|||
* 配送状态更改回调 |
|||
*/ |
|||
public function riderStatus(): ResponseInterface |
|||
{ |
|||
if (!$this->checkSign($this->request->query('sign'))) { |
|||
return $this->response->json([ |
|||
'error_code' => 500, |
|||
'error_msg' => '签名错误', |
|||
]); |
|||
} |
|||
|
|||
$formData = $this->request->all(); |
|||
if (empty($formData['shop_order_id'])) { |
|||
return $this->response->json([ |
|||
'error_code' => 500, |
|||
'error_msg' => '无效的shop_order_id', |
|||
]); |
|||
} |
|||
|
|||
# 主订单表
|
|||
$orderMain = OrderMain::whereIn('state', [OrderState::PAID, OrderState::DELIVERY]) |
|||
->where('global_order_id', $formData['shop_order_id']) |
|||
->first(); |
|||
|
|||
if (!$orderMain) { |
|||
return $this->response->json([ |
|||
'error_code' => 500, |
|||
'error_msg' => '订单不存在', |
|||
]); |
|||
} |
|||
|
|||
DB::beginTransaction(); |
|||
try { |
|||
# 主订单表
|
|||
$orderMain->state = OrderState::DELIVERY; |
|||
//order_status 订单状态 10-配送员确认;12:配送员到店;15:配送员配送中
|
|||
if (!empty($formData['order_status'])) { |
|||
if ($formData['order_status'] == 10 && $orderMain->receive_time == 0) { |
|||
$orderMain->receive_time = time(); // 接单时间
|
|||
} else if ($formData['order_status'] == 12 && $orderMain->delivery_start_time == 0) { |
|||
$orderMain->delivery_start_time = time(); // 开始配送时间
|
|||
} |
|||
} |
|||
$orderMain->save(); |
|||
|
|||
# 子订单表
|
|||
Order::where('order_main_id', $formData['shop_order_id']) |
|||
->update(['state' => $orderMain->state]); |
|||
|
|||
DB::commit(); |
|||
} catch (\Exception $exception) { |
|||
DB::rollBack(); |
|||
return $this->response->json([ |
|||
'error_code' => 500, |
|||
'error_msg' => $exception->getMessage(), |
|||
]); |
|||
} |
|||
|
|||
return $this->response->json([ |
|||
'error_code' => 0, |
|||
'error_msg' => 'success', |
|||
]); |
|||
} |
|||
|
|||
/** |
|||
* 骑士撤单状态回调 |
|||
*/ |
|||
public function riderRecall(): ResponseInterface |
|||
{ |
|||
if (!$this->checkSign($this->request->query('sign'))) { |
|||
return $this->response->json([ |
|||
'error_code' => 500, |
|||
'error_msg' => '签名错误', |
|||
]); |
|||
} |
|||
|
|||
$formData = $this->request->all(); |
|||
if (empty($formData['shop_order_id'])) { |
|||
return $this->response->json([ |
|||
'error_code' => 500, |
|||
'error_msg' => '无效的shop_order_id', |
|||
]); |
|||
} |
|||
|
|||
//order_status 22-配送员撤单
|
|||
//TODO 因目前订单表没有相关撤单的字段,故目前不做处理,仅仅返回成功给顺丰
|
|||
return $this->response->json([ |
|||
'error_code' => 0, |
|||
'error_msg' => 'success', |
|||
]); |
|||
} |
|||
|
|||
/** |
|||
* 订单完成回调 |
|||
*/ |
|||
public function orderComplete(): ResponseInterface |
|||
{ |
|||
if (!$this->checkSign($this->request->query('sign'))) { |
|||
return $this->response->json([ |
|||
'error_code' => 500, |
|||
'error_msg' => '签名错误', |
|||
]); |
|||
} |
|||
|
|||
$formData = $this->request->all(); |
|||
if (empty($formData['shop_order_id'])) { |
|||
return $this->response->json([ |
|||
'error_code' => 500, |
|||
'error_msg' => '无效的shop_order_id', |
|||
]); |
|||
} |
|||
|
|||
# 主订单表
|
|||
$orderMain = OrderMain::where('state', '>', OrderState::UNPAID) |
|||
->where('global_order_id', $formData['shop_order_id']) |
|||
->first(); |
|||
|
|||
if (!$orderMain) { |
|||
return $this->response->json([ |
|||
'error_code' => 500, |
|||
'error_msg' => '订单不存在', |
|||
]); |
|||
} |
|||
|
|||
DB::beginTransaction(); |
|||
try { |
|||
# 主订单表
|
|||
$orderMain->state = OrderState::COMPLETED; |
|||
$orderMain->complete_time = time(); |
|||
$orderMain->delivery_time = time(); |
|||
$orderMain->save(); |
|||
|
|||
# 子订单表
|
|||
Order::where('order_main_id', $formData['shop_order_id']) |
|||
->update(['state' => $orderMain->state]); |
|||
|
|||
DB::commit(); |
|||
} catch (\Exception $exception) { |
|||
DB::rollBack(); |
|||
return $this->response->json([ |
|||
'error_code' => 500, |
|||
'error_msg' => $exception->getMessage(), |
|||
]); |
|||
} |
|||
|
|||
return $this->response->json([ |
|||
'error_code' => 0, |
|||
'error_msg' => 'success', |
|||
]); |
|||
} |
|||
|
|||
/** |
|||
* 顺丰原因订单取消回调 |
|||
*/ |
|||
public function sfCancel(): ResponseInterface |
|||
{ |
|||
//TODO 因目前订单表没有相关撤单的字段,故目前不做处理,仅仅返回成功给顺丰
|
|||
return $this->riderRecall(); |
|||
} |
|||
|
|||
/** |
|||
* 订单异常回调 |
|||
*/ |
|||
public function riderException(): ResponseInterface |
|||
{ |
|||
/** ex_id枚举值: |
|||
4003:托寄物丢失或损坏 |
|||
1001:商家出货慢 |
|||
2010:顾客拒绝实名认证 |
|||
3004:实名认证校验失败 |
|||
1007:更改取货地址 |
|||
2001:顾客电话无法接通 |
|||
2004:更改期望送达时间 |
|||
2005:顾客拒收 |
|||
2008:顾客不在家 |
|||
2009:更改送货地址 |
|||
4001:配送地址错误 |
|||
4002:其他 |
|||
*/ |
|||
//TODO 因目前订单表没有相关撤单的字段,故目前不做处理,仅仅返回成功给顺丰
|
|||
return $this->riderRecall(); |
|||
} |
|||
|
|||
/** |
|||
* 回调签名校验 |
|||
*/ |
|||
private function checkSign(?string $checkSign): bool |
|||
{ |
|||
$post_data = $this->request->getBody()->getContents(); |
|||
echo PHP_EOL, '$post_data', PHP_EOL; |
|||
print_r($post_data); |
|||
$sign_char = $post_data . "&{$this->dev_id}&{$this->dev_key}"; |
|||
return $checkSign == base64_encode(md5($sign_char)); |
|||
} |
|||
} |
|||
@ -0,0 +1,65 @@ |
|||
<?php |
|||
|
|||
declare (strict_types=1); |
|||
|
|||
namespace App\Model\v3; |
|||
|
|||
use Hyperf\DbConnection\Model\Model; |
|||
|
|||
/** |
|||
* @property int $id |
|||
* @property int $order_main_id |
|||
* @property string $main_ordr_no |
|||
* @property string $pymd_cd |
|||
* @property string $clrg_dt |
|||
* @property string $sub_appid |
|||
* @property string $sub_openid |
|||
* @property string $py_ordr_tpcd |
|||
* @property float $ordr_tamt |
|||
* @property float $txn_tamt |
|||
* @property string $orderlist |
|||
* @property string $py_trn_no |
|||
* @property string $prim_ordr_no |
|||
* @property string $ordr_gen_tm |
|||
* @property string $cshdk_url |
|||
* @property string $rtn_par_data |
|||
* @property string $ordr_stcd |
|||
* @property string $rtn_orderlist |
|||
* @property string $pay_time |
|||
* @property string $pay_type |
|||
* @property string $pay_channel |
|||
* @property string $debit_credit_type |
|||
* @property \Carbon\Carbon $created_at |
|||
* @property \Carbon\Carbon $updated_at |
|||
*/ |
|||
class CcbPayment extends Model |
|||
{ |
|||
/** |
|||
* The table associated with the model. |
|||
* |
|||
* @var string |
|||
*/ |
|||
protected $table = 'lanzu_ccb_payment'; |
|||
/** |
|||
* The attributes that are mass assignable. |
|||
* |
|||
* @var array |
|||
*/ |
|||
protected $fillable = []; |
|||
/** |
|||
* The attributes that should be cast to native types. |
|||
* |
|||
* @var array |
|||
*/ |
|||
protected $casts = [ |
|||
'id' => 'integer', |
|||
'order_main_id' => 'integer', |
|||
'created_at' => 'datetime', |
|||
'updated_at' => 'datetime', |
|||
]; |
|||
|
|||
public function orderMain() |
|||
{ |
|||
return $this->belongsTo(OrderMain::class, 'order_main_id', 'global_order_id'); |
|||
} |
|||
} |
|||
@ -0,0 +1,14 @@ |
|||
<?php |
|||
|
|||
namespace App\Model\v3; |
|||
use App\Model\Model; |
|||
use Hyperf\Database\Model\Relations\BelongsTo; |
|||
|
|||
class SfExpressOrder extends Model |
|||
{ |
|||
protected $table = 'lanzu_sf_express_orders'; |
|||
public function orderMain(): BelongsTo |
|||
{ |
|||
return $this->belongsTo(OrderMain::class, 'shop_order_id', 'global_order_id'); |
|||
} |
|||
} |
|||
@ -0,0 +1,642 @@ |
|||
<?php |
|||
|
|||
namespace App\Service\v3; |
|||
|
|||
use App\Commons\Log; |
|||
use App\Constants\v3\ErrorCode; |
|||
use App\Constants\v3\LogLabel; |
|||
use App\Exception\BusinessException; |
|||
use App\Exception\ErrorCodeException; |
|||
use App\Model\v3\CcbPayment; |
|||
use App\Model\v3\OrderMain; |
|||
use App\Model\v3\User; |
|||
use App\TaskWorker\SSDBTask; |
|||
use Hyperf\Di\Annotation\Inject; |
|||
use Hyperf\Guzzle\ClientFactory; |
|||
use Hyperf\Logger\LoggerFactory; |
|||
use Hyperf\Utils\ApplicationContext; |
|||
|
|||
class CcbPaymentService |
|||
{ |
|||
/** |
|||
* 是否测试环境 |
|||
* @var bool |
|||
*/ |
|||
private $isDebug; |
|||
|
|||
/** |
|||
* 测试环境请求的域名 |
|||
* @var string |
|||
*/ |
|||
private $devBaseUri = 'http://marketpayktwo.dev.jh:8028'; |
|||
|
|||
/** |
|||
* 生产环境请求的域名 |
|||
* @var string |
|||
*/ |
|||
private $prodBaseUri = 'https://marketpay.ccb.com'; |
|||
|
|||
/** |
|||
* 市场编号 |
|||
* @var string |
|||
*/ |
|||
private $mktId; |
|||
|
|||
/** |
|||
* 我方商家编号 |
|||
* @var string |
|||
*/ |
|||
private $merchantId; |
|||
|
|||
/** |
|||
* 支付方式 |
|||
* @var string |
|||
*/ |
|||
private $pymdCd; |
|||
|
|||
/** |
|||
* 我方私钥 |
|||
* @var resource |
|||
*/ |
|||
private $selfPrivateKey; |
|||
|
|||
/** |
|||
* 银行公钥 |
|||
* @var resource |
|||
*/ |
|||
private $bankPublicKey; |
|||
|
|||
/** |
|||
* 发起渠道编号 |
|||
* @var string |
|||
*/ |
|||
private $ittpartyStmId = '00000'; |
|||
|
|||
/** |
|||
* 支付渠道代码 |
|||
* @var string |
|||
*/ |
|||
private $pyChnlCd = '0000000000000000000000000'; |
|||
|
|||
/** |
|||
* @var \Hyperf\Guzzle\ClientFactory |
|||
*/ |
|||
private $clientFactory; |
|||
|
|||
/** |
|||
* @var \Psr\Log\LoggerInterface |
|||
*/ |
|||
private $logger; |
|||
|
|||
/** |
|||
* @Inject |
|||
* @var Log |
|||
*/ |
|||
protected $log; |
|||
|
|||
public function __construct(ClientFactory $clientFactory, LoggerFactory $loggerFactory) |
|||
{ |
|||
$this->clientFactory = $clientFactory; |
|||
$this->logger = $loggerFactory->get('ccb'); |
|||
|
|||
$this->isDebug = config('ccb.debug'); |
|||
$this->mktId = config('ccb.mkt_id'); |
|||
$this->merchantId = config('ccb.merchant_id'); |
|||
$this->pymdCd = config('ccb.pymd_cd'); |
|||
|
|||
$selfPrivateKey = config('ccb.self_private_key'); |
|||
$selfPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\n".chunk_split($selfPrivateKey, 64, "\n")."-----END RSA PRIVATE KEY-----\n"; |
|||
$this->selfPrivateKey = openssl_get_privatekey($selfPrivateKey); |
|||
|
|||
$bankPublicKey = config('ccb.bank_public_key'); |
|||
$bankPublicKey = "-----BEGIN PUBLIC KEY-----\n".chunk_split($bankPublicKey, 64, "\n")."-----END PUBLIC KEY-----\n"; |
|||
$this->bankPublicKey = openssl_get_publickey($bankPublicKey); |
|||
} |
|||
|
|||
/** |
|||
* 使用我方私钥加密 |
|||
* @param string $data |
|||
* @return string |
|||
*/ |
|||
public function encrypt(string $data) |
|||
{ |
|||
$str = ''; |
|||
foreach (str_split($data, 117) as $chunk) { |
|||
openssl_private_encrypt($chunk, $crypted, $this->selfPrivateKey); |
|||
$str .= $crypted; |
|||
} |
|||
return base64_encode($str); |
|||
} |
|||
|
|||
/** |
|||
* 使用银行公钥解密 |
|||
* @param string $data |
|||
* @return string |
|||
*/ |
|||
public function decrypt(string $data) |
|||
{ |
|||
$raw = base64_decode($data); |
|||
$str = ''; |
|||
foreach (str_split($raw, 256) as $chunk) { |
|||
openssl_public_decrypt($chunk, $decrypted, $this->bankPublicKey); |
|||
$str .= $decrypted; |
|||
} |
|||
return $str; |
|||
} |
|||
|
|||
/** |
|||
* 使用我方私钥生成签名 |
|||
* @param string $data |
|||
* @return string |
|||
*/ |
|||
public function sign(string $data) |
|||
{ |
|||
openssl_sign($data, $signature, $this->selfPrivateKey, OPENSSL_ALGO_SHA256); |
|||
return base64_encode($signature); |
|||
} |
|||
|
|||
/** |
|||
* 使用银行公钥验证签名 |
|||
* @param string $data |
|||
* @param string $signature |
|||
* @return bool |
|||
*/ |
|||
public function verifySign(string $data, string $signature) |
|||
{ |
|||
$signature = base64_decode($signature); |
|||
$result = openssl_verify($data, $signature, $this->bankPublicKey, OPENSSL_ALGO_SHA256); |
|||
return $result == 1; |
|||
} |
|||
|
|||
/** |
|||
* 计算待签名字符串 |
|||
* @param array $params |
|||
* @return string |
|||
*/ |
|||
public function createSign(array $params) |
|||
{ |
|||
// 不参与签名的字符串
|
|||
$unsignKeys = ['Sign_Inf', 'Svc_Rsp_St', 'Svc_Rsp_Cd', 'Rsp_Inf']; |
|||
|
|||
$result = []; |
|||
|
|||
ksort($params); |
|||
|
|||
foreach ($params as $key => $item) { |
|||
if (in_array($key, $unsignKeys)) { |
|||
continue; |
|||
} |
|||
if (is_array($item)) { |
|||
foreach ($item as $child) { |
|||
$value = $this->createSign($child); |
|||
if ($value !== '') { |
|||
$result[] = ['', $value]; |
|||
} |
|||
} |
|||
} else { |
|||
$value = trim($item); |
|||
if ($value !== '') { |
|||
$result[] = [$key, $value]; |
|||
} |
|||
} |
|||
} |
|||
|
|||
$str = ''; |
|||
|
|||
foreach ($result as [$key, $value]) { |
|||
$str .= $key ? "$key=$value&" : "$value&"; |
|||
} |
|||
|
|||
return rtrim($str, '&'); |
|||
} |
|||
|
|||
/** |
|||
* 发送API请求 |
|||
* @param string $uri |
|||
* @param array $params |
|||
* @return array |
|||
*/ |
|||
private function apiRequest(string $uri, array $params = []): array |
|||
{ |
|||
$signData = $this->createSign($params); |
|||
|
|||
$params['Sign_Inf'] = $this->sign($signData); |
|||
|
|||
if ($this->isDebug) { |
|||
$uri = $this->devBaseUri.$uri; |
|||
} else { |
|||
$uri = $this->prodBaseUri.$uri; |
|||
} |
|||
|
|||
$options = ['json' => $params]; |
|||
|
|||
$startTime = microtime(true); |
|||
|
|||
try { |
|||
$response = $this->clientFactory->create(['timeout' => 60])->post($uri, $options); |
|||
} catch (\Exception $e) { |
|||
$this->saveApiLog(0, $uri, $params, $e->getMessage()); |
|||
throw new BusinessException(500, '请求异常'); |
|||
} |
|||
|
|||
$useTime = round((microtime(true) - $startTime) * 1000, 2); |
|||
|
|||
$content = $response->getBody()->getContents(); |
|||
$result = json_decode($content, true); |
|||
|
|||
if (!isset($result['Svc_Rsp_St']) || $result['Svc_Rsp_St'] != '00') { |
|||
$this->saveApiLog($useTime, $uri, $params, $content); |
|||
throw new BusinessException(500, (($result['Rsp_Inf'] ?? '') ?: 'CCB请求失败')); |
|||
} |
|||
|
|||
if (!isset($result['Sign_Inf']) || !$this->verifySign($this->createSign($result), $result['Sign_Inf'])) { |
|||
$this->saveApiLog($useTime, $uri, $params, $content); |
|||
throw new BusinessException(500, (($result['Rsp_Inf'] ?? '') ?: 'CCB验签失败')); |
|||
} |
|||
|
|||
if ($this->isDebug) { |
|||
$this->saveApiLog($useTime, $uri, $params, $content); |
|||
} |
|||
|
|||
return $result; |
|||
} |
|||
|
|||
/** |
|||
* 保存API请求日志 |
|||
* @param $useTime |
|||
* @param $uri |
|||
* @param $params |
|||
* @param $content |
|||
* @return void |
|||
*/ |
|||
private function saveApiLog($useTime, $uri, $params, $content) |
|||
{ |
|||
$this->logger->info( |
|||
sprintf( |
|||
"%s\nTime: %.2f ms\nUrl: %s\nParams:\n%s\nContent:\n%s\n", |
|||
'CCB API Log', |
|||
$useTime, |
|||
$uri, |
|||
json_encode($params, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE), |
|||
$content |
|||
) |
|||
); |
|||
} |
|||
|
|||
private function getTimestamp() |
|||
{ |
|||
return (new \DateTime())->format('YmdHisv'); |
|||
} |
|||
|
|||
private function genSerialNumber() |
|||
{ |
|||
return date('YmdHis').mt_rand(10000, 99999).mt_rand(10000, 99999); |
|||
} |
|||
|
|||
private function genMainOrderNo() |
|||
{ |
|||
return time().mt_rand(10000, 99999).mt_rand(10000, 99999); |
|||
} |
|||
|
|||
/** |
|||
* 3.1 生成支付订单接口 |
|||
* @param string $Main_Ordr_No 主订单编号 |
|||
* @param string $Ordr_Tamt 订单总金额 |
|||
* @param string $Txn_Tamt 交易总金额(实付) |
|||
* @param string|null $Sub_Appid 当前调起支付的小程序appid |
|||
* @param string|null $Sub_Openid 用户在小程序下的openid |
|||
* @param array $Orderlist 子订单列表 |
|||
* @return array |
|||
*/ |
|||
public function gatherPlaceorder(string $Main_Ordr_No, string $Ordr_Tamt, string $Txn_Tamt, ?string $Sub_Appid, ?string $Sub_Openid, array $Orderlist) |
|||
{ |
|||
$uri = '/online/direct/gatherPlaceorder'; |
|||
|
|||
$params = [ |
|||
'Ittparty_Stm_Id' => $this->ittpartyStmId, |
|||
'Py_Chnl_Cd' => $this->pyChnlCd, |
|||
'Ittparty_Tms' => $this->getTimestamp(), |
|||
'Ittparty_Jrnl_No' => $this->genSerialNumber(), |
|||
'Mkt_Id' => $this->mktId, |
|||
'Main_Ordr_No' => $Main_Ordr_No, |
|||
'Pymd_Cd' => $this->pymdCd, |
|||
'Py_Ordr_Tpcd' => '04', |
|||
'Py_Rslt_Ntc_Sn' => '1', |
|||
'Ccy' => '156', |
|||
'Ordr_Tamt' => $Ordr_Tamt, |
|||
'Txn_Tamt' => $Txn_Tamt, |
|||
'Order_Time_Out' => '1800', |
|||
'Orderlist' => $Orderlist, |
|||
'Vno' => '4', |
|||
]; |
|||
|
|||
if ($this->pymdCd == '05') { |
|||
$params['Sub_Appid'] = $Sub_Appid; |
|||
$params['Sub_Openid'] = $Sub_Openid; |
|||
} |
|||
|
|||
return $this->apiRequest($uri, $params); |
|||
} |
|||
|
|||
/** |
|||
* 下单子订单格式化 |
|||
* @param string $Mkt_Mrch_Id 商家编号 |
|||
* @param string $Cmdty_Ordr_No 子订单编号 |
|||
* @param string $Ordr_Amt 订单金额 |
|||
* @param string $Txnamt 实付金额 |
|||
* @param string $Cmdty_Dsc 商品描述 |
|||
* @return string[] |
|||
*/ |
|||
public function subOrderListItem(string $Mkt_Mrch_Id, string $Cmdty_Ordr_No, string $Ordr_Amt, string $Txnamt, string $Cmdty_Dsc) |
|||
{ |
|||
return compact('Mkt_Mrch_Id', 'Cmdty_Ordr_No', 'Ordr_Amt', 'Txnamt', 'Cmdty_Dsc'); |
|||
} |
|||
|
|||
/** |
|||
* 3.4 查询支付结果接口,同一笔订单不支持并发查询 |
|||
* @param string $Main_Ordr_No 主订单号,主订单号与支付流水号必输其一 |
|||
* @param string $Py_Trn_No 银行支付流水号 |
|||
* @return array |
|||
*/ |
|||
public function gatherEnquireOrder(string $Main_Ordr_No, string $Py_Trn_No = '') |
|||
{ |
|||
$uri = '/online/direct/gatherEnquireOrder'; |
|||
|
|||
$params = [ |
|||
'Ittparty_Stm_Id' => $this->ittpartyStmId, |
|||
'Py_Chnl_Cd' => $this->pyChnlCd, |
|||
'Ittparty_Tms' => $this->getTimestamp(), |
|||
'Ittparty_Jrnl_No' => $this->genSerialNumber(), |
|||
'Mkt_Id' => $this->mktId, |
|||
'Main_Ordr_No' => $Main_Ordr_No, |
|||
'Py_Trn_No' => $Py_Trn_No, |
|||
'Vno' => '4', |
|||
]; |
|||
|
|||
$ssdb = ApplicationContext::getContainer()->get(SSDBTask::class); |
|||
|
|||
$key = 'ccb_'.__FUNCTION__.'_'.$Main_Ordr_No.$Py_Trn_No; |
|||
|
|||
if ($ssdb->exec('setnx',$key, 1)) { |
|||
try { |
|||
return $this->apiRequest($uri, $params); |
|||
} finally { |
|||
$ssdb->exec('expire', $key, 2); |
|||
} |
|||
} else { |
|||
sleep(1); |
|||
return $this->gatherEnquireOrder($Main_Ordr_No, $Py_Trn_No); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 4.1 订单退款接口 |
|||
* @param string $Cust_Rfnd_Trcno 退款流水号,对于同一笔退款唯一 |
|||
* @param string $Py_Trn_No 银行支付流水号 |
|||
* @param string $Rfnd_Amt 退款金额,全额退款时可不传 |
|||
* @param array $Sub_Ordr_List 子订单列表,全额退款时不需要传该域 |
|||
* @return array |
|||
*/ |
|||
public function refundOrder(string $Cust_Rfnd_Trcno, string $Py_Trn_No, string $Rfnd_Amt = '', array $Sub_Ordr_List = []) |
|||
{ |
|||
$uri = '/online/direct/refundOrder'; |
|||
|
|||
$params = [ |
|||
'Ittparty_Stm_Id' => $this->ittpartyStmId, |
|||
'Py_Chnl_Cd' => $this->pyChnlCd, |
|||
'Ittparty_Tms' => $this->getTimestamp(), |
|||
'Ittparty_Jrnl_No' => $this->genSerialNumber(), |
|||
'Mkt_Id' => $this->mktId, |
|||
'Cust_Rfnd_Trcno' => $Cust_Rfnd_Trcno, |
|||
'Py_Trn_No' => $Py_Trn_No, |
|||
'Rfnd_Amt' => $Rfnd_Amt, |
|||
'Sub_Ordr_List' => $Sub_Ordr_List, |
|||
'Vno' => '3', |
|||
]; |
|||
|
|||
if ($Sub_Ordr_List) { |
|||
$params['Sub_Ordr_List'] = $Sub_Ordr_List; |
|||
} |
|||
|
|||
return $this->apiRequest($uri, $params); |
|||
} |
|||
|
|||
/** |
|||
* 退款子订单格式化 |
|||
* @param string $Sub_Ordr_Id 银行子订单编号 |
|||
* @param string $Rfnd_Amt 退款金额 |
|||
* @return string[] |
|||
*/ |
|||
public function refundSubOrderListItem(string $Sub_Ordr_Id, string $Rfnd_Amt) |
|||
{ |
|||
return compact('Sub_Ordr_Id', 'Rfnd_Amt'); |
|||
} |
|||
|
|||
/** |
|||
* 4.3 查询退款结果接口,同一笔退款不支持并发查询 |
|||
* @param string $Cust_Rfnd_Trcno 我方退款流水号,与银行退款流水号必输其一 |
|||
* @param string $Rfnd_Trcno 银行退款流水号 |
|||
* @return array |
|||
*/ |
|||
public function enquireRefundOrder(string $Cust_Rfnd_Trcno, string $Rfnd_Trcno = '') |
|||
{ |
|||
$uri = '/online/direct/enquireRefundOrder'; |
|||
|
|||
$params = [ |
|||
'Ittparty_Stm_Id' => $this->ittpartyStmId, |
|||
'Py_Chnl_Cd' => $this->pyChnlCd, |
|||
'Ittparty_Tms' => $this->getTimestamp(), |
|||
'Ittparty_Jrnl_No' => $this->genSerialNumber(), |
|||
'Mkt_Id' => $this->mktId, |
|||
'Cust_Rfnd_Trcno' => $Cust_Rfnd_Trcno, |
|||
'Rfnd_Trcno' => $Rfnd_Trcno, |
|||
'Vno' => '4', |
|||
]; |
|||
|
|||
return $this->apiRequest($uri, $params); |
|||
} |
|||
|
|||
/** |
|||
* 5.3 确认收货接口 |
|||
* @param string $Prim_Ordr_No 银行主订单编号 |
|||
* @return array |
|||
*/ |
|||
public function mergeNoticeArrival(string $Prim_Ordr_No) |
|||
{ |
|||
$uri = '/online/direct/enquireRefundOrder'; |
|||
|
|||
$params = [ |
|||
'Ittparty_Stm_Id' => $this->ittpartyStmId, |
|||
'Py_Chnl_Cd' => $this->pyChnlCd, |
|||
'Ittparty_Tms' => $this->getTimestamp(), |
|||
'Ittparty_Jrnl_No' => $this->genSerialNumber(), |
|||
'Mkt_Id' => $this->mktId, |
|||
'Prim_Ordr_No' => $Prim_Ordr_No, |
|||
'Vno' => '4', |
|||
]; |
|||
|
|||
return $this->apiRequest($uri, $params); |
|||
} |
|||
|
|||
/** |
|||
* 10.1 订单信息查询 |
|||
* @param string $Main_Ordr_No 主订单编号 |
|||
* @param string $Py_Trn_No 支付流水号,主订单号与支付流水号必输其一 |
|||
* @return array |
|||
*/ |
|||
public function orderInfQuery(string $Main_Ordr_No, string $Py_Trn_No = '') |
|||
{ |
|||
$uri = '/online/direct/OrderInfQuery'; |
|||
|
|||
$params = [ |
|||
'Ittparty_Stm_Id' => $this->ittpartyStmId, |
|||
'Py_Chnl_Cd' => $this->pyChnlCd, |
|||
'Ittparty_Tms' => $this->getTimestamp(), |
|||
'Ittparty_Jrnl_No' => $this->genSerialNumber(), |
|||
'Mkt_Id' => $this->mktId, |
|||
'Main_Ordr_No' => $Main_Ordr_No, |
|||
'Py_Trn_No' => $Py_Trn_No, |
|||
'Vno' => '4', |
|||
]; |
|||
|
|||
return $this->apiRequest($uri, $params); |
|||
} |
|||
|
|||
|
|||
/** |
|||
* 创建支付订单 |
|||
* @param $globalOrderId |
|||
* @param $userId |
|||
* @return array |
|||
* @throws \GuzzleHttp\Exception\GuzzleException |
|||
*/ |
|||
public function createCcbPayment($globalOrderId, $userId) |
|||
{ |
|||
try { |
|||
// 待支付的,未超时(15min,900sec)的订单
|
|||
$orderMain = OrderMain::query() |
|||
->where(['state' => OrderState::UNPAID, 'global_order_id' => $globalOrderId, 'user_id' => $userId]) |
|||
->where('created_at', '>=', (time() - 900)) |
|||
->first(); |
|||
if (empty($orderMain)) { |
|||
throw new BusinessException(ErrorCode::ORDER_NOT_AVAILABLE, '[订单号无效]'.$globalOrderId); |
|||
} |
|||
|
|||
$user = User::select('openid')->find($userId); |
|||
|
|||
$model = new CcbPayment(); |
|||
$model->order_main_id = $orderMain->global_order_id; |
|||
$model->main_ordr_no = $this->genMainOrderNo(); |
|||
$model->pymd_cd = $this->pymdCd; |
|||
if ($this->pymdCd == '05') { |
|||
$model->sub_appid = config('wechat.applet.app_id'); |
|||
$model->sub_openid = $user->openid; |
|||
} |
|||
$model->py_ordr_tpcd = '04'; |
|||
$model->ordr_tamt = $orderMain->money; |
|||
$model->txn_tamt = $orderMain->money; |
|||
$subOrderList = []; |
|||
|
|||
// 运费判断
|
|||
if (bccomp($orderMain->delivery_money, '0', 2) == 1) { |
|||
$subOrderList[] = $this->subOrderListItem( |
|||
$this->merchantId, |
|||
$model->main_ordr_no.'D', |
|||
$orderMain->delivery_money, |
|||
$orderMain->delivery_money, |
|||
'配送费' |
|||
); |
|||
} |
|||
|
|||
// 我方分润比例%
|
|||
$selfProfitRatio = config('ccb.self_profit_ratio'); |
|||
|
|||
if (bccomp($selfProfitRatio, '0', 3) == 0) { |
|||
throw new BusinessException(500, '[未配置分润比例]'); |
|||
} |
|||
|
|||
foreach ($orderMain->orders as $order) { |
|||
if (empty($order->store->ccb_merchant_id)) { |
|||
throw new BusinessException(500, '[店铺未配置商家编号]'.$order->store_id); |
|||
} |
|||
foreach ($order->orderGoods as $orderGoods) { |
|||
$goodsMoney = bcmul($orderGoods->price, (string)$orderGoods->number, 2); |
|||
$selfProfitMoney = bcmul($goodsMoney, $selfProfitRatio, 2); |
|||
$merchantProfitMoney = bcsub($goodsMoney, $selfProfitMoney, 2); |
|||
// 平台抽佣后最小金额不能为0
|
|||
if (bccomp($merchantProfitMoney, '0', 2) == 0) { |
|||
$selfProfitMoney = '0.00'; |
|||
$merchantProfitMoney = $goodsMoney; |
|||
} |
|||
$subOrderList[] = $this->subOrderListItem( |
|||
$order->store->ccb_merchant_id, |
|||
$model->main_ordr_no.'G'.$orderGoods->id.'N01', |
|||
$merchantProfitMoney, |
|||
$merchantProfitMoney, |
|||
$orderGoods->name.'(分佣到账)' |
|||
); |
|||
if (bccomp($selfProfitMoney, '0', 2) == 1) { |
|||
$subOrderList[] = $this->subOrderListItem( |
|||
$this->merchantId, |
|||
$model->main_ordr_no.'G'.$orderGoods->id.'N02', |
|||
$selfProfitMoney, |
|||
$selfProfitMoney, |
|||
$orderGoods->name.'(平台抽佣)' |
|||
); |
|||
} |
|||
} |
|||
} |
|||
|
|||
$model->orderlist = json_encode($subOrderList); |
|||
$model->save(); |
|||
|
|||
$result = $this->gatherPlaceorder( |
|||
$model->main_ordr_no, |
|||
$model->ordr_tamt, |
|||
$model->txn_tamt, |
|||
$model->sub_appid, |
|||
$model->sub_openid, |
|||
$subOrderList |
|||
); |
|||
|
|||
$model->py_trn_no = $result['Py_Trn_No']; |
|||
$model->prim_ordr_no = $result['Prim_Ordr_No']; |
|||
$model->ordr_gen_tm = $result['Ordr_Gen_Tm']; |
|||
if (isset($result['Cshdk_Url'])) { |
|||
$model->cshdk_url = $result['Cshdk_Url']; |
|||
} |
|||
if ($this->pymdCd == '05') { |
|||
$model->rtn_par_data = json_encode($result['Rtn_Par_Data']); |
|||
} |
|||
$model->ordr_stcd = $result['Ordr_Stcd']; |
|||
$model->rtn_orderlist = json_encode($result['Orderlist']); |
|||
$model->save(); |
|||
|
|||
if ($this->pymdCd == '05') { |
|||
// 返回支付参数给前端
|
|||
$parameters = [ |
|||
'appId' => $result['Rtn_Par_Data']['appId'], |
|||
'timeStamp' => $result['Rtn_Par_Data']['timeStamp'], |
|||
'nonceStr' => $result['Rtn_Par_Data']['nonceStr'], |
|||
'package' => $result['Rtn_Par_Data']['package'], |
|||
'signType' => $result['Rtn_Par_Data']['signType'], |
|||
'paySign' => $result['Rtn_Par_Data']['paySign'], |
|||
]; |
|||
} else { |
|||
$parameters = [ |
|||
'Cshdk_Url' => $model->cshdk_url, |
|||
]; |
|||
} |
|||
|
|||
$parameters['order_main_id'] = $orderMain->global_order_id; |
|||
|
|||
return $parameters; |
|||
|
|||
} catch (\Exception $e) { |
|||
$this->log->event(LogLabel::ORDER_PAYMENT_LOG, ['payment_do_exception_msg' => $e->getMessage()]); |
|||
$message = $e instanceof BusinessException ? $e->getMessage() : '[稍后重试]'; |
|||
throw new ErrorCodeException(ErrorCode::PAYMENT_FAIL, $message); |
|||
} |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,262 @@ |
|||
<?php |
|||
|
|||
namespace App\Service\v3; |
|||
|
|||
use App\Exception\BusinessException; |
|||
use Hyperf\Guzzle\ClientFactory; |
|||
use Hyperf\Utils\ApplicationContext; |
|||
|
|||
/** |
|||
* 顺丰同城相关 |
|||
* 文档:https://commit-openic.sf-express.com/open/api/docs/index#/apidoc
|
|||
*/ |
|||
class SfExpress |
|||
{ |
|||
private string $dev_id; |
|||
private string $dev_key; |
|||
private string $shop_id; |
|||
private string $host = 'https://openic.sf-express.com'; |
|||
private ClientFactory $clientFactory; |
|||
private static ?SfExpress $_instance = NULL; |
|||
|
|||
public function __construct() |
|||
{ |
|||
$this->dev_id = env('SF_EXPRESS_DEV_ID'); |
|||
$this->dev_key = env('SF_EXPRESS_DEV_KEY'); |
|||
$this->shop_id = env('SF_EXPRESS_SHOP_ID'); |
|||
$this->clientFactory = ApplicationContext::getContainer()->get(ClientFactory::class); |
|||
} |
|||
|
|||
public static function getInstance(): SfExpress |
|||
{ |
|||
if (is_null(self::$_instance)) { |
|||
self::$_instance = new static(); |
|||
} |
|||
return self::$_instance; |
|||
} |
|||
|
|||
/** |
|||
* 创建订单 |
|||
*/ |
|||
public function createOrder(array $params): array |
|||
{ |
|||
if (!isset($params['shop_order_id'], $params['order_time'], $params['receive'], $params['order_detail'])) { |
|||
throw new BusinessException(500, '商户订单号、用户下单时间、收货信息、订单信息不能为空'); |
|||
} |
|||
|
|||
$params = array_merge([ |
|||
'dev_id' => $this->dev_id, //必填
|
|||
'shop_id' => $this->shop_id, //必填
|
|||
'shop_type' => 1, //1:顺丰店铺ID 2:接入方店铺ID
|
|||
'shop_order_id' => '', //商户订单号
|
|||
'shop_preparation_time' => 15, //商家预计备餐时长,分钟级时间 比如: 10 分钟 则传入 10
|
|||
'order_source' => '街链平台', //必填。订单接入来源 1:美团;2:饿了么;3:百度;4:口碑;其他请直接填写中文字符串值
|
|||
// 'order_sequence' => '', //取货序号 与order_source配合使用 如:饿了么10号单,表示如下:order_source=2;order_sequence=10。用于骑士快速寻找配送物
|
|||
// 'lbs_type' => 2, //坐标类型,1:百度坐标,2:高德坐标
|
|||
'pay_type' => 1, //必填,用户支付方式:1、已支付 0、货到付款
|
|||
'order_time' => time(), |
|||
'is_appoint' => 0, //必填,是否是预约单,0:非预约单;1:预约单
|
|||
'appoint_type' => 0, //预约单类型,1:预约单送达单;2:预约单上门单,默认:0
|
|||
// 'expect_time' => '', //用户期望送达时间,若传入自此段且时间大于配送时效,则按照预约送达单处理,时间小于配送时效按照立即单处理;appoint_type=1时需必传,秒级时间戳
|
|||
// 'expect_pickup_time' => '', //用户期望上门时间,appoint_type=2时需必传,秒级时间戳
|
|||
// 'shop_expect_time' => 0, //商家期望送达时间 只展示给骑士,不参与时效考核;秒级时间戳
|
|||
'is_insured' => 0, //必填,是否保价,0:非保价;1:保价
|
|||
'is_person_direct' => 0, //必填,是否是专人直送订单,0:否;1:是
|
|||
// 'vehicle' => 0, //配送交通工具,0:否;1:电动车;2:小轿车
|
|||
// 'declared_value' => 0, //保价金额
|
|||
// 'gratuity_fee' => 0, //订单小费,不传或者传0为不加小费,单位分,加小费最低不能少于100分
|
|||
'remark' => '无备注', //订单备注
|
|||
'rider_pick_method' => 1, //物流流向,1:从门店取件送至用户;2:从用户取件送至门店
|
|||
'return_flag' => 511, //1:商品总价格,2:配送距离,4:物品重量,8:起送时间,16:期望送达时间,32:支付费用,64:实际支持金额,128:优惠券总金额,256:结算方式,例如全部返回为填入511
|
|||
'push_time' => time(), //必填,推单时间,秒级时间戳(格林尼治时间)
|
|||
'version' => 17, //版本号 参照文档主版本号填写 如:文档版本号1.7,version=17
|
|||
'receive' => [ //收货人信息 Obj,详见receive结构
|
|||
'user_name' => '', //必填,用户姓名
|
|||
'user_phone' => '', //必填,用户电话
|
|||
'user_address' => '', //必填,用户详细地址
|
|||
'user_lng' => 0, //必填,用户地址经度
|
|||
'user_lat' => 0, //必填,用户地址纬度
|
|||
// 'city_name' => '', //发单城市 用来校验是否跨城;请填写城市的中文名称,如北京市、深圳市
|
|||
], |
|||
/*'shop' => [ //发货店铺信息;obj,详见shop结构,平台级开发者需要传入
|
|||
'shop_name' => '店铺姓名', |
|||
'shop_phone' => '店铺电话', |
|||
'shop_address' => '店铺地址', |
|||
'shop_lng' => '店铺经度', |
|||
'shop_lat' => '店铺纬度', |
|||
],*/ |
|||
'order_detail' => [ // 必填,订单详情
|
|||
'total_price' => 0, //用户订单商品总金额(单位:分) 100 表示1元(最大值为100万, 超过此值则按100万计算)
|
|||
'product_type' => 10, //必填,物品类型。1:快餐,2:药品,3:百货,4:脏衣服收,5:干净衣服派,6:生鲜,其它详见文档
|
|||
// 'user_money' => 0, // 用户实付商家金额(单位:分) 100 表示1元
|
|||
// 'shop_money' => 0, // 商家实收用户金额(单位:分) 100 表示1元
|
|||
'weight_gram' => 0, // 必填,物品重量(单位:克) 100 表示100g
|
|||
// 'volume_litre' => 0, // 物品体积(单位:升) 1 表示1升
|
|||
// 'delivery_money' => 0, // 商家收取用户的配送费(单位:分) 100 表示1元
|
|||
'product_num' => 1, // 必填,物品个数
|
|||
'product_type_num' => 1, // 必填,物品种类个数
|
|||
'product_detail' => [ // 必填,物品种类个数
|
|||
[ |
|||
'product_name' => '', // 必填,物品名称
|
|||
// 'product_id' => 1, // 物品ID
|
|||
'product_num' => 1, // 必填,物品数量
|
|||
// 'product_price' => 0, // 物品价格
|
|||
// 'product_unit' => 0, // 物品单位
|
|||
// 'product_remark' => 0, // 备注
|
|||
// 'item_detail' => 0, // 详情
|
|||
], |
|||
], |
|||
], |
|||
/*'multi_pickup_info' => [ //多点取货信息
|
|||
[ |
|||
'pickup_shop_address' => '取货点地址', // 必填,取货点地址
|
|||
'pickup_shop_phone' => '取货点店铺手机号', // 必填,取货点店铺手机号
|
|||
'pickup_shop_name' => '取货点店铺手机号', // 必填,取货点店铺名称
|
|||
'pickup_lng' => '取货点经度', // 必填,取货点经度
|
|||
'pickup_lat' => '取货点纬度', // 必填,取货点纬度
|
|||
'pickup_products' => '', // 必填,取货点店铺物品信息
|
|||
], |
|||
],*/ |
|||
], $params); |
|||
|
|||
return $this->send('/open/api/external/createorder', $params); |
|||
} |
|||
|
|||
/** |
|||
* 取消订单 |
|||
*/ |
|||
public function cancelOrder(array $params): array |
|||
{ |
|||
$params = array_merge([ |
|||
'dev_id' => $this->dev_id, |
|||
'order_id' => $params['order_id'], |
|||
'shop_id' => $this->shop_id, // 使用商家订单号,需要传入shop_id
|
|||
'shop_type' => 1, // 输入shop_id,shop_type需必传
|
|||
'order_type' => 2, // 订单ID类型,1、顺丰订单号 2、商家订单号
|
|||
'cancel_code' => 300, |
|||
'push_time' => time(), |
|||
], $params); |
|||
|
|||
return $this->send('/open/api/external/cancelorder', $params); |
|||
} |
|||
|
|||
/** |
|||
* 获取顺丰同城配送费 |
|||
*/ |
|||
public function getDeliveryCost(array $params): float |
|||
{ |
|||
$res = $this->preCreateOrder($params); |
|||
$real_pay_money = $res['result']['real_pay_money'] ?? null; |
|||
if ($real_pay_money === null) { |
|||
throw new BusinessException(500, '获取配送费失败'); |
|||
} |
|||
return (float)bcdiv($real_pay_money, 100, 2); |
|||
} |
|||
|
|||
/** |
|||
* 获取原始配送费 |
|||
*/ |
|||
public function getOriginDeliveryCost(float $deliveryCost): float |
|||
{ |
|||
return (float)bcadd($deliveryCost,3.50,2); |
|||
} |
|||
|
|||
/** |
|||
* 预创建订单 |
|||
*/ |
|||
private function preCreateOrder(array $params): array |
|||
{ |
|||
if (!isset($params['user_lng'], $params['user_lat'], $params['user_address'], $params['weight'], $params['shop'])) { |
|||
throw new BusinessException(500, '经度、纬度、收货地址、重量、发货店铺信息不能为空'); |
|||
} |
|||
$params = array_merge([ |
|||
'dev_id' => $this->dev_id, //必填
|
|||
'shop_id' => $this->shop_id, //必填
|
|||
'shop_type' => 1, //1:顺丰店铺ID 2:接入方店铺ID
|
|||
'user_lng' => 0, //必填,用户地址经度
|
|||
'user_lat' => 0, //必填,用户地址纬度
|
|||
'user_address' => '', //必填,用户详细地址
|
|||
'weight' => 0, //必填,物品重量(单位:克)
|
|||
'product_type' => 6, //必填,物品类型。1:快餐,2:药品,3:百货,4:脏衣服收,5:干净衣服派,6:生鲜,其它详见文档
|
|||
// 'total_price' => 0, //用户订单总金额(单位:分)
|
|||
'is_appoint' => 0, //必填,是否是预约单,0:非预约单;1:预约单
|
|||
'appoint_type' => 0, //预约单类型,1:预约单送达单;2:预约单上门单,默认:0
|
|||
// 'expect_time' => '', //用户期望送达时间,若传入自此段且时间大于配送时效,则按照预约送达单处理,时间小于配送时效按照立即单处理;appoint_type=1时需必传,秒级时间戳
|
|||
// 'expect_pickup_time' => '', //用户期望上门时间,appoint_type=2时需必传,秒级时间戳
|
|||
// 'lbs_type' => 2, //坐标类型,1:百度坐标,2:高德坐标
|
|||
'pay_type' => 1, //必填,用户支付方式:1、已支付 0、货到付款
|
|||
// 'receive_user_money' => 0, //代收金额,单位:分
|
|||
'is_insured' => 0, //必填,是否保价,0:非保价;1:保价
|
|||
'is_person_direct' => 0, //必填,是否是专人直送订单,0:否;1:是
|
|||
// 'declared_value' => 0, //保价金额
|
|||
// 'gratuity_fee' => 0, //订单小费,不传或者传0为不加小费,单位分,加小费最低不能少于100分
|
|||
'rider_pick_method' => 1, //物流流向,1:从门店取件送至用户;2:从用户取件送至门店
|
|||
'return_flag' => 511, //1:商品总价格,2:配送距离,4:物品重量,8:起送时间,16:期望送达时间,32:支付费用,64:实际支持金额,128:优惠券总金额,256:结算方式,例如全部返回为填入511
|
|||
'push_time' => time(), //必填,推单时间,秒级时间戳(格林尼治时间)
|
|||
/*'shop' => [ //发货店铺信息;obj,详见shop结构,平台级开发者需要传入
|
|||
'shop_name' => '店铺姓名', |
|||
'shop_phone' => '店铺电话', |
|||
'shop_address' => '店铺地址', |
|||
'shop_lng' => '店铺经度', |
|||
'shop_lat' => '店铺纬度', |
|||
], |
|||
'multi_pickup_info' => [ //多点取货信息
|
|||
'pickup_shop_address' => '取货点地址', |
|||
'pickup_lng' => '取货点经度', |
|||
'pickup_lat' => '取货点纬度', |
|||
],*/ |
|||
], $params); |
|||
|
|||
return $this->send('/open/api/external/precreateorder', $params); |
|||
} |
|||
|
|||
/** |
|||
* 发送请求 |
|||
*/ |
|||
public function send(string $url, array $params): array |
|||
{ |
|||
$url = $this->host . $url; |
|||
$url = $url . (str_contains($url, '?') ? '&sign=' . $this->getSign($params) : '?sign=' . $this->getSign($params)); |
|||
|
|||
$res = json_decode($this->clientFactory->create()->post($url, ['json' => $params])->getBody()->getContents(), true); |
|||
if (!$res || !isset($res['error_code']) || $res['error_code'] != 0) { |
|||
throw new BusinessException(500, ($res['error_code'] ?? '') . ':' . ($res['error_msg'] ?? '请求异常')); |
|||
} |
|||
|
|||
return $res; |
|||
} |
|||
|
|||
/** |
|||
* 计算请求签名 |
|||
*/ |
|||
private function getSign(array $params): string |
|||
{ |
|||
$post_data = json_encode($params); |
|||
$sign_char = $post_data . "&{$this->dev_id}&{$this->dev_key}"; |
|||
return base64_encode(md5($sign_char)); |
|||
} |
|||
|
|||
/** |
|||
* 前端传上来的送达时间(如:11:30 - 12:00)转顺丰的expect_time等预约参数 |
|||
*/ |
|||
public function deliveryTimeNote2expectTime(string $deliveryTimeNote): array |
|||
{ |
|||
if (!empty($deliveryTimeNote) && $deliveryTimeNote != '尽快送达' && strpos($deliveryTimeNote, '-') !== false) { |
|||
$arr = array_map(function ($v) { |
|||
return trim($v); |
|||
}, explode('-', $deliveryTimeNote)); |
|||
|
|||
if ($arr[0] && $arr[1]) { |
|||
$startTime = strtotime($arr[0]); |
|||
$endTime = strtotime($arr[1]); |
|||
# 判断是否是有效时间戳
|
|||
if ($startTime > 1650000000 && $endTime > 1650000000) { |
|||
$sfParams['is_appoint'] = 1; |
|||
$sfParams['appoint_type'] = 1; |
|||
$sfParams['expect_time'] = floor(($startTime + $endTime) / 2); |
|||
} |
|||
} |
|||
} |
|||
return $sfParams ?? []; |
|||
} |
|||
} |
|||
@ -0,0 +1,19 @@ |
|||
<?php |
|||
|
|||
declare(strict_types=1); |
|||
|
|||
return [ |
|||
'debug' => env('CCB_DEBUG', false), |
|||
'pymd_cd' => env('CCB_PYMD_CD', ''), |
|||
'mkt_id' => env('CCB_MKT_ID', ''), |
|||
'merchant_id' => env('CCB_MERCHANT_ID', ''), |
|||
'self_profit_ratio' => env('CCB_SELF_PROFIT_RATIO', 0), |
|||
'self_private_key' => env('CCB_SELF_PRIVATE_KEY', ''), |
|||
'bank_public_key' => env('CCB_BANK_PUBLIC_KEY', ''), |
|||
|
|||
'notify_url' => [ |
|||
'online' => env('SITE_HOST').'/v3/ccb/notify/pay', |
|||
//'offline' => env('SITE_HOST') . '/v3/ccb/notify/offline',
|
|||
'refund' => env('SITE_HOST').'/v3/ccb/notify/refund', |
|||
], |
|||
]; |
|||
@ -0,0 +1,100 @@ |
|||
<?php |
|||
|
|||
namespace HyperfTest\Cases; |
|||
|
|||
use App\Service\v3\CcbPaymentService; |
|||
use Hyperf\Utils\ApplicationContext; |
|||
use HyperfTest\HttpTestCase; |
|||
|
|||
class CCBTest extends HttpTestCase |
|||
{ |
|||
// public function testSign()
|
|||
// {
|
|||
// $ccb = ApplicationContext::getContainer()->get(CcbPaymentService::class);
|
|||
//
|
|||
// $data = "Write Once, Run Anywhere";
|
|||
//
|
|||
// $result = $ccb->sign($data);
|
|||
//
|
|||
// $s = 'odUeD1V6obC/j8lUvmFwn6LSQ2DrvaDEin5DKs0FiB/HttboPJncmLisH22Y1grPezE0a+Ij6cdd5Taof8e4A76pKdXA+hDGz0nPMlCRgSF5tHQ6uVXktL/3lqpVTX6ECjRoHmzmo6cAMqVXYQKEl56r4gJcBPW4X4ghRtTgw9AK8+8b8O5EAqxuPxMyhSOYrCsUYRXapezV3uioEReYjvhg/u+kRf662P2nL0ab3szGMXMAoE+JjgMAHR9WCL3Can/5ADgoFff/7kMSxrA7/r94EfkDN50IvRVAx9WBLx3+WWcRRfM6JcqZ91B+g00wYN/OSZHTJDPgV6Ofd5cBpA==';
|
|||
//
|
|||
// $this->assertTrue($result == $s);
|
|||
// }
|
|||
//
|
|||
// public function testCreateSign()
|
|||
// {
|
|||
// $ccb = ApplicationContext::getContainer()->get(CcbPaymentService::class);
|
|||
//
|
|||
// $params = json_decode('{"Blank3":" ","Blank2":"","Sign_Inf":"signInf","Rsp_Inf":"rspInf","Svc_Rsp_St":"svcRspSt","Svc_Rsp_Cd":"svcRspCd","Amt":"amt","Pymd_Cd":"pymdCd","Parlist":[{"Seq_No":"seqNo","Mkt_Mrch_Id":"mktMrchIdFj"},{"Seq_No":"seqNo","Xbb":[{"sdc":"1131","xyz":"xxxx"}],"Mkt_Mrch_Id":"mktMrchIdFj2"},{"Seq_No":"seqNo3","Mkt_Mrch_Id":"mktMrchIdFj3"}]}', true);
|
|||
//
|
|||
// $str = $ccb->createSign($params);
|
|||
//
|
|||
// $s = 'Amt=amt&Mkt_Mrch_Id=mktMrchIdFj&Seq_No=seqNo&Mkt_Mrch_Id=mktMrchIdFj2&Seq_No=seqNo&sdc=1131&xyz=xxxx&Mkt_Mrch_Id=mktMrchIdFj3&Seq_No=seqNo3&Pymd_Cd=pymdCd';
|
|||
//
|
|||
// $this->assertTrue($str == $s);
|
|||
// }
|
|||
|
|||
// public function testOrder()
|
|||
// {
|
|||
// $ccb = ApplicationContext::getContainer()->get(CcbPaymentService::class);
|
|||
//
|
|||
// $subOrderList[] = $ccb->subOrderListItem(
|
|||
// '41060860800469000000',
|
|||
// '151201',
|
|||
// '0.50',
|
|||
// '0.50'
|
|||
// );
|
|||
//
|
|||
// $subOrderList[] = $ccb->subOrderListItem(
|
|||
// '41060860800469061877',
|
|||
// '151202',
|
|||
// '1.02',
|
|||
// '1.02'
|
|||
// );
|
|||
//
|
|||
// $subOrderList[] = $ccb->subOrderListItem(
|
|||
// '41060860800469061878',
|
|||
// '151203',
|
|||
// '2.30',
|
|||
// '2.30'
|
|||
// );
|
|||
//
|
|||
// $result = $ccb->gatherPlaceorder(
|
|||
// '202208212237008561189348', //$ccb->genSerialNumber(),
|
|||
// 'm2020060915410278993',
|
|||
// '3.82',
|
|||
// '3.82',
|
|||
// '03',
|
|||
// '',
|
|||
// '',
|
|||
// $subOrderList
|
|||
// );
|
|||
//
|
|||
// var_export($result);
|
|||
// }
|
|||
|
|||
// public function testQuery()
|
|||
// {
|
|||
// $ccb = ApplicationContext::getContainer()->get(CcbPaymentService::class);
|
|||
//
|
|||
// $result = $ccb->gatherEnquireOrder('m2020060915410278990');
|
|||
//
|
|||
// var_export($result);
|
|||
// }
|
|||
//
|
|||
// public function testOrderInfQuery()
|
|||
// {
|
|||
// $ccb = ApplicationContext::getContainer()->get(CcbPaymentService::class);
|
|||
//
|
|||
// $result = $ccb->orderInfQuery('m2020060915410278990', '10500000780012708212236595958H');
|
|||
//
|
|||
// var_export($result);
|
|||
// }
|
|||
|
|||
public function testCreateCcbPayment() |
|||
{ |
|||
$ccb = ApplicationContext::getContainer()->get(CcbPaymentService::class); |
|||
$resul = $ccb->createCcbPayment('415142026151948289', 193155); |
|||
var_export($resul); |
|||
} |
|||
} |
|||
@ -0,0 +1,3 @@ |
|||
/pages/orderSubmit/orderSubmit.vue约490行增加 |
|||
shopcart_ids: that.shopcart_ids, |
|||
delivery_time_note: that.order_info.appointment_time.distribution[that.time_index].value, |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue