vr-shopxo-plugin/app/plugins/vr_ticket/service/TicketService.php

230 lines
7.3 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<?php
/**
* VR票务插件 - 票务服务
*
* 核心业务:订单支付成功 → 生成电子票
*
* @package vr_ticket\service
*/
namespace app\plugins\vr_ticket\service;
class TicketService
{
/**
* 订单支付成功回调
*
* 从 plugin.json 的 hook 触发:
* plugins_service_order_pay_success_handle_end
*
* @param array $params 钩子参数,含 business_data, user_id, business_ids(order_ids)
* @return bool
*/
public static function onOrderPaid($params = [])
{
$order_id = $params['business_id'] ?? ($params['business_ids'][0] ?? 0);
if (empty($order_id)) {
BaseService::log('onOrderPaid: empty order_id', $params, 'warning');
return false;
}
// 查询订单
$order = \Db::name('Order')->find($order_id);
if (empty($order) || $order['pay_status'] != 1) {
BaseService::log('onOrderPaid: order not paid or not found', ['order_id' => $order_id], 'warning');
return false;
}
// 判断是否为票务商品
if (!BaseService::isTicketGoods($order['goods_id'])) {
BaseService::log('onOrderPaid: not a ticket goods', ['order_id' => $order_id], 'info');
return true; // 不是票务商品,不报错
}
// 查询商品快照(规格信息)
$order_goods = \Db::name('OrderGoods')
->where('order_id', $order_id)
->select();
if (empty($order_goods)) {
BaseService::log('onOrderPaid: no order goods', ['order_id' => $order_id], 'error');
return false;
}
// 逐个生成票(每个规格选项 = 一张票)
$count = 0;
foreach ($order_goods as $og) {
$ticket_id = self::issueTicket($order, $og);
if ($ticket_id > 0) {
$count++;
}
}
BaseService::log('onOrderPaid: success', [
'order_id' => $order_id,
'tickets_issued' => $count,
]);
return $count > 0;
}
/**
* 发放单张票
*
* @param array $order 订单数据
* @param array $order_goods 订单商品数据(包含 spec_base_id
* @return int 票ID
*/
public static function issueTicket($order, $order_goods)
{
$ticket_code = BaseService::generateUuid();
// 构建 QR 数据
$qr_payload = [
'id' => 0, // 写入后再更新
'code' => $ticket_code,
'event' => $order['goods_id'],
'seat' => $order_goods['spec_name'] ?? '', // 规格名=座位信息
];
$qr_data = BaseService::encryptQrData($qr_payload);
// 观演人信息(从订单扩展字段读取,由购票页表单写入)
$extension_data = json_decode($order['extension_data'] ?? '{}', true);
$attendee = $extension_data['attendee'] ?? [];
$now = BaseService::now();
$ticket_id = \Db::name(BaseService::table('tickets'))->insertGetId([
'order_id' => $order['id'],
'order_no' => $order['order_no'],
'goods_id' => $order['goods_id'],
'goods_snapshot' => json_encode([
'goods_name' => $order['goods_name'] ?? '',
'spec_name' => $order_goods['spec_name'] ?? '',
'price' => $order_goods['goods_price'] ?? 0,
], JSON_UNESCAPED_UNICODE),
'user_id' => $order['user_id'],
'ticket_code' => $ticket_code,
'qr_data' => $qr_data,
'seat_info' => $order_goods['spec_name'] ?? '',
'spec_base_id' => $order_goods['spec_base_id'] ?? 0,
'real_name' => $attendee['real_name'] ?? '',
'phone' => $attendee['phone'] ?? '',
'id_card' => $attendee['id_card'] ?? '',
'verify_status' => 0, // 0=未核销
'issued_at' => $now,
'created_at' => $now,
'updated_at' => $now,
]);
// 更新 QR 数据中的 ticket_id
if ($ticket_id > 0) {
$qr_payload['id'] = $ticket_id;
$qr_data_updated = BaseService::encryptQrData($qr_payload);
\Db::name(BaseService::table('tickets'))
->where('id', $ticket_id)
->update(['qr_data' => $qr_data_updated]);
}
return $ticket_id;
}
/**
* 核销票
*
* @param string $ticket_code 票码
* @param int $verifier_id 核销员ID
* @return array [code, msg]
*/
public static function verifyTicket($ticket_code, $verifier_id)
{
$ticket = \Db::name(BaseService::table('tickets'))
->where('ticket_code', $ticket_code)
->find();
if (empty($ticket)) {
return ['code' => -1, 'msg' => '票码不存在'];
}
if ($ticket['verify_status'] == 1) {
return ['code' => -2, 'msg' => '该票已核销'];
}
if ($ticket['verify_status'] == 2) {
return ['code' => -3, 'msg' => '该票已退款'];
}
$now = BaseService::now();
// 更新票状态
\Db::name(BaseService::table('tickets'))
->where('id', $ticket['id'])
->update([
'verify_status' => 1,
'verify_time' => $now,
'verifier_id' => $verifier_id,
'updated_at' => $now,
]);
// 写入核销记录
$verifier = \Db::name(BaseService::table('verifiers'))
->where('id', $verifier_id)
->find();
\Db::name(BaseService::table('verifications'))->insert([
'ticket_id' => $ticket['id'],
'ticket_code' => $ticket_code,
'verifier_id' => $verifier_id,
'verifier_name'=> $verifier['name'] ?? '',
'goods_id' => $ticket['goods_id'],
'created_at' => $now,
]);
BaseService::log('verifyTicket: success', [
'ticket_id' => $ticket['id'],
'verifier_id' => $verifier_id,
]);
return [
'code' => 0,
'msg' => '核销成功',
'data' => [
'seat_info' => $ticket['seat_info'],
'real_name' => $ticket['real_name'],
'goods_name' => json_decode($ticket['goods_snapshot'] ?? '{}', true)['goods_name'] ?? '',
],
];
}
/**
* 获取用户所有票
*/
public static function getUserTickets($user_id, $status = null)
{
$where = ['user_id' => $user_id];
if ($status !== null) {
$where['verify_status'] = $status;
}
return \Db::name(BaseService::table('tickets'))
->where($where)
->order('created_at', 'desc')
->select();
}
/**
* 生成 QR 码图片 URL
*
* @param string $ticket_code
* @return string QR码图片URL
*/
public static function getQrCodeUrl($ticket_code)
{
$content = base64_encode(json_encode([
'type' => 'vr_ticket',
'code' => $ticket_code,
]));
return ROOT_URL . '?s=index/qrcode/index&content=' . urlencode($content) . '&size=8&level=H';
}
}