Commit 657119da by yink

feat: 添加订单退款功能并优化积分解冻逻辑

- 在订单管理中添加退款功能,支持管理员手动退款
- 优化积分解冻逻辑,增加7天解冻期
- 更新商品库存管理,确保退款时库存正确恢复
- 修改积分记录处理逻辑,支持退款时的积分返还
parent 5ab76182
......@@ -10,6 +10,7 @@
use Dcat\Admin\Show;
use Dcat\Admin\Http\Controllers\AdminController;
use App\Admin\Actions\TransferToPlatForm;
use App\Models\StoreAdminUsers;
class OrderDivideRecordController extends AdminController
{
......@@ -29,21 +30,23 @@ protected function grid()
$grid->column('order_price', '订单商品价格');
$grid->column('divide_price', '佣金');
//$grid->column('proportion', '分佣比例%');
$grid->column('sh_type', '推荐类型')->display(function ($val) {
$arr = ['平台', '直推', '间推', '商家'];
return $arr[$val];
$grid->column('sh_type', '分佣类型')->display(function ($val) {
return OrderDivideRecord::COMMISSION_TYPE[$val];
});
$grid->column('is_div', '是否分账')->display(function ($val) {
$grid->column('is_div', '是否分账')->display(function ($val) {
return $val == 1 ? '是' : '否';
});
$grid->column('um_id', '推荐公司/分享人')->display(function ($val) {
$grid->column('um_id', '商户/员工')->display(function ($val) {
$stype = $this->sh_type;
$name = '';
if ($stype == 3) {
if ($stype == 0) {
$name = '平台';
} else if ($stype == 3) {
$name = Merchant::where('id', $val)->value('name');
} else {
$name = $stype ? User::where('id', $val)->value('phone') : '';
}else if($stype == 5){
$name = StoreAdminUsers::where('id', $val)->value('name');
}
return $name;
});
$grid->column('remark', '备注')->width(80);
......@@ -56,6 +59,41 @@ protected function grid()
$grid->disableDeleteButton();
$grid->disableRowSelector();
// 添加导出字段映射
$titles = [
'id' => 'ID',
'order.order_sn' => '订单号',
'users.phone' => '会员手机号',
'order_price' => '商品价格',
'divide_price' => '分佣金额',
'sh_type' => '分佣类型',
'is_div' => '是否分账',
'um_id' => '推荐人/商家',
'created_at' => '创建时间'
];
// 添加导出按钮
$grid->export($titles)->rows(function ($rows) {
foreach ($rows as $index => &$row) {
// 处理分佣类型显示
$row['is_div'] = $row['is_div'] == 1? '是' : '否';
$row['um_id'] = $row['um_id'] == 0? '平台' : $row['um_id'];
// 处理商家/员工显示
if ($row['sh_type'] == 0) {
$row['um_id'] = '平台';
} else if ($row['sh_type'] == 3) {
$row['um_id'] = Merchant::where('id', $row['um_id'])->value('name');
}else if($row['sh_type'] == 5){
$row['um_id'] = StoreAdminUsers::where('id', $row['um_id'])->value('name');
}
$row['sh_type'] = OrderDivideRecord::COMMISSION_TYPE[$row['sh_type']];
}
return $rows;
});
$grid->filter(function (Grid\Filter $filter) {
// 更改为 panel 布局
$filter->panel();
......@@ -64,12 +102,17 @@ protected function grid()
$filter->between('created_at', '创建时间')->datetime()->width(4);
});
$grid->actions(function (Grid\Displayers\Actions $actions) {
//分账给平台
if ($actions->row->is_div == 0 && in_array($actions->row->sh_type, [1, 2])) {
$actions->append(new TransferToPlatForm('分账给平台', $actions->row->id));
}
});
//先注释,目前没有手动分账金额给平台说法
// $grid->actions(function (Grid\Displayers\Actions $actions) {
// //分账给平台
// if ($actions->row->is_div == 0 && in_array($actions->row->sh_type, [1, 2])) {
// $actions->append(new TransferToPlatForm('分账给平台', $actions->row->id));
// }
// });
});
}
......
......@@ -17,6 +17,8 @@
use App\Admin\Forms\VerifierCodeForm;
use App\Admin\Forms\ShippingForm;
use Dcat\Admin\Admin;
use App\Http\Controllers\Api\OrderController;
use Illuminate\Support\Facades\DB;
class OrderInfoController extends AdminController
......@@ -33,6 +35,9 @@ protected function grid()
$grid->column('id')->sortable();
$grid->column('order_sn', '订单号')->width(80);
$grid->column('mobile', '手机号');
$grid->column('is_div', '已分账')->display(function ($val) {
return $val ? '是' : '否';
});
$grid->column('goods', '商品信息')->expand(function (Grid\Displayers\Expand $expand) {
$expand->button('查看');
......@@ -170,7 +175,18 @@ protected function grid()
});
$titles = ['id' => 'ID', 'goods_name' => '名称', 'address_id' => '邮箱'];
$titles = [
'id' => 'ID',
'order_sn' => '订单号',
'mobile' => '手机号',
'goods_name' => '商品名称',
'goods_attr' => '商品规格',
'goods_number' => '商品数量',
'goods_price' => '商品单价',
'goods_amount' => '订单金额',
'order_status' => '订单状态',
'created_at' => '下单时间'
];
// 添加导出按钮
$grid->export($titles)->rows(function ($rows) {
......@@ -198,7 +214,45 @@ protected function grid()
return $rows;
});
// 添加退款操作按钮
$grid->actions(function (Grid\Displayers\Actions $actions) {
//只对特定状态的订单显示退款按钮
if ($this->is_div == 0 ) {
$actions->append('<a href="javascript:void(0)" class="refund-order" data-id="'.$this->id.'"><i class="feather icon-refresh-ccw"></i> 退款</a>');
}
});
// 添加退款操作的JS代码
Admin::script(<<<JS
$('.refund-order').click(function() {
var id = $(this).data('id');
Dcat.confirm('确定要给该笔订单退款吗?支付金额会原路返回。', null, function() {
Dcat.loading();
$.ajax({
url: '/order-refund',
type: 'POST',
data: {
id: id,
_token: Dcat.token
},
success: function(data) {
Dcat.loading(false);
if (data.status) {
Dcat.success(data.message);
Dcat.reload();
} else {
Dcat.error(data.message);
}
},
error: function() {
Dcat.loading(false);
Dcat.error('请求失败,请重试');
}
});
});
});
JS);
});
}
......@@ -266,4 +320,32 @@ protected function form()
$form->disableViewButton();
});
}
//管理员退款
/**
* 管理员退款功能
* 功能:处理订单退款操作,包括退款金额原路返回和库存恢复
* 参数:无显式参数,通过request获取订单ID
* 返回值:json格式,包含操作状态和消息
* 异常:捕获数据库操作异常并回滚
* 使用示例:前端通过AJAX调用/order-refund接口
* 注意事项:1.仅对特定状态订单可退款 2.使用事务保证数据一致性 3.记录操作日志
*/
public function OrderAdminRefund()
{
$id = request('id');
$orderObj = OrderInfo::find($id);
if (!$orderObj) {
return response()->json(['status' => false, 'message' => '订单不存在']);
}
if ($orderObj->is_div == 0) {
OrderController::canceOrderFunc($orderObj);
}else{
return response()->json(['status' => false, 'message' => '已分账,不允许退款!']);
}
}
}
......@@ -56,6 +56,7 @@
$router->resource('setting', 'SystemSettingController'); //数值设置
$router->resource('orderInfo', 'OrderInfoController'); //订单管理
$router->post('order-refund', 'OrderInfoController@OrderAdminRefund'); // 添加退款路由
$router->resource('order-divide-record', 'OrderDivideRecordController'); //订单分佣记录
......
......@@ -2,7 +2,29 @@
namespace App\Command;
use Illuminate\Http\Request;
class Log{
class Log {
/**
* 获取当前请求对象
* @return Request|null 返回当前请求对象或null
*
* 功能说明:
* 1. 尝试通过Laravel的request()辅助函数获取当前请求
* 2. 如果辅助函数不可用,则返回null
*
* 使用示例:
* $request = Log::getCurrentRequest();
*
* 注意事项:
* 1. 此方法依赖Laravel的请求上下文
* 2. 在非HTTP请求环境(如命令行)中会返回null
*/
static private function getCurrentRequest(): ?Request
{
if (function_exists('request')) {
return request();
}
return null;
}
// 私有方法:构建用户信息
static private function buildUserInfo(?Request $request): string {
if ($request && $request->user()) {
......@@ -41,8 +63,9 @@ static private function ensureLogDir(string $logPath): void {
}
//保留兼容以前日志
static public function add(string $logKey, mixed $logInfo, ?Request $request = null): void {
static public function add(string $logKey, mixed $logInfo): void {
try {
$request = self::getCurrentRequest();
$day = date('Y-m-d');
$logPath = storage_path("logs/a_runLog_".$day.".log");
self::ensureLogDir($logPath);
......@@ -55,8 +78,9 @@ static public function add(string $logKey, mixed $logInfo, ?Request $request = n
}
// 中间件请求
static public function RequestLog(string $logKey, mixed $logInfo, ?Request $request = null): void {
static public function RequestLog(string $logKey, mixed $logInfo,Request $Request=null): void {
try {
$request = self::getCurrentRequest();
$day = date('Y-m-d');
$logPath = storage_path("logs/a_runLog_Request".$day.".log");
self::ensureLogDir($logPath);
......@@ -68,20 +92,20 @@ static public function RequestLog(string $logKey, mixed $logInfo, ?Request $requ
}
}
//addByName==info
// 错误日志
static public function error(string $logKey,mixed $logInfo, ?Request $request = null): void {
self::writeNamedLog('a_error_', $logKey, $logInfo, $request, 'addByName');
static public function error(string $logKey, mixed $logInfo): void {
self::writeNamedLog('a_error_', $logKey, $logInfo, 'addByName');
}
// 信息日志
static public function info( mixed $logInfo, ?Request $request = null): void {
self::writeNamedLog('a_runLog_','debug', $logInfo, $request, 'info');
static public function info(mixed $logInfo): void {
self::writeNamedLog('a_runLog_', 'debug', $logInfo, 'info');
}
// 私有方法:处理命名日志
static private function writeNamedLog(string $prefix, string $logKey, mixed $logInfo, ?Request $request, string $methodName): void {
static private function writeNamedLog(string $prefix, string $logKey, mixed $logInfo, string $methodName): void {
try {
$request = self::getCurrentRequest();
$logPath = storage_path("logs/{$prefix}{$logKey}.log");
self::ensureLogDir($logPath);
$userInfo = self::buildUserInfo($request);
......
......@@ -19,7 +19,6 @@
class HfOrderController extends BaseController
{
//退款回调
public function refundNotify()
{
......
......@@ -69,7 +69,7 @@ public function CreateBuyOrder(Request $request)
$orderObj = new OrderInfoModel();
$userObj = $request->user();
$user_id = $userObj->id;
$merchant_id = (int)$userObj->merchant_id; //绑定企业
$merchant_id = (int)$userObj->merchant_id; //绑定的商户ID
$spuid = $userObj->spuid; //直推
$goods_id = $request->goods_id;
$num = $request->num ?? 1;
......@@ -83,14 +83,11 @@ public function CreateBuyOrder(Request $request)
$consignee = $request->consignee ?? '';
//$address_id = $request->address_id ?? 0; //地址ID
$pay_type = $request->pay_type; //支付方式 1:微信 2:积分 3:混合
if (!in_array($pay_type, [1, 2, 3])) {
return $this->JsonResponse('', '请选择支付方式', 500);
}
$buycode = $request->buycode; //直购码
$goodsObj = GoodModel::find($goods_id);
if (!$goodsObj) {
return $this->JsonResponse('', '参数错误', 201);
return $this->JsonResponse('', '商品参数错误', 201);
}
// $userAddress = '';
// if ($address_id) {
......@@ -110,47 +107,23 @@ public function CreateBuyOrder(Request $request)
if ($attr_id) {
$arrObj = GoodSku::where(['id' => $attr_id, 'goods_id' => $goods_id])->first();
if (!$arrObj) {
return $this->JsonResponse('', '参数错误', 201);
return $this->JsonResponse('', 'sku参数错误', 201);
} else {
if ($arrObj->stock < $num) {
return $this->JsonResponse('', '该商品库存不足', 500);
}
}
$attr_val = $arrObj ? $arrObj->attr_val : '';
$good_price = ($arrObj && $goodsObj->goods_type && $merchant_id) ? $arrObj->cg_price : $arrObj->market_price;
$good_price = ($arrObj && $goodsObj->goods_type && $merchant_id && $buycode) ? $arrObj->cg_price : $arrObj->market_price;
}
//商品总价
$total_price = ($good_price * $num);
$point_amount = $total_price;//积分抵扣金额
$order_amount=$total_price;//订单金额
$order_amount = $total_price; //订单金额
$order_status = 0;
$pay_status = 0;
//判断支付方式
if ($pay_type == 1 ) {
$point_amount=0;//不用积分支付
}else if ($pay_type == 2 ) {
if ($userObj->balance < $total_price) {
return $this->JsonResponse('', '积分不足!', 500);
}
//扣除积分
if (!UserPointChangeRec::pointChangeRecord($userObj->id, $total_price, 0, 2)) {
return $this->JsonResponse('', '网络异常,积分抵扣失败!', 500);
}
$order_amount=0;
$order_status = 1;
$pay_status = 1;
}else if($pay_type == 3){
if ($userObj->balance >= $total_price) {
return $this->JsonResponse('', '积分充足,可选择积分支付!', 500);
}
$point_amount=$userObj->balance;
$order_amount=$total_price-$point_amount;
}
$tmp = [];
$tmp['goods_id'] = $goods_id;
......@@ -172,7 +145,6 @@ public function CreateBuyOrder(Request $request)
$orderObj->mobile = $phone;
$orderObj->goods_amount = $total_price;
$orderObj->order_amount = $order_amount;
$orderObj->point_amount = $point_amount;
$orderObj->order_status = $order_status;
$orderObj->pay_status = $pay_status;
$orderObj->goods_sn = $goodObj->goods_sn;
......@@ -190,7 +162,7 @@ public function CreateBuyOrder(Request $request)
DB::commit();
//15分钟取消订单
//$this->dispatch(new CancelOrder($orderObj, 900));
return $this->JsonResponse(['order_id' => $orderObj->id]);
return $this->JsonResponse(['order_id' => $orderObj->id, 'order_amount' => $order_amount]);
} catch (\Exception $exception) {
Log::add('创建预支付订单失败', $exception->getMessage());
DB::rollBack();
......@@ -215,10 +187,7 @@ public function CreateOrder(Request $request)
$phone = $request->phone ? $request->phone : $userObj->phone;
$consignee = $request->consignee ?? '';
$pay_type = $request->pay_type; //支付方式 1:微信 2:积分 3:混合
if (!in_array($pay_type, [1, 2, 3])) {
return $this->JsonResponse('', '请选择支付方式', 500);
}
$buycode = $request->buycode; //直购码
if (!$catKey) {
return $this->JsonResponse('', '参数错误', 201);
......@@ -254,7 +223,7 @@ public function CreateOrder(Request $request)
return $this->JsonResponse('', '该商品库存不足!', 500);
}
}
$goods_price = ($merchant_id && $goodsObj->goods_type) ? $skuObj->cg_price : $skuObj->market_price;
$goods_price = ($merchant_id && $goodsObj->goods_type && $buycode) ? $skuObj->cg_price : $skuObj->market_price;
$goods_img = isset($goodsObj->cover_img) ? $goodsObj->cover_img : '';
$goods_name .= $goodsObj->goods_name . "、";
......@@ -278,35 +247,10 @@ public function CreateOrder(Request $request)
return $this->JsonResponse('', '参数错误', 201);
}
$point_amount = $total_price; //积分抵扣金额
$order_amount = $total_price; //订单金额
$order_status = 0;
$pay_status = 0;
//判断支付方式
if ($pay_type == 1) {
$point_amount = 0; //不用积分支付
} else if ($pay_type == 2) {
if ($userObj->balance < $total_price) {
return $this->JsonResponse('', '积分不足!', 500);
}
//扣除积分
if (!UserPointChangeRec::pointChangeRecord($userObj->id, $total_price, 0, 2)) {
return $this->JsonResponse('', '网络异常,积分抵扣失败!', 500);
}
$order_amount = 0;
$order_status = 1;
$pay_status = 1;
} else if ($pay_type == 3) {
if ($userObj->balance >= $total_price) {
return $this->JsonResponse('', '积分充足,可选择积分支付!', 500);
}
$point_amount = $userObj->balance;
$order_amount = $total_price - $point_amount;
}
$orderObj->order_sn = $order_sn;
$orderObj->user_id = $user_id;
......@@ -316,7 +260,6 @@ public function CreateOrder(Request $request)
$orderObj->mobile = $phone;
$orderObj->goods_amount = $total_price;
$orderObj->order_amount = $order_amount;
$orderObj->point_amount = $point_amount;
$orderObj->order_status = $order_status;
$orderObj->pay_status = $pay_status;
$orderObj->delivery_type = $delivery_type;
......@@ -337,7 +280,7 @@ public function CreateOrder(Request $request)
$userObj->save();
DB::commit();
return $this->JsonResponse(['order_id' => $orderObj->id]);
return $this->JsonResponse(['order_id' => $orderObj->id, 'order_amount' => $order_amount]);
} catch (\Exception $exception) {
Log::add('创建购物车订单失败', $exception->getMessage());
DB::rollBack();
......@@ -364,21 +307,83 @@ private function getOrderSn()
public function pay(Request $request)
{
$order_id = $request->order_id ?? 0;
$openid = $request->user()->openid;
$userObj = $request->user();
$openid = $userObj->openid;
$pay_type = $request->pay_type; //支付方式 1:微信 2:积分 3:混合
if (!in_array($pay_type, [1, 2, 3])) {
return $this->JsonResponse('', '请选择支付方式', 500);
}
DB::beginTransaction();
try {
$res = '';
// 订单不存在直接返回错误
$order = OrderInfoModel::find($order_id);
if ($order->pay_cs > 0 && $order->pay_cs < 20) {
if (!$order) {
return $this->JsonResponse('', '订单不存在', 404);
}
// 订单状态必须为待支付(0)
if ($order->order_status != 0) {
return $this->JsonResponse('', '请勿重复支付!', 500);
}
if ($order->pay_cs < 20) {
$order_record = $order->order_record ?? $order->order_sn;
$order->order_sn = $this->getOrderSn();
$order->order_record = $order_record . "|" . $order->order_sn;
$order->pay_type = $pay_type; //订单支付方式
$order->save();
}
$point_amount = 0; //积分抵扣金额
$order_amount = $order->order_amount; //订单金额
//判断支付方式
if ($pay_type == 1) {
$order->point_amount = $point_amount; //积分抵扣金额
} else if ($pay_type == 2) {
if ($userObj->balance < $order_amount) {
return $this->JsonResponse('', '积分不足!', 500);
}
//扣除积分
if (!UserPointChangeRec::pointChangeRecord($userObj->id, $order_amount, 0, 2, 1, $order_id)) {
return $this->JsonResponse('', '网络异常,积分抵扣失败!002', 500);
}
//积分支付
$order->point_amount = $order_amount; //积分抵扣金额
$order->pay_cs += 1;
$order->order_amount = 0; //订单金额0
$order->pay_status = 1; //支付状态
$order->order_status = 1; //订单状态
$order->save();
DB::commit();
return $this->JsonResponse('', '积分支付成功!', 200);
} else if ($pay_type == 3) {
if ($userObj->balance >= $order_amount) {
return $this->JsonResponse('', '积分充足,可选择积分支付!', 500);
}
//扣除积分
if (!UserPointChangeRec::pointChangeRecord($userObj->id, $userObj->balance, 0, 2, 1, $order_id)) {
return $this->JsonResponse('', '网络异常,积分抵扣失败!003', 500);
}
$order_amount = $order_amount - $userObj->balance;
$order->point_amount = $userObj->balance; //积分抵扣金额
$order->order_amount = $order_amount;
}
$res = '';
$orderGoodsObj = OrderGoods::where("order_id", $order_id)->first();
$order_title = $orderGoodsObj ? $orderGoodsObj->goods_name : '';
Log::add('--支付订单号ID--', ['order_id' => $order_id, 'order_sn' => $order->order_sn]);
$res = (new Adapay())->pay($order_title, $order->order_sn, $order->order_amount, $openid);
$res = (new Adapay())->pay($order_title, $order->order_sn, $order_amount, $openid);
$order->pay_cs += 1;
$order->save();
......@@ -455,6 +460,7 @@ public function orderList(Request $request)
return $this->JsonResponse($data);
}
//取消订单
public function canceOrder(Request $request)
{
$order_id = $request->order_id ?? null;
......@@ -468,52 +474,67 @@ public function canceOrder(Request $request)
if (!in_array($model->order_status, [0, 1])) {
return $this->JsonResponse('', '不满足取消条件' . $model->order_status, 500);
}
$this->canceOrderFunc($model);
return $this->JsonResponse('');
}
//取消订单-纯方法
public static function canceOrderFunc($order)
{
DB::beginTransaction();
try {
//未分账才可以退款
if ($order->is_div == 1) {
return $this->JsonResponse('', '订单已分账,无法取消!', 500);
}
$Adapay = new Adapay();
//代到货订单--退库存
if ($model->order_status == 1) {
//更新商品库存
$goodsList = OrderGoods::where("order_id", $order_id)->get();
foreach ($goodsList as $item) {
$gid = $item->goods_id;
$attr_id = $item->attr_id;
$mer_id = $item->merchant_id;
$goods_number = $item->goods_number;
$goodsObj = GoodModel::find($gid);
//更新商品规格库存
$attrObj = GoodSku::find($attr_id);
$attr_stock = $attrObj->stock + $goods_number;
$attrObj->stock = $attr_stock;
$attrObj->save();
//更新商品sku
$skuArr = json_decode($goodsObj->sku, true);
if ($skuArr['sku']) {
foreach ($skuArr['sku'] as $kk => $vv) {
if (isset($vv['attr_sn']) && $vv['attr_sn'] == $attrObj->attr_sn) {
$skuArr['sku'][$kk]['stock'] = $attr_stock;
}
}
$goodsObj->sku = json_encode($skuArr, JSON_UNESCAPED_UNICODE);
$goodsObj->save();
}
//商户规格库存
$mgsObj = MerchantGoodSku::where(['goods_id' => $gid, 'attr_id' => $attr_id, 'merchant_id' => $mer_id])->first();
if ($mer_id && $mgsObj) {
$changeStock = $mgsObj->stock + $goods_number;
$mgsObj->stock = $changeStock;
$mgsObj->save();
}
}
if ($order->order_status == 1) {
$Adapay->updateGoodsStock($order);
}
//待发货订单--退款
if ($model->order_status == 1 && $model->order_amount > 0) {
$order_sn = $model->order_sn;
//未分账订单,退款
if ($order->order_amount > 0) {
$order_sn = $order->order_sn;
$refund_no = "R" . date("YmdHis") . rand(100000, 999999); //退单号
$result = (new Adapay())->refund($order_sn, $refund_no);
$result = $Adapay->refund($order_sn, $refund_no);
Log::info($result);
}
$model->order_status = 7;
$model->save();
//判断是否现金支付,查询是否需要收回冻结中的积分
if ($order->pay_type == 1) {
// 先获取结果集再操作
$userPointChangeRecs = UserPointChangeRec::where([
'order_id' => $order->id,
'point_state' => '<>1',
'change_type' => 1
])->get();
Log::Add('canceOrderFunc', '冻结积分删除记录:' . json_encode($userPointChangeRecs->toArray()));
// 批量删除冻结中的积分
UserPointChangeRec::where([
'order_id' => $order->id,
'point_state' => '<>1',
'change_type' => 1
])->delete();
}
//查询是否需要退用户积分
if ($order->point_amount > 0) {
//新增积分
if (!UserPointChangeRec::pointChangeRecord($order->user_id, $order->point_amount, 1, 4, 1, $order->id)) {
return $this->JsonResponse('', '网络异常,积分返还失败!002', 500);
}
}
$order->order_status = 7;
$order->save();
DB::commit();
} catch (\Exception $exception) {
......@@ -524,6 +545,7 @@ public function canceOrder(Request $request)
return $this->JsonResponse('');
}
public function delOrder(Request $request)
{
$order_id = $request->order_id ?? null;
......@@ -629,11 +651,15 @@ public function scanCodeVerifi(Request $request)
$orderObj->shipping_type = 4;
$orderObj->shipping_goods = $ogItem->shipping_goods;
$orderObj->shipping_at = date("Y-m-d H:i:s");
//更新订单状态为解冻中,解冻7天,到期后分发佣金
$orderObj->start_freeze_time = date('Y-m-d H:i:s');
$orderObj->save();
//更新积分状态为解冻中,解冻7天,到期后发放积分到账户积分余额
userPointChangeRec::pointUnfreezeimg($orderObj);
}
//更新积分状态为解冻中,解冻7天
userPointChangeRec::pointUnfreeze($orderObj);
DB::commit();
} catch (Exception $e) {
......@@ -859,7 +885,7 @@ public function refreshTokenLYK(Request $request)
/**
* 轮询查询解冻结束的积分,改成已完成,积分转入余额
* @param Request $request HTTP请求对象
......@@ -927,8 +953,4 @@ public function pointUnfreezeComplete(Request $request)
return $this->JsonResponse([], '解冻积分处理失败', 500);
}
}
}
......@@ -141,7 +141,7 @@ public function updateOrderStatusToDiv(Request $request)
if ($orderList) {
foreach ($orderList as $kk => $order) {
$orderObj = OrderInfo::find($order->id);
//分账
if (Adapay::handlePaymentConfirmAndDivide($orderObj->order_no, $orderObj->id)) {
$orderObj->is_div = 1;
$orderObj->save();
......@@ -157,6 +157,77 @@ public function updateOrderStatusToDiv(Request $request)
/**
* 轮训用户积分解冻中积分,改成已解冻,积分进入用户账户
* @return bool 返回操作结果
*
* 功能说明:
* 1. 查询所有解冻中(状态为2)的积分记录
* 2. 检查解冻结束日期是否已到
* 3. 将符合条件的记录状态更新为已完成(1)
* 4. 将积分转入用户账户
*
* 使用示例:
* UserPointChangeRec::pointUnfreezeEnd();
*
* 注意事项:
* 1. 仅处理状态为解冻中(2)的积分记录
* 2. 仅处理解冻结束日期小于当前时间的记录
* 3. 操作在事务中进行,保证数据一致性
*/
public static function pointUnfreezeEnd(Request $request)
{
DB::beginTransaction();
try {
// 查询解冻中积分
$records = DB::table('user_point_change_rec')
->where([
'point_state' => 2, // 解冻中
'change_type' => 1 // 增加积分
])
->where('freeze_end_date', '<=', date('Y-m-d H:i:s'))
->get();
if ($records->isEmpty()) {
Log::add('point_unfreeze_end', [
'msg' => '没有找到可完成的解冻积分记录'
]);
return true;
}
foreach ($records as $record) {
// 更新积分记录状态为已完成
DB::table('user_point_change_rec')
->where('id', $record->id)
->update([
'point_state' => 1, // 已完成
'updated_at' => date('Y-m-d H:i:s')
]);
// 将积分转入用户账户
$user = User::find($record->user_id);
$user->balance += $record->point_amount;
$user->total_revenue += $record->point_amount;
$user->save();
}
DB::commit();
Log::add('point_unfreeze_end', [
'count' => count($records),
'msg' => '成功完成积分解冻'
]);
return true;
} catch (\Exception $e) {
DB::rollBack();
Log::add('point_unfreeze_end_error', [
'error' => $e->getMessage()
]);
return false;
}
}
}
......@@ -12,6 +12,7 @@
use App\Models\User;
use App\Models\UserAddress;
use App\Models\OrderDivideRecord;
use App\Models\UserPointChangeRec;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
......@@ -168,22 +169,15 @@ public function info(Request $request)
{
$user = $request->user();
$merchant_id = $user->merchant_id ?? 0;
$total_revenue = $user->total_revenue ?? 0; // 总金额
$merObj = Merchant::where('id', $merchant_id)->first();
$balanceValue = $merObj->balance ?? 0;
$user_id = $user->id ?? 0;
// 使用 Tools 类计算 T+1 未到账金额
$pendingCashout = Tools::calculatePendingCashout($user_id);
// 调整金额计算公式
$displayBalance = $balanceValue + $pendingCashout;
$displayCashout = $total_revenue - $displayBalance;
//计算冻结中、解冻中的积分
$frozen_balance = UserPointChangeRec::where('user_id', $user_id)->where('change_type', 1)->where('point_state', 3)->sum('point_amount');
$thawing_balance = UserPointChangeRec::where('user_id', $user_id)->where('change_type', 1)->where('point_state', 2)->sum('point_amount');
$balance = number_format($displayBalance, 2, '.', '');// 余额
$cashout = number_format($displayCashout, 2, '.', '');// 已提现
$balance = number_format($user->balance, 2, '.', '');// 余额
$frozen_balance = number_format($frozen_balance, 2, '.', '');// 冻结中
$thawing_balance = number_format($thawing_balance, 2, '.', '');// 解冻中
return $this->JsonResponse([
'user_id' => $user->id,
......@@ -194,9 +188,9 @@ public function info(Request $request)
//'status' => $user->status,
'merchant_id' => $merchant_id,
'buycode' => $user->buycode ?? '',
'balance' => $balance ?? 0,
'total_revenue' => $total_revenue ?? 0,
'cashout' => $cashout ?? 0
'balance' => $balance ?? 0,// 可用积分余额
'frozen_balance' => $frozen_balance ?? 0,// 冻结中的积分
'thawing_balance' => $thawing_balance ?? 0 // 解冻中的积分
]);
}
......@@ -480,6 +474,11 @@ public function getMyFriend(Request $request)
//绑定直购码
public function bindBuycode(Request $request)
{
$userObj = $request->user();
if ($userObj->buycode) {
return $this->JsonResponse('已经绑定过直购码');//直接返回成功
}
$code = $request->code ?? '';
$merObj = Merchant::where("buycode", $code)->first();
......@@ -488,7 +487,6 @@ public function bindBuycode(Request $request)
}
DB::beginTransaction();
try {
$userObj = $request->user();
$userObj->buycode = $code;
$userObj->merchant_id = $merObj->id;
$userObj->save();
......
......@@ -65,10 +65,10 @@ public function pay($order_title, $order_sn, $order_amount, $openid)
}
}
//支付回调-分账--》改成冻结,6天后解冻分账
//支付回调-分账--》改成冻结,7天后解冻分账
public function payNotify($params = [])
{
$adapay_tools = new \NwVVVS\AdapaySdk\AdapayTools(); //验证签名
$post_data = json_decode($params['data'], 1);
$post_data_str = json_encode($post_data, JSON_UNESCAPED_UNICODE);
......@@ -97,47 +97,54 @@ public function payNotify($params = [])
$orderObj->pay_status = 1;
$orderObj->freeze_stat = $message['freeze_stat'];
if ($orderObj->save()) {
//更新商品销量、库存
$goodsList = OrderGoods::where("order_id", $orderObj->id)->get();
foreach ($goodsList as $item) {
//Log::add('--订单商品对象--', $item);
$gid = $item->goods_id;
$attr_id = $item->attr_id;
$mer_id = $item->merchant_id;
$goods_number = $item->goods_number;
if ($orderObj->pay_type=1) {//纯现金支付才返积分
//创建直推分积分记录
$this->createPointRecordByOrder($orderObj->id);
//更新此商品支付状态
$item->is_pay = 1;
$item->save();
$goodsObj = GoodModel::find($gid);
//更新商品规格库存
$attrObj = GoodSku::find($attr_id);
$attr_stock = ($attrObj->stock - $goods_number) >= 0 ? $attrObj->stock - $goods_number : 0;
$attrObj->stock = $attr_stock;
$attrObj->save();
//更新商品sku
$skuArr = json_decode($goodsObj->sku, true);
if ($skuArr['sku']) {
foreach ($skuArr['sku'] as $kk => $vv) {
if (isset($vv['attr_sn']) && $vv['attr_sn'] == $attrObj->attr_sn) {
$skuArr['sku'][$kk]['stock'] = $attr_stock;
}
}
$goodsObj->sku = json_encode($skuArr, JSON_UNESCAPED_UNICODE);
$goodsObj->save();
}
//商户规格库存
$mgsObj = MerchantGoodSku::where(['goods_id' => $gid, 'attr_id' => $attr_id, 'merchant_id' => $mer_id])->first();
if ($mer_id && $mgsObj) {
$changeStock = ($mgsObj->stock >= $goods_number) ? $mgsObj->stock - $goods_number : 0;
$mgsObj->stock = $changeStock;
$mgsObj->save();
}
}
//更新商品销量、库存
$this->updateGoodsStock($orderObj);
// //更新商品销量、库存
// $goodsList = OrderGoods::where("order_id", $orderObj->id)->get();
// foreach ($goodsList as $item) {
// //Log::add('--订单商品对象--', $item);
// $gid = $item->goods_id;
// $attr_id = $item->attr_id;
// $mer_id = $item->merchant_id;
// $goods_number = $item->goods_number;
// //更新此商品支付状态
// $item->is_pay = 1;
// $item->save();
// $goodsObj = GoodModel::find($gid);
// //更新商品规格库存
// $attrObj = GoodSku::find($attr_id);
// $attr_stock = ($attrObj->stock - $goods_number) >= 0 ? $attrObj->stock - $goods_number : 0;
// $attrObj->stock = $attr_stock;
// $attrObj->save();
// //更新商品sku
// $skuArr = json_decode($goodsObj->sku, true);
// if ($skuArr['sku']) {
// foreach ($skuArr['sku'] as $kk => $vv) {
// if (isset($vv['attr_sn']) && $vv['attr_sn'] == $attrObj->attr_sn) {
// $skuArr['sku'][$kk]['stock'] = $attr_stock;
// }
// }
// $goodsObj->sku = json_encode($skuArr, JSON_UNESCAPED_UNICODE);
// $goodsObj->save();
// }
// //商户规格库存
// $mgsObj = MerchantGoodSku::where(['goods_id' => $gid, 'attr_id' => $attr_id, 'merchant_id' => $mer_id])->first();
// if ($mer_id && $mgsObj) {
// $changeStock = ($mgsObj->stock >= $goods_number) ? $mgsObj->stock - $goods_number : 0;
// $mgsObj->stock = $changeStock;
// $mgsObj->save();
// }
// }
}
}
//支付记录
......@@ -174,10 +181,10 @@ public function payNotify($params = [])
return false;
}
$orderObj->freeze_stat = 'UNFREEZE';
$orderObj->start_freeze_time = date('Y-m-d H:i:s');
$orderObj->save();
// 调用汇付接口分账-6天后在解冻分账
// 调用汇付接口分账-6天后在解冻分账--》【改到updateOrderStatusToDiv里面去了】
//$this->handlePaymentConfirmAndDivide($order_no, $orderObj, $payment_confirm);
}
return true;
......@@ -524,7 +531,7 @@ public static function handlePaymentConfirmAndDivide($order_no, $order_id)
}
......@@ -606,7 +613,7 @@ public static function createPointRecordByOrder($order_id)
// 计算直推用户的积分
$total_first_commission = $goodsObj->total_first_commission;
// 为直推用户创建积分记录
UserPointChangeRec::pointChangeRecord ($spuid, $total_first_commission ,1,1,3, $order_id); //
UserPointChangeRec::pointChangeRecord($spuid, $total_first_commission, 1, 1, 3, $order_id); //
}
//判断间推是否存在
......@@ -614,9 +621,8 @@ public static function createPointRecordByOrder($order_id)
// 计算间推用户的积分
$total_second_commission = $goodsObj->total_second_commission;
// 为间推用户创建积分记录
UserPointChangeRec::pointChangeRecord ($second_spuid, $total_second_commission ,1,2,3, $order_id); //
UserPointChangeRec::pointChangeRecord($second_spuid, $total_second_commission, 1, 2, 3, $order_id); //
}
}
DB::commit();
......@@ -631,5 +637,87 @@ public static function createPointRecordByOrder($order_id)
}
}
/**
* 根据订单对象更新商品库存
*
* 功能说明:
* 1. 根据订单对象获取订单商品列表
* 2. 遍历订单商品,更新商品规格库存、商品SKU库存和商户规格库存
*
* 参数说明:
* @param OrderInfo $orderObj 订单对象
*
* 返回值说明:
* @return bool 更新成功返回true,失败返回false
*
* 异常说明:
* @throws Exception 当订单对象无效或商品不存在时抛出异常
*
* 使用示例:
* $order = OrderInfo::find(123);
* Adapay::updateGoodsStock($order);
*
* 注意事项:
* 1. 需要在事务中调用此方法
* 2. 会同时更新商品规格库存、商品SKU和商户规格库存
*/
public static function updateGoodsStock($orderObj)
{
if (!$orderObj || !$orderObj->id) {
throw new Exception('订单对象无效');
}
$orderGoods = OrderGoods::where('order_id', $orderObj->id)->get();
if ($orderGoods->isEmpty()) {
throw new Exception('订单商品不存在');
}
foreach ($orderGoods as $item) {
$goodsObj = GoodModel::find($item->goods_id);
if (!$goodsObj) {
Log::add('商品不存在', ['goods_id' => $item->goods_id]);
continue;
}
//更新商品规格库存
$attrObj = GoodSku::find($item->attr_id);
if (!$attrObj) {
Log::add('商品规格不存在', ['attr_id' => $item->attr_id]);
continue;
}
$attr_stock = ($attrObj->stock - $item->goods_number) >= 0 ? $attrObj->stock - $item->goods_number : 0;
$attrObj->stock = $attr_stock;
$attrObj->save();
//更新商品sku
$skuArr = json_decode($goodsObj->sku, true);
if ($skuArr['sku']) {
foreach ($skuArr['sku'] as $kk => $vv) {
if (isset($vv['attr_sn']) && $vv['attr_sn'] == $attrObj->attr_sn) {
$skuArr['sku'][$kk]['stock'] = $attr_stock;
}
}
$goodsObj->sku = json_encode($skuArr, JSON_UNESCAPED_UNICODE);
$goodsObj->save();
}
//商户规格库存
$mgsObj = MerchantGoodSku::where([
'goods_id' => $item->goods_id,
'attr_id' => $item->attr_id,
'merchant_id' => $orderObj->merchant_id
])->first();
if ($orderObj->merchant_id && $mgsObj) {
$changeStock = ($mgsObj->stock >= $item->goods_number) ? $mgsObj->stock - $item->goods_number : 0;
$mgsObj->stock = $changeStock;
$mgsObj->save();
}
}
return true;
}
}
......@@ -6,6 +6,7 @@
use Dcat\Admin\Traits\HasDateTimeFormatter;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\DB;
class OrderDivideRecord extends Model
{
......@@ -13,14 +14,17 @@ class OrderDivideRecord extends Model
use SoftDeletes;
protected $table = 'order_divide_record';
//佣金类别-//就是字段sh_type
public const COMMISSION_TYPE = [
1 => '直推佣金',//需求调整,不再分账,改成积分,支付时抵扣
2 => '间推佣金',//需求调整,不再分账,改成积分,支付时抵扣
3 => '用户取货佣金',
0 => '平台',
1 => '直推', //需求调整,不再分账,改成积分,支付时抵扣
2 => '间推', //需求调整,不再分账,改成积分,支付时抵扣
3 => '商户',
4 => '手动调账分账',
5 => '员工佣金',
5 => '员工',
];
/**
* 收益分配
* @param int $order_id 订单ID
......@@ -40,6 +44,10 @@ public static function divide($order_id, $payconfirm_no = '')
'merchant_member_id' => '',
'merchant_amount' => 0,
];
$employeePreData = [
'employee_member_id' => '',
'employee_amount' => 0,
];
//商户是否实名
$isMerchantRealName = 0;
......@@ -48,6 +56,17 @@ public static function divide($order_id, $payconfirm_no = '')
$isMerchantRealName = ($hfCompanyMObj->status == 'succeeded') ? 1 : 0;
}
//查询用户绑定的员工
$employee = DB::table('store_employee_user_rec')
->where('user_id', $buyer_id)
->first();
$isEmployeeRealName = 0;
if ($employee) {
$employeeObj = StoreAdminUsers::find($employee->employee_id);
$hfEmployeeMObj = HfCompanyMember::where('merchant_id', $employeeObj->merchant_id)->first();
$isEmployeeRealName = ($hfEmployeeMObj->status == 'succeeded') ? 1 : 0;
}
$ogList = OrderGoods::where("order_id", $order_id)->get(); //订单商品
foreach ($ogList as $kk => $item) {
$goods_amount = $item->goods_price * $item->goods_number;
......@@ -61,6 +80,13 @@ public static function divide($order_id, $payconfirm_no = '')
//商户分佣记录
if ($merchant_id && $merchant_commission >= 1 && $merchant_commission < 100) {
$divide_price = number_format($goods_amount * ($merchant_commission / 100), 2);
// 如果有员工绑定,扣除员工佣金部分
if ($employee && $employeeObj->commission_rate >= 1 && $employeeObj->commission_rate < 100) {
$employee_divide = number_format($divide_price * ($employeeObj->commission_rate / 100), 2);
$divide_price -= $employee_divide;
}
//收益直接到商户账户
$merObj = Merchant::find($merchant_id);
//汇付参数
......@@ -72,6 +98,15 @@ public static function divide($order_id, $payconfirm_no = '')
$commissionPreData['merchant_amount'] += $divide_price;
}
}
//员工分佣记录
if ($employee && $employeeObj->commission_rate >= 1 && $employeeObj->commission_rate < 100) {
// 基于商家分到佣金计算员工分佣
$merchant_divide_price = number_format($goods_amount * ($merchant_commission / 100), 2);
$employee_divide_price = number_format($merchant_divide_price * ($employeeObj->commission_rate / 100), 2);
$employeePreData['employee_amount'] += $employee_divide_price;
$employeePreData['employee_member_id'] = $hfEmployeeMObj->member_id;
}
}
//商户佣金
......@@ -82,8 +117,16 @@ public static function divide($order_id, $payconfirm_no = '')
}
}
//员工佣金
if ($employee && $employeePreData['employee_amount'] > 0) {
self::addRecord($sp_ogid, $order_id, $orderObj->goods_amount, $employeePreData['employee_amount'], $employeeObj->commission_rate, $employeeObj->member_id, $buyer_id, 5, $isEmployeeRealName, $payconfirm_no);
if ($isEmployeeRealName) {
array_push($div_members, ['member_id' => $employeePreData['employee_member_id'], 'amount' => sprintf("%.2f", $employeePreData['employee_amount']), 'fee_flag' => 'N']);
}
}
//平台本身
$aimeiyuePrice = $total_amount - $commissionPreData['merchant_amount'];
$aimeiyuePrice = $total_amount - $commissionPreData['merchant_amount'] - $employeePreData['employee_amount'];
self::addRecord($sp_ogid, $order_id, $orderObj->goods_amount, $aimeiyuePrice, '', 0, $buyer_id, 0, 1, $payconfirm_no);
array_push($div_members, ['member_id' => 0, 'amount' => sprintf("%.2f", $aimeiyuePrice), 'fee_flag' => 'Y']);
......@@ -91,7 +134,10 @@ public static function divide($order_id, $payconfirm_no = '')
if (!$isMerchantRealName) {
$commissionPreData['merchant_amount'] = 0;
}
$confirm_amt = $aimeiyuePrice + $commissionPreData['merchant_amount'];
if (!$isEmployeeRealName) {
$employeePreData['employee_amount'] = 0;
}
$confirm_amt = $aimeiyuePrice + $commissionPreData['merchant_amount'] + $employeePreData['employee_amount'];
return ['div_members' => $div_members, 'confirm_amt' => sprintf("%.2f", $confirm_amt)];
}
......@@ -104,7 +150,7 @@ public static function divide($order_id, $payconfirm_no = '')
* @param string $commission 佣金比例
* @param int $um_id 用户或商户ID
* @param int $buyer_id 买家ID
* @param int $sh_type 分账类型 推送类型 1:直推 2:间推 3:公司 4:手动分账 5:员工
* @param int $sh_type 分账类型 推送类型 0:平台 1:直推 2:间推 3:商户 4:手动分账 5:员工
* @param int $isExistAccount 是否实名
* @param string $payconfirm_no 支付确认编号
*/
......@@ -134,4 +180,4 @@ public function users()
{
return $this->belongsTo(User::class, 'user_id', 'id');
}
}
\ No newline at end of file
}
......@@ -19,13 +19,22 @@ public function user()
return $this->belongsTo(User::class, 'user_id');
}
//积分来源定义【source】
public const source = [
1 => '直推',
2 => '间推',
3 => '购物',
4 => '退款',
9 => '手动补偿',
];
/**
* 用户积分变更记录
* @param int $user_id 用户ID
* @param int $point_amount 积分数量
* @param int $change_type 变更类型:1-增加,0-减少 (默认1)
* @param int $source 积分来源:1-直推,2-间推,3-购物,9-手动补偿 (默认1)
* @param int $source 积分来源:1-直推,2-间推,3-购物,4-退款,9-手动补偿 (默认1)
* @param int $point_state 积分状态:1-已完成,2-解冻中,3-冻结中 (默认1)
* @param int $order_id 关联订单ID
* @param string $remark 备注信息
......@@ -42,7 +51,7 @@ public function user()
* 1. 积分数量必须为正整数
* 2. 变更类型必须为0或1
*/
public static function pointChangeRecord($user_id, $point_amount, $change_type = 1, $source = 1,$point_state = 1,$order_id='', $remark = '' )
public static function pointChangeRecord($user_id, $point_amount, $change_type = 1, $source = 1,$point_state = 1,$order_id=0, $remark = '' )
{
DB::beginTransaction();
try {
......@@ -119,7 +128,7 @@ public static function pointChangeRecord($user_id, $point_amount, $change_type
* 2. 解冻后状态变为解冻中(2)
* 3. 解冻结束日期为当前时间+7天
*/
public static function pointUnfreeze($orderObj)
public static function pointUnfreezeimg($orderObj)
{
DB::beginTransaction();
try {
......@@ -167,4 +176,7 @@ public static function pointUnfreeze($orderObj)
return false;
}
}
}
......@@ -21,6 +21,14 @@
Route::namespace('App\Http\Controllers\Api')->middleware('acceptJson')->group(function () {
//轮训接口
Route::post('updateOrderStatusToDiv','OrderDivideRecordController@updateOrderStatusToDiv'); //分佣订单解冻轮训
Route::post('pointUnfreezeEnd','OrderDivideRecordController@pointUnfreezeEnd'); //订单积分解冻轮训
//调试路由
Route::post('simulate-login','LoginController@simulateLogin'); //模拟登陆
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment