HEX
Server: Apache/2.4.58 (Ubuntu)
System: Linux Bradford-Sitios 6.14.0-1017-azure #17~24.04.1-Ubuntu SMP Mon Dec 1 20:10:50 UTC 2025 x86_64
User: www-data (33)
PHP: 7.4.33
Disabled: pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare,
Upload Files
File: /var/www/api_matriculas/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);
		}
	}
}