File: /var/www/api-talleres.bradford/routes/api.php
<?php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use Illuminate\Support\Facades\Log;
use App\Http\Middleware\VerifyCsrfToken;
// ===============================
// 🔹 Auth
// ===============================
use App\Http\Controllers\AuthController;
// ===============================
// 🔹 Core Controllers
// ===============================
use App\Http\Controllers\{
ClubController,
ClubEnrollmentController,
ClubOrderController,
ConfigurationController,
CountryController,
CourseController,
CourseLetterController,
DashboardController,
ExcelUploadController,
ExcelUploadLineController,
GenderController,
MyProfileController,
ParentController,
PeriodController,
PostulationController,
ProfileController,
RegionController,
RelationshipController,
ReportController,
StudentController,
UserController,
WebhookGeneralController
};
// ===============================
// 🔹 Toku Controllers
// ===============================
use App\Http\Controllers\Toku\{
CheckoutSessionController,
PaymentMethodController,
CustomerController,
EventsController,
InvoiceController,
PaymentController,
RedirectionController,
SubscriptionController,
TransactionController,
WebhookController
};
use App\Http\Controllers\Toku\webhook\{
WebhookCustomerController,
WebhookInvoiceController,
WebhookPaymentController,
WebhookPaymentIntentController,
WebhookPaymentMethodController,
WebhookPayoutController,
WebhookSubscriptionController,
WebhookTransactionController
};
// ===============================
// 🔹 Signapis Controllers
// ===============================
use App\Http\Controllers\Signapis\{
SignapisDocumentController,
SignapisLogosController,
SignapisNotificationsController,
SignapisReportsController,
SignapisSigninController,
SignapisTemplatesController,
SignapisTestController,
SignapisWebhookController
};
// ===============================
// 🔹 Firmaki Controllers
// ===============================
use App\Http\Controllers\Firmaki\WebhookController as FirmakiWebhookController;
// ===============================
// 🔹 Rutas protegidas por Sanctum
// ===============================
Route::middleware('auth:sanctum')->get('/user', fn(Request $r) => $r->user());
// ===============================
// 🔹 Autenticación
// ===============================
Route::post('/login', [AuthController::class, 'login']);
Route::post('/activate-account', [AuthController::class, 'activateAccount']);
Route::post('/validate-code-account', [AuthController::class, 'validateCodeActivation']);
Route::post('/activate-password', [AuthController::class, 'activatePasswordWithCode']);
Route::post('/recovery', [AuthController::class, 'sendRecoveryCode']);
Route::post('/validate-code', [AuthController::class, 'validateCode']);
Route::post('/reset-password', [AuthController::class, 'resetPassword']);
Route::post('/sign-in', [AuthController::class, 'loginApi']);
Route::post('/logout', [AuthController::class, 'logout']);
// ===============================================
// 🔹 TODO el resto del API (usuarios + integraciones)
// ===============================================
Route::middleware(['auth.any'])->group(function () {
// =======================================
// 🔹 PERFIL / SESIÓN
// =======================================
Route::get('/me', [AuthController::class, 'validateSession']);
Route::get('/me-2/{id}', [AuthController::class, 'getUser']);
// =======================================
// 🔹 MI PERFIL
// =======================================
Route::get('/my-profile', [MyProfileController::class, 'show']);
Route::put('/my-profile', [MyProfileController::class, 'update']);
Route::put('/my-profile/password', [MyProfileController::class, 'updatePassword']);
Route::middleware(['auth.any'])->group(function () {
// =======================================
// 🔹 DASHBOARD
// =======================================
Route::get('/dashboard', [DashboardController::class, 'dashboard']);
// =======================================
// 🔹 CORE CRUD
// =======================================
Route::get('/profiles-list', fn(ProfileController $c) => $c->list(false));
Route::get('/profiles', [ProfileController::class, 'list']);
Route::post('/profiles/store', [ProfileController::class, 'store']);
Route::post('/profiles/permissions-matrix', [ProfileController::class, 'updatePermissionsMatrix']);
Route::get('/profiles/{id}', [ProfileController::class, 'show']);
Route::put('/profiles/{id}', [ProfileController::class, 'update']);
Route::delete('/profiles/{id}', [ProfileController::class, 'destroy']);
Route::get('/permissions', [ProfileController::class, 'getPermissions']);
Route::get('/courses-list', fn(CourseController $c) => $c->list(false));
Route::get('/courses', [CourseController::class, 'list']);
Route::post('/courses/store', [CourseController::class, 'store']);
Route::get('/courses/{id}', [CourseController::class, 'show']);
Route::put('/courses/{id}', [CourseController::class, 'update']);
Route::delete('/courses/{id}', [CourseController::class, 'destroy']);
Route::get('/course-letters-list', fn(CourseLetterController $c) => $c->list(false));
Route::get('/course-letters', [CourseLetterController::class, 'list']);
Route::post('/course-letters/store', [CourseLetterController::class, 'store']);
Route::get('/course-letters/{id}', [CourseLetterController::class, 'show']);
Route::put('/course-letters/{id}', [CourseLetterController::class, 'update']);
Route::delete('/course-letters/{id}', [CourseLetterController::class, 'destroy']);
Route::get('/genders-list', fn(GenderController $c) => $c->list(false));
Route::get('/genders', [GenderController::class, 'list']);
Route::post('/genders/store', [GenderController::class, 'store']);
Route::get('/genders/{id}', [GenderController::class, 'show']);
Route::put('/genders/{id}', [GenderController::class, 'update']);
Route::delete('/genders/{id}', [GenderController::class, 'destroy']);
Route::get('/relationships-list', fn(RelationshipController $c) => $c->list(false));
Route::get('/relationships', [RelationshipController::class, 'list']);
Route::post('/relationships/store', [RelationshipController::class, 'store']);
Route::get('/relationships/{id}', [RelationshipController::class, 'show']);
Route::put('/relationships/{id}', [RelationshipController::class, 'update']);
Route::delete('/relationships/{id}', [RelationshipController::class, 'destroy']);
Route::get('/countries-list', fn(CountryController $c) => $c->list(false));
Route::get('/countries', [CountryController::class, 'list']);
Route::post('/countries/store', [CountryController::class, 'store']);
Route::get('/countries/{id}', [CountryController::class, 'show']);
Route::put('/countries/{id}', [CountryController::class, 'update']);
Route::delete('/countries/{id}', [CountryController::class, 'destroy']);
Route::get('/regions-list', fn(RegionController $c) => $c->list(false));
Route::get('/regions', [RegionController::class, 'list']);
Route::post('/regions/store', [RegionController::class, 'store']);
Route::get('/regions/{id}', [RegionController::class, 'show']);
Route::put('/regions/{id}', [RegionController::class, 'update']);
Route::delete('/regions/{id}', [RegionController::class, 'destroy']);
Route::get('/students', [StudentController::class, 'list']);
Route::post('/students/store', [StudentController::class, 'store']);
Route::get('/students/{id}', [StudentController::class, 'show']);
Route::put('/students/{id}', [StudentController::class, 'update']);
Route::delete('/students/{id}', [StudentController::class, 'destroy']);
Route::get('/parents-list', fn(ParentController $c) => $c->list(true));
Route::get('/parents', [ParentController::class, 'list']);
Route::post('/parents/store', [ParentController::class, 'store']);
Route::get('/parents/{id}', [ParentController::class, 'show']);
Route::put('/parents/{id}', [ParentController::class, 'update']);
Route::delete('/parents/{id}', [ParentController::class, 'destroy']);
Route::get('/users', [UserController::class, 'list']);
Route::post('/users/store', [UserController::class, 'store']);
Route::get('/users/{id}', [UserController::class, 'show']);
Route::put('/users/{id}', [UserController::class, 'update']);
Route::delete('/users/{id}', [UserController::class, 'destroy']);
Route::get('/configuration', [ConfigurationController::class, 'showByCode']);
Route::post('/configuration', [ConfigurationController::class, 'storeOrUpdate']);
Route::get('postulations', [PostulationController::class, 'list']);
Route::post('postulations/store', [PostulationController::class, 'store']);
Route::get('postulations/{id}', [PostulationController::class, 'show']);
Route::put('postulations/{id}', [PostulationController::class, 'update']);
Route::delete('postulations/{id}', [PostulationController::class, 'destroy']);
Route::get('periods', [PeriodController::class, 'list']);
Route::post('periods', [PeriodController::class, 'store']);
Route::get('periods/{id}', [PeriodController::class, 'show']);
Route::put('periods/{id}', [PeriodController::class, 'update']);
Route::delete('periods/{id}', [PeriodController::class, 'destroy']);
Route::put('/periods/{id}/activate', [PeriodController::class, 'activate']);
Route::get('/get-period', [PeriodController::class, 'getPeriodActivate']);
// Talleres (Clubs)
Route::get('/clubs', [ClubController::class, 'list']);
Route::post('/clubs/store', [ClubController::class, 'store']);
Route::get('/clubs/{id}', [ClubController::class, 'show']);
Route::put('/clubs/{id}', [ClubController::class, 'update']);
Route::delete('/clubs/{id}', [ClubController::class, 'destroy']);
// Órdenes de Talleres (Carrito - Parent)
Route::get('/club-orders/enrollment-config', [ClubOrderController::class, 'enrollmentConfig']);
Route::get('/club-orders/current', [ClubOrderController::class, 'getCurrentActive']);
Route::post('/club-orders/active', [ClubOrderController::class, 'getOrCreateActive']);
Route::get('/club-orders/history', [ClubOrderController::class, 'history']);
Route::get('/club-orders/by-code/{code}', [ClubOrderController::class, 'showByCode']);
Route::get('/club-orders/{id}', [ClubOrderController::class, 'show'])->where('id', '[0-9]+');
Route::get('/club-orders/{id}/detail', [ClubOrderController::class, 'showDetail'])->where('id', '[0-9]+');
Route::post('/club-orders/{id}/items', [ClubOrderController::class, 'addItem'])->where('id', '[0-9]+');
Route::post('/club-orders/{id}/items/bulk', [ClubOrderController::class, 'addItemsBulk'])->where('id', '[0-9]+');
Route::delete('/club-orders/{orderId}/items/{itemId}', [ClubOrderController::class, 'removeItem'])->where(['orderId' => '[0-9]+', 'itemId' => '[0-9]+']);
Route::post('/club-orders/{id}/pay', [ClubOrderController::class, 'processPayment'])->where('id', '[0-9]+');
Route::post('/club-orders/{id}/checkout', [ClubOrderController::class, 'createTokuCheckout'])->where('id', '[0-9]+');
Route::post('/club-orders/{id}/cancel', [ClubOrderController::class, 'cancel'])->where('id', '[0-9]+');
Route::post('/club-orders/{id}/extend', [ClubOrderController::class, 'extend'])->where('id', '[0-9]+');
// Órdenes de Talleres (Admin)
Route::get('/club-orders/admin/all', [ClubOrderController::class, 'adminIndex']);
Route::get('/club-orders/admin/{id}', [ClubOrderController::class, 'adminShow'])->where('id', '[0-9]+');
// Inscripciones a Talleres (Parent)
Route::get('/club-enrollments', [ClubEnrollmentController::class, 'index']);
Route::get('/club-enrollments/check', [ClubEnrollmentController::class, 'checkEnrollment']);
Route::get('/club-enrollments/count', [ClubEnrollmentController::class, 'countForStudent']);
Route::get('/club-enrollments/student/{studentId}', [ClubEnrollmentController::class, 'forStudent'])->where('studentId', '[0-9]+');
Route::get('/club-enrollments/{id}', [ClubEnrollmentController::class, 'show'])->where('id', '[0-9]+');
Route::post('/club-enrollments/{id}/request-cancellation', [ClubEnrollmentController::class, 'requestCancellation'])->where('id', '[0-9]+');
Route::post('/club-enrollments/{id}/cancel', [ClubEnrollmentController::class, 'cancel'])->where('id', '[0-9]+');
Route::post('/club-enrollments/{id}/reject-cancellation', [ClubEnrollmentController::class, 'rejectCancellation'])->where('id', '[0-9]+');
// Inscripciones a Talleres (Admin)
Route::get('/club-enrollments/admin/all', [ClubEnrollmentController::class, 'adminIndex']);
Route::get('/club-enrollments/admin/club/{clubId}', [ClubEnrollmentController::class, 'adminForClub'])->where('clubId', '[0-9]+');
Route::get('/club-enrollments/admin/report', [ClubEnrollmentController::class, 'report']);
Route::get('/club-enrollments/admin/export', [ClubEnrollmentController::class, 'export']);
// Reportes
Route::get('/reports/financial', [ReportController::class, 'financialReport']);
Route::get('/reports/financial/export-excel', [ReportController::class, 'financialReportExcel']);
Route::get('/webhook-logs', [WebhookGeneralController::class, 'list']); // Listar Webhooks
// Excel Uploads
Route::prefix('excel-uploads')->group(function () {
Route::get('/', [ExcelUploadController::class, 'list']);
Route::get('/stats', [ExcelUploadController::class, 'stats']);
Route::get('/{id}', [ExcelUploadController::class, 'show']);
Route::post('/', [ExcelUploadController::class, 'store']);
Route::put('/{uploadId}/lines/{lineNumber}', [ExcelUploadController::class, 'updateLine']);
Route::post('/{id}/confirm', [ExcelUploadController::class, 'confirm']);
Route::post('/{id}/cancel', [ExcelUploadController::class, 'cancel']);
Route::delete('/{id}', [ExcelUploadController::class, 'destroy']);
Route::post('/{id}/reprocess', [ExcelUploadController::class, 'reprocess']);
Route::get('/{id}/logs', [ExcelUploadController::class, 'getLogs']);
Route::get('/{id}/download-all', [ExcelUploadController::class, 'downloadAllLines']);
});
// Excel Upload Types
Route::prefix('excel-upload-types')->group(function () {
Route::get('/', [ExcelUploadController::class, 'getTypes']);
Route::get('/{code}', [ExcelUploadController::class, 'getTypeDetail']);
Route::get('/{code}/template', [ExcelUploadController::class, 'downloadTemplate']);
Route::get('/{code}/stats', [ExcelUploadController::class, 'getTypeStats']);
});
// Upload Lines
Route::prefix('upload-lines')->group(function () {
Route::get('/', [ExcelUploadLineController::class, 'list']);
Route::get('/{id}', [ExcelUploadLineController::class, 'show']);
Route::post('/bulk-update', [ExcelUploadLineController::class, 'bulkUpdate']);
Route::post('/{id}/restore', [ExcelUploadLineController::class, 'restore']);
// Eliminar lÃnea individual
Route::delete('/{uploadId}/lines/{lineNumber}', [ExcelUploadLineController::class, 'deleteLine']);
// Eliminar múltiples lÃneas
Route::post('/{uploadId}/lines/bulk-delete', [ExcelUploadLineController::class, 'bulkDeleteLines']);
});
});
// ======================================
// 🔹 TOKU ROUTES (internas + webhooks)
// ======================================
Route::prefix('/toku')->group(function () {
// 🔸 Clientes internos (API)
Route::post('customers', [CustomerController::class, 'store']);
Route::put('customers/{id}', [CustomerController::class, 'update']);
Route::get('customers/{id}', [CustomerController::class, 'show']);
Route::delete('customers/{id}', [CustomerController::class, 'delete']);
// 🔸 Eventos / Facturas / Pagos / Suscripciones
Route::get('events', [EventsController::class, 'index']);
Route::post('invoices', [InvoiceController::class, 'store']);
Route::put('invoices/{id}', [InvoiceController::class, 'update']);
Route::get('invoices/{id}', [InvoiceController::class, 'show']);
Route::post('invoices/{id}/void', [InvoiceController::class, 'void']);
Route::delete('invoices/{id}', [InvoiceController::class, 'destroy']);
Route::get('invoices/customer/{id}', [InvoiceController::class, 'byCustomer']);
Route::post('payments', [PaymentController::class, 'storeOrUpdate']);
Route::put('payments', [PaymentController::class, 'update']);
Route::delete('payments', [PaymentController::class, 'destroy']);
Route::get('organization/payments', [PaymentController::class, 'index']);
Route::get('payments/{id}', [PaymentController::class, 'show']);
Route::delete('payment-methods/{id}', [PaymentMethodController::class, 'delete']);
Route::get('organization/payment-methods', [PaymentMethodController::class, 'list']);
Route::get('payment-methods/customers/{customer_id}', [PaymentMethodController::class, 'listByCustomer']);
Route::post('subscriptions/associate/payment-method', [PaymentMethodController::class, 'associateToSubscription']);
Route::post('subscriptions/associate/payment-method/batch', [PaymentMethodController::class, 'associateBatch']);
Route::post('redirection', [RedirectionController::class, 'store']);
Route::put('redirection', [RedirectionController::class, 'update']);
Route::post('subscriptions', [SubscriptionController::class, 'create']);
Route::put('subscriptions/{id}', [SubscriptionController::class, 'update']);
Route::get('subscriptions/{id}', [SubscriptionController::class, 'get']);
Route::delete('subscriptions/{id}', [SubscriptionController::class, 'delete']);
Route::get('subscriptions/customer/{id}', [SubscriptionController::class, 'getByCustomer']);
Route::get('transactions', [TransactionController::class, 'index']);
Route::get('transactions/{id}', [TransactionController::class, 'show']);
Route::get('transactions/{id}/fees', [TransactionController::class, 'fees']);
Route::post('checkout-sessions', [CheckoutSessionController::class, 'store']);
Route::get('checkout-sessions/{id}', [CheckoutSessionController::class, 'show']);
Route::patch('checkout-sessions/{id}', [CheckoutSessionController::class, 'update']);
Route::post('checkout-sessions/{id}/expire', [CheckoutSessionController::class, 'expire']);
// Webhooks
Route::get('/webhook-endpoints', [WebhookController::class, 'index']); // Listar Webhooks
Route::post('/webhook-endpoints', [WebhookController::class, 'store']); // Crear Webhook
Route::put('/webhook-endpoints/{id}', [WebhookController::class, 'updateWebhook']); // Editar Webhook
Route::get('/webhook-endpoints/{id}', [WebhookController::class, 'show']); // Obtener Webhook
Route::post('/dummy_webhook', [WebhookController::class, 'testDummy']); // Envóo test Webhook
// ======================================
// 🔹 Webhooks (acepta X-App-Token o Bearer)
// ======================================
Route::prefix('webhooks')->group(function () {
Route::post('/transactions', [WebhookTransactionController::class, 'handle']);
Route::post('/customers', [WebhookCustomerController::class, 'handle']);
Route::post('/subscriptions', [WebhookSubscriptionController::class, 'handle']);
Route::post('/invoices', [WebhookInvoiceController::class, 'handle']);
Route::post('/payments', [WebhookPaymentController::class, 'handle']);
Route::post('/payouts', [WebhookPayoutController::class, 'handle']);
Route::post('/payment-methods', [WebhookPaymentMethodController::class, 'handle']);
Route::post('/payment-intents', [WebhookPaymentIntentController::class, 'handle']);
});
// Dummy webhook test
Route::post('/dummy_webhook', [WebhookController::class, 'testDummy']);
});
// ======================================
// 🔹 SIGNAPIS ROUTES
// ======================================
Route::prefix('/signapis')->group(function () {
// ======================================
// 🔹 RUTAS DE PRUEBAS
// ======================================
Route::post('/test/send', [SignapisTestController::class, 'sendToSignapis']);
Route::post('/test/webhook-register', [SignapisTestController::class, 'registerWebhookTest']);
Route::post('/test/webhook', [SignapisTestController::class, 'webhook']);
// ======================================
// 🔹 Webhooks
// ======================================
Route::get('/webhook', [SignapisWebhookController::class, 'getWebhook']);
Route::post('/webhook', [SignapisWebhookController::class, 'configureWebhook']);
Route::delete('/webhook', [SignapisWebhookController::class, 'deleteWebhook']);
Route::post('/webhook/test', [SignapisWebhookController::class, 'testWebhook']);
// ======================================
// 🔹 Logos
// ======================================
Route::post('/logos', [SignapisLogosController::class, 'createLogo']);
Route::get('/logos', [SignapisLogosController::class, 'listLogos']);
Route::get('/logos/{code}', [SignapisLogosController::class, 'getLogo']);
Route::delete('/logos/{code}', [SignapisLogosController::class, 'deleteLogo']);
// ======================================
// 🔹 Templates
// ======================================
Route::post('/templates', [SignapisTemplatesController::class, 'createTemplate']);
Route::get('/templates', [SignapisTemplatesController::class, 'listTemplates']);
Route::get('/templates/{code}/{type}', [SignapisTemplatesController::class, 'getTemplate']);
Route::patch('/templates/{code}/{type}', [SignapisTemplatesController::class, 'updateTemplate']);
Route::delete('/templates/{code}/{type}', [SignapisTemplatesController::class, 'deleteTemplate']);
Route::delete('/templates/{code}', [SignapisTemplatesController::class, 'deleteTemplatesByCode']);
Route::post('/templates/test', [SignapisTemplatesController::class, 'testTemplate']);
// ======================================
// 🔹 Notifications
// ======================================
Route::post('/signatories/{signatoryId}/resend', [SignapisNotificationsController::class, 'resendInvitation']);
// ======================================
// 🔹 Documentos
// ======================================
Route::post('/documents', [SignapisDocumentController::class, 'createDocument']); // Crear documento
Route::get('/documents/{documentId}', [SignapisDocumentController::class, 'getDocument']); // Obtener documento
// Firmantes
Route::post('/documents/signatories', [SignapisDocumentController::class, 'addSignatories']); // Agregar firmantes
Route::patch('/documents/signatories/{signatoryId}', [SignapisDocumentController::class, 'updateSignatory']); // Actualizar firmante
Route::delete('/documents/signatories/{signatoryId}', [SignapisDocumentController::class, 'deleteSignatory']); // Eliminar firmante
Route::post('/documents/signatories/{signatoryId}/reject', [SignapisDocumentController::class, 'rejectDocument']); // Rechazar documento
// Cancelaciones
Route::patch('/documents/{documentId}/cancel', [SignapisDocumentController::class, 'cancelDocumentById']); // Cancelar por ID interno
Route::patch('/documents/client/{documentClientId}/cancel', [SignapisDocumentController::class, 'cancelDocumentByClientId']); // Cancelar por ID cliente
// ======================================
// 🔹 Batches
// ======================================
Route::post('/documents/batch/file', [SignapisDocumentController::class, 'uploadBatchFile']);
Route::post('/documents/batch', [SignapisDocumentController::class, 'createBatch']);
Route::post('/documents/batch/signatories/{signatoryId}/sign', [SignapisDocumentController::class, 'signBatch']);
Route::post('/documents/batch/signatories/{signatoryId}/reject', [SignapisDocumentController::class, 'rejectBatch']);
Route::get('/documents/batch/{groupId}', [SignapisDocumentController::class, 'getBatch']);
Route::patch('/documents/batch/{groupId}/cancel', [SignapisDocumentController::class, 'cancelBatch']);
Route::post('/documents/batch/certify', [SignapisDocumentController::class, 'certifyBatch']);
Route::get('/documents/batch/{groupId}/summary/{email}', [SignapisDocumentController::class, 'getBatchSignerSummary']);
Route::patch('/documents/batch/{groupId}/summary/{email}', [SignapisDocumentController::class, 'updateBatchSigner']);
// ======================================
// 🔹 Documentos (Individual Signing)
// ======================================
Route::post('/documents/signatories/{signatoryId}/sign', [SignapisSigninController::class, 'signDocument']);
// ======================================
// 🔹 Reportes
// ======================================
Route::get('/reports/statusDocuments', [SignapisReportsController::class, 'getStatusDocumentsReport']);
Route::get('/reports/company', [SignapisReportsController::class, 'getCompanyReport']);
});
// ======================================
// 🔹 WEBHOOK DE PRUEBA
// ======================================
Route::post('/payment-webhook', function (Request $request) {
Log::info('Webhook /payment-webhook recibido', [
'ip' => $request->ip(),
'headers' => $request->headers->all(),
'payload' => $request->all(),
]);
return response()->json(['ok' => true], 200);
})->withoutMiddleware([VerifyCsrfToken::class]);
});
Route::post('/toku/webhooks', [WebhookGeneralController::class, 'handle']);
Route::post('/signapis-webhooks', [WebhookGeneralController::class, 'handle']);