feat: implement system-wide activity logging with database persistence, repository patterns, and admin controller access.

This commit is contained in:
pbao9
2026-05-16 20:01:52 +07:00
parent 8a115c5175
commit 551c90d60b
44 changed files with 845 additions and 33 deletions
@@ -0,0 +1,111 @@
<?php
namespace App\Http\Controllers\Api\Admin\ActivityLog;
use App\Http\Controllers\Controller;
use App\Models\ActivityLog;
use App\Repositories\ActivityLog\ActivityLogRepositoryInterface;
use App\Support\Cache\CacheKey;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
class ActivityLogController extends Controller
{
private const CACHE_TTL = 60; // seconds
public function __construct(
private readonly ActivityLogRepositoryInterface $activityLogRepository,
) {}
public function index(Request $request): JsonResponse
{
$perPage = min((int) $request->get('per_page', 20), 200);
$filters = $request->only([
'log_name',
'event',
'causer_type',
'causer_id',
'causer_name',
'subject_type',
'subject_id',
'ip_address',
'date_from',
'date_to',
'search',
'page',
]);
$cacheKey = CacheKey::build('activity_logs', 'list', array_merge(
$filters,
['per_page' => $perPage, 'page' => (int) $request->get('page', 1)]
));
$data = Cache::remember($cacheKey, self::CACHE_TTL, function () use ($filters, $perPage) {
$paginator = $this->activityLogRepository->filter($filters, $perPage);
return [
'items' => $paginator->items(),
'total' => $paginator->total(),
'per_page' => $paginator->perPage(),
'current_page' => $paginator->currentPage(),
'last_page' => $paginator->lastPage(),
];
});
return response()->json(['error' => false, 'data' => $data]);
}
public function show(int $id): JsonResponse
{
$cacheKey = CacheKey::build('activity_logs', 'detail', ['id' => $id]);
$log = Cache::remember($cacheKey, self::CACHE_TTL * 5, function () use ($id) {
return $this->activityLogRepository->find($id);
});
if (!$log) {
return response()->json(['error' => true, 'message' => 'Không tìm thấy log'], 404);
}
return response()->json(['error' => false, 'data' => $log]);
}
public function modules(): JsonResponse
{
$cacheKey = CacheKey::build('activity_logs', 'modules');
$modules = Cache::remember($cacheKey, self::CACHE_TTL * 10, function () {
return ActivityLog::query()
->select('log_name')
->distinct()
->orderBy('log_name')
->pluck('log_name');
});
return response()->json(['error' => false, 'data' => $modules]);
}
public function stats(): JsonResponse
{
$cacheKey = CacheKey::build('activity_logs', 'stats');
$stats = Cache::remember($cacheKey, self::CACHE_TTL * 2, function () {
return [
'total' => ActivityLog::count(),
'today' => ActivityLog::whereDate('created_at', today())->count(),
'by_event' => ActivityLog::selectRaw('event, COUNT(*) as count')
->groupBy('event')
->orderByDesc('count')
->limit(10)
->pluck('count', 'event'),
'by_causer' => ActivityLog::selectRaw('causer_type, COUNT(*) as count')
->groupBy('causer_type')
->pluck('count', 'causer_type'),
];
});
return response()->json(['error' => false, 'data' => $stats]);
}
}
@@ -4,6 +4,7 @@ namespace App\Http\Controllers\Api\Admin\Auth;
use App\Http\Controllers\Controller;
use App\Http\Resources\Api\Admin\AdminUserResource;
use App\Services\ActivityLogger;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
@@ -12,6 +13,8 @@ use Tymon\JWTAuth\Exceptions\JWTException;
class AuthController extends Controller
{
public function __construct(private readonly ActivityLogger $activityLogger) {}
public function login(Request $request): JsonResponse
{
$request->validate([
@@ -22,6 +25,11 @@ class AuthController extends Controller
$token = Auth::guard('admin')->attempt($request->only('username', 'password'));
if (!$token) {
$this->activityLogger->log(
event: 'login_failed',
logName: 'auth',
description: '[admin] Đăng nhập thất bại với username: ' . $request->username,
);
return response()->json([
'error' => true,
'message' => 'Thông tin đăng nhập không chính xác.',
@@ -30,6 +38,8 @@ class AuthController extends Controller
$user = Auth::guard('admin')->user();
$this->activityLogger->logAuth('login', 'admin', $user->id, $user->username ?? $user->email);
return response()->json([
'error' => false,
'data' => [
@@ -76,6 +86,11 @@ class AuthController extends Controller
public function logout(): JsonResponse
{
$user = Auth::guard('admin')->user();
if ($user) {
$this->activityLogger->logAuth('logout', 'admin', $user->id, $user->username ?? $user->email);
}
Auth::guard('admin')->logout();
return response()->json([
@@ -7,6 +7,7 @@ use App\Http\Requests\Api\Client\ClientAuthRequest;
use App\Http\Requests\Api\Client\ClientRegisterRequest;
use App\Http\Requests\Api\Client\ClientUpdateRequest;
use App\Http\Resources\Api\Client\ClientResource;
use App\Services\ActivityLogger;
use App\Services\Api\Client\ClientAuthService;
use Illuminate\Http\Request;
use Tymon\JWTAuth\Facades\JWTAuth;
@@ -21,10 +22,12 @@ use Tymon\JWTAuth\Exceptions\JWTException;
class ClientController extends Controller
{
protected $authService;
protected ActivityLogger $activityLogger;
public function __construct(ClientAuthService $authService)
public function __construct(ClientAuthService $authService, ActivityLogger $activityLogger)
{
$this->authService = $authService;
$this->activityLogger = $activityLogger;
}
/**
@@ -130,10 +133,13 @@ class ClientController extends Controller
{
$result = $this->authService->authenticateClient($request->validated());
$client = $result['client'];
$this->activityLogger->logAuth('login', 'customer', $client->id, $client->email);
return response()->json([
'error' => false,
'data' => [
'client' => new ClientResource($result['client']->loadCount(['vps', 'hosting', 'domain'])),
'client' => new ClientResource($client->loadCount(['vps', 'hosting', 'domain'])),
'token' => $result['token'],
'refresh_token' => $result['refresh_token'],
'expires_in' => config('jwt.ttl', 60) * 60, // seconds
@@ -182,10 +188,13 @@ class ClientController extends Controller
{
$result = $this->authService->registerClient($request->validated());
$client = $result['client'];
$this->activityLogger->logAuth('register', 'customer', $client->id, $client->email);
return response()->json([
'error' => false,
'data' => [
'client' => new ClientResource($result['client']->loadCount(['vps', 'hosting', 'domain'])),
'client' => new ClientResource($client->loadCount(['vps', 'hosting', 'domain'])),
'token' => $result['token'],
'refresh_token' => $result['refresh_token'],
'expires_in' => config('jwt.ttl', 60) * 60,
@@ -222,6 +231,11 @@ class ClientController extends Controller
*/
public function logout(Request $request)
{
$customer = auth('client')->user();
if ($customer) {
$this->activityLogger->logAuth('logout', 'customer', $customer->id, $customer->email);
}
if ($rawToken = $request->input('refresh_token')) {
$this->authService->revokeRefreshToken($rawToken);
}
@@ -297,9 +311,22 @@ class ClientController extends Controller
{
$user = auth('client')->user();
$oldValues = array_intersect_key($user->toArray(), $request->validated());
$user->fill($request->validated());
$dirty = $user->getDirty();
$user->save();
if (!empty($dirty)) {
$this->activityLogger->log(
event: 'profile_update',
logName: 'Customer',
description: "Customer {$user->email} cập nhật thông tin cá nhân: " . implode(', ', array_keys($dirty)),
subject: $user,
oldValues: array_intersect_key($oldValues, $dirty),
newValues: array_diff_key($dirty, array_flip(['password', 'remember_token'])),
);
}
return response()->json([
'error' => false,
'message' => 'Cập nhật thông tin thành công',
@@ -9,6 +9,7 @@ use App\Http\Services\vCenter;
use App\Models\Order;
use App\Models\Service;
use App\Repositories\Api\ServiceClient\ServiceClientRepository;
use App\Services\ActivityLogger;
use App\Services\Api\ServiceClient\ServiceClientService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
@@ -17,13 +18,16 @@ class ServiceController extends Controller
{
protected $serviceClientService;
protected $serviceClientRepository;
protected ActivityLogger $activityLogger;
public function __construct(
ServiceClientService $serviceClientService,
ServiceClientRepository $serviceClientRepository
ServiceClientRepository $serviceClientRepository,
ActivityLogger $activityLogger,
) {
$this->serviceClientService = $serviceClientService;
$this->serviceClientRepository = $serviceClientRepository;
$this->activityLogger = $activityLogger;
}
public function getService(Request $request)
@@ -99,6 +103,14 @@ class ServiceController extends Controller
$ticket = basename(parse_url((string) $consoleTicket['data'], PHP_URL_PATH));
$this->activityLogger->log(
event: 'console_access',
logName: 'VM',
description: "Customer {$customer->email} truy cập console VM: {$vm->name} (service: {$uuid})",
subject: $vm,
newValues: ['service_uuid' => $uuid, 'vm_name' => $vm->name],
);
return response()->json([
'error' => false,
'message' => $ticket,
@@ -154,6 +166,14 @@ class ServiceController extends Controller
return response()->json(['error' => true, 'message' => $consoleTicket['data']]);
}
$this->activityLogger->log(
event: 'console_access',
logName: 'VM',
description: "Customer {$customer->email} truy cập console VM: {$vm->name} (order: {$order->order_num})",
subject: $vm,
newValues: ['order_num' => $order->order_num, 'vm_name' => $vm->name],
);
return response()->json([
'error' => false,
'data' => $consoleTicket['data'],
@@ -19,6 +19,7 @@ use App\Models\Order;
use App\Models\Product;
use App\Models\Service;
use App\Repositories\Api\Order\OrderRepository;
use App\Services\ActivityLogger;
use App\Services\Api\Order\OrderService;
use Carbon\Carbon;
use Illuminate\Http\JsonResponse;
@@ -31,8 +32,9 @@ use Illuminate\Support\Facades\DB;
class OrderController extends Controller
{
public function __construct(
protected OrderService $orderService,
protected OrderRepository $orderRepo,
protected OrderService $orderService,
protected OrderRepository $orderRepo,
protected ActivityLogger $activityLogger,
) {}
// =========================================================================
@@ -147,6 +149,14 @@ class OrderController extends Controller
$order = $result['order']->load(['orderItems.product', 'invoice', 'customer']);
$invoice = $result['invoice'];
$this->activityLogger->log(
event: 'created',
logName: 'Order',
description: "Customer {$customer->email} tạo đơn hàng #{$order->order_num} - Tổng: " . number_format($order->total) . ' VNĐ',
subject: $order,
newValues: ['order_num' => $order->order_num, 'total' => $order->total, 'product_id' => $data['product_id']],
);
return response()->json([
'success' => true,
'message' => 'Tạo đơn hàng thành công.',
@@ -190,6 +200,14 @@ class OrderController extends Controller
$this->orderService->pay($order, $request->payment_method);
$this->activityLogger->log(
event: 'payment',
logName: 'Order',
description: "Customer {$request->user()->email} thanh toán đơn hàng #{$order->order_num} qua {$request->payment_method}",
subject: $order,
newValues: ['payment_method' => $request->payment_method, 'total' => $order->total],
);
return response()->json(['success' => true, 'message' => 'Thanh toán thành công.']);
} catch (\Exception $e) {
return $this->error($e->getMessage());
@@ -222,6 +240,13 @@ class OrderController extends Controller
RetryProvisioningOrchestrator::dispatch($order->id, $request->user()->id);
$this->activityLogger->log(
event: 'retry_provisioning',
logName: 'Order',
description: "Customer {$request->user()->email} yêu cầu khởi tạo lại dịch vụ cho đơn hàng #{$order->order_num}",
subject: $order,
);
return response()->json([
'success' => true,
'message' => 'Đã yêu cầu khởi tạo lại dịch vụ. Hệ thống sẽ kiểm tra và xử lý trong vài phút.',
@@ -470,6 +495,14 @@ class OrderController extends Controller
$service->update(['auto_renew' => (bool) $validated['auto_renew']]);
$this->activityLogger->log(
event: 'updated',
logName: 'Service',
description: "Customer {$request->user()->email} " . ($validated['auto_renew'] ? 'bật' : 'tắt') . " tự động gia hạn dịch vụ #{$service->id}",
subject: $service,
newValues: ['auto_renew' => (bool) $validated['auto_renew']],
);
return response()->json([
'success' => true,
'message' => 'Cập nhật tự động gia hạn thành công.',
@@ -597,6 +630,14 @@ class OrderController extends Controller
->delay(now()->addSeconds(5));
}
$this->activityLogger->log(
event: 'renew',
logName: 'Service',
description: "Customer {$customer->email} gia hạn dịch vụ #{$service->id} ({$service->server_name}) - {$months} tháng - " . number_format($price) . ' VNĐ',
subject: $service,
newValues: ['months' => $months, 'price' => $price, 'invoice_number' => $invoice->invoice_number],
);
return response()->json([
'success' => true,
'message' => 'Gia hạn thành công. Dịch vụ đã được kích hoạt lại.',
@@ -10,6 +10,7 @@ use App\Jobs\VirtualMachine\Snapshot\RevertSnapshot;
use App\Jobs\VirtualMachine\Snapshot\RemoveSnapshot;
use App\Models\ModuleSnapshot;
use App\Models\ModuleVmware;
use App\Services\ActivityLogger;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
@@ -17,6 +18,8 @@ class SnapshotController extends Controller
{
use ResolvesVm;
public function __construct(protected ActivityLogger $activityLogger) {}
public function store(Request $request): JsonResponse
{
$customer = $request->user();
@@ -47,6 +50,14 @@ class SnapshotController extends Controller
CreateSnapshot::dispatch($snapshot->id);
$this->activityLogger->log(
event: 'created',
logName: 'Snapshot',
description: "Customer {$customer->email} tạo snapshot: {$snapshot->name} cho VM #{$vm->id}",
subject: $snapshot,
newValues: ['name' => $snapshot->name, 'vm_id' => $vm->id],
);
return response()->json([
'error' => false,
'message' => 'Đã gửi yêu cầu tạo snapshot vào hàng đợi',
@@ -159,6 +170,13 @@ class SnapshotController extends Controller
RevertSnapshot::dispatch($vm->id, $snapshot->id);
$this->activityLogger->log(
event: 'revert',
logName: 'Snapshot',
description: "Customer {$customer->email} revert snapshot: {$snapshot->name} (ID: {$snapshot->id}) cho VM #{$vm->id}",
subject: $snapshot,
);
return response()->json([
'error' => false,
'message' => 'Đã gửi yêu cầu revert snapshot vào hàng đợi',
@@ -189,6 +207,13 @@ class SnapshotController extends Controller
RemoveSnapshot::dispatch($vm->id, $snapshot->id);
$this->activityLogger->log(
event: 'deleted',
logName: 'Snapshot',
description: "Customer {$customer->email} xóa snapshot: {$snapshot->name} (ID: {$snapshot->id}) của VM #{$vm->id}",
subject: $snapshot,
);
return response()->json([
'error' => false,
'message' => 'Đã gửi yêu cầu xóa snapshot vào hàng đợi',
@@ -14,6 +14,7 @@ use App\Jobs\VirtualMachine\ChangeVmPasswordJob;
use App\Models\ModuleVmware;
use App\Models\Os;
use App\Models\Service;
use App\Services\ActivityLogger;
use App\Services\VmProvisionService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
@@ -24,6 +25,8 @@ class VmController extends Controller
use ResolvesVm {
ResolvesVm::resolveVmById as resolveVmForClient;
}
public function __construct(protected ActivityLogger $activityLogger) {}
// -------------------------------------------------------------------------
// Power ON
// -------------------------------------------------------------------------
@@ -47,6 +50,13 @@ class VmController extends Controller
$result = $action->execute($vm);
$this->activityLogger->log(
event: 'power_on',
logName: 'VM',
description: "Customer {$request->user()->email} bật VM: {$vm->name} (ID: {$vm->vmware_id})",
subject: $vm,
);
return $this->vmResponse($result, 'Đã gửi lệnh bật VM.');
}
@@ -73,6 +83,13 @@ class VmController extends Controller
$result = $action->execute($vm);
$this->activityLogger->log(
event: 'power_off',
logName: 'VM',
description: "Customer {$request->user()->email} tắt VM: {$vm->name} (ID: {$vm->vmware_id})",
subject: $vm,
);
return $this->vmResponse($result, 'Đã gửi lệnh tắt VM.');
}
@@ -189,6 +206,14 @@ class VmController extends Controller
. "ℹ️ Kiểm tra lại VM để xác nhận IP đã thay đổi chưa.");
}
$this->activityLogger->log(
event: 'change_ip',
logName: 'VM',
description: "Customer {$request->user()->email} đổi IP VM: {$vm->name} → {$validated['ip_address']}",
subject: $vm,
newValues: ['ip_address' => $validated['ip_address'], 'gateway' => $gateway, 'os_type' => $osType],
);
return response()->json([
'success' => true,
'message' => 'Đã gửi lệnh đổi IP.',
@@ -234,6 +259,16 @@ class VmController extends Controller
? (bool) $result['success']
: !($result['error'] ?? true);
if ($ok) {
$this->activityLogger->log(
event: 'change_port',
logName: 'VM',
description: "Customer {$request->user()->email} đổi cổng RDP VM: {$vm->name} → port {$validated['new_port']}",
subject: $vm,
newValues: ['new_port' => $validated['new_port']],
);
}
return response()->json([
'success' => $ok,
'message' => $ok ? 'Đổi cổng RDP thành công.' : ($result['message'] ?? 'Đổi cổng thất bại.'),
@@ -269,6 +304,14 @@ class VmController extends Controller
return $result;
}
$this->activityLogger->log(
event: 'console_access',
logName: 'VM',
description: "Customer {$request->user()->email} truy cập console VM: {$vm->name} (ID: {$vm->vmware_id})",
subject: $vm,
newValues: ['product_id' => $productId, 'vm_name' => $vm->name],
);
return response()->json([
'error' => false,
'data' => $result['data'],
@@ -300,6 +343,13 @@ class VmController extends Controller
], 400);
}
$this->activityLogger->log(
event: 'restart',
logName: 'VM',
description: "Customer {$request->user()->email} restart VM: {$vm->name} (ID: {$vm->vmware_id})",
subject: $vm,
);
return response()->json([
'error' => false,
'message' => 'Đã gửi lệnh restart VM',
@@ -345,6 +395,14 @@ class VmController extends Controller
$validated['current_password'],
);
$this->activityLogger->log(
event: 'change_password',
logName: 'VM',
description: "Customer {$request->user()->email} yêu cầu đổi mật khẩu VM: {$vm->name}",
subject: $vm,
newValues: ['os_family' => $osFamily],
);
return response()->json([
'success' => true,
'message' => 'Yêu cầu đổi mật khẩu đã được ghi nhận. Hệ thống sẽ xử lý trong vài phút.',
@@ -6,6 +6,7 @@ use App\Http\Controllers\Controller;
use App\Http\Controllers\Api\Service\Concerns\ResolvesVm;
use App\Http\Services\vCenter;
use App\Models\ModuleVmware;
use App\Services\ActivityLogger;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
@@ -14,6 +15,8 @@ class VmRebuildController extends Controller
{
use ResolvesVm;
public function __construct(protected ActivityLogger $activityLogger) {}
public function options(Request $request): JsonResponse
{
$productId = (int) $request->query('product');
@@ -103,6 +106,14 @@ class VmRebuildController extends Controller
], 400);
}
$this->activityLogger->log(
event: 'rebuild',
logName: 'VM',
description: "Customer {$customer->email} rebuild VM: {$vm->name} với OS ID: {$payload['os_id']}",
subject: $vm,
newValues: ['os_id' => $payload['os_id']],
);
return response()->json([
'error' => false,
'message' => 'Đã gửi yêu cầu rebuild VM',
@@ -207,6 +218,14 @@ class VmRebuildController extends Controller
}
}
$this->activityLogger->log(
event: 'upgrade_addons',
logName: 'VM',
description: "Customer {$customer->email} nâng cấp addons VM: {$vm->name} - áp dụng: " . implode(', ', $applied ?: ['none']),
subject: $vm,
newValues: array_filter(['cpu' => $payload['cpu'] ?? null, 'ram' => $payload['ram'] ?? null, 'disk' => $payload['disk'] ?? null]),
);
return response()->json([
'error' => false,
'message' => 'Đã gửi yêu cầu nâng cấp addons',
@@ -8,6 +8,7 @@ use App\Http\Requests\DepositRequest;
use App\Http\Services\Telegram;
use App\Models\Log;
use App\Models\Transaction;
use App\Services\ActivityLogger;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
@@ -16,6 +17,7 @@ use Illuminate\Support\Str;
class ManualDepositController extends Controller
{
public function __construct(protected ActivityLogger $activityLogger) {}
/**
* GET /v1/transaction/manual-deposit/pending
* Kiểm tra xem user có GD manual đang chờ duyệt (đã submit proof) không.
@@ -111,6 +113,13 @@ class ManualDepositController extends Controller
return response()->json(['error' => true, 'message' => 'Có lỗi xảy ra, vui lòng thử lại'], 500);
}
$this->activityLogger->log(
event: 'deposit_prepare',
logName: 'Transaction',
description: "Customer {$user->email} tạo yêu cầu nạp tiền thủ công: " . number_format($request->amount) . ' VNĐ - Mã: ' . $publicCode,
newValues: ['public_code' => $publicCode, 'amount' => $request->amount, 'type' => 'manual'],
);
return response()->json([
'error' => false,
'data' => [
@@ -136,12 +145,22 @@ class ManualDepositController extends Controller
->whereNull('proof_image')
->firstOrFail();
$amount = $transaction->amount;
$publicCode = $transaction->public_code;
DB::transaction(function () use ($transaction, $user) {
$user->total_pending = max(0, $user->total_pending - $transaction->amount);
$user->save();
$transaction->forceDelete();
});
$this->activityLogger->log(
event: 'deposit_cancel',
logName: 'Transaction',
description: "Customer {$user->email} huỷ yêu cầu nạp tiền thủ công: " . number_format($amount) . ' VNĐ - Mã: ' . $publicCode,
newValues: ['public_code' => $publicCode, 'amount' => $amount],
);
return response()->json(['error' => false, 'message' => 'Đã huỷ yêu cầu']);
}
@@ -188,6 +207,13 @@ class ManualDepositController extends Controller
'customer_id' => $user->id,
]);
$this->activityLogger->log(
event: 'deposit_confirm',
logName: 'Transaction',
description: "Customer {$user->email} nộp chứng từ nạp tiền thủ công: " . number_format($transaction->amount) . ' VNĐ - Mã: ' . $transaction->public_code,
newValues: ['public_code' => $transaction->public_code, 'amount' => $transaction->amount, 'has_proof' => true],
);
return response()->json([
'error' => false,
'message' => 'Yêu cầu nạp tiền đã được ghi nhận, vui lòng chờ admin xác nhận',
@@ -11,6 +11,7 @@ use App\Models\Customer;
use App\Models\Invoice;
use App\Models\Log;
use App\Models\Transaction;
use App\Services\ActivityLogger;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
@@ -20,10 +21,12 @@ use Illuminate\Support\Str;
class TransactionController extends Controller
{
protected VNPayService $vnpayService;
protected ActivityLogger $activityLogger;
public function __construct(VNPayService $vnpayService)
public function __construct(VNPayService $vnpayService, ActivityLogger $activityLogger)
{
$this->vnpayService = $vnpayService;
$this->activityLogger = $activityLogger;
}
public function handle(DepositRequest $request)
@@ -48,6 +51,14 @@ class TransactionController extends Controller
'transaction_uuid' => $uuid,
]);
$this->activityLogger->log(
event: 'deposit_vnpay',
logName: 'Transaction',
description: "Customer {$user->email} tạo yêu cầu nạp tiền VNPay: " . number_format($request->amount) . ' VNĐ - Mã: ' . $publicCode,
subject: $transaction,
newValues: ['public_code' => $publicCode, 'amount' => $request->amount, 'type' => 'vnpay'],
);
return response()->json([
'error' => false,
'message' => 'Tạo yêu cầu nạp tiền thành công',
@@ -151,6 +162,14 @@ class TransactionController extends Controller
'customer_id' => $transaction->customer_id,
]);
$this->activityLogger->log(
event: 'deposit_success',
logName: 'Transaction',
description: "Customer {$customer->email} nạp tiền VNPay thành công: " . number_format($transaction->amount) . ' VNĐ - Mã: ' . $transaction->public_code,
subject: $transaction,
newValues: ['amount' => $transaction->amount, 'new_total' => $customer->total, 'public_code' => $transaction->public_code],
);
DepositSuccessJob::dispatch([
'customer_email' => $customer->email,
'customer_name' => $customer->fullname,