From aa904079a225059bcd8bec9d858392f995ddbbfb Mon Sep 17 00:00:00 2001
From: kittapath <>
Date: Sun, 14 Sep 2025 21:02:24 +0700
Subject: [PATCH] add holiday
---
.../Controllers/HolidayController.cs | 310 ++++++++
BMA.EHR.Leave/Request/HolidayCopyRequest.cs | 10 +
BMA.EHR.Leave/Request/HolidayRequest.cs | 15 +
BMA.EHR.Leave/Request/HolidayUpdateRequest.cs | 13 +
.../SummaryHolidayByMonthResponseItem.cs | 14 +
BMA.EHR.Leave/Services/HolidayService.cs | 678 ++++++++++++++++++
.../Controllers/MessageController.cs | 190 +++++
.../Controllers/NotifyController.cs | 5 -
8 files changed, 1230 insertions(+), 5 deletions(-)
create mode 100644 BMA.EHR.Leave/Controllers/HolidayController.cs
create mode 100644 BMA.EHR.Leave/Request/HolidayCopyRequest.cs
create mode 100644 BMA.EHR.Leave/Request/HolidayRequest.cs
create mode 100644 BMA.EHR.Leave/Request/HolidayUpdateRequest.cs
create mode 100644 BMA.EHR.Leave/Response/SummaryHolidayByMonthResponseItem.cs
create mode 100644 BMA.EHR.Leave/Services/HolidayService.cs
create mode 100644 BMA.EHR.Placement.Service/Controllers/MessageController.cs
diff --git a/BMA.EHR.Leave/Controllers/HolidayController.cs b/BMA.EHR.Leave/Controllers/HolidayController.cs
new file mode 100644
index 00000000..9e2b2de1
--- /dev/null
+++ b/BMA.EHR.Leave/Controllers/HolidayController.cs
@@ -0,0 +1,310 @@
+using BMA.EHR.Domain.Common;
+using BMA.EHR.Domain.Models.MetaData;
+using BMA.EHR.Leave.Service.Request;
+using BMA.EHR.Leave.Service.Services;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+using Swashbuckle.AspNetCore.Annotations;
+
+namespace BMA.EHR.Leave.Service.Controllers
+{
+ [Route("api/v{version:apiVersion}/leave/metadata/holiday")]
+ [ApiVersion("1.0")]
+ [ApiController]
+ [Produces("application/json")]
+ [Authorize]
+ [SwaggerTag("จัดการข้อมูลปฏิทินวันหยุด")]
+ public class HolidayController : BaseController
+ {
+ #region " Fields "
+
+ private readonly HolidayService _holidayService;
+
+ #endregion
+
+ #region " Constructor and Destructor "
+
+ public HolidayController(HolidayService holidayService)
+ {
+ _holidayService = holidayService;
+ }
+
+ #endregion
+
+ #region " Methods "
+
+ ///
+ /// อ่านข้อมูลจาก Relational Db โดยแสดงเฉพาะข้อมูลที่ Active เท่านั้น ตามปี
+ ///
+ /// ปี่ที่ต้องการ
+ ///
+ /// เมื่อทำการอ่านข้อมูลจาก Relational Database สำเร็จ
+ /// ไม่ได้ Login เข้าระบบ
+ /// เมื่อเกิดข้อผิดพลาดในการทำงาน
+ [HttpGet("{year:int}")]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status401Unauthorized)]
+ [ProducesResponseType(StatusCodes.Status500InternalServerError)]
+ public async Task> GetsAsync(int year)
+ {
+ try
+ {
+ var items1 = await _holidayService.GetNormalAsync(year);
+ var items2 = await _holidayService.Get6DayAsync(year);
+
+ return Success(new { Normal = items1, SixDays = items2 });
+ }
+ catch (Exception ex)
+ {
+ return Error(ex);
+ }
+ }
+
+ ///
+ /// อ่านข้อมูลจาก Relational Db โดยแสดงเฉพาะข้อมูลที่ Active เท่านั้น ตามเดือน
+ ///
+ /// ปี่ที่ต้องการ
+ /// เดือนที่ต้องการ
+ ///
+ /// เมื่อทำการอ่านข้อมูลจาก Relational Database สำเร็จ
+ /// ไม่ได้ Login เข้าระบบ
+ /// เมื่อเกิดข้อผิดพลาดในการทำงาน
+ [HttpGet("{year:int}/{month:int}")]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status401Unauthorized)]
+ [ProducesResponseType(StatusCodes.Status500InternalServerError)]
+ public async Task> GetsAsyncByMonth(int year, int month)
+ {
+ try
+ {
+ var items1 = await _holidayService.GetNormalByMonthAsync(year, month);
+ var items2 = await _holidayService.Get6DayByMonthAsync(year, month);
+
+ return Success(new { Normal = items1, SixDays = items2 });
+ }
+ catch (Exception ex)
+ {
+ return Error(ex);
+ }
+ }
+
+ ///
+ /// สร้างรายการวันหยุดใหม่แบบรายการเดียว
+ ///
+ ///
+ /// ทำรายการสำเร็จ
+ /// ไม่ได้ Login เข้าระบบ
+ /// เมื่อเกิดข้อผิดพลาดในการทำงาน
+ [HttpPost]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status401Unauthorized)]
+ [ProducesResponseType(StatusCodes.Status500InternalServerError)]
+ public async Task> CreateAsync(Holiday inserted)
+ {
+ try
+ {
+ // create normal
+ await _holidayService.CreateAsync(inserted);
+
+ // create 6days
+ await _holidayService.Create6DayAsync(inserted);
+
+ //save database
+ await _holidayService.SaveDatabase();
+
+ return Success(inserted);
+ }
+ catch (Exception ex)
+ {
+ return Error(ex);
+ }
+ }
+
+ ///
+ /// สร้างรายการวันหยุดใหม่แบบหลายรายการ
+ ///
+ /// ช่วงวันที่ที่ต้องการเพิ่ม
+ /// ประเภทวันหยุด ส่งค่ามาเป็น normal / 6day
+ ///
+ /// ทำรายการสำเร็จ
+ /// ไม่ได้ Login เข้าระบบ
+ /// เมื่อเกิดข้อผิดพลาดในการทำงาน
+ [HttpPost("range/add/{category}")]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status401Unauthorized)]
+ [ProducesResponseType(StatusCodes.Status500InternalServerError)]
+ public async Task> CreateRangeAsync(List inserted, string category)
+ {
+ try
+ {
+ await _holidayService.CreateRangeAsync(inserted, category);
+
+ return Success(inserted);
+ }
+ catch (Exception ex)
+ {
+ return Error(ex);
+ }
+ }
+
+ ///
+ /// แก้ไขรายการวันหยุด
+ ///
+ /// รหัส
+ /// ข้อมูลที่ต้องการแก้ไข
+ ///
+ /// ทำรายการสำเร็จ
+ /// ไม่ได้ Login เข้าระบบ
+ /// เมื่อเกิดข้อผิดพลาดในการทำงาน
+ [HttpPut("{category}/{id:length(36)}")]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status401Unauthorized)]
+ [ProducesResponseType(StatusCodes.Status500InternalServerError)]
+ public async Task> UpdateAsync(string id, Holiday updated)
+ {
+ try
+ {
+ await _holidayService.UpdateAsync(Guid.Parse(id), updated);
+
+ return Success(updated);
+ }
+ catch (Exception ex)
+ {
+ return Error(ex);
+ }
+ }
+
+ ///
+ /// แก้ไขรายการวันหยุด
+ ///
+ /// Group ข่อมูลที่แก้ไข
+ /// ประเภทวันหยุด ส่งค่ามาเป็น normal / 6day
+ ///
+ /// ทำรายการสำเร็จ
+ /// ไม่ได้ Login เข้าระบบ
+ /// เมื่อเกิดข้อผิดพลาดในการทำงาน
+ [HttpPost("range/edit/{category}")]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status401Unauthorized)]
+ [ProducesResponseType(StatusCodes.Status500InternalServerError)]
+ public async Task> UpdateRangeAsync(HolidayUpdateRequest data, string category)
+ {
+ try
+ {
+ var isNormal = category.ToUpper() == "NORMAL";
+ await _holidayService.UpdateRangeAsync(data.history, data.updated, isNormal);
+
+ return Success(data.updated);
+ }
+ catch (Exception ex)
+ {
+ return Error(ex);
+ }
+ }
+
+ ///
+ /// ลบรายการวันหยุด
+ ///
+ /// รหัส
+ ///
+ /// ทำรายการสำเร็จ
+ /// ไม่ได้ Login เข้าระบบ
+ /// เมื่อเกิดข้อผิดพลาดในการทำงาน
+ [HttpDelete("{id:length(36)}")]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status401Unauthorized)]
+ [ProducesResponseType(StatusCodes.Status500InternalServerError)]
+ public async Task> DeleteAsync(string id)
+ {
+ try
+ {
+ await _holidayService.DeleteAsync(Guid.Parse(id));
+
+ return Success();
+ }
+ catch (Exception ex)
+ {
+ return Error(ex);
+ }
+ }
+
+ ///
+ /// ลบรายการวันหยุด
+ ///
+ /// ช่วงวันที่ที่ต้องการลบ
+ /// ประเภทวันหยุด ส่งค่ามาเป็น normal / 6day
+ ///
+ /// ทำรายการสำเร็จ
+ /// ไม่ได้ Login เข้าระบบ
+ /// เมื่อเกิดข้อผิดพลาดในการทำงาน
+ [HttpPost("range/delete/{category}")]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status401Unauthorized)]
+ [ProducesResponseType(StatusCodes.Status500InternalServerError)]
+ public async Task> DeleteRangeAsync(List delete, string category)
+ {
+ try
+ {
+ var isNormal = category.ToUpper() == "NORMAL";
+ await _holidayService.DeleteRangeAsync(delete, isNormal);
+
+ return Success();
+ }
+ catch (Exception ex)
+ {
+ return Error(ex);
+ }
+ }
+
+ ///
+ /// คัดลอกข้อมูลวันหยุด โดยระบุปีที่ต้องการคัดลอก และ ปีที่ต้องการบันทึก
+ ///
+ /// Request Body
+ ///
+ [HttpPost("copy")]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status401Unauthorized)]
+ [ProducesResponseType(StatusCodes.Status500InternalServerError)]
+ public async Task> CopyAsync([FromBody] HolidayCopyRequest request)
+ {
+ try
+ {
+ await _holidayService.CopyAsync(request.FromYear, request.ToYear);
+
+ return Success();
+ }
+ catch (Exception ex)
+ {
+ return Error(ex);
+ }
+ }
+
+ ///
+ /// สรุปวันหยุดในแต่ละปี
+ ///
+ /// ปี่ที่ต้องการ
+ ///
+ /// เมื่อทำการอ่านข้อมูลจาก Relational Database สำเร็จ
+ /// ไม่ได้ Login เข้าระบบ
+ /// เมื่อเกิดข้อผิดพลาดในการทำงาน
+ [HttpGet("summary/{year:int}")]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status401Unauthorized)]
+ [ProducesResponseType(StatusCodes.Status500InternalServerError)]
+ public async Task> GetDataGroupMonthAsync(int year)
+ {
+ try
+ {
+ var items = await _holidayService.GetDataGroupMonthAsync(year);
+
+ return Success(items);
+ }
+ catch (Exception ex)
+ {
+ return Error(ex);
+ }
+ }
+
+ #endregion
+ }
+}
diff --git a/BMA.EHR.Leave/Request/HolidayCopyRequest.cs b/BMA.EHR.Leave/Request/HolidayCopyRequest.cs
new file mode 100644
index 00000000..21b04204
--- /dev/null
+++ b/BMA.EHR.Leave/Request/HolidayCopyRequest.cs
@@ -0,0 +1,10 @@
+
+namespace BMA.EHR.Leave.Service.Request
+{
+ public class HolidayCopyRequest
+ {
+ public int FromYear { get; set; } = DateTime.Now.Year;
+
+ public int ToYear { get; set; } = DateTime.Now.Year;
+ }
+}
diff --git a/BMA.EHR.Leave/Request/HolidayRequest.cs b/BMA.EHR.Leave/Request/HolidayRequest.cs
new file mode 100644
index 00000000..7ce9f895
--- /dev/null
+++ b/BMA.EHR.Leave/Request/HolidayRequest.cs
@@ -0,0 +1,15 @@
+
+namespace BMA.EHR.Leave.Service.Request
+{
+ public class HolidayRequest
+ {
+ public DateTime dateStart { get; set; } = DateTime.Now;
+
+ public DateTime dateEnd { get; set; } = DateTime.Now;
+
+ public int Year { get; set; } = DateTime.Now.Year;
+
+ public string Name { get; set; } = string.Empty;
+
+ }
+}
diff --git a/BMA.EHR.Leave/Request/HolidayUpdateRequest.cs b/BMA.EHR.Leave/Request/HolidayUpdateRequest.cs
new file mode 100644
index 00000000..91251c96
--- /dev/null
+++ b/BMA.EHR.Leave/Request/HolidayUpdateRequest.cs
@@ -0,0 +1,13 @@
+
+using BMA.EHR.Domain.Models.MetaData;
+
+namespace BMA.EHR.Leave.Service.Request
+{
+ public class HolidayUpdateRequest
+ {
+ public List history { get; set; }
+
+ public List updated { get; set; }
+
+ }
+}
diff --git a/BMA.EHR.Leave/Response/SummaryHolidayByMonthResponseItem.cs b/BMA.EHR.Leave/Response/SummaryHolidayByMonthResponseItem.cs
new file mode 100644
index 00000000..925779f2
--- /dev/null
+++ b/BMA.EHR.Leave/Response/SummaryHolidayByMonthResponseItem.cs
@@ -0,0 +1,14 @@
+namespace BMA.EHR.Leave.Service.Response
+{
+ public class SummaryHolidayByMonthResponseItem
+ {
+ public int? Id { get; set; }
+
+ public int? Count { get; set; }
+
+ public string? Month { get; set; }
+
+ public string? MonthFull { get; set; }
+
+ }
+}
diff --git a/BMA.EHR.Leave/Services/HolidayService.cs b/BMA.EHR.Leave/Services/HolidayService.cs
new file mode 100644
index 00000000..b7fd99ff
--- /dev/null
+++ b/BMA.EHR.Leave/Services/HolidayService.cs
@@ -0,0 +1,678 @@
+using System.Security.Claims;
+using BMA.EHR.Domain.Models.MetaData;
+using BMA.EHR.Domain.Shared;
+using BMA.EHR.Infrastructure.Persistence;
+using Microsoft.EntityFrameworkCore;
+using BMA.EHR.Domain.Extensions;
+using BMA.EHR.Leave.Service.Response;
+
+namespace BMA.EHR.Leave.Service.Services
+{
+ public class HolidayService
+ {
+ #region " Fields "
+
+ private readonly ApplicationDBContext _context;
+ private readonly IHttpContextAccessor _httpContextAccessor;
+
+ #endregion
+
+ #region " Constructor and Destructor "
+
+ public HolidayService(ApplicationDBContext context,
+ IHttpContextAccessor httpContextAccessor)
+ {
+ _context = context;
+ _httpContextAccessor = httpContextAccessor;
+ }
+
+ #endregion
+
+ #region " Properties "
+
+ private string? UserId => _httpContextAccessor?.HttpContext?.User?.FindFirst(ClaimTypes.NameIdentifier)?.Value;
+
+ private string? FullName => _httpContextAccessor?.HttpContext?.User?.FindFirst("name")?.Value;
+
+ #endregion
+
+ #region " Methods "
+
+ #region " Private "
+
+ private async Task IsHoliday(DateTime date)
+ {
+ var holidays = (await GetsAsync(date.Date.Year))
+ .Where(d => d.Category.ToUpper() == "NORMAL")
+ .Select(d => d.HolidayDate.Date).ToList();
+
+ if (holidays.Any())
+ {
+ return holidays.Contains(date);
+ }
+ else
+ return false;
+ }
+
+ private async Task IsHoliday6Days(DateTime date)
+ {
+ var holidays = (await GetsAsync(date.Date.Year))
+ .Where(d => d.Category.ToUpper() != "NORMAL")
+ .Select(d => d.HolidayDate.Date).ToList();
+
+ if (holidays.Any())
+ {
+ return holidays.Contains(date);
+ }
+ else
+ return false;
+ }
+
+ private async Task IsWeekend(DateTime date)
+ {
+ var res = date.DayOfWeek == DayOfWeek.Saturday
+ || date.DayOfWeek == DayOfWeek.Sunday;
+
+ return await Task.FromResult(res);
+ }
+
+ private async Task IsWeekend6Days(DateTime date)
+ {
+ var res = date.DayOfWeek == DayOfWeek.Sunday;
+
+ return await Task.FromResult(res);
+ }
+
+ private async Task GetNextWorkingDay(DateTime date)
+ {
+ while ((await IsHoliday(date)) || (await IsWeekend(date)))
+ {
+ date = date.AddDays(1);
+ }
+
+ return date;
+ }
+
+ private async Task GetNextWorkingDay6Days(DateTime date)
+ {
+ while ((await IsHoliday6Days(date)) || (await IsWeekend6Days(date)))
+ {
+ date = date.AddDays(1);
+ }
+
+ return date;
+ }
+
+ private async Task CheckWorkingDay(DateTime date)
+ {
+
+ while ((await IsHoliday(date)) || (await IsWeekend(date)))
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ private async Task CheckWorkingDay6Days(DateTime date)
+ {
+
+ while ((await IsHoliday6Days(date)) || (await IsWeekend6Days(date)))
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ #endregion
+
+
+ public async Task> GetsAsync(int year, bool showSpecial = true)
+ {
+ var holidays = _context.Holidays.AsQueryable()
+ .Where(x => x.Year == year.ToCeYear());
+
+ if (!showSpecial)
+ {
+ holidays = holidays.Where(x => !x.IsSpecial);
+ }
+
+ return await holidays.OrderBy(d => d.HolidayDate.Date).ToListAsync();
+ }
+
+ public async Task> GetNormalAsync(int year, bool showSpecial = true)
+ {
+ var holidays = _context.Holidays.AsQueryable()
+ .Where(x => x.Category.ToUpper() == "NORMAL")
+ .Where(x => x.Year == year.ToCeYear());
+
+ if (!showSpecial)
+ {
+ holidays = holidays.Where(x => !x.IsSpecial);
+ }
+
+ return await holidays.OrderBy(d => d.HolidayDate.Date).ToListAsync();
+ }
+
+ public async Task> Get6DayAsync(int year, bool showSpecial = true)
+ {
+ var holidays = _context.Holidays.AsQueryable()
+ .Where(x => x.Category.ToUpper() != "NORMAL")
+ .Where(x => x.Year == year.ToCeYear());
+
+ if (!showSpecial)
+ {
+ holidays = holidays.Where(x => !x.IsSpecial);
+ }
+
+ return await holidays.OrderBy(d => d.HolidayDate.Date).ToListAsync();
+ }
+
+ public async Task> GetsAsyncByMonth(int year, int month)
+ {
+ return await _context.Holidays.AsQueryable()
+ .Where(x => x.Year == year.ToCeYear())
+ .Where(x => x.HolidayDate.Month == month)
+ .OrderBy(d => d.HolidayDate.Date)
+ .ToListAsync();
+ }
+
+ public async Task> GetNormalByMonthAsync(int year, int month)
+ {
+ return await _context.Holidays.AsQueryable()
+ .Where(x => x.Category.ToUpper() == "NORMAL")
+ .Where(x => x.Year == year.ToCeYear())
+ .Where(x => x.HolidayDate.Month == month)
+ .OrderBy(d => d.HolidayDate.Date)
+ .ToListAsync();
+ }
+
+ public async Task> Get6DayByMonthAsync(int year, int month)
+ {
+ return await _context.Holidays.AsQueryable()
+ .Where(x => x.Category.ToUpper() != "NORMAL")
+ .Where(x => x.Year == year.ToCeYear())
+ .Where(x => x.HolidayDate.Month == month)
+ .OrderBy(d => d.HolidayDate.Date)
+ .ToListAsync();
+ }
+
+ public async Task GetByIdAsync(Guid id)
+ {
+ return await _context.Holidays.FirstOrDefaultAsync(x => x.Id == id);
+ }
+
+ public async Task DeleteAsync(Guid id)
+ {
+ var existData = await _context.Holidays.FirstOrDefaultAsync(x => x.Id == id);
+ if (existData != null)
+ {
+ _context.Holidays.Remove(existData);
+ await _context.SaveChangesAsync();
+ }
+ }
+
+ public async Task DeleteRangeAsync(List holidays, bool isNormal = true)
+ {
+ foreach (var holiday in holidays)
+ {
+ if (isNormal)
+ {
+ var existData = await _context.Holidays.AsQueryable()
+ .Where(h => h.Category.ToUpper() == "NORMAL")
+ .FirstOrDefaultAsync(x => DateTime.Compare(x.HolidayDate.Date, holiday.HolidayDate.Date) == 0);
+ if (existData != null)
+ {
+ _context.Holidays.Remove(existData);
+ await _context.SaveChangesAsync();
+ }
+ }
+ else
+ {
+ var existData = await _context.Holidays.AsQueryable()
+ .Where(h => h.Category.ToUpper() != "NORMAL")
+ .FirstOrDefaultAsync(x => DateTime.Compare(x.HolidayDate.Date, holiday.HolidayDate.Date) == 0);
+ if (existData != null)
+ {
+ _context.Holidays.Remove(existData);
+ await _context.SaveChangesAsync();
+ }
+ }
+ }
+ }
+
+ public async Task UpdateAsync(Guid id, Holiday updated)
+ {
+ var existData = await _context.Holidays.FirstOrDefaultAsync(x => x.Id == id);
+ if (existData != null)
+ {
+ // if (!existData.Compare(updated))
+ if (existData.Name != updated.Name)
+ {
+ existData.Name = updated.Name;
+ // existData.Year = updated.Year.ToCeYear();
+ existData.HolidayDate = updated.HolidayDate.Date;
+ // existData.HolidayDate = await GetNextWorkingDay(updated.HolidayDate.Date);
+ existData.OriginalDate = updated.OriginalDate;
+ existData.LastUpdatedAt = DateTime.Now;
+ existData.LastUpdateUserId = UserId ?? "";
+ existData.LastUpdateFullName = FullName ?? "";
+
+ await _context.SaveChangesAsync();
+ }
+ }
+ }
+
+ public async Task UpdateRangeAsync(List historys, List holidays, bool isNormal = true)
+ {
+ if (isNormal)
+ {
+ // foreach (var holiday in holidays)
+ // {
+ // var dupData = await _context.Holidays.AsQueryable()
+ // .Where(h => h.Category.ToUpper() == "NORMAL")
+ // .FirstOrDefaultAsync(h => h.Year == holiday.Year && h.Name == holiday.Name && DateTime.Compare(h.HolidayDate.Date, holiday.HolidayDate.Date) != 0);
+ // if (dupData != null)
+ // throw new Exception(GlobalMessages.NameDupicate);
+ // }
+
+ foreach (var history in historys)
+ {
+ var existData = await _context.Holidays.AsQueryable()
+ .Where(h => h.Category.ToUpper() == "NORMAL")
+ .FirstOrDefaultAsync(x => DateTime.Compare(x.HolidayDate.Date, history.HolidayDate.Date) == 0);
+ if (existData != null)
+ {
+ _context.Holidays.Remove(existData);
+ await _context.SaveChangesAsync();
+ }
+ }
+
+ foreach (var holiday in holidays)
+ {
+ // if (!(await IsHoliday(holiday.HolidayDate.Date)) && !(await IsWeekend(holiday.HolidayDate.Date)))
+ // {
+ await CreateAsync(holiday);
+ // }
+ }
+ // apply to database
+ await _context.SaveChangesAsync();
+ }
+ else
+ {
+ // foreach (var holiday in holidays)
+ // {
+ // var dupData = await _context.Holidays.AsQueryable()
+ // .Where(h => h.Category.ToUpper() != "NORMAL")
+ // .FirstOrDefaultAsync(h => h.Year == holiday.Year && h.Name == holiday.Name && DateTime.Compare(h.HolidayDate.Date, holiday.HolidayDate.Date) != 0);
+ // if (dupData != null)
+ // throw new Exception(GlobalMessages.NameDupicate);
+ // }
+
+ foreach (var history in historys)
+ {
+ var existData = await _context.Holidays.AsQueryable()
+ .Where(h => h.Category.ToUpper() != "NORMAL")
+ .FirstOrDefaultAsync(x => DateTime.Compare(x.HolidayDate.Date, history.HolidayDate.Date) == 0);
+ if (existData != null)
+ {
+ _context.Holidays.Remove(existData);
+ await _context.SaveChangesAsync();
+ }
+ }
+
+ foreach (var holiday in holidays)
+ {
+ // if (!(await IsHoliday6Days(holiday.HolidayDate.Date)) && !(await IsWeekend6Days(holiday.HolidayDate.Date)))
+ // {
+ await Create6DayAsync(holiday);
+ // }
+ }
+ // apply to database
+ await _context.SaveChangesAsync();
+ }
+
+ }
+
+ public async Task CreateAsync(Holiday inserted)
+ {
+ var existData = await _context.Holidays.AsQueryable()
+ .Where(d => d.Category.ToUpper() == "NORMAL")
+ .FirstOrDefaultAsync(h => h.Year == inserted.Year && DateTime.Compare(h.HolidayDate.Date, inserted.HolidayDate.Date) == 0);
+
+ if (existData != null)
+ throw new Exception(GlobalMessages.DataExist5);
+
+ // var dupData = await _context.Holidays.AsQueryable()
+ // .Where(d => d.Category.ToUpper() == "NORMAL")
+ // .FirstOrDefaultAsync(h => h.Year == inserted.Year && h.Name == inserted.Name);
+
+ // if (dupData != null)
+ // throw new Exception(GlobalMessages.NameDupicate);
+
+ inserted.Id = Guid.NewGuid();
+ inserted.Year = inserted.Year.ToCeYear();
+ inserted.HolidayDate = inserted.HolidayDate.Date;
+ // inserted.HolidayDate = await GetNextWorkingDay(inserted.HolidayDate.Date);
+ inserted.OriginalDate = inserted.HolidayDate.Date;
+ inserted.CreatedUserId = UserId ?? "";
+ inserted.CreatedFullName = FullName ?? "System Administrator";
+ inserted.CreatedAt = DateTime.Now;
+ inserted.LastUpdatedAt = DateTime.Now;
+ inserted.LastUpdateFullName = FullName ?? "System Administrator";
+ inserted.LastUpdateUserId = UserId ?? "";
+ inserted.Category = "NORMAL";
+
+ await _context.Holidays.AddAsync(inserted);
+
+ // apply to database
+ // await _context.SaveChangesAsync();
+ }
+
+ public async Task Create6DayAsync(Holiday inserted)
+ {
+ var existData = await _context.Holidays.AsQueryable()
+ .Where(d => d.Category.ToUpper() != "NORMAL")
+ .FirstOrDefaultAsync(h => h.Year == inserted.Year && DateTime.Compare(h.HolidayDate.Date, inserted.HolidayDate.Date) == 0);
+
+ if (existData != null)
+ throw new Exception(GlobalMessages.DataExist6);
+
+ // var dupData = await _context.Holidays.AsQueryable()
+ // .Where(d => d.Category.ToUpper() != "NORMAL")
+ // .FirstOrDefaultAsync(h => h.Year == inserted.Year && h.Name == inserted.Name);
+
+ // if (dupData != null)
+ // throw new Exception(GlobalMessages.NameDupicate);
+
+ inserted.Id = Guid.NewGuid();
+ inserted.Year = inserted.Year.ToCeYear();
+ inserted.HolidayDate = inserted.HolidayDate.Date;
+ // inserted.HolidayDate = await GetNextWorkingDay6Days(inserted.HolidayDate.Date);
+ inserted.OriginalDate = inserted.HolidayDate.Date;
+ inserted.CreatedUserId = UserId ?? "";
+ inserted.CreatedFullName = FullName ?? "System Administrator";
+ inserted.CreatedAt = DateTime.Now;
+ inserted.LastUpdatedAt = DateTime.Now;
+ inserted.LastUpdateFullName = FullName ?? "System Administrator";
+ inserted.LastUpdateUserId = UserId ?? "";
+ inserted.Category = "6DAYS";
+
+ await _context.Holidays.AddAsync(inserted);
+
+ // apply to database
+ // await _context.SaveChangesAsync();
+ }
+
+ public async Task CreateRangeAsync(List holidays, string category)
+ {
+ foreach (var holiday in holidays)
+ {
+ if (category.ToUpper() == "NORMAL" || category.ToUpper() == "ALL")
+ {
+ var existData1 = await _context.Holidays.AsQueryable()
+ .Where(d => d.Category.ToUpper() == "NORMAL")
+ .FirstOrDefaultAsync(h => h.Year == holiday.Year && DateTime.Compare(h.HolidayDate.Date, holiday.HolidayDate.Date) == 0);
+
+ if (existData1 != null)
+ throw new Exception(GlobalMessages.DataExist5);
+
+ // var dupData1 = await _context.Holidays.AsQueryable()
+ // .Where(d => d.Category.ToUpper() != "NORMAL")
+ // .FirstOrDefaultAsync(h => h.Year == holiday.Year && h.Name == holiday.Name);
+
+ // if (dupData1 != null)
+ // throw new Exception(GlobalMessages.NameDupicate);
+
+ // create for normal
+ var inserted = new Holiday
+ {
+ Id = Guid.NewGuid(),
+ Year = holiday.Year.ToCeYear(),
+ Name = holiday.Name,
+ HolidayDate = holiday.HolidayDate.Date,
+ OriginalDate = holiday.HolidayDate.Date,
+ CreatedUserId = UserId ?? "",
+ CreatedFullName = FullName ?? "System Administrator",
+ CreatedAt = DateTime.Now,
+ LastUpdatedAt = DateTime.Now,
+ LastUpdateFullName = FullName ?? "System Administrator",
+ LastUpdateUserId = UserId ?? "",
+ Category = "NORMAL",
+ };
+
+ await _context.Holidays.AddAsync(inserted);
+ }
+
+ if (category.ToUpper() == "6DAYS" || category.ToUpper() == "ALL")
+ {
+ var existData2 = await _context.Holidays.AsQueryable()
+ .Where(d => d.Category.ToUpper() != "NORMAL")
+ .FirstOrDefaultAsync(h => h.Year == holiday.Year && DateTime.Compare(h.HolidayDate.Date, holiday.HolidayDate.Date) == 0);
+
+ if (existData2 != null)
+ throw new Exception(GlobalMessages.DataExist6);
+
+ // var dupData2 = await _context.Holidays.AsQueryable()
+ // .Where(d => d.Category.ToUpper() != "6DAYS")
+ // .FirstOrDefaultAsync(h => h.Year == holiday.Year && h.Name == holiday.Name);
+
+ // if (dupData2 != null)
+ // throw new Exception(GlobalMessages.NameDupicate);
+
+ // create for 6days
+ var inserted2 = new Holiday
+ {
+ Id = Guid.NewGuid(),
+ Year = holiday.Year.ToCeYear(),
+ Name = holiday.Name,
+ HolidayDate = holiday.HolidayDate.Date,
+ OriginalDate = holiday.HolidayDate.Date,
+ CreatedUserId = UserId ?? "",
+ CreatedFullName = FullName ?? "System Administrator",
+ CreatedAt = DateTime.Now,
+ LastUpdatedAt = DateTime.Now,
+ LastUpdateFullName = FullName ?? "System Administrator",
+ LastUpdateUserId = UserId ?? "",
+ Category = "6DAYS",
+ };
+ await _context.Holidays.AddAsync(inserted2);
+ }
+ }
+ // apply to database
+ await _context.SaveChangesAsync();
+ }
+
+ public async Task CopyAsync(int fromYear, int toYear)
+ {
+ if (toYear <= fromYear)
+ throw new Exception(GlobalMessages.HolidayOfYearNotCopy);
+
+ var source = await GetsAsync(fromYear.ToCeYear());
+ if (source == null)
+ throw new Exception(GlobalMessages.HolidayOfYearNotFound);
+
+ // JACK EDIT : เพิ่ม Logic การตรวจเช็คว่าปีที่จะ Copy ไปมีในฐานข้อมูลแล้วหรือไม่?
+ var dest = await GetsAsync(toYear.ToCeYear());
+ if (dest.Count() > 0)
+ throw new Exception(GlobalMessages.DestinationHolidayIsExist);
+ source = source.Where(x => x.Category == "NORMAL");
+ foreach (var holiday in source)
+ {
+ // create for normal
+ var inserted = new Holiday
+ {
+ Id = Guid.NewGuid(),
+ Year = toYear.ToCeYear(),
+ Name = holiday.Name,
+ HolidayDate = await GetNextWorkingDay(holiday.OriginalDate.AddYears(toYear - fromYear)),
+ OriginalDate = holiday.OriginalDate.AddYears(toYear - fromYear),
+ CreatedUserId = UserId ?? "",
+ CreatedFullName = FullName ?? "",
+ CreatedAt = DateTime.Now,
+ Category = "NORMAL"
+ };
+
+ await _context.Holidays.AddAsync(inserted);
+
+
+ // create for 6days
+ var inserted2 = new Holiday
+ {
+ Id = Guid.NewGuid(),
+ Year = toYear.ToCeYear(),
+ Name = holiday.Name,
+ HolidayDate = await GetNextWorkingDay6Days(holiday.OriginalDate.AddYears(toYear - fromYear)),
+ OriginalDate = holiday.OriginalDate.AddYears(toYear - fromYear),
+ CreatedUserId = UserId ?? "",
+ CreatedFullName = FullName ?? "",
+ CreatedAt = DateTime.Now,
+ Category = "6DAYS"
+ };
+ await _context.Holidays.AddAsync(inserted2);
+
+ // apply to database
+ await _context.SaveChangesAsync();
+ }
+ }
+
+ public async Task SaveDatabase()
+ {
+ // apply to database
+ await _context.SaveChangesAsync();
+ }
+
+ public async Task> GetDataGroupMonthAsync(int year)
+ {
+ var res = new List
+ {new SummaryHolidayByMonthResponseItem
+ {
+ Id = 1,
+ Count = _context.Holidays.AsQueryable()
+ .Where(h => h.Category.ToUpper() == "NORMAL")
+ .Where(x => x.Year == year.ToCeYear())
+ .Where(x => x.HolidayDate.Month == 1)
+ .OrderBy(d => d.Name).Count(),
+ Month = "ม.ค.",
+ MonthFull = "มกราคม",
+ },new SummaryHolidayByMonthResponseItem
+ {
+ Id = 2,
+ Count = _context.Holidays.AsQueryable()
+ .Where(h => h.Category.ToUpper() == "NORMAL")
+ .Where(x => x.Year == year.ToCeYear())
+ .Where(x => x.HolidayDate.Month == 2)
+ .OrderBy(d => d.Name).Count(),
+ Month = "ก.พ.",
+ MonthFull = "กุมภาพันธ์",
+ },new SummaryHolidayByMonthResponseItem
+ {
+ Id = 3,
+ Count = _context.Holidays.AsQueryable()
+ .Where(h => h.Category.ToUpper() == "NORMAL")
+ .Where(x => x.Year == year.ToCeYear())
+ .Where(x => x.HolidayDate.Month == 3)
+ .OrderBy(d => d.Name).Count(),
+ Month = "มี.ค.",
+ MonthFull = "มีนาคม",
+ },new SummaryHolidayByMonthResponseItem
+ {
+ Id = 4,
+ Count = _context.Holidays.AsQueryable()
+ .Where(h => h.Category.ToUpper() == "NORMAL")
+ .Where(x => x.Year == year.ToCeYear())
+ .Where(x => x.HolidayDate.Month == 4)
+ .OrderBy(d => d.Name).Count(),
+ Month = "เม.ย.",
+ MonthFull = "เมษายน",
+ },new SummaryHolidayByMonthResponseItem
+ {
+ Id = 5,
+ Count = _context.Holidays.AsQueryable()
+ .Where(h => h.Category.ToUpper() == "NORMAL")
+ .Where(x => x.Year == year.ToCeYear())
+ .Where(x => x.HolidayDate.Month == 5)
+ .OrderBy(d => d.Name).Count(),
+ Month = "พ.ค.",
+ MonthFull = "พฤษภาคม",
+ },new SummaryHolidayByMonthResponseItem
+ {
+ Id = 6,
+ Count = _context.Holidays.AsQueryable()
+ .Where(h => h.Category.ToUpper() == "NORMAL")
+ .Where(x => x.Year == year.ToCeYear())
+ .Where(x => x.HolidayDate.Month == 6)
+ .OrderBy(d => d.Name).Count(),
+ Month = "มิ.ย.",
+ MonthFull = "มิถุนายน",
+ },new SummaryHolidayByMonthResponseItem
+ {
+ Id = 7,
+ Count = _context.Holidays.AsQueryable()
+ .Where(h => h.Category.ToUpper() == "NORMAL")
+ .Where(x => x.Year == year.ToCeYear())
+ .Where(x => x.HolidayDate.Month == 7)
+ .OrderBy(d => d.Name).Count(),
+ Month = "ก.ค.",
+ MonthFull = "กรกฎาคม",
+ },new SummaryHolidayByMonthResponseItem
+ {
+ Id = 8,
+ Count = _context.Holidays.AsQueryable()
+ .Where(h => h.Category.ToUpper() == "NORMAL")
+ .Where(x => x.Year == year.ToCeYear())
+ .Where(x => x.HolidayDate.Month == 8)
+ .OrderBy(d => d.Name).Count(),
+ Month = "ส.ค.",
+ MonthFull = "สิงหาคม",
+ },new SummaryHolidayByMonthResponseItem
+ {
+ Id = 9,
+ Count = _context.Holidays.AsQueryable()
+ .Where(h => h.Category.ToUpper() == "NORMAL")
+ .Where(x => x.Year == year.ToCeYear())
+ .Where(x => x.HolidayDate.Month == 9)
+ .OrderBy(d => d.Name).Count(),
+ Month = "ก.ย.",
+ MonthFull = "กันยายน",
+ },new SummaryHolidayByMonthResponseItem
+ {
+ Id = 10,
+ Count = _context.Holidays.AsQueryable()
+ .Where(h => h.Category.ToUpper() == "NORMAL")
+ .Where(x => x.Year == year.ToCeYear())
+ .Where(x => x.HolidayDate.Month == 10)
+ .OrderBy(d => d.Name).Count(),
+ Month = "ต.ค.",
+ MonthFull = "ตุลาคม",
+ },new SummaryHolidayByMonthResponseItem
+ {
+ Id = 11,
+ Count = _context.Holidays.AsQueryable()
+ .Where(h => h.Category.ToUpper() == "NORMAL")
+ .Where(x => x.Year == year.ToCeYear())
+ .Where(x => x.HolidayDate.Month == 11)
+ .OrderBy(d => d.Name).Count(),
+ Month = "พ.ย.",
+ MonthFull = "พฤศจิกายน",
+ },new SummaryHolidayByMonthResponseItem
+ {
+ Id = 12,
+ Count = _context.Holidays.AsQueryable()
+ .Where(h => h.Category.ToUpper() == "NORMAL")
+ .Where(x => x.Year == year.ToCeYear())
+ .Where(x => x.HolidayDate.Month == 12)
+ .OrderBy(d => d.Name).Count(),
+ Month = "ธ.ค.",
+ MonthFull = "ธันวาคม",
+ }
+ };
+
+
+ return await Task.FromResult(res);
+ }
+
+ #endregion
+ }
+}
diff --git a/BMA.EHR.Placement.Service/Controllers/MessageController.cs b/BMA.EHR.Placement.Service/Controllers/MessageController.cs
new file mode 100644
index 00000000..c4434eb1
--- /dev/null
+++ b/BMA.EHR.Placement.Service/Controllers/MessageController.cs
@@ -0,0 +1,190 @@
+using BMA.EHR.Application.Repositories.MessageQueue;
+using BMA.EHR.Domain.Common;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+using Swashbuckle.AspNetCore.Annotations;
+
+namespace BMA.EHR.Placement.Service.Controllers
+{
+ [Route("api/v{version:apiVersion}/placement/message")]
+ [ApiVersion("1.0")]
+ [ApiController]
+ [Produces("application/json")]
+ [Authorize]
+ [SwaggerTag("API ระบบ Inbox และ Notification")]
+ public class MessageController : BaseController
+ {
+ #region " Fields "
+
+ private readonly InboxRepository _inboxRepository;
+ private readonly NotificationRepository _notificationRepository;
+
+ #endregion
+
+ #region " Constuctor and Destructor "
+
+ public MessageController(InboxRepository inboxRepository,
+ NotificationRepository notificationRepository)
+ {
+ _inboxRepository = inboxRepository;
+ _notificationRepository = notificationRepository;
+ }
+
+ #endregion
+
+ #region " Methods "
+
+ ///
+ /// แสดงข้อมูล Inbox ของ user ที่ Login
+ ///
+ ///
+ /// เมื่อทำการอ่านข้อมูลจาก Relational Database สำเร็จ
+ /// ไม่ได้ Login เข้าระบบ
+ /// เมื่อเกิดข้อผิดพลาดในการทำงาน
+ [HttpGet("my-inboxes")]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status401Unauthorized)]
+ [ProducesResponseType(StatusCodes.Status500InternalServerError)]
+ public async Task> GetMyInboxAsync(int page = 1, int pageSize = 20)
+ {
+ try
+ {
+ var inboxes = await _inboxRepository.GetMyInboxAsync(page, pageSize);
+
+ return Success(inboxes);
+ }
+ catch
+ {
+ throw;
+ }
+ }
+
+ ///
+ /// ดูข้อมูล Inbox ของ user ที่ Login
+ ///
+ ///
+ /// เมื่อทำการอ่านข้อมูลจาก Relational Database สำเร็จ
+ /// ไม่ได้ Login เข้าระบบ
+ /// เมื่อเกิดข้อผิดพลาดในการทำงาน
+ [HttpGet("my-inboxes/{id:length(36)}")]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status401Unauthorized)]
+ [ProducesResponseType(StatusCodes.Status500InternalServerError)]
+ public async Task> GetByIdMyInboxAsync(Guid id)
+ {
+ try
+ {
+ await _inboxRepository.GetByIdMyInboxAsync(id);
+
+ return Success();
+ }
+ catch
+ {
+ throw;
+ }
+ }
+
+ ///
+ /// ลบข้อมูล Inbox ของ user ที่ Login
+ ///
+ ///
+ /// เมื่อทำการอ่านข้อมูลจาก Relational Database สำเร็จ
+ /// ไม่ได้ Login เข้าระบบ
+ /// เมื่อเกิดข้อผิดพลาดในการทำงาน
+ [HttpDelete("my-inboxes/{id:length(36)}")]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status401Unauthorized)]
+ [ProducesResponseType(StatusCodes.Status500InternalServerError)]
+ public async Task> DeleteMyInboxAsync(Guid id)
+ {
+ try
+ {
+ await _inboxRepository.DeleteMyInboxAsync(id);
+
+ return Success();
+ }
+ catch
+ {
+ throw;
+ }
+ }
+
+ ///
+ /// แสดงข้อมูล Notification ของ user ที่ Login
+ ///
+ ///
+ /// เมื่อทำการอ่านข้อมูลจาก Relational Database สำเร็จ
+ /// ไม่ได้ Login เข้าระบบ
+ /// เมื่อเกิดข้อผิดพลาดในการทำงาน
+ [HttpGet("my-notifications")]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status401Unauthorized)]
+ [ProducesResponseType(StatusCodes.Status500InternalServerError)]
+ public async Task> GetMyNotificationAsync(int page = 1, int pageSize = 20)
+ {
+ try
+ {
+ var noti = await _notificationRepository.GetMyNotificationAsync(page, pageSize);
+
+ return Success(noti);
+ }
+ catch
+ {
+ throw;
+ }
+ }
+
+ ///
+ /// แสดงข้อมูล Notification ของ user ที่ Login ที่ยังไม่ได้อ่าน
+ ///
+ ///
+ /// เมื่อทำการอ่านข้อมูลจาก Relational Database สำเร็จ
+ /// ไม่ได้ Login เข้าระบบ
+ /// เมื่อเกิดข้อผิดพลาดในการทำงาน
+ [HttpGet("my-notifications/noread")]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status401Unauthorized)]
+ [ProducesResponseType(StatusCodes.Status500InternalServerError)]
+ public async Task> GetMyNotificationAsyncNoread()
+ {
+ try
+ {
+ var noti = await _notificationRepository.GetMyNotificationAsyncNoread();
+
+ return Success(noti);
+ }
+ catch
+ {
+ throw;
+ }
+ }
+
+ ///
+ /// ลบข้อมูล Notification ของ user ที่ Login
+ ///
+ ///
+ /// เมื่อทำการอ่านข้อมูลจาก Relational Database สำเร็จ
+ /// ไม่ได้ Login เข้าระบบ
+ /// เมื่อเกิดข้อผิดพลาดในการทำงาน
+ [HttpDelete("my-notifications/{id:length(36)}")]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status401Unauthorized)]
+ [ProducesResponseType(StatusCodes.Status500InternalServerError)]
+ public async Task> DeleteMyNotificationAsync(Guid id)
+ {
+ try
+ {
+ await _notificationRepository.DeleteMyNotificationAsync(id);
+
+ return Success();
+ }
+ catch
+ {
+ throw;
+ }
+ }
+
+
+ #endregion
+ }
+}
diff --git a/BMA.EHR.Placement.Service/Controllers/NotifyController.cs b/BMA.EHR.Placement.Service/Controllers/NotifyController.cs
index 8ef642fa..cfead6d4 100644
--- a/BMA.EHR.Placement.Service/Controllers/NotifyController.cs
+++ b/BMA.EHR.Placement.Service/Controllers/NotifyController.cs
@@ -1,10 +1,6 @@
using BMA.EHR.Application.Repositories;
using BMA.EHR.Application.Repositories.MessageQueue;
using BMA.EHR.Domain.Common;
-using BMA.EHR.Domain.Extensions;
-using BMA.EHR.Domain.Models.MetaData;
-using BMA.EHR.Domain.Models.Notifications;
-using BMA.EHR.Domain.Models.Placement;
using BMA.EHR.Domain.Models.Probation;
using BMA.EHR.Domain.Shared;
using BMA.EHR.Infrastructure.Persistence;
@@ -18,7 +14,6 @@ using RabbitMQ.Client;
using Swashbuckle.AspNetCore.Annotations;
using System.Net.Http.Headers;
using System.Security.Claims;
-using System.Security.Cryptography;
using System.Text;
namespace BMA.EHR.Placement.Service.Controllers