HEX
Server: Apache/2.4.41 (Ubuntu)
System: Linux ip-172-31-42-149 5.15.0-1084-aws #91~20.04.1-Ubuntu SMP Fri May 2 07:00:04 UTC 2025 aarch64
User: ubuntu (1000)
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/vhost/disk-apps/demo.sports-crowd.com/app/Http/Controllers/AcademyPurchaseController.php
<?php

namespace App\Http\Controllers;

use \Excel;
use App\Erp;
use App\Tag;
use App\User;
use Exception;
use App\ErpLog;
use App\Module;
use App\Address;
use App\UserTag;
use Carbon\Carbon;
use App\AcademyUser;
use App\ErpParameter;
use App\AcademyPeriod;
use App\PaymentMethod;
use App\AcademyCategory;
use App\AcademyLocation;
use App\AcademyLocationPeriod;
use App\AcademyParameter;
use App\AcademyPurchase;
use App\Core\Academy\Application\ParameterService;
use App\PaymentTransaction;
use App\Services\ErpService;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Auth;
use App\Repositories\ERPLogRepository;
use App\Core\Payment\PaymentStatusEnum;
use App\Http\Controllers\UtilController;
use Yajra\DataTables\Facades\DataTables;
use App\Services\AcademyLocationsService;
use App\Repositories\PaymentTransactionRepository;
use App\Http\Controllers\Exports\AcademyPurchasesExport;
use App\Core\Payment\Application\PaymentTransactionService;
use App\Http\Controllers\Imports\AcademySchedulePaymentsImport;
use App\Http\Controllers\Imports\AcademySchedulePaymentsTemplate;
use App\Core\CorporateIdentity\Application\CorporateIdentityService;

class AcademyPurchaseController extends Controller implements PaymentTransactionRepository, ERPLogRepository
{
    private $util;
    public $messages = [];
    private $academyParameterController;
    private $academyParameterService;

    public function __construct()
    {
        $this->util = new UtilController();
        $this->academyParameterController = new AcademyParameterController;
        $this->academyParameterService = new ParameterService();
    }

    public function index($type_academy = 'children')
    {
        $states = PaymentTransaction::groupBy('state')->orderBy('state', 'ASC')->pluck('state');
        $states[] = 'Vacio';

        $duePayments = array();
        $duePayments[] = 'SI';
        $duePayments[] = 'NO';
        $academyLocationsService = new AcademyLocationsService;

        if (!$academyLocationsService->validateAuthorizedLocations()) {
            $authorizedLocations = $academyLocationsService->getAuthorizedLocations();
            $franchises = AcademyLocation::select('id', 'name')->where('active', 1)->whereIn('id', $authorizedLocations)->orderBy('name', 'ASC')->get();
        } else {
            $franchises = AcademyLocation::select('id', 'name')->where('active', 1)->orderBy('name', 'ASC')->get();
        }

        // Obtener academy_location_id de las franquicias seleccionadas
        $academyLocationIds = $franchises->pluck('id')->toArray();

        // Obtener academy_period_id basado en academy_location_id
        $academyPeriodIds = AcademyLocationPeriod::whereIn('academy_location_id', $academyLocationIds)
            ->pluck('academy_period_id')
            ->toArray();

        // Verificar si hay academyPeriodIds válidos
        if (!empty($academyPeriodIds)) {
            // Si hay academyPeriodIds, se filtran por academyPeriodIds
            $academyPeriods = AcademyPeriod::whereIn('id', $academyPeriodIds)->pluck('name')->toArray();
        } else {
            // Si no hay, se filtran todos
            $academyPeriods = AcademyPeriod::pluck('name')->toArray();
        }

        // Inicializar el array de tipos con 'Inscripción'
        $types = array_merge(['Inscripción'], $academyPeriods);

        $corporateIdentity = CorporateIdentityService::get();
        return view('academy.purchases.list', compact('states', 'types', 'duePayments', 'type_academy', 'franchises', 'corporateIdentity'));
    }

    public function tableFilter(Request $request)
    {
        $obj = $this->tableFilterQuery($request);

        DB::enableQueryLog();
        $dataTable = DataTables::of($obj);

        $dataTable->filterColumn('coaches', function ($query, $keyword) {
            $query->havingRaw("GROUP_CONCAT(DISTINCT(CONCAT_WS(' ', users1.first_name, users1.last_name, CONCAT('(',users1.email,')'))) LIKE ?", ['%' . $keyword . '%']);
        });

        $dataTable->filterColumn('hashed_reference', function ($query, $keyword) {
            $query->whereRaw('MD5(payment_transactions.reference) LIKE ?', ['%' . $keyword . '%']);
        });
        $this->tableFilterCustomColumns($dataTable);

        $response = $dataTable->make(true);
        $data = $response->getData();
        $data = json_decode(json_encode($data), true);
        $queries = DB::getQueryLog();
        $newQueries = [];
        foreach ($queries as $query) {
            if (str_contains($query['query'], 'group by') && str_contains($query['query'], 'academy_purchases')) {
                $newQueries[] = $query;
            }
        }
        $data['queries'] = $newQueries;
        return $data;
    }

    public function validateExport(Request $request)
    {
        if ($request['query']) {
            ini_set('memory_limit', '2048M');
            $results = $this->util->getGenericData($request["query"], $request["bindings"]);
            if (count($results) > 0) {
                $name = 'ReporteAcademiaPagos' . time() . '.xlsx';
                Excel::store(new AcademyPurchasesExport($results), $name, 'public');
                return response()->json(['success' => true, 'message' => 'Validación OK', 'data' => $name]);
            }
        }
        return response()->json(['success' => false, 'message' => 'No existen datos a exportar']);
    }

    public function export($name)
    {
        return $this->util->export($name);
    }

    public function finishPayment($paymentTransaction)
    {
        if (!$paymentTransaction) {
            return response()->json(['success' => false, 'message' => 'No se encontró la transacción de pago'], 200);
        }
        if ($paymentTransaction->state == 'CONFIRMED') {
            $academyPurchase = AcademyPurchase::with('academy_user', 'academy_user.user', 'payment_transaction')
                ->where('payment_transaction_id', $paymentTransaction->id)
                ->first();

            if (!$academyPurchase || !$academyPurchase->academy_user_id) {
                return response()->json(['success' => false, 'message' => 'No se encontró el pago de la academia'], 200);
            }

            // Asignar estado academia
            $academyState = new AcademyStateController();
            $academyState->assignStateAcademy($academyPurchase->academy_user_id);

            // Validar pago inscripción
            if (isset($academyPurchase->enrollment_academy_price)) {
                $request = new Request([
                    'id'    => $academyPurchase->academy_user_id,
                    'state' => true
                ]);

                // Ajustar cupos disponibles
                $controller = new AcademyScheduleController();
                $controller->adjustAvailableSlotsSchedules();

                // Activar usuario
                $academyController = new AcademyController;
                $academyController->activate($request);

                // Asociar etiqueta Inscrito_academia_XXXX
                $this->createEnrollmentTag($academyPurchase, $academyPurchase->term);

                // Validar periodo por defecto
                $academyPeriodController = new AcademyPeriodController;
                if ($academyDefaultPeriod = $academyPeriodController->validateDefaultPeriod($academyPurchase->academy_user_id)) {
                    $this->createPaymentSchedule(
                        $academyPurchase->academy_user_id,
                        $academyDefaultPeriod->id,
                        $academyPurchase->user_id,
                        null,
                        1
                    );
                }
            }
            // Validar pago mensualidad
            else {
                $academyController = new AcademyController;
                // Validar estado de pago
                $academyController->validatePaymentStatus($academyPurchase->academy_user_id);
                // Validar estado activo
                $academyController->validateActive($academyPurchase->academy_user_id);
                // Crear proximo pago
                $purchase = $this->createNextPayment($academyPurchase);
                // Validar estado al día de pagos y notificación de renovación
                if (!$purchase) {
                    $academyController->notificateEmailRegistrationRenewal($academyPurchase->academy_user_id);
                }
            }

            try {
                $invoice = new CollectionInvoiceController();
                $invoice->validateCreditCollectionInvoice($paymentTransaction->gateway_payments_id, $paymentTransaction->reference, $paymentTransaction->gateway_transaction_id, 'academy', $academyPurchase->price);
                // $pay = new LealPayController();
                // $pay->validateUserPointsAccumulation($order);
            } catch (\Throwable $th) {
                $data = [
                    'academyPurchase'       => $academyPurchase,
                    'message'               => $th->getMessage(),
                    'getFile'               => $th->getFile(),
                    'getLine'               => $th->getLine(),
                ];
                $util = new UtilController;
                $util->logFile(json_encode($data));
            }

            // Sincronizar pago al ERP
            $this->syncERP($academyPurchase);
        }
    }

