Merge branch 'develop' of github.com:Frappet/hrms-api-backend into develop

This commit is contained in:
moss 2025-04-23 09:33:01 +07:00
commit b4c169be75
12 changed files with 2126 additions and 225 deletions

View file

@ -74,6 +74,7 @@ namespace BMA.EHR.Application.Repositories.Leaves.LeaveRequests
{
var data = await _dbContext.Set<LeaveRequest>().AsQueryable()
//.AsNoTracking()
.Include(x => x.Approvers)
.Include(x => x.LeaveDocument)
.ThenInclude(x => x.Document)
.Include(x => x.LeaveDraftDocument)
@ -88,6 +89,7 @@ namespace BMA.EHR.Application.Repositories.Leaves.LeaveRequests
{
var data = await _dbContext.Set<LeaveRequest>().AsQueryable()
.AsNoTracking()
.Include(x => x.Approvers)
.Include(x => x.LeaveDocument)
.ThenInclude(x => x.Document)
.Include(x => x.LeaveDraftDocument)
@ -508,6 +510,10 @@ namespace BMA.EHR.Application.Repositories.Leaves.LeaveRequests
public async Task CommanderApproveLeaveRequest(Guid id, string reason)
{
// Get UserId from token
var userId = UserId == null ? Guid.Empty : Guid.Parse(UserId);
var rawData = await GetByIdAsync(id);
if (rawData == null)
{
@ -516,18 +522,117 @@ namespace BMA.EHR.Application.Repositories.Leaves.LeaveRequests
if (rawData.ApproveStep != "st2")
{
throw new Exception("คำขอนี้ยังไม่ได้รับการอนุมัติจากเจ้าหน้าที่ ไม่สามารถทำรายการได้");
throw new Exception("คำขอนี้ยังไม่ได้อยู่ในขั้นตอนที่สามารถอนุมัติได้ ไม่สามารถทำรายการได้");
}
rawData.LeaveStatus = "PENDING";
rawData.LeaveComment = reason;
rawData.ApproveStep = "st3";
// check commander approve
var approvers = rawData.Approvers.Where(x => x.ApproveType!.ToUpper() == "COMMANDER").OrderBy(x => x.Seq).ToList();
var maxSeq = approvers.Max(x => x.Seq);
var approver = approvers.FirstOrDefault(x => x.KeycloakId == userId);
if (approver == null)
{
throw new Exception("คุณไม่มีสิทธิ์อนุมัติการลาในขั้นตอนนี้");
}
approver.ApproveStatus = "APPROVE";
approver.Comment = reason;
if (approver.Seq != maxSeq)
{
var nextApprover = approvers.FirstOrDefault(x => x.Seq == approver.Seq + 1);
// Send Noti
var noti = new Notification
{
Body = $"การขอลาของคุณ {rawData.FirstName} {rawData.LastName} รอรับการอนุมัติจากคุณ",
ReceiverUserId = nextApprover!.ProfileId,
Type = "",
Payload = "",
};
_appDbContext.Set<Notification>().Add(noti);
await _appDbContext.SaveChangesAsync();
rawData.LeaveStatus = "PENDING";
await UpdateAsync(rawData);
}
else
{
rawData.LeaveStatus = "PENDING";
rawData.LeaveComment = reason;
rawData.ApproveStep = "st3";
await UpdateAsync(rawData);
}
}
public async Task CommanderRejectLeaveRequest(Guid id, string reason)
{
// Get UserId from token
var userId = UserId == null ? Guid.Empty : Guid.Parse(UserId);
var rawData = await GetByIdAsync(id);
if (rawData == null)
{
throw new Exception(GlobalMessages.DataNotFound);
}
if (rawData.ApproveStep != "st2")
{
throw new Exception("คำขอนี้ยังไม่ได้อยู่ในขั้นตอนที่สามารถอนุมัติได้ ไม่สามารถทำรายการได้");
}
// check commander approve
var approvers = rawData.Approvers.Where(x => x.ApproveType!.ToUpper() == "COMMANDER").OrderBy(x => x.Seq).ToList();
var maxSeq = approvers.Max(x => x.Seq);
var approver = approvers.FirstOrDefault(x => x.KeycloakId == userId);
if (approver == null)
{
throw new Exception("คุณไม่มีสิทธิ์อนุมัติการลาในขั้นตอนนี้");
}
approver.ApproveStatus = "REJECT";
approver.Comment = reason;
if (approver.Seq != maxSeq)
{
var nextApprover = approvers.FirstOrDefault(x => x.Seq == approver.Seq + 1);
// Send Noti
var noti = new Notification
{
Body = $"การขอลาของคุณ {rawData.FirstName} {rawData.LastName} รอรับการอนุมัติจากคุณ",
ReceiverUserId = nextApprover!.ProfileId,
Type = "",
Payload = "",
};
_appDbContext.Set<Notification>().Add(noti);
await _appDbContext.SaveChangesAsync();
rawData.LeaveStatus = "PENDING";
await UpdateAsync(rawData);
}
else
{
rawData.LeaveStatus = "PENDING";
rawData.LeaveComment = reason;
rawData.ApproveStep = "st3";
await UpdateAsync(rawData);
}
await UpdateAsync(rawData);
}
public async Task ApproveLeaveRequest(Guid id, string reason)
{
// Get UserId from token
var userId = UserId == null ? Guid.Empty : Guid.Parse(UserId);
var rawData = await GetByIdAsync(id);
if (rawData == null)
{
@ -536,107 +641,125 @@ namespace BMA.EHR.Application.Repositories.Leaves.LeaveRequests
if (rawData.ApproveStep != "st3")
{
throw new Exception("คำขอนี้ยังไม่ได้รับการอนุมัติจากผู้บังคับบัญชา ไม่สามารถทำรายการได้");
throw new Exception("คำขอนี้ยังไม่ได้อยู่ในขั้นตอนที่สามารถอนุมัติได้ ไม่สามารถทำรายการได้");
}
var profile = await _userProfileRepository.GetProfileByKeycloakIdAsync(rawData.KeycloakUserId, AccessToken);
if (profile == null)
// check commander approve
var approvers = rawData.Approvers.Where(x => x.ApproveType!.ToUpper() == "APPROVER").OrderBy(x => x.Seq).ToList();
var maxSeq = approvers.Max(x => x.Seq);
var approver = approvers.FirstOrDefault(x => x.KeycloakId == userId);
if (approver == null)
{
throw new Exception(GlobalMessages.DataNotFound);
throw new Exception("คุณไม่มีสิทธิ์อนุมัติการลาในขั้นตอนนี้");
}
rawData.LeaveStatus = "APPROVE";
rawData.LeaveDirectorComment = reason;
rawData.ApproveStep = "st4";
approver.ApproveStatus = "APPROVE";
approver.Comment = reason;
await UpdateAsync(rawData);
//var leaveType = await _appDbContext.Set<TypeLeave>()
// .FirstOrDefaultAsync(x => x.Name == rawData.Type.Name);
// insert to profile leave
// var profileLeave = new ProfileLeave
// {
// DateStartLeave = rawData.LeaveStartDate,
// DateEndLeave = rawData.LeaveEndDate,
// TotalLeave = rawData.LeaveTotal,
// Status = "approve",
// Reason = rawData.LeaveDetail,
// ProfileId = profile.Id, // change from profile object to id
// TypeLeave = leaveType
// };
// _appDbContext.Set<ProfileLeave>().Add(profileLeave);
var _baseAPI = _configuration["API"];
var apiUrlSalary = string.Empty;
if (profile.ProfileType == "OFFICER")
if (approver.Seq != maxSeq)
{
apiUrlSalary = $"{_baseAPI}/org/profile/leave";
using (var client = new HttpClient())
var nextApprover = approvers.FirstOrDefault(x => x.Seq == approver.Seq + 1);
// Send Noti
var noti1 = new Notification
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", AccessToken.Replace("Bearer ", ""));
client.DefaultRequestHeaders.Add("api_key", _configuration["API_KEY"]);
var _res = await client.PostAsJsonAsync(apiUrlSalary, new
{
profileId = profile.Id,
leaveTypeId = rawData?.Type?.Id ?? null,
dateLeaveStart = rawData.LeaveStartDate,
dateLeaveEnd = rawData.LeaveEndDate,
totalLeave = 0,//หน้า fe ไม่ได้ใช้
leaveCount = 0,//หน้า fe ไม่ได้ใช้
leaveDays = rawData.LeaveTotal,
status = "approve",
reason = rawData.LeaveDetail,
});
// var _result = await _res.Content.ReadAsStringAsync();
}
}
else if (profile.ProfileType == "EMPLOYEE")
{
apiUrlSalary = $"{_baseAPI}/org/profile-employee/leave";
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", AccessToken.Replace("Bearer ", ""));
client.DefaultRequestHeaders.Add("api_key", _configuration["API_KEY"]);
var _res = await client.PostAsJsonAsync(apiUrlSalary, new
{
profileEmployeeId = profile.Id,
leaveTypeId = rawData?.Type?.Id ?? null,
dateLeaveStart = rawData.LeaveStartDate,
dateLeaveEnd = rawData.LeaveEndDate,
totalLeave = 0,
leaveCount = 0,
leaveDays = rawData.LeaveTotal,
status = "approve",
reason = rawData.LeaveDetail,
});
}
Body = $"การขอลาของคุณ {rawData.FirstName} {rawData.LastName} รอรับการอนุมัติจากคุณ",
ReceiverUserId = nextApprover!.ProfileId,
Type = "",
Payload = "",
};
_appDbContext.Set<Notification>().Add(noti1);
await _appDbContext.SaveChangesAsync();
await UpdateAsync(rawData);
}
else
{
throw new Exception("ไม่สามารถทำรายการได้");
var profile = await _userProfileRepository.GetProfileByKeycloakIdAsync(rawData.KeycloakUserId, AccessToken);
if (profile == null)
{
throw new Exception(GlobalMessages.DataNotFound);
}
rawData.LeaveStatus = "APPROVE";
rawData.LeaveDirectorComment = reason;
rawData.ApproveStep = "st4";
await UpdateAsync(rawData);
var _baseAPI = _configuration["API"];
var apiUrlSalary = string.Empty;
if (profile.ProfileType == "OFFICER")
{
apiUrlSalary = $"{_baseAPI}/org/profile/leave";
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", AccessToken.Replace("Bearer ", ""));
client.DefaultRequestHeaders.Add("api_key", _configuration["API_KEY"]);
var _res = await client.PostAsJsonAsync(apiUrlSalary, new
{
profileId = profile.Id,
leaveTypeId = rawData?.Type?.Id ?? null,
dateLeaveStart = rawData.LeaveStartDate,
dateLeaveEnd = rawData.LeaveEndDate,
totalLeave = 0,//หน้า fe ไม่ได้ใช้
leaveCount = 0,//หน้า fe ไม่ได้ใช้
leaveDays = rawData.LeaveTotal,
status = "approve",
reason = rawData.LeaveDetail,
});
// var _result = await _res.Content.ReadAsStringAsync();
}
}
else if (profile.ProfileType == "EMPLOYEE")
{
apiUrlSalary = $"{_baseAPI}/org/profile-employee/leave";
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", AccessToken.Replace("Bearer ", ""));
client.DefaultRequestHeaders.Add("api_key", _configuration["API_KEY"]);
var _res = await client.PostAsJsonAsync(apiUrlSalary, new
{
profileEmployeeId = profile.Id,
leaveTypeId = rawData?.Type?.Id ?? null,
dateLeaveStart = rawData.LeaveStartDate,
dateLeaveEnd = rawData.LeaveEndDate,
totalLeave = 0,
leaveCount = 0,
leaveDays = rawData.LeaveTotal,
status = "approve",
reason = rawData.LeaveDetail,
});
}
}
else
{
throw new Exception("ไม่สามารถทำรายการได้");
}
await _appDbContext.SaveChangesAsync();
// insert to process timestamp
// Send Noti
var noti = new Notification
{
Body = $"การขอลาของคุณได้รับการอนุมัติ",
ReceiverUserId = profile.Id,
Type = "",
Payload = "",
};
_appDbContext.Set<Notification>().Add(noti);
await _appDbContext.SaveChangesAsync();
}
await _appDbContext.SaveChangesAsync();
// insert to process timestamp
// Send Noti
var noti = new Notification
{
Body = $"การขอลาของคุณได้รับการอนุมัติ",
ReceiverUserId = profile.Id,
Type = "",
Payload = "",
};
_appDbContext.Set<Notification>().Add(noti);
await _appDbContext.SaveChangesAsync();
}
public async Task RejectLeaveRequest(Guid id, string reason)
{
// Get UserId from token
var userId = UserId == null ? Guid.Empty : Guid.Parse(UserId);
var rawData = await GetByIdAsync(id);
if (rawData == null)
{
@ -645,31 +768,63 @@ namespace BMA.EHR.Application.Repositories.Leaves.LeaveRequests
if (rawData.ApproveStep != "st3")
{
throw new Exception("คำขอนี้ยังไม่ได้รับการอนุมัติจากผู้บังคับบัญชา ไม่สามารถทำรายการได้");
throw new Exception("คำขอนี้ยังไม่ได้อยู่ในขั้นตอนที่สามารถอนุมัติได้ ไม่สามารถทำรายการได้");
}
var profile = await _userProfileRepository.GetProfileByKeycloakIdAsync(rawData.KeycloakUserId, AccessToken);
if (profile == null)
// check commander approve
var approvers = rawData.Approvers.Where(x => x.ApproveType!.ToUpper() == "APPROVER").OrderBy(x => x.Seq).ToList();
var maxSeq = approvers.Max(x => x.Seq);
var approver = approvers.FirstOrDefault(x => x.KeycloakId == userId);
if (approver == null)
{
throw new Exception(GlobalMessages.DataNotFound);
throw new Exception("คุณไม่มีสิทธิ์อนุมัติการลาในขั้นตอนนี้");
}
rawData.LeaveStatus = "REJECT";
rawData.LeaveDirectorComment = reason;
rawData.ApproveStep = "st5";
approver.ApproveStatus = "REJECT";
approver.Comment = reason;
await UpdateAsync(rawData);
// Send Noti
var noti = new Notification
if (approver.Seq != maxSeq)
{
Body = $"การขอลาของคุณไม่ได้รับการอนุมัติ \r\nเนื่องจาก{reason}",
ReceiverUserId = profile.Id,
Type = "",
Payload = "",
};
_appDbContext.Set<Notification>().Add(noti);
await _appDbContext.SaveChangesAsync();
var nextApprover = approvers.FirstOrDefault(x => x.Seq == approver.Seq + 1);
// Send Noti
var noti1 = new Notification
{
Body = $"การขอลาของคุณ {rawData.FirstName} {rawData.LastName} รอรับการอนุมัติจากคุณ",
ReceiverUserId = nextApprover!.ProfileId,
Type = "",
Payload = "",
};
_appDbContext.Set<Notification>().Add(noti1);
await _appDbContext.SaveChangesAsync();
await UpdateAsync(rawData);
}
else
{
var profile = await _userProfileRepository.GetProfileByKeycloakIdAsync(rawData.KeycloakUserId, AccessToken);
if (profile == null)
{
throw new Exception(GlobalMessages.DataNotFound);
}
rawData.LeaveStatus = "REJECT";
rawData.LeaveDirectorComment = reason;
rawData.ApproveStep = "st5";
await UpdateAsync(rawData);
// Send Noti
var noti = new Notification
{
Body = $"การขอลาของคุณไม่ได้รับการอนุมัติ \r\nเนื่องจาก{reason}",
ReceiverUserId = profile.Id,
Type = "",
Payload = "",
};
_appDbContext.Set<Notification>().Add(noti);
await _appDbContext.SaveChangesAsync();
}
}
public async Task<List<GetSumApproveLeaveByTypeDto>> GetSumSendLeaveAsync(int year)

