From 12802838183a481810474438d4eb49513256bae9 Mon Sep 17 00:00:00 2001 From: xiaochong0302 Date: Mon, 11 May 2020 19:50:28 +0800 Subject: [PATCH] =?UTF-8?q?=E6=95=B4=E7=90=86=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Console/Tasks/OrderTask.php | 11 +++ app/Http/Admin/Controllers/TestController.php | 13 +--- app/Http/Admin/Services/AlipayTest.php | 13 +++- app/Http/Web/Controllers/OrderController.php | 6 +- app/Http/Web/Controllers/PayController.php | 74 ------------------- app/Http/Web/Controllers/RefundController.php | 68 +++++++++++++++++ app/Http/Web/Controllers/TradeController.php | 11 +-- app/Http/Web/Services/Trade.php | 59 +++++++++++++++ .../{ConfirmInfo.php => OrderConfirm.php} | 27 ++++--- app/Services/Frontend/Order/OrderCreate.php | 2 + app/Services/Frontend/Order/OrderInfo.php | 47 ++++++++---- app/Services/Frontend/Pay/Alipay.php | 35 --------- app/Services/Frontend/Pay/Wxpay.php | 25 ------- app/Services/Frontend/Refund/RefundCancel.php | 32 ++++++++ .../Frontend/Refund/RefundConfirm.php | 36 +++++++++ app/Services/Frontend/Refund/RefundCreate.php | 53 +++++++++++++ app/Services/Frontend/Refund/RefundInfo.php | 34 +++++++++ app/Services/Frontend/RefundTrait.php | 24 ++++++ app/Services/Frontend/Trade/TradeCreate.php | 63 ++-------------- app/Services/Frontend/Trade/TradeInfo.php | 1 - app/Services/Pay.php | 7 ++ app/Services/Pay/Alipay.php | 58 +++++++++------ app/Services/Pay/Wxpay.php | 68 +++++++++++++---- app/Services/Refund.php | 40 ++-------- app/Validators/Order.php | 42 +++++++---- app/Validators/Refund.php | 21 +++++- config/errors.php | 1 + 27 files changed, 546 insertions(+), 325 deletions(-) delete mode 100644 app/Http/Web/Controllers/PayController.php create mode 100644 app/Http/Web/Controllers/RefundController.php create mode 100644 app/Http/Web/Services/Trade.php rename app/Services/Frontend/Order/{ConfirmInfo.php => OrderConfirm.php} (84%) delete mode 100644 app/Services/Frontend/Pay/Alipay.php delete mode 100644 app/Services/Frontend/Pay/Wxpay.php create mode 100644 app/Services/Frontend/Refund/RefundCancel.php create mode 100644 app/Services/Frontend/Refund/RefundConfirm.php create mode 100644 app/Services/Frontend/Refund/RefundCreate.php create mode 100644 app/Services/Frontend/Refund/RefundInfo.php create mode 100644 app/Services/Frontend/RefundTrait.php diff --git a/app/Console/Tasks/OrderTask.php b/app/Console/Tasks/OrderTask.php index b0285153..bc384afd 100644 --- a/app/Console/Tasks/OrderTask.php +++ b/app/Console/Tasks/OrderTask.php @@ -55,6 +55,9 @@ class OrderTask extends Task case OrderModel::ITEM_VIP: $this->handleVipOrder($order); break; + case OrderModel::ITEM_REWARD: + $this->handleRewardOrder($order); + break; } $task->status = TaskModel::STATUS_FINISHED; @@ -162,6 +165,14 @@ class OrderTask extends Task } } + /** + * @param OrderModel $order + */ + protected function handleRewardOrder(OrderModel $order) + { + + } + /** * @param OrderModel $order */ diff --git a/app/Http/Admin/Controllers/TestController.php b/app/Http/Admin/Controllers/TestController.php index 8ea8a85a..474545c6 100644 --- a/app/Http/Admin/Controllers/TestController.php +++ b/app/Http/Admin/Controllers/TestController.php @@ -176,23 +176,14 @@ class TestController extends Controller $order = $alipayTestService->createOrder(); $trade = $alipayTestService->createTrade($order); - $code = $alipayTestService->scan($trade); + $codeUrl = $alipayTestService->scan($trade); - if ($order && $trade && $code) { + if ($order && $trade && $codeUrl) { $this->db->commit(); } else { $this->db->rollback(); } - $codeUrl = null; - - if (!empty($code)) { - $codeUrl = $this->url->get( - ['for' => 'web.qrcode_img'], - ['text' => urlencode($code)] - ); - } - $this->view->pick('setting/pay_alipay_test'); $this->view->setVar('trade_sn', $trade->sn); $this->view->setVar('code_url', $codeUrl); diff --git a/app/Http/Admin/Services/AlipayTest.php b/app/Http/Admin/Services/AlipayTest.php index 8269c20e..68a98328 100644 --- a/app/Http/Admin/Services/AlipayTest.php +++ b/app/Http/Admin/Services/AlipayTest.php @@ -17,9 +17,18 @@ class AlipayTest extends PayTest { $alipayService = new AlipayService(); - $qrcode = $alipayService->scan($trade); + $code = $alipayService->scan($trade); - return $qrcode ?: false; + $codeUrl = null; + + if ($code) { + $codeUrl = $this->url->get( + ['for' => 'web.qrcode_img'], + ['text' => urlencode($code)] + ); + } + + return $codeUrl ?: false; } public function status($tradeNo) diff --git a/app/Http/Web/Controllers/OrderController.php b/app/Http/Web/Controllers/OrderController.php index ec7637ad..80f019cd 100644 --- a/app/Http/Web/Controllers/OrderController.php +++ b/app/Http/Web/Controllers/OrderController.php @@ -34,7 +34,11 @@ class OrderController extends Controller $order = $service->handle(); - return $this->jsonSuccess(['sn' => $order->sn]); + $service = new OrderInfoService(); + + $order = $service->handle($order->sn); + + return $this->jsonSuccess(['order' => $order]); } /** diff --git a/app/Http/Web/Controllers/PayController.php b/app/Http/Web/Controllers/PayController.php deleted file mode 100644 index 9884f5c2..00000000 --- a/app/Http/Web/Controllers/PayController.php +++ /dev/null @@ -1,74 +0,0 @@ -notify(); - - if (!$response) exit; - - $response->send(); - - exit; - } - - /** - * @Post("/wxpay/notify", name="web.wxpay.notify") - */ - public function wxpayNotifyAction() - { - $wxpayService = new WxpayService(); - - $response = $wxpayService->notify(); - - if (!$response) exit; - - $response->send(); - - exit; - } - - /** - * @Post("/alipay/status", name="web.alipay.status") - */ - public function alipayStatusAction() - { - $sn = $this->request->getPost('sn'); - - $alipayService = new AlipayService(); - - $status = $alipayService->status($sn); - - return $this->jsonSuccess(['status' => $status]); - } - - /** - * @Post("/wxpay/status", name="web.wxpay.status") - */ - public function wxpayStatusAction() - { - $sn = $this->request->getPost('sn'); - - $wxpayService = new WxpayService(); - - $status = $wxpayService->status($sn); - - return $this->jsonSuccess(['status' => $status]); - } - -} diff --git a/app/Http/Web/Controllers/RefundController.php b/app/Http/Web/Controllers/RefundController.php new file mode 100644 index 00000000..7bc197c4 --- /dev/null +++ b/app/Http/Web/Controllers/RefundController.php @@ -0,0 +1,68 @@ +handle(); + + $this->view->setVar('info', $info); + } + + /** + * @Post("/create", name="web.refund.create") + */ + public function createAction() + { + $service = new RefundCreateService(); + + $refund = $service->handle(); + + $service = new RefundInfoService(); + + $refund = $service->handle($refund->sn); + + return $this->jsonSuccess(['refund' => $refund]); + } + + /** + * @Get("/{sn:[0-9]+}/info", name="web.refund.info") + */ + public function infoAction($sn) + { + $service = new RefundInfoService(); + + $refund = $service->handle($sn); + + return $this->jsonSuccess(['refund' => $refund]); + } + + /** + * @Post("/{sn:[0-9]+}/cancel", name="web.refund.cancel") + */ + public function cancelAction($sn) + { + $service = new RefundCancelService(); + + $refund = $service->handle($sn); + + return $this->jsonSuccess(['refund' => $refund]); + } + +} diff --git a/app/Http/Web/Controllers/TradeController.php b/app/Http/Web/Controllers/TradeController.php index f41f8b0f..86217b7d 100644 --- a/app/Http/Web/Controllers/TradeController.php +++ b/app/Http/Web/Controllers/TradeController.php @@ -2,7 +2,7 @@ namespace App\Http\Web\Controllers; -use App\Services\Frontend\Trade\TradeCreate as TradeCreateService; +use App\Http\Web\Services\Trade as TradeService; use App\Services\Frontend\Trade\TradeInfo as TradeInfoService; /** @@ -16,14 +16,11 @@ class TradeController extends Controller */ public function createAction() { - $service = new TradeCreateService(); + $service = new TradeService(); - $result = $service->handle(); + $content = $service->create(); - return $this->jsonSuccess([ - 'trade_sn' => $result['trade_sn'], - 'code_url' => $result['code_url'], - ]); + return $this->jsonSuccess($content); } /** diff --git a/app/Http/Web/Services/Trade.php b/app/Http/Web/Services/Trade.php new file mode 100644 index 00000000..c0d47370 --- /dev/null +++ b/app/Http/Web/Services/Trade.php @@ -0,0 +1,59 @@ +db->begin(); + + $service = new TradeCreateService(); + + $trade = $service->handle(); + + $qrCodeUrl = $this->getQrCodeUrl($trade); + + if ($trade && $qrCodeUrl) { + + $this->db->commit(); + + return [ + 'sn' => $trade->sn, + 'channel' => $trade->channel, + 'qrcode_url' => $qrCodeUrl, + ]; + + } else { + + $this->db->rollback(); + + throw new BadRequestException('trade.create_failed'); + } + } + + protected function getQrCodeUrl(TradeModel $trade) + { + $qrCodeUrl = null; + + $alipayService = new AlipayService(); + + $text = $alipayService->scan($trade); + + if ($text) { + $qrCodeUrl = $this->url->get( + ['for' => 'web.qrcode_img'], + ['text' => urlencode($text)] + ); + } + + return $qrCodeUrl; + } + +} diff --git a/app/Services/Frontend/Order/ConfirmInfo.php b/app/Services/Frontend/Order/OrderConfirm.php similarity index 84% rename from app/Services/Frontend/Order/ConfirmInfo.php rename to app/Services/Frontend/Order/OrderConfirm.php index a7e80780..f7212b48 100644 --- a/app/Services/Frontend/Order/ConfirmInfo.php +++ b/app/Services/Frontend/Order/OrderConfirm.php @@ -34,21 +34,21 @@ class OrderConfirm extends Service $course = $validator->checkCourse($itemId); - $result['item_info']['course'] = $this->handleCourse($course); + $result['item_info']['course'] = $this->handleCourseInfo($course); $result['amount'] = $user->vip ? $course->vip_price : $course->market_price; } elseif ($itemType == OrderModel::ITEM_PACKAGE) { $package = $validator->checkPackage($itemId); - $result['item_info']['package'] = $this->handlePackage($package); + $result['item_info']['package'] = $this->handlePackageInfo($package); $result['amount'] = $user->vip ? $package->vip_price : $package->market_price; } elseif ($itemType == OrderModel::ITEM_VIP) { $vip = $validator->checkVip($itemId); - $result['item_info']['vip'] = $this->handleVip($vip); + $result['item_info']['vip'] = $this->handleVipInfo($vip); $result['amount'] = $vip->price; } elseif ($itemType == OrderModel::ITEM_REWARD) { @@ -58,8 +58,8 @@ class OrderConfirm extends Service $course = $validator->checkCourse($courseId); $reward = $validator->checkReward($rewardId); - $result['item_info']['course'] = $this->handleCourse($course); - $result['item_info']['reward'] = $this->handleReward($reward); + $result['item_info']['course'] = $this->handleCourseInfo($course); + $result['item_info']['reward'] = $this->handleRewardInfo($reward); $result['amount'] = $reward->price; } @@ -68,12 +68,12 @@ class OrderConfirm extends Service return $result; } - protected function handleCourse(CourseModel $course) + protected function handleCourseInfo(CourseModel $course) { - return $this->formatCourse($course); + return $this->formatCourseInfo($course); } - protected function handlePackage(PackageModel $package) + protected function handlePackageInfo(PackageModel $package) { $result = [ 'id' => $package->id, @@ -87,13 +87,13 @@ class OrderConfirm extends Service $courses = $packageRepo->findCourses($package->id); foreach ($courses as $course) { - $result['courses'][] = $this->formatCourse($course); + $result['courses'][] = $this->formatCourseInfo($course); } return $result; } - protected function handleVip(VipModel $vip) + protected function handleVipInfo(VipModel $vip) { return [ 'id' => $vip->id, @@ -103,7 +103,7 @@ class OrderConfirm extends Service ]; } - protected function handleReward(RewardModel $reward) + protected function handleRewardInfo(RewardModel $reward) { return [ 'id' => $reward->id, @@ -112,16 +112,15 @@ class OrderConfirm extends Service ]; } - protected function formatCourse(CourseModel $course) + protected function formatCourseInfo(CourseModel $course) { - $course->cover = kg_ci_img_url($course->cover); - return [ 'id' => $course->id, 'title' => $course->title, 'cover' => $course->cover, 'model' => $course->model, 'level' => $course->level, + 'rating' => $course->rating, 'study_expiry' => $course->study_expiry, 'refund_expiry' => $course->refund_expiry, 'market_price' => $course->market_price, diff --git a/app/Services/Frontend/Order/OrderCreate.php b/app/Services/Frontend/Order/OrderCreate.php index b706ff86..ce9bd36c 100644 --- a/app/Services/Frontend/Order/OrderCreate.php +++ b/app/Services/Frontend/Order/OrderCreate.php @@ -199,6 +199,8 @@ class OrderCreate extends Service $studyExpiryTime = strtotime("+{$course->study_expiry} months"); $refundExpiryTime = strtotime("+{$course->refund_expiry} days"); + $course->cover = CourseModel::getCoverPath($course->cover); + return [ 'id' => $course->id, 'title' => $course->title, diff --git a/app/Services/Frontend/Order/OrderInfo.php b/app/Services/Frontend/Order/OrderInfo.php index 8f398f74..4c7e0322 100644 --- a/app/Services/Frontend/Order/OrderInfo.php +++ b/app/Services/Frontend/Order/OrderInfo.php @@ -23,12 +23,10 @@ class OrderInfo extends Service $order->item_info = $this->handleItemInfo($order); return [ - 'id' => $order->id, 'sn' => $order->sn, 'subject' => $order->subject, 'amount' => $order->amount, 'status' => $order->status, - 'user_id' => $order->user_id, 'item_id' => $order->item_id, 'item_type' => $order->item_type, 'item_info' => $order->item_info, @@ -43,30 +41,37 @@ class OrderInfo extends Service */ $itemInfo = $order->item_info; - if ($order->item_type == OrderModel::ITEM_COURSE) { + $result = []; - return $this->handleCourseInfo($itemInfo); - - } elseif ($order->item_type == OrderModel::ITEM_PACKAGE) { - - return $this->handlePackageInfo($itemInfo); - - } elseif ($order->item_type == OrderModel::ITEM_VIP) { - - return $this->handleVipInfo($itemInfo); + switch ($order->item_type) { + case OrderModel::ITEM_COURSE: + $result = $this->handleCourseInfo($itemInfo); + break; + case OrderModel::ITEM_PACKAGE: + $result = $this->handlePackageInfo($itemInfo); + break; + case OrderModel::ITEM_VIP: + $result = $this->handleVipInfo($itemInfo); + break; + case OrderModel::ITEM_REWARD: + $result = $this->handleRewardInfo($itemInfo); + break; + case OrderModel::ITEM_TEST: + $result = $this->handleTestInfo($itemInfo); + break; } - return $itemInfo; + return $result ?: new \stdClass(); } - protected function handleCourseInfo(array $itemInfo) + protected function handleCourseInfo($itemInfo) { $itemInfo['course']['cover'] = kg_ci_img_url($itemInfo['course']['cover']); return $itemInfo; } - protected function handlePackageInfo(array $itemInfo) + protected function handlePackageInfo($itemInfo) { $baseUrl = kg_ci_base_url(); @@ -77,7 +82,17 @@ class OrderInfo extends Service return $itemInfo; } - protected function handleVipInfo(array $itemInfo) + protected function handleVipInfo($itemInfo) + { + return $itemInfo; + } + + protected function handleRewardInfo($itemInfo) + { + return $itemInfo; + } + + protected function handleTestInfo($itemInfo) { return $itemInfo; } diff --git a/app/Services/Frontend/Pay/Alipay.php b/app/Services/Frontend/Pay/Alipay.php deleted file mode 100644 index 13f007c3..00000000 --- a/app/Services/Frontend/Pay/Alipay.php +++ /dev/null @@ -1,35 +0,0 @@ -scan($trade); - - if ($text) { - $qrCodeUrl = $this->url->get( - ['for' => 'web.qrcode_img'], - ['text' => urlencode($text)] - ); - } - - return $qrCodeUrl; - } - - public function wap(TradeModel $trade) - { - - } - -} diff --git a/app/Services/Frontend/Pay/Wxpay.php b/app/Services/Frontend/Pay/Wxpay.php deleted file mode 100644 index 67c9c18e..00000000 --- a/app/Services/Frontend/Pay/Wxpay.php +++ /dev/null @@ -1,25 +0,0 @@ -checkRefundBySn($sn); + + $user = $this->getLoginUser(); + + $validator = new RefundValidator(); + + $validator->checkOwner($user->id, $refund->user_id); + + $refund->status = RefundModel::STATUS_CANCELED; + + $refund->update(); + + return $refund; + } + +} diff --git a/app/Services/Frontend/Refund/RefundConfirm.php b/app/Services/Frontend/Refund/RefundConfirm.php new file mode 100644 index 00000000..cd32744d --- /dev/null +++ b/app/Services/Frontend/Refund/RefundConfirm.php @@ -0,0 +1,36 @@ +request->getQuery('order_sn'); + + $order = $this->checkOrderBySn($sn); + + + } + + protected function handleRefund(RefundModel $refund) + { + return [ + 'sn' => $refund->sn, + 'subject' => $refund->subject, + 'amount' => $refund->amount, + 'status' => $refund->status, + 'apply_note' => $refund->apply_note, + 'review_note' => $refund->review_note, + 'create_time' => $refund->create_time, + ]; + } + +} diff --git a/app/Services/Frontend/Refund/RefundCreate.php b/app/Services/Frontend/Refund/RefundCreate.php new file mode 100644 index 00000000..0dc2f0e2 --- /dev/null +++ b/app/Services/Frontend/Refund/RefundCreate.php @@ -0,0 +1,53 @@ +request->getPost(); + + $order = $this->checkOrderBySn($post['order_sn']); + + $user = $this->getLoginUser(); + + $validator = new OrderValidator(); + + $validator->checkIfAllowRefund($order); + + $refundService = new RefundService(); + + $refundAmount = $refundService->getRefundAmount($order); + + $validator = new RefundValidator(); + + $validator->checkAmount($order->amount, $refundAmount); + + $applyNote = $validator->checkApplyNote($post['apply_note']); + + $refund = new RefundModel(); + + $refund->subject = $order->subject; + $refund->amount = $order->amount; + $refund->apply_note = $applyNote; + $refund->order_id = $order->id; + $refund->trade_id = $order->id; + $refund->user_id = $user->id; + + $refund->create(); + + return $refund; + } + +} diff --git a/app/Services/Frontend/Refund/RefundInfo.php b/app/Services/Frontend/Refund/RefundInfo.php new file mode 100644 index 00000000..703a7dfe --- /dev/null +++ b/app/Services/Frontend/Refund/RefundInfo.php @@ -0,0 +1,34 @@ +checkRefundBySn($sn); + + return $this->handleRefund($refund); + } + + protected function handleRefund(RefundModel $refund) + { + return [ + 'sn' => $refund->sn, + 'subject' => $refund->subject, + 'amount' => $refund->amount, + 'apply_note' => $refund->apply_note, + 'review_note' => $refund->review_note, + 'status' => $refund->status, + 'create_time' => $refund->create_time, + ]; + } + +} diff --git a/app/Services/Frontend/RefundTrait.php b/app/Services/Frontend/RefundTrait.php new file mode 100644 index 00000000..dfca7b1f --- /dev/null +++ b/app/Services/Frontend/RefundTrait.php @@ -0,0 +1,24 @@ +checkRefund($id); + } + + public function checkRefundBySn($id) + { + $validator = new RefundValidator(); + + return $validator->checkRefundBySn($id); + } + +} diff --git a/app/Services/Frontend/Trade/TradeCreate.php b/app/Services/Frontend/Trade/TradeCreate.php index 34e8aa5c..2c3acbc7 100644 --- a/app/Services/Frontend/Trade/TradeCreate.php +++ b/app/Services/Frontend/Trade/TradeCreate.php @@ -5,8 +5,6 @@ namespace App\Services\Frontend\Trade; use App\Models\Trade as TradeModel; use App\Services\Frontend\OrderTrait; use App\Services\Frontend\Service; -use App\Services\Pay\Alipay as AlipayService; -use App\Services\Pay\Wxpay as WxPayService; use App\Validators\Trade as TradeValidator; class TradeCreate extends Service @@ -26,62 +24,17 @@ class TradeCreate extends Service $channel = $validator->checkChannel($post['channel']); - try { + $trade = new TradeModel(); - $this->db->begin(); + $trade->subject = $order->subject; + $trade->amount = $order->amount; + $trade->channel = $channel; + $trade->order_id = $order->id; + $trade->user_id = $user->id; - $trade = new TradeModel(); + $trade->create(); - $trade->subject = $order->subject; - $trade->amount = $order->amount; - $trade->channel = $channel; - $trade->order_id = $order->id; - $trade->user_id = $user->id; - - $trade->create(); - - $qrCodeUrl = $this->getQrCodeUrl($trade); - - $this->db->commit(); - - return [ - 'trade_sn' => $trade->sn, - 'code_url' => $qrCodeUrl, - ]; - - } catch (\Exception $e) { - - $this->db->rollback(); - - throw new \RuntimeException('trade.create_failed'); - } - } - - protected function getQrCodeUrl(TradeModel $trade) - { - $qrCodeUrl = null; - - if ($trade->channel == TradeModel::CHANNEL_ALIPAY) { - - $alipayService = new AlipayService(); - - $text = $alipayService->scan($trade); - - if ($text) { - $qrCodeUrl = $this->url->get( - ['for' => 'web.qrcode_img'], - ['text' => urlencode($text)] - ); - } - - } elseif ($trade->channel == TradeModel::CHANNEL_WXPAY) { - - $wxpayService = new WxPayService(); - - $qrCodeUrl = $wxpayService->scan($trade); - } - - return $qrCodeUrl; + return $trade; } } diff --git a/app/Services/Frontend/Trade/TradeInfo.php b/app/Services/Frontend/Trade/TradeInfo.php index 67fda454..78613b64 100644 --- a/app/Services/Frontend/Trade/TradeInfo.php +++ b/app/Services/Frontend/Trade/TradeInfo.php @@ -21,7 +21,6 @@ class TradeInfo extends Service protected function handleTrade(TradeModel $trade) { return [ - 'id' => $trade->id, 'sn' => $trade->sn, 'subject' => $trade->subject, 'amount' => $trade->amount, diff --git a/app/Services/Pay.php b/app/Services/Pay.php index ead0f515..e4578134 100644 --- a/app/Services/Pay.php +++ b/app/Services/Pay.php @@ -31,6 +31,13 @@ abstract class Pay extends Service */ abstract public function scan(TradeModel $trade); + /** + * h5下单 + * + * @param TradeModel $trade + */ + abstract public function wap(TradeModel $trade); + /** * 异步通知 */ diff --git a/app/Services/Pay/Alipay.php b/app/Services/Pay/Alipay.php index 8c7da3b4..55670e32 100644 --- a/app/Services/Pay/Alipay.php +++ b/app/Services/Pay/Alipay.php @@ -6,6 +6,7 @@ use App\Models\Refund as RefundModel; use App\Models\Trade as TradeModel; use App\Repos\Trade as TradeRepo; use App\Services\Pay as PayService; +use Symfony\Component\HttpFoundation\Response as HttpResponse; use Yansongda\Pay\Gateways\Alipay as AlipayGateway; use Yansongda\Pay\Log; use Yansongda\Pay\Pay; @@ -19,16 +20,19 @@ class Alipay extends PayService */ protected $settings; - /** - * @var AlipayGateway - */ - protected $gateway; - public function __construct() { $this->settings = $this->getSectionSettings('pay.alipay'); + } - $this->gateway = $this->getGateway(); + public function setReturnUrl($returnUrl) + { + $this->settings['return_url'] = $returnUrl; + } + + public function setNotifyUrl($notifyUrl) + { + $this->settings['notify_url'] = $notifyUrl; } /** @@ -39,9 +43,11 @@ class Alipay extends PayService */ public function scan(TradeModel $trade) { + $gateway = $this->getGateway(); + try { - $response = $this->gateway->scan([ + $response = $gateway->scan([ 'out_trade_no' => $trade->sn, 'total_amount' => $trade->amount, 'subject' => $trade->subject, @@ -66,23 +72,23 @@ class Alipay extends PayService * 移动端支付 * * @param TradeModel $trade - * @return bool|string + * @return HttpResponse|bool */ public function wap(TradeModel $trade) { + $gateway = $this->getGateway(); + try { - $response = $this->gateway->wap([ + return $gateway->wap([ 'out_trade_no' => $trade->sn, 'total_amount' => $trade->amount, 'subject' => $trade->subject, ]); - $result = $response->qr_code ?? false; - } catch (\Exception $e) { - Log::error('Alipay Qrcode Exception', [ + Log::error('Alipay Wap Exception', [ 'code' => $e->getCode(), 'message' => $e->getMessage(), ]); @@ -95,12 +101,15 @@ class Alipay extends PayService /** * 异步通知 + * @return HttpResponse|bool */ public function notify() { + $gateway = $this->getGateway(); + try { - $data = $this->gateway->verify(); + $data = $gateway->verify(); Log::debug('Alipay Verify Data', $data->all()); @@ -142,7 +151,7 @@ class Alipay extends PayService $this->eventsManager->fire('pay:afterPay', $this, $trade); - return $this->gateway->success(); + return $gateway->success(); } /** @@ -154,11 +163,13 @@ class Alipay extends PayService */ public function find($outTradeNo, $type = 'wap') { + $gateway = $this->getGateway(); + try { $order = ['out_trade_no' => $outTradeNo]; - $result = $this->gateway->find($order, $type); + $result = $gateway->find($order, $type); } catch (\Exception $e) { @@ -181,11 +192,11 @@ class Alipay extends PayService */ public function close($outTradeNo) { + $gateway = $this->getGateway(); + try { - $response = $this->gateway->close([ - 'out_trade_no' => $outTradeNo, - ]); + $response = $gateway->close(['out_trade_no' => $outTradeNo]); $result = $response->code == '10000'; @@ -210,11 +221,11 @@ class Alipay extends PayService */ public function cancel($outTradeNo) { + $gateway = $this->getGateway(); + try { - $response = $this->gateway->cancel([ - 'out_trade_no' => $outTradeNo, - ]); + $response = $gateway->cancel(['out_trade_no' => $outTradeNo]); $result = $response->code == '10000'; @@ -239,13 +250,15 @@ class Alipay extends PayService */ public function refund(RefundModel $refund) { + $gateway = $this->getGateway(); + try { $tradeRepo = new TradeRepo(); $trade = $tradeRepo->findById($refund->trade_id); - $response = $this->gateway->refund([ + $response = $gateway->refund([ 'out_trade_no' => $trade->sn, 'out_request_no' => $refund->sn, 'refund_amount' => $refund->amount, @@ -281,6 +294,7 @@ class Alipay extends PayService 'app_id' => $this->settings['app_id'], 'ali_public_key' => $this->settings['public_key'], 'private_key' => $this->settings['private_key'], + 'return_url' => $this->settings['return_url'], 'notify_url' => $this->settings['notify_url'], 'log' => [ 'file' => log_path('alipay.log'), diff --git a/app/Services/Pay/Wxpay.php b/app/Services/Pay/Wxpay.php index ab412cac..a4d359da 100644 --- a/app/Services/Pay/Wxpay.php +++ b/app/Services/Pay/Wxpay.php @@ -6,6 +6,7 @@ use App\Models\Refund as RefundModel; use App\Models\Trade as TradeModel; use App\Repos\Trade as TradeRepo; use App\Services\Pay as PayService; +use Symfony\Component\HttpFoundation\Response as HttpResponse; use Yansongda\Pay\Gateways\Wechat as WechatGateway; use Yansongda\Pay\Log; use Yansongda\Pay\Pay; @@ -19,16 +20,14 @@ class Wxpay extends PayService */ protected $settings; - /** - * @var WechatGateway - */ - protected $gateway; - public function __construct() { $this->settings = $this->getSectionSettings('pay.wxpay'); + } - $this->gateway = $this->getGateway(); + public function setNotifyUrl($notifyUrl) + { + $this->settings['notify_url'] = $notifyUrl; } /** @@ -39,9 +38,11 @@ class Wxpay extends PayService */ public function scan(TradeModel $trade) { + $gateway = $this->getGateway(); + try { - $response = $this->gateway->scan([ + $response = $gateway->scan([ 'out_trade_no' => $trade->sn, 'total_fee' => 100 * $trade->amount, 'body' => $trade->subject, @@ -62,14 +63,49 @@ class Wxpay extends PayService return $result; } + /** + * 移动端支付 + * + * @param TradeModel $trade + * @return HttpResponse|bool + */ + public function wap(TradeModel $trade) + { + $gateway = $this->getGateway(); + + try { + + return $gateway->wap([ + 'out_trade_no' => $trade->sn, + 'total_fee' => 100 * $trade->amount, + 'body' => $trade->subject, + ]); + + } catch (\Exception $e) { + + Log::error('Wxpay Wap Exception', [ + 'code' => $e->getCode(), + 'message' => $e->getMessage(), + ]); + + $result = false; + } + + return $result; + } + /** * 异步通知 + * + * @return HttpResponse|bool */ public function notify() { + $gateway = $this->getGateway(); + try { - $data = $this->gateway->verify(); + $data = $gateway->verify(); Log::debug('Wxpay Verify Data', $data->all()); @@ -109,7 +145,7 @@ class Wxpay extends PayService $this->eventsManager->fire('pay:afterPay', $this, $trade); - return $this->gateway->success(); + return $gateway->success(); } /** @@ -121,11 +157,13 @@ class Wxpay extends PayService */ public function find($outTradeNo, $type = 'wap') { + $gateway = $this->getGateway(); + try { $order = ['out_trade_no' => $outTradeNo]; - $result = $this->gateway->find($order, $type); + $result = $gateway->find($order, $type); } catch (\Exception $e) { @@ -148,11 +186,11 @@ class Wxpay extends PayService */ public function close($outTradeNo) { + $gateway = $this->getGateway(); + try { - $response = $this->gateway->close([ - 'out_trade_no' => $outTradeNo, - ]); + $response = $gateway->close(['out_trade_no' => $outTradeNo]); $result = $response->result_code == 'SUCCESS'; @@ -188,13 +226,15 @@ class Wxpay extends PayService */ public function refund(RefundModel $refund) { + $gateway = $this->getGateway(); + try { $tradeRepo = new TradeRepo(); $trade = $tradeRepo->findById($refund->trade_id); - $response = $this->gateway->refund([ + $response = $gateway->refund([ 'out_trade_no' => $trade->sn, 'out_refund_no' => $refund->sn, 'total_fee' => 100 * $trade->amount, diff --git a/app/Services/Refund.php b/app/Services/Refund.php index ac16fd0c..42b1c532 100644 --- a/app/Services/Refund.php +++ b/app/Services/Refund.php @@ -8,11 +8,7 @@ use App\Repos\Course as CourseRepo; class Refund extends Service { - /** - * @param OrderModel $order - * @return float - */ - public function getRefundAmount($order) + public function getRefundAmount(OrderModel $order) { $amount = 0.00; @@ -29,28 +25,20 @@ class Refund extends Service return $amount; } - /** - * @param OrderModel $order - * @return float - */ - protected function getCourseRefundAmount($order) + protected function getCourseRefundAmount(OrderModel $order) { /** * @var array $itemInfo */ $itemInfo = $order->item_info; - $course = $itemInfo['course']; - $courseId = $order->item_id; $userId = $order->user_id; $amount = $order->amount; - $expireTime = strtotime("+{$course['expiry']} days", $order->create_time); - $refundAmount = 0.00; - if ($expireTime > time()) { + if ($itemInfo['course']['refund_expiry_time'] > time()) { $percent = $this->getCourseRefundPercent($courseId, $userId); $refundAmount = $amount * $percent; } @@ -58,25 +46,19 @@ class Refund extends Service return $refundAmount; } - /** - * @param OrderModel $order - * @return float - */ - protected function getPackageRefundAmount($order) + protected function getPackageRefundAmount(OrderModel $order) { /** * @var array $itemInfo */ $itemInfo = $order->item_info; - $courses = $itemInfo['courses']; - $userId = $order->user_id; $amount = $order->amount; $totalMarketPrice = 0.00; - foreach ($courses as $course) { + foreach ($itemInfo['courses'] as $course) { $totalMarketPrice += $course['market_price']; } @@ -85,11 +67,8 @@ class Refund extends Service /** * 按照占比方式计算退款 */ - foreach ($courses as $course) { - - $expireTime = strtotime("+{$course['expiry']} days", $order->create_time); - - if ($expireTime > time()) { + foreach ($itemInfo['courses'] as $course) { + if ($course['refund_expiry_time'] > time()) { $pricePercent = round($course['market_price'] / $totalMarketPrice, 4); $refundPercent = $this->getCourseRefundPercent($userId, $course['id']); $refundAmount = round($amount * $pricePercent * $refundPercent, 2); @@ -100,11 +79,6 @@ class Refund extends Service return $totalRefundAmount; } - /** - * @param int $courseId - * @param int $userId - * @return float - */ protected function getCourseRefundPercent($courseId, $userId) { $courseRepo = new CourseRepo(); diff --git a/app/Validators/Order.php b/app/Validators/Order.php index d14dbe8d..5057f023 100644 --- a/app/Validators/Order.php +++ b/app/Validators/Order.php @@ -59,52 +59,52 @@ class Order extends Validator { $courseRepo = new CourseRepo(); - $item = $courseRepo->findById($itemId); + $course = $courseRepo->findById($itemId); - if (!$item) { + if (!$course) { throw new BadRequestException('order.item_not_found'); } - return $item; + return $course; } public function checkPackage($itemId) { $packageRepo = new PackageRepo(); - $item = $packageRepo->findById($itemId); + $package = $packageRepo->findById($itemId); - if (!$item) { + if (!$package) { throw new BadRequestException('order.item_not_found'); } - return $item; + return $package; } public function checkVip($itemId) { $vipRepo = new VipRepo(); - $item = $vipRepo->findById($itemId); + $vip = $vipRepo->findById($itemId); - if (!$item) { + if (!$vip) { throw new BadRequestException('order.item_not_found'); } - return $item; + return $vip; } public function checkReward($itemId) { $rewardRepo = new RewardRepo(); - $item = $rewardRepo->findById($itemId); + $reward = $rewardRepo->findById($itemId); - if (!$item) { + if (!$reward) { throw new BadRequestException('order.item_not_found'); } - return $item; + return $reward; } public function checkAmount($amount) @@ -118,13 +118,29 @@ class Order extends Validator return $value; } - public function checkIfAllowCancel($order) + public function checkIfAllowCancel(OrderModel $order) { if ($order->status != OrderModel::STATUS_PENDING) { throw new BadRequestException('order.cancel_not_allowed'); } } + public function checkIfAllowRefund(OrderModel $order) + { + if ($order->status != OrderModel::STATUS_FINISHED) { + throw new BadRequestException('order.refund_not_allowed'); + } + + $types = [ + OrderModel::ITEM_COURSE, + OrderModel::ITEM_PACKAGE, + ]; + + if (!in_array($order->item_type, $types)) { + throw new BadRequestException('order.refund_not_allowed'); + } + } + public function checkIfBoughtCourse($userId, $courseId) { $orderRepo = new OrderRepo(); diff --git a/app/Validators/Refund.php b/app/Validators/Refund.php index 1e4cc917..8932d475 100644 --- a/app/Validators/Refund.php +++ b/app/Validators/Refund.php @@ -42,7 +42,10 @@ class Refund extends Validator public function checkReviewStatus($status) { - $list = [RefundModel::STATUS_APPROVED, RefundModel::STATUS_REFUSED]; + $list = [ + RefundModel::STATUS_APPROVED, + RefundModel::STATUS_REFUSED, + ]; if (!in_array($status, $list)) { throw new BadRequestException('refund.invalid_review_status'); @@ -51,6 +54,13 @@ class Refund extends Validator return $status; } + public function checkAmount($orderAmount, $refundAmount) + { + if ($refundAmount > $orderAmount) { + throw new BadRequestException('refund.invalid_amount'); + } + } + public function checkApplyNote($note) { $value = $this->filter->sanitize($note, ['trim', 'string']); @@ -85,7 +95,14 @@ class Refund extends Validator return $value; } - public function checkIfAllowReview($refund) + public function checkIfAllowCancel(RefundModel $refund) + { + if ($refund->status != RefundModel::STATUS_PENDING) { + throw new BadRequestException('refund.cancel_not_allowed'); + } + } + + public function checkIfAllowReview(RefundModel $refund) { if ($refund->status != RefundModel::STATUS_PENDING) { throw new BadRequestException('refund.review_not_allowed'); diff --git a/config/errors.php b/config/errors.php index 1ccb8a5d..fd74a4fc 100644 --- a/config/errors.php +++ b/config/errors.php @@ -278,6 +278,7 @@ $error['refund.apply_note_too_short'] = '退款原因太短(少于2个字符 $error['refund.apply_note_too_long'] = '退款原因太长(多于255个字符)'; $error['refund.review_note_too_short'] = '审核备注太短(少于2个字符)'; $error['refund.review_note_too_long'] = '审核备注太长(多于255个字符)'; +$error['refund.cancel_not_allowed'] = '当前不允许取消退款'; $error['refund.review_not_allowed'] = '当前不允许审核退款'; $error['refund.invalid_review_status'] = '无效的审核状态';