1
0
mirror of https://gitee.com/koogua/course-tencent-cloud.git synced 2025-06-21 11:18:10 +08:00

修复审核退款

This commit is contained in:
xiaochong0302 2020-06-11 19:12:11 +08:00
parent 9cd1466f06
commit aee651812f
26 changed files with 184 additions and 93 deletions

View File

@ -27,7 +27,7 @@ class StudentController extends Controller
$studentService = new StudentService();
$pager = $studentService->getPlans();
$pager = $studentService->getRelations();
$course = null;
@ -64,7 +64,7 @@ class StudentController extends Controller
{
$studentService = new StudentService();
$student = $studentService->createPlan();
$student = $studentService->createRelation();
$location = $this->url->get(
['for' => 'admin.student.list'],
@ -84,15 +84,15 @@ class StudentController extends Controller
*/
public function editAction()
{
$planId = $this->request->getQuery('plan_id');
$relationId = $this->request->getQuery('relation_id');
$studentService = new StudentService();
$plan = $studentService->getPlan($planId);
$course = $studentService->getCourse($plan->course_id);
$student = $studentService->getStudent($plan->user_id);
$relation = $studentService->getRelation($relationId);
$course = $studentService->getCourse($relation->course_id);
$student = $studentService->getStudent($relation->user_id);
$this->view->setVar('plan', $plan);
$this->view->setVar('relation', $relation);
$this->view->setVar('course', $course);
$this->view->setVar('student', $student);
}
@ -104,7 +104,7 @@ class StudentController extends Controller
{
$studentService = new StudentService();
$studentService->updatePlan();
$studentService->updateRelation();
$location = $this->url->get(['for' => 'admin.student.list']);

View File

@ -17,6 +17,9 @@ class Order extends Service
$pageQuery = new PaginateQuery();
$params = $pageQuery->getParams();
$params['deleted'] = $params['deleted'] ?? 0;
$sort = $pageQuery->getSort();
$page = $pageQuery->getPage();
$limit = $pageQuery->getLimit();

View File

@ -4,6 +4,7 @@ namespace App\Http\Admin\Services;
use App\Builders\RefundList as RefundListBuilder;
use App\Library\Paginator\Query as PaginateQuery;
use App\Models\Refund as RefundModel;
use App\Models\Task as TaskModel;
use App\Repos\Account as AccountRepo;
use App\Repos\Order as OrderRepo;
@ -86,20 +87,20 @@ class Refund extends Service
$validator->checkIfAllowReview($refund);
$data['status'] = $validator->checkReviewStatus($post['status']);
$data['status'] = $validator->checkReviewStatus($post['review_status']);
$data['review_note'] = $validator->checkReviewNote($post['review_note']);
$refund->update($data);
$task = new TaskModel();
$task->item_id = $refund->id;
$task->item_type = TaskModel::TYPE_REFUND;
$task->item_info = ['refund' => $refund->toArray()];
$task->priority = TaskModel::PRIORITY_HIGH;
$task->status = TaskModel::STATUS_PENDING;
$task->create();
if ($post['status'] == RefundModel::STATUS_APPROVED) {
$task = new TaskModel();
$task->item_id = $refund->id;
$task->item_type = TaskModel::TYPE_REFUND;
$task->item_info = ['refund' => $refund->toArray()];
$task->priority = TaskModel::PRIORITY_HIGH;
$task->status = TaskModel::STATUS_PENDING;
$task->create();
}
return $refund;
}

View File

@ -30,7 +30,7 @@ class Student extends Service
return $repo->findById($userId);
}
public function getPlans()
public function getRelations()
{
$pagerQuery = new PagerQuery();
@ -47,7 +47,7 @@ class Student extends Service
$pager = $courseUserRepo->paginate($params, $sort, $page, $limit);
return $this->handlePlans($pager);
return $this->handleRelations($pager);
}
public function getLearnings()
@ -69,12 +69,12 @@ class Student extends Service
return $this->handleLearnings($pager);
}
public function getPlan($id)
public function getRelation($id)
{
return $this->findOrFail($id);
}
public function createPlan()
public function createRelation()
{
$post = $this->request->getPost();
@ -100,11 +100,11 @@ class Student extends Service
return $courseUser;
}
public function updatePlan()
public function updateRelation()
{
$post = $this->request->getPost();
$plan = $this->findOrFail($post['plan_id']);
$relation = $this->findOrFail($post['relation_id']);
$validator = new CourseUserValidator();
@ -114,9 +114,9 @@ class Student extends Service
$data['expiry_time'] = $validator->checkExpiryTime($post['expiry_time']);
}
$plan->update($data);
$relation->update($data);
return $plan;
return $relation;
}
protected function updateUserCount($courseId)
@ -137,7 +137,7 @@ class Student extends Service
return $validator->checkCourseUser($id);
}
protected function handlePlans($pager)
protected function handleRelations($pager)
{
if ($pager->total_items > 0) {

View File

@ -10,14 +10,21 @@
<tr>
<th>退款序号</th>
<th>退款金额</th>
<th>退款原因</th>
<th>退款备注</th>
<th>退款状态</th>
<th>创建时间</th>
</tr>
<tr>
<td>{{ refund.sn }}</td>
<td>¥{{ refund.amount }}</td>
<td><span title="{{ refund.apply_note }}">{{ substr(refund.apply_note,0,15) }}</span></td>
<td>
{% if refund.apply_note %}
<p class="layui-elip" title="{{ refund.apply_note }}">{{ refund.apply_note }}</p>
{% endif %}
{% if refund.review_note %}
<p class="layui-elip" title="{{ refund.review_note }}">{{ refund.review_note }}</p>
{% endif %}
</td>
<td>{{ refund_status(refund) }}</td>
<td>{{ date('Y-m-d H:i:s',refund.create_time) }}</td>
</tr>
@ -33,8 +40,8 @@
<div class="layui-form-item">
<label class="layui-form-label">审核结果</label>
<div class="layui-input-block">
<input type="radio" name="status" value="approved" title="同意">
<input type="radio" name="status" value="refused" title="拒绝">
<input type="radio" name="review_status" value="approved" title="同意">
<input type="radio" name="review_status" value="refused" title="拒绝">
</div>
</div>
<div class="layui-form-item">

View File

@ -21,7 +21,7 @@
<div class="layui-form-item">
<label class="layui-form-label">过期时间</label>
<div class="layui-input-block">
<input class="layui-input" type="text" name="expiry_time" autocomplete="off" value="{{ date('Y-m-d H:i:s',plan.expiry_time) }}" lay-verify="required">
<input class="layui-input" type="text" name="expiry_time" autocomplete="off" value="{{ date('Y-m-d H:i:s',relation.expiry_time) }}" lay-verify="required">
</div>
</div>
@ -30,7 +30,7 @@
<div class="layui-input-block">
<button class="layui-btn" lay-submit="true" lay-filter="go">提交</button>
<button type="button" class="kg-back layui-btn layui-btn-primary">返回</button>
<input type="hidden" name="plan_id" value="{{ plan.id }}"/>
<input type="hidden" name="relation_id" value="{{ relation.id }}"/>
</div>
</div>

View File

@ -53,6 +53,7 @@
</thead>
<tbody>
{% for item in pager.items %}
{% set learning_url = url({'for':'admin.student.learning'},{'course_id':item.course_id,'user_id':item.user_id,'plan_id':item.plan_id}) %}
<tr>
<td>
<p>课程:<a href="{{ url({'for':'admin.student.list'},{'course_id':item.course.id}) }}">{{ item.course.title }}{{ item.course.id }}</a></p>
@ -71,8 +72,8 @@
<div class="layui-dropdown">
<button class="layui-btn layui-btn-sm">操作 <span class="layui-icon layui-icon-triangle-d"></span></button>
<ul>
<li><a href="{{ url({'for':'admin.student.edit'},{'plan_id':item.id}) }}">编辑学员</a></li>
<li><a href="javascript:" class="kg-learning" data-url="{{ url({'for':'admin.student.learning'},{'course_id':item.course_id,'user_id':item.user_id}) }}">学习记录</a></li>
<li><a href="{{ url({'for':'admin.student.edit'},{'relation_id':item.id}) }}">编辑学员</a></li>
<li><a href="javascript:" class="kg-learning" data-url="{{ learning_url }}">学习记录</a></li>
</ul>
</div>
</td>

View File

@ -21,7 +21,7 @@ class MyController extends Controller
*/
public function homeAction()
{
$this->dispatcher->forward([
$this->response->redirect([
'for' => 'web.user.show',
'id' => $this->authUser->id,
]);

View File

@ -40,13 +40,14 @@ class RefundController extends Controller
{
$service = new RefundCreateService();
$refund = $service->handle();
$service->handle();
$service = new RefundInfoService();
$content = [
'location' => $this->url->get(['for' => 'web.my.orders']),
'msg' => '申请退款成功',
];
$refund = $service->handle($refund->sn);
return $this->jsonSuccess(['refund' => $refund]);
return $this->jsonSuccess($content);
}
/**

View File

@ -13,9 +13,6 @@
<div class="container">
<table class="layui-table kg-table order-table" lay-size="lg">
<tr>
<td colspan="6">订单编号:{{ order.sn }}</td>
<tr>
<tr>
<td>基本信息</td>
<td>订单金额</td>
@ -28,15 +25,17 @@
<td><span class="price">{{ '¥%0.2f'|format(order.amount) }}</span></td>
<td>{{ item_type(order.item_type) }}</td>
<td>{{ order_status(order.status) }}</td>
<td>{{ history_info(order.history) }}</td>
<td>{{ status_history(order.status_history) }}</td>
</tr>
</table>
<br>
<div class="text-center">
<a href="javascript:" class="kg-back layui-btn layui-bg-gray">返回上页</a>
{% if order.status == 'pending' %}
<a class="layui-btn layui-bg-blue" href="{{ url({'for':'web.order.pay'},{'sn':order.sn}) }}">立即支付</a>
{% endif %}
{% if (order.item_type in ['course','package']) and (order.status == 'finished') %}
{% set confirm_url = url({'for':'web.refund.confirm'},{'sn':order.sn}) %}
<a href="{{ confirm_url }}" class="layui-btn layui-bg-blue">申请退款</a>
<a class="layui-btn layui-bg-blue" href="{{ url({'for':'web.refund.confirm'},{'sn':order.sn}) }}">申请退款</a>
{% endif %}
</div>
<br>

View File

@ -11,7 +11,7 @@
<div class="header">
订单名称:<span>{{ order.subject }}</span>
订单编号:<span>{{ order.sn }}</span>
支付金额:<span class="amount">{{ order.amount }}</span>
支付金额:<span class="amount">{{ '¥%0.2f'|format(order.amount) }}</span>
</div>
<div class="channel">
{% set create_url = url({'for':'web.trade.create'}) %}

View File

@ -39,7 +39,7 @@
{% endif %}
{%- endmacro %}
{%- macro history_info(items) %}
{%- macro status_history(items) %}
{% for item in items %}
{% if item.status == 'pending' %}
<p>创建时间:{{ date('Y-m-d H:i:s',item.create_time) }}</p>

View File

@ -9,7 +9,7 @@
<div class="order-item">
<p>课程名称:<a href="{{ course_url }}" target="_blank">{{ course.title }}</a></p>
<p>退款期限:{{ date('Y-m-d H:i:s',course.refund_expiry_time) }}</p>
<p>退款金额:<span class="price">{{ '¥%0.2f'|format(course.refund_amount) }}</span>退款比例:{{ 100 * course.refund_percent }}%</p>
<p>退款金额:<span class="price">{{ '¥%0.2f'|format(course.refund_amount) }}</span>退款比例:<span class="price">{{ 100 * course.refund_percent }}%</span></p>
</div>
{% elseif confirm.item_type == 'package' %}
{% set courses = confirm.item_info.courses %}
@ -18,7 +18,7 @@
<div class="order-item">
<p>课程名称:<a href="{{ course_url }}" target="_blank">{{ course.title }}</a></p>
<p>退款期限:{{ date('Y-m-d H:i:s',course.refund_expiry_time) }}</p>
<p>退款金额:<span>{{ '¥%0.2f'|format(course.refund_amount) }}</span>退款比例:{{ 100 * course.refund_percent }}%</p>
<p>退款金额:<span class="price">{{ '¥%0.2f'|format(course.refund_amount) }}</span>退款比例:<span class="price">{{ 100 * course.refund_percent }}%</span></p>
</div>
{% endfor %}
{% endif %}
@ -34,10 +34,7 @@
<div class="container">
<table class="layui-table kg-table order-table" lay-size="lg">
<tr>
<td colspan="6">订单编号:{{ order.sn }}</td>
<tr>
<tr>
<td>基本信息</td>
<td>订单编号:{{ order.sn }}</td>
<td>订单金额</td>
<td>退款金额</td>
</tr>
@ -48,11 +45,20 @@
</tr>
</table>
<br>
<div class="text-center">
<a href="javascript:" class="kg-back layui-btn layui-bg-gray">返回上页</a>
<a href="javascript:" class="layui-btn layui-bg-blue">提交申请</a>
</div>
<br>
<form class="layui-form layui-form-pane" method="post" action="{{ url({'for':'web.refund.create'}) }}">
<div class="layui-form-item layui-form-text">
<label class="layui-form-label">退款原因</label>
<div class="layui-input-block">
<textarea class="layui-textarea" name="apply_note" lay-verify="required"></textarea>
</div>
</div>
<br>
<div class="layui-form-item text-center">
<button type="button" class="kg-back layui-btn layui-bg-gray">返回上页</button>
<button class="layui-btn layui-bg-blue" lay-submit="true" lay-filter="go">提交申请</button>
<input type="hidden" name="order_sn" value="{{ order.sn }}">
</div>
</form>
</div>
{% endblock %}

View File

@ -1,10 +1,14 @@
{{ partial('partials/macro_course') }}
{% if pager.total_pages > 0 %}
<div class="course-list clearfix">
{% for item in pager.items %}
{{ learning_course_card(item) }}
{% endfor %}
<div class="course-list learning-course-list clearfix">
<div class="layui-row layui-col-space20">
{% for item in pager.items %}
<div class="layui-col-md3">
{{ learning_course_card(item) }}
</div>
{% endfor %}
</div>
</div>
{{ partial('partials/pager_ajax') }}
{% endif %}

View File

@ -2,9 +2,13 @@
{% if pager.total_pages > 0 %}
<div class="course-list clearfix">
{% for item in pager.items %}
{{ course_card(item) }}
{% endfor %}
<div class="layui-row layui-col-space20">
{% for item in pager.items %}
<div class="layui-col-md3">
{{ course_card(item) }}
</div>
{% endfor %}
</div>
</div>
{{ partial('partials/pager_ajax') }}
{% endif %}

View File

@ -20,11 +20,11 @@
{% endif %}
</div>
{% set course_url = url({'for':'web.user.courses','id':user.id}) %}
{% set favorite_url = url({'for':'web.user.favorites','id':user.id}) %}
{% set friend_url = url({'for':'web.user.friends','id':user.id}) %}
{% set courses_url = url({'for':'web.user.courses','id':user.id},{'limit':12}) %}
{% set favorites_url = url({'for':'web.user.favorites','id':user.id},{'limit':12}) %}
{% set friends_url = url({'for':'web.user.friends','id':user.id},{'limit':12}) %}
<div class="container">
<div class="tab-container">
<div class="layui-tab layui-tab-brief user-tab">
<ul class="layui-tab-title">
<li class="layui-this">课程</li>
@ -32,9 +32,9 @@
<li>好友</li>
</ul>
<div class="layui-tab-content">
<div class="layui-tab-item layui-show" id="tab-courses" data-url="{{ course_url }}"></div>
<div class="layui-tab-item" id="tab-favorites" data-url="{{ favorite_url }}"></div>
<div class="layui-tab-item" id="tab-friends" data-url="{{ friend_url }}"></div>
<div class="layui-tab-item layui-show" id="tab-courses" data-url="{{ courses_url }}"></div>
<div class="layui-tab-item" id="tab-favorites" data-url="{{ favorites_url }}"></div>
<div class="layui-tab-item" id="tab-friends" data-url="{{ friends_url }}"></div>
</div>
</div>
</div>

View File

@ -17,6 +17,10 @@ class Learning extends Repository
$builder->where('1 = 1');
if (!empty($where['plan_id'])) {
$builder->andWhere('plan_id = :plan_id:', ['plan_id' => $where['plan_id']]);
}
if (!empty($where['course_id'])) {
$builder->andWhere('course_id = :course_id:', ['course_id' => $where['course_id']]);
}

View File

@ -169,11 +169,37 @@ class Order extends Repository
* @param $orderId
* @return ResultsetInterface|Resultset|OrderStatusModel[]
*/
public function findHistory($orderId)
public function findStatusHistory($orderId)
{
return OrderStatusModel::query()
->where('order_id = :order_id:', ['order_id' => $orderId])
->execute();
}
/**
* @param int $orderId
* @return TradeModel|Model|bool
*/
public function findLastTrade($orderId)
{
return TradeModel::findFirst([
'conditions' => 'order_id = :order_id:',
'bind' => ['order_id' => $orderId],
'order' => 'id DESC',
]);
}
/**
* @param int $orderId
* @return RefundModel|Model|bool
*/
public function findLastRefund($orderId)
{
return RefundModel::findFirst([
'conditions' => 'order_id = :order_id:',
'bind' => ['order_id' => $orderId],
'order' => 'id DESC',
]);
}
}

View File

@ -31,6 +31,10 @@ class Refund extends Repository
$builder->andWhere('status = :status:', ['status' => $where['status']]);
}
if (isset($where['deleted'])) {
$builder->andWhere('deleted = :deleted:', ['deleted' => $where['deleted']]);
}
if (!empty($where['start_time']) && !empty($where['end_time'])) {
$startTime = strtotime($where['start_time']);
$endTime = strtotime($where['end_time']);

View File

@ -44,6 +44,10 @@ class Trade extends Repository
$builder->andWhere('status = :status:', ['status' => $where['status']]);
}
if (isset($where['deleted'])) {
$builder->andWhere('deleted = :deleted:', ['deleted' => $where['deleted']]);
}
if (!empty($where['start_time']) && !empty($where['end_time'])) {
$startTime = strtotime($where['start_time']);
$endTime = strtotime($where['end_time']);

View File

@ -23,25 +23,25 @@ class OrderInfo extends FrontendService
{
$order->item_info = $this->handleItemInfo($order);
$history = $this->handleHistory($order);
$statusHistory = $this->handleStatusHistory($order);
return [
'sn' => $order->sn,
'subject' => $order->subject,
'amount' => $order->amount,
'status' => $order->status,
'status_history' => $statusHistory,
'item_id' => $order->item_id,
'item_type' => $order->item_type,
'item_info' => $order->item_info,
'history' => $history,
];
}
protected function handleHistory(OrderModel $order)
protected function handleStatusHistory(OrderModel $order)
{
$orderRepo = new OrderRepo();
$records = $orderRepo->findHistory($order->id);
$records = $orderRepo->findStatusHistory($order->id);
if ($records->count() == 0) {
return [];

View File

@ -3,6 +3,7 @@
namespace App\Services\Frontend\Refund;
use App\Models\Refund as RefundModel;
use App\Repos\Order as OrderRepo;
use App\Services\Frontend\OrderTrait;
use App\Services\Frontend\Service as FrontendService;
use App\Services\Refund as RefundService;
@ -22,27 +23,35 @@ class RefundCreate extends FrontendService
$user = $this->getLoginUser();
$orderRepo = new OrderRepo();
$trade = $orderRepo->findLastTrade($order->id);
$validator = new OrderValidator();
$validator->checkOwner($user->id, $order->user_id);
$validator->checkIfAllowRefund($order);
$refundService = new RefundService();
$refundAmount = $refundService->getRefundAmount($order);
$preview = $refundService->preview($order);
$refundAmount = $preview['refund_amount'];
$validator = new RefundValidator();
$validator->checkAmount($order->amount, $refundAmount);
$applyNote = $validator->checkApplyNote($post['apply_note']);
$validator->checkAmount($order->amount, $refundAmount);
$refund = new RefundModel();
$refund->subject = $order->subject;
$refund->amount = $order->amount;
$refund->amount = $refundAmount;
$refund->apply_note = $applyNote;
$refund->order_id = $order->id;
$refund->trade_id = $order->id;
$refund->trade_id = $trade->id;
$refund->user_id = $user->id;
$refund->create();

View File

@ -4,6 +4,7 @@ namespace App\Validators;
use App\Exceptions\BadRequest as BadRequestException;
use App\Models\Order as OrderModel;
use App\Models\Refund as RefundModel;
use App\Repos\Course as CourseRepo;
use App\Repos\Order as OrderRepo;
use App\Repos\Package as PackageRepo;
@ -137,7 +138,20 @@ class Order extends Validator
];
if (!in_array($order->item_type, $types)) {
throw new BadRequestException('order.refund_not_allowed');
throw new BadRequestException('order.refund_item_unsupported');
}
$orderRepo = new OrderRepo();
$refund = $orderRepo->findLastRefund($order->id);
$scopes = [
RefundModel::STATUS_PENDING,
RefundModel::STATUS_APPROVED,
];
if ($refund && in_array($refund->status, $scopes)) {
throw new BadRequestException('order.refund_apply_existed');
}
}

View File

@ -75,7 +75,7 @@ class Trade extends Validator
];
if ($refund && in_array($refund->status, $scopes)) {
throw new BadRequestException('trade.refund_existed');
throw new BadRequestException('trade.refund_apply_existed');
}
}

View File

@ -259,10 +259,13 @@ $error['slide.invalid_publish_status'] = '无效的发布状态';
*/
$error['order.not_found'] = '订单不存在';
$error['order.item_not_found'] = '商品不存在';
$error['order.close_not_allowed'] = '当前不允许关闭订单';
$error['order.has_bought_course'] = '已经够买过该课程';
$error['order.has_bought_package'] = '已经够买过该套餐';
$error['order.trade_expired'] = '交易已过期';
$error['order.has_bought_course'] = '已经购买过该课程';
$error['order.has_bought_package'] = '已经购买过该套餐';
$error['order.close_not_allowed'] = '当前不允许关闭订单';
$error['order.refund_not_allowed'] = '当前不允许申请退款';
$error['order.refund_item_unsupported'] = '该品类不支持退款';
$error['order.refund_apply_existed'] = '退款申请已经存在';
/**
* 交易相关
@ -272,7 +275,7 @@ $error['trade.create_failed'] = '创建交易失败';
$error['trade.invalid_channel'] = '无效的平台类型';
$error['trade.close_not_allowed'] = '当前不允许关闭交易';
$error['trade.refund_not_allowed'] = '当前不允许交易退款';
$error['trade.refund_existed'] = '退款申请已经存在,请等待处理结果';
$error['trade.refund_apply_existed'] = '退款申请已经存在,请等待处理结果';
/**
* 退款相关

View File

@ -983,15 +983,16 @@
}
.learning-course-card {
height: 230px;
height: 260px;
}
.learning-course-card .progress {
width: 210px;
padding: 15px 0;
width: 260px;
padding: 15px 0 15px 5px;
}
.learning-course-card .duration {
padding: 0 5px;
font-size: 12px;
color: #666;
}