View file

@ -23,5 +23,7 @@ namespace BMA.EHR.Domain.Models.Leave.Requests
public string ApproveStatus { get; set; } = string.Empty;
public string Comment { get; set; } = string.Empty;
public string? ApproveType { get; set; } = string.Empty; // ผู้บังคับบัญชา = commander, ผู้มีอำนาจอนุมัติ = Approver
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,29 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace BMA.EHR.Infrastructure.Migrations.LeaveDb
{
/// <inheritdoc />
public partial class AddApproverType : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "ApproveType",
table: "LeaveRequestApprovers",
type: "longtext",
nullable: true)
.Annotation("MySql:CharSet", "utf8mb4");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "ApproveType",
table: "LeaveRequestApprovers");
}
}
}

View file

@ -625,6 +625,9 @@ namespace BMA.EHR.Infrastructure.Migrations.LeaveDb
.IsRequired()
.HasColumnType("longtext");
b.Property<string>("ApproveType")
.HasColumnType("longtext");
b.Property<string>("Comment")
.IsRequired()
.HasColumnType("longtext");

View file

@ -3,6 +3,7 @@ using BMA.EHR.Application.Repositories.Commands;
using BMA.EHR.Application.Repositories.Leaves.LeaveRequests;
using BMA.EHR.Application.Repositories.Leaves.TimeAttendants;
using BMA.EHR.Application.Repositories.MetaData;
using BMA.EHR.Application.Responses.Profiles;
using BMA.EHR.Domain.Common;
using BMA.EHR.Domain.Extensions;
using BMA.EHR.Domain.Models.Leave.Requests;
@ -10,13 +11,15 @@ using BMA.EHR.Domain.Shared;
using BMA.EHR.Leave.Service.DTOs.Reports;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json.Linq;
using Microsoft.OpenApi.Any;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Org.BouncyCastle.Asn1.Pkcs;
using Org.BouncyCastle.Ocsp;
using Sentry;
using Swashbuckle.AspNetCore.Annotations;
using System.Globalization;
using System.Security.Claims;
using BMA.EHR.Application.Responses.Profiles;
using Microsoft.OpenApi.Any;
namespace BMA.EHR.Leave.Service.Controllers
{
@ -228,12 +231,17 @@ namespace BMA.EHR.Leave.Service.Controllers
private async Task<dynamic> GetReport03(LeaveRequest data)
{
var profile = await _userProfileRepository.GetProfileByKeycloakIdAsync(data.KeycloakUserId, AccessToken);
if (profile == null)
{
return Error(GlobalMessages.DataNotFound, StatusCodes.Status404NotFound);
}
var fullName = $"{profile!.Prefix}{profile!.FirstName} {profile!.LastName}";
//var rootOc = _userProfileRepository.GetRootOcId(profile.OcId ?? Guid.Empty, AccessToken);
@ -247,6 +255,46 @@ namespace BMA.EHR.Leave.Service.Controllers
var sumLeave = await _leaveRequestRepository.GetSumApproveLeaveByTypeForUserAsync(data.KeycloakUserId, data.Type.Id, data.LeaveStartDate.Year);
//var userCalendar = await _userCalendarRepository.GetExist(profile.Id);
//var category = userCalendar == null ? "NORMAL" : userCalendar.Calendar;
//var sumWorkDay = await _holidayRepository.GetHolidayCountAsync(data.LeaveStartDate.Date, data.LeaveEndDate.Date, category);
//var sumWeekend = _holidayRepository.GetWeekEndCount(data.LeaveStartDate.Date, data.LeaveEndDate.Date, category);
var extendLeave = 0.0;
var leaveLimit = data.Type.Limit;
var approvePrevYear = await _leaveRequestRepository.GetSumApproveLeaveAsync(data.LeaveStartDate.Year - 1);
if (data.Type.Code == "LV-005")
{
var apprvPrevData = approvePrevYear.FirstOrDefault(x => x.KeycloakUserId == data.KeycloakUserId && x.LeaveTypeId == data.Type.Id);
var apprvPrev = apprvPrevData == null ? 0 : apprvPrevData.SumLeaveDay;
//var profile = await _userProfileRepository.GetProfileByKeycloakIdAsync(data.KeycloakUserId, AccessToken);
var govAge = (profile?.DateStart?.Date ?? DateTime.Now.Date).DiffDay(DateTime.Now.Date);
if (govAge >= 180)
{
if (govAge >= 3650)
{
// ถ้าอายุราชการเกิน 10 ปี ได้บวกเพิ่มอีก 10 วัน
extendLeave = 30 - apprvPrev; // หายอดวันลาที่เหลือของปีก่อน
if (extendLeave >= 20) extendLeave = 20;
}
else
{
extendLeave = 20 - apprvPrev; // หายอดวันลาที่เหลือของปีก่อน
if (extendLeave >= 10) extendLeave = 10;
}
}
else
leaveLimit = 0;
}
return new
{
template = "leave11",
@ -263,17 +311,21 @@ namespace BMA.EHR.Leave.Service.Controllers
positionLeaveName = profile!.PositionLeaveName == null ? "-" : profile!.PositionLeaveName.ToThaiNumber(),
organizationName = profile!.Oc!.ToThaiNumber() ?? "",
restDayOldTotal = data.RestDayOldTotal.ToString().ToThaiNumber(),
restDayCurrentTotal = data.RestDayCurrentTotal.ToString().ToThaiNumber(),
restDayOldTotal = extendLeave.ToString().ToThaiNumber(),
restDayCurrentTotal = leaveLimit.ToString().ToThaiNumber(),
//restDayOldTotal = data.RestDayOldTotal.ToString().ToThaiNumber(),
//restDayCurrentTotal = data.RestDayCurrentTotal.ToString().ToThaiNumber(),
leaveDateStart = data.LeaveStartDate.Date.ToThaiShortDate().ToThaiNumber(),
leaveDateEnd = data.LeaveEndDate.Date.ToThaiShortDate().ToThaiNumber(),
LeaveTotal = data.LeaveStartDate.DiffDay(data.LeaveEndDate).ToString().ToThaiNumber(),
leaveTotal = data.LeaveTotal.ToString().ToThaiNumber(),
//LeaveTotal = data.LeaveStartDate.DiffDay(data.LeaveEndDate).ToString().ToThaiNumber(),
leaveAddress = data.LeaveAddress.ToThaiNumber(),
leaveNumber = data.LeaveNumber.ToThaiNumber(),
LeaveSummary = sumLeave.ToString().ToThaiNumber(),
LeaveRemain = (data.Type.Limit - sumLeave).ToString().ToThaiNumber(),
LeaveRemain = (data.Type.Limit + extendLeave - sumLeave).ToString().ToThaiNumber(),
}
};
}
@ -1258,6 +1310,13 @@ namespace BMA.EHR.Leave.Service.Controllers
remarkStr += "ครึ่งวันเช้า";
else if (leaveRange == "AFTERNOON")
remarkStr += "ครึ่งวันบ่าย";
var leaveRangeEnd = leaveReq.LeaveRangeEnd == null ? "" : leaveReq.LeaveRangeEnd.ToUpper();
if (leaveRangeEnd == "MORNING")
remarkStr += "ครึ่งวันเช้า";
else if (leaveRangeEnd == "AFTERNOON")
remarkStr += "ครึ่งวันบ่าย";
break;
default:
remarkStr += leaveReq.Type.Name;

