Skip to content

Commit 11d3b5b

Browse files
committed
feat[litemall-admin, litemall-admin-api]: 售后页面实现审核和退款功能
1 parent 4611d82 commit 11d3b5b

File tree

5 files changed

+310
-42
lines changed

5 files changed

+310
-42
lines changed

litemall-admin-api/src/main/java/org/linlinjava/litemall/admin/service/AdminOrderService.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ public Object refund(String body) {
165165
notifyService.notifySmsTemplate(order.getMobile(), NotifyType.REFUND,
166166
new String[]{order.getOrderSn().substring(8, 14)});
167167

168-
logHelper.logOrderSucceed("退款", "订单编号 " + orderId);
168+
logHelper.logOrderSucceed("退款", "订单编号 " + order.getOrderSn());
169169
return ResponseUtil.ok();
170170
}
171171

@@ -210,7 +210,7 @@ public Object ship(String body) {
210210
// "您的订单已经发货,快递公司 {1},快递单 {2} ,请注意查收"
211211
notifyService.notifySmsTemplate(order.getMobile(), NotifyType.SHIP, new String[]{shipChannel, shipSn});
212212

213-
logHelper.logOrderSucceed("发货", "订单编号 " + orderId);
213+
logHelper.logOrderSucceed("发货", "订单编号 " + order.getOrderSn());
214214
return ResponseUtil.ok();
215215
}
216216

litemall-admin-api/src/main/java/org/linlinjava/litemall/admin/util/AdminResponseCode.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,6 @@ public class AdminResponseCode {
2424
public static final Integer GROUPON_GOODS_EXISTED = 651;
2525
public static final Integer GROUPON_GOODS_OFFLINE = 652;
2626
public static final Integer NOTICE_UPDATE_NOT_ALLOWED = 660;
27+
public static final Integer AFTERSALE_NOT_ALLOWED = 670;
2728

2829
}
Lines changed: 184 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,38 @@
11
package org.linlinjava.litemall.admin.web;
22

3+
import com.github.binarywang.wxpay.bean.request.WxPayRefundRequest;
4+
import com.github.binarywang.wxpay.bean.result.WxPayRefundResult;
5+
import com.github.binarywang.wxpay.exception.WxPayException;
6+
import com.github.binarywang.wxpay.service.WxPayService;
37
import org.apache.commons.logging.Log;
48
import org.apache.commons.logging.LogFactory;
59
import org.apache.shiro.authz.annotation.RequiresPermissions;
610
import org.linlinjava.litemall.admin.annotation.RequiresPermissionsDesc;
11+
import org.linlinjava.litemall.admin.service.LogHelper;
12+
import org.linlinjava.litemall.admin.util.AdminResponseCode;
13+
import org.linlinjava.litemall.core.notify.NotifyService;
14+
import org.linlinjava.litemall.core.notify.NotifyType;
715
import org.linlinjava.litemall.core.util.JacksonUtil;
816
import org.linlinjava.litemall.core.util.ResponseUtil;
917
import org.linlinjava.litemall.core.validator.Order;
1018
import org.linlinjava.litemall.core.validator.Sort;
1119
import org.linlinjava.litemall.db.domain.LitemallAftersale;
20+
import org.linlinjava.litemall.db.domain.LitemallGoodsProduct;
21+
import org.linlinjava.litemall.db.domain.LitemallOrder;
22+
import org.linlinjava.litemall.db.domain.LitemallOrderGoods;
1223
import org.linlinjava.litemall.db.service.*;
24+
import org.linlinjava.litemall.db.util.AftersaleConstant;
25+
import org.linlinjava.litemall.db.util.OrderUtil;
1326
import org.springframework.beans.factory.annotation.Autowired;
1427
import org.springframework.validation.annotation.Validated;
1528
import org.springframework.web.bind.annotation.*;
29+
30+
import java.math.BigDecimal;
31+
import java.time.LocalDateTime;
1632
import java.util.List;
1733

