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/matriculas_api_dev/app/Repositories/ParentRepository.php
<?php

namespace App\Repositories;

use App\Models\Parents;
use App\Models\Profile;
use App\Models\User;
use Exception;
use Illuminate\Support\Facades\DB;

class ParentRepository
{
    public function getByCodeToku($code_toku, $id = null)
    {
        $query = Parents::where('code_toku', $code_toku)->where('deleted', false);

        if ($id > 0) {
            $query->where('id', '!=', $id);
        }

        $register = $query->first();
        if (!$register) {
            return false;
        }

        return $register;
    }
  
    public function getByRut($rut, $id = null)
    {
        $query = Parents::where('rut', $rut)->where('deleted', false);

        if ($id > 0) {
            $query->where('id', '!=', $id);
        }

        $register = $query->first();
        if (!$register) {
            return false;
        }

        return $register;
    }

    public function getProfile()
    {
        $profileData = Profile::where('code', 'parent')->first();
        if (!$profileData) {
            throw new Exception("Perfil de apoderado no existe o fue eliminado", 404);
        }
        return $profileData->id;
    }


    public function getAll()
    {
        $registers = Parents::where('deleted', false);

        return $registers->orderBy('first_name', 'asc')->get();
    }

    /**
     * Obtener apoderados disponibles para crear matrícula en un periodo.
     * Solo retorna apoderados que tengan al menos un estudiante:
     *   1. Habilitado en student_period para ese periodo
     *   2. Que NO tenga ya un contrato para ese periodo
     */
    public function getAvailableForPeriod($periodId)
    {
        return Parents::where('deleted', false)
            ->whereExists(function ($query) use ($periodId) {
                $query->select(DB::raw(1))
                    ->from('students')
                    ->whereColumn('students.financial_parent_id', 'parents.id')
                    ->where('students.deleted', false)
                    ->where('students.status', true)
                    // Estudiante debe estar en student_period para este periodo
                    ->whereExists(function ($spQuery) use ($periodId) {
                        $spQuery->select(DB::raw(1))
                            ->from('student_period')
                            ->whereColumn('student_period.student_id', 'students.id')
                            ->where('student_period.period_id', $periodId);
                    })
                    // Estudiante NO debe tener contrato para este periodo
                    ->whereNotExists(function ($cdQuery) use ($periodId) {
                        $cdQuery->select(DB::raw(1))
                            ->from('contracts_detail')
                            ->join('contracts', 'contracts.id', '=', 'contracts_detail.contract_id')
                            ->whereColumn('contracts_detail.student_id', 'students.id')
                            ->where('contracts.period_id', $periodId);
                    });
            })
            ->orderBy('first_name', 'asc')
            ->get();
    }


    public function getById($id, $validateProfile = true)
    {
        $profileId = $this->getProfile();
        $query = Parents::whereHas('user', function ($q) use ($profileId, $validateProfile) {
            if ($validateProfile) {
                $q->where('profile_id', '=', $profileId);
            }
            $q->where('deleted', false);
        })->where('deleted', false)->where('id', $id);
        $register = $query->first();
        
        if (!$register) {
            throw new Exception("Apoderado no existe o fue eliminado", 404);
        }
        return $register;
    }