    public function indexEditUserPayment($id)
    {
        $academy_payment    = AcademyPurchase::where('id', $id)->with('user', 'academy_user', 'payment_transaction')->first();
        $allPeriodsAcademy  = AcademyPeriod::select('id', 'name')->where('active', true)->get();
        $paymentMethods     = PaymentMethod::select('id', 'name')->where('active', true)->get();
        $type = 'purchases';
        return view('academy.payments.edit', compact('academy_payment', 'allPeriodsAcademy', 'paymentMethods', 'type'));
    }

    public function indexPayUser($id)
    {
        $academy_payment    = AcademyPurchase::where('id', $id)->with('user', 'academy_user', 'payment_transaction')->first();
        $paymentMethods     = PaymentMethod::select('id', 'name')->where('active', true)->get();
        $type = 'purchases';
        return view('academy.payments.pay', compact('academy_payment', 'paymentMethods', 'type'));
    }

    public function createEnrollmentPayment($academyUser, $discount, $paymentType, $confirmPayment = false)
    {
        $academyCategory = null;
        if ($academyUser->academy_category_id) {
            $academyCategory = AcademyCategory::where([['id', $academyUser->academy_category_id], ['active', 1]])->first();
        }
        if (!$academyCategory) {
            return array('status' => false, 'message' => 'El alumno no contiene una categoría registrada o vigente al día de hoy');
        }

        $now = Carbon::now();

        $startTerm = $this->academyParameterController->registrationStartDate($academyUser->type_academy);
        $endTerm = $this->academyParameterController->registrationEndDate($academyUser->type_academy);

        $years = [$startTerm->year, $endTerm->year];
        $term = implode('-', array_unique($years));

        $startTermString = $startTerm->toDateString();
        $endTermString = $endTerm->toDateString();
        $academyPurchase = AcademyPurchase::with('payment_transaction')
            ->where('academy_user_id', $academyUser->id)
            ->where('term_type', $paymentType)
            ->where(function ($query) use ($term, $startTermString, $endTermString) {
                $query->where('term', $term)
                    ->orWhere(function ($query) use ($startTermString, $endTermString) {
                        $query->where('start_term', $startTermString)->where('end_term', $endTermString);
                    });
            })
            ->whereNull('deleted_at')
            ->first();

        if ($academyPurchase && !$academyPurchase->payment_transaction) {
            $academyPurchase->delete();
            $academyPurchase = null;
        }

        if ($academyPurchase && $academyPurchase->payment_transaction && $academyPurchase->payment_transaction->state == 'CONFIRMED') {
            return array('status' => true, 'academyPurchase' => $academyPurchase, 'message' => 'Ya existe un pago de inscripción vigente para este alumno');
        }

        if (!$discount) {
            $studentDiscount = $this->validateStudentDiscounts($academyUser->id, 'enrollment');
            if ($studentDiscount) {
                $discount = $studentDiscount;
            }
        }

        $serviceCharge = 0;
        $controller = new ServiceChargeController;
        if ($controller->validateServiceCharge()) {
            $request = new Request([
                'services'      => 'academy',
                'payment_types' => 'enrollment',
                'categories'    => [$academyCategory->id]
            ]);
            $serviceCharge = $controller->calculateServiceCharge($request);
        }
        $paymentDueDate         = $endTerm;
        if ($daysPaymentDueDate = $this->academyParameterController->validateEnableCollectionAdvancePayments()) {
            $paymentDueDate     = Carbon::parse($startTerm)->addDays($daysPaymentDueDate - 1);
        }

        $subTotal = $this->formatNumberForCurrency($academyCategory->inscription_value * (1 - ($discount / 100)));
        if ($serviceCharge && str_contains($serviceCharge . '', '%')) {
            $serviceCharge = (floatval(str_replace('%', '', $serviceCharge)) / 100) * $subTotal;
        }
        $serviceCharge = !$subTotal ? 0 : $this->formatNumberForCurrency($serviceCharge);
        $data = [
            'enrollment_academy_price'  => $academyCategory->inscription_value,
            'subtotal'                  => $subTotal,
            'service_charge'            => $serviceCharge,
            'price'                     => $subTotal + $serviceCharge,
            'discount'                  => $discount,
            'user_id'                   => $academyUser->user_id,
            'academy_user_id'           => $academyUser->id,
            'state'                     => 0,
            'active'                    => 1,
            'term_type'                 => $paymentType,
            'term'                      => $term,
            'start_term'                => $startTerm->toDateString(),
            'end_term'                  => $endTerm->toDateString(),
            'payment_activation'        => $now,
            'payment_due_date'          => $paymentDueDate->toDateString(),
            'payment_identifier'        => intval($now->getPreciseTimestamp(3))
        ];
        if ($academyPurchase) {
            $academyPurchase->update($data);
            return array('status' => true, 'academyPurchase' => $academyPurchase);
        }
        $academyPurchase = AcademyPurchase::updateOrCreate(
            [
                'academy_user_id'   => $academyUser->id,
                'term_type'         => $paymentType,
                'term'              => $term
            ],
            $data
        );

        $module = Module::where('route', 'academy')->first();
        $this->registerLog(Auth::user() ? Auth::user()->id : 1, 'Crear Pago Inscripción', json_encode(AcademyPurchase::with('academy_user')->find($academyPurchase->id)), "Create", $module->id);

        if ($discount == 100 || $confirmPayment) {
            $controller = new AcademyController;
            $status = $controller->changeSchedule($academyUser->id, $academyUser->academy_schedule_id);
            $status = json_decode(json_encode($status), true);
            if (!$status['original']['r']) {
                return array('status' => false, 'message' => 'El pago no se puede confirmar porque no hay cupos disponibles en el horario registrado del alumno');
            }
            $paymentTransaction = $this->createPaymentTransaction($discount, $academyUser);
            $academyPurchase->payment_transaction_id = $paymentTransaction->id;
            $academyPurchase->update();
            $this->finishPayment($paymentTransaction);
        }
        return array('status' => true, 'academyPurchase' => $academyPurchase);
    }

    public function createPaymentTransaction($discount, $academyUser)
    {
        $paymentTransaction = PaymentTransactionService::createPendingTransaction(
            get_class($this),
            null,
            $academyUser->identification
        );

        $paymentTransaction->comment = 'Pago generado automáticamente por el sistema, ' . ($discount == 100 ? '100% descuento' : 'pago confirmado desde plantilla');
        $paymentTransaction->payment_date = Carbon::now();
        $paymentTransaction->state = PaymentStatusEnum::CONFIRMED;
        $paymentTransaction->save();

        return $paymentTransaction;
    }

