erp-platform/api/src/Erp.Platform.Application/Intranet/IntranetAppService.cs
2025-12-04 00:01:00 +03:00

481 lines
17 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using ClosedXML;
using Erp.Platform.BlobStoring;
using Erp.Platform.Entities;
using Erp.Platform.FileManagement;
using Erp.Platform.Intranet;
using Microsoft.AspNetCore.Authorization;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.MultiTenancy;
namespace Erp.Platform.Public;
[Authorize]
public class IntranetAppService : PlatformAppService, IIntranetAppService
{
private readonly ICurrentTenant _currentTenant;
private readonly BlobManager _blobContainer;
private readonly IConfiguration _configuration;
private readonly IRepository<Event, Guid> _eventRepository;
private readonly IRepository<Employee, Guid> _employeeRepository;
private readonly IRepository<Visitor, Guid> _visitorRepository;
private readonly IRepository<Reservation, Guid> _reservationRepository;
private readonly IRepository<Training, Guid> _trainingRepository;
private readonly IRepository<Expense, Guid> _expenseRepository;
private readonly IRepository<Announcement, Guid> _announcementRepository;
private readonly IRepository<Department, Guid> _departmentRepository;
private readonly IRepository<ShuttleRoute, Guid> _shuttleRouteRepository;
private readonly IRepository<Meal, Guid> _mealRepository;
private readonly IRepository<Leave, Guid> _leaveRepository;
private readonly IRepository<Overtime, Guid> _overtimeRepository;
private readonly IRepository<Survey, Guid> _surveyRepository;
private readonly IRepository<SocialPost, Guid> _socialPostRepository;
public IntranetAppService(
ICurrentTenant currentTenant,
BlobManager blobContainer,
IConfiguration configuration,
IRepository<Event, Guid> eventRepository,
IRepository<Employee, Guid> employeeRepository,
IRepository<Visitor, Guid> visitorRepository,
IRepository<Reservation, Guid> reservationRepository,
IRepository<Training, Guid> trainingRepository,
IRepository<Expense, Guid> expenseRepository,
IRepository<Announcement, Guid> announcementRepository,
IRepository<Department, Guid> departmentRepository,
IRepository<ShuttleRoute, Guid> shuttleRouteRepository,
IRepository<Meal, Guid> mealRepository,
IRepository<Leave, Guid> leaveRepository,
IRepository<Overtime, Guid> overtimeRepository,
IRepository<Survey, Guid> surveyRepository,
IRepository<SocialPost, Guid> socialPostRepository
)
{
_currentTenant = currentTenant;
_blobContainer = blobContainer;
_configuration = configuration;
_eventRepository = eventRepository;
_employeeRepository = employeeRepository;
_visitorRepository = visitorRepository;
_reservationRepository = reservationRepository;
_trainingRepository = trainingRepository;
_expenseRepository = expenseRepository;
_announcementRepository = announcementRepository;
_departmentRepository = departmentRepository;
_shuttleRouteRepository = shuttleRouteRepository;
_mealRepository = mealRepository;
_leaveRepository = leaveRepository;
_overtimeRepository = overtimeRepository;
_surveyRepository = surveyRepository;
_socialPostRepository = socialPostRepository;
}
public async Task<IntranetDashboardDto> GetIntranetDashboardAsync()
{
return new IntranetDashboardDto
{
Events = await GetUpcomingEventsAsync(),
Birthdays = await GetBirthdaysAsync(),
Visitors = await GetVisitorsAsync(),
Reservations = await GetReservationsAsync(),
Trainings = await GetTrainingsAsync(),
Expenses = await GetExpensesAsync(),
Documents = await GetIntranetDocumentsAsync(BlobContainerNames.Intranet),
Announcements = await GetAnnouncementsAsync(),
ShuttleRoutes = await GetShuttleRoutesAsync(),
Meals = await GetMealsAsync(),
Leaves = await GetLeavesAsync(),
Overtimes = await GetOvertimesAsync(),
Surveys = await GetSurveysAsync(),
SocialPosts = await GetSocialPostsAsync()
};
}
private async Task<List<SocialPostDto>> GetSocialPostsAsync()
{
var socialPosts = await _socialPostRepository
.WithDetailsAsync(e => e.Employee, e => e.Location, e => e.Media, e => e.Comments, e => e.Likes)
.ContinueWith(t => t.Result.ToList());
return ObjectMapper.Map<List<SocialPost>, List<SocialPostDto>>(socialPosts);
}
private async Task<List<SurveyDto>> GetSurveysAsync()
{
var queryable = await _surveyRepository.GetQueryableAsync();
var surveys = queryable
.Where(s => s.Status == "active")
.Include(s => s.Questions)
.ThenInclude(q => q.Options)
.ToList();
return ObjectMapper.Map<List<Survey>, List<SurveyDto>>(surveys);
}
private async Task<List<OvertimeDto>> GetOvertimesAsync()
{
var today = DateTime.Now;
var overtimes = await _overtimeRepository
.WithDetailsAsync(e => e.Employee)
.ContinueWith(t => t.Result.ToList());
return ObjectMapper.Map<List<Overtime>, List<OvertimeDto>>(overtimes);
}
private async Task<List<LeaveDto>> GetLeavesAsync()
{
var today = DateTime.Now;
var leaves = await _leaveRepository
.WithDetailsAsync(e => e.Employee)
.ContinueWith(t => t.Result.ToList());
return ObjectMapper.Map<List<Leave>, List<LeaveDto>>(leaves);
}
private async Task<List<MealDto>> GetMealsAsync()
{
// Bu haftanın başlangıç ve bitiş tarihlerini hesapla
var today = DateTime.Now.Date;
var dayOfWeek = (int)today.DayOfWeek;
// Pazartesi'yi haftanın başı olarak kabul ediyoruz (ISO 8601)
var weekStart = today.AddDays(-(dayOfWeek == 0 ? 6 : dayOfWeek - 1));
var weekEnd = weekStart.AddDays(6);
// Sadece bu haftanın yemeklerini getir
var meals = await _mealRepository.GetListAsync(m =>
m.Date >= weekStart && m.Date <= weekEnd);
var mealDtos = new List<MealDto>();
foreach (var meal in meals)
{
var dto = ObjectMapper.Map<Meal, MealDto>(meal);
if (!string.IsNullOrEmpty(meal.Materials))
{
dto.Materials = meal.Materials
.Split('|', StringSplitOptions.RemoveEmptyEntries)
.Select(r => r.Trim())
.ToArray();
}
else
{
dto.Materials = [];
}
mealDtos.Add(dto);
}
return mealDtos;
}
private async Task<List<ShuttleRouteDto>> GetShuttleRoutesAsync()
{
var shuttleRoutes = await _shuttleRouteRepository.GetListAsync();
var shuttleRouteDtos = new List<ShuttleRouteDto>();
foreach (var shuttleRoute in shuttleRoutes)
{
var dto = ObjectMapper.Map<ShuttleRoute, ShuttleRouteDto>(shuttleRoute);
// Route string'ini array'e çevir (pipe ile ayrılmış)
if (!string.IsNullOrEmpty(shuttleRoute.Route))
{
dto.Route = shuttleRoute.Route
.Split('|', StringSplitOptions.RemoveEmptyEntries)
.Select(r => r.Trim())
.ToArray();
}
else
{
dto.Route = [];
}
shuttleRouteDtos.Add(dto);
}
return shuttleRouteDtos;
}
private async Task<List<AnnouncementDto>> GetAnnouncementsAsync()
{
var announcements = await _announcementRepository
.WithDetailsAsync(e => e.Employee)
.ContinueWith(t => t.Result.ToList());
var announcementDtos = new List<AnnouncementDto>();
// Tüm departmanları bir kez çek (performans için)
var allDepartments = await _departmentRepository.GetListAsync();
foreach (var announcement in announcements)
{
var dto = ObjectMapper.Map<Announcement, AnnouncementDto>(announcement);
// Departments string'ini array'e çevir (pipe ile ayrılmış ID'ler)
if (!string.IsNullOrEmpty(announcement.Departments))
{
var departmentIds = announcement.Departments
.Split('|', StringSplitOptions.RemoveEmptyEntries)
.Select(d => d.Trim())
.ToArray();
// ID'leri Department Name'lere çevir
var departmentNames = new List<string>();
foreach (var deptId in departmentIds)
{
if (Guid.TryParse(deptId, out var guid))
{
var department = allDepartments.FirstOrDefault(d => d.Id == guid);
if (department != null)
{
departmentNames.Add(department.Name);
}
}
}
dto.Departments = departmentNames.ToArray();
}
else
{
dto.Departments = [];
}
announcementDtos.Add(dto);
}
return announcementDtos;
}
private async Task<ExpensesDto> GetExpensesAsync()
{
var queryable = await _expenseRepository.GetQueryableAsync();
var today = DateTime.Today;
var oneMonthAgo = today.AddMonths(-1);
// Son 1 ay içerisindeki kayıtlar
var lastMonthExpenses = queryable
.Where(a => a.RequestDate >= oneMonthAgo && a.RequestDate <= today);
// Son 1 aydaki toplam talep miktarı
var totalRequested = lastMonthExpenses.Sum(a => a.Amount);
// Son 1 aydaki onaylanan harcamaların toplamı
var totalApproved = lastMonthExpenses
.Where(a => a.Status == "approved")
.Sum(a => a.Amount);
// Son 5 kayıt
var last5Expenses = queryable
.OrderByDescending(a => a.RequestDate)
.Take(5)
.ToList();
// Map işlemleri
var last5Dtos = ObjectMapper.Map<List<Expense>, List<ExpenseDto>>(last5Expenses);
// Dönüş DTO'su
return new ExpensesDto
{
TotalRequested = totalRequested,
TotalApproved = totalApproved,
Last5Expenses = last5Dtos
};
}
private async Task<List<TrainingDto>> GetTrainingsAsync()
{
var trainings = await _trainingRepository.GetListAsync(a => a.StartDate >= DateTime.Today);
return ObjectMapper.Map<List<Training>, List<TrainingDto>>(trainings);
}
private async Task<List<ReservationDto>> GetReservationsAsync()
{
var reservations = await _reservationRepository.GetListAsync(a => a.StartDate >= DateTime.Today);
return ObjectMapper.Map<List<Reservation>, List<ReservationDto>>(reservations);
}
private async Task<List<VisitorDto>> GetVisitorsAsync()
{
var visitors = await _visitorRepository.GetListAsync(a => a.VisitDate >= DateTime.Today);
return ObjectMapper.Map<List<Visitor>, List<VisitorDto>>(visitors);
}
private async Task<List<EmployeeDto>> GetBirthdaysAsync()
{
var today = DateTime.Now;
var employees = await _employeeRepository
.WithDetailsAsync(e => e.EmploymentType, e => e.JobPosition, e => e.Department)
.ContinueWith(t => t.Result
.Where(e => e.BirthDate.Day == today.Day && e.BirthDate.Month == today.Month)
.ToList());
return ObjectMapper.Map<List<Employee>, List<EmployeeDto>>(employees);
}
private async Task<List<EventDto>> GetUpcomingEventsAsync()
{
var events = await _eventRepository
.WithDetailsAsync(e => e.Category, e => e.Type, e => e.Category, e => e.Photos, e => e.Comments)
.ContinueWith(t => t.Result.ToList().Where(e => e.isPublished).OrderByDescending(e => e.CreationTime));
var result = new List<EventDto>();
foreach (var evt in events)
{
var employee = await _employeeRepository
.WithDetailsAsync(e => e.JobPosition)
.ContinueWith(t => t.Result.FirstOrDefault(e => e.Id == evt.EmployeeId));
if (employee != null)
{
var calendarEvent = new EventDto
{
Id = evt.Id.ToString(),
Name = evt.Name,
Description = evt.Description,
TypeName = evt.Type?.Name,
CategoryName = evt.Category?.Name,
Date = evt.Date,
Place = evt.Place,
Organizer = new EventOrganizerDto
{
Id = employee.Id,
Name = employee.Name,
Position = employee.JobPosition.Name,
Avatar = employee.Avatar
},
Participants = evt.ParticipantsCount,
Photos = [],
Comments = [],
Likes = evt.Likes,
IsPublished = evt.isPublished
};
// Comment'lerin author bilgilerini doldur
if (evt.Comments != null && evt.Comments.Any())
{
foreach (var comment in evt.Comments)
{
var commentAuthor = await _employeeRepository
.WithDetailsAsync(e => e.JobPosition)
.ContinueWith(t => t.Result.FirstOrDefault(e => e.Id == comment.EmployeeId));
if (commentAuthor != null)
{
calendarEvent.Comments.Add(new EventCommentDto
{
Id = comment.Id.ToString(),
Employee = new EventOrganizerDto
{
Id = commentAuthor.Id,
Name = commentAuthor.Name,
Position = commentAuthor.JobPosition.Name,
Avatar = commentAuthor.Avatar
},
Content = comment.Content,
CreationTime = comment.CreationTime,
Likes = comment.Likes
});
}
}
}
result.Add(calendarEvent);
}
}
return result;
}
public async Task<List<FileItemDto>> GetIntranetDocumentsAsync(string folderPath)
{
var items = new List<FileItemDto>();
var cdnBasePath = _configuration["App:CdnPath"];
if (string.IsNullOrEmpty(cdnBasePath))
{
Logger.LogWarning("CDN path is not configured");
return items;
}
var tenantId = _currentTenant.Id?.ToString() ?? "host";
var fullPath = Path.Combine(cdnBasePath, tenantId);
if (!string.IsNullOrEmpty(folderPath))
{
fullPath = Path.Combine(fullPath, folderPath);
}
if (!Directory.Exists(fullPath))
{
Logger.LogWarning($"Directory not found: {fullPath}");
return items;
}
var files = Directory.GetFiles(fullPath);
foreach (var file in files)
{
var fileInfo = new FileInfo(file);
var relativePath = string.IsNullOrEmpty(folderPath) ? fileInfo.Name : $"{folderPath}/{fileInfo.Name}";
items.Add(new FileItemDto
{
Id = Guid.NewGuid().ToString(),
Name = fileInfo.Name,
Type = "file",
Size = fileInfo.Length,
Extension = fileInfo.Extension,
MimeType = GetMimeType(fileInfo.Extension),
CreatedAt = fileInfo.CreationTime,
ModifiedAt = fileInfo.LastWriteTime,
Path = relativePath,
ParentId = string.Empty,
IsReadOnly = false,
ChildCount = 0
});
}
return items.OrderBy(x => x.Name).ToList();
}
private string GetMimeType(string extension)
{
return extension.ToLowerInvariant() switch
{
".pdf" => "application/pdf",
".doc" => "application/msword",
".docx" => "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
".xls" => "application/vnd.ms-excel",
".xlsx" => "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
".ppt" => "application/vnd.ms-powerpoint",
".pptx" => "application/vnd.openxmlformats-officedocument.presentationml.presentation",
".jpg" or ".jpeg" => "image/jpeg",
".png" => "image/png",
".gif" => "image/gif",
".txt" => "text/plain",
".zip" => "application/zip",
".rar" => "application/x-rar-compressed",
_ => "application/octet-stream"
};
}
}