diff --git a/CHANGELOG.md b/CHANGELOG.md index 6cb084df..60350d56 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,17 @@ +### [v1.2.8](https://gitee.com/koogua/course-tencent-cloud/releases/v1.2.8)(2021-03-08) + +### 更新 + +- 数据库迁移脚本整理 +- 数据表软删除字段整理 +- 微信公众号路由整理 +- 退款增加手续费逻辑 +- 课程增加不支持退款逻辑 +- 会员价格和期限可通过后台配置 +- 修复IM通知中字段重命名导致的问题 +- 修复购买会员会员标识未改变的问题 +- 会员中心订单列表样式调整 + ### [v1.2.7](https://gitee.com/koogua/course-tencent-cloud/releases/v1.2.7)(2021-02-26) ### 新增 diff --git a/app/Console/Tasks/RefundTask.php b/app/Console/Tasks/RefundTask.php index 1a3556ff..c85f3ba9 100644 --- a/app/Console/Tasks/RefundTask.php +++ b/app/Console/Tasks/RefundTask.php @@ -39,8 +39,8 @@ class RefundTask extends Task $itemInfo = $task->item_info; $refund = $refundRepo->findById($itemInfo['refund']['id']); - $trade = $tradeRepo->findById($itemInfo['refund']['trade_id']); - $order = $orderRepo->findById($itemInfo['refund']['order_id']); + $trade = $tradeRepo->findById($refund->trade_id); + $order = $orderRepo->findById($refund->order_id); if (!$refund || !$trade || !$order) { $task->status = TaskModel::STATUS_FAILED; diff --git a/app/Http/Admin/Controllers/SettingController.php b/app/Http/Admin/Controllers/SettingController.php index 1a79a60e..cae94452 100644 --- a/app/Http/Admin/Controllers/SettingController.php +++ b/app/Http/Admin/Controllers/SettingController.php @@ -282,7 +282,7 @@ class SettingController extends Controller if ($this->request->isPost()) { - $data = $this->request->getPost('vip', 'string'); + $data = $this->request->getPost('vip'); $settingService->updateVipSettings($data); @@ -290,9 +290,9 @@ class SettingController extends Controller } else { - $vips = $settingService->getVipSettings(); + $items = $settingService->getVipSettings(); - $this->view->setVar('vips', $vips); + $this->view->setVar('items', $items); } } diff --git a/app/Http/Admin/Controllers/TradeController.php b/app/Http/Admin/Controllers/TradeController.php index 2600351f..98d35538 100644 --- a/app/Http/Admin/Controllers/TradeController.php +++ b/app/Http/Admin/Controllers/TradeController.php @@ -3,6 +3,7 @@ namespace App\Http\Admin\Controllers; use App\Http\Admin\Services\Trade as TradeService; +use Phalcon\Mvc\View; /** * @RoutePrefix("/admin/trade") @@ -70,25 +71,26 @@ class TradeController extends Controller } /** - * @Post("/{id:[0-9]+}/refund", name="admin.trade.refund") + * @Route("/{id:[0-9]+}/refund", name="admin.trade.refund") */ public function refundAction($id) { $tradeService = new TradeService(); - $refund = $tradeService->refundTrade($id); + if ($this->request->isPost()) { - $location = $this->url->get([ - 'for' => 'admin.refund.show', - 'id' => $refund->id, - ]); + $tradeService->refundTrade($id); - $content = [ - 'location' => $location, - 'msg' => '申请退款成功', - ]; + return $this->jsonSuccess(['msg' => '提交申请成功']); + } - return $this->jsonSuccess($content); + $this->view->setRenderLevel(View::LEVEL_ACTION_VIEW); + + $trade = $tradeService->getTrade($id); + $confirm = $tradeService->confirmRefund($id); + + $this->view->setVar('trade', $trade); + $this->view->setVar('confirm', $confirm); } } diff --git a/app/Http/Admin/Services/Setting.php b/app/Http/Admin/Services/Setting.php index 5989b2ac..a1340246 100644 --- a/app/Http/Admin/Services/Setting.php +++ b/app/Http/Admin/Services/Setting.php @@ -91,7 +91,7 @@ class Setting extends Service { $vipRepo = new VipRepo(); - return $vipRepo->findAll(['deleted' => 0]); + return $vipRepo->findAll(); } public function getLiveSettings($section) @@ -198,9 +198,13 @@ class Setting extends Service { $vipRepo = new VipRepo(); - foreach ($items as $id => $price) { + foreach ($items as $id => $item) { $vip = $vipRepo->findById($id); - $vip->price = $price; + if (!$vip) continue; + $vip->title = sprintf('%s个月', $item['expiry']); + $vip->expiry = (int)$item['expiry']; + $vip->price = (float)$item['price']; + $vip->deleted = (int)$item['deleted']; $vip->update(); } } diff --git a/app/Http/Admin/Services/Trade.php b/app/Http/Admin/Services/Trade.php index 9b818a81..f1d576b3 100644 --- a/app/Http/Admin/Services/Trade.php +++ b/app/Http/Admin/Services/Trade.php @@ -10,6 +10,7 @@ use App\Repos\Account as AccountRepo; use App\Repos\Order as OrderRepo; use App\Repos\Trade as TradeRepo; use App\Repos\User as UserRepo; +use App\Validators\Refund as RefundValidator; use App\Validators\Trade as TradeValidator; class Trade extends Service @@ -93,22 +94,47 @@ class Trade extends Service return $accountRepo->findById($userId); } + public function confirmRefund($tradeId) + { + $trade = $this->findOrFail($tradeId); + + $orderRepo = new OrderRepo(); + + $order = $orderRepo->findById($trade->order_id); + + $refund = new \App\Services\Refund(); + + return $refund->preview($order); + } + public function refundTrade($id) { $trade = $this->findOrFail($id); + $user = $this->getLoginUser(); + + $post = $this->request->getPost(); + $validator = new TradeValidator(); $validator->checkIfAllowRefund($trade); + $validator = new RefundValidator(); + + $applyNote = $validator->checkApplyNote($post['apply_note']); + + $refundAmount = $validator->checkAmount($trade->amount, $post['refund_amount']); + + $applyNote = sprintf('%s - 操作员(%s)', $applyNote, $user->id); + $refund = new RefundModel(); + $refund->amount = $refundAmount; $refund->subject = $trade->subject; - $refund->amount = $trade->amount; $refund->owner_id = $trade->owner_id; $refund->order_id = $trade->order_id; $refund->trade_id = $trade->id; - $refund->apply_note = '后台人工申请退款'; + $refund->apply_note = $applyNote; $refund->create(); diff --git a/app/Http/Admin/Views/order/macro.volt b/app/Http/Admin/Views/order/macro.volt index 7aa625bc..6b6a4847 100644 --- a/app/Http/Admin/Views/order/macro.volt +++ b/app/Http/Admin/Views/order/macro.volt @@ -4,7 +4,7 @@