    public function create($data)
    {
        $profileId = $this->getProfile();
        $documentType = $data->document_type ?? 'RUT';
        $isPassport = $documentType === 'PASSPORT';

        // Determinar identificador
        if ($isPassport) {
            $identifier = !empty($data->rut) ? strUpper($data->rut) : null;
        } else {
            $identifier = !empty($data->rut) ? formatterRut($data->rut, false) : null;
        }

        // Crear usuario
        $password = bcrypt($data->password);
        $createUserData = [
            'name'                => strUpper($data->first_name . ' ' . $data->last_name),
            'username'            => $identifier ?: strLower($data->email),
            'rut'                 => $identifier,
            'email'               => strLower($data->email),
            'password'            => $password,
            'activation_token'    => ($data->activation_token && !empty($data->activation_token)) ? ($data->activation_token) : null,
            'account_confirmed'   => $data->account_confirmed ?? false,
            'account_confirmed_at' => $data->account_confirmed_at ?? null,
            'status'              => true,
            'profile_id'          => $profileId,
            'created_at'          => now(),
            'updated_at'          => now(),
        ];

        if (auth()->check()) {
            $createUserData['user_created'] = auth()->user()->id;
            $createUserData['user_updated'] = auth()->user()->id;
        }

        $user = User::create($createUserData);
        if (!$user) {
            throw new Exception("Ocurrió un error al crear usuario para apoderado", 500);
        }

        // Crear registro en parents
        $createParentData = [
            'relationship_id' => $data->relationship ?? null,
            'document_type'   => $documentType,
            'rut'             => $identifier,
            'first_name'      => strUpper($data->first_name),
            'second_name'     => $data->second_name ? strUpper($data->second_name) : null,
            'last_name'       => strUpper($data->last_name),
            'second_last_name' => $data->second_last_name ? strUpper($data->second_last_name) : null,
            'email'           => strLower($data->email),
            'mobile'          => $data->mobile ?? null,
            'home_phone'      => $data->home_phone ?? null,
            'work_phone'      => $data->work_phone ?? null,
            'birth_date'      => $data->birth_date ?? null,
            'gender_id'       => $data->gender ?? null,
            'country_id'      => $data->country ?? null,
            'region_id'       => $data->region ?? null,
            'commune_id'      => $data->commune ?? null,
            'address'         => $data->address ?? null,
            'profession'      => $data->profession ?? null,
            'status'          => true,
            'user_id'         => $user->id,
            'created_at'      => now(),
            'updated_at'      => now(),
        ];

        if (auth()->check()) {
            $createParentData['user_created'] = auth()->user()->id;
            $createParentData['user_updated'] = auth()->user()->id;
        }

        $parent = Parents::create($createParentData);

        return $parent;
    }



    /**
     * createOrUpdate para API v1 (clave: parent_rut o passport)
     */
    public function createOrUpdateByRut($data)
    {
        $documentType = $data->document_type ?? 'RUT';
        $isPassport = $documentType === 'PASSPORT';

        if ($isPassport) {
            $identifier = strUpper($data->parent_rut);
        } else {
            $identifier = formatterRut($data->parent_rut, false);
        }

        $existing = $this->getByRut($identifier);

        if ($existing) {
            // Update existing parent
            if (!empty($data->first_name))             $existing->first_name       = strUpper($data->first_name);
            if (!empty($data->second_name))            $existing->second_name      = strUpper($data->second_name);
            if (!empty($data->last_name))              $existing->last_name        = strUpper($data->last_name);
            if (!empty($data->second_last_name))       $existing->second_last_name = strUpper($data->second_last_name);
            if (!empty($data->email))                  $existing->email            = strLower($data->email);
            if (!empty($data->mobile))                 $existing->mobile           = $data->mobile;
            if (!empty($data->birth_date))             $existing->birth_date       = $data->birth_date;
            if (!empty($data->address))                $existing->address          = $data->address;
            if (isset($data->family_relationship_id))  $existing->relationship_id  = $data->family_relationship_id;
            if (!empty($data->external_id))            $existing->external_id      = $data->external_id;
            $existing->document_type = $documentType;
            $existing->updated_at = now();
            $existing->save();

            // Update associated user email/name
            if ($existing->user_id) {
                $user = User::find($existing->user_id);
                if ($user) {
                    $user->name = strUpper($existing->first_name . ' ' . $existing->last_name);
                    if (!empty($data->email)) {
                        $user->email = strLower($data->email);
                    }
                    $user->updated_at = now();
                    $user->save();
                }
            }

            return ['operation' => 'update', 'parent' => $existing];
        }

        // Create new parent with user
        $profileId = $this->getProfile();
        $email = strLower($data->email ?? '');
        $password = bcrypt('1234');
        $activationToken = getToken();

        $user = User::create([
            'name'              => strUpper(($data->first_name ?? '') . ' ' . ($data->last_name ?? '')),
            'username'          => $identifier ?: $email,
            'rut'               => $identifier,
            'email'             => $email,
            'password'          => $password,
            'activation_token'  => $activationToken,
            'account_confirmed' => false,
            'status'            => true,
            'profile_id'        => $profileId,
            'created_at'        => now(),
            'updated_at'        => now(),
        ]);

        $parent = Parents::create([
            'external_id'       => $data->external_id ?? null,
            'relationship_id'   => $data->family_relationship_id ?? null,
            'document_type'     => $documentType,
            'rut'               => $identifier,
            'first_name'        => strUpper($data->first_name ?? ''),
            'second_name'       => !empty($data->second_name) ? strUpper($data->second_name) : null,
            'last_name'         => strUpper($data->last_name ?? ''),
            'second_last_name'  => !empty($data->second_last_name) ? strUpper($data->second_last_name) : null,
            'email'             => $email,
            'mobile'            => $data->mobile ?? null,
            'birth_date'        => $data->birth_date ?? null,
            'address'           => $data->address ?? null,
            'status'            => true,
            'user_id'           => $user->id,
            'created_at'        => now(),
            'updated_at'        => now(),
        ]);

        return ['operation' => 'create', 'parent' => $parent];
    }