View file

@ -12,10 +12,12 @@ using BMA.EHR.Infrastructure.Persistence;
using BMA.EHR.Leave.Service.DTOs.LeaveRequest;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Org.BouncyCastle.Asn1.Pkcs;
using Sentry;
using Swashbuckle.AspNetCore.Annotations;
using System.Net.Http.Headers;
using System.Security.Claims;
@ -111,6 +113,57 @@ namespace BMA.EHR.Leave.Service.Controllers
#region " Methods "
/// <summary>
/// เพิ่มรายชิื่อผู้อนุมัติ หรือ ผู้บังคับบัญชา
/// </summary>
/// <returns>
/// </returns>
/// <response code="200">เมื่อทำรายการสำเร็จ</response>
/// <response code="401">ไม่ได้ Login เข้าระบบ</response>
/// <response code="500">เมื่อเกิดข้อผิดพลาดในการทำงาน</response>
[HttpPost("officer/add-approver/{type}/{id:guid}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<ActionResult<ResponseObject>> AddApprover(string type, Guid id, [FromBody] List<LeaveRequestApproverDto> req)
{
try
{
var leaveReq = await _leaveRequestRepository.GetByIdAsync(id);
if (leaveReq == null)
{
return Error(GlobalMessages.DataNotFound, StatusCodes.Status404NotFound);
}
var delete = leaveReq.Approvers.RemoveAll(x => x.ApproveType == type.Trim().ToUpper());
foreach (var r in req)
{
leaveReq.Approvers.Add(new LeaveRequestApprover
{
Seq = r.Seq,
Prefix = r.Prefix,
FirstName = r.FirstName,
LastName = r.LastName,
PositionName = r.PositionName,
ProfileId = r.ProfileId,
KeycloakId = r.KeycloakId,
ApproveStatus = "PENDING",
ApproveType = type.Trim().ToUpper()
});
}
await _leaveRequestRepository.UpdateAsync(leaveReq);
return Success();
}
catch (Exception ex)
{
return Error(ex);
}
}
/// <summary>
/// LV2_001 - สร้างคำขอการลา (USER)
/// </summary>
@ -174,6 +227,7 @@ namespace BMA.EHR.Leave.Service.Controllers
LeaveSubTypeName = req.LeaveSubTypeName,
LeaveRange = req.LeaveRange,
LeaveRangeEnd = req.LeaveRangeEnd,
LeaveStartDate = req.LeaveStartDate,
LeaveEndDate = req.LeaveEndDate,
LeaveWrote = req.LeaveWrote ?? "",
@ -367,30 +421,30 @@ namespace BMA.EHR.Leave.Service.Controllers
leaveRequest.PositionLevelName = profile.PosLevel == null ? "" : profile.PosLevel;
leaveRequest.OrganizationName = userOc;
if (req.Approvers != null && req.Approvers != "")
{
//var jsonString = System.Text.Json.JsonSerializer.Deserialize<string>(req.Approvers ?? "");
//var fixedJson = req.Approvers.Replace("\\\"", "\"");
var approvers = JsonConvert.DeserializeObject<List<LeaveRequestApproverDto>>(req.Approvers);
if (approver != null)
{
foreach (var r in approvers!)
{
leaveRequest.Approvers.Add(new LeaveRequestApprover
{
Seq = r.Seq,
Prefix = r.Prefix,
FirstName = r.FirstName,
LastName = r.LastName,
PositionName = r.PositionName,
ProfileId = r.ProfileId,
KeycloakId = r.KeycloakId,
ApproveStatus = "PENDING",
});
}
}
//if (req.Approvers != null && req.Approvers != "")
//{
// //var jsonString = System.Text.Json.JsonSerializer.Deserialize<string>(req.Approvers ?? "");
// //var fixedJson = req.Approvers.Replace("\\\"", "\"");
// var approvers = JsonConvert.DeserializeObject<List<LeaveRequestApproverDto>>(req.Approvers);
// if (approver != null)
// {
// foreach (var r in approvers!)
// {
// leaveRequest.Approvers.Add(new LeaveRequestApprover
// {
// Seq = r.Seq,
// Prefix = r.Prefix,
// FirstName = r.FirstName,
// LastName = r.LastName,
// PositionName = r.PositionName,
// ProfileId = r.ProfileId,
// KeycloakId = r.KeycloakId,
// ApproveStatus = "PENDING",
// });
// }
// }
}
//}
// save to database
@ -493,6 +547,7 @@ namespace BMA.EHR.Leave.Service.Controllers
// ลองใช้ oldData
oldData.LeaveRange = req.LeaveRange;
oldData.LeaveRangeEnd = req.LeaveRangeEnd;
oldData.LeaveStartDate = req.LeaveStartDate;
oldData.LeaveEndDate = req.LeaveEndDate;
oldData.LeaveWrote = req.LeaveWrote ?? "";
@ -1328,7 +1383,8 @@ namespace BMA.EHR.Leave.Service.Controllers
var result = new GetLeaveRequestByIdDto
{
Id = rawData.Id,
LeaveRange = rawData.LeaveRange ?? "",
LeaveRange = rawData.LeaveRange ?? "ALL",
LeaveRangeEnd = rawData.LeaveRangeEnd ?? "ALL",
LeaveTypeName = rawData.Type.Name,
LeaveSubTypeName = rawData.LeaveSubTypeName,
LeaveTypeId = rawData.Type.Id,
@ -1493,6 +1549,7 @@ namespace BMA.EHR.Leave.Service.Controllers
Agency = agency_name,//agency == null ? "" : agency.Name,
Org = item.Root ?? "",//userOc == null ? "-" : userOc.Root,
LeaveRange = item.LeaveRange ?? "ALL",
LeaveRangeEnd = item.LeaveRangeEnd ?? "ALL",
HajjDayStatus = item.HajjDayStatus,
};
@ -1758,15 +1815,57 @@ namespace BMA.EHR.Leave.Service.Controllers
public async Task<ActionResult<ResponseObject>> CommanderApproveLeaveRequestAsync(Guid id,
[FromBody] LeaveRequestApproveDto req)
{
var getPermission = await _permission.GetPermissionAPIAsync("UPDATE", "SYS_LEAVE_LIST");
var jsonData = JsonConvert.DeserializeObject<JObject>(getPermission);
if (jsonData["status"]?.ToString() != "200")
try
{
return Error(jsonData["message"]?.ToString(), StatusCodes.Status403Forbidden);
}
await _leaveRequestRepository.CommanderApproveLeaveRequest(id, req.Reason ?? "");
var getPermission = await _permission.GetPermissionAPIAsync("UPDATE", "SYS_LEAVE_LIST");
var jsonData = JsonConvert.DeserializeObject<JObject>(getPermission);
if (jsonData["status"]?.ToString() != "200")
{
return Error(jsonData["message"]?.ToString(), StatusCodes.Status403Forbidden);
}
await _leaveRequestRepository.CommanderApproveLeaveRequest(id, req.Reason ?? "");
return Success();
}
catch(Exception ex)
{
return Error(ex);
}
}
/// <summary>
/// ผู้บังคับบัญชาไม่อนุมัติการลา(ADMIN)
/// </summary>
/// <returns>
/// </returns>
/// <response code="200">เมื่อทำรายการสำเร็จ</response>
/// <response code="401">ไม่ได้ Login เข้าระบบ</response>
/// <response code="500">เมื่อเกิดข้อผิดพลาดในการทำงาน</response>
[HttpPut("admin/reject/comander/{id:guid}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<ActionResult<ResponseObject>> CommanderRejectLeaveRequestAsync(Guid id,
[FromBody] LeaveRequestApproveDto req)
{
try
{
var getPermission = await _permission.GetPermissionAPIAsync("UPDATE", "SYS_LEAVE_LIST");
var jsonData = JsonConvert.DeserializeObject<JObject>(getPermission);
if (jsonData["status"]?.ToString() != "200")
{
return Error(jsonData["message"]?.ToString(), StatusCodes.Status403Forbidden);
}
await _leaveRequestRepository.CommanderRejectLeaveRequest(id, req.Reason ?? "");
return Success();
}
catch (Exception ex)
{
return Error(ex);
}
return Success();
}
/// <summary>
@ -1784,15 +1883,23 @@ namespace BMA.EHR.Leave.Service.Controllers
public async Task<ActionResult<ResponseObject>> ApproveLeaveRequestAsync(Guid id,
[FromBody] LeaveRequestApproveDto req)
{
var getPermission = await _permission.GetPermissionAPIAsync("UPDATE", "SYS_LEAVE_LIST");
var jsonData = JsonConvert.DeserializeObject<JObject>(getPermission);
if (jsonData["status"]?.ToString() != "200")
try
{
return Error(jsonData["message"]?.ToString(), StatusCodes.Status403Forbidden);
}
await _leaveRequestRepository.ApproveLeaveRequest(id, req.Reason ?? "");
var getPermission = await _permission.GetPermissionAPIAsync("UPDATE", "SYS_LEAVE_LIST");
var jsonData = JsonConvert.DeserializeObject<JObject>(getPermission);
if (jsonData["status"]?.ToString() != "200")
{
return Error(jsonData["message"]?.ToString(), StatusCodes.Status403Forbidden);
}
await _leaveRequestRepository.ApproveLeaveRequest(id, req.Reason ?? "");
return Success();
return Success();
}
catch (Exception ex)
{
return Error(ex);
}
}
/// <summary>
@ -1810,49 +1917,56 @@ namespace BMA.EHR.Leave.Service.Controllers
public async Task<ActionResult<ResponseObject>> SendLeaveRequestAsync(Guid id,
[FromBody] LeaveRequestApproveDto req)
{
await _leaveRequestRepository.SendToOfficerAsync(id);
try
{
await _leaveRequestRepository.SendToOfficerAsync(id);
var userId = UserId == null ? Guid.Empty : Guid.Parse(UserId);
var profile = await _userProfileRepository.GetProfileByKeycloakIdAsync(userId, AccessToken);
if (profile == null)
{
return Error(GlobalMessages.DataNotFound, StatusCodes.Status404NotFound);
}
var baseAPIOrg = _configuration["API"];
var apiUrlOrg = $"{baseAPIOrg}/org/workflow/add-workflow";
if (profile.ProfileType == "OFFICER")
{
using (var client = new HttpClient())
var userId = UserId == null ? Guid.Empty : Guid.Parse(UserId);
var profile = await _userProfileRepository.GetProfileByKeycloakIdAsync(userId, AccessToken);
if (profile == null)
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", AccessToken.Replace("Bearer ", ""));
client.DefaultRequestHeaders.Add("api_key", _configuration["API_KEY"]);
var _res = await client.PostAsJsonAsync(apiUrlOrg, new
{
refId = id,
sysName = "SYS_LEAVE_LIST",
posLevelName = profile.PosLevel ?? "",
posTypeName = profile.PosType ?? "",
fullName = $"{profile.Prefix}{profile.FirstName} {profile.LastName}"
});
return Error(GlobalMessages.DataNotFound, StatusCodes.Status404NotFound);
}
}
else
{
using (var client = new HttpClient())
var baseAPIOrg = _configuration["API"];
var apiUrlOrg = $"{baseAPIOrg}/org/workflow/add-workflow";
if (profile.ProfileType == "OFFICER")
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", AccessToken.Replace("Bearer ", ""));
client.DefaultRequestHeaders.Add("api_key", _configuration["API_KEY"]);
var _res = await client.PostAsJsonAsync(apiUrlOrg, new
using (var client = new HttpClient())
{
refId = id,
sysName = "SYS_LEAVE_LIST_EMP",
posLevelName = "EMP",
posTypeName = "EMP",
});
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", AccessToken.Replace("Bearer ", ""));
client.DefaultRequestHeaders.Add("api_key", _configuration["API_KEY"]);
var _res = await client.PostAsJsonAsync(apiUrlOrg, new
{
refId = id,
sysName = "SYS_LEAVE_LIST",
posLevelName = profile.PosLevel ?? "",
posTypeName = profile.PosType ?? "",
fullName = $"{profile.Prefix}{profile.FirstName} {profile.LastName}"
});
}
}
else
{
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", AccessToken.Replace("Bearer ", ""));
client.DefaultRequestHeaders.Add("api_key", _configuration["API_KEY"]);
var _res = await client.PostAsJsonAsync(apiUrlOrg, new
{
refId = id,
sysName = "SYS_LEAVE_LIST_EMP",
posLevelName = "EMP",
posTypeName = "EMP",
});
}
}
}
return Success();
return Success();
}
catch (Exception ex)
{
return Error(ex);
}
}
/// <summary>
@ -1870,15 +1984,23 @@ namespace BMA.EHR.Leave.Service.Controllers
public async Task<ActionResult<ResponseObject>> RejectLeaveRequestAsync(Guid id,
[FromBody] LeaveRequestApproveDto req)
{
var getPermission = await _permission.GetPermissionAPIAsync("UPDATE", "SYS_LEAVE_LIST");
var jsonData = JsonConvert.DeserializeObject<JObject>(getPermission);
if (jsonData["status"]?.ToString() != "200")
try
{
return Error(jsonData["message"]?.ToString(), StatusCodes.Status403Forbidden);
}
await _leaveRequestRepository.RejectLeaveRequest(id, req.Reason ?? "");
var getPermission = await _permission.GetPermissionAPIAsync("UPDATE", "SYS_LEAVE_LIST");
var jsonData = JsonConvert.DeserializeObject<JObject>(getPermission);
if (jsonData["status"]?.ToString() != "200")
{
return Error(jsonData["message"]?.ToString(), StatusCodes.Status403Forbidden);
}
await _leaveRequestRepository.RejectLeaveRequest(id, req.Reason ?? "");
return Success();
return Success();
}
catch (Exception ex)
{
return Error(ex);
}
}
/// <summary>
@ -1974,6 +2096,38 @@ namespace BMA.EHR.Leave.Service.Controllers
if (rawData.Root != null && rawData.Root != "")
orgName += $" {rawData.Root}";
// #1136
var extendLeave = 0.0;
var leaveLimit = rawData.Type.Limit;
var approvePrevYear = await _leaveRequestRepository.GetSumApproveLeaveAsync(thisYear - 1);
if (rawData.Type.Code == "LV-005")
{
var apprvPrevData = approvePrevYear.FirstOrDefault(x => x.KeycloakUserId == rawData.KeycloakUserId && x.LeaveTypeId == rawData.Type.Id);
var apprvPrev = apprvPrevData == null ? 0 : apprvPrevData.SumLeaveDay;
var profile = await _userProfileRepository.GetProfileByKeycloakIdAsync(rawData.KeycloakUserId, AccessToken);
var govAge = (profile?.DateStart?.Date ?? DateTime.Now.Date).DiffDay(DateTime.Now.Date);
if (govAge >= 180)
{
if (govAge >= 3650)
{
// ถ้าอายุราชการเกิน 10 ปี ได้บวกเพิ่มอีก 10 วัน
extendLeave = 30 - apprvPrev; // หายอดวันลาที่เหลือของปีก่อน
if (extendLeave >= 20) extendLeave = 20;
}
else
{
extendLeave = 20 - apprvPrev; // หายอดวันลาที่เหลือของปีก่อน
if (extendLeave >= 10) extendLeave = 10;
}
}
else
leaveLimit = 0;
}
var result = new GetLeaveRequestForAdminByIdDto
{
Id = rawData.Id,
@ -1993,6 +2147,7 @@ namespace BMA.EHR.Leave.Service.Controllers
LeaveNumber = rawData.LeaveNumber,
LeaveDetail = rawData.LeaveDetail,
LeaveRange = rawData.LeaveRange ?? "ALL",
LeaveRangeEnd = rawData.LeaveRangeEnd ?? "ALL",
LeaveDocument = new(),
//LeaveDocument = rawData.LeaveDocument == null ? "" : await _minIOService.ImagesPath(rawData.LeaveDocument.Id),
LeaveDraftDocument = rawData.LeaveDraftDocument == null ? "" : await _minIOService.ImagesPath(rawData.LeaveDraftDocument.Id),
@ -2012,8 +2167,12 @@ namespace BMA.EHR.Leave.Service.Controllers
WifeDayName = rawData.WifeDayName,
WifeDayDateBorn = rawData.WifeDayDateBorn,
RestDayOldTotal = rawData.RestDayOldTotal,
RestDayCurrentTotal = rawData.RestDayCurrentTotal,
RestDayOldTotal = extendLeave,
RestDayCurrentTotal = rawData.Type.Limit,
// #1134
//RestDayOldTotal = rawData.RestDayOldTotal,
//RestDayCurrentTotal = rawData.RestDayCurrentTotal,
OrdainDayStatus = rawData.OrdainDayStatus,
OrdainDayLocationName = rawData.OrdainDayLocationName,
OrdainDayLocationAddress = rawData.OrdainDayLocationAddress,
@ -2066,9 +2225,9 @@ namespace BMA.EHR.Leave.Service.Controllers
ApproveStep = rawData.ApproveStep ?? "-",
LeaveLimit = rawData.Type.Limit,
LeaveLimit = rawData.Type.Limit + extendLeave,
LeaveSummary = leaveSummary,
LeaveRemain = rawData.Type.Limit - leaveSummary
LeaveRemain = (rawData.Type.Limit + extendLeave) - leaveSummary
};
if (rawData.LeaveDocument != null && rawData.LeaveDocument.Count > 0)
@ -2136,7 +2295,7 @@ namespace BMA.EHR.Leave.Service.Controllers
if (leaveType.Code == "LV-005")
{
var apprvPrevData = approvePrevYear.FirstOrDefault(x => x.KeycloakUserId == userId && x.LeaveTypeId == leaveType.Id);
var apprvPrev = apprvPrevData == null ? 0 : approveData.SumLeaveDay;
var apprvPrev = apprvPrevData == null ? 0 : apprvPrevData.SumLeaveDay;
var profile = await _userProfileRepository.GetProfileByKeycloakIdAsync(userId, AccessToken);
var govAge = (profile?.DateStart?.Date ?? DateTime.Now.Date).DiffDay(DateTime.Now.Date);

View file

@ -21,6 +21,8 @@ namespace BMA.EHR.Leave.Service.DTOs.LeaveRequest
public string? LeaveRange { get; set; } = "ALL";
public string? LeaveRangeEnd { get; set; } = "ALL";
public double LeaveTotal { get; set; } = 0.0;
public string? LeaveAddress { get; set; }
@ -100,31 +102,7 @@ namespace BMA.EHR.Leave.Service.DTOs.LeaveRequest
public DateTime? CoupleDayEndDateHistory { get; set; }
public string? CoupleDaySumTotalHistory { get; set; }
public string? Approvers { get; set; } = string.Empty;
}
public class LeaveRequestApproverDto
{
[JsonProperty("seq")]
public int Seq { get; set; } = 0;
[JsonProperty("prefix")]
public string Prefix { get; set; } = string.Empty;
[JsonProperty("firstName")]
public string FirstName { get; set; } = string.Empty;
[JsonProperty("lastName")]
public string LastName { get; set; } = string.Empty;
[JsonProperty("positionName")]
public string PositionName { get; set; } = string.Empty;
[JsonProperty("profileId")]
public Guid ProfileId { get; set; } = Guid.Empty;
[JsonProperty("keycloakId")]
public Guid KeycloakId { get; set; } = Guid.Empty;
}
}

