File: /var/www/matriculas_api_dev/app/Http/Controllers/ContractController.php
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use App\Http\Requests\Contract\StoreContractRequest;
use App\Http\Requests\Contract\UpdateContractRequest;
use App\Http\Requests\Contract\UpdateContractParentRequest;
use App\Http\Requests\Contract\UploadSignedContractRequest;
use App\Http\Requests\Contract\ChangeContractParentRequest;
use App\Services\ContractService;
use App\Services\DebtCalculationService;
use Illuminate\Http\Request;
use Exception;
use Illuminate\Support\Facades\Response;
class ContractController extends Controller
{
protected $contractService;
public function __construct(ContractService $contractService)
{
// $this->middleware('auth.users')->except('logout');
// $this->middleware('auth.users:CANCEL_CONTRACT')->only(['cancel']);
$this->contractService = $contractService;
}
public function list(Request $request)
{
try {
$periodId = $request->get('period_id');
$limit = $request->get('limit');
$data = $this->contractService->list($periodId, null, $limit);
return genericResponse(['data' => $data, 'message' => 'ok', 'code' => 200], 200);
} catch (Exception $e) {
return genericResponse(['error' => $e->getMessage()], $e->getCode() ?: 500);
}
}
public function store(StoreContractRequest $request)
{
try {
$this->contractService->store($request);
return genericResponse(['data' => null, 'message' => 'Contrato creado correctamente', 'code' => 201], 201);
} catch (Exception $e) {
return genericResponse(['error' => $e->getMessage()], $e->getCode() ?: 500);
}
}
public function update($id, UpdateContractRequest $request)
{
try {
$this->contractService->update($id, $request);
return genericResponse(['data' => null, 'message' => 'Contrato actualizado correctamente', 'code' => 204], 204);
} catch (Exception $e) {
return genericResponse(['error' => $e->getMessage()], $e->getCode() ?: 500);
}
}
public function updateParent($code, UpdateContractParentRequest $request)
{
try {
$this->contractService->updateParent($code, $request);
return genericResponse(['data' => null, 'message' => 'Datos actualizado correctamente', 'code' => 204], 204);
} catch (Exception $e) {
return genericResponse(['error' => $e->getMessage()], $e->getCode() ?: 500);
}
}
public function show($id)
{
try {
$data = $this->contractService->show($id);
return genericResponse(['data' => $data, 'message' => 'ok', 'code' => 200], 200);
} catch (Exception $e) {
return genericResponse(['error' => $e->getMessage()], $e->getCode() ?: 500);
}
}
public function showByCode($code)
{
try {
$data = $this->contractService->showByCode($code);
return genericResponse(['data' => $data, 'message' => 'ok', 'code' => 200], 200);
} catch (Exception $e) {
return genericResponse(['error' => $e->getMessage()], $e->getCode() ?: 500);
}
}
public function signature($code)
{
try {
$data = $this->contractService->signature($code);
return genericResponse(['data' => $data, 'message' => 'ok', 'code' => 200], 200);
} catch (Exception $e) {
return genericResponse(['error' => $e->getMessage()], $e->getCode() ?: 500);
}
}
public function destroy($id)
{
try {
$this->contractService->delete($id);
return genericResponse(['data' => null, 'message' => 'Contrato eliminado correctamente', 'code' => 200], 200);
} catch (Exception $e) {
return genericResponse(['error' => $e->getMessage()], $e->getCode() ?: 500);
}
}
public function uploadSignedPdf($code, UploadSignedContractRequest $request)
{
try {
$data = $this->contractService->uploadSignedPdf($code, $request->file('signed_pdf'));
return genericResponse(['data' => $data, 'message' => 'Contrato firmado subido correctamente', 'code' => 200], 200);
} catch (Exception $e) {
return genericResponse(['error' => $e->getMessage()], $e->getCode() ?: 500);
}
}
public function generatePdf($id, Request $request, $type = 'code')
{
try {
return $this->contractService->generatePdf($id, $request, $type);
} catch (Exception $e) {
$errorCode = $e->getCode();
return genericResponse(['error' => $e->getMessage()], $errorCode ?: 500);
}
}
public function sendPDF($id)
{
try {
$data = $this->contractService->sendPDF($id);
return genericResponse(['data' => null, 'message' => 'Contrato enviado correctamente', 'code' => 200], 200);
} catch (Exception $e) {
$errorCode = $e->getCode();
return genericResponse(['error' => $e->getMessage()], $errorCode ?: 500);
}
}
public function generatePDF64($code)
{
try {
$data = $this->contractService->generatePDF64($code);
if (empty($data->file_data)) {
throw new \Exception("No se encontró el archivo PDF firmado.", 404);
}
$pdfContent = base64_decode($data->file_data);
return Response::make($pdfContent, 200, [
'Content-Type' => 'application/pdf',
'Content-Disposition' => 'inline; filename="Contrato_' . $data->code_contract . '.pdf"',
]);
// Decodificar base64 a binario
$pdfContent = base64_decode($data->file_data);
// Generar un nombre de archivo seguro
$fileName = 'contrato_' . preg_replace('/[^A-Za-z0-9_\-]/', '_', $data->code_contract) . '.pdf';
// 🔹 FORZAR DESCARGA DIRECTA (Attachment)
return Response::make($pdfContent, 200, [
'Content-Type' => 'application/pdf',
'Content-Disposition' => 'attachment; filename="' . strLower($fileName) . '"',
'Content-Transfer-Encoding' => 'binary',
'Accept-Ranges' => 'bytes',
]);
} catch (Exception $e) {
$errorCode = $e->getCode();
return genericResponse(['error' => $e->getMessage()], $errorCode ?: 500);
}
}
public function getContractActive()
{
try {
$data = $this->contractService->getContractActive();
return genericResponse(['data' => $data, 'message' => 'OK', 'code' => 200], 200);
} catch (Exception $e) {
$errorCode = $e->getCode();
return genericResponse(['error' => $e->getMessage()], $errorCode ?: 500);
}
}
public function incompleteEnrollments()
{
try {
$data = $this->contractService->getIncompleteEnrollmentsForParent();
return genericResponse(['data' => $data, 'message' => 'ok', 'code' => 200], 200);
} catch (Exception $e) {
return genericResponse(['error' => $e->getMessage()], $e->getCode() ?: 500);
}
}
public function changeParent($code, ChangeContractParentRequest $request)
{
try {
if (!auth()->user()->hasPermission('CHANGE_PARENT_CONTRACT')) {
throw new Exception('No tienes permisos para cambiar el apoderado de un contrato.', 403);
}
$this->contractService->changeFinancialParent($code, $request->new_parent_id);
return genericResponse(['data' => null, 'message' => 'Apoderado financiero cambiado correctamente', 'code' => 200], 200);
} catch (Exception $e) {
return genericResponse(['error' => $e->getMessage()], $e->getCode() ?: 500);
}
}
public function recalculateSiblings(Request $request)
{
try {
$request->validate([
'parent_id' => 'required|integer|exists:parents,id',
'period_id' => 'required|integer|exists:periods,id',
]);
$debtService = app(DebtCalculationService::class);
$result = $debtService->recalculateFamilySiblingDebts(
$request->parent_id,
$request->period_id
);
return genericResponse([
'data' => $result,
'message' => 'Recalculación de hermanos completada',
'code' => 200
], 200);
} catch (Exception $e) {
return genericResponse(['error' => $e->getMessage()], $e->getCode() ?: 500);
}
}
public function toggleLateOptionals($code, Request $request)
{
try {
if (!auth()->user()->hasPermission('UNLOCK_OPTIONAL_PAYMENTS')) {
throw new Exception('No tienes permisos para reabrir el pago de opcionales.', 403);
}
$request->validate([
'allow' => 'required|boolean',
]);
$result = $this->contractService->toggleLateOptionals($code, $request->allow);
$msg = $request->allow
? 'Pago de opcionales reabierto correctamente'
: 'Pago de opcionales cerrado correctamente';
return genericResponse(['data' => $result, 'message' => $msg, 'code' => 200], 200);
} catch (Exception $e) {
return genericResponse(['error' => $e->getMessage()], $e->getCode() ?: 500);
}
}
}