    public function createPaymentSchedule(
        $academyUserId,
        $academyUserPeriodId,
        $userId,
        $initMonth,
        $paymentsAmount = 1,
        $discount = null,
        $confirmPayment = false,
        $message = null,
        $schedule = null
    ) {
        $academyUser = AcademyUser::where('id', $academyUserId)->first();
        $academyCategory = null;
        if ($academyUser->academy_category_id) {
            $academyCategory = AcademyCategory::where([['id', $academyUser->academy_category_id], ['active', 1]])->first();
        }
        if (!$academyCategory) {
            return;
        }

        $academyPeriod = AcademyPeriod::where('id', $academyUserPeriodId)
            ->first();

        if (!$academyPeriod) {
            return array('status' => false, 'message' => 'El periodo seleccionado no existe o se encuentra inactivo');
        }

        if ($academyPeriod) {
            $academyUser->update(['academy_period_id' => $academyPeriod->id]);
        }

        $user = User::select('id', 'pns_id')->where('id', $academyUser->user_id)->first();

        $start_term = Carbon::now();
        $currentMonth = $start_term->month;
        if (!$initMonth) {

            // Obtener mes pendiente
            $pendingMonths = $this->getPendingMonths($academyUser->id);
            $initMonth =  max($pendingMonths[0], $academyPeriod->init_month);

            if (!($currentMonth == $academyPeriod->end_month || ($academyPeriod->init_month > $currentMonth && $academyPeriod->end_month <= 12) || $this->validateOldEnrolledUser($academyUser->id, $academyUser->type_academy))) {
                if (($start_term->day > $this->validateMaximumPaymentDayMonth($academyUser->type_academy)) && $initMonth == $currentMonth) {
                    $initMonth += 1;
                }
            }

            //se validan pagos anticipados del siguiente año
            if (($currentMonth >= $academyPeriod->end_month && $currentMonth <= 12) || ($this->academyParameterController->validateRegistrationStartDate($start_term, $academyUser->type_academy))) {
                $initMonth = $academyPeriod->init_month;
                $start_term->addYear();
            }
        } else if ($this->academyParameterController->validateRegistrationStartDate($start_term, $academyUser->type_academy) && $this->validateEnrollmentTagNextYear($academyUser->user_id) && $initMonth < $academyPeriod->end_month) {
            $start_term->addYear();
            $currentMonth = $start_term->month;
        }

        //tratar de no generar un pago posterior al "mes fin de pago"
        if (($currentMonth > $academyPeriod->end_month) && ($initMonth > $academyPeriod->end_month)) {
            return;
        }

        $serviceCharge = 0;
        $controller = new ServiceChargeController;
        if ($controller->validateServiceCharge()) {
            $request = new Request([
                'services'      => 'academy',
                'payment_types' => 'monthly',
                'categories'    => [$academyCategory->id]
            ]);
            $serviceCharge = $controller->calculateServiceCharge($request);
        }

        $start_term->day(1);
        $start_term->month($initMonth);

        $academyPurchaseSaved = null;
        $registrationEndDate = $this->academyParameterController->registrationEndDate($academyUser->type_academy);

        //Se obtiene la cantidad de meses disponibles
        $pendingMonthsToCreateNextPayment = $registrationEndDate->month - $initMonth + 1;

        $academyPeriodAux = null;

        //Se valida si existe periodo que cumpla con la cantidad de meses disponibles
        if ($academyPeriod->annual_installments > $pendingMonthsToCreateNextPayment) {

            //Se obtiene el periodo que cumpla con la cantidad de meses disponibles
            $academyPeriodAux = AcademyPeriod::where('active', true)
                ->where('init_month', '<=', $initMonth)
                ->where('end_month', '>=', $initMonth)
                ->where('annual_installments', '<=', $pendingMonthsToCreateNextPayment)
                ->orderBy('annual_installments', 'desc')
                ->first();
        }

        if ($academyPeriodAux) {
            $academyPeriod = $academyPeriodAux;
        }

        //Cantidad de meses del periodo aceptado
        $monthsAmount = $academyPeriod->annual_installments;

        //Se validan descuentos
        if (!$discount) {
            $discount = $academyPeriod->discount;
            $studentDiscount = $this->validateStudentDiscounts($academyUser->id, 'monthly');
            if ($studentDiscount) {
                $discount = $studentDiscount;
            }
        }

        $paymentsByDate = $this->academyParameterService->paymentsByDate();
        $paymentActivationDateInApp = $this->academyParameterService->paymentActivationDateInApp();
        do {
            $end_term = Carbon::parse($start_term)->addMonths($monthsAmount)->subDays(1);
            $registrationEndDate = $this->academyParameterController->registrationEndDate($academyUser->type_academy);
            if (Carbon::parse($start_term) > $registrationEndDate) {
                return;
            }
            if ($end_term > $registrationEndDate) {
                $end_term = $registrationEndDate;
            }

            $start_term_month = $start_term->locale('es')->monthName;
            $end_term_month = Carbon::parse($end_term)->locale('es')->monthName;
            if ($start_term->year == $end_term->year) {
                if (!str_contains($academyPeriod->name, $start_term->year))
                    $term = $start_term->year . ', ' . (($start_term_month == $end_term_month) ? $start_term_month : ($start_term_month . ' - ' . $end_term_month));
                else
                    $term = (($start_term_month == $end_term_month) ? $start_term_month : ($start_term_month . ' - ' . $end_term_month));
            } else {
                $term =  $start_term_month . ', ' . $start_term->year .  ' - ' . $end_term_month . ', ' . $end_term->year;
            }

            $startTermString = $start_term->toDateString();
            $endTermString = $end_term->toDateString();
            $previousPurchase = AcademyPurchase::with('payment_transaction')
                ->where('academy_user_id', $academyUserId)
                ->where('term_type', '!=', 'Inscripción')
                ->where('start_term', $startTermString)
                ->where('end_term', $endTermString)
                ->first();
            if ($previousPurchase) {
                if ($discount == 100 || $confirmPayment) {
                    if (!$previousPurchase->payment_transaction || $previousPurchase->payment_transaction->state != 'CONFIRMED') {
                        $paymentTransaction = $this->createPaymentTransaction($discount, $previousPurchase->academy_user);
                        $previousPurchase->payment_transaction_id = $paymentTransaction->id;
                        $previousPurchase->update();

                        $academyController = new AcademyController;
                        $academyController->validatePaymentStatus($previousPurchase->academy_user_id);
                    }
                }
                if ($paymentsAmount == 1)
                    // Retorna cuando encuentra que el pago que se esta tratando de generar ya existe
                    return $previousPurchase;
                else {
                    $start_term = $end_term;
                    $paymentsAmount -= 1;
                    continue;
                }
            } else if ($start_term && $end_term) {
                $paymentAvailable = $this->validatePaymentAvailableRegistrationPayment($academyUser, $start_term->toDateString(), $end_term->toDateString());
                if (!$paymentAvailable) {
                    if ($paymentsAmount == 1)
                        return;
                    else {
                        $start_term = $end_term;
                        $paymentsAmount -= 1;
                        continue;
                    }
                }
            }

            // TODO - Revisar este if porque con el manejo de los meses del siguiente año y fecha de fin inscripción, no se puede generar un pago posterior al mes de fin de pago.
            // if (Carbon::parse($end_term)->subDays(1)->year > $start_term->year) {
            //     $academyPeriodNew = AcademyPeriod::select('id')
            //         ->where('annual_installments', '<=', 12 - $start_term->month + 1)
            //         ->orderBy('annual_installments', 'DESC')->first();

            //     $this->createPaymentSchedule(
            //         $academyUserId,
            //         $academyPeriodNew->id,
            //         $userId,
            //         $initMonth,
            //         $paymentsAmount,
            //         $discount,
            //         $confirmPayment,
            //         $message,
            //         $schedule
            //     );
            //     return;
            // }
            $monthly_academy_price = $academyCategory->monthly_payment * $monthsAmount;
            $subTotal = $this->formatNumberForCurrency($monthly_academy_price * (1 - ($discount / 100)));
            if ($serviceCharge && str_contains($serviceCharge . '', '%')) {
                $serviceCharge = (floatval(str_replace('%', '', $serviceCharge)) / 100) * $subTotal;
            }
            $academyPurchase = new AcademyPurchase;
            $academyPurchase->monthly_academy_price = $monthly_academy_price;
            $academyPurchase->price_discount        = 0;
            $academyPurchase->discount              = $discount;
            $academyPurchase->subtotal              = $subTotal;
            $academyPurchase->service_charge        = !$academyPurchase->subtotal ? 0 : $this->formatNumberForCurrency($serviceCharge);
            $academyPurchase->price                 = $academyPurchase->subtotal + $academyPurchase->service_charge;
            $academyPurchase->user_id               = $academyUser->user_id;
            $academyPurchase->academy_user_id       = $academyUser->id;
            $academyPurchase->active                = 1;
            $academyPurchase->term_type             = $academyPeriod->name;
            $academyPurchase->term                  = $term;
            $academyPurchase->start_term            = Carbon::parse($start_term)->toDateString();
            $academyPurchase->end_term              = Carbon::parse($end_term)->toDateString();
            $paymentActivation                      = Carbon::now();
            if ($paymentsByDate) {
                $startTerm          = Carbon::parse($academyPurchase->start_term);
                $paymentActivation  = $startTerm->copy()->day($paymentActivationDateInApp);
            }
            $academyPurchase->payment_activation    = $paymentActivation;
            $paymentDueDate                         = $academyPurchase->end_term;
            if ($daysPaymentDueDate = $this->academyParameterController->validateEnableCollectionAdvancePayments($academyUser->type_academy)) {
                $paymentDueDate                     = Carbon::parse($start_term)->addDays($daysPaymentDueDate - 1)->toDateString();
            }
            $academyPurchase->payment_due_date      = $paymentDueDate;
            $academyPurchase->payment_identifier    = intval(\Carbon\Carbon::now()->getPreciseTimestamp(3));
            $academyPurchase->state                 = $academyPurchase->payment_due_date < $academyPurchase->payment_activation;
            $academyPurchase->save();

            $module = Module::where('route', 'academy')->first();
            $this->registerLog(Auth::user() ? Auth::user()->id : 1, 'Crear Pago Mensualidad', json_encode(AcademyPurchase::with('academy_user')->find($academyPurchase->id)), "Create", $module->id);

            if ($discount == 100 || $confirmPayment) {
                $paymentTransaction = $this->createPaymentTransaction($discount, $academyPurchase->academy_user);
                $academyPurchase->payment_transaction_id = $paymentTransaction->id;
                $academyPurchase->update();

                $academyController = new AcademyController;
                $academyController->validatePaymentStatus($academyPurchase->academy_user_id);

                if ($paymentsAmount == 1 && $discount == 100 && $initMonth < 12) {
                    $this->createPaymentSchedule(
                        $academyUserId,
                        $academyUserPeriodId,
                        $userId,
                        $initMonth + 1,
                        $paymentsAmount,
                        $discount,
                        $confirmPayment,
                        $message,
                        $schedule
                    );
                }
                if ($paymentsAmount == 1) {
                    // Retorna para evitar envio masivo de notificaciones
                    return $academyPurchase;
                }
            }

            $start_term = $end_term->addDays(1);
            if (!$academyPurchaseSaved)
                $academyPurchaseSaved = $academyPurchase;

            if ($user && $discount != 100) {
                if (!$message) {
                    $message = 'Ya puedes realizar el pago "' . $academyPurchase->term . '" del alumno ' . $academyUser->student_name . ' ' . $academyUser->student_last_name . '.';
                } else if (str_contains($message, 'notify')) {
                    $message = $this->academyParameterController->replaceWildcardsMessage($this->academyParameterController->getParametersMessage($message, true), $academyPurchase->term_type, $academyPurchase->term, $academyUser->student_name . ' ' . $academyUser->student_last_name, config('app.name'));
                }
                if ($user && $user->pns_id) {
                    $notificationsController = new NotificationsController;
                    $notificationsController->createSystemNotification($message, $user->id, $schedule);
                }
            }
            $paymentsAmount -= 1;
        } while ($start_term->year == Carbon::now()->year && $paymentsAmount > 0);

        return $academyPurchaseSaved;
    }

