From 6d1928b1aeb8170d31ee974d78d5e43c2ec6e882 Mon Sep 17 00:00:00 2001 From: li kesong Date: Fri, 22 Jul 2022 20:39:31 +0800 Subject: [PATCH] =?UTF-8?q?=E5=BB=BA=E8=A1=8C=E6=94=AF=E4=BB=98=EF=BC=88?= =?UTF-8?q?=E6=94=AF=E4=BB=98=E7=9A=84=E5=88=86=E8=B4=A6=E5=8F=82=E6=95=B0?= =?UTF-8?q?=E6=9C=AA=E5=AE=8C=E5=96=84=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MySQL_change.sql | 8 + app/Controller/v3/CcbNotifyController.php | 287 ++++++++++++++++++ app/Service/v3/CcbPay.php | 218 +++++++++++++ .../v3/Implementations/CcbPayService.php | 152 ++++++++++ config/autoload/dependencies.php | 4 +- config/routes.php | 8 + test/Cases/CcbTest.php | 16 + 7 files changed, 691 insertions(+), 2 deletions(-) create mode 100644 MySQL_change.sql create mode 100644 app/Controller/v3/CcbNotifyController.php create mode 100644 app/Service/v3/CcbPay.php create mode 100644 app/Service/v3/Implementations/CcbPayService.php create mode 100644 test/Cases/CcbTest.php diff --git a/MySQL_change.sql b/MySQL_change.sql new file mode 100644 index 0000000..efe5345 --- /dev/null +++ b/MySQL_change.sql @@ -0,0 +1,8 @@ +# TODO 屏蔽提现接口 +# 2022-05-01 11:57 +ALTER TABLE `lanzu_order_main` + ADD COLUMN `py_trn_no` VARCHAR(50) NOT NULL DEFAULT '' COMMENT '建行生成的支付流水号' AFTER `pay_time`; + +# 2022-05-01 19:05 +ALTER TABLE `lanzu_store` + ADD COLUMN `card_no` VARCHAR(100) NULL DEFAULT '' COMMENT '银行卡号(用于建行接口分账)' AFTER `cash_code_img`; \ No newline at end of file diff --git a/app/Controller/v3/CcbNotifyController.php b/app/Controller/v3/CcbNotifyController.php new file mode 100644 index 0000000..18c719c --- /dev/null +++ b/app/Controller/v3/CcbNotifyController.php @@ -0,0 +1,287 @@ + '主订单编号', + 'Py_Trn_No' => 'Py_Trn_No', + 'Ordr_Amt' => '订单金额', + 'Txnamt' => '支付金额', + 'Pay_Time' => '支付时间', + 'Ordr_Stcd' => '2成功 3失败 4失效', + 'TYPE' => '非必输。Pymd_cd=‘05’返回,支付宝:ALIPAY 微信:WEIXIN 建行:CCB 银联:UNIONPAY(暂不支付)', + 'Sign_Inf' => '签名参数', + ];*/ + + $formData = $this->request->all(); + try { + /*if (!CcbPay::getInstance()->SHA256WithRSAVerify($formData)) { + throw new BusinessException(500, '签名验证失败,收到的数据为:' . json_encode($formData)); + }*/ + + if (!isset($formData['Ordr_Stcd']) || $formData['Ordr_Stcd'] != 2) { + throw new BusinessException(500, 'Ordr_Stcd状态码异常:' . ($formData['Ordr_Stcd'] ?? 'null')); + } else if (!isset($formData['Main_Ordr_No'])) { + throw new BusinessException(500, '未获取到订单号Main_Ordr_No'); + } + + $orderMain = OrderMain::where([ + 'global_order_id' => $formData['Main_Ordr_No'], + 'type' => OrderType::ONLINE, + 'state' => OrderState::UNPAID + ])->first(); + + if (!$orderMain) { + throw new BusinessException(500, $formData['Main_Ordr_No'] . '订单不存在!'); + } + + $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); + + co(function () use ($orderMain) { + $openid = User::query()->where(['id' => $orderMain->user_id])->value('openid'); + $unionid = $this->userInfoService->getPaidUnionId($openid, ['mch_id' => config('wxpay.mch_id'), 'out_trade_no' => $orderMain->global_order_id]); + if ($unionid) { + User::query()->where(['id' => $orderMain->user_id, 'openid' => $openid])->update(['unionid' => $unionid]); + } + }); + + return $this->response->json(['Svc_Rsp_St' => '00', 'Rsp_Inf' => 'success']); // 00成功;01失败 + } catch (Exception $exception) { + $this->log->event( + LogLabel::ORDER_ONLINE_PAY_NOTIFY_LOG, + ['exception_fail' => $exception->getMessage()] + ); + return $this->response->json(['Svc_Rsp_St' => '01', 'Rsp_Inf' => $exception->getMessage()]); // 00成功;01失败 + } + } + + /** + * 退款通知 + */ + public function refund(): ResponseInterface + { + /*$formData = [ + 'Ittparty_Tms' => '发起方时间戳 yyyymmddhhmmssfff', + 'Ittparty_Jrnl_No' => '该笔直连交易的客户方流水号(不允许重复)', + 'Py_Trn_No' => '支付流水号', + 'Cust_Rfnd_Trcno' => '请求时送入客户方退款流水号,则返回送入的值,否则该字段为空。', + 'Super_Refund_No' => '惠市宝生成,与退款动作唯一匹配', + 'Rfnd_Amt' => '退款金额', + 'Refund_Rsp_St' => '00-退款成功 01-退款失败', + 'Refund_Rsp_Inf' => '退款响应信息', + 'Sign_Inf' => '签名信息', + ];*/ + + $formData = $this->request->all(); + Db::beginTransaction(); + try { + /*if (!CcbPay::getInstance()->SHA256WithRSAVerify($formData)) { + throw new BusinessException(500, '签名验证失败,收到的数据为:' . json_encode($formData)); + }*/ + + if (!isset($formData['Refund_Rsp_St'])) { + throw new BusinessException(500, 'Refund_Rsp_St状态码异常:' . ($formData['Ordr_Stcd'] ?? 'null')); + } else if (!isset($formData['Ittparty_Jrnl_No'])) { + throw new BusinessException(500, '未获取到订单号Ittparty_Jrnl_No'); + } + + $orderMain = OrderMain::whereNotIn('state', [OrderState::UNPAID]) + ->where(['global_order_id' => $formData['Ittparty_Jrnl_No']]) + ->first(); + + if (!$orderMain) { + throw new BusinessException(500, $formData['Ittparty_Jrnl_No'] . '订单不存在!'); + } else if ($orderMain->state == OrderState::REFUNDED) { + return $this->response->json(['Svc_Rsp_St' => '00', 'Ittparty_Tms' => date('YmdHis000'), 'Rsp_Inf' => 'success']); + } else if ($formData['Refund_Rsp_St'] != '00') { // 建行返回退款失败 + $orderMain->state = OrderState::REFUND_REFUSE; + $orderMain->refuse_refund_note = '建行拒绝退款'; + $orderMain->save(); + Db::commit(); + + return $this->response->json(['Svc_Rsp_St' => '00', 'Ittparty_Tms' => date('YmdHis000'), 'Rsp_Inf' => 'success']); // 00成功;01失败 + } + + // 添加退款时间 + $orderMain->refund_time = time(); + $orderMain->state = OrderState::REFUNDED; + $orderMain->save(); + + // 退款返还优惠券 + $this->couponService->orderRefundCoupons($orderMain->global_order_id); + + // 处理特价商品缓存 + $orderChildren = Order::query()->where(['order_main_id' => $orderMain->global_order_id])->get()->toArray(); + $orderGoods = OrderGoods::query()->whereIn('order_id', array_values(array_column($orderChildren, 'id')))->get()->toArray(); + foreach ($orderGoods as &$item) { + if ($item['activity_type'] == 2) { # 活动商品 + $this->goodsActivityService->clearCacheRecord($item['goods_id'], $item['number'], $orderMain->user_id); + $goods = GoodsActivity::find($item['goods_id']); + } else { + $goods = Goods::find($item['goods_id']); + } + $goods->inventory = $goods->inventory + $item['number']; + $goods->sales = $goods->sales - $item['number']; + $goods->save(); + } + + // 添加用户的流水 + $this->financialService->userByOLOrderRefund($orderMain->user_id, $orderMain->global_order_id, $orderMain->money); + + Db::commit(); + + // 记录badge + $orderChildIds = array_values(array_column($orderChildren, 'store_id')); + $this->badgeService->doByOrder($orderMain->user_id, $orderChildIds, $orderMain->global_order_id, OrderState::REFUNDED); + + return $this->response->json(['Svc_Rsp_St' => '00', 'Ittparty_Tms' => date('YmdHis000'), 'Rsp_Inf' => 'success']); // 00成功;01失败 + } catch (\Exception $exception) { + Db::rollBack(); + $this->log->event( + LogLabel::ORDER_ONLINE_PAY_NOTIFY_LOG, + ['exception_fail' => $exception->getMessage()] + ); + return $this->response->json(['Svc_Rsp_St' => '01', 'Ittparty_Tms' => date('YmdHis000'), 'Rsp_Inf' => $exception->getMessage()]); // 00成功;01失败 + } + } +} \ No newline at end of file diff --git a/app/Service/v3/CcbPay.php b/app/Service/v3/CcbPay.php new file mode 100644 index 0000000..8b3960e --- /dev/null +++ b/app/Service/v3/CcbPay.php @@ -0,0 +1,218 @@ +privateKey = env('CCB_SELF_PRIVATE_KEY'); + $this->privateKey = "-----BEGIN RSA PRIVATE KEY-----\n" . chunk_split($this->privateKey, 64, "\n") . "-----END RSA PRIVATE KEY-----\n"; + + $this->publicKey = env('CCB_BANK_PUBLIC_KEY'); + $this->publicKey = "-----BEGIN PUBLIC KEY-----\n" . chunk_split($this->publicKey, 64, "\n") . "-----END PUBLIC KEY-----\n"; + + $this->clientFactory = ApplicationContext::getContainer()->get(ClientFactory::class); + } + + public static function getInstance(): CcbPay + { + if (self::$_instance === null) { + self::$_instance = new self(); + } + return self::$_instance; + } + + /** + * 发起退款 + */ + public function refundOrder(array $args): array + { + if (!isset($args['Ittparty_Jrnl_No'], $args['Py_Trn_No'])) { + throw new BusinessException(500, '交易流水号、支付流水号不能为空'); + } + + $params = array_merge([ + 'Ittparty_Stm_Id' => '00000', //固定5个0 + 'Py_Chnl_Cd' => '0000000000000000000000000', // 因定25个0 + 'Ittparty_Tms' => date('YmdHis999'), // 时间yyyymmddhhmmssfff,年月日, 时分秒,毫秒 + 'Ittparty_Jrnl_No' => '', //该笔直连交易的客户方流水号(不允许重复) + 'Mkt_Id' => env('CCB_MKT_ID'), //14位市场编号,该字段由银行在正式上线前提供,测试阶段有测试数据 + 'Py_Trn_No' => '', // 支付流水号,由建行生成,与该订单的支付动作唯一匹配 + // 'Rfnd_Amt' => 0, // 订单全额退款时不需要送,订单部分退款时必须送此值,且值等于所有子订单的退款金额之和 + /*'Sub_Ordr_List' => [ // 子订单列表,主订单全额退款时不需要传该域 + + ],*/ + 'Vno' => '3', // 非必输 + ], $args); + + return $this->send('/online/direct/refundOrder', $params); + } + + /** + * 创建订单 + */ + public function gatherPlaceOrder(array $args): array + { + if (!isset($args['Ittparty_Jrnl_No'], $args['Main_Ordr_No'], $args['Ordr_Tamt'], $args['Txn_Tamt'], $args['Sub_Openid'], $args['Orderlist'])) { + throw new BusinessException(500, '流水号、主订单流水号、付款金额、实付总金额、openid、Orderlist不能为空'); + } + + $params = array_merge([ + 'Ittparty_Stm_Id' => '00000', //固定5个0 + 'Py_Chnl_Cd' => '0000000000000000000000000', // 因定25个0 + 'Ittparty_Tms' => date('YmdHis888'), // 时间yyyymmddhhmmssfff,年月日, 时分秒,毫秒 + 'Ittparty_Jrnl_No' => '', //该笔直连交易的客户方流水号(不允许重复) + 'Mkt_Id' => env('CCB_MKT_ID'), //14位市场编号,该字段由银行在正式上线前提供,测试阶段有测试数据 + 'Main_Ordr_No' => '', // 客户方主订单流水号,不允许重复 + 'Pymd_Cd' => env('CCB_PYMD_CD'), // 03 移动端H5页面 (app) 05 微信小程序(无收银台) + 'Py_Ordr_Tpcd' => '04', //02 消费券购买订单 03 在途订单(只有是否支持在途模式为“是”时才可以使用)(注:品类管控市场订单类型必须为03) 04普通订单 + 'Py_Rslt_Ntc_Sn' => '1', // 支付结果通知给市场方维护的指定地址序号,对应建行后台设置的地址,1-10之间 + 'Ccy' => '156', // 156人民币 + 'Ordr_Tamt' => 0, // 应付总金额 + 'Txn_Tamt' => $args['Txn_Tamt'] ?? $args['Ordr_Tamt'], // 消费者实付总金额 + 'Sub_Appid' => env('APP_ID'), // “Pymd_Cd(支付方式代码)”为“05-微信小程序”时必输;当前调起支付的小程序APPID + 'Sub_Openid' => '', // “Pymd_Cd(支付方式代码)”为“05-微信小程序”时必输;用户在小程序appid下的唯一标识 + 'Orderlist' => [ + 'Ordr_Amt' => $args['Ordr_Amt'] ?? $args['Ordr_Tamt'], // 订单商品总金额,即应付金额,所有商品订单金额之和等于主订单金额; + 'Cmdty_Ordr_No' => '', // 返显输入接口中的客户方子订单编号 + 'Txnamt' => $args['Txnamt'] ?? $args['Ordr_Tamt'], // 消费者实付金额,所有商品订单金额之和等于主交易总金额金额 + 'Mkt_Mrch_Id' => '41060860800469061877', // 商家编号 + 'Clrg_Rule_Id' => 'F410608608004691879', // 分账规则编号,1.“Py_Ordr_Tpcd(订单类型)”为“02-消费券购买订单”时该字段无效,可不送;2.走默认分账策略,可不送;3.多个子订单时不可送 + 'Parlist' => [ + ['Seq_No' => '1', 'Mkt_Mrch_Id' => '41060860800469061878'], // Seq_No:参与方顺序号(默认从1开始);Mkt_Mrch_Id:商家编号 + ['Seq_No' => '2', 'Mkt_Mrch_Id' => '41060860800469000000'], + ] + ], + 'Vno' => '4', + ], $args); + + return $this->send('/online/direct/gatherPlaceorder', $params); + } + + /** + * 发送请求 + */ + private function send(string $url, array &$params): array + { + $this->SHA256WithRSASign($params); // 计算签名,加入签名参数 + + $res = json_decode($this->clientFactory->create()->post($this->host . $url, ['json' => $params])->getBody()->getContents(), true); + if (!$res || !isset($res['Svc_Rsp_St']) || $res['Svc_Rsp_St'] != '00') { + throw new BusinessException(500, ($res['Rsp_Inf'] ?? '请求异常')); + } else if (env('APP_ENV') != 'prod' && (!isset($res['Sign_Inf']) || !$this->SHA256WithRSAVerify($res))) { + throw new BusinessException(500, '返回数据签名验证失败'); + } + + return $res; + } + + /** + * SHA256WithRSA加密 + */ + private function SHA256WithRSAEncrypt(string $data): string + { + openssl_private_encrypt( + $data, + $encrypted_data, + openssl_get_privatekey($this->privateKey), + ); + return base64_encode($encrypted_data); + } + + /** + * SHA256WithRSA解密 + */ + private function SHA256WithRSADecrypt(string $data) + { + openssl_public_decrypt( + base64_decode($data), + $decrypted_data, + openssl_get_publickey($this->publicKey), + OPENSSL_ALGO_SHA256 + ); + return $decrypted_data; + } + + /** + * SHA256WithRSA生成签名 + * @param array $params 请求的参数 + */ + private function SHA256WithRSASign(array &$params) + { + $this->kSort($params); + openssl_sign( + $this->joinStr($params), + $binary_signature, + openssl_get_privatekey($this->privateKey), + OPENSSL_ALGO_SHA256, + ); + $params['Sign_Inf'] = base64_encode($binary_signature); + } + + /** + * 字符串验签 + * openssl_verify => 1:签名正确;0:签名不正确;-1:验签出错error + * @param array $params 请求接口后返回的数组 + * @return bool + */ + public function SHA256WithRSAVerify(array $params): bool + { + // 公共参数不参与签名 + $sign = $params['Sign_Inf']; + unset($params['Sign_Inf'], $params['Svc_Rsp_St'], $params['Svc_Rsp_Cd'], $params['Rsp_Inf']); + + $this->kSort($params); + return openssl_verify( + $this->joinStr($params), + base64_decode($sign), + openssl_get_publickey($this->publicKey), + OPENSSL_ALGO_SHA256 + ) === 1; + } + + /** + * 数据按key排序,包括子元素 + */ + private function kSort(array &$params) + { + ksort($params); + foreach ($params as &$item) { + if (is_array($item)) { + $this->kSort($item); + } + } + } + + /** + * 字符串拼接 + */ + private function joinStr(array $params): string + { + $str = ''; + foreach ($params as $key => $item) { + if ($item === '' || $item === []) { // 如果参数的值为空则不参与签名 + continue; + } + if (is_array($item)) { + $str .= (empty($str) ? '' : '&') . $this->joinStr($item); + } else { + $str .= (empty($str) ? '' : '&') . $key . '=' . $item; + } + } + return $str; + } +} \ No newline at end of file diff --git a/app/Service/v3/Implementations/CcbPayService.php b/app/Service/v3/Implementations/CcbPayService.php new file mode 100644 index 0000000..45aecad --- /dev/null +++ b/app/Service/v3/Implementations/CcbPayService.php @@ -0,0 +1,152 @@ +=', (time() - 900)) + ->where(['state' => OrderState::UNPAID, 'global_order_id' => $globalOrderId, 'user_id' => $userId]) + ->first(); + + if (empty($orderMain)) { + throw new ErrorCodeException(ErrorCode::ORDER_NOT_AVAILABLE, '[支付订单号]' . $globalOrderId); + } + + $payMoney = $orderMain->money; // 注:此处单位是元,不是分 + if (env('APP_ENV') != 'prod' && $orderMain->type == OrderType::ONLINE) { + $payMoney = 0.01; + } + + $user = User::select('openid')->find($userId); + + // 设置分账规则 + $order = Order::with('store:id,card_no')->where('order_main_id', $globalOrderId)->get(); + $parList = []; + $seqNo = 1; + foreach ($order as $item) { + if (!empty($item->store->card_no)) { + $parList[] = [ + 'Seq_No' => $seqNo, + 'Mkt_Mrch_Id' => $item->store->card_no, +// 'Amt' => 0, // TODO 分账金额 + ]; + $seqNo++; + } + } + + $res = CcbPay::getInstance()->gatherPlaceOrder([ + 'Ittparty_Jrnl_No' => $globalOrderId, + 'Main_Ordr_No' => $globalOrderId, + 'Ordr_Tamt' => $payMoney, // 订单总金额 + 'Txn_Tamt' => $payMoney, // 应付金额 + 'Sub_Openid' => $user['openid'], + 'Orderlist' => [ + 'Ordr_Amt' => $payMoney, // 订单商品总金额,即应付金额,所有商品订单金额之和等于主订单金额; + 'Cmdty_Ordr_No' => $globalOrderId, // 返显输入接口中的客户方子订单编号 + 'Txnamt' => $payMoney, // 消费者实付金额,所有商品订单金额之和等于主交易总金额金额 + 'Mkt_Mrch_Id' => env('CCB_MKT_MRCH_ID'), // 商家编号 + 'Clrg_Rule_Id' => env('CCB_CLRG_RULE_ID'), // 分账规则编号,1.“Py_Ordr_Tpcd(订单类型)”为“02-消费券购买订单”时该字段无效,可不送;2.走默认分账策略,可不送;3.多个子订单时不可送 + 'Parlist' => $parList, + ], + ]); + + // 保存一下 $res['Py_Trn_No'] 参数,后续退款等都会用到 + $orderMain->py_trn_no = $res['Py_Trn_No']; + $orderMain->save(); + + // 返回支付参数给前端 + return [ + 'appId' => $res['Rtn_Par_Data']['appid'], + 'timeStamp' => $res['Rtn_Par_Data']['timeStamp'], + 'nonceStr' => $res['Rtn_Par_Data']['nonceStr'], + 'package' => $res['Rtn_Par_Data']['package'], + 'signType' => $res['Rtn_Par_Data']['signType'], + 'paySign' => $res['Rtn_Par_Data']['paySign'], + 'order_main_id' => $globalOrderId, + ]; + } catch (\Exception $e) { + $this->log->event(LogLabel::ORDER_PAYMENT_LOG, ['payment_do_exception_msg' => $e->getMessage()]); + throw new ErrorCodeException(ErrorCode::PAYMENT_FAIL, '[稍后重试]'); + } + } + + public function check() + { + // TODO: Implement check() method. + } + + /** + * 退款的整单,用户申请的退款 + * @param $globalOrderId + * @param $userId + * @return bool + */ + public function undo($globalOrderId, $userId) + { + try{ + // 已支付的,未退款的,使用微信(或建行)支付的订单 + $orderMain = OrderMain::query() + ->whereIn('state', [OrderState::PAID, OrderState::DELIVERY, OrderState::COMPLETED, OrderState::EVALUATED, OrderState::REFUNDING]) + ->where(['global_order_id' => $globalOrderId, 'user_id' => $userId, 'pay_type' => Payment::WECHAT, 'refund_time' => 0]) + ->first(); + + if (empty($orderMain)) { + throw new ErrorCodeException(ErrorCode::ORDER_NOT_AVAILABLE, '[支付订单号]' . $globalOrderId); + } + + $result = CcbPay::getInstance()->refundOrder([ + 'Ittparty_Jrnl_No' => $globalOrderId, + 'Py_Trn_No' => $orderMain->py_trn_no, + ]); + + if (!isset($result['Refund_Rsp_St'])) { // 接口返回异常 + throw new ErrorCodeException(ErrorCode::REFUND_PAYMENT_FAIL, '退款异常,操作失败'); + } else if ($result['Refund_Rsp_St'] == '01') { + throw new ErrorCodeException(ErrorCode::REFUND_PAYMENT_FAIL, '退款失败'); + } else if ($result['Refund_Rsp_St'] == '02') { + throw new ErrorCodeException(ErrorCode::REFUND_PAYMENT_FAIL, '退款延迟等待'); + } else if ($result['Refund_Rsp_St'] == '03') { + throw new ErrorCodeException(ErrorCode::REFUND_PAYMENT_FAIL, '退款结果不确定,请稍后查看退款结果'); + } + + return true; + } catch (\Exception $e) { + $this->log->event(LogLabel::ORDER_REFUND_LOG, ['payment_do_exception_msg' => $e->getMessage()]); + throw new ErrorCodeException(ErrorCode::REFUND_PAYMENT_FAIL); + } + } + + public function payToWx($money, $tradeNo, $openId, $userName, $desc = '', $checkName = 'NO_CHECK') + { + throw new ErrorCodeException(500, 'payToWx未实现'); + } +} \ No newline at end of file diff --git a/config/autoload/dependencies.php b/config/autoload/dependencies.php index ae5d01c..d93e954 100644 --- a/config/autoload/dependencies.php +++ b/config/autoload/dependencies.php @@ -66,7 +66,7 @@ return [ \App\Service\v3\Interfaces\GoodsActivityServiceInterface::class => \App\Service\v3\Implementations\GoodsActivityService::class, \App\Service\v3\Interfaces\RevenueListServiceInterface::class => \App\Service\v3\Implementations\RevenueListService::class, \App\Service\v3\Interfaces\CouponRecServiceInterface::class => \App\Service\v3\Implementations\CouponRecService::class, - \App\Service\v3\Interfaces\PaymentServiceInterface::class => \App\Service\v3\Implementations\PaymentService::class, + \App\Service\v3\Interfaces\PaymentServiceInterface::class => \App\Service\v3\Implementations\CcbPayService::class, \App\Service\v3\Interfaces\WithdrawalListServiceInterface::class => \App\Service\v3\Implementations\WithdrawalListService::class, \App\Service\v3\Interfaces\OrderOfflineServiceInterface::class => \App\Service\v3\Implementations\OrderOfflineService::class, \App\Service\v3\Interfaces\BusinessHoursServiceInterface::class => \App\Service\v3\Implementations\BusinessHoursService::class, @@ -93,4 +93,4 @@ return [ \App\Service\v3\Interfaces\GoodsInventoryServiceInterface::class => \App\Service\v3\Implementations\GoodsInventoryService::class, \App\Service\v3\Interfaces\HorsemanServiceInterface::class => \App\Service\v3\Implementations\HorsemanService::class, \App\Service\v3\Interfaces\ShareInfoServiceInterface::class => \App\Service\v3\Implementations\ShareInfoService::class, -]; +]; \ No newline at end of file diff --git a/config/routes.php b/config/routes.php index a5f6040..f605f4a 100644 --- a/config/routes.php +++ b/config/routes.php @@ -9,6 +9,8 @@ declare(strict_types=1); * @contact group@hyperf.io * @license https://github.com/hyperf/hyperf/blob/master/LICENSE */ + +use App\Controller\v3\CcbNotifyController; use Hyperf\HttpServer\Router\Router; Router::addRoute(['GET', 'POST', 'HEAD'], '/', 'App\Controller\IndexController@index'); @@ -186,4 +188,10 @@ Router::addGroup('/v3/wechat/',function () { Router::post('notify/online', 'App\Controller\v3\NotifyController@wxminiOnline'); Router::post('notify/offline', 'App\Controller\v3\NotifyController@wxminiOffline'); Router::post('notify/refund', 'App\Controller\v3\NotifyController@wxminiRefund'); +}); + +// 建行支付回调 +Router::addGroup('/v3/ccb', function () { + Router::post('/pay_result', [CcbNotifyController::class, 'payResult']); + Router::post('/refund', [CcbNotifyController::class, 'refund']); }); \ No newline at end of file diff --git a/test/Cases/CcbTest.php b/test/Cases/CcbTest.php new file mode 100644 index 0000000..470e024 --- /dev/null +++ b/test/Cases/CcbTest.php @@ -0,0 +1,16 @@ +SHA256WithRSAEncrypt('123456'); + echo PHP_EOL, '222222222222222', PHP_EOL; + } +} \ No newline at end of file