Files
2026-03-14 16:20:49 +08:00

541 lines
22 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace app\api\logic;
use app\common\logic\BaseLogic;
use app\common\logic\RefundLogic;
use app\common\model\order\Order;
use app\common\model\order\OrderAll;
use app\common\model\order\OrderGroup;
use app\common\model\order\OrderStore;
use app\common\model\order\OrderStoreRenew;
use app\common\model\pay\Pay;
use app\common\model\refund\RefundRecord;
use app\common\model\store\Store;
use app\common\model\store\StoreUserAccountLog;
use app\common\model\teastore\TeaStore;
use app\common\model\teastore\TeaStoreGroup;
use app\common\model\teastore\TeaStoreRoom;
use app\common\model\user\User;
use app\common\model\user\UserAccountLog;
use app\common\model\user\UserCoupon;
use app\common\model\user\UserGroup;
use app\common\model\user\UserStoreMoney;
use app\common\service\FileService;
use app\common\service\pay\WeChatPayService;
use think\facade\{Db, Config};
class PayLogic extends BaseLogic
{
// public static function yuePay($data,$user_id){
// $result = Pay::where("id",$data['id'])->find();
// $user = User::where("id",$user_id)->find();
// if($user['user_money'] < $result['order_amount']){
// throw new \Exception('余额不足');
// }
// $user->dec('user_money', $result['order_amount']);
// $user->save();
// $order_data['order_status'] = 1;
// $order_data['pay_status'] = 1;
// $order_data['update_dtime'] = date("Y-m-d H:i:s");
// Order::where("id",$result['order_id'])->update($order_data);
// $d['order_sn'] = createSn('pay','order_sn');
// $d['create_time'] = date("Y-m-d H:i:s");
// $d['pay_time'] = date("Y-m-d H:i:s");
// $result = Pay::where("id",$data['id'])->update($d);
// return $result;
// }
public static function yuePay($data, $user_id)
{
Db::startTrans();
try {
$payId = $data['id'];
$currentTime = date("Y-m-d H:i:s");
// 1. 查询支付记录(悲观锁)
$pay = Pay::where("id", $payId)->lock(true)->find();
if (!$pay) {
throw new \Exception('支付记录不存在');
}
// 支付记录状态检查
if ($pay['pay_status'] == 1) {
throw new \Exception('该支付记录已完成支付');
}
// 2. 查询关联订单
if($pay['order_type'] == 1){
$order = OrderStore::where("id", $pay['order_id'])->find();
}elseif($pay['order_type'] == 2){
$order = OrderGroup::where("id", $pay['order_id'])->find();
}elseif($pay['order_type'] == 7){
$order = OrderStoreRenew::where("id", $pay['order_id'])->find();
}
if (!$order) {
throw new \Exception('关联订单不存在');
}
// 3. 查询用户并检查余额(悲观锁)
$user = User::where("id", $user_id)->lock(true)->find();
if (!$user) {
throw new \Exception('用户不存在');
}
// 金额处理:保持数值类型用于计算,字符串类型用于显示
$amount = (float)$pay['order_amount'];
// 区分门店余额支付还是平台余额
if($data['pay_way'] == 3){
$user_store_money = UserStoreMoney::where("user_id",$user_id)->where("store_id",$data['store_id'])->find();
$userMoney = (float)$user_store_money['money'];
}else{
$userMoney = (float)$user['user_money'];
}
// 用于显示的格式化金额
$displayAmount = number_format($amount, 2);
$displayUserMoney = number_format($userMoney, 2);
if ($userMoney < $amount) {
throw new \Exception("余额不足,当前余额: {$displayUserMoney},需支付: {$displayAmount}");
}
// 4. 扣减用户余额(使用数值类型的 $amount
// $userSave = User::where("id", $user_id)->setDec('user_money', $amount);
$newBalance = round($userMoney - $amount, 2);
if($data['pay_way'] == 3){
$userSave = UserStoreMoney::where("user_id", $user_id)->where("store_id",$data['store_id'])->update(['money' => $newBalance,"update_dtime"=>date("Y-m-d H:i:s")]);
}else{
$userSave = User::where("id", $user_id)->update(['user_money' => $newBalance,"update_time"=>time()]);
}
if (!$userSave) {
throw new \Exception('用户余额扣减失败');
}
$change_type = 0;
$sub_sn = 0;
// 5. 更新订单状态
if($pay['order_type'] == 1) {
$change_type = 1;
$type = 3;
// 修改优惠券使用状态
if($order['group_coupon_id']>=0){
UserGroup::where("id", $order['group_coupon_id'])->update(["status"=>1]);
}
if($order['user_coupon_id']>=0){
UserCoupon::where('id',$order['user_coupon_id'])->update(["status"=>1]);
}
$amount = $order['order_amount'];
$orderUpdate = OrderStore::where("id", $pay['order_id'])->update([
'order_status' => 1,
'pay_status' => 1,
'update_dtime' => $currentTime
]);
if(isset($order['room_id'])){
if($order['room_id']!=0&&$order['room_id']!=""&&$order['room_id']!=null){
TeaStoreRoom::where('id', $order['room_id'])->inc('sold', 1)->update();
}
}
if (!$orderUpdate) {
throw new \Exception('订单状态更新失败');
}
}elseif($pay['order_type'] == 2){
$change_type = 4;
$type = 6;
$orderUpdate = OrderGroup::where("id", $pay['order_id'])->update([
'order_status' => 1,
'pay_status' => 1,
'update_dtime' => $currentTime
]);
if (!$orderUpdate) {
throw new \Exception('订单状态更新失败');
}
$qr_sn = createSn("user_group","qr_sn");
$qr_url = CommonLogic::qrcode($qr_sn);
$group = TeaStoreGroup::where('id', $order['group_id'])->find();
UserGroup::create([
"user_id"=>$user_id,
"group_id"=>$order['group_id'],
"qr_sn"=>$qr_sn,
"qr_url"=>$qr_url['file_url'],
"type"=>$group['type'],
"order_id"=>$order['id'],
"store_id"=>$order['store_id'],
"dtime"=>date("Y-m-d H:i:s")
]);
if(isset($order['group_id'])){
if($order['group_id']!=0&&$order['group_id']!=""&&$order['group_id']!=null){
TeaStoreGroup::where('id', $order['group_id'])->inc('sold', 1)->update();
}
}
}elseif($pay['order_type'] == 7){
$renew_order = OrderStoreRenew::where('id',$pay['order_id'])->find();
if(!$renew_order){
throw new \Exception('付款失败,订单不存在');
}
$source_id = $renew_order->source_id;
$store_order = OrderStore::where('id',$source_id)->find();
if(!$store_order){
throw new \Exception('包间订单错误,订单不存在');
}
$renew_timeslot = explode(',', $renew_order->timeslot);
$store_timeslot = explode(',', $store_order->timeslot);
$timeList = array_merge($store_timeslot, $renew_timeslot);
$end = end($timeList);
$renew_price = $renew_order->price;
$renew_order->pay_status = 1;
$renew_order->pay_dtime = 1;
$renew_order->save();
$transfer_order = OrderStore::where('transfer_order_id',$store_order['id'])->select();
$ids = explode(',',$store_order->id);
if($transfer_order->count() > 0){
$orderIds = $transfer_order->column('id');
$ids = array_merge($ids,$orderIds);
}
OrderStore::whereIn("id",$ids)->update([
"end_time"=>$end,
'timeslot'=>implode(',', $timeList),
'renew_dtime'=>implode(',', $timeList),
'is_renewal'=>1,
'renew_price'=>$renew_order->price+$store_order->renew_price,
'renew_hour'=>$renew_order->hour + $store_order->renew_hour,
'store_income_price'=>$store_order->store_income_price+$renew_price
]);
$change_type = 2;
$type = 7;
$sub_sn =$renew_order->order_sn;
$order['order_sn'] =$store_order->order_sn;
$order['store_id'] =$store_order->store_id;
$order['room_id'] =$store_order->room_id;
$amount = $renew_order->price;
}
OrderAll::where("source_sn", $order['order_sn'])->where("type", $type)->update([
'order_status' => 1,
'pay_status' => 1,
'pay_way'=>$order['pay_way'],
'update_time' => time()
]);
// 6. 更新支付记录
$payUpdate = Pay::where("id", $payId)->update([
'order_sn' => createSn('pay', 'order_sn'),
'pay_status' => 1,
'pay_time' => $currentTime
]);
if (!$payUpdate) {
throw new \Exception('支付记录更新失败');
}
// 7. 记录资金流水(使用数值类型的金额)
$moneyLog = self::addUserAccountLog(
$user_id,
$change_type,
$amount,
$userMoney,
$newBalance,
$order
);
$change_object = 1;
if($data['pay_way'] == 3){
$amount = 0;
$change_object = 3;
}
if($pay['order_type'] != 2){
// 记录店家资金流水(使用数值类型的金额)
self::addStoreUserAccountLog(
$data['pay_way'],
$pay['order_type'],
$user_id,
$change_object,
$change_type,
$amount,
$order,
$sub_sn
);
}
// 8. 记录支付日志
self::addPayLog($payId, $user_id, $amount, 'success');
Db::commit();
// 9. 支付成功后的后续操作(可异步处理)
self::afterPaySuccess($pay['order_id'], $user_id);
return [
'success' => true,
'pay_id' => $payId,
'order_id' => $pay['order_id'],
'order_sn' => $order['order_sn'],
'amount' => $displayAmount, // 返回格式化后的金额用于显示
'balance' => number_format($userMoney - $amount, 2) // 格式化余额
];
} catch (\Exception $e) {
Db::rollback();
// 记录支付失败日志
if (isset($payId)) {
self::addPayLog($payId, $user_id, $amount ?? 0, 'fail', $e->getMessage());
}
self::$error = $e->getMessage();
return false;
}
}
private static function addUserAccountLog($user_id,$change_type, $amount,$userMoney, $newBalance,$order)
{
return Db::name('user_account_log')->insert([
'sn'=>createSn("user_account_log","sn"),
'user_id' => $user_id,
'change_object'=>1,
'change_type'=>$change_type,
'action'=>2,
'amount' => $amount,
'before_amount'=>$userMoney,
'after_amount' => $newBalance,
'source_sn' => $order['order_sn'],
'store_id'=>$order['store_id'],
'create_time' => time()
]);
}
private static function addStoreUserAccountLog($pay_way,$order_type,$user_id,$change_object,$change_type, $amount,$order,$sub_sn)
{
$tea_store = TeaStore::where("id",$order['store_id'])->find();
// if($amount != 0){
StoreUserAccountLog::create([
'sn'=>createSn("store_user_account_log","sn"),
'change_object'=>$change_object,
'change_type'=>$change_type,
'user_id'=>$user_id,
'action'=>1,
'amount' => $amount,
'before_amount'=>$tea_store['balance'],
'after_amount' => round($amount+$tea_store['balance'],2),
'source_sn' => $order['order_sn'],
'store_id'=>$order['store_id'],
'sub_sn'=>$sub_sn,
'room_id'=>$order['room_id'],
'create_time' => time()
]);
// if($order_type == 7 ){
// TeaStore::where('id', $order['store_id'])->inc('total_amount', $amount)->update();
// TeaStore::where('id', $order['store_id'])->inc('balance', $amount)->update();
// }
if($pay_way != 3){
TeaStore::where('id', $order['store_id'])->inc('total_amount',$amount)->update();
TeaStore::where('id', $order['store_id'])->inc('balance', $amount)->update();
}
// }
if($order['group_coupon_id'] != 0&&$order_type == 1){
$group = UserGroup::where("id",$order['group_coupon_id'])->find();
$store_group = TeaStoreGroup::where("id",$group['group_id'])->find();
$change_object = 4;
if($group['type'] == 2){
$store_group['discount_price'] = 0;
$change_object = 5;
$amount = 0;
}
StoreUserAccountLog::create([
'sn'=>createSn("store_user_account_log","sn"),
'change_object'=>$change_object,
'change_type'=>1,
'user_id'=>$user_id,
'action'=>1,
'amount' => $store_group['discount_price'],
'before_amount'=>round($tea_store['balance']+$amount,2),
'after_amount' => round($tea_store['balance']+$amount+$store_group['discount_price'],2),
'source_sn' => $order['order_sn'],
'store_id'=>$order['store_id'],
'room_id'=>$order['room_id'],
'remark'=>"团购套餐",
'create_time' => time()
]);
TeaStore::where('id', $order['store_id'])->inc('total_amount', $store_group['discount_price'])->update();
TeaStore::where('id', $order['store_id'])->inc('balance', $store_group['discount_price'])->update();
}
return true;
}
/**
* 记录支付日志
*/
private static function addPayLog($pay_id, $user_id, $amount, $status, $message = '')
{
return Db::name('pay_log')->insert([
'pay_id' => $pay_id,
'user_id' => $user_id,
'amount' => $amount,
'status' => $status,
'message' => $message,
'create_time' => time()
]);
}
// 退款
public static function refund($data, $user_id){
$refund_msg = RefundRecord::where("id",$data['id'])->find();
$remark = "";
$change_type = 0;
// 判断是否为微信支付
// 0为茶艺师 1为茶室支付 2购买套餐 3购买会员 4充值 5团购退款 6茶室退款
if($refund_msg['order_type'] == 5){
$order = OrderGroup::where("order_sn",$refund_msg['source_sn'])->find();
$remark = "团购套餐退款";
$order_amount = $order['order_amount'];
}elseif($refund_msg['order_type'] == 1){
$order = OrderStore::where("order_sn",$refund_msg['source_sn'])->find();
$remark = "包间预定退款";
$order_amount = $order['store_income_price'];
$change_type = 1;
}
if(isset($order)){
// 微信支付
if($order['pay_way'] == 2){
if($order['order_amount'] <= 0){
//查询是否使用优惠券
if($order['user_coupon_id'] != 0){
$r = UserCoupon::where("id",$order['user_coupon_id'])->update(['status'=>0]);
}
//查询是否使用团购券
if($order['group_coupon_id'] != 0){
$r = UserGroup::where("id",$order['user_coupon_id'])->update(['status'=>0]);
}
if(!isset($r)){
throw new \Exception('退款失败100001');
}
}else{
if($refund_msg['order_type'] == 5){
UserGroup::where('order_id',$order['id'])->update(['status'=>4]);
}
$refundData = [
'transaction_id'=>$order->transaction_id,
'refund_sn'=>$refund_msg->order_sn,
'total_amount'=>$order->order_amount,
'notify_url'=>FileService::getFileUrl('api/pay/notifyMnp'),
];
$payService = (new WeChatPayService(1, $user_id ?? null));
$result = $payService->refund($refundData);
if($result['status'] !=='PROCESSING'){
throw new \Exception('押金退款失败请联系客服');
}
return true;
}
}else{
// 余额退款
RefundRecord::where("id",$data['id'])->update(['refund_way'=>3,'refund_status'=>1]);
// 更新总表状态
OrderAll::where("source_sn",$refund_msg['order_sn'])->where("type",$refund_msg['order_type'])->update([
"pay_way"=>$order['pay_way'],
"order_status"=>5,
"pay_status"=>1,
"pay_time"=>time(),
"update_time"=>time()
]);
$user = User::where("id",$user_id)->find();
$money = 0;
$user_money = 0;
if($order['pay_way'] == 1){
// 平台余额
$money = $user['user_money'];
$user_money = round($user['user_money']+$refund_msg['refund_amount'],2);
User::where("id",$user_id)->update(['user_money'=>$user_money]);
}else{
// 门店余额
$user_store_money = UserStoreMoney::where("user_id",$user_id)->where("store_id",$order['store_id'])->find();
$money = $user_store_money['money'];
$user_money = round($user_store_money['money']+$refund_msg['refund_amount'],2);
UserStoreMoney::where("user_id",$user_id)->where("store_id",$order['store_id'])->update(['money'=>$user_money]);
}
// 更新用户流水
UserAccountLog::create([
"sn"=>createSn("user_account_log","sn"),
"user_id"=>$user_id,
"change_object"=>1,
"change_type"=>5,
"action"=>1,
"amount"=>$refund_msg['refund_amount'],
"before_amount"=>$money,
"after_amount"=>$user_money,
"source_sn"=>$refund_msg['order_sn'],
"store_id"=>$refund_msg['store_id'],
"remark"=>$remark,
"create_time"=>time()
]);
}
// 修改订单状态
if($refund_msg['order_type'] == 5){
$rs = OrderGroup::where("order_sn",$refund_msg['source_sn'])->update(['order_status'=>5]);
UserGroup::where("id",$refund_msg['content_id'])->update(['status'=>3]);
}elseif($refund_msg['order_type'] == 1){
$rs = OrderStore::where("order_sn",$refund_msg['source_sn'])->update(['order_status'=>5]);
}
if(isset($rs)){
if(!$rs){
throw new \Exception('退款失败100002');
}
}else{
throw new \Exception('退款失败100003');
}
// if($refund_msg['order_type'] == 5){
// // 扣除店家余额
// $tes_store = TeaStore::where('id', $order['store_id'])->find();
// $total_amount = round($tes_store['total_amount'] - $order_amount,2);
// $balance = round($tes_store['balance'] - $order_amount,2);
// TeaStore::where('id', $order['store_id'])->update(['total_amount'=>$total_amount,'balance'=>$balance]);
// // 添加店家流水
// StoreUserAccountLog::create([
// 'order_sn'=>createSn("store_user_account_log","order_sn"),
// 'change_object'=>1,
// 'change_type'=>$change_type,
// 'action'=>2,
// 'amount' => $order_amount,
// 'before_amount'=>$tes_store['balance'],
// 'after_amount' => $balance,
// 'source_sn' => $order['order_sn'],
// 'store_id'=>$order['store_id'],
// 'room_id'=>$order['room_id'],
// 'remark'=>$remark,
// 'create_time' => time()
// ]);
// }
return true;
}else{
throw new \Exception('暂无订单信息');
}
}
/**
* 支付成功后置操作
*/
private static function afterPaySuccess($order_id, $user_id)
{
// 可以在这里处理:
// 1. 发送通知
// 2. 更新库存
// 3. 记录日志
// 4. 触发其他业务逻辑
// 示例:发送支付成功通知
// NoticeService::sendPaySuccessNotice($user_id, $order_id);
}
}