    public function exportTemplate()
    {
        return Excel::download(new AcademySchedulePaymentsTemplate(), 'PlantillaProgramarPagos' . '_' . time() . '.xlsx');
    }

    public function import(Request $request)
    {
        try {
            $file = new AcademySchedulePaymentsImport();
            $file->request = $request;
            Excel::import($file, $request->importSchedulePayments);
            return array('r' => true, 'd' => $file->answer, 'm' => trans('messages.academy_payments.import_successfully') . ' ' . $file->edit['creados'] . ' creados');
        } catch (Exception $e) {
            $error = [
                'function'              => 'import',
                'request'               => $request->all(),
                'message'               => $e->getMessage(),
                'getFile'               => $e->getFile(),
                'getLine'               => $e->getLine(),
            ];
            $util = new UtilController();
            $util->logFile(json_encode($error));
            return array('r' => false, 'm' => trans('messages.academy_payments.import_error') . "'" . $request->importSchedulePayments->getClientOriginalName() . "', el archivo no cumple con el formato requerido.");
        }
    }

    public function modifyStudentPaymentSchedule($id)
    {
        $academy_payment = AcademyPurchase::where('academy_user_id', $id)->with('user', 'academy_user', 'payment_transaction')->get();
        $student_info_change_payment_type = AcademyPurchase::where('academy_user_id', $id)->with('user', 'academy_user', 'payment_transaction')->first();

        $validate_monthly_payment = false;
        $paid_registration = false;
        $payment_id = $student_info_change_payment_type->payment_transaction_id;
        $cnt = 0;
        foreach ($academy_payment as $payment) {
            $cnt++;
            $payment_transaction_id = $payment->payment_transaction_id;
            $academyPurchaseId = $payment->id;
            $payments_made = AcademyPurchase::where('id', $academyPurchaseId)->with('user', 'academy_user', 'payment_transaction')->first();
            if (isset($payments_made)) {
                $transacción_id = $payments_made->payment_transaction_id;
                if (isset($transacción_id)) {
                    // Validamos el pago de la Inscripción
                    if ($payments_made->payment_transaction->state == 'CONFIRMED' && isset($payments_made->enrollment_academy_price)) {
                        $paid_registration = true;
                    }
                } else {
                    if ($paid_registration == true) {
                        if (!isset($payments_made->academy_user->payment_status)) {
                            $validate_monthly_payment = true;
                        }
                    } else {
                        if ($paid_registration == false) {
                            return array('r' => false, 'd' => null, 'm' => trans('messages.academy_purchases.tag16'));
                        }
                    }
                }

                if ($paid_registration == true) {
                    // Validacion el payment_transaction_id no sea el mismo de la Inscripción
                    if (($payment_transaction_id == null || isset($payment_transaction_id)) && $payment_id != $payment_transaction_id) {
                        if (!isset($payments_made->academy_user->payment_status)) {
                            if (!isset($payments_made->payment_transaction->state) || $payments_made->payment_transaction->state == 'PENDING') {
                                $validate_monthly_payment = true;
                            } else {
                                $validate_monthly_payment = false;
                                $this->messages = [
                                    'message'  => trans('messages.academy_purchases.tag18'),
                                    'state' => false,
                                ];
                                break;
                            }
                        } else {
                            $validate_monthly_payment = false;
                            $this->messages = [
                                'message'  => trans('messages.academy_purchases.tag18'),
                                'state' => false,
                            ];
                            break;
                        }
                    }
                }
            }
        }
        if ($validate_monthly_payment == true) {
            return array('r' => true, 'd' => $student_info_change_payment_type, 'm' => trans('messages.academy_purchases.tag17'));
        } else {
            return array('r' => false, 'd' => null, 'm' => trans('messages.academy_purchases.tag18'));
        }
    }

    public function typePaymentModifiedAndAccepted(Request $request)
    {
        try {
            $academy_user_id     = $request['id'];
            $userApp_id          = $request['userApp_id'];
            $periods_academy_new = $request['periods_academy_new'];
            $if_remove_payments  = false;

            $academy_payment = AcademyPurchase::where('academy_user_id', $academy_user_id)->with('user', 'academy_user', 'payment_transaction')->get();
            if ($academy_payment) {
                foreach ($academy_payment as $payment) {
                    if (!$payment->enrollment_academy_price) {
                        $academyPurchaseId = $payment->id;
                        $remove_payment = AcademyPurchase::find($academyPurchaseId);
                        $remove_payment->delete();
                        $if_remove_payments = true;
                    }
                }
            }
            if ($if_remove_payments == true) {
                $this->createPaymentSchedule(
                    $academy_user_id,
                    $periods_academy_new,
                    $userApp_id,
                    null,
                    null
                );
                $dataId = AcademyPurchase::latest('id')->first();
            }
            return array('r' => true, 'd' => $dataId, 'm' => __('messages.academy_purchases.tag21'));
        } catch (\Throwable $th) {
            return array('r' => false, 'd' => null, 'm' => __('messages.academy_purchases.tag22'));
        }
    }

    public function validatePayment($id)
    {
        $academyPurchase = AcademyPurchase::where('id', $id)->with('payment_transaction')->first();
        $paymentTransactionController = new PaymentTransactionController();
        $paymentTransactionController->validatePayment($academyPurchase->payment_transaction);

        return array(
            'r' => true,
            'data' => null,
            'm' => 'Se validó el pago en la pasarela de pagos'
        );
    }

    public function delete(Request $request, $id)
    {
        try {
            $payment = AcademyPurchase::with('user', 'academy_user', 'payment_transaction')->find($id);
            if (AcademyPurchase::where('id', $id)->delete()) {
                if ($payment->payment_transaction) {
                    $payment->payment_transaction->delete();
                }
                $this->registerLog(Auth::user()->id, 'Eliminar Pago Academia', json_encode($payment), "Delete", $this->getModule($request));
                return response(array("r" => true, "type" => "success", "title" => "", "m" => __('messages.deleted_successfully'), "data" => null));
            } else {
                return response(array("r" => false, "type" => "error", "title" => "Oops...", "m" => __('messages.error_removing'), "data" => null));
            }
        } catch (\Illuminate\Database\QueryException $e) {
            return response(array("r" => false, "type" => "error", "title" => "Oops...", "m" => __('messages.delete_relation_data'), "data" => null));
        }
    }

    public function createNextPayment($academyPurchase, $message = null, $schedule = null)
    {
        $endTerm        = Carbon::parse($academyPurchase->end_term);
        $startTerm      = $endTerm->month + 1;
        if ($endTerm->year > Carbon::now()->year) {
            $startTerm += 12;
        }

        $pendingMonths  = $this->getPendingMonths($academyPurchase->academy_user_id, $startTerm);
        if (!in_array($startTerm, $pendingMonths)) {
            return false;
        }

        $academyUser = AcademyUser::select('id', 'user_id', 'academy_period_id')->where('id', $academyPurchase->academy_user_id)->first();
        return $this->createPaymentSchedule(
            $academyUser->id,
            $academyUser->academy_period_id,
            $academyUser->user_id,
            $startTerm,
            1,
            null,
            false,
            $message,
            $schedule
        );
    }