课程名称:{{ course['title'] }}

优惠价格:{{ '¥%0.2f'|format(course['market_price']) }},会员价格:{{ '¥%0.2f'|format(course['vip_price']) }}

-

学习期限:{{ date('Y-m-d H:i:s',course['study_expiry_time']) }},退款期限:{{ date('Y-m-d H:i:s',course['refund_expiry_time']) }}

+

学习期限:{{ date('Y-m-d H:i:s',course['study_expiry_time']) }},退款期限:{% if course['refund_expiry'] > 0 %}{{ date('Y-m-d H:i:s',course['refund_expiry_time']) }}{% else %}不支持{% endif %}

{% elseif order.item_type == 2 %} {% set courses = order.item_info['courses'] %} @@ -12,7 +12,7 @@

课程名称:{{ course['title'] }}

优惠价格:{{ '¥%0.2f'|format(course['market_price']) }},会员价格:{{ '¥%0.2f'|format(course['vip_price']) }}

-

学习期限:{{ date('Y-m-d H:i:s',course['study_expiry_time']) }},退款期限:{{ date('Y-m-d H:i:s',course['refund_expiry_time']) }}

+

学习期限:{{ date('Y-m-d H:i:s',course['study_expiry_time']) }},退款期限:{% if course['refund_expiry'] > 0 %}{{ date('Y-m-d H:i:s',course['refund_expiry_time']) }}{% else %}不支持{% endif %}

{% endfor %} {% elseif order.item_type == 3 %} diff --git a/app/Http/Admin/Views/setting/pay_alipay.volt b/app/Http/Admin/Views/setting/pay_alipay.volt index ebc1bf6c..9f139dd1 100644 --- a/app/Http/Admin/Views/setting/pay_alipay.volt +++ b/app/Http/Admin/Views/setting/pay_alipay.volt @@ -6,6 +6,17 @@ +
+ +
+ +
+
diff --git a/app/Http/Admin/Views/setting/pay_wxpay.volt b/app/Http/Admin/Views/setting/pay_wxpay.volt index 22cdc504..0c544a65 100644 --- a/app/Http/Admin/Views/setting/pay_wxpay.volt +++ b/app/Http/Admin/Views/setting/pay_wxpay.volt @@ -6,6 +6,17 @@
+
+ +
+ +
+
diff --git a/app/Http/Admin/Views/setting/point.volt b/app/Http/Admin/Views/setting/point.volt index 93fc26cd..ff566cb7 100644 --- a/app/Http/Admin/Views/setting/point.volt +++ b/app/Http/Admin/Views/setting/point.volt @@ -36,7 +36,7 @@
行为奖励规则
- +
diff --git a/app/Http/Admin/Views/setting/vip.volt b/app/Http/Admin/Views/setting/vip.volt index 4c39a072..3631a9a2 100644 --- a/app/Http/Admin/Views/setting/vip.volt +++ b/app/Http/Admin/Views/setting/vip.volt @@ -6,15 +6,39 @@
会员设置
- {% for item in vips %} -
- -
- -
-
-
- {% endfor %} +
+ + + + + + + + + + + + + + {% for item in items %} + + + + + + {% endfor %} + +
启用期限价格(元)
+ + + + +
+
diff --git a/app/Http/Admin/Views/trade/refund.volt b/app/Http/Admin/Views/trade/refund.volt new file mode 100644 index 00000000..d5c54c7b --- /dev/null +++ b/app/Http/Admin/Views/trade/refund.volt @@ -0,0 +1,114 @@ +{% extends 'templates/layer.volt' %} + +{% block content %} + + {%- macro item_info(confirm) %} + {% if confirm.item_type == 1 %} + {% set course = confirm.item_info.course %} + {% set expiry_flag = course.refund_expiry_time < time() ? '(已过期)' : '' %} +
+

课程名称:{{ course.title }}

+

退款期限:{{ date('Y-m-d H:i:s',course.refund_expiry_time) }} {{ expiry_flag }}

