Proyectos de Subversion LeadersLinked - Backend

Rev

Rev 17347 | Mostrar el archivo completo | | | Autoría | Ultima modificación | Ver Log |

Rev 17347 Rev 17350
Línea 2493... Línea 2493...
2493
            ]);
2493
            ]);
2494
        }
2494
        }
2495
    }
2495
    }
Línea -... Línea 2496...
-
 
2496
    
-
 
2497
    
-
 
2498
    /**
-
 
2499
     * Acción para mostrar el progreso de microlearning de un estudiante específico por tópicos
-
 
2500
     * 
-
 
2501
     * Este método muestra el progreso del estudiante agrupado por tópicos, donde cada tópico
-
 
2502
     * contiene múltiples cápsulas. Se calcula el progreso agregado por tópico basado en
-
 
2503
     * las cápsulas completadas vs. el total de cápsulas asignadas.
-
 
2504
     * 
-
 
2505
     * Este método maneja dos tipos de respuesta:
-
 
2506
     * - Respuesta JSON: Retorna datos del progreso por tópico en formato JSON para AJAX
-
 
2507
     * - Respuesta HTML: Retorna la vista del formulario de reporte de estudiante
-
 
2508
     * 
2496
    
2509
     * @return JsonModel|ViewModel Respuesta en formato JSON o vista HTML
2497
    
2510
     */
-
 
2511
    public function progressForStudentAction()
2498
    public function progressForStudentAction()