34+
import static org.linlinjava.litemall.admin.util.AdminResponseCode.ORDER_REFUND_FAILED;
35+
1836
@RestController
1937
@RequestMapping("/admin/aftersale")
2038
@Validated
@@ -27,34 +45,188 @@ public class AdminAftersaleController {
2745
private LitemallOrderService orderService;
2846
@Autowired
2947
private LitemallOrderGoodsService orderGoodsService;
48+
@Autowired
49+
private LitemallGoodsProductService goodsProductService;
50+
@Autowired
51+
private LogHelper logHelper;
52+
@Autowired
53+
private WxPayService wxPayService;
54+
@Autowired
55+
private NotifyService notifyService;
3056

3157
@RequiresPermissions("admin:aftersale:list")
3258
@RequiresPermissionsDesc(menu = {"商城管理", "售后管理"}, button = "查询")
3359
@GetMapping("/list")
34-
public Object list(Integer orderId, String aftersaleSn,
60+
public Object list(Integer orderId, String aftersaleSn, Short status,
3561
@RequestParam(defaultValue = "1") Integer page,
3662
@RequestParam(defaultValue = "10") Integer limit,
3763
@Sort @RequestParam(defaultValue = "add_time") String sort,
3864
@Order @RequestParam(defaultValue = "desc") String order) {
39-
List<LitemallAftersale> aftersaleList = aftersaleService.querySelective(orderId, aftersaleSn, page, limit, sort, order);
65+
List<LitemallAftersale> aftersaleList = aftersaleService.querySelective(orderId, aftersaleSn, status, page, limit, sort, order);
4066
return ResponseUtil.okList(aftersaleList);
4167
}
4268

69+
@RequiresPermissions("admin:aftersale:recept")
70+
@RequiresPermissionsDesc(menu = {"商城管理", "售后管理"}, button = "审核通过")
71+
@PostMapping("/recept")
72+
public Object recept(@RequestBody LitemallAftersale aftersale) {
73+
Integer id = aftersale.getId();
74+
LitemallAftersale aftersaleOne = aftersaleService.findById(id);
75+
if(aftersaleOne == null){
76+
return ResponseUtil.fail(AdminResponseCode.AFTERSALE_NOT_ALLOWED, "售后不存在");
77+
}
78+
Short status = aftersaleOne.getStatus();
79+
if(!status.equals(AftersaleConstant.STATUS_REQUEST)){
80+
return ResponseUtil.fail(AdminResponseCode.AFTERSALE_NOT_ALLOWED, "售后不能进行审核通过操作");
81+
}
82+
aftersaleOne.setStatus(AftersaleConstant.STATUS_RECEPT);
83+
aftersaleOne.setHandleTime(LocalDateTime.now());
84+
aftersaleService.updateById(aftersaleOne);
85+
86+
// 订单也要更新售后状态
87+
orderService.updateAftersaleStatus(aftersaleOne.getOrderId(), AftersaleConstant.STATUS_RECEPT);
88+
return ResponseUtil.ok();
89+
}
90+
91+
@RequiresPermissions("admin:aftersale:batch-recept")
92+
@RequiresPermissionsDesc(menu = {"商城管理", "售后管理"}, button = "批量通过")
93+
@PostMapping("/batch-recept")
94+
public Object batchRecept(@RequestBody String body) {
95+
List<Integer> ids = JacksonUtil.parseIntegerList(body, "ids");
96+
// NOTE
97+
// 批量操作中,如果一部分数据项失败,应该如何处理
98+
// 这里采用忽略失败,继续处理其他项。
99+
// 当然开发者可以采取其他处理方式,具体情况具体分析,例如利用事务回滚所有操作然后返回用户失败信息
100+
for(Integer id : ids) {
101+
LitemallAftersale aftersale = aftersaleService.findById(id);
102+
if(aftersale == null){
103+
continue;
104+
}
105+
Short status = aftersale.getStatus();
106+
if(!status.equals(AftersaleConstant.STATUS_REQUEST)){
107+
continue;
108+
}
109+
aftersale.setStatus(AftersaleConstant.STATUS_RECEPT);
110+
aftersale.setHandleTime(LocalDateTime.now());
111+
aftersaleService.updateById(aftersale);
112+
113+
// 订单也要更新售后状态
114+
orderService.updateAftersaleStatus(aftersale.getOrderId(), AftersaleConstant.STATUS_RECEPT);
115+
}
116+
return ResponseUtil.ok();
117+
}
118+
119+
@RequiresPermissions("admin:aftersale:reject")
120+
@RequiresPermissionsDesc(menu = {"商城管理", "售后管理"}, button = "审核拒绝")
121+
@PostMapping("/reject")
122+
public Object reject(@RequestBody LitemallAftersale aftersale) {
123+
Integer id = aftersale.getId();
124+
LitemallAftersale aftersaleOne = aftersaleService.findById(id);
125+
if(aftersaleOne == null){
126+
return ResponseUtil.badArgumentValue();
127+
}
128+
Short status = aftersaleOne.getStatus();
129+
if(!status.equals(AftersaleConstant.STATUS_REQUEST)){
130+
return ResponseUtil.fail(AdminResponseCode.AFTERSALE_NOT_ALLOWED, "售后不能进行审核拒绝操作");
131+
}
132+
aftersaleOne.setStatus(AftersaleConstant.STATUS_REJECT);
133+
aftersaleOne.setHandleTime(LocalDateTime.now());
134+
aftersaleService.updateById(aftersaleOne);
43135

44-
@RequiresPermissions("admin:aftersale:delete")
45-
@RequiresPermissionsDesc(menu = {"商城管理", "售后管理"}, button = "删除")
46-
@PostMapping("/delete")
47-
public Object delete(@RequestBody LitemallAftersale aftersale) {
48-
aftersaleService.deleteById(aftersale.getId());
136+
// 订单也要更新售后状态
137+
orderService.updateAftersaleStatus(aftersaleOne.getOrderId(), AftersaleConstant.STATUS_REJECT);
49138
return ResponseUtil.ok();
50139
}
51140

52-
@RequiresPermissions("admin:aftersale:batch-delete")
53-
@RequiresPermissionsDesc(menu = {"商城管理", "售后管理"}, button = "批量删除")
54-
@PostMapping("/batch-delete")
55-
public Object batchDelete(@RequestBody String body) {
141+
@RequiresPermissions("admin:aftersale:batch-reject")
142+
@RequiresPermissionsDesc(menu = {"商城管理", "售后管理"}, button = "批量拒绝")
143+
@PostMapping("/batch-reject")
144+
public Object batchReject(@RequestBody String body) {
56145
List<Integer> ids = JacksonUtil.parseIntegerList(body, "ids");
57-
aftersaleService.deleteByIds(ids);
146+
for(Integer id : ids) {
147+
LitemallAftersale aftersale = aftersaleService.findById(id);
148+
if(aftersale == null){
149+
continue;
150+
}
151+
Short status = aftersale.getStatus();
152+
if(!status.equals(AftersaleConstant.STATUS_REQUEST)){
153+
continue;
154+
}
155+
aftersale.setStatus(AftersaleConstant.STATUS_REJECT);
156+
aftersale.setHandleTime(LocalDateTime.now());
157+
aftersaleService.updateById(aftersale);
158+
159+
// 订单也要更新售后状态
160+
orderService.updateAftersaleStatus(aftersale.getOrderId(), AftersaleConstant.STATUS_REJECT);
161+
}
162+
return ResponseUtil.ok();
163+
}
164+
165+
@RequiresPermissions("admin:aftersale:refund")
166+
@RequiresPermissionsDesc(menu = {"商城管理", "售后管理"}, button = "退款")
167+
@PostMapping("/refund")
168+
public Object refund(@RequestBody LitemallAftersale aftersale) {
169+
Integer id = aftersale.getId();
170+
LitemallAftersale aftersaleOne = aftersaleService.findById(id);
171+
if(aftersaleOne == null){
172+
return ResponseUtil.badArgumentValue();
173+
}
174+
if(!aftersaleOne.getStatus().equals(AftersaleConstant.STATUS_RECEPT)){
175+
return ResponseUtil.fail(AdminResponseCode.AFTERSALE_NOT_ALLOWED, "售后不能进行退款操作");
176+
}
177+
Integer orderId = aftersaleOne.getOrderId();
178+
LitemallOrder order = orderService.findById(orderId);
179+
180+
// 微信退款
181+
WxPayRefundRequest wxPayRefundRequest = new WxPayRefundRequest();
182+
wxPayRefundRequest.setOutTradeNo(order.getOrderSn());
183+
wxPayRefundRequest.setOutRefundNo("refund_" + order.getOrderSn());
184+
// 元转成分
185+
Integer totalFee = aftersaleOne.getAmount().multiply(new BigDecimal(100)).intValue();
186+
wxPayRefundRequest.setTotalFee(totalFee);
187+
wxPayRefundRequest.setRefundFee(totalFee);
188+
189+
WxPayRefundResult wxPayRefundResult;
190+
try {
191+
wxPayRefundResult = wxPayService.refund(wxPayRefundRequest);
192+
} catch (WxPayException e) {
193+
logger.error(e.getMessage(), e);
194+
return ResponseUtil.fail(ORDER_REFUND_FAILED, "订单退款失败");
195+
}
196+
if (!wxPayRefundResult.getReturnCode().equals("SUCCESS")) {
197+
logger.warn("refund fail: " + wxPayRefundResult.getReturnMsg());
198+
return ResponseUtil.fail(ORDER_REFUND_FAILED, "订单退款失败");
199+
}
200+
if (!wxPayRefundResult.getResultCode().equals("SUCCESS")) {
201+
logger.warn("refund fail: " + wxPayRefundResult.getReturnMsg());
202+
return ResponseUtil.fail(ORDER_REFUND_FAILED, "订单退款失败");
203+
}
204+
205+
aftersaleOne.setStatus(AftersaleConstant.STATUS_REFUND);
206+
aftersaleOne.setHandleTime(LocalDateTime.now());
207+
aftersaleService.updateById(aftersaleOne);
208+
209+
orderService.updateAftersaleStatus(orderId, AftersaleConstant.STATUS_REFUND);
210+
211+
// NOTE
212+
// 如果是“退货退款”类型的售后,这里退款说明用户的货已经退回,则需要商品货品数量增加
213+
// 开发者也可以删除一下代码,在其他地方增加商品货品入库操作
214+
if(aftersale.getType().equals(AftersaleConstant.TYPE_GOODS_REQUIRED)) {
215+
List<LitemallOrderGoods> orderGoodsList = orderGoodsService.queryByOid(orderId);
216+
for (LitemallOrderGoods orderGoods : orderGoodsList) {
217+
Integer productId = orderGoods.getProductId();
218+
Short number = orderGoods.getNumber();
219+
goodsProductService.addStock(productId, number);
220+
}
221+
}
222+
223+
// 发送短信通知,这里采用异步发送
224+
// 退款成功通知用户, 例如“您申请的订单退款 [ 单号:{1} ] 已成功,请耐心等待到账。”
225+
// TODO 注意订单号只发后6位
226+
notifyService.notifySmsTemplate(order.getMobile(), NotifyType.REFUND,
227+
new String[]{order.getOrderSn().substring(8, 14)});
228+
229+
logHelper.logOrderSucceed("退款", "订单编号 " + order.getOrderSn() + " 售后编号 " + aftersale.getAftersaleSn());
58230
return ResponseUtil.ok();
59231
}
60232
}

litemall-admin/src/api/aftersale.js

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,41 @@ export function listAftersale(query) {
88
})
99
}
1010

11-
export function deleteAftersale(data) {
11+
export function receptAftersale(data) {
1212
return request({
13-
url: '/aftersale/delete',
13+
url: '/aftersale/recept',
1414
method: 'post',
1515
data
1616
})
1717
}
1818

19-
export function batchDeleteAftersale(data) {
19+
export function batchReceptAftersale(data) {
2020
return request({
21-
url: '/aftersale/batch-delete',
21+
url: '/aftersale/batch-recept',
22+
method: 'post',
23+
data
24+
})
25+
}
26+
27+
export function rejectAftersale(data) {
28+
return request({
29+
url: '/aftersale/reject',
30+
method: 'post',
31+
data
32+
})
33+
}
34+
35+
export function batchRejectAftersale(data) {
36+
return request({
37+
url: '/aftersale/batch-reject',
38+
method: 'post',
39+
data
40+
})
41+
}
42+
43+
export function refundAftersale(data) {
44+
return request({
45+
url: '/aftersale/refund',
2246
method: 'post',
2347
data
2448
})

0 commit comments

Comments
 (0)