+

退款金额:{{ '¥%0.2f'|format(course.refund_amount) }},退款比例:{{ 100 * course.refund_percent }}%

+
+ {% elseif confirm.item_type == 2 %} + {% set courses = confirm.item_info.courses %} + {% for course in courses %} + {% set expiry_flag = course.refund_expiry_time < time() ? '(已过期)' : '' %} +
+

课程名称:{{ course.title }}

+

退款期限:{{ date('Y-m-d H:i:s',course.refund_expiry_time) }} {{ expiry_flag }}

+

退款金额:{{ '¥%0.2f'|format(course.refund_amount) }},退款比例:{{ 100 * course.refund_percent }}%

+
+ {% endfor %} + {% elseif confirm.item_type == 3 %} + {% set course = confirm.item_info.course %} + {% set reward = confirm.item_info.reward %} +
+

课程名称:{{ course.title }}

+

赞赏金额:{{ '¥%0.2f'|format(reward.price) }}

+
+ {% elseif confirm.item_type == 4 %} + {% set vip = confirm.item_info.vip %} +
+

服务名称:会员服务({{ vip.title }})

+

会员期限:{{ date('Y-m-d H:i:s',vip.expiry_time) }}

+
+ {% elseif confirm.item_type == 99 %} +
+

服务名称:支付测试