    public function update($registerData, $data)
    {
        $userId = $registerData->user_id;
        $documentType = $data->document_type ?? $registerData->document_type ?? 'RUT';
        $isPassport = $documentType === 'PASSPORT';

        // Determinar identificador
        if (!empty($data->rut)) {
            $identifier = $isPassport ? strUpper($data->rut) : formatterRut($data->rut, false);
        } else {
            $identifier = $registerData->rut;
        }

        // Actualizar datos de parent
        $registerData->relationship_id  = $data->relationship ?? $registerData->relationship_id;
        $registerData->document_type    = $documentType;
        $registerData->rut              = $identifier;
        $registerData->first_name       = strUpper($data->first_name ?? $registerData->first_name);
        $registerData->second_name      = $data->second_name ? strUpper($data->second_name) : $registerData->second_name;
        $registerData->last_name        = strUpper($data->last_name ?? $registerData->last_name);
        $registerData->second_last_name = $data->second_last_name ? strUpper($data->second_last_name) : $registerData->second_last_name;
        $registerData->email            = strLower($data->email ?? $registerData->email);
        $registerData->mobile           = $data->mobile ?? $registerData->mobile;
        $registerData->home_phone       = $data->home_phone ?? $registerData->home_phone;
        $registerData->work_phone       = $data->work_phone ?? $registerData->work_phone;
        $registerData->birth_date       = $data->birth_date ?? $registerData->birth_date;
        $registerData->gender_id        = $data->gender ?? $registerData->gender_id;
        $registerData->country_id       = $data->country ?? $registerData->country_id;
        $registerData->region_id        = $data->region ?? $registerData->region_id;
        $registerData->commune_id       = $data->commune ?? $registerData->commune_id;
        $registerData->address          = $data->address ?? $registerData->address;
        $registerData->profession       = $data->profession ?? $registerData->profession;
        $registerData->status           = $data->status == 1 ? true : false;
        $registerData->user_updated     = auth()->check() ? auth()->user()->id : $registerData->user_updated;
        $registerData->updated_at       = now();

        if ($registerData->save()) {
            // Actualizar usuario asociado
            $userData = User::find($userId);
            if ($userData) {
                $userData->name       = strUpper($data->first_name . ' ' . $data->last_name);
                $userData->email      = strLower($data->email ?? $userData->email);
                $userData->rut        = $identifier;
                $userData->status     = $data->status == 1 ? true : false;
                $userData->updated_at = now();
                if (auth()->check()) {
                    $userData->user_updated = auth()->user()->id;
                }
                $userData->save();
            }
        }

        return true;
    }
}