    public function getPendingMonths($academyUserId, $initMonth = null)
    {
        $currentDate        = Carbon::now();
        $maximumPaymentDays = AcademyParameter::where('key', 'maximum_payment_day_month')->first()->value ?? 15;
        $dataAcademyUser    = AcademyUser::select('academy_users.type_academy', 'academy_periods.end_month')
            ->leftjoin('academy_periods', 'academy_users.academy_period_id', '=', 'academy_periods.id')
            ->where('academy_users.id', $academyUserId)
            ->first();

        if ($this->academyParameterController->validateRegistrationStartDate($currentDate, $dataAcademyUser->type_academy)) {
            $currentDate->startOfYear()->addYear();
        }

        if (!$initMonth) {
            $month              = $currentDate->month;
            $initMonth          = $currentDate->day > $maximumPaymentDays ? $month + 1 : $month;
        }

        $year               = $currentDate->year;
        $currentMonths      = [];
        $endMonth           = $dataAcademyUser->end_month ?? 12;
        if ($initMonth <= $endMonth) {
            $availableMonths    = range($initMonth, $endMonth);
        } else {
            $availableMonths    = range($initMonth, $endMonth + 12);
        }
        $purchases = AcademyPurchase::select('academy_purchases.start_term', 'academy_purchases.end_term')
            ->where('academy_purchases.academy_user_id', $academyUserId)
            ->whereNull('academy_purchases.enrollment_academy_price')
            ->whereYear('academy_purchases.start_term',  $year)
            ->join('payment_transactions', 'academy_purchases.payment_transaction_id', '=', 'payment_transactions.id')
            ->where('payment_transactions.state', 'CONFIRMED')
            ->get();

        foreach ($purchases as $purchase) {
            $startMonth     = Carbon::parse($purchase->start_term)->month;
            $endDate        = Carbon::parse($purchase->end_term);
            $currentMonths  = array_merge($currentMonths, range($startMonth, $endDate->year > $year ? $endMonth : $endDate->month));
        }


        $months = array_diff($availableMonths, $currentMonths);
        return count($months) > 0 ? array_slice($months, 0, 1) : [];
    }

    public function adjustPaymentsEnrolledStudents()
    {
        $academyUsers = AcademyUser::select('academy_users.*')->whereIn('academy_state_id', [6, 7])->get();
        foreach ($academyUsers as $academyUser) {
            $purchases = AcademyPurchase::where('academy_user_id', $academyUser->id)->whereNull('enrollment_academy_price')->get();
            if (!count($purchases)) {
                $this->createPaymentSchedule(
                    $academyUser->id,
                    $academyUser->academy_period_id,
                    $academyUser->user_id,
                    null,
                    1
                );
            } else {
                $purchases = AcademyPurchase::select('academy_purchases.*')->where('academy_user_id', $academyUser->id)->whereNull('enrollment_academy_price')
                    ->leftjoin('payment_transactions', 'payment_transactions.id', '=', 'academy_purchases.payment_transaction_id')
                    ->where(function ($q) {
                        $q->whereNotIn('payment_transactions.state', ['PENDING', 'CONFIRMED'])->orWhereNull('payment_transactions.id');
                    })
                    ->orderBy('start_term', 'ASC')
                    ->get();
                foreach ($purchases as $key => $purchase) {
                    if ($key > 0) {
                        $purchase->delete();
                    } else {
                        $purchase->update(['active' => true]);
                    }
                }
            }
        }
        return 'Proceso ejecutado, total alumnos revisados: ' . count($academyUsers);
    }

    public function validateStudentDiscounts($academyUserId, $type)
    {
        $controller = new AcademyDiscountController();
        return $controller->validateStudentDiscounts($academyUserId, $type);
    }

    public function getPayment($id)
    {
        return AcademyPurchase::with(
            'academy_user',
            'academy_user.user',
            'academy_user.academy_location',
            'academy_user.academy_location.academy_location_erp',
            'academy_user.academy_category',
            'academy_user.academy_category.academy_category_erp',
            'academy_user.academy_category.academy_location.academy_location_erp',
            'payment_transaction',
            'payment_transaction.payment_method',
            'payment_transaction.gateway_payments'
        )->find($id);
    }

    public function getSucursalForERP($id)
    {
        $sucursal       = 2;
        $payment        = AcademyPurchase::find($id);
        $users          = AcademyUser::where('user_id', $payment->user_id)->pluck('id')->toArray();
        $sucursal       += array_search($payment->academy_user_id, $users);
        if ($sucursal == 5)
            $sucursal   += 1;

        return $this->util->completeLeadingZeros($sucursal, 3);
    }

    private function validateSyncWithERPPayment($academyPurchase)
    {
        return !AcademyPurchase::select('sync_with_erp')->where('id', $academyPurchase->id)->first()->sync_with_erp;
    }

    public function saveERPLog($data, $message, $action)
    {
        $transactionId = $data;
        ErpLog::updateOrCreate(
            [
                'origin'         => 'academy',
                'transaction_id' => $transactionId,
                'resolved'       => false
            ],
            [
                'origin'         => 'academy',
                'action'         => $action,
                'origin_class'   => get_class($this),
                'data'           => $data,
                'transaction_id' => $transactionId,
                'message'        => $message,
            ]
        );
    }

    public function retrySyncERP($data, $action)
    {
        $academyPurchase = AcademyPurchase::find($data);
        $this->syncERP($academyPurchase, $action);
    }

    public function confirmSyncERP($academyPurchase)
    {
        $academyPurchase->sync_with_erp = true;
        $academyPurchase->update();
    }

    public function syncERP($academyPurchase, $action = null)
    {
        try {
            $erps = Erp::select('id', 'class')->where('active', true)->get();

            $erpSync = ErpParameter::where('key', 'academy_sync')->first();
            if (!$erpSync || $erpSync->value == 'false') {
                $this->saveERPLog($academyPurchase->id, 'Sinc ERP deshabilitada', 'syncERP');
                return;
            }

            if (!$this->validateSyncWithERPPayment($academyPurchase)) {
                return;
            }

            $erpService = new ErpService;
            foreach ($erps as $index => $erp) {
                $classPath = $erp->class;
                $ERPRepository = new $classPath($erp->id);

                $erpBaseController = new ERPBaseController;
                $erpReference = $academyPurchase->erp_reference ?? 'A' . $academyPurchase->id;

                if (
                    $academyPurchase->price < $erpBaseController->minPriceToSync($ERPRepository->erpId) ||
                    !$erpService->canSync($erpReference, $ERPRepository, 'academy_sync')
                ) {
                    return;
                }

                $previousBill = $ERPRepository->hasPreviousBill($erpReference);
                if ($previousBill['r']) {
                    $academyPurchase->erp_response = $previousBill['d'];
                    $academyPurchase->update();
                    $this->confirmSyncERP($academyPurchase);

                    if (isset($previousBill['saveLog']) && $previousBill['saveLog']) {
                        $this->saveERPLog(
                            $academyPurchase->id,
                            json_encode($previousBill['error']),
                            'createOrder'
                        );
                    }

                    continue;
                }

                $academyPurchase->erp_reference = $ERPRepository->getNextReference($erpReference);
                $academyPurchase->update();
                $erpService->synchronizing($erpReference);

                switch ($action) {
                    case 'createOrder':
                        $this->createOrderERP($academyPurchase, $ERPRepository);
                        break;
                    case 'createRC':
                        $this->createRCERP($academyPurchase, $ERPRepository);
                        break;
                    case 'createBill':
                        $this->createBillERP($academyPurchase, $ERPRepository);
                        break;
                    default:
                        $this->createThirdClientERP($academyPurchase, $ERPRepository);
                        break;
                }
            }
        } catch (Exception $e) {
            $error = [
                'message'               => $e->getMessage(),
                'getFile'               => $e->getFile(),
                'getLine'               => $e->getLine(),
            ];
            $this->saveERPLog($academyPurchase->id, json_encode($error), 'syncERP');
        }
    }

    private function createThirdClientERP($academyPurchase, $ERPRepository)
    {
        $academyUser = AcademyUser::withTrashed()
            ->with('academy_schedule')
            ->with('advisor_document_type')
            ->where('id', $academyPurchase->academy_user_id)
            ->first();

        $academyUser->address_id =  $academyUser->address_id ?? $ERPRepository->getDefaultAddress($academyUser->user_id);
        $academyUser->update();

        $addressObj = Address::with('city')->find($academyUser->address_id);
        $address   = $addressObj->direction . ' | ' . $addressObj->district;
        $shortAddress  = $addressObj->direction;
        $country    = $addressObj->city ? $addressObj->city->state->country->name : null;
        $province   = $addressObj->city ? $addressObj->city->state->name : null;
        $city       = $addressObj->city ? $addressObj->city->name : null;

        $juricalPerson = $academyUser->type_person == 'JURIDICAL_PERSON';
        $thirdDocument = $juricalPerson ? $academyUser->advisor_nit : $academyUser->advisor_identification;

        $params = new \stdClass();
        $third  = new \stdClass();
        $client = new \stdClass();

        $third->document        = $thirdDocument;
        $third->firstName       = $academyUser->advisor_name;
        $third->lastName        = $academyUser->advisor_last_name;
        $third->contact         = $academyUser->advisor_last_name . ' ' . $academyUser->advisor_name;
        $third->phone           = $academyUser->phone;
        $third->email           = $academyUser->mail;
        $third->documentType    = $ERPRepository->mapDocumentType($juricalPerson ? 'nit' : $academyUser->advisor_document_type->alias);
        $third->birthDate       = Carbon::parse($academyUser->created_at)->format('Ymd');
        $third->typeThird       = $academyUser->type_person;
        $third->gender          = '0';
        $third->socialReason        = $juricalPerson ? $academyUser->advisor_business_name : $third->contact;
        $third->establishmentName   = $juricalPerson ? $academyUser->advisor_property_name : $third->contact;
        $third->ciiu                =  $juricalPerson ? $academyUser->advisor_isic_code : null;

        $client->document       = $academyUser->identification;
        $client->contact        = $academyUser->student_last_name . ' ' . $academyUser->student_name;
        $client->phone          = $academyUser->phone;
        $client->email          = $academyUser->mail;

        $params->third          = $third;
        $params->client         = $client;
        $params->address        = str_replace('#', 'N', $address);
        $params->shortAddress   = str_replace('#', 'N', $shortAddress);
        $params->country        = $country;
        $params->province       = $province;
        $params->city           = $city;
        $params->sucursal       = $this->getSucursalForERP($academyPurchase->id);
        $params->price_list     = $academyUser->academy_schedule ? $academyUser->academy_schedule->academy_categories_schedules[0]->academy_category->academy_location->price_list : '';
        $params->typeClient     = 'CACD';
        $params->postal         = '';
        $params->hasTaxes       = '1';
        $params->createThirdPos = true;
        $params->idCriteria     = '101';
        $params->criteria       = '1012';
        $params->currency       = 'COP';
        $params->latitude       = $addressObj ? $addressObj->lat : null;
        $params->longitude       = $addressObj ? $addressObj->long : null;

        $response = $ERPRepository->createThirdClient($params);
        if (!$response['r']) {
            $this->saveERPLog($academyPurchase->id, json_encode($response['d']), 'createThirdClient');
            return;
        }
        $this->createOrderERP($academyPurchase, $ERPRepository);
    }