View file

@ -27,6 +27,8 @@ namespace BMA.EHR.Leave.Service.DTOs.LeaveRequest
public string? LeaveRange { get; set; } = string.Empty;
public string? LeaveRangeEnd { get; set; } = string.Empty;
public string LeaveAddress { get; set; } = string.Empty;
public string LeaveNumber { get; set; } = string.Empty;

View file

@ -135,6 +135,9 @@ namespace BMA.EHR.Leave.Service.DTOs.LeaveRequest
public double LeaveRemain { get; set; } = 0;
public string LeaveRange { get; set; } = string.Empty;
public string LeaveRangeEnd { get; set; } = string.Empty;
public string? ProfileType { get; set; }
public string? CommanderPosition { get; set; } = string.Empty;

View file

@ -32,6 +32,8 @@
public string LeaveRange { get; set; } = string.Empty;
public string LeaveRangeEnd { get; set; } = string.Empty;
public bool? HajjDayStatus { get; set; }
public string? ProfileType { get; set; }

View file

@ -0,0 +1,28 @@
using Newtonsoft.Json;
namespace BMA.EHR.Leave.Service.DTOs.LeaveRequest
{
public class LeaveRequestApproverDto
{
[JsonProperty("seq")]
public int Seq { get; set; } = 0;
[JsonProperty("prefix")]
public string Prefix { get; set; } = string.Empty;
[JsonProperty("firstName")]
public string FirstName { get; set; } = string.Empty;
[JsonProperty("lastName")]
public string LastName { get; set; } = string.Empty;
[JsonProperty("positionName")]
public string PositionName { get; set; } = string.Empty;
[JsonProperty("profileId")]
public Guid ProfileId { get; set; } = Guid.Empty;
[JsonProperty("keycloakId")]
public Guid KeycloakId { get; set; } = Guid.Empty;
}
}