2512
    {
2499
    {
2513
        // Obtener información del usuario actual y su empresa
2500
        $currentUserPlugin = $this->plugin('currentUserPlugin');
2514
        $currentUserPlugin = $this->plugin('currentUserPlugin');
Línea 2501... Línea 2515...
2501
        $currentUser = $currentUserPlugin->getUser();
2515
        $currentUser = $currentUserPlugin->getUser();
Línea -... Línea 2516...
-
 
2516
        $currentCompany = $currentUserPlugin->getCompany();
2502
        $currentCompany = $currentUserPlugin->getCompany();
2517
        
2503
        
2518
        $request = $this->getRequest();
2504
        $request = $this->getRequest();
-
 
-
 
2519
        
2505
        
2520
        // Solo procesar peticiones GET
Línea -... Línea 2521...
-
 
2521
        if($request->isGet())
2506
        if($request->isGet())
2522
        {
2507
        {
2523
            // Obtener headers de la petición para determinar el tipo de respuesta
2508
            
2524
            $headers  = $request->getHeaders();
2509
            $headers  = $request->getHeaders();
-
 
2510
            
2525
            
Línea -... Línea 2526...
-
 
2526
            // Verificar si la petición espera una respuesta JSON
2511
            $isJson = false;
2527
            $isJson = false;
2512
            if($headers->has('Accept')) {
2528
            if($headers->has('Accept')) {
Línea -... Línea 2529...
-
 
2529
                $accept = $headers->get('Accept');
2513
                $accept = $headers->get('Accept');
2530
                $prioritized = $accept->getPrioritized();
2514
                
2531
                
2515
                $prioritized = $accept->getPrioritized();
2532
                // Iterar sobre los tipos de contenido aceptados
2516
                
-
 
2517
                foreach($prioritized as $key => $value) {
2533
                foreach($prioritized as $key => $value) {
2518
                    $raw = trim($value->getRaw());
2534
                    $raw = trim($value->getRaw());
Línea 2519... Línea -...
2519
                    
-
 
-
 
2535
                    
2520
                    if(!$isJson) {
2536
                    // Verificar si se solicita JSON
2521
                        $isJson = strpos($raw, 'json');
-
 
-
 
2537
                    if(!$isJson) {
2522
                    }
2538
                        $isJson = strpos($raw, 'json');
2523
                    
2539
                    }
Línea -... Línea 2540...
-
 
2540
                }
2524
                }
2541
            }
Línea -... Línea 2542...
-
 
2542
            
2525
            }
2543
            // Procesamiento para respuesta JSON (peticiones AJAX)
2526
            
2544
            if($isJson) {
Línea 2527... Línea -...
2527
            
-
 
-
 
2545
                // Verificar permisos ACL para descarga de Excel
2528
            if($isJson) {
2546
                $acl = $this->getEvent()->getViewModel()->getVariable('acl');
2529
                
2547
                $allowDownload = $acl->isAllowed($currentUser->usertype_id, 'microlearning/reports/progress-for-student/excel');
2530
                $acl = $this->getEvent()->getViewModel()->getVariable('acl');
2548
 
2531
                $allowDownload = $acl->isAllowed($currentUser->usertype_id, 'microlearning/reports/progress-for-student/excel');
2549
                // Obtener y sanitizar el UUID del estudiante desde query parameters
2532
 
2550
                $student_uuid = Functions::sanitizeFilterString($this->params()->fromQuery('student_uuid'));
2533
                $student_uuid     = Functions::sanitizeFilterString($this->params()->fromQuery('student_uuid'));
2551
                
Línea 2534... Línea -...
2534
                
-
 
-
 
2552
                // Buscar el usuario por UUID y red
2535
                $userMapper = UserMapper::getInstance($this->adapter);
2553
                $userMapper = UserMapper::getInstance($this->adapter);
2536
                $user = $userMapper->fetchOneByUuidAndNetworkId($student_uuid, $currentUser->network_id);
2554
                $user = $userMapper->fetchOneByUuidAndNetworkId($student_uuid, $currentUser->network_id);
Línea 2537... Línea -...
2537
                
-
 
-
 
2555
                
2538
                
2556
                // Validar que el usuario existe
2539
                if(!$user) {
2557
                if(!$user) {
2540
                    return new JsonModel([
2558
                    return new JsonModel([
2541
                        'success' => false,
2559
                        'success' => false,
2542
                        'data' => 'ERROR_USER_NOT_FOUND'
2560
                        'data' => 'ERROR_USER_NOT_FOUND'
2543
                    ]);
2561
                    ]);
Línea 2544... Línea -...
2544
                }
-
 
-
 
2562
                }
2545
                
2563
                
2546
                
2564
                // Verificar que el usuario tiene acceso a cápsulas de microlearning de la empresa
2547
                $microlearningCapsuleUserMapper = MicrolearningCapsuleUserMapper::getInstance($this->adapter);
2565
                $microlearningCapsuleUserMapper = MicrolearningCapsuleUserMapper::getInstance($this->adapter);
Línea 2548... Línea -...
2548
                $count = $microlearningCapsuleUserMapper->fetchCountByCompanyIdAndUserId($currentCompany->id, $user->id);
-
 
-
 
2566
                $count = $microlearningCapsuleUserMapper->fetchCountByCompanyIdAndUserId($currentCompany->id, $user->id);
2549
                
2567
                
2550
 
2568
                // Si no tiene acceso, retornar error de autorización
2551
                if(!$count) {
2569
                if(!$count) {
2552
                    return new JsonModel([
2570
                    return new JsonModel([
2553
                        'success' => false,
2571
                        'success' => false,
-
 
2572
                        'data' => 'ERROR_UNAUTHORIZED'
2554
                        'data' => 'ERROR_UNAUTHORIZED'
2573
                    ]);
2555
                    ]);
-
 
2556
                }
2574
                }
2557
                
2575
                
-
 
2576
                // Inicializar estructura de datos de respuesta
2558
                
2577
                $data = [
Línea -... Línea 2578...
-
 
2578
                    'items' => [],
2559
                $data = [
2579
                ];
2560
                    'items' => [],
2580
                
2561
                ];
2581
                // Primera consulta: Obtener todos los tópicos asignados al usuario
2562
                
2582
                $queryMapper = QueryMapper::getInstance($this->adapter);
2563
                
2583
                $sql = $queryMapper->getSql();
Línea 2564... Línea -...
2564
                $queryMapper = QueryMapper::getInstance($this->adapter);
-
 
-
 
2584
                $select = $sql->select();
2565
                $sql = $queryMapper->getSql();
2585
                $select->columns(['topic_id', 'access', 'paid_from', 'paid_to' ]);
2566
                $select = $sql->select();
2586
                $select->from(['tb1' => MicrolearningTopicUserMapper::_TABLE] );
2567
                $select->columns(['capsule_id', 'access', 'paid_from', 'paid_to' ]);
2587
                // Join con tabla de tópicos para obtener el nombre del tópico
2568
                $select->from(['tb1' => MicrolearningCapsuleUserMapper::_TABLE] );
2588
                $select->join(['tb2' => MicrolearningTopicMapper::_TABLE], 'tb1.company_id = tb2.company_id AND tb1.topic_id = tb2.id', ['topic' => 'name']);
2569
                $select->join(['tb2' => MicrolearningTopicMapper::_TABLE], 'tb1.company_id = tb2.company_id AND tb1.topic_id = tb2.id', ['topic' => 'name']);
2589
                $select->where->equalTo('tb1.company_id', $currentCompany->id);
2570
                $select->join(['tb3' => MicrolearningCapsuleMapper::_TABLE], 'tb1.company_id = tb3.company_id AND tb1.topic_id = tb3.topic_id AND tb1.capsule_id = tb3.id', ['capsule' => 'name']);
2590
                $select->where->equalTo('tb1.user_id', $user->id);
2571
                $select->where->equalTo('tb1.company_id', $currentCompany->id);
2591
                $select->group('tb1.topic_id'); // Agrupar por tópico para evitar duplicados
2572
                $select->where->equalTo('tb1.user_id', $user->id);
2592
                $select->order('tb2.name ASC');
2573
                $select->order('tb2.name ASC, tb3.name ASC');
2593
 
2574
 
-
 
2575
 
2594
 
Línea -... Línea 2595...
-
 
2595
                // Construir array inicial de items con valores por defecto (agrupado por tópico)
2576
                $items = [];
2596
                $items = [];
2577
                $records = $queryMapper->fetchAll($select);
2597
                $records = $queryMapper->fetchAll($select);
Línea 2578... Línea -...
2578
                foreach($records as $record)
-
 
2579
                {
-
 
2580
                    $capsule_id = $record['capsule_id'];
2598
                foreach($records as $record)
2581
 
2599
                {
-
 
2600
                    $topic_id = $record['topic_id'];
-
 
2601
 
2582
                    
2602
                    // Estructura base de cada tópico con estadísticas de cápsulas
2583
                    $item = [
2603
                    $item = [
-
 
2604
                        'topic' => ucwords(strtolower($record['topic'])),
-
 
2605
                        'progress' => 0, // Porcentaje de progreso del tópico
2584
                        'topic' => ucwords(strtolower($record['topic'])),
2606
                        'total_capsules' => 0, // Total de cápsulas asignadas en el tópico
2585
                        'capsule' => ucwords(strtolower($record['capsule'])),
2607
                        'completed_capsules' => 0, // Cápsulas completadas
2586
                        'progress' => 0,
2608
                        'started_capsules' => 0, // Cápsulas iniciadas pero no completadas
-
 
2609
                        'pending_capsules' => 0, // Cápsulas sin iniciar
-
 
2610
                        'added_on' => '', // Fecha de inicio del primer progreso
Línea 2587... Línea -...
2587
                        'total_slides' => 0,
-
 
2588
                        'view_slides' => 0,
-
 
2589
                        'completed' => 'No',
-
 
2590
                        'added_on' => '',
2611
                        'updated_on' => '', // Fecha de última actualización
2591
                        'updated_on' => '',
-
 
2592
                        
-
 
2593
                    ];
-
 
2594
                    
2612
                    ];
2595
                    $items[ $record['capsule_id'] ] =  $item;
2613
                    
-
 
2614
                    // Indexar por ID de tópico para facilitar actualización posterior
2596
                }
2615
                    $items[ $topic_id ] = $item;
2597
 
2616
                }
2598
                
2617
 
Línea 2599... Línea 2618...
2599
                
2618
                // Segunda consulta: Obtener fechas de progreso y finalizar cálculos por tópico
2600
                $queryMapper = QueryMapper::getInstance($this->adapter);
2619
                $select = $sql->select();
Línea -... Línea 2620...
-
 
2620
                $select->columns([
-
 
2621
                    'topic_id', 
Línea 2601... Línea 2622...
2601
                $sql = $queryMapper->getSql();
2622
                    'added_on' => new \Laminas\Db\Sql\Expression('MIN(added_on)'), // Fecha de primer acceso
2602
                $select = $sql->select(MicrolearningUserProgressMapper::_TABLE);
2623
                    'updated_on' => new \Laminas\Db\Sql\Expression('MAX(updated_on)') // Fecha de última actividad
2603
                $select->columns(['capsule_id', 'progress', 'total_slides' , 'view_slides', 'completed', 'added_on','updated_on']);
2624
                ]);
-
 
2625
                $select->from(MicrolearningUserProgressMapper::_TABLE);
2604
                $select->where->equalTo('company_id', $currentCompany->id);
2626
                $select->where->equalTo('company_id', $currentCompany->id);
2605
                $select->where->equalTo('user_id', $user->id);
2627
                $select->where->equalTo('user_id', $user->id);
-
 
2628
                $select->where->equalTo('type', MicrolearningUserProgress::TYPE_CAPSULE);
2606
                $select->where->equalTo('type', MicrolearningUserProgress::TYPE_CAPSULE);
2629
                $select->where->in('topic_id', $topic_ids);
-
 
2630
                $select->group('topic_id');
2607
 
2631
 
Línea 2608... Línea -...
2608
                
-
 
-
 
2632
                $records = $queryMapper->fetchAll($select);
2609
                
2633
                foreach($records as $record) {
Línea -... Línea 2634...
-
 
2634
                    $topic_id = $record['topic_id'];
2610
                
2635
                    
2611
                $records = $queryMapper->fetchAll($select);
2636
                    // Formatear fechas de inicio y actualización del tópico
2612
                
2637
                    $dt_added_on = \DateTime::createFromFormat('Y-m-d H:i:s', $record['added_on']);
Línea 2613... Línea -...
2613
                
-
 
2614
         
-
 
-
 
2638
                    $added_on = $dt_added_on->format('d/m/Y h:i a');
2615
                foreach($records as $record)
2639
                    
2616
                {
2640
                    $dt_updated_on = \DateTime::createFromFormat('Y-m-d H:i:s', $record['updated_on']);
2617
                    $capsule_id = $record['capsule_id'];
2641
                    $updated_on = $dt_updated_on->format('d/m/Y h:i a');
2618
                    $dt_added_on = \DateTime::createFromFormat('Y-m-d H:i:s', $record['added_on']);
2642
                    
2619
                    $added_on = $dt_added_on->format('d/m/Y h:i a');
2643
                    $items[$topic_id]['added_on'] = $added_on;
-
 
2644
                    $items[$topic_id]['updated_on'] = $updated_on;
Línea 2620... Línea -...
2620
                    
-
 
-
 
2645
                    
2621
                    $dt_updated_on = \DateTime::createFromFormat('Y-m-d H:i:s', $record['updated_on']);
2646
                    // Calcular cápsulas pendientes (no iniciadas)
Línea 2622... Línea -...
2622
                    $updated_on = $dt_updated_on->format('d/m/Y h:i a');
-
 
2623
                    
-
 
-
 
2647
                    $items[$topic_id]['pending_capsules'] = $items[$topic_id]['total_capsules'] - 
2624
                    
2648
                        ($items[$topic_id]['completed_capsules'] + $items[$topic_id]['started_capsules']);
2625
                    $items[ $capsule_id ]['progress'] = $record['progress'];
2649
                    
2626
                    $items[ $capsule_id ]['total_slides'] = $record['total_slides'];
2650
                    // Calcular progreso total del tópico como porcentaje de cápsulas completadas
2627
                    $items[ $capsule_id ]['view_slides'] = $record['view_slides'];
2651
                    if($items[$topic_id]['total_capsules'] > 0) {
2628
                    $items[ $capsule_id ]['completed'] = $record['completed'] == 1 ? 'Si' : 'No';
2652
                        $progress = ($items[$topic_id]['completed_capsules'] * 100) / $items[$topic_id]['total_capsules'];
Línea 2659... Línea 2683...
2659
                
2683
                
2660
                return $viewModel ;
2684
                return $viewModel ;
Línea 2661... Línea 2685...
2661
            }
2685
            }
-
 
2686
            
2662
            
2687
        } else {
2663
        } else {
2688
            // Método HTTP no permitido (solo se acepta GET)
2664
            return new JsonModel([
2689
            return new JsonModel([
2665
                'success' => false,
2690
                'success' => false,
2666
                'data' => 'ERROR_METHOD_NOT_ALLOWED'
2691
                'data' => 'ERROR_METHOD_NOT_ALLOWED'