    private function createOrderERP($academyPurchase, $ERPRepository)
    {
        $paymentDetail = $this->getPayment($academyPurchase->id);
        $hasPreviousOrder = $ERPRepository->hasPreviousOrder(
            $academyPurchase->erp_reference,
            $paymentDetail->payment_transaction->reference,
            $paymentDetail->payment_transaction->gateway_transaction_id
        );

        if ($hasPreviousOrder) {
            $this->createRCERP($academyPurchase, $ERPRepository);
            return;
        }

        $academyUser = $paymentDetail->academy_user;
        if (!$academyUser->academy_category) {
            $this->saveERPLog(
                $academyPurchase->id,
                'El deportista ' . $academyUser->student_name . ' ' . $academyUser->student_last_name . ' no tiene categoria asignada',
                'createOrder'
            );
            return;
        }

        $academyCategoryErp = $paymentDetail->academy_user->academy_category->academy_category_erp;
        $academyLocationErp = $paymentDetail->academy_user->academy_category->academy_location->academy_location_erp;
        $paymentTransaction = $academyPurchase->payment_transaction;

        if (!$academyCategoryErp) {
            $this->saveERPLog(
                $academyPurchase->id,
                'La categería (' . $paymentDetail->academy_user->academy_category->name . ') no tiene código de servicio configurado',
                'createOrder'
            );
            return;
        }

        $serviceCode = $paymentDetail->enrollment_academy_price ? $academyCategoryErp->registration_service_item_code : $academyCategoryErp->pension_service_item_code;
        if ($paymentDetail->monthly_academy_price && $paymentDetail->academy_user->academy_period) {
            $academyPeriod = $paymentDetail->academy_user->academy_period;
            $academyPeriodErp = $academyPeriod->academy_period_erp;
            if (count($academyPeriodErp)) {
                if ($academyPeriod->annual_installments > 1) {
                    $serviceCode = $academyPeriodErp[0]->service_item_code;
                } else {
                    if (Carbon::parse($paymentTransaction->payment_date) < Carbon::parse($academyPurchase->start_term)) {
                        $serviceCode = $academyPeriodErp[0]->service_item_code;
                    }
                }
            }
        }

        $academyUser = $paymentDetail->academy_user;
        $juricalPerson = $academyUser->type_person == 'JURIDICAL_PERSON';
        $addressObj = Address::with('city')->where('id', $academyUser->address_id)->first();
        $operationCenter = $academyLocationErp->operation_center ?? null;
        $costCenter = $academyCategoryErp->cost_center ?? null;

        $third                  = new \stdClass();
        $third->firstName       = $academyUser->advisor_name;
        $third->lastName        = $academyUser->advisor_last_name;
        $third->contact         = $academyUser->advisor_last_name . ' ' . $academyUser->advisor_name;
        $third->phone           = $academyUser->phone;
        $third->email           = $academyUser->mail;
        $third->documentType    = $ERPRepository->mapDocumentTypeOrder($juricalPerson ? 'nit' : $academyUser->advisor_document_type->alias);
        $third->document         = $juricalPerson ? $academyUser->advisor_nit : $academyUser->advisor_identification;

        $orderParams                    = new \stdClass();
        $orderParams->operationCenter   = $operationCenter;
        $orderParams->document          = $third->document;
        $orderParams->sucursal          = $this->getSucursalForERP($academyPurchase->id);
        $orderParams->costCenter        = $costCenter;
        $orderParams->date              = Carbon::now()->format('Ymd');
        $orderParams->customerType      = 'CACD';
        $orderParams->note              = $paymentDetail->payment_transaction->reference . ' - ' . $academyPurchase->term_type . ' - ' . $academyPurchase->term;
        $orderParams->reference         = $academyPurchase->erp_reference;
        $orderParams->numeroPedido      = $academyPurchase->id;
        $orderParams->third             = $third;
        $orderParams->transaction       = $paymentDetail->payment_transaction;
        $orderParams->address           = $addressObj;

        $itemParams                     = new \stdClass();
        $itemParams->operation_center   = $operationCenter;
        $itemParams->serviceCode        = $serviceCode;
        $itemParams->warehouse          = 'AC' . $operationCenter;
        $itemParams->cost_center        = $costCenter;
        $itemParams->date               = $orderParams->date;
        $itemParams->price_list         = $academyLocationErp->price_list ?? null;
        $itemParams->price              = $paymentDetail->price; //Pago total incluido descuentos
        $itemParams->fullPrice          = $academyPurchase->monthly_academy_price ?? $academyPurchase->enrollment_academy_price;
        $itemParams->discount           = 0;

        $discounts = [];
        if ($paymentDetail->discount > 0 && $academyLocationErp) {
            $discount = array(
                'f430_id_co'                => $academyLocationErp->operation_center,
                'f430_consec_docto'         => '1',
                'f431_nro_registro'         => '1',
                'f432_tasa'                 => $paymentDetail->discount,
                'f432_vlr_uni'              => 0,
            );
            array_push($discounts, $discount);
            $itemParams->discount += $this->formatNumberForCurrency(($itemParams->price * $paymentDetail->discount) / 100);
        }

        if ($paymentDetail->price_discount > 0 && $academyLocationErp) {
            $discount = array(
                'f430_id_co'                => $academyLocationErp->operation_center,
                'f430_consec_docto'         => '1',
                'f431_nro_registro'         => '1',
                'f432_tasa'                 => 0,
                'f432_vlr_uni'              => $paymentDetail->price_discount,
            );

            array_push($discounts, $discount);
            $itemParams->discount += $paymentDetail->price_discount;
        }

        $orderParams->discounts = $discounts;
        $orderParams->items = [$ERPRepository->generateOrderItem($itemParams)];

        $response = $ERPRepository->createOrder($orderParams);
        if (!$response['r']) {
            $this->saveERPLog($academyPurchase->id, json_encode($response['d']), 'createOrder');
            return;
        }

        $academyPurchase->erp_response = is_string($response['d']) ? $response['d'] : null;
        $academyPurchase->update();

        if (isset($response['saveLog']) && $response['saveLog']) {
            $this->saveERPLog(
                $academyPurchase->id,
                json_encode($response['error']),
                'createOrder'
            );
        }

        $this->createRCERP($academyPurchase, $ERPRepository);
    }

