initial commit
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
namespace Indotalent.Shared.Consts;
|
||||
|
||||
public static class GlobalConsts
|
||||
{
|
||||
public const string AppInitial = "HRM";
|
||||
public const string AppName = "HRM: Human Resource Management";
|
||||
public const string AppTagline = "The Next-Gen People Engine: Built for Scale, Engineered for Excellence.";
|
||||
|
||||
public const int StringLengthId = 36;
|
||||
public const int StringLengthShort = 500;
|
||||
public const int StringLengthMedium = 1000;
|
||||
public const int StringLengthLong = 4000;
|
||||
|
||||
|
||||
public const int ODataMaxTop = 5000;
|
||||
|
||||
|
||||
public const string BehaviourError = nameof(BehaviourError);
|
||||
public const string GlobalError = nameof(GlobalError);
|
||||
|
||||
public static class Roles
|
||||
{
|
||||
public const string Administrator = "Administrator";
|
||||
public const string Manager = "Manager";
|
||||
public const string Employee = "Employee";
|
||||
}
|
||||
|
||||
public static class Formatting
|
||||
{
|
||||
public const string DateFormat = "dd MMM yyyy";
|
||||
public const string DateTimeFormat = "dd MMM yyyy HH:mm";
|
||||
public const string CurrencyCulture = "id-ID";
|
||||
}
|
||||
|
||||
public static class Pagination
|
||||
{
|
||||
public const int DefaultPageSize = 10;
|
||||
public static readonly int[] PageSizeOptions = { 10, 25, 50, 100 };
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace Indotalent.Shared.Models;
|
||||
|
||||
public class ApiRequest
|
||||
{
|
||||
public int Skip { get; set; } = 1;
|
||||
public int Top { get; set; } = 5;
|
||||
public string? SearchTerm { get; set; }
|
||||
public string? SortBy { get; set; }
|
||||
public bool IsAscending { get; set; } = true;
|
||||
public bool IsPagedEnabled { get; set; } = true;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
namespace Indotalent.Shared.Models;
|
||||
|
||||
public class ApiResponse<T>
|
||||
{
|
||||
public bool IsSuccess { get; set; }
|
||||
public int StatusCode { get; set; }
|
||||
public string? Message { get; set; }
|
||||
public T? Value { get; set; }
|
||||
public PaginationMetadata? Pagination { get; set; }
|
||||
public List<string>? Errors { get; set; }
|
||||
public DateTime ServerTime { get; set; } = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
public class PaginationMetadata
|
||||
{
|
||||
public int Count { get; set; }
|
||||
public int Top { get; set; }
|
||||
public int Skip { get; set; }
|
||||
public int TotalPages => (int)Math.Ceiling((double)Count / (Top == 0 ? 1 : Top));
|
||||
public bool HasPrevious => Skip > 0;
|
||||
public bool HasNext => (Skip + Top) < Count;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Indotalent.Shared.Models;
|
||||
|
||||
public class PagedList<T>
|
||||
{
|
||||
public PagedList()
|
||||
{
|
||||
Value = new List<T>();
|
||||
}
|
||||
|
||||
public List<T> Value { get; set; }
|
||||
public int Skip { get; set; }
|
||||
public int Top { get; set; }
|
||||
public int TotalPages { get; set; }
|
||||
public int Count { get; set; }
|
||||
|
||||
[JsonConstructor]
|
||||
public PagedList(List<T> value, int count, int skip, int top, int totalPages)
|
||||
{
|
||||
Value = value;
|
||||
Count = count;
|
||||
Skip = skip;
|
||||
Top = top;
|
||||
TotalPages = totalPages;
|
||||
}
|
||||
|
||||
public PagedList(List<T> value, int count, int skip, int top)
|
||||
{
|
||||
Value = value;
|
||||
Count = count;
|
||||
Skip = skip;
|
||||
Top = top;
|
||||
TotalPages = (int)Math.Ceiling(count / (double)top);
|
||||
}
|
||||
|
||||
public bool HasPrevious => Skip > 0;
|
||||
public bool HasNext => (Skip + Top) < Count;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using FluentValidation;
|
||||
|
||||
namespace Indotalent.Shared.Utils;
|
||||
|
||||
//public static class FluentValidationHelper
|
||||
//{
|
||||
// public static Func<object, string, Task<IEnumerable<string>>> ValidateValue<T>(this AbstractValidator<T> validator) => async (model, propertyName) =>
|
||||
// {
|
||||
// var result = await validator.ValidateAsync(ValidationContext<T>.CreateWithOptions((T)model, x => x.IncludeProperties(propertyName)));
|
||||
// if (result.IsValid) return Array.Empty<string>();
|
||||
// return result.Errors.Select(e => e.ErrorMessage);
|
||||
// };
|
||||
//}
|
||||
|
||||
public static class FluentValidationHelper
|
||||
{
|
||||
public static Func<object, string, Task<IEnumerable<string>>> ValidateValue<T>(this AbstractValidator<T> validator) => async (model, propertyName) =>
|
||||
{
|
||||
if (model is not T typedModel)
|
||||
return Array.Empty<string>();
|
||||
|
||||
var context = ValidationContext<T>.CreateWithOptions(typedModel, x => x.IncludeProperties(propertyName));
|
||||
var result = await validator.ValidateAsync(context);
|
||||
|
||||
if (result.IsValid)
|
||||
return Array.Empty<string>();
|
||||
|
||||
return result.Errors.Select(e => e.ErrorMessage);
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
using QuestPDF.Fluent;
|
||||
using QuestPDF.Helpers;
|
||||
using QuestPDF.Infrastructure;
|
||||
using Indotalent.Features.Payroll.PayrollDetails.Cqrs;
|
||||
|
||||
namespace Indotalent.Features.Payroll.Payrolls;
|
||||
|
||||
public class PayrollSlipPdfGenerator
|
||||
{
|
||||
|
||||
public static byte[] Generate(GetPayrollSlipByIdResponse data, string periodName)
|
||||
{
|
||||
QuestPDF.Settings.License = LicenseType.Community;
|
||||
|
||||
var primaryBlue = "#0D47A1";
|
||||
var lightGreyBg = "#F8FAFC";
|
||||
var borderColor = "#E2E8F0";
|
||||
var textSlate = "#64748b";
|
||||
|
||||
return Document.Create(container =>
|
||||
{
|
||||
container.Page(page =>
|
||||
{
|
||||
page.Size(PageSizes.A5.Landscape());
|
||||
page.Margin(1, Unit.Centimetre);
|
||||
page.PageColor(Colors.White);
|
||||
page.DefaultTextStyle(x => x.FontSize(9).FontFamily(Fonts.Verdana));
|
||||
|
||||
page.Header().PaddingBottom(10).Row(row =>
|
||||
{
|
||||
row.RelativeItem().Text("PAYROLL SLIP DETAILS")
|
||||
.FontSize(14)
|
||||
.ExtraBold()
|
||||
.FontColor(Colors.Black);
|
||||
});
|
||||
|
||||
page.Content().Column(col =>
|
||||
{
|
||||
col.Item().Border(1).BorderColor(borderColor).Background(lightGreyBg).Padding(10).Row(row =>
|
||||
{
|
||||
row.RelativeItem().Column(c =>
|
||||
{
|
||||
c.Item().Text("Employee Name").FontSize(8).SemiBold().FontColor(textSlate);
|
||||
c.Item().Text(data.EmployeeName).FontSize(11).ExtraBold().FontColor(primaryBlue);
|
||||
c.Item().PaddingTop(5).Text("Code").FontSize(8).SemiBold().FontColor(textSlate);
|
||||
c.Item().Text(data.EmployeeCode).FontSize(10).Bold();
|
||||
});
|
||||
|
||||
row.RelativeItem().AlignRight().Column(c =>
|
||||
{
|
||||
c.Item().Text("Payroll Period").FontSize(8).SemiBold().FontColor(textSlate);
|
||||
c.Item().Text(periodName).FontSize(11).Bold();
|
||||
c.Item().PaddingTop(5).Text("Basic Salary").FontSize(8).SemiBold().FontColor(textSlate);
|
||||
c.Item().Text(data.BasicSalary.ToString("N0")).FontSize(11).ExtraBold().FontColor(primaryBlue);
|
||||
});
|
||||
});
|
||||
|
||||
col.Item().PaddingTop(15).Row(row =>
|
||||
{
|
||||
row.RelativeItem().Column(c =>
|
||||
{
|
||||
c.Item().Text("Incomes (+)").FontSize(10).ExtraBold().FontColor(Colors.Green.Medium);
|
||||
c.Item().PaddingVertical(5).LineHorizontal(1).LineColor(borderColor);
|
||||
|
||||
foreach (var inc in data.Incomes)
|
||||
{
|
||||
c.Item().PaddingBottom(2).Row(r =>
|
||||
{
|
||||
r.RelativeItem().Text(inc.ComponentName);
|
||||
r.RelativeItem().AlignRight().Text(inc.Amount.ToString("N0")).Bold();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
row.ConstantItem(20);
|
||||
|
||||
row.RelativeItem().BorderLeft(1).BorderColor(borderColor).PaddingLeft(10).Column(c =>
|
||||
{
|
||||
c.Item().Text("Deductions (-)").FontSize(10).ExtraBold().FontColor(Colors.Red.Medium);
|
||||
c.Item().PaddingVertical(5).LineHorizontal(1).LineColor(borderColor);
|
||||
|
||||
foreach (var ded in data.Deductions)
|
||||
{
|
||||
c.Item().PaddingBottom(2).Row(r =>
|
||||
{
|
||||
r.RelativeItem().Text(ded.ComponentName);
|
||||
r.RelativeItem().AlignRight().Text($"({ded.Amount.ToString("N0")})").Bold().FontColor(Colors.Red.Medium);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
col.Item().PaddingTop(20).Background(primaryBlue).Padding(10).Row(row =>
|
||||
{
|
||||
row.RelativeItem().AlignLeft().AlignMiddle().Text("TAKE HOME PAY")
|
||||
.FontSize(12)
|
||||
.ExtraBold()
|
||||
.FontColor(Colors.White);
|
||||
|
||||
row.RelativeItem().AlignRight().AlignMiddle().Text(data.TakeHomePay.ToString("N0"))
|
||||
.FontSize(14)
|
||||
.ExtraBold()
|
||||
.FontColor(Colors.White);
|
||||
});
|
||||
});
|
||||
|
||||
page.Footer().PaddingTop(10).Row(row =>
|
||||
{
|
||||
row.RelativeItem().Text(x =>
|
||||
{
|
||||
x.Span("Generated on: ").FontSize(8).FontColor(textSlate);
|
||||
x.Span(DateTime.Now.ToString("dd MMM yyyy HH:mm")).FontSize(8).FontColor(textSlate);
|
||||
});
|
||||
|
||||
row.RelativeItem().AlignRight().Text(x =>
|
||||
{
|
||||
x.Span("Page ").FontSize(8);
|
||||
x.CurrentPageNumber().FontSize(8);
|
||||
});
|
||||
});
|
||||
});
|
||||
}).GeneratePdf();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
namespace Indotalent.Shared.Utils;
|
||||
|
||||
public static class SequentialGuidGenerator
|
||||
{
|
||||
public static string NewSequentialId()
|
||||
{
|
||||
byte[] guidBytes = Guid.NewGuid().ToByteArray();
|
||||
|
||||
byte[] timestampBytes = BitConverter.GetBytes(DateTime.UtcNow.Ticks);
|
||||
|
||||
if (BitConverter.IsLittleEndian)
|
||||
{
|
||||
Array.Reverse(timestampBytes);
|
||||
}
|
||||
|
||||
guidBytes[10] = timestampBytes[2];
|
||||
guidBytes[11] = timestampBytes[3];
|
||||
guidBytes[12] = timestampBytes[4];
|
||||
guidBytes[13] = timestampBytes[5];
|
||||
guidBytes[14] = timestampBytes[6];
|
||||
guidBytes[15] = timestampBytes[7];
|
||||
|
||||
return new Guid(guidBytes).ToString();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user