update analytic

This commit is contained in:
Efril 2026-01-27 00:38:32 +07:00
parent c8ea680e05
commit 490aa19840

View File

@ -3,6 +3,8 @@ package repository
import ( import (
"context" "context"
"fmt" "fmt"
"log"
"strings"
"time" "time"
"github.com/google/uuid" "github.com/google/uuid"
@ -320,7 +322,10 @@ func (r *AnalyticsRepository) GetDepartmentStats(ctx context.Context, startDate,
db := DBFromContext(ctx, r.db) db := DBFromContext(ctx, r.db)
var results []map[string]interface{} var results []map[string]interface{}
// First try using summary table for better performance // Format tanggal untuk logging
log.Printf("GetDepartmentStats called with startDate: %v, endDate: %v", startDate, endDate)
// Try summary table first
query := ` query := `
SELECT SELECT
d.id as department_id, d.id as department_id,
@ -332,67 +337,128 @@ func (r *AnalyticsRepository) GetDepartmentStats(ctx context.Context, startDate,
COALESCE(AVG(dls.avg_response_hours), 0) as avg_response_time, COALESCE(AVG(dls.avg_response_hours), 0) as avg_response_time,
COALESCE(AVG(dls.completion_rate), 0) as completion_rate COALESCE(AVG(dls.completion_rate), 0) as completion_rate
FROM departments d FROM departments d
LEFT JOIN department_letter_summary dls ON dls.department_id = d.id LEFT JOIN department_letter_summary dls ON dls.department_id = d.id`
WHERE 1=1
%s var conditions []string
GROUP BY d.id, d.name, d.code var args []interface{}
ORDER BY (COALESCE(SUM(dls.incoming_count), 0) + COALESCE(SUM(dls.outgoing_count), 0)) DESC
`
dateFilter := ""
if !startDate.IsZero() { if !startDate.IsZero() {
dateFilter += fmt.Sprintf(" AND dls.summary_date >= '%s'", startDate.Format("2006-01-02")) conditions = append(conditions, "dls.summary_date >= ?")
args = append(args, startDate.Format("2006-01-02"))
} }
if !endDate.IsZero() { if !endDate.IsZero() {
dateFilter += fmt.Sprintf(" AND dls.summary_date <= '%s'", endDate.Format("2006-01-02")) conditions = append(conditions, "dls.summary_date <= ?")
args = append(args, endDate.Format("2006-01-02"))
} }
query = fmt.Sprintf(query, dateFilter) if len(conditions) > 0 {
query += " WHERE " + strings.Join(conditions, " AND ")
}
if err := db.Raw(query).Scan(&results).Error; err != nil { query += `
GROUP BY d.id, d.name, d.code
ORDER BY (COALESCE(SUM(dls.incoming_count), 0) + COALESCE(SUM(dls.outgoing_count), 0)) DESC`
log.Printf("Summary query: %s, args: %v", query, args)
if err := db.Raw(query, args...).Scan(&results).Error; err != nil {
return nil, err return nil, err
} }
// If no results from summary table, fall back to direct query // Check if summary table has data for this period
if len(results) == 0 { var summaryCount int64
checkQuery := "SELECT COUNT(*) FROM department_letter_summary WHERE 1=1"
checkArgs := []interface{}{}
if !startDate.IsZero() {
checkQuery += " AND summary_date >= ?"
checkArgs = append(checkArgs, startDate.Format("2006-01-02"))
}
if !endDate.IsZero() {
checkQuery += " AND summary_date <= ?"
checkArgs = append(checkArgs, endDate.Format("2006-01-02"))
}
db.Raw(checkQuery, checkArgs...).Scan(&summaryCount)
log.Printf("Summary count: %d", summaryCount)
// If no summary data exists for this period, fall back to direct query
if summaryCount == 0 {
log.Println("Using fallback query (no summary data)")
// Use CTE for better performance
fallbackQuery := ` fallbackQuery := `
WITH filtered_incoming AS (
SELECT
li.id,
li.created_at,
li.updated_at,
lir.recipient_department_id
FROM letters_incoming li
INNER JOIN letter_incoming_recipients lir ON lir.letter_id = li.id
WHERE li.deleted_at IS NULL`
var fallbackArgs []interface{}
if !startDate.IsZero() {
fallbackQuery += " AND li.created_at >= ?"
fallbackArgs = append(fallbackArgs, startDate)
}
if !endDate.IsZero() {
fallbackQuery += " AND li.created_at <= ?"
fallbackArgs = append(fallbackArgs, endDate)
}
fallbackQuery += `
),
filtered_outgoing AS (
SELECT
lo.id,
lo.status,
lo.created_at,
lo.updated_at,
lor.department_id
FROM letters_outgoing lo
INNER JOIN letter_outgoing_recipients lor ON lor.letter_id = lo.id
WHERE lo.deleted_at IS NULL`
if !startDate.IsZero() {
fallbackQuery += " AND lo.created_at >= ?"
fallbackArgs = append(fallbackArgs, startDate)
}
if !endDate.IsZero() {
fallbackQuery += " AND lo.created_at <= ?"
fallbackArgs = append(fallbackArgs, endDate)
}
fallbackQuery += `
)
SELECT SELECT
d.id as department_id, d.id as department_id,
d.name as department_name, d.name as department_name,
d.code as department_code, d.code as department_code,
COUNT(DISTINCT lir.letter_id) as incoming_count, COUNT(DISTINCT fi.id) as incoming_count,
COUNT(DISTINCT lor.letter_id) as outgoing_count, COUNT(DISTINCT fo.id) as outgoing_count,
COUNT(DISTINCT CASE WHEN lo.status = 'pending_approval' THEN lo.id END) as pending_count, COUNT(DISTINCT CASE WHEN fo.status = 'pending_approval' THEN fo.id END) as pending_count,
COALESCE(AVG(CASE COALESCE(AVG(CASE
WHEN lo.status IN ('approved', 'sent', 'archived') WHEN fo.status IN ('approved', 'sent', 'archived')
THEN EXTRACT(EPOCH FROM (lo.updated_at - lo.created_at))/3600 THEN EXTRACT(EPOCH FROM (fo.updated_at - fo.created_at))/3600
END), 0) as avg_response_time, END), 0) as avg_response_time,
CASE CASE
WHEN COUNT(DISTINCT lo.id) > 0 WHEN COUNT(DISTINCT fo.id) > 0
THEN ROUND(COUNT(DISTINCT CASE WHEN lo.status IN ('sent', 'archived') THEN lo.id END) * 100.0 / COUNT(DISTINCT lo.id), 2) THEN ROUND(COUNT(DISTINCT CASE WHEN fo.status IN ('sent', 'archived') THEN fo.id END) * 100.0 / COUNT(DISTINCT fo.id), 2)
ELSE 0 ELSE 0
END as completion_rate END as completion_rate
FROM departments d FROM departments d
LEFT JOIN letter_incoming_recipients lir ON lir.recipient_department_id = d.id LEFT JOIN filtered_incoming fi ON fi.recipient_department_id = d.id
LEFT JOIN letter_outgoing_recipients lor ON lor.department_id = d.id LEFT JOIN filtered_outgoing fo ON fo.department_id = d.id
LEFT JOIN letters_outgoing lo ON lo.id = lor.letter_id AND lo.deleted_at IS NULL
WHERE 1=1
%s
GROUP BY d.id, d.name, d.code GROUP BY d.id, d.name, d.code
ORDER BY (COUNT(DISTINCT lir.letter_id) + COUNT(DISTINCT lor.letter_id)) DESC ORDER BY (COUNT(DISTINCT fi.id) + COUNT(DISTINCT fo.id)) DESC`
`
fallbackDateFilter := "" log.Printf("Fallback query: %s", fallbackQuery)
if !startDate.IsZero() { log.Printf("Fallback args: %v", fallbackArgs)
fallbackDateFilter += fmt.Sprintf(" AND (lo.created_at >= '%s' OR lo.created_at IS NULL)", startDate.Format("2006-01-02"))
}
if !endDate.IsZero() {
fallbackDateFilter += fmt.Sprintf(" AND (lo.created_at <= '%s' OR lo.created_at IS NULL)", endDate.Format("2006-01-02"))
}
fallbackQuery = fmt.Sprintf(fallbackQuery, fallbackDateFilter) if err := db.Raw(fallbackQuery, fallbackArgs...).Scan(&results).Error; err != nil {
if err := db.Raw(fallbackQuery).Scan(&results).Error; err != nil {
return nil, err return nil, err
} }
} }