    private function createRCERP($academyPurchase, $ERPRepository)
    {
        $erpBaseController = new ERPBaseController;
        if (!$erpBaseController->syncRcEnabled($ERPRepository->erpId)) {
            $this->createBillERP($academyPurchase, $ERPRepository);
            return;
        }

        $paymentTransaction = $academyPurchase->payment_transaction;
        $response = $ERPRepository->getOrder('A' . $academyPurchase->id);
        if (!$response['r']) {
            $this->saveERPLog($academyPurchase->id, json_encode($response['d']), 'createRC');
            return;
        }

        $paymentMethod = PaymentMethod::select('code')->where('id', $paymentTransaction->payment_method_id)->first();
        foreach ($response['d']->detalle->Table as $index => $siesaOrder) {
            $paymentDetail = $this->getPayment($academyPurchase->id);
            $academyUser = $paymentDetail->academy_user;
            $response = $ERPRepository->getRC($academyUser->advisor_identification, $siesaOrder->CentroDeOperacion);
            if ($response['r']) {
                $previousRC = array_filter($response['d']->detalle->Table, function ($item) use ($paymentTransaction, $paymentDetail) {
                    return str_contains($item->Notas, $paymentTransaction->reference) && $item->TotalRecibo == $paymentDetail->price;
                }, ARRAY_FILTER_USE_BOTH);

                if (count($previousRC)) {
                    $this->createBillERP($academyPurchase, $ERPRepository);
                    continue;
                }
            }

            $juricalPerson = $academyUser->type_person == 'JURIDICAL_PERSON';

            $parameters = new \stdClass();
            $parameters->paymentDate = Carbon::parse($paymentTransaction->payment_date)->format('Ymd');
            $parameters->idThird = $juricalPerson ? $academyUser->advisor_nit : $academyUser->advisor_identification;
            $parameters->currency = 'COP';
            $parameters->siesaOrder = $siesaOrder;
            $parameters->fe = '1105';
            $parameters->note = $paymentTransaction->reference . ' - ' . $academyPurchase->term_type . ' - ' . $academyPurchase->term;
            $parameters->assistant = '28050502';
            $parameters->sucursal = $this->getSucursalForERP($academyPurchase->id);
            $parameters->paymetMethod = $paymentMethod ?  $paymentMethod->code : 'WAC';
            $parameters->UN = '100';
            $parameters->price = $paymentDetail->price;

            $response = $ERPRepository->createRC($parameters);
            if (!$response['r']) {
                $this->saveERPLog($academyPurchase->id, json_encode($response['d']), 'createRC');
                return;
            }
            $this->createBillERP($academyPurchase, $ERPRepository);
        }
    }

    private function createBillERP($academyPurchase, $ERPRepository)
    {
        $erpBaseController = new ERPBaseController;
        if (!$erpBaseController->syncBillEnabled($ERPRepository->erpId)) {
            $this->confirmSyncERP($academyPurchase);
            return;
        }

        $response = $ERPRepository->getOrder('A' . $academyPurchase->id);
        if (!$response['r']) {
            $this->saveERPLog($academyPurchase->id, json_encode($response['d']), 'createBill');
            return;
        }

        $paymentTransaction = $academyPurchase->payment_transaction;
        $paymentDetail = $this->getPayment($academyPurchase->id);
        $academyUser = $paymentDetail->academy_user;
        $juricalPerson = $academyUser->type_person == 'JURIDICAL_PERSON';

        foreach ($response['d']->detalle->Table as $index => $siesaOrder) {
            $parameters = new \stdClass();
            $parameters->siesaOrder     = $siesaOrder;
            $parameters->thirdDocument  = $juricalPerson ? $academyUser->advisor_nit : $academyUser->advisor_identification;
            $parameters->note           = $paymentTransaction->reference;
            $parameters->price          = $paymentDetail->price;
            $parameters->typeDocument   = 'FE1';

            $response = $ERPRepository->createBill($parameters);
            if (!$response['r']) {
                $this->saveERPLog($academyPurchase->id, json_encode($response['d']), 'createBill');
                return;
            }
        }
        $this->confirmSyncERP($academyPurchase);
    }

    private function validatePaymentAvailableRegistrationPayment($academyUser, $start_term, $end_term)
    {
        return AcademyPurchase::join('payment_transactions', 'academy_purchases.payment_transaction_id', '=', 'payment_transactions.id')
            ->where('payment_transactions.state', 'CONFIRMED')
            ->where('academy_purchases.academy_user_id', $academyUser->id)
            ->whereNotNull('academy_purchases.enrollment_academy_price')
            ->whereDate('academy_purchases.start_term', '<=', $start_term)
            ->whereDate('academy_purchases.end_term', '>=', $end_term)
            ->first();
    }

    public function createEnrollmentTag($academyPurchase, $year)
    {
        $tag = $this->validateTag('Inscrito_academia_' . $year);
        UserTag::updateOrCreate(
            ['tag_id' => $tag->id, 'user_id' => $academyPurchase->user_id, 'academy_user_id' => $academyPurchase->academy_user_id],
            ['tag_id' => $tag->id, 'user_id' => $academyPurchase->user_id, 'academy_user_id' => $academyPurchase->academy_user_id]
        );
    }

    private function validateEnrollmentTagNextYear($userId)
    {
        $year = date('Y');
        $year += 1;
        $tag = $this->validateTag('Inscrito_academia_' . $year);
        return UserTag::where([['user_id', $userId], ['tag_id', $tag->id]])->first();
    }

    public function validateEnrollmentTagYear($userId, $year)
    {
        $tag = $this->validateTag('Inscrito_academia_' . $year);
        return UserTag::where([['user_id', $userId], ['tag_id', $tag->id]])->first();
    }

    private function validateTag($nameTag)
    {
        $tag = Tag::where('name', '=', $nameTag)->first();
        if (!$tag) {
            $tag = Tag::create(['name' => $nameTag, 'description' => $nameTag]);
        }
        return $tag;
    }

    public function validateStudentsWithoutRegistrationPaymentGenerated($academyUserId = null)
    {
        $date = Carbon::now();
        $year = $date->year;

        //Obtener alumnos sin pagos en el año actual
        $users = AcademyUser::select('id')->where('academy_state_id', 5)
            ->whereNull('deleted_at')
            ->whereNotIn('id', function ($query) use ($year) {
                $query->select('academy_user_id')
                    ->from('academy_purchases')
                    ->where('term', 'like', "{$year}%")
                    ->where('term_type', 'Inscripción')
                    ->whereNull('deleted_at');
            })
            ->groupBy('id')
            ->get();

        foreach ($users as $student) {
            $academyUser = AcademyUser::find($student->id);
            $this->createEnrollmentPayment(
                $academyUser,
                0,
                'Inscripción'
            );
        }
    }

    private function validateOldEnrolledUser($academyUserId, $typeAcademy = 'children')
    {
        $oldEnrollmentUser = false;
        if (
            $this->academyParameterController->getParametersValueByTypeAcademy('enable_registration_renewal', $typeAcademy) == 'false' &&
            $this->academyParameterController->getParametersValueByTypeAcademy('enable_first_month_renewal_payment_for_children', $typeAcademy) == 'true'
        ) {
            $validOldEnrollmentUser = AcademyPurchase::select('academy_purchases.id')
                ->join('payment_transactions', 'payment_transactions.id', '=', 'academy_purchases.payment_transaction_id')
                ->where('academy_purchases.academy_user_id', $academyUserId)
                ->whereNull('academy_purchases.deleted_at')->whereNotNull('academy_purchases.enrollment_academy_price')->where('academy_purchases.term', Carbon::now()->subYear(1)->year)
                ->where('payment_transactions.state', 'CONFIRMED')
                ->first();
            if ($validOldEnrollmentUser)
                $oldEnrollmentUser = true;
        }
        return $oldEnrollmentUser;
    }

    private function validateMaximumPaymentDayMonth($typeAcademy = 'children')
    {
        $day = 15;
        if ($academyParameter = $this->academyParameterController->getParametersValueByTypeAcademy('maximum_payment_day_month', $typeAcademy)) {
            $day = $academyParameter;
        }
        return $day;
    }