+
+ {% endif %} + {%- endmacro %} + + + + + + + + + + + + + + +
退款项目支付金额手续费({{ confirm.service_rate }}%)退款金额
{{ item_info(confirm) }}{{ '¥%0.2f'|format(trade.amount) }}{{ '¥%0.2f'|format(confirm.service_fee) }} +
{{ '¥%0.2f'|format(confirm.refund_amount) }}
+
+
+
+
+ +
+
+
+
+
+ +
+ +
+
+
+ + + + +
+
+ +{% endblock %} + +{% block inline_js %} + + + +{% endblock %} \ No newline at end of file diff --git a/app/Http/Admin/Views/trade/show.volt b/app/Http/Admin/Views/trade/show.volt index d544e590..2c3142f0 100644 --- a/app/Http/Admin/Views/trade/show.volt +++ b/app/Http/Admin/Views/trade/show.volt @@ -9,11 +9,11 @@
- {% set trade_refund_url = url({'for':'admin.trade.refund','id':trade.id}) %} + {% set refund_url = url({'for':'admin.trade.refund','id':trade.id}) %}
{% if trade.status == 2 %} - + {% endif %}
@@ -32,15 +32,15 @@ {% for item in refunds %} - {% set refund_sh_url = url({'for':'admin.refund.status_history','id':item.id}) %} - {% set refund_show_url = url({'for':'admin.refund.show','id':item.id}) %} + {% set history_url = url({'for':'admin.refund.status_history','id':item.id}) %} + {% set show_url = url({'for':'admin.refund.show','id':item.id}) %} {{ item.sn }} {{ '¥%0.2f'|format(item.amount) }} {{ substr(item.apply_note,0,15) }} - {{ refund_status(item.status) }} + {{ refund_status(item.status) }} {{ date('Y-m-d H:i:s',item.create_time) }} - 详情 + 详情 {% endfor %} @@ -69,25 +69,15 @@ layui.use(['jquery', 'layer'], function () { var $ = layui.jquery; + var layer = layui.layer; $('.kg-refund').on('click', function () { var url = $(this).data('url'); - var tips = '确定要申请退款吗?'; - layer.confirm(tips, function () { - $.ajax({ - type: 'POST', - url: url, - success: function (res) { - layer.msg(res.msg, {icon: 1}); - setTimeout(function () { - window.location.href = res.location; - }, 3000); - }, - error: function (xhr) { - var json = JSON.parse(xhr.responseText); - layer.msg(json.msg, {icon: 2}); - } - }); + layer.open({ + type: 2, + title: '申请退款', + content: [url, 'no'], + area: ['800px', '320px'] }); }); diff --git a/app/Http/Admin/Views/trade/trade_info.volt b/app/Http/Admin/Views/trade/trade_info.volt index a179b37b..38a24ad3 100644 --- a/app/Http/Admin/Views/trade/trade_info.volt +++ b/app/Http/Admin/Views/trade/trade_info.volt @@ -1,4 +1,4 @@ -{% set trade_sh_url = url({'for':'admin.trade.status_history','id':trade.id}) %} +{% set trade_history_url = url({'for':'admin.trade.status_history','id':trade.id}) %}
交易信息 @@ -16,7 +16,7 @@ {{ trade.sn }} {{ '¥%0.2f'|format(trade.amount) }} {{ channel_type(trade.channel) }} - {{ trade_status(trade.status) }} + {{ trade_status(trade.status) }} {{ date('Y-m-d H:i:s',trade.create_time) }} \ No newline at end of file diff --git a/app/Http/Home/Controllers/WeChatOfficialAccountController.php b/app/Http/Home/Controllers/WeChatOfficialAccountController.php index b67cab4f..7c3a080e 100644 --- a/app/Http/Home/Controllers/WeChatOfficialAccountController.php +++ b/app/Http/Home/Controllers/WeChatOfficialAccountController.php @@ -14,7 +14,7 @@ class WeChatOfficialAccountController extends \Phalcon\Mvc\Controller use ResponseTrait; /** - * @Get("/subscribe/status", name="home.wechat.oa.sub_status") + * @Get("/subscribe/status", name="home.wechat_oa.sub_status") */ public function subscribeStatusAction() { @@ -26,7 +26,7 @@ class WeChatOfficialAccountController extends \Phalcon\Mvc\Controller } /** - * @Get("/subscribe/qrcode", name="home.wechat.oa.sub_qrcode") + * @Get("/subscribe/qrcode", name="home.wechat_oa.sub_qrcode") */ public function subscribeQrCodeAction() { @@ -38,7 +38,7 @@ class WeChatOfficialAccountController extends \Phalcon\Mvc\Controller } /** - * @Get("/notify", name="home.wechat.oa.verify") + * @Get("/notify", name="home.wechat_oa.verify") */ public function verifyAction() { @@ -54,7 +54,7 @@ class WeChatOfficialAccountController extends \Phalcon\Mvc\Controller } /** - * @Post("/notify", name="home.wechat.oa.notify") + * @Post("/notify", name="home.wechat_oa.notify") */ public function notifyAction() { diff --git a/app/Http/Home/Services/ImGroupTrait.php b/app/Http/Home/Services/ImGroupTrait.php index d411e4d6..12ff0985 100644 --- a/app/Http/Home/Services/ImGroupTrait.php +++ b/app/Http/Home/Services/ImGroupTrait.php @@ -60,9 +60,7 @@ Trait ImGroupTrait $notice = $validator->checkNotice($noticeId); - if ($notice->item_type != ImNoticeModel::TYPE_GROUP_REQUEST) { - return; - } + if ($notice->item_type != ImNoticeModel::TYPE_GROUP_REQUEST) return; $groupId = $notice->item_info['group']['id'] ?: 0; @@ -70,7 +68,7 @@ Trait ImGroupTrait $group = $validator->checkGroup($groupId); - $validator->checkOwner($user->id, $group->user_id); + $validator->checkOwner($user->id, $group->owner_id); $applicant = $this->getImUser($notice->sender_id); @@ -120,9 +118,7 @@ Trait ImGroupTrait $notice = $validator->checkNotice($noticeId); - if ($notice->item_type != ImNoticeModel::TYPE_GROUP_REQUEST) { - return; - } + if ($notice->item_type != ImNoticeModel::TYPE_GROUP_REQUEST) return; $groupId = $notice->item_info['group']['id'] ?: 0; @@ -130,7 +126,7 @@ Trait ImGroupTrait $group = $validator->checkGroup($groupId); - $validator->checkOwner($user->id, $group->user_id); + $validator->checkOwner($user->id, $group->owner_id); $itemInfo = $notice->item_info; @@ -282,9 +278,7 @@ Trait ImGroupTrait $users = $groupRepo->findUsers($group->id); - if ($users->count() == 0) { - return; - } + if ($users->count() == 0) return; Gateway::$registerAddress = $this->getRegisterAddress(); diff --git a/app/Http/Home/Views/course/show_meta.volt b/app/Http/Home/Views/course/show_meta.volt index c668df67..8d71dc67 100644 --- a/app/Http/Home/Views/course/show_meta.volt +++ b/app/Http/Home/Views/course/show_meta.volt @@ -28,7 +28,11 @@ {%- macro meta_expiry_info(course) %}

学习期限{{ course.study_expiry }}个月 - 退款期限{{ course.refund_expiry }}天 + {% if course.refund_expiry > 0 %} + 退款期限{{ course.refund_expiry }}天 + {% else %} + 退款期限不支持 + {% endif %}

{%- endmacro %} diff --git a/app/Http/Home/Views/macros/order.volt b/app/Http/Home/Views/macros/order.volt index ed29ab31..8cab1c94 100644 --- a/app/Http/Home/Views/macros/order.volt +++ b/app/Http/Home/Views/macros/order.volt @@ -4,7 +4,7 @@

课程名称:{{ course.title }}

优惠价格:{{ '¥%0.2f'|format(course.market_price) }}会员价格:{{ '¥%0.2f'|format(course.vip_price) }}

-

学习期限:{{ date('Y-m-d',course.study_expiry_time) }}退款期限:{{ date('Y-m-d',course.refund_expiry_time) }}

+

学习期限:{{ date('Y-m-d H:i:s',course.study_expiry_time) }}退款期限:{% if course.refund_expiry > 0 %}{{ date('Y-m-d H:i:s',course.refund_expiry_time) }}{% else %}不支持{% endif %}

{% elseif order.item_type == 2 %} {% set courses = order.item_info.courses %} @@ -12,7 +12,7 @@

课程名称:{{ course.title }}

优惠价格:{{ '¥%0.2f'|format(course.market_price) }}会员价格:{{ '¥%0.2f'|format(course.vip_price) }}

-

学习期限:{{ date('Y-m-d',course.study_expiry_time) }}退款期限:{{ date('Y-m-d',course.refund_expiry_time) }}

+

学习期限:{{ date('Y-m-d H:i:s',course.study_expiry_time) }}退款期限:{% if course.refund_expiry > 0 %}{{ date('Y-m-d H:i:s',course.refund_expiry_time) }}{% else %}不支持{% endif %}

{% endfor %} {% elseif order.item_type == 3 %} diff --git a/app/Http/Home/Views/order/confirm.volt b/app/Http/Home/Views/order/confirm.volt index 365c2a18..290e16bc 100644 --- a/app/Http/Home/Views/order/confirm.volt +++ b/app/Http/Home/Views/order/confirm.volt @@ -13,13 +13,17 @@

{{ course.title }}

- 原始价格 {{ '¥%0.2f'|format(course.origin_price) }} - 优惠价格 {{ '¥%0.2f'|format(course.market_price) }} - 会员价格 {{ '¥%0.2f'|format(course.vip_price) }} + 原始价格{{ '¥%0.2f'|format(course.origin_price) }} + 优惠价格{{ '¥%0.2f'|format(course.market_price) }} + 会员价格{{ '¥%0.2f'|format(course.vip_price) }}

- 学习期限 {{ course.study_expiry }}个月 - 退款期限 {{ course.refund_expiry }}天 + 学习期限{{ course.study_expiry }}个月 + {% if course.refund_expiry > 0 %} + 退款期限{{ course.refund_expiry }}天 + {% else %} + 退款期限不支持 + {% endif %}

diff --git a/app/Http/Home/Views/order/info.volt b/app/Http/Home/Views/order/info.volt index c4472b16..5e4c5234 100644 --- a/app/Http/Home/Views/order/info.volt +++ b/app/Http/Home/Views/order/info.volt @@ -7,7 +7,7 @@ {% set order_pay_url = url({'for':'home.order.pay'},{'sn':order.sn}) %} {% set refund_confirm_url = url({'for':'home.refund.confirm'},{'sn':order.sn}) %} - +
订单金额:{{ '¥%0.2f'|format(order.amount) }} diff --git a/app/Http/Home/Views/refund/confirm.volt b/app/Http/Home/Views/refund/confirm.volt index c19683f9..44715192 100644 --- a/app/Http/Home/Views/refund/confirm.volt +++ b/app/Http/Home/Views/refund/confirm.volt @@ -24,29 +24,31 @@ {% endif %} {%- endmacro %} - +
- + + - + +
退款项目退款金额 订单金额手续费({{ confirm.service_rate }}%)退款金额
{{ item_info(confirm) }}{{ '¥%0.2f'|format(confirm.refund_amount) }} {{ '¥%0.2f'|format(order.amount) }}{{ '¥%0.2f'|format(confirm.service_fee) }}{{ '¥%0.2f'|format(confirm.refund_amount) }}

{% if confirm.refund_amount > 0 %}
-
+
- +
- +
diff --git a/app/Library/AppInfo.php b/app/Library/AppInfo.php index b5df7269..de45a4a2 100644 --- a/app/Library/AppInfo.php +++ b/app/Library/AppInfo.php @@ -11,7 +11,7 @@ class AppInfo protected $link = 'https://koogua.com'; - protected $version = '1.2.7'; + protected $version = '1.2.8'; public function __get($name) { diff --git a/app/Models/Course.php b/app/Models/Course.php index 71285d02..de7e38fd 100644 --- a/app/Models/Course.php +++ b/app/Models/Course.php @@ -408,6 +408,7 @@ class Course extends Model public static function refundExpiryOptions() { return [ + 0 => '0天', 7 => '7天', 14 => '14天', 30 => '30天', diff --git a/app/Models/Vip.php b/app/Models/Vip.php index b6a8446e..5f998438 100644 --- a/app/Models/Vip.php +++ b/app/Models/Vip.php @@ -22,7 +22,7 @@ class Vip extends Model public $title = ''; /** - * 期限(天) + * 期限(月) * * @var int */ diff --git a/app/Services/LiveNotify.php b/app/Services/LiveNotify.php index 82fcc768..f088a6bd 100644 --- a/app/Services/LiveNotify.php +++ b/app/Services/LiveNotify.php @@ -35,9 +35,7 @@ class LiveNotify extends Service 'action' => $action, ])); - if (!$this->checkSign($sign, $time)) { - return false; - } + if (!$this->checkSign($sign, $time)) return false; $result = false; @@ -125,7 +123,7 @@ class LiveNotify extends Service */ protected function handleRecord() { - + return true; } /** @@ -133,7 +131,7 @@ class LiveNotify extends Service */ protected function handleSnapshot() { - + return true; } /** @@ -141,7 +139,7 @@ class LiveNotify extends Service */ protected function handlePorn() { - + return true; } protected function handleStreamBeginNotice(ChapterModel $chapter) @@ -153,9 +151,7 @@ class LiveNotify extends Service $keyName = "live_notify:{$chapter->id}"; - if ($cache->get($keyName)) { - return; - } + if ($cache->get($keyName)) return; $cache->save($keyName, time(), 86400); @@ -163,9 +159,7 @@ class LiveNotify extends Service $courseUsers = $courseUserRepo->findByCourseId($chapter->course_id); - if ($courseUsers->count() == 0) { - return; - } + if ($courseUsers->count() == 0) return; $notice = new LiveBeginNotice(); @@ -206,13 +200,9 @@ class LiveNotify extends Service */ protected function checkSign($sign, $time) { - if (!$sign || !$time) { - return false; - } + if (!$sign || !$time) return false; - if ($time < time()) { - return false; - } + if ($time < time()) return false; $notify = $this->getSettings('live.notify'); diff --git a/app/Services/Logic/Notice/RefundFinish.php b/app/Services/Logic/Notice/RefundFinish.php index 6defe9fb..cec2ff8e 100644 --- a/app/Services/Logic/Notice/RefundFinish.php +++ b/app/Services/Logic/Notice/RefundFinish.php @@ -8,7 +8,7 @@ use App\Repos\Refund as RefundRepo; use App\Repos\User as UserRepo; use App\Repos\WeChatSubscribe as WeChatSubscribeRepo; use App\Services\Logic\Notice\Sms\RefundFinish as SmsRefundFinishNotice; -use App\Services\Logic\Notice\WeChat\OrderFinish as WeChatRefundFinishNotice; +use App\Services\Logic\Notice\WeChat\RefundFinish as WeChatRefundFinishNotice; use App\Services\Logic\Service as LogicService; class RefundFinish extends LogicService diff --git a/app/Services/Logic/Refund/RefundCreate.php b/app/Services/Logic/Refund/RefundCreate.php index bb9749ec..228e52ab 100644 --- a/app/Services/Logic/Refund/RefundCreate.php +++ b/app/Services/Logic/Refund/RefundCreate.php @@ -70,11 +70,7 @@ class RefundCreate extends Service $task = new TaskModel(); $itemInfo = [ - 'refund' => [ - 'id' => $refund->id, - 'order_id' => $refund->order_id, - 'trade_id' => $refund->trade_id, - ], + 'refund' => ['id' => $refund->id], ]; $task->item_id = $refund->id; diff --git a/app/Services/Pay/Alipay.php b/app/Services/Pay/Alipay.php index 25ce01dc..fb65b0fc 100644 --- a/app/Services/Pay/Alipay.php +++ b/app/Services/Pay/Alipay.php @@ -207,15 +207,15 @@ class Alipay extends PayService /** * 查询交易(扫码生成订单后可执行) * - * @param string $outTradeNo + * @param string $tradeNo * @param string $type * @return Collection|bool */ - public function find($outTradeNo, $type = 'wap') + public function find($tradeNo, $type = 'wap') { try { - $order = ['out_trade_no' => $outTradeNo]; + $order = ['out_trade_no' => $tradeNo]; $result = $this->gateway->find($order, $type); @@ -235,14 +235,14 @@ class Alipay extends PayService /** * 关闭交易(扫码生成订单后可执行) * - * @param string $outTradeNo + * @param string $tradeNo * @return bool */ - public function close($outTradeNo) + public function close($tradeNo) { try { - $response = $this->gateway->close(['out_trade_no' => $outTradeNo]); + $response = $this->gateway->close(['out_trade_no' => $tradeNo]); $result = $response->code == '10000'; @@ -262,14 +262,14 @@ class Alipay extends PayService /** * 撤销交易(未生成订单也可执行) * - * @param string $outTradeNo + * @param string $tradeNo * @return bool */ - public function cancel($outTradeNo) + public function cancel($tradeNo) { try { - $response = $this->gateway->cancel(['out_trade_no' => $outTradeNo]); + $response = $this->gateway->cancel(['out_trade_no' => $tradeNo]); $result = $response->code == '10000'; diff --git a/app/Services/Pay/Wxpay.php b/app/Services/Pay/Wxpay.php index 89ee126a..051b3187 100644 --- a/app/Services/Pay/Wxpay.php +++ b/app/Services/Pay/Wxpay.php @@ -208,15 +208,15 @@ class Wxpay extends PayService /** * 查询交易(扫码生成订单后可执行) * - * @param string $outTradeNo + * @param string $tradeNo * @param string $type * @return Collection|bool */ - public function find($outTradeNo, $type = 'wap') + public function find($tradeNo, $type = 'wap') { try { - $order = ['out_trade_no' => $outTradeNo]; + $order = ['out_trade_no' => $tradeNo]; $result = $this->gateway->find($order, $type); @@ -236,14 +236,14 @@ class Wxpay extends PayService /** * 关闭交易(扫码生成订单后可执行) * - * @param string $outTradeNo + * @param string $tradeNo * @return bool */ - public function close($outTradeNo) + public function close($tradeNo) { try { - $response = $this->gateway->close(['out_trade_no' => $outTradeNo]); + $response = $this->gateway->close(['out_trade_no' => $tradeNo]); $result = $response->result_code == 'SUCCESS'; @@ -263,12 +263,12 @@ class Wxpay extends PayService /** * 取消交易 * - * @param string $outTradeNo + * @param string $tradeNo * @return bool */ - public function cancel($outTradeNo) + public function cancel($tradeNo) { - return $this->close($outTradeNo); + return $this->close($tradeNo); } /** diff --git a/app/Services/Refund.php b/app/Services/Refund.php index 124450ea..5b0736ad 100644 --- a/app/Services/Refund.php +++ b/app/Services/Refund.php @@ -3,15 +3,23 @@ namespace App\Services; use App\Models\Order as OrderModel; +use App\Models\Trade as TradeModel; use App\Repos\Course as CourseRepo; use App\Repos\CourseUser as CourseUserRepo; +use App\Repos\Order as OrderRepo; class Refund extends Service { public function preview(OrderModel $order) { - $result = []; + $result = [ + 'item_type' => 0, + 'item_info' => [], + 'refund_amount' => 0.00, + 'service_fee' => 0.00, + 'service_rate' => 5.00, + ]; switch ($order->item_type) { case OrderModel::ITEM_COURSE: @@ -20,6 +28,15 @@ class Refund extends Service case OrderModel::ITEM_PACKAGE: $result = $this->previewPackageRefund($order); break; + case OrderModel::ITEM_REWARD: + $result = $this->previewRewardRefund($order); + break; + case OrderModel::ITEM_VIP: + $result = $this->previewVipRefund($order); + break; + case OrderModel::ITEM_TEST: + $result = $this->previewTestRefund($order); + break; } return $result; @@ -27,19 +44,19 @@ class Refund extends Service protected function previewCourseRefund(OrderModel $order) { - /** - * @var array $itemInfo - */ $itemInfo = $order->item_info; $itemInfo['course']['cover'] = kg_cos_cover_url($itemInfo['course']['cover']); + $serviceFee = $this->getServiceFee($order); + $serviceRate = $this->getServiceRate($order); + $refundPercent = 0.00; $refundAmount = 0.00; if ($itemInfo['course']['refund_expiry_time'] > time()) { $refundPercent = $this->getCourseRefundPercent($order->item_id, $order->owner_id); - $refundAmount = $order->amount * $refundPercent; + $refundAmount = round(($order->amount - $serviceFee) * $refundPercent, 2); } $itemInfo['course']['refund_percent'] = $refundPercent; @@ -49,16 +66,18 @@ class Refund extends Service 'item_type' => $order->item_type, 'item_info' => $itemInfo, 'refund_amount' => $refundAmount, + 'service_fee' => $serviceFee, + 'service_rate' => $serviceRate, ]; } protected function previewPackageRefund(OrderModel $order) { - /** - * @var array $itemInfo - */ $itemInfo = $order->item_info; + $serviceFee = $this->getServiceFee($order); + $serviceRate = $this->getServiceRate($order); + $totalMarketPrice = 0.00; foreach ($itemInfo['courses'] as $course) { @@ -80,7 +99,7 @@ class Refund extends Service if ($course['refund_expiry_time'] > time()) { $pricePercent = round($course['market_price'] / $totalMarketPrice, 4); $refundPercent = $this->getCourseRefundPercent($course['id'], $order->owner_id); - $refundAmount = round($order->amount * $pricePercent * $refundPercent, 2); + $refundAmount = round(($order->amount - $serviceFee) * $pricePercent * $refundPercent, 2); $totalRefundAmount += $refundAmount; } @@ -92,45 +111,97 @@ class Refund extends Service 'item_type' => $order->item_type, 'item_info' => $itemInfo, 'refund_amount' => $totalRefundAmount, + 'service_fee' => $serviceFee, + 'service_rate' => $serviceRate, ]; } + protected function previewRewardRefund(OrderModel $order) + { + return $this->previewOtherRefund($order); + } + + protected function previewVipRefund(OrderModel $order) + { + return $this->previewOtherRefund($order); + } + + protected function previewTestRefund(OrderModel $order) + { + return $this->previewOtherRefund($order); + } + + protected function previewOtherRefund(OrderModel $order) + { + $serviceFee = $this->getServiceFee($order); + $serviceRate = $this->getServiceRate($order); + + $refundAmount = round($order->amount - $serviceFee, 2); + + return [ + 'item_type' => $order->item_type, + 'item_info' => $order->item_info, + 'refund_amount' => $refundAmount, + 'service_fee' => $serviceFee, + 'service_rate' => $serviceRate, + ]; + } + + protected function getServiceFee(OrderModel $order) + { + $serviceRate = $this->getServiceRate($order); + + $serviceFee = round($order->amount * $serviceRate / 100, 2); + + return $serviceFee >= 0.01 ? $serviceFee : 0.00; + } + + protected function getServiceRate(OrderModel $order) + { + $orderRepo = new OrderRepo(); + + $trade = $orderRepo->findLastTrade($order->id); + + $alipay = $this->getSettings('pay.alipay'); + $wxpay = $this->getSettings('pay.wxpay'); + + $serviceRate = 5; + + switch ($trade->channel) { + case TradeModel::CHANNEL_ALIPAY: + $serviceRate = $alipay['service_rate'] ?: $serviceRate; + break; + case TradeModel::CHANNEL_WXPAY: + $serviceRate = $wxpay['service_rate'] ?: $serviceRate; + break; + } + + return $serviceRate; + } + protected function getCourseRefundPercent($courseId, $userId) { $courseRepo = new CourseRepo(); $courseLessons = $courseRepo->findLessons($courseId); - if ($courseLessons->count() == 0) { - return 1.00; - } + if ($courseLessons->count() == 0) return 1.00; $courseUserRepo = new CourseUserRepo(); $courseUser = $courseUserRepo->findCourseUser($courseId, $userId); - if (!$courseUser) { - return 1.00; - } + if (!$courseUser) return 1.00; $userLearnings = $courseRepo->findUserLearnings($courseId, $userId, $courseUser->plan_id); - if ($userLearnings->count() == 0) { - return 1.00; - } + if ($userLearnings->count() == 0) return 1.00; - /** - * @var array $consumedUserLearnings - */ $consumedUserLearnings = $userLearnings->filter(function ($item) { - if ($item->consumed == 1) { - return $item; - } + if ($item->consumed == 1) return $item; }); - if (count($consumedUserLearnings) == 0) { - return 1.00; - } + if (count($consumedUserLearnings) == 0) return 1.00; $courseLessonIds = kg_array_column($courseLessons->toArray(), 'id'); $consumedUserLessonIds = kg_array_column($consumedUserLearnings, 'chapter_id'); diff --git a/app/Validators/Order.php b/app/Validators/Order.php index cdf4f45c..5fc693c9 100644 --- a/app/Validators/Order.php +++ b/app/Validators/Order.php @@ -5,6 +5,7 @@ namespace App\Validators; use App\Exceptions\BadRequest as BadRequestException; use App\Models\Order as OrderModel; use App\Models\Refund as RefundModel; +use App\Models\Trade as TradeModel; use App\Repos\Course as CourseRepo; use App\Repos\Order as OrderRepo; use App\Repos\Package as PackageRepo; @@ -154,6 +155,12 @@ class Order extends Validator $orderRepo = new OrderRepo(); + $trade = $orderRepo->findLastTrade($order->id); + + if ($trade->status != TradeModel::STATUS_FINISHED) { + throw new BadRequestException('order.refund_not_allowed'); + } + $refund = $orderRepo->findLastRefund($order->id); $scopes = [ @@ -174,16 +181,8 @@ class Order extends Validator $order = $orderRepo->findUserLastFinishedOrder($userId, $courseId, $itemType); - if ($order) { - - /** - * @var array $itemInfo - */ - $itemInfo = $order->item_info; - - if ($itemInfo['course']['study_expiry_time'] > time()) { - throw new BadRequestException('order.has_bought_course'); - } + if ($order && $order->item_info['course']['study_expiry_time'] > time()) { + throw new BadRequestException('order.has_bought_course'); } } diff --git a/app/Validators/Refund.php b/app/Validators/Refund.php index 1b309b91..c0a6d37d 100644 --- a/app/Validators/Refund.php +++ b/app/Validators/Refund.php @@ -42,9 +42,15 @@ class Refund extends Validator public function checkAmount($orderAmount, $refundAmount) { + if ($orderAmount <= 0 || $refundAmount <= 0) { + throw new BadRequestException('refund.invalid_amount'); + } + if ($refundAmount > $orderAmount) { throw new BadRequestException('refund.invalid_amount'); } + + return (float)$refundAmount; } public function checkStatus($status) diff --git a/config/errors.php b/config/errors.php index ca812440..326947ff 100644 --- a/config/errors.php +++ b/config/errors.php @@ -289,6 +289,7 @@ $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_amount'] = '无效的退款金额'; $error['refund.invalid_status'] = '无效的状态类型'; /** diff --git a/db/migrations/20210305115507_data_202103051930.php b/db/migrations/20210305115507_data_202103051930.php new file mode 100644 index 00000000..1053b337 --- /dev/null +++ b/db/migrations/20210305115507_data_202103051930.php @@ -0,0 +1,39 @@ + 'pay.alipay', + 'item_key' => 'service_rate', + 'item_value' => 5, + ], + [ + 'section' => 'pay.wxpay', + 'item_key' => 'service_rate', + 'item_value' => 5, + ], + ]; + + $this->table('kg_setting')->insert($rows)->save(); + } + + public function down() + { + $this->getQueryBuilder() + ->delete('kg_setting') + ->where(['section' => 'pay.alipay', 'item_key' => 'service_rate']) + ->execute(); + + $this->getQueryBuilder() + ->delete('kg_setting') + ->where(['section' => 'pay.wxpay', 'item_key' => 'service_rate']) + ->execute(); + } + +} diff --git a/public/static/admin/css/common.css b/public/static/admin/css/common.css index 1bba752e..22bc2a78 100644 --- a/public/static/admin/css/common.css +++ b/public/static/admin/css/common.css @@ -34,6 +34,18 @@ list-style: decimal; } +.red { + color: red; +} + +.green { + color: green; +} + +.gray { + color: gray; +} + .loading { padding: 30px; text-align: center; diff --git a/public/static/home/css/common.css b/public/static/home/css/common.css index d30bd0c5..31aea755 100644 --- a/public/static/home/css/common.css +++ b/public/static/home/css/common.css @@ -489,11 +489,12 @@ height: 118px; } -.course-meta .info span { +.course-meta .info .key { margin-right: 5px; } .course-meta .info .value { + margin-right: 5px; color: #666; } @@ -1074,9 +1075,13 @@ float: left; } -.cart-course-card span { +.cart-course-card .key { + margin-right: 5px; +} + +.cart-course-card .value { + margin-right: 5px; color: #666; - margin: 0 5px; } .cart-course-card .origin-price { @@ -1683,17 +1688,14 @@ } .order-card { - padding: 10px 0; + padding-bottom: 20px; margin-bottom: 20px; - background-color: white; + border-bottom: 1px dashed #e6e6e6; color: #666; - box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05); } .order-card .header { - padding-bottom: 10px; margin-bottom: 10px; - border-bottom: 1px solid #e6e6e6; } .order-card .header span { diff --git a/scheduler.php b/scheduler.php index 253ad168..4c73f927 100644 --- a/scheduler.php +++ b/scheduler.php @@ -13,9 +13,6 @@ $bin = '/usr/local/bin/php'; $scheduler->php($script, $bin, ['--task' => 'deliver', '--action' => 'main']) ->at('*/3 * * * *'); -$scheduler->php($script, $bin, ['--task' => 'notice', '--action' => 'main']) - ->at('*/3 * * * *'); - $scheduler->php($script, $bin, ['--task' => 'vod_event', '--action' => 'main']) ->at('*/5 * * * *'); @@ -34,6 +31,9 @@ $scheduler->php($script, $bin, ['--task' => 'server_monitor', '--action' => 'mai $scheduler->php($script, $bin, ['--task' => 'close_trade', '--action' => 'main']) ->at('*/13 * * * *'); +$scheduler->php($script, $bin, ['--task' => 'notice', '--action' => 'main']) + ->everyMinute(); + $scheduler->php($script, $bin, ['--task' => 'close_order', '--action' => 'main']) ->hourly(3);