Files
code-bang/backend/application/common/service/OrderService.php
T
2026-10-27 18:10:51 +08:00

773 lines
33 KiB
PHP
Raw 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\common\service;
use think\Cache;
use think\Db;
use think\Log;
use EasyWeChat\Pay\Message as PayMessage;
use app\common\model\Orders;
use app\common\traits\ServiceTrait;
use think\Exception;
class OrderService
{
use ServiceTrait;
/** @var Orders */
public static $Model = Orders::class;
const LOCK_ORDER_PREFIX = 'lock_order_cache:'; //重复创建订单锁
const DEFAULT_SAAS_ID = '1000'; //默认商家ID(fa_orders.saas_id 为 NOT NULL 且无默认值,商品无归属时兜底)
//订单状态
const ORDER_STATUS_NO = 0; //关闭
const ORDER_STATUS_WAIT_PAY = 10; //待付款
const ORDER_STATUS_WAIT_SHIP = 20; //已支付(待发货)
const ORDER_STATUS_SHIPPED = 30; //已发货(待收货)
const ORDER_STATUS_FAILED = 31; //交易失败
const ORDER_STATUS_TIMEOUT = 33; //订单超时
const ORDER_STATUS_FINISHED = 40; //已完成
const ORDER_STATUS_CANCEL = 50; //已取消
const ORDER_STATUS_REFUNDED = 60; //已退款
const ORDER_STATUS_MAP = [
self::ORDER_STATUS_NO => '订单关闭',
self::ORDER_STATUS_WAIT_PAY => '待支付',
self::ORDER_STATUS_WAIT_SHIP => '待发货',
self::ORDER_STATUS_SHIPPED => '已发货',
self::ORDER_STATUS_FAILED => '交易失败',
self::ORDER_STATUS_TIMEOUT => '订单超时',
self::ORDER_STATUS_CANCEL => '用户取消订单',
self::ORDER_STATUS_FINISHED => '交易完成',
self::ORDER_STATUS_REFUNDED => '已退款',
];
// 订单操作按钮
const BUTTON_PAY = 1; // 付款
const BUTTON_CANCEL = 2; // 取消订单
const BUTTON_CONFIRM = 3; // 确认收货
const BUTTON_APPLY_REFUND = 4; // 申请售后
const BUTTON_VIEW_REFUND = 5; // 查看退款
const BUTTON_COMMENT = 6; // 评价
const BUTTON_DELETE = 7; // 删除订单
const BUTTON_DELIVERY = 8; // 查看物流
const BUTTON_REBUY = 9; // 再次购买
const BUTTON_INVITE_GROUPON = 11; //邀请好友拼团
const BUTTON_MAP = [
self::BUTTON_PAY => '付款', // 付款
self::BUTTON_CANCEL => '取消订单', // 取消订单
self::BUTTON_CONFIRM => '确认收货', // 确认收货
self::BUTTON_APPLY_REFUND => '申请售后', // 申请售后
self::BUTTON_VIEW_REFUND => '查看退款', // 查看退款
self::BUTTON_COMMENT => '评价', // 评价
self::BUTTON_DELETE => '删除订单', // 删除订单
self::BUTTON_DELIVERY => '查看物流', // 查看物流
self::BUTTON_REBUY => '再次购买', // 再次购买
self::BUTTON_INVITE_GROUPON => '邀请好友拼团', //邀请好友拼团
];
const ORDER_TYPE_SOFTWARE = 0;//软件产品;
const ORDER_TYPE_FIRST_PAYMENT = 1;//首付款款订单;
const ORDER_TYPE_FINAL_PAYMENT = 2; //尾款订单;
const ORDER_TYPE_MAP = [
self::ORDER_TYPE_SOFTWARE => '软件产品',
self::ORDER_TYPE_FIRST_PAYMENT => '需求首付款',
self::ORDER_TYPE_FINAL_PAYMENT => '需求尾款',
];
/**
* 生成订单
* @param $requestData
* @return array
* @throws \Exception
*/
public static function createOrder($requestData)
{
try {
$user = $requestData['userInfo'] ?? [];
$userId = $user['id'] ?? 0;
$openid = $user['openid'] ?? '';
Log::info('创建订单数据-request:' . json_encode($requestData, JSON_UNESCAPED_UNICODE));
if (empty($requestData['goodsRequestList'])) {
throw new \Exception('订单数据错误');
}
//如果30秒内有重复数据,直接返回缓存订单,不再创建
$lockOrderKey = self::getLockOrderKey($userId, $requestData);
if ($lockOrderRes = Cache::get($lockOrderKey)) {
return json_decode($lockOrderRes, true);
}
$goodsRequestList = $requestData['goodsRequestList'];
$count = count($goodsRequestList);
if ($count == 0) {
Log::error('订单创建失败:商品数量不能为0');
throw new \Exception('订单创建失败:商品数量不能为0');
}
$total_amount = 0;
$total_quantity = 0;
$goodsDataList = [];
foreach ($goodsRequestList as $item) {
$quantity = max(1, $item['quantity']);
$total_quantity += $quantity;
$total_amount += $quantity * $item['price'];
$goodsDataList[] = [
'spu_id' => $item['spuId'],
'sku_id' => $item['sku_id'] ?? '',
'goods_name' => $item['goodsName'],
'goods_picture_url' => $item['primaryImage'],
'origin_price' => $item['price'],
'actual_price' => $item['price'],
'buy_quantity' => $quantity,
'item_total_amount' => $item['price'] * $quantity,
'item_discount_amount' => 0,
'item_payment_amount' => $item['price'] * $quantity,
'goods_payment_price' => $item['price'],
];
}
// saas_id 取商品归属商家,取不到时用默认值(fa_orders.saas_id 不允许为空且无默认值)
$goodsInfo = GoodsService::getOne(['spu_id' => $goodsRequestList[0]['spuId'] ?? '']);
$saasId = ($goodsInfo && !empty($goodsInfo->saas_id)) ? $goodsInfo->saas_id : self::DEFAULT_SAAS_ID;
$storeInfo = $requestData['storeInfoList'][0] ?? [];
$orderData = [
'user_id' => $userId,
'saas_id' => $saasId,
'store_id' => $storeInfo['storeId'] ?? ($goodsRequestList[0]['storeId'] ?? 1),
'store_name' => $storeInfo['storeName'] ?? '',
'parent_order_no' => '', // 单订单无父子关系,稍后回填为自身订单号
'order_no' => generate_order_sn(),
'order_status' => OrderService::ORDER_STATUS_WAIT_PAY,
'order_type' => 0,
'total_amount' => $total_amount,
'payment_amount' => $total_amount,
'goods_amount' => $total_amount,
'discount_amount' => 0,
'remark' => $storeInfo['remark'] ?? '',
'promoter_id' => PromotionService::getPromoterId(intval($userId)),
];
$orderData['parent_order_no'] = $orderData['order_no'];
VirtualPayService::rememberPayPlatform($orderData['order_no'], $requestData['payPlatform'] ?? '');
$existed = OrderService::getOne(['order_no' => $orderData['order_no']]);
if (!$existed) {
//创建订单及订单商品
$orderRes = self::$Model::create($orderData);
Log::info('创建订单数据:' . json_encode($orderData, JSON_UNESCAPED_UNICODE));
if (!$orderRes) {
Log::error('创建订单创建失败:' . json_encode($orderData, JSON_UNESCAPED_UNICODE));
throw new \Exception('订单创建失败');
}
$goodsRes = $orderRes->orderGoods()->saveAll($goodsDataList);
if (!$goodsRes) {
Log::error('创建订单产品失败:' . json_encode($orderData, JSON_UNESCAPED_UNICODE));
throw new \Exception('订单创建数据失败');
}
}
$orderData += [
'channel' => 'wechat',
'tradeNo' => $orderData['order_no'],
'interactId' => 0,
'transactionId' => 0,
'payInfo' => self::pay($orderData['order_no'], $total_amount, $openid),
];
if (!empty($orderData['payInfo']['paid'])) {
$orderData['order_status'] = self::ORDER_STATUS_WAIT_SHIP;
}
//存入缓存
Cache::set($lockOrderKey, json_encode($orderData), 30);
return $orderData;
} catch (Exception $e) {
throw new \Exception('订单数据保存失败:' . $e->getMessage());
}
}
/**
* 生成需求订单
* @param $requestData
* @throws \Exception
*/
public static function createDemandOrder($requestData)
{
try {
$demandId = $requestData['demandId'] ?? 0;
$formData = $requestData['formData'] ?? [];
$totalCost = $formData['totalCost'] ?? 0;
Log::info('创建需求订单数据-request:' . json_encode($requestData, JSON_UNESCAPED_UNICODE));
$demand = DemandService::getOne(['id' => $demandId]);
if (!$demand) {
throw new \Exception('该需求不存在');
}
$winBid = DemandBiddingService::getOne(['demand_id' => $demandId, 'bidding_status' => DemandBiddingService::STATUS_BIDDING_WIN]);
$orderInfo = self::where(['parent_order_no' => $demand->parent_order_no])->find();
$ratio = 0.5; //分期比率50%
if (!$orderInfo) {
$promoterId = PromotionService::getPromoterId(intval($demand->user_id));
$installments = 2;//分期数
for ($i = 1; $i <= $installments; $i++) {
$total_amount = $i == 1 ? $totalCost * $ratio : $totalCost * (1 - $ratio);
$goodsDataList = [[
'spu_id' => 0,
'sku_id' => 0,
'goods_name' => '需求签约-' . ($i == 1 ? '首付款' : '尾款') . $demand->parent_order_no,
'goods_picture_url' => 'https://soft-market.oss-cn-shenzhen.aliyuncs.com/images/contract.png',
'origin_price' => $total_amount,
'actual_price' => $total_amount,
'buy_quantity' => 1,
'item_total_amount' => $total_amount,
'item_discount_amount' => 0,
'item_payment_amount' => $total_amount,
'goods_payment_price' => $total_amount,
]];
$orderData = [
'user_id' => $demand->user_id,
'saas_id' => self::DEFAULT_SAAS_ID,
'store_id' => 1,
'store_name' => '',
'parent_order_no' => $demand->parent_order_no,
'order_no' => generate_order_sn(),
'order_status' => OrderService::ORDER_STATUS_WAIT_PAY,
'order_type' => $i,
'total_amount' => $total_amount,
'payment_amount' => $total_amount,
'goods_amount' => $total_amount,
'discount_amount' => 0,
'remark' => '',
'promoter_id' => $promoterId,
];
$existed = OrderService::getOne(['order_no' => $orderData['order_no']]);
if (!$existed) {
//创建订单及订单商品
$orderRes = self::$Model::create($orderData);
Log::info('创建需求订单数据:' . json_encode($orderData, JSON_UNESCAPED_UNICODE));
if (!$orderRes) {
Log::error('创建需求订单创建失败:' . json_encode($orderData, JSON_UNESCAPED_UNICODE));
throw new \Exception('需求订单创建失败');
}
$goodsRes = $orderRes->orderGoods()->saveAll($goodsDataList);
if (!$goodsRes) {
Log::error('创建需求订单产品失败:' . json_encode($orderData, JSON_UNESCAPED_UNICODE));
throw new \Exception('需求订单创建数据失败');
}
}
}
}
//查找签约记录,没有则创建
$contractInfo = ContractService::getOne(['demand_id' => $demand, 'bidding_id' => $winBid->id ?? 0]);
if (!$contractInfo) {
//创建合同数据
$firstContract = ContractService::getFirstContract($demandId);
$depositAmount = $firstContract ? $firstContract->deposit_amount : $formData['totalCost'] * $ratio;
ContractService::createData($demandId, $winBid->id ?? 0, $depositAmount, $formData);
}
return $contractInfo;
} catch (Exception $e) {
throw new \Exception('需求订单数据保存失败:' . $e->getMessage());
}
}
public static function getDemandOrder($parentOrderNo, $contractType)
{
$res = self::getOne(['parent_order_no' => $parentOrderNo, 'order_type' => $contractType], ['orderGoods', 'orderPayment']);
return $res;
}
public static function orderPay($requestData)
{
try {
$user = $requestData['userInfo'] ?? [];
$userId = $user['id'] ?? 0;
$openid = $user['openid'] ?? '';
$orderNo = $requestData['orderNo'] ?? '';
if (!$orderNo) {
throw new \Exception('订单号不存在');
}
$fields = 'user_id,store_id,order_no,order_status,order_type,total_amount,payment_amount,goods_amount,discount_amount,remark';
$orderInfo = OrderService::where(['order_no' => $orderNo, 'user_id' => $userId])->field($fields)->find();
if (!$orderInfo) {
throw new \Exception('该订单不存在');
}
$orderData = $orderInfo->toArray();
VirtualPayService::rememberPayPlatform($orderNo, $requestData['payPlatform'] ?? '');
Log::info('微信下单[发起支付] ' . json_encode([
'order_no' => $orderNo,
'user_id' => $userId,
'order_status' => $orderData['order_status'] ?? null,
'status_text' => self::ORDER_STATUS_MAP[$orderData['order_status'] ?? -1] ?? '未知',
'payment_amount' => $orderData['payment_amount'] ?? 0,
'total_amount' => $orderData['total_amount'] ?? 0,
], JSON_UNESCAPED_UNICODE));
$orderData += [
'channel' => 'wechat',
'tradeNo' => $orderData['order_no'],
'interactId' => 1,
'transactionId' => 0,
'payInfo' => self::pay($orderInfo->order_no, $orderInfo->payment_amount, $openid),
];
if (!empty($orderData['payInfo']['paid'])) {
$orderData['order_status'] = self::ORDER_STATUS_WAIT_SHIP;
}
Log::info('虚拟支付下单[下单成功] ' . json_encode([
'order_no' => $orderNo,
'paid' => $orderData['payInfo']['paid'] ?? 0,
'mode' => $orderData['payInfo']['mode'] ?? '',
], JSON_UNESCAPED_UNICODE));
return $orderData;
} catch (Exception $e) {
throw new \Exception('订单支付异常:' . $e->getMessage());
}
}
/**
* 订单操作
* @param $request
* @return mixed
* @throws \Exception
*/
public static function orderOperate($requestData, $userId)
{
$goodsInfo = $requestData['goodsInfo'] ?? [];
$type = $requestData['type'] ?? '';
switch ($type) {
case self::BUTTON_CONFIRM:
$res = self::confirmOrder($goodsInfo['id'] ?? 0, $userId);
break;
case self::BUTTON_CANCEL:
$res = self::cancelOrder($goodsInfo['id'] ?? 0, $userId);
break;
default:
throw new \Exception('非法操作');
}
return $res;
}
/**
* 取消订单
* @param $order_id
* @param $userId
* @return mixed
* @throws \Exception
*/
public static function cancelOrder($orderId, $userId = 0)
{
try {
$where = ['id' => $orderId, 'user_id' => $userId];
$order = self::getOne($where);
if (!$order) {
throw new \Exception('该订单不存在');
}
Db::startTrans();
if (!in_array($order->order_status, [OrderService::ORDER_STATUS_WAIT_PAY, OrderService::ORDER_STATUS_WAIT_SHIP])) {
throw new \Exception('该订单为' . OrderService::ORDER_STATUS_MAP[$order->order_status] . ',不能取消');
}
//修改订单状态
$upRes = self::where($where)->update(['order_status' => OrderService::ORDER_STATUS_CANCEL]);
if (!$upRes) {
throw new \Exception('更新订单状态失败');
}
//退款原路返回
// OrderRefund::dispatch(['order_sn' => $order->order_sn, 'actual_amount' => $order->actual_amount]);
//给用户发送出票失败结果通知
// SendMsg::dispatch(['order_id' => $order->id, 'user_id' => $order->user_id, 'template_id' => SubscribeMessageService::MSG_TEMP_ORDER_FAILED, 'desc' => SubscribeMessageService::ORDER_MSG_MAP['failed'], 'desc2' => SubscribeMessageService::ORDER_MSG_MAP['refund']]);
Db::commit();
$info = OrderService::getOne(['id' => $orderId]);
return $info;
} catch (\Exception $e) {
Db::rollback();
throw $e;
}
}
/**
* 确认收货
* @param $orderId
* @param $userId
* @return mixed
* @throws \Exception
*/
public static function confirmOrder($orderId, $userId = 0)
{
try {
$where = ['id' => $orderId, 'user_id' => $userId];
$order = self::getOne($where);
if (!$order) {
throw new \Exception('该订单不存在');
}
Db::startTrans();
if (!in_array($order->order_status, [OrderService::ORDER_STATUS_SHIPPED])) {
throw new \Exception('该订单为' . OrderService::ORDER_STATUS_MAP[$order->order_status] . ',不能确认收货');
}
//修改订单状态
$upRes = self::where($where)->update(['order_status' => OrderService::ORDER_STATUS_FINISHED]);
if (!$upRes) {
throw new \Exception('更新订单状态失败');
}
//需求订单(首付款/尾款):同步需求状态与关联订单
if (in_array($order->order_type, [self::ORDER_TYPE_FIRST_PAYMENT, self::ORDER_TYPE_FINAL_PAYMENT])) {
$demand = DemandService::getOne(['parent_order_no' => $order->parent_order_no]);
if ($demand && $demand->status == DemandService::STATUS_CONFIRM_RECEIPT) {
$demand->status = DemandService::STATUS_FINISHED;
$demand->settle_status = CommonService::ONGOING; //结算中
$saveRes = $demand->save();
if (!$saveRes) {
throw new \Exception('更新需求状态失败');
}
//同一需求下的关联订单全部改为已完成
$upRes = self::where(['parent_order_no' => $order->parent_order_no])->update(['order_status' => self::ORDER_STATUS_FINISHED]);
if (!$upRes) {
throw new \Exception('更新关联订单状态失败');
}
}
}
//交易完成:结算推广佣金
PromotionService::settleOrders($order->parent_order_no ? ['parent_order_no' => $order->parent_order_no] : ['id' => $order->id]);
Db::commit();
$info = OrderService::getOne(['id' => $orderId]);
return $info;
} catch (\Exception $e) {
Db::rollback();
throw $e;
}
}
/**
* 微信支付回调(EasyWeChat 6.x / 支付 v3: 自动验签+解密)
* @return \Psr\Http\Message\ResponseInterface
* @throws \Exception
*/
public static function payNotify()
{
$service = new EasyWeChatService();
return $service->handlePayNotify(function (PayMessage $message, $traceId = '') {
$prefix = '微信支付回调[业务] trace=' . $traceId . ' ';
$order_no = $message->out_trade_no ?? '';
$total = $message->amount['total'] ?? 0;
Log::info($prefix . '支付成功通知: ' . json_encode([
'order_no' => $order_no,
'transaction_id' => $message->transaction_id ?? '',
'trade_state' => $message->trade_state ?? '',
'trade_type' => $message->trade_type ?? '',
'amount_fen' => $total,
'amount_yuan' => sprintf('%.2f', $total / 100),
'success_time' => $message->success_time ?? '',
], JSON_UNESCAPED_UNICODE));
$orderInfo = OrderService::getOne(['order_no' => $order_no]);
if (!$orderInfo) {
Log::error($prefix . '订单不存在: ' . json_encode(['order_no' => $order_no], JSON_UNESCAPED_UNICODE));
throw new \Exception('获取订单数据失败');
}
Log::info($prefix . '订单当前状态: ' . json_encode([
'order_id' => $orderInfo->id,
'order_no' => $order_no,
'order_status' => $orderInfo->order_status,
'status_text' => self::ORDER_STATUS_MAP[$orderInfo->order_status] ?? '未知',
'order_type' => $orderInfo->order_type,
'parent_no' => $orderInfo->parent_order_no ?? '',
'payment_amount'=> $orderInfo->payment_amount,
], JSON_UNESCAPED_UNICODE));
if (($message->trade_state ?? '') != 'SUCCESS') {
Log::error($prefix . '支付状态异常: trade_state=' . ($message->trade_state ?? ''));
throw new \Exception('支付失败:' . ($message->trade_state ?? ''));
}
self::finishPaid(
$order_no,
(int)$total,
(string)($message->transaction_id ?? ''),
(string)($message->trade_type ?? 'JSAPI'),
strtotime((string)($message->success_time ?? '')) ?: time(),
$traceId
);
return true;
});
}
/**
* 获取缓存
* @param $userId
* @param $data array
* @return mixed
*/
public static function getLockOrderKey($userId, $data)
{
$key = self::LOCK_ORDER_PREFIX . md5($userId . json_encode($data));
return $key;
}
/**
* 支付成功入账。虚拟支付确认和微信支付回调共用,重复通知直接返回
* @param string $orderNo
* @param int $amountFen 实付金额,单位分
* @param string $transactionId
* @param string $payWay
* @param int $paidTime
* @param string $traceId
* @param string $payPlatform android|ios,空则用下单时记下的终端
* @return bool
* @throws \Exception
*/
public static function finishPaid($orderNo, $amountFen, $transactionId, $payWay, $paidTime, $traceId = '', $payPlatform = '')
{
$payPlatform = VirtualPayService::normalizePayPlatform($payPlatform);
if ($payPlatform === '') {
$payPlatform = VirtualPayService::payPlatformOf($orderNo);
}
if ($payPlatform === '') {
$payPlatform = 'android';
}
$prefix = '订单支付入账 trace=' . $traceId . ' ';
try {
Db::transaction(function () use ($orderNo, $amountFen, $transactionId, $payWay, $paidTime, $prefix, $payPlatform) {
$orderInfo = self::where('order_no', $orderNo)->lock(true)->find();
if (!$orderInfo) {
Log::error($prefix . '订单不存在: ' . $orderNo);
throw new \Exception('获取订单数据失败');
}
if ((int)$orderInfo->order_status !== self::ORDER_STATUS_WAIT_PAY) {
Log::info($prefix . '订单已处理过,跳过状态更新: ' . json_encode([
'order_no' => $orderNo,
'order_status' => $orderInfo->order_status,
], JSON_UNESCAPED_UNICODE));
return;
}
$checkMoney = sprintf('%.1f', $amountFen / 100) == sprintf('%.1f', $orderInfo->payment_amount);
if (!$checkMoney) {
Log::error($prefix . '金额校验失败: ' . json_encode([
'notify_amount' => sprintf('%.2f', $amountFen / 100),
'order_amount' => sprintf('%.2f', $orderInfo->payment_amount),
], JSON_UNESCAPED_UNICODE));
throw new \Exception('金额错误:' . sprintf('%.2f', $amountFen / 100) . '----' . sprintf('%.2f', $orderInfo->payment_amount));
}
$paymentData = [
'order_no' => $orderNo,
'pay_status' => 'SUCCESS',
'amount' => $amountFen / 100,
'currency' => 'CNY',
'pay_type' => '1',
'pay_way' => $payWay ?: 'XPAY',
'pay_platform' => $payPlatform,
'trace_no' => $transactionId,
'pay_time' => time(),
'pay_success_time' => $paidTime > 0 ? $paidTime : time(),
];
self::where('order_no', $orderNo)->update(['order_status' => self::ORDER_STATUS_WAIT_SHIP]);
OrderPaymentService::create($paymentData);
if ($orderInfo->order_type == self::ORDER_TYPE_FIRST_PAYMENT) {
DemandService::customerContractFinishedDeal($orderInfo->parent_order_no);
} elseif ($orderInfo->order_type == self::ORDER_TYPE_FINAL_PAYMENT) {
DemandService::customerWorkAcceptFinishedDeal($orderInfo->parent_order_no);
}
Log::info($prefix . '入账成功 ' . json_encode($paymentData, JSON_UNESCAPED_UNICODE));
});
} catch (\Exception $e) {
Log::error($prefix . '入账失败: ' . $e->getMessage());
throw $e;
}
return true;
}
/**
* 虚拟支付下单。上一笔现金单已经支付成功时直接入账,不再拉起收银台
* @param string $order_sn
* @param float|string $total_fee
* @param string $openid
* @param string $body
* @return array
* @throws \Exception
*/
public static function pay($order_sn, $total_fee, $openid, string $body = '软件产品服务')
{
if (!($body && $order_sn && $total_fee && $openid)) {
Log::error('虚拟支付下单[参数错误] ' . json_encode([
'body' => $body,
'order_sn' => $order_sn,
'total_fee' => $total_fee,
'openid' => $openid,
], JSON_UNESCAPED_UNICODE));
throw new \Exception('支付参数错误2');
}
$current = self::getOne(['order_no' => $order_sn]);
if ($current && !in_array((int)$current->order_status, [
self::ORDER_STATUS_WAIT_PAY,
self::ORDER_STATUS_WAIT_SHIP,
self::ORDER_STATUS_SHIPPED,
self::ORDER_STATUS_FINISHED,
], true)) {
throw new \Exception('订单状态不可支付');
}
if (VirtualPayService::settleIfPaid($order_sn, $openid)) {
return ['paid' => 1];
}
return VirtualPayService::createClientPay($order_sn, $total_fee, $openid);
}
/**
* 客户端支付成功后确认:查现金单、扣代币、更新订单
* @param string $orderNo
* @param int $userId
* @return array
* @throws \Exception
*/
public static function confirmVirtualPay($orderNo, $userId, $payPlatform = '')
{
VirtualPayService::rememberPayPlatform($orderNo, $payPlatform);
$order = self::getOne(['order_no' => $orderNo, 'user_id' => $userId]);
if (!$order) {
throw new \Exception('订单不存在');
}
if ((int)$order->order_status !== self::ORDER_STATUS_WAIT_PAY) {
return ['order_status' => (int)$order->order_status];
}
$openid = \app\common\model\User::where('id', $userId)->value('openid');
if (!$openid) {
throw new \Exception('用户未绑定微信');
}
if (!VirtualPayService::settleIfPaid($orderNo, $openid)) {
throw new \Exception('支付结果确认中,请稍后在订单里再次点击支付,不会重复扣款');
}
$fresh = self::getOne(['order_no' => $orderNo]);
return ['order_status' => (int)($fresh->order_status ?? self::ORDER_STATUS_WAIT_SHIP)];
}
/**
* 获取订单操作按钮
* @param $orderStatus
* @return array
*/
public static function getOrderButtons($orderStatus): array
{
$buttons = [];
if ($orderStatus == self::ORDER_STATUS_WAIT_PAY) {
$buttons[] = ['name' => self::BUTTON_MAP[OrderService::BUTTON_CANCEL], 'primary' => false, 'type' => OrderService::BUTTON_CANCEL];
$buttons[] = ['name' => self::BUTTON_MAP[OrderService::BUTTON_PAY], 'primary' => true, 'type' => OrderService::BUTTON_PAY];
}
if ($orderStatus == self::ORDER_STATUS_SHIPPED) {
$buttons[] = ['name' => self::BUTTON_MAP[OrderService::BUTTON_CONFIRM], 'primary' => true, 'type' => OrderService::BUTTON_CONFIRM];
}
return $buttons;
}
/**
* 获取订单统计
* @param $userId
* @return array[]
*/
public static function getOrderCount($userId): array
{
$orderCountList = [
['orderNum' => 0, 'tabType' => OrderService::ORDER_STATUS_WAIT_PAY],
['orderNum' => 0, 'tabType' => OrderService::ORDER_STATUS_WAIT_SHIP],
['orderNum' => 0, 'tabType' => OrderService::ORDER_STATUS_SHIPPED],
['orderNum' => 0, 'tabType' => OrderService::ORDER_STATUS_FINISHED],
['orderNum' => 0, 'tabType' => OrderService::ORDER_STATUS_REFUNDED],
];
$countList = self::where(['user_id' => $userId, 'order_type' => self::ORDER_TYPE_SOFTWARE])->field('order_status, COUNT(*) as total')
->group('order_status')
->select();
foreach ($orderCountList as &$value) {
if ($value['tabType'] == OrderService::ORDER_STATUS_FINISHED) {
continue;
}
foreach ($countList as $item) {
if ($item->order_status == $value['tabType']) {
$value['orderNum'] = $item->total;
}
}
}
return $orderCountList;
}
/**
* 订单发货(只生成发货单并更新状态,发货通知在后台「订单发货管理」编辑并确认发货时发送)
* @param $id
* @return void
* @throws \Exception
*/
public static function orderShip($id)
{
Db::transaction(function () use ($id) {
//加锁读取,防止并发重复发货、重复分配激活码
$order = OrderService::where(['id' => $id])->lock(true)->find();
if (!$order) {
exception('订单不存在');
}
if ($order->order_status != OrderService::ORDER_STATUS_WAIT_SHIP) {
exception('订单状态异常,不能发货');
}
//查询激活码
$code = SoftCodeService::getAvailableCode();
//生成发货单
OrderShipService::createData($order->order_no, $order->orderGoods[0]->spu_id, $code);
$order->order_status = OrderService::ORDER_STATUS_SHIPPED;
//修改发货状态
$saveRes = $order->save();
if (!$saveRes) {
exception('更新发货状态失败');
}
});
}
/**
* 发送软件订单发货通知(订阅消息 + 站内消息),失败只记日志
* @param string $orderNo 订单号
* @return bool 是否发送成功
* @throws \Exception 订单不存在或不是已发货的软件订单
*/
public static function sendShipNotice($orderNo): bool
{
$order = self::getOne(['order_no' => $orderNo], ['orderGoods']);
if (!$order) {
exception('订单不存在');
}
if ($order->order_type != self::ORDER_TYPE_SOFTWARE) {
exception('仅软件订单支持发送发货通知');
}
if ($order->order_status != self::ORDER_STATUS_SHIPPED) {
exception('订单未发货,不能发送发货通知');
}
try {
$msgData = [
'page' => SubscribeMessageService::PAGE_ORDER_DETAIL,
'param' => ['orderNo' => $order->order_no],
'values' => [
$order->order_no,
mb_substr($order->orderGoods[0]->goods_name, 0, 20),
'已发货',
SubscribeMessageService::MSG_MAP[SubscribeMessageService::MSG_TEMP_ORDER_SHIPPED]['remark'],
]
];
(new EasyWeChatService())->sendMsg($order->user_id, SubscribeMessageService::MSG_TEMP_ORDER_SHIPPED, $msgData);
} catch (\Exception $e) {
Log::error(__CLASS__ . ' 订单发货通知发送失败:' . json_encode([
'order_no' => $orderNo,
'error' => $e->getMessage(),
], JSON_UNESCAPED_UNICODE));
return false;
}
return true;
}
}