    private function tableFilterQuery($request)
    {
        $states = $request->states;
        $types = $request->types;
        $duePayments = $request->duePayments;
        $from_term = $request->from_term;
        $to_term = $request->to_term;
        $from_date = $request->from_date;
        $to_date = $request->to_date;
        $type_academy = $request->type_academy;
        $franchises = $request->franchises;

        DB::statement("SET sql_mode = ''");
        $query = DB::table('academy_purchases')
            ->select(
                'academy_purchases.id',
                'academy_user.id AS academy_user.id',
                'academy_user.student_name AS academy_user.student_name',
                'academy_user.student_last_name AS academy_user.student_last_name',
                'academy_user.identification AS academy_user.identification',
                'academy_user.student_academy_code AS academy_user.student_academy_code',
                'academy_state.name AS academy_state.name',
                'academy_state.color AS academy_state.color',
                'academy_locations.name AS locationName',
                'academy_categories.name AS categoryName',
                'academy_schedules.name AS scheduleName',
                'appUser.first_name AS academy_user.user.first_name',
                'appUser.last_name AS academy_user.user.last_name',
                'appUser.email AS academy_user.user.email',
                'academy_user.advisor_name AS academy_user.advisor_name',
                'academy_user.advisor_last_name AS academy_user.advisor_last_name',
                'academy_user.advisor_identification AS advisor_identification',
                DB::raw('GROUP_CONCAT(DISTINCT(tags.name)) AS segmentation'),
                DB::raw('IF(academy_purchases.state = 1, "SI", "NO") AS duePayment'),
                'academy_purchases.term_type',
                'academy_purchases.term',
                'academy_purchases.start_term',
                'academy_purchases.end_term',
                'academy_purchases.payment_activation',
                'academy_purchases.payment_due_date',
                'academy_purchases.enrollment_academy_price',
                'academy_purchases.monthly_academy_price',
                'academy_purchases.price_discount',
                'academy_purchases.discount',
                'academy_purchases.subtotal',
                'academy_purchases.service_charge',
                'academy_purchases.price',
                'payment_transactions.reference',
                DB::raw('MD5(payment_transactions.reference) AS hashed_reference'),
                'payment_transactions.gateway_transaction_id',
                'payment_transactions.state',
                'payment_transactions.comment',
                'payment_methods.name AS payment_method',
                'payment_transactions.support',
                'academy_user.birthdate',
                'document_types.name AS studentDocumentType',
                DB::raw('IF(payment_transactions.state = "CONFIRMED",payment_transactions.payment_date,"") AS payment_date'),
                'gateway_payments.name AS gateway_payments_name',
                DB::raw("GROUP_CONCAT(DISTINCT(CONCAT_WS(' ', users1.first_name, users1.last_name, CONCAT('(',users1.email,')'))) ORDER BY users1.id ASC) AS coaches"),
                'academy_purchases.sync_with_erp',
                'academy_purchases.erp_response',
                'academy_purchases.erp_reference'
            )
            ->leftjoin('payment_transactions', 'academy_purchases.payment_transaction_id', '=', 'payment_transactions.id')
            ->leftjoin('payment_methods', 'payment_methods.id', '=', 'payment_transactions.payment_method_id')
            ->join('academy_users AS academy_user', function ($join) {
                $join->on('academy_purchases.academy_user_id', '=', 'academy_user.id')
                    ->whereNull('academy_user.deleted_at');
            })
            ->join('document_types', 'document_types.id', '=', 'academy_user.student_document_type_id')
            ->leftjoin('academy_states AS academy_state', 'academy_state.id', '=', 'academy_user.academy_state_id')
            ->leftjoin('academy_categories', 'academy_categories.id', '=', 'academy_user.academy_category_id')
            ->leftjoin('academy_schedules', 'academy_schedules.id', '=', 'academy_user.academy_schedule_id')
            ->leftjoin('academy_schedules_coaches', 'academy_schedules_coaches.academy_schedule_id', '=', 'academy_schedules.id')
            ->leftjoin('users AS users1', 'users1.id', '=', 'academy_schedules_coaches.user_id')->whereNull('users1.deleted_at')
            ->leftjoin('academy_locations', 'academy_locations.id', '=', 'academy_categories.academy_location_id')
            ->leftjoin('users AS appUser', 'academy_user.user_id', '=', 'appUser.id')
            ->leftjoin('user_tags', 'appUser.id', '=', 'user_tags.user_id')
            ->leftjoin('tags', function ($join) {
                $join->on('tags.id', '=', 'user_tags.tag_id')->where('tags.active', 1);
            })
            ->leftjoin('gateway_payments', 'gateway_payments.id', '=', 'payment_transactions.gateway_payments_id')
            ->where([['academy_user.type_academy', $type_academy], ['academy_purchases.active', 1]])
            ->whereNull('academy_purchases.deleted_at')
            ->groupBy('academy_purchases.id');

        //new filters
        $academyLocationsService = new AcademyLocationsService;
        if (!$academyLocationsService->validateAuthorizedLocations()) {
            $authorizedLocations = $academyLocationsService->getAuthorizedLocations();
            $query->whereIn('academy_locations.id', $authorizedLocations);
        }

        if ($request['categories'] || $request['locations']) {

            $query->join('academy_categories_schedules as acs_filter', 'acs_filter.academy_schedule_id', '=', 'academy_schedules.id');

            if ($request['locations']) {
                $query->join('academy_categories as ac_filter_category', 'ac_filter_category.id', '=', 'acs_filter.academy_category_id')
                    ->whereIn('ac_filter_category.academy_location_id', $request['locations'])
                    ->whereIn('academy_categories.academy_location_id', $request['locations']);
            }
            if ($request['categories']) {
                $query->whereIn('acs_filter.academy_category_id', $request['categories']);
                //   ->whereIn('academy_categories_schedules.academy_category_id', $request['categories']);
            }
        }

        if ($request['schedules']) {
            $query->join('academy_schedules_coaches as asc_filter', 'asc_filter.academy_schedule_id', '=', 'academy_schedules.id')
                ->whereIn('asc_filter.academy_schedule_id', $request['schedules']);
        }

        if ($request['coaches']) {
            $query->join('academy_schedules_coaches as asc_main', 'asc_main.academy_schedule_id', '=', 'academy_schedules.id')
                ->whereIn('asc_main.user_id', $request['coaches']);
        }
        //end new filters

        if ($states && $states != 'null') {
            $options = $states;
            $states = [];
            $emptyOption = false;

            $query->where(function ($q) use ($options, &$states, &$emptyOption) {
                foreach ($options as $option) {
                    if ($option == 'Vacio') {
                        $q->whereNull('academy_purchases.payment_transaction_id');
                        $emptyOption = true;
                    } else {
                        $states[] = $option;
                    }
                }

                if (!empty($states)) {
                    if ($emptyOption) {
                        $q->orWhereIn('payment_transactions.state', $states);
                    } else {
                        $q->whereIn('payment_transactions.state', $states);
                    }
                }
            });
        }

        if ($types && $types != 'null') {
            $query->whereIn('academy_purchases.term_type', $types);
        }

        if ($duePayments && $duePayments != 'null') {
            $duePayments = str_replace('SI', 1, $duePayments);
            $duePayments = str_replace('NO', 0, $duePayments);
            $query->whereIn('academy_purchases.state', $duePayments);
        }

        if ($from_term && $from_term != 'null') {
            $query->whereDate('academy_purchases.start_term', '>=', $from_term);
        }

        if ($to_term && $to_term != 'null') {
            $query->whereDate('academy_purchases.end_term', '<=', $to_term);
        }

        if ($from_date && $from_date != 'null') {
            $query->whereDate('payment_transactions.payment_date', '>=', $from_date);
        }

        if ($to_date && $to_date != 'null') {
            $query->whereDate('payment_transactions.payment_date', '<=', $to_date);
        }

        DB::statement("SET sql_mode = 'STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION'");
        return $query;
    }

    private function tableFilterCustomColumns($dataTable)
    {
        $dataTable->addColumn('actions', function ($obj) {
            if (
                $this->validateRolePermissions('academy', 'administrator') ||
                $this->validateRolePermissions('academy', 'supervisor')
            ) {
                $actions = '<i class="fa fa-pencil iconMini" onClick="clickEditPayment(' . $obj->id . ')" data-id="' . $obj->id . '" title="Editar Pago"></i>';
                $hideDeletePayment = $obj->state && $obj->state == 'CONFIRMED' && $obj->gateway_transaction_id && Auth::user()->rol_id != $this->__SUPERADMIN_ROL;
                if (!$hideDeletePayment) {
                    $actions .= '<i class="fa fa-trash iconMini" onClick="clickDelete(' . $obj->id . ')" data-id="' . $obj->id . '" title="Eliminar"></i>';
                }
                if (!$obj->state || (!$obj->support && $obj->state != 'CONFIRMED')) {
                    $actions .= '<i class="fa fa-money iconMini" onClick="clickPay(' . $obj->id . ')" data-id="' . $obj->id . '" title="Cargar Pago"></i>';
                }
                if ($obj->state && $obj->support && $obj->state != 'CONFIRMED') {
                    $actions .= '<i class="fa fa-check iconMini" onClick="clickValidatePay(' . $obj->id . ')" data-id="' . $obj->id . '" title="Validar Pago"></i>';
                }
                if ($obj->state && $obj->state != 'CONFIRMED') {
                    $actions .= '<i class="fa fa-credit-card iconMini" onClick="clickValidatePaymentInGateway(' . $obj->id . ')" data-id="' . $obj->id . '" title="Validar en pasarela"></i>';
                }

                // if ($obj->state && $obj->state == 'CONFIRMED' && $obj->sync_with_erp) {
                //     $actions .= '<button type="button" class="btn btn-primary btn-xs" onClick="openCreditNote(' . $obj->id . ')"> <i class="fa fa-dollar"></i> ' . trans('messages.erp.credit_note') . '</button>';
                // }

                return $actions;
            } else {
                return '';
            }
        })
            ->addColumn('pending', function ($obj) {
                return $obj->state && $obj->support && $obj->state != 'CONFIRMED';
            })
            ->editColumn('state', function ($obj) {
                return '<span class="label ' . ($obj->state == 'CONFIRMED' ? 'label-success' : 'label-danger') . '">' . $obj->state . '</span>';
            })
            ->editColumn('payment_date', function ($obj) {
                return $obj->payment_date ? Carbon::parse($obj->payment_date)->format('Y-m-d h:i:s A') : '';
            })
            ->rawColumns(['actions', 'state', 'payment_date']);
    }
}