【新增】后台增加【取消并退款】功能,针对用户支付后并未发货的订单,后台可以直接取消并生成退款单,后台再进行选择退款方式。

This commit is contained in:
jianweie
2024-05-17 00:19:47 +08:00
parent dd7db9810d
commit 20751db9a4
4 changed files with 188 additions and 3 deletions

View File

@@ -163,6 +163,13 @@ namespace CoreCms.Net.IServices
/// <returns></returns> /// <returns></returns>
Task<WebApiCallBack> CancelOrder(string[] ids, int userId = 0); Task<WebApiCallBack> CancelOrder(string[] ids, int userId = 0);
/// <summary>
/// 取消订单并退款
/// </summary>
/// <param name="orderId"></param>
/// <returns></returns>
Task<WebApiCallBack> CancelOrderAndRefund(string orderId);
/// <summary> /// <summary>
/// 后端根据订单状态生成不同的操作按钮 /// 后端根据订单状态生成不同的操作按钮

View File

@@ -31,13 +31,17 @@ using CoreCms.Net.Model.ViewModels.UI;
using CoreCms.Net.Utility.Extensions; using CoreCms.Net.Utility.Extensions;
using CoreCms.Net.Utility.Helper; using CoreCms.Net.Utility.Helper;
using CoreCms.Net.WeChat.Service.HttpClients; using CoreCms.Net.WeChat.Service.HttpClients;
using EnumsNET;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using Org.BouncyCastle.Crypto;
using SKIT.FlurlHttpClient.Wechat.Api; using SKIT.FlurlHttpClient.Wechat.Api;
using SKIT.FlurlHttpClient.Wechat.Api.Models; using SKIT.FlurlHttpClient.Wechat.Api.Models;
using SqlSugar; using SqlSugar;
using Yitter.IdGenerator; using Yitter.IdGenerator;
using static CoreCms.Net.Configuration.GlobalEnumVars;
using static SKIT.FlurlHttpClient.Wechat.Api.Models.ChannelsECAftersaleGetAftersaleOrderResponse.Types.AftersaleOrder.Types;
namespace CoreCms.Net.Services namespace CoreCms.Net.Services
@@ -62,6 +66,7 @@ namespace CoreCms.Net.Services
private readonly ICoreCmsLogisticsServices _logisticsServices; private readonly ICoreCmsLogisticsServices _logisticsServices;
private readonly ICoreCmsInvoiceServices _invoiceServices; private readonly ICoreCmsInvoiceServices _invoiceServices;
private readonly ICoreCmsBillAftersalesServices _billAftersalesServices; private readonly ICoreCmsBillAftersalesServices _billAftersalesServices;
private readonly ICoreCmsBillAftersalesItemServices _billAftersalesItemServices;
private readonly ICoreCmsOrderItemServices _orderItemServices; private readonly ICoreCmsOrderItemServices _orderItemServices;
private readonly ICoreCmsInvoiceRecordServices _invoiceRecordServices; private readonly ICoreCmsInvoiceRecordServices _invoiceRecordServices;
private readonly ICoreCmsOrderLogServices _orderLogServices; private readonly ICoreCmsOrderLogServices _orderLogServices;
@@ -107,7 +112,7 @@ namespace CoreCms.Net.Services
, ICoreCmsPaymentsServices paymentsServices , ICoreCmsPaymentsServices paymentsServices
, ICoreCmsBillRefundServices billRefundServices , ICoreCmsBillRefundServices billRefundServices
, ICoreCmsBillLadingServices billLadingServices , ICoreCmsBillLadingServices billLadingServices
, ICoreCmsBillReshipServices billReshipServices, ICoreCmsMessageCenterServices messageCenterServices, ICoreCmsGoodsCommentServices goodsCommentServices, ISysTaskLogServices taskLogServices, ICoreCmsPromotionRecordServices promotionRecordServices, IRedisOperationRepository redisOperationRepository, ICoreCmsUserWeChatInfoServices userWeChatInfoServices, IWeChatApiHttpClientFactory weChatApiHttpClientFactory, IUnitOfWork unitOfWork) , ICoreCmsBillReshipServices billReshipServices, ICoreCmsMessageCenterServices messageCenterServices, ICoreCmsGoodsCommentServices goodsCommentServices, ISysTaskLogServices taskLogServices, ICoreCmsPromotionRecordServices promotionRecordServices, IRedisOperationRepository redisOperationRepository, ICoreCmsUserWeChatInfoServices userWeChatInfoServices, IWeChatApiHttpClientFactory weChatApiHttpClientFactory, IUnitOfWork unitOfWork, ICoreCmsBillAftersalesItemServices billAftersalesItemServices)
{ {
this._dal = dal; this._dal = dal;
base.BaseDal = dal; base.BaseDal = dal;
@@ -144,6 +149,7 @@ namespace CoreCms.Net.Services
_userWeChatInfoServices = userWeChatInfoServices; _userWeChatInfoServices = userWeChatInfoServices;
_weChatApiHttpClientFactory = weChatApiHttpClientFactory; _weChatApiHttpClientFactory = weChatApiHttpClientFactory;
_unitOfWork = unitOfWork; _unitOfWork = unitOfWork;
_billAftersalesItemServices = billAftersalesItemServices;
} }
#region #region
@@ -1638,6 +1644,150 @@ namespace CoreCms.Net.Services
} }
#endregion #endregion
/// <summary>
/// 取消订单并退款
/// </summary>
/// <param name="orderId"></param>
/// <returns></returns>
public async Task<WebApiCallBack> CancelOrderAndRefund(string orderId)
{
var jm = new WebApiCallBack();
//获取订单并确认是否属于已支付并未发货的订单
var where = PredicateBuilder.True<CoreCmsOrder>();
where = where.And(p => p.orderId == orderId);
where = where.And(p => p.payStatus == (int)GlobalEnumVars.OrderPayStatus.Yes);
where = where.And(p => p.status == (int)GlobalEnumVars.OrderStatus.Normal);
where = where.And(p => p.shipStatus == (int)GlobalEnumVars.OrderShipStatus.No);
var orderInfo = await _dal.QueryByClauseAsync(where);
if (orderInfo == null)
{
jm.status = false;
jm.msg = "不满足条件,必须是已支付未发货订单。";
return jm;
}
//判断是否存在售后单据。
var haveAs = await _billAftersalesServices.ExistsAsync(p => p.orderId == orderId && p.userId == orderInfo.userId);
if (haveAs)
{
jm.msg = "存在售后单,暂不支持直接取消。";
jm.status = false;
return jm;
}
orderInfo.items = await _orderItemServices.QueryListByClauseAsync(p => p.orderId == orderInfo.orderId);
AfterSalesVal(orderInfo, 0);
if (orderInfo.addAftersalesStatus == false)
{
jm.msg = GlobalErrorCodeVars.Code13200;
jm.code = 13200;
return jm;
}
//构建售后单
//生成售后单号
var afterSalesId = CommonHelper.GetSerialNumberType((int)GlobalEnumVars.SerialNumberType.);
var billAftersales = new CoreCmsBillAftersales();
billAftersales.aftersalesId = afterSalesId;
billAftersales.orderId = orderId;
billAftersales.userId = orderInfo.userId;
billAftersales.type = 1;
billAftersales.refundAmount = orderInfo.payedAmount;
billAftersales.reason = "后台主动发起取消订单,并走售后流程生成退款单。";
billAftersales.status = (int)GlobalEnumVars.BillAftersalesStatus.Success;
billAftersales.createTime = DateTime.Now;
//保存主表数据
await _billAftersalesServices.InsertAsync(billAftersales);
//保存子项目
var aftersalesItemData = orderInfo.items.Select(orderItem => new CoreCmsBillAftersalesItem
{
aftersalesId = afterSalesId,
orderItemsId = orderItem.id,
goodsId = orderItem.goodsId,
productId = orderItem.productId,
sn = orderItem.sn,
bn = orderItem.bn,
name = orderItem.name,
imageUrl = orderItem.imageUrl,
nums = orderItem.nums,
addon = orderItem.addon,
createTime = DateTime.Now
})
.ToList();
await _billAftersalesItemServices.InsertAsync(aftersalesItemData);
//构建退款单
if (billAftersales.refundAmount > 0)
{
var billRefund = new CoreCmsBillRefund();
billRefund.refundId = CommonHelper.GetSerialNumberType((int)GlobalEnumVars.SerialNumberType.退);
billRefund.aftersalesId = afterSalesId;
billRefund.money = billAftersales.refundAmount;
billRefund.userId = billAftersales.userId;
billRefund.sourceId = billAftersales.orderId;
billRefund.type = orderInfo.orderType;
//取支付成功的支付单号
var paymentsInfo = await _billPaymentsServices.QueryByClauseAsync(p => p.sourceId == billRefund.sourceId && p.type == orderInfo.orderType && p.status == (int)GlobalEnumVars.BillPaymentsStatus.Payed);
if (paymentsInfo != null)
{
billRefund.paymentCode = paymentsInfo.paymentCode;
billRefund.tradeNo = paymentsInfo.tradeNo;
}
billRefund.status = (int)GlobalEnumVars.BillRefundStatus.STATUS_NOREFUND;
billRefund.createTime = DateTime.Now;
await _billRefundServices.InsertAsync(billRefund);
}
//构建订单记录
//订单记录
var orderLog = new CoreCmsOrderLog
{
orderId = orderInfo.orderId,
userId = orderInfo.userId,
type = (int)GlobalEnumVars.OrderLogTypes.LOG_TYPE_CANCEL,
msg = "后端操作取消订单并退款",
data = JsonConvert.SerializeObject(orderInfo),
createTime = DateTime.Now
};
await _orderLogServices.InsertAsync(orderLog);
//如果有积分消费退还
if (orderInfo.point > 0)
{
await _userPointLogServices.SetPoint(orderInfo.userId, orderInfo.point, (int)GlobalEnumVars.UserPointSourceTypes.PointCanCelOrder, "后端取消订单:" + orderInfo.orderId + "返还积分");
}
//优惠券返还
if (!string.IsNullOrEmpty(orderInfo.coupon))
{
await _couponServices.CancelReturnCoupon(orderInfo.coupon);
}
//状态修改
await _dal.UpdateAsync(
p => new CoreCmsOrder()
{
payStatus = (int)GlobalEnumVars.OrderPayStatus.Refunded,
status = (int)GlobalEnumVars.OrderStatus.Cancel,
updateTime = DateTime.Now
}, p => p.orderId == orderId);
var orderItems = await _orderItemServices.QueryListByClauseAsync(p => p.orderId == orderId);
//更改库存
foreach (var item in orderItems)
{
_goodsServices.ChangeStock(item.productId, GlobalEnumVars.OrderChangeStockType.cancel.ToString(), item.nums);
}
jm.msg = "订单取消成功请前往退款单退款。";
return jm;
}
#region #region
/// <summary> /// <summary>
@@ -1669,7 +1819,10 @@ namespace CoreCms.Net.Services
{ {
html.Append("<a class='layui-btn layui-btn-xs edit-order' lay-active='editOrder' data-id='" + orderId + "'>编辑</a><br>"); html.Append("<a class='layui-btn layui-btn-xs edit-order' lay-active='editOrder' data-id='" + orderId + "'>编辑</a><br>");
html.Append("<a class='layui-btn layui-btn-xs ship-order' lay-active='shipOrder' data-id='" + orderId + "'>发货</a><br>"); html.Append("<a class='layui-btn layui-btn-xs ship-order' lay-active='shipOrder' data-id='" + orderId + "'>发货</a><br>");
if (shipStatus == (int)GlobalEnumVars.OrderShipStatus.No)
{
html.Append("<a class='layui-btn layui-btn-xs layui-btn-danger cancel-order' lay-active='cancelOrderAndRefund' data-id='" + orderId + "'>取消并退款</a><br>");
}
if (receiptType == (int)GlobalEnumVars.OrderReceiptType.IntraCityService || receiptType == (int)GlobalEnumVars.OrderReceiptType.SelfDelivery) if (receiptType == (int)GlobalEnumVars.OrderReceiptType.IntraCityService || receiptType == (int)GlobalEnumVars.OrderReceiptType.SelfDelivery)
{ {
html.Append("<a class='layui-btn layui-btn-xs layui-btn-normal seconds-ship-order' lay-active='secondsShipOrder' data-id='" + orderId + "'>秒发</a><br>"); html.Append("<a class='layui-btn layui-btn-xs layui-btn-normal seconds-ship-order' lay-active='secondsShipOrder' data-id='" + orderId + "'>秒发</a><br>");

View File

@@ -108,7 +108,12 @@ namespace CoreCms.Net.Services
var res = await _userBalanceServices.Change(paymentInfo.userId, var res = await _userBalanceServices.Change(paymentInfo.userId,
(int)GlobalEnumVars.UserBalanceSourceTypes.Refund, refundInfo.money, paymentInfo.paymentId); (int)GlobalEnumVars.UserBalanceSourceTypes.Refund, refundInfo.money, paymentInfo.paymentId);
if (res.status == false) return jm; if (res.status == false)
{
jm.msg = res.msg;
jm.status = false;
return jm;
}
jm.status = true; jm.status = true;
jm.data = res; jm.data = res;
jm.msg = "退款成功"; jm.msg = "退款成功";

View File

@@ -525,6 +525,11 @@
var id = $(this).attr('data-deliveryId'); var id = $(this).attr('data-deliveryId');
refreshDelivery(id); refreshDelivery(id);
}, },
//取消订单并退款
cancelOrderAndRefund: function () {
var id = $(this).attr('data-id');
doCancelOrderAndRefund(id);
},
}); });
//头工具栏事件 //头工具栏事件
@@ -1212,6 +1217,21 @@
}); });
} }
//取消订单并退款
function doCancelOrderAndRefund(id) {
layer.confirm('确认取消订单号:' + id + ' 的订单吗?', {
title: '提示', btn: ['确认', '取消'] //按钮
}, function () {
coreHelper.Post("Api/CoreCmsOrder/CancelOrderAndRefund", { id: id }, function (e) {
layer.msg(e.msg, { time: 1300 }, function () {
layui.table.reloadData('LAY-app-CoreCmsOrder-tableBox'); //重载表格
doreLoadOrderCount();
});
});
});
return false;
}
//完成订单 //完成订单
function doCompleteOrder(id) { function doCompleteOrder(id) {
coreHelper.Post("Api/CoreCmsOrder/GetDoHaveAfterSale", { id: id }, function (e) { coreHelper.Post("Api/CoreCmsOrder/GetDoHaveAfterSale", { id: id }, function (e) {