Added the payment request details API
This commit is contained in:
parent
cf24f3af32
commit
4c0ef1f585
7334
Marco.Pms.DataAccess/Migrations/20251103100115_Added_Changed_ExpensesType_To_ExpenseCategory.Designer.cs
generated
Normal file
7334
Marco.Pms.DataAccess/Migrations/20251103100115_Added_Changed_ExpensesType_To_ExpenseCategory.Designer.cs
generated
Normal file
File diff suppressed because one or more lines are too long
@ -0,0 +1,107 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Marco.Pms.DataAccess.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class Added_Changed_ExpensesType_To_ExpenseCategory : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Expenses_ExpensesTypeMaster_ExpensesTypeId",
|
||||||
|
table: "Expenses");
|
||||||
|
|
||||||
|
migrationBuilder.RenameColumn(
|
||||||
|
name: "ExpensesTypeId",
|
||||||
|
table: "Expenses",
|
||||||
|
newName: "ExpenseCategoryId");
|
||||||
|
|
||||||
|
migrationBuilder.RenameIndex(
|
||||||
|
name: "IX_Expenses_ExpensesTypeId",
|
||||||
|
table: "Expenses",
|
||||||
|
newName: "IX_Expenses_ExpenseCategoryId");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<Guid>(
|
||||||
|
name: "ProjectId",
|
||||||
|
table: "AdvancePaymentTransactions",
|
||||||
|
type: "char(36)",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: new Guid("00000000-0000-0000-0000-000000000000"),
|
||||||
|
collation: "ascii_general_ci");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "Title",
|
||||||
|
table: "AdvancePaymentTransactions",
|
||||||
|
type: "longtext",
|
||||||
|
nullable: false)
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_AdvancePaymentTransactions_ProjectId",
|
||||||
|
table: "AdvancePaymentTransactions",
|
||||||
|
column: "ProjectId");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_AdvancePaymentTransactions_Projects_ProjectId",
|
||||||
|
table: "AdvancePaymentTransactions",
|
||||||
|
column: "ProjectId",
|
||||||
|
principalTable: "Projects",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Expenses_ExpenseCategoryMasters_ExpenseCategoryId",
|
||||||
|
table: "Expenses",
|
||||||
|
column: "ExpenseCategoryId",
|
||||||
|
principalTable: "ExpenseCategoryMasters",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_AdvancePaymentTransactions_Projects_ProjectId",
|
||||||
|
table: "AdvancePaymentTransactions");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Expenses_ExpenseCategoryMasters_ExpenseCategoryId",
|
||||||
|
table: "Expenses");
|
||||||
|
|
||||||
|
migrationBuilder.DropIndex(
|
||||||
|
name: "IX_AdvancePaymentTransactions_ProjectId",
|
||||||
|
table: "AdvancePaymentTransactions");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "ProjectId",
|
||||||
|
table: "AdvancePaymentTransactions");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "Title",
|
||||||
|
table: "AdvancePaymentTransactions");
|
||||||
|
|
||||||
|
migrationBuilder.RenameColumn(
|
||||||
|
name: "ExpenseCategoryId",
|
||||||
|
table: "Expenses",
|
||||||
|
newName: "ExpensesTypeId");
|
||||||
|
|
||||||
|
migrationBuilder.RenameIndex(
|
||||||
|
name: "IX_Expenses_ExpenseCategoryId",
|
||||||
|
table: "Expenses",
|
||||||
|
newName: "IX_Expenses_ExpensesTypeId");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Expenses_ExpensesTypeMaster_ExpensesTypeId",
|
||||||
|
table: "Expenses",
|
||||||
|
column: "ExpensesTypeId",
|
||||||
|
principalTable: "ExpensesTypeMaster",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2097,15 +2097,24 @@ namespace Marco.Pms.DataAccess.Migrations
|
|||||||
b.Property<bool>("IsActive")
|
b.Property<bool>("IsActive")
|
||||||
.HasColumnType("tinyint(1)");
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.Property<Guid>("ProjectId")
|
||||||
|
.HasColumnType("char(36)");
|
||||||
|
|
||||||
b.Property<Guid>("TenantId")
|
b.Property<Guid>("TenantId")
|
||||||
.HasColumnType("char(36)");
|
.HasColumnType("char(36)");
|
||||||
|
|
||||||
|
b.Property<string>("Title")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Id");
|
||||||
|
|
||||||
b.HasIndex("CreatedById");
|
b.HasIndex("CreatedById");
|
||||||
|
|
||||||
b.HasIndex("EmployeeId");
|
b.HasIndex("EmployeeId");
|
||||||
|
|
||||||
|
b.HasIndex("ProjectId");
|
||||||
|
|
||||||
b.HasIndex("TenantId");
|
b.HasIndex("TenantId");
|
||||||
|
|
||||||
b.ToTable("AdvancePaymentTransactions");
|
b.ToTable("AdvancePaymentTransactions");
|
||||||
@ -2310,13 +2319,13 @@ namespace Marco.Pms.DataAccess.Migrations
|
|||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasColumnType("longtext");
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<Guid>("ExpenseCategoryId")
|
||||||
|
.HasColumnType("char(36)");
|
||||||
|
|
||||||
b.Property<string>("ExpenseUId")
|
b.Property<string>("ExpenseUId")
|
||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasColumnType("longtext");
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
b.Property<Guid>("ExpensesTypeId")
|
|
||||||
.HasColumnType("char(36)");
|
|
||||||
|
|
||||||
b.Property<string>("GSTNumber")
|
b.Property<string>("GSTNumber")
|
||||||
.HasColumnType("longtext");
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
@ -2369,7 +2378,7 @@ namespace Marco.Pms.DataAccess.Migrations
|
|||||||
|
|
||||||
b.HasIndex("CreatedById");
|
b.HasIndex("CreatedById");
|
||||||
|
|
||||||
b.HasIndex("ExpensesTypeId");
|
b.HasIndex("ExpenseCategoryId");
|
||||||
|
|
||||||
b.HasIndex("PaidById");
|
b.HasIndex("PaidById");
|
||||||
|
|
||||||
@ -6208,6 +6217,12 @@ namespace Marco.Pms.DataAccess.Migrations
|
|||||||
.OnDelete(DeleteBehavior.Cascade)
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
.IsRequired();
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("Marco.Pms.Model.Projects.Project", "Project")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ProjectId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
b.HasOne("Marco.Pms.Model.TenantModels.Tenant", "Tenant")
|
b.HasOne("Marco.Pms.Model.TenantModels.Tenant", "Tenant")
|
||||||
.WithMany()
|
.WithMany()
|
||||||
.HasForeignKey("TenantId")
|
.HasForeignKey("TenantId")
|
||||||
@ -6218,6 +6233,8 @@ namespace Marco.Pms.DataAccess.Migrations
|
|||||||
|
|
||||||
b.Navigation("Employee");
|
b.Navigation("Employee");
|
||||||
|
|
||||||
|
b.Navigation("Project");
|
||||||
|
|
||||||
b.Navigation("Tenant");
|
b.Navigation("Tenant");
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -6298,9 +6315,9 @@ namespace Marco.Pms.DataAccess.Migrations
|
|||||||
.OnDelete(DeleteBehavior.Cascade)
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
.IsRequired();
|
.IsRequired();
|
||||||
|
|
||||||
b.HasOne("Marco.Pms.Model.Master.ExpensesTypeMaster", "ExpensesType")
|
b.HasOne("Marco.Pms.Model.Expenses.ExpenseCategoryMaster", "ExpenseCategory")
|
||||||
.WithMany()
|
.WithMany()
|
||||||
.HasForeignKey("ExpensesTypeId")
|
.HasForeignKey("ExpenseCategoryId")
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
.IsRequired();
|
.IsRequired();
|
||||||
|
|
||||||
@ -6346,7 +6363,7 @@ namespace Marco.Pms.DataAccess.Migrations
|
|||||||
|
|
||||||
b.Navigation("CreatedBy");
|
b.Navigation("CreatedBy");
|
||||||
|
|
||||||
b.Navigation("ExpensesType");
|
b.Navigation("ExpenseCategory");
|
||||||
|
|
||||||
b.Navigation("PaidBy");
|
b.Navigation("PaidBy");
|
||||||
|
|
||||||
|
|||||||
@ -5,7 +5,7 @@ namespace Marco.Pms.Model.Dtos.Expenses
|
|||||||
public class CreateExpensesDto
|
public class CreateExpensesDto
|
||||||
{
|
{
|
||||||
public required Guid ProjectId { get; set; }
|
public required Guid ProjectId { get; set; }
|
||||||
public required Guid ExpensesTypeId { get; set; }
|
public required Guid ExpenseCategoryId { get; set; }
|
||||||
public required Guid PaymentModeId { get; set; }
|
public required Guid PaymentModeId { get; set; }
|
||||||
public required Guid PaidById { get; set; }
|
public required Guid PaidById { get; set; }
|
||||||
public DateTime TransactionDate { get; set; } = DateTime.Now;
|
public DateTime TransactionDate { get; set; } = DateTime.Now;
|
||||||
|
|||||||
@ -6,7 +6,7 @@ namespace Marco.Pms.Model.Dtos.Expenses
|
|||||||
{
|
{
|
||||||
public required Guid Id { get; set; }
|
public required Guid Id { get; set; }
|
||||||
public required Guid ProjectId { get; set; }
|
public required Guid ProjectId { get; set; }
|
||||||
public required Guid ExpensesTypeId { get; set; }
|
public required Guid ExpenseCategoryId { get; set; }
|
||||||
public required Guid PaymentModeId { get; set; }
|
public required Guid PaymentModeId { get; set; }
|
||||||
public required Guid PaidById { get; set; }
|
public required Guid PaidById { get; set; }
|
||||||
public DateTime TransactionDate { get; set; } = DateTime.Now;
|
public DateTime TransactionDate { get; set; } = DateTime.Now;
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
using Marco.Pms.Model.Employees;
|
using Marco.Pms.Model.Employees;
|
||||||
|
using Marco.Pms.Model.Projects;
|
||||||
using Marco.Pms.Model.Utilities;
|
using Marco.Pms.Model.Utilities;
|
||||||
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
|
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
@ -10,6 +11,12 @@ namespace Marco.Pms.Model.Expenses
|
|||||||
public Guid Id { get; set; }
|
public Guid Id { get; set; }
|
||||||
public string FinanceUIdPrefix { get; set; } = default!;
|
public string FinanceUIdPrefix { get; set; } = default!;
|
||||||
public int FinanceUIdPostfix { get; set; }
|
public int FinanceUIdPostfix { get; set; }
|
||||||
|
public string Title { get; set; } = default!;
|
||||||
|
public Guid ProjectId { get; set; }
|
||||||
|
|
||||||
|
[ValidateNever]
|
||||||
|
[ForeignKey("ProjectId")]
|
||||||
|
public Project? Project { get; set; }
|
||||||
public Guid EmployeeId { get; set; }
|
public Guid EmployeeId { get; set; }
|
||||||
|
|
||||||
[ValidateNever]
|
[ValidateNever]
|
||||||
|
|||||||
@ -15,11 +15,11 @@ namespace Marco.Pms.Model.Expenses
|
|||||||
[ValidateNever]
|
[ValidateNever]
|
||||||
[ForeignKey("ProjectId")]
|
[ForeignKey("ProjectId")]
|
||||||
public Project? Project { get; set; }
|
public Project? Project { get; set; }
|
||||||
public Guid ExpensesTypeId { get; set; }
|
public Guid ExpenseCategoryId { get; set; }
|
||||||
|
|
||||||
[ValidateNever]
|
[ValidateNever]
|
||||||
[ForeignKey("ExpensesTypeId")]
|
[ForeignKey("ExpenseCategoryId")]
|
||||||
public ExpensesTypeMaster? ExpensesType { get; set; }
|
public ExpenseCategoryMaster? ExpenseCategory { get; set; }
|
||||||
public Guid PaymentModeId { get; set; }
|
public Guid PaymentModeId { get; set; }
|
||||||
|
|
||||||
[ValidateNever]
|
[ValidateNever]
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
public List<Guid>? StatusIds { get; set; }
|
public List<Guid>? StatusIds { get; set; }
|
||||||
public List<Guid>? CreatedByIds { get; set; }
|
public List<Guid>? CreatedByIds { get; set; }
|
||||||
public List<Guid>? PaidById { get; set; }
|
public List<Guid>? PaidById { get; set; }
|
||||||
public List<Guid>? ExpenseTypeIds { get; set; }
|
public List<Guid>? ExpenseCategoryIds { get; set; }
|
||||||
public bool IsTransactionDate { get; set; } = false;
|
public bool IsTransactionDate { get; set; } = false;
|
||||||
public DateTime? StartDate { get; set; }
|
public DateTime? StartDate { get; set; }
|
||||||
public DateTime? EndDate { get; set; }
|
public DateTime? EndDate { get; set; }
|
||||||
|
|||||||
@ -8,7 +8,7 @@ namespace Marco.Pms.Model.MongoDBModels.Expenses
|
|||||||
{
|
{
|
||||||
public string Id { get; set; } = string.Empty;
|
public string Id { get; set; } = string.Empty;
|
||||||
public ProjectBasicMongoDB Project { get; set; } = new ProjectBasicMongoDB();
|
public ProjectBasicMongoDB Project { get; set; } = new ProjectBasicMongoDB();
|
||||||
public ExpensesTypeMasterMongoDB ExpensesType { get; set; } = new ExpensesTypeMasterMongoDB();
|
public ExpenseCategoryMasterMongoDB ExpenseCategory { get; set; } = new ExpenseCategoryMasterMongoDB();
|
||||||
public PaymentModeMatserMongoDB PaymentMode { get; set; } = new PaymentModeMatserMongoDB();
|
public PaymentModeMatserMongoDB PaymentMode { get; set; } = new PaymentModeMatserMongoDB();
|
||||||
public BasicEmployeeMongoDB PaidBy { get; set; } = new BasicEmployeeMongoDB();
|
public BasicEmployeeMongoDB PaidBy { get; set; } = new BasicEmployeeMongoDB();
|
||||||
public BasicEmployeeMongoDB CreatedBy { get; set; } = new BasicEmployeeMongoDB();
|
public BasicEmployeeMongoDB CreatedBy { get; set; } = new BasicEmployeeMongoDB();
|
||||||
|
|||||||
@ -0,0 +1,11 @@
|
|||||||
|
namespace Marco.Pms.Model.MongoDBModels.Masters
|
||||||
|
{
|
||||||
|
public class ExpenseCategoryMasterMongoDB
|
||||||
|
{
|
||||||
|
public string Id { get; set; } = string.Empty;
|
||||||
|
public string Name { get; set; } = string.Empty;
|
||||||
|
public bool NoOfPersonsRequired { get; set; }
|
||||||
|
public string Description { get; set; } = string.Empty;
|
||||||
|
public string TenantId { get; set; } = string.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -9,7 +9,7 @@ namespace Marco.Pms.Model.ViewModels.Expenses
|
|||||||
{
|
{
|
||||||
public Guid Id { get; set; }
|
public Guid Id { get; set; }
|
||||||
public ProjectInfoVM? Project { get; set; }
|
public ProjectInfoVM? Project { get; set; }
|
||||||
public ExpensesTypeMasterVM? ExpensesType { get; set; }
|
public ExpensesCategoryMasterVM? ExpensesType { get; set; }
|
||||||
public PaymentModeMatserVM? PaymentMode { get; set; }
|
public PaymentModeMatserVM? PaymentMode { get; set; }
|
||||||
public BasicEmployeeVM? PaidBy { get; set; }
|
public BasicEmployeeVM? PaidBy { get; set; }
|
||||||
public BasicEmployeeVM? CreatedBy { get; set; }
|
public BasicEmployeeVM? CreatedBy { get; set; }
|
||||||
|
|||||||
@ -8,7 +8,7 @@ namespace Marco.Pms.Model.ViewModels.Expanses
|
|||||||
{
|
{
|
||||||
public Guid Id { get; set; }
|
public Guid Id { get; set; }
|
||||||
public ProjectInfoVM? Project { get; set; }
|
public ProjectInfoVM? Project { get; set; }
|
||||||
public ExpensesTypeMasterVM? ExpensesType { get; set; }
|
public ExpensesCategoryMasterVM? ExpensesCategory { get; set; }
|
||||||
public PaymentModeMatserVM? PaymentMode { get; set; }
|
public PaymentModeMatserVM? PaymentMode { get; set; }
|
||||||
public BasicEmployeeVM? PaidBy { get; set; }
|
public BasicEmployeeVM? PaidBy { get; set; }
|
||||||
public BasicEmployeeVM? CreatedBy { get; set; }
|
public BasicEmployeeVM? CreatedBy { get; set; }
|
||||||
|
|||||||
@ -0,0 +1,12 @@
|
|||||||
|
namespace Marco.Pms.Model.ViewModels.Expenses
|
||||||
|
{
|
||||||
|
public class PaymentRequestAttachmentVM
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
public string? FileName { get; set; }
|
||||||
|
public string? Url { get; set; }
|
||||||
|
public string? ThumbUrl { get; set; }
|
||||||
|
public long FileSize { get; set; }
|
||||||
|
public string? ContentType { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,32 @@
|
|||||||
|
using Marco.Pms.Model.Expenses;
|
||||||
|
using Marco.Pms.Model.Master;
|
||||||
|
using Marco.Pms.Model.ViewModels.Activities;
|
||||||
|
using Marco.Pms.Model.ViewModels.Master;
|
||||||
|
using Marco.Pms.Model.ViewModels.Projects;
|
||||||
|
|
||||||
|
namespace Marco.Pms.Model.ViewModels.Expenses
|
||||||
|
{
|
||||||
|
public class PaymentRequestDetailsVM
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
public string? Title { get; set; }
|
||||||
|
public string? Description { get; set; }
|
||||||
|
public string? PaymentRequestUID { get; set; }
|
||||||
|
public string? Payee { get; set; }
|
||||||
|
public CurrencyMaster? Currency { get; set; }
|
||||||
|
public double Amount { get; set; }
|
||||||
|
public DateTime DueDate { get; set; }
|
||||||
|
public BasicProjectVM? Project { get; set; }
|
||||||
|
public RecurringPayment? RecurringPayment { get; set; }
|
||||||
|
public ExpensesCategoryMasterVM? ExpenseCategory { get; set; }
|
||||||
|
public ExpensesStatusMasterVM? ExpenseStatus { get; set; }
|
||||||
|
public bool IsAdvancePayment { get; set; }
|
||||||
|
public DateTime CreatedAt { get; set; }
|
||||||
|
public BasicEmployeeVM? CreatedBy { get; set; }
|
||||||
|
public DateTime UpdatedAt { get; set; }
|
||||||
|
public BasicEmployeeVM? UpdatedBy { get; set; }
|
||||||
|
public List<ExpensesStatusMasterVM>? NextStatus { get; set; }
|
||||||
|
public List<PaymentRequestAttachmentVM>? Attachments { get; set; }
|
||||||
|
public bool IsActive { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -18,14 +18,11 @@ namespace Marco.Pms.Model.ViewModels.Expenses
|
|||||||
public DateTime DueDate { get; set; }
|
public DateTime DueDate { get; set; }
|
||||||
public BasicProjectVM? Project { get; set; }
|
public BasicProjectVM? Project { get; set; }
|
||||||
public RecurringPayment? RecurringPayment { get; set; }
|
public RecurringPayment? RecurringPayment { get; set; }
|
||||||
public ExpensesTypeMasterVM? ExpenseCategory { get; set; }
|
public ExpensesCategoryMasterVM? ExpenseCategory { get; set; }
|
||||||
public ExpensesStatusMasterVM? ExpenseStatus { get; set; }
|
public ExpensesStatusMasterVM? ExpenseStatus { get; set; }
|
||||||
public bool IsAdvancePayment { get; set; }
|
public bool IsAdvancePayment { get; set; }
|
||||||
public bool IsActive { get; set; }
|
|
||||||
public DateTime CreatedAt { get; set; }
|
public DateTime CreatedAt { get; set; }
|
||||||
public BasicEmployeeVM? CreatedBy { get; set; }
|
public BasicEmployeeVM? CreatedBy { get; set; }
|
||||||
public DateTime? UpdatedAt { get; set; }
|
public bool IsActive { get; set; }
|
||||||
public Guid? UpdatedById { get; set; }
|
|
||||||
public BasicEmployeeVM? UpdatedBy { get; set; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
namespace Marco.Pms.Model.ViewModels.Master
|
namespace Marco.Pms.Model.ViewModels.Master
|
||||||
{
|
{
|
||||||
public class ExpensesTypeMasterVM
|
public class ExpensesCategoryMasterVM
|
||||||
{
|
{
|
||||||
public Guid Id { get; set; }
|
public Guid Id { get; set; }
|
||||||
public string Name { get; set; } = string.Empty;
|
public string Name { get; set; } = string.Empty;
|
||||||
@ -642,7 +642,7 @@ namespace Marco.Pms.Services.Controllers
|
|||||||
baseQuery = baseQuery.Where(e => e.ProjectId == projectId);
|
baseQuery = baseQuery.Where(e => e.ProjectId == projectId);
|
||||||
|
|
||||||
if (categoryId.HasValue)
|
if (categoryId.HasValue)
|
||||||
baseQuery = baseQuery.Where(e => e.ExpensesTypeId == categoryId);
|
baseQuery = baseQuery.Where(e => e.ExpenseCategoryId == categoryId);
|
||||||
|
|
||||||
// Single server-side group/aggregate by project
|
// Single server-side group/aggregate by project
|
||||||
var report = await baseQuery
|
var report = await baseQuery
|
||||||
@ -716,10 +716,10 @@ namespace Marco.Pms.Services.Controllers
|
|||||||
// Project to a minimal shape before grouping to avoid loading navigation graphs
|
// Project to a minimal shape before grouping to avoid loading navigation graphs
|
||||||
// Group by expense type name; adjust to the correct key if ExpensesCategory is an enum or navigation
|
// Group by expense type name; adjust to the correct key if ExpensesCategory is an enum or navigation
|
||||||
var query = baseQuery
|
var query = baseQuery
|
||||||
.Where(e => e.ExpensesType != null)
|
.Where(e => e.ExpenseCategory != null)
|
||||||
.Select(e => new
|
.Select(e => new
|
||||||
{
|
{
|
||||||
ExpenseTypeName = e.ExpensesType!.Name, // If enum, use e.ExpensesCategory.ToString()
|
ExpenseTypeName = e.ExpenseCategory!.Name, // If enum, use e.ExpensesCategory.ToString()
|
||||||
Amount = e.Amount,
|
Amount = e.Amount,
|
||||||
StatusId = e.StatusId
|
StatusId = e.StatusId
|
||||||
})
|
})
|
||||||
|
|||||||
@ -48,10 +48,10 @@ namespace Marco.Pms.Services.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("details")]
|
[HttpGet("details")]
|
||||||
public async Task<IActionResult> GetExpenseDetails([FromQuery] Guid? id, [FromQuery] string? financeUId)
|
public async Task<IActionResult> GetExpenseDetails([FromQuery] Guid? id, [FromQuery] string? expenseUId)
|
||||||
{
|
{
|
||||||
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
||||||
var response = await _expensesService.GetExpenseDetailsAsync(id, financeUId, loggedInEmployee, tenantId);
|
var response = await _expensesService.GetExpenseDetailsAsync(id, expenseUId, loggedInEmployee, tenantId);
|
||||||
return StatusCode(response.StatusCode, response);
|
return StatusCode(response.StatusCode, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,6 +134,15 @@ namespace Marco.Pms.Services.Controllers
|
|||||||
var response = await _expensesService.GetPaymentRequestListAsync(searchString, filter, isActive, pageSize, pageNumber, loggedInEmployee, tenantId);
|
var response = await _expensesService.GetPaymentRequestListAsync(searchString, filter, isActive, pageSize, pageNumber, loggedInEmployee, tenantId);
|
||||||
return StatusCode(response.StatusCode, response);
|
return StatusCode(response.StatusCode, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpGet("get/payment-request/details/{id?}")]
|
||||||
|
public async Task<IActionResult> GetPaymentRequestDetails(Guid? id, [FromQuery] string? paymentRequestUId)
|
||||||
|
{
|
||||||
|
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
||||||
|
var response = await _expensesService.GetPaymentRequestDetailsAsync(id, paymentRequestUId, loggedInEmployee, tenantId);
|
||||||
|
return StatusCode(response.StatusCode, response);
|
||||||
|
}
|
||||||
|
|
||||||
[HttpPost("payment-request/create")]
|
[HttpPost("payment-request/create")]
|
||||||
public async Task<IActionResult> CreatePaymentRequest([FromBody] PaymentRequestDto model)
|
public async Task<IActionResult> CreatePaymentRequest([FromBody] PaymentRequestDto model)
|
||||||
{
|
{
|
||||||
@ -146,6 +155,7 @@ namespace Marco.Pms.Services.Controllers
|
|||||||
}
|
}
|
||||||
return StatusCode(response.StatusCode, response);
|
return StatusCode(response.StatusCode, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPut("payment-request/edit/{id}")]
|
[HttpPut("payment-request/edit/{id}")]
|
||||||
public async Task<IActionResult> EditPaymentRequest(Guid id, [FromBody] PaymentRequestDto model)
|
public async Task<IActionResult> EditPaymentRequest(Guid id, [FromBody] PaymentRequestDto model)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1144,7 +1144,7 @@ namespace Marco.Pms.Services.Helpers
|
|||||||
var expenseIds = model.Select(m => m.Id).ToList();
|
var expenseIds = model.Select(m => m.Id).ToList();
|
||||||
var projectIds = model.Select(m => m.ProjectId).ToList();
|
var projectIds = model.Select(m => m.ProjectId).ToList();
|
||||||
var statusIds = model.Select(m => m.StatusId).ToList();
|
var statusIds = model.Select(m => m.StatusId).ToList();
|
||||||
var expensesTypeIds = model.Select(m => m.ExpensesTypeId).ToList();
|
var expensesTypeIds = model.Select(m => m.ExpenseCategoryId).ToList();
|
||||||
var paymentModeIds = model.Select(m => m.PaymentModeId).ToList();
|
var paymentModeIds = model.Select(m => m.PaymentModeId).ToList();
|
||||||
var createdByIds = model.Select(m => m.CreatedById).ToList();
|
var createdByIds = model.Select(m => m.CreatedById).ToList();
|
||||||
var reviewedByIds = model.Select(m => m.ReviewedById).ToList();
|
var reviewedByIds = model.Select(m => m.ReviewedById).ToList();
|
||||||
@ -1273,7 +1273,7 @@ namespace Marco.Pms.Services.Helpers
|
|||||||
|
|
||||||
response.NextStatus = statusMappings.Where(s => s.StatusId == m.StatusId).Select(s => _mapper.Map<List<ExpensesStatusMasterMongoDB>>(s.NextStatus)).FirstOrDefault() ?? new List<ExpensesStatusMasterMongoDB>();
|
response.NextStatus = statusMappings.Where(s => s.StatusId == m.StatusId).Select(s => _mapper.Map<List<ExpensesStatusMasterMongoDB>>(s.NextStatus)).FirstOrDefault() ?? new List<ExpensesStatusMasterMongoDB>();
|
||||||
response.PaymentMode = paymentModes.Where(pm => pm.Id == m.PaymentModeId).Select(pm => _mapper.Map<PaymentModeMatserMongoDB>(pm)).FirstOrDefault() ?? new PaymentModeMatserMongoDB();
|
response.PaymentMode = paymentModes.Where(pm => pm.Id == m.PaymentModeId).Select(pm => _mapper.Map<PaymentModeMatserMongoDB>(pm)).FirstOrDefault() ?? new PaymentModeMatserMongoDB();
|
||||||
response.ExpensesType = expenseTypes.Where(et => et.Id == m.ExpensesTypeId).Select(et => _mapper.Map<ExpensesTypeMasterMongoDB>(et)).FirstOrDefault() ?? new ExpensesTypeMasterMongoDB();
|
response.ExpenseCategory = expenseTypes.Where(et => et.Id == m.ExpenseCategoryId).Select(et => _mapper.Map<ExpenseCategoryMasterMongoDB>(et)).FirstOrDefault() ?? new ExpenseCategoryMasterMongoDB();
|
||||||
response.Documents = billAttachments.Where(ba => ba.ExpensesId == m.Id).Select(ba => ba.Documents).FirstOrDefault() ?? new List<DocumentMongoDB>();
|
response.Documents = billAttachments.Where(ba => ba.ExpensesId == m.Id).Select(ba => ba.Documents).FirstOrDefault() ?? new List<DocumentMongoDB>();
|
||||||
return response;
|
return response;
|
||||||
}).ToList();
|
}).ToList();
|
||||||
@ -1315,7 +1315,7 @@ namespace Marco.Pms.Services.Helpers
|
|||||||
var expenseTypeTask = Task.Run(async () =>
|
var expenseTypeTask = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
||||||
return await dbContext.ExpensesTypeMaster.AsNoTracking().FirstOrDefaultAsync(et => et.Id == model.ExpensesTypeId && et.TenantId == tenantId);
|
return await dbContext.ExpensesTypeMaster.AsNoTracking().FirstOrDefaultAsync(et => et.Id == model.ExpenseCategoryId && et.TenantId == tenantId);
|
||||||
});
|
});
|
||||||
var paymentModeTask = Task.Run(async () =>
|
var paymentModeTask = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
@ -1403,7 +1403,7 @@ namespace Marco.Pms.Services.Helpers
|
|||||||
response.Status = _mapper.Map<ExpensesStatusMasterMongoDB>(status);
|
response.Status = _mapper.Map<ExpensesStatusMasterMongoDB>(status);
|
||||||
}
|
}
|
||||||
response.PaymentMode = _mapper.Map<PaymentModeMatserMongoDB>(paymentMode);
|
response.PaymentMode = _mapper.Map<PaymentModeMatserMongoDB>(paymentMode);
|
||||||
response.ExpensesType = _mapper.Map<ExpensesTypeMasterMongoDB>(expenseType);
|
response.ExpenseCategory = _mapper.Map<ExpenseCategoryMasterMongoDB>(expenseType);
|
||||||
if (billAttachment != null) response.Documents = billAttachment.Documents;
|
if (billAttachment != null) response.Documents = billAttachment.Documents;
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
|
|||||||
@ -257,9 +257,14 @@ namespace Marco.Pms.Services.MappingProfiles
|
|||||||
.ForMember(
|
.ForMember(
|
||||||
dest => dest.Id,
|
dest => dest.Id,
|
||||||
opt => opt.MapFrom(src => Guid.Parse(src.Id)));
|
opt => opt.MapFrom(src => Guid.Parse(src.Id)));
|
||||||
|
|
||||||
#region ======================================================= Payment Request =======================================================
|
#region ======================================================= Payment Request =======================================================
|
||||||
|
|
||||||
CreateMap<PaymentRequestDto, PaymentRequest>();
|
CreateMap<PaymentRequestDto, PaymentRequest>();
|
||||||
CreateMap<PaymentRequest, PaymentRequestVM>();
|
CreateMap<PaymentRequest, PaymentRequestVM>();
|
||||||
|
CreateMap<PaymentRequest, PaymentRequestDetailsVM>();
|
||||||
|
CreateMap<Document, PaymentRequestAttachmentVM>();
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
CreateMap<AdvancePaymentTransaction, AdvancePaymentTransactionVM>();
|
CreateMap<AdvancePaymentTransaction, AdvancePaymentTransactionVM>();
|
||||||
@ -346,10 +351,10 @@ namespace Marco.Pms.Services.MappingProfiles
|
|||||||
// Explicitly and safely convert nullable Guid to non-nullable Guid
|
// Explicitly and safely convert nullable Guid to non-nullable Guid
|
||||||
opt => opt.MapFrom(src => src.Id ?? Guid.Empty)
|
opt => opt.MapFrom(src => src.Id ?? Guid.Empty)
|
||||||
);
|
);
|
||||||
CreateMap<ExpensesTypeMaster, ExpensesTypeMasterVM>();
|
CreateMap<ExpensesTypeMaster, ExpensesCategoryMasterVM>();
|
||||||
CreateMap<ExpenseCategoryMaster, ExpensesTypeMasterVM>();
|
CreateMap<ExpenseCategoryMaster, ExpensesCategoryMasterVM>();
|
||||||
|
|
||||||
CreateMap<ExpenseCategoryMaster, ExpensesTypeMasterMongoDB>()
|
CreateMap<ExpenseCategoryMaster, ExpenseCategoryMasterMongoDB>()
|
||||||
.ForMember(
|
.ForMember(
|
||||||
dest => dest.Id,
|
dest => dest.Id,
|
||||||
opt => opt.MapFrom(src => src.Id.ToString()))
|
opt => opt.MapFrom(src => src.Id.ToString()))
|
||||||
@ -357,7 +362,7 @@ namespace Marco.Pms.Services.MappingProfiles
|
|||||||
dest => dest.TenantId,
|
dest => dest.TenantId,
|
||||||
opt => opt.MapFrom(src => src.TenantId.ToString()));
|
opt => opt.MapFrom(src => src.TenantId.ToString()));
|
||||||
|
|
||||||
CreateMap<ExpensesTypeMaster, ExpensesTypeMasterMongoDB>()
|
CreateMap<ExpensesTypeMaster, ExpenseCategoryMasterMongoDB>()
|
||||||
.ForMember(
|
.ForMember(
|
||||||
dest => dest.Id,
|
dest => dest.Id,
|
||||||
opt => opt.MapFrom(src => src.Id.ToString()))
|
opt => opt.MapFrom(src => src.Id.ToString()))
|
||||||
@ -365,7 +370,7 @@ namespace Marco.Pms.Services.MappingProfiles
|
|||||||
dest => dest.TenantId,
|
dest => dest.TenantId,
|
||||||
opt => opt.MapFrom(src => src.TenantId.ToString()));
|
opt => opt.MapFrom(src => src.TenantId.ToString()));
|
||||||
|
|
||||||
CreateMap<ExpensesTypeMasterMongoDB, ExpensesTypeMasterVM>()
|
CreateMap<ExpenseCategoryMasterMongoDB, ExpensesCategoryMasterVM>()
|
||||||
.ForMember(
|
.ForMember(
|
||||||
dest => dest.Id,
|
dest => dest.Id,
|
||||||
opt => opt.MapFrom(src => Guid.Parse(src.Id)));
|
opt => opt.MapFrom(src => Guid.Parse(src.Id)));
|
||||||
|
|||||||
@ -141,7 +141,7 @@ namespace Marco.Pms.Services.Service
|
|||||||
.Include(e => e.PaymentMode)
|
.Include(e => e.PaymentMode)
|
||||||
.Include(e => e.Project)
|
.Include(e => e.Project)
|
||||||
.Include(e => e.PaymentMode)
|
.Include(e => e.PaymentMode)
|
||||||
.Include(e => e.ExpensesType)
|
.Include(e => e.ExpenseCategory)
|
||||||
.Include(e => e.Status)
|
.Include(e => e.Status)
|
||||||
.Where(e => e.TenantId == tenantId); // Always filter by TenantId first.
|
.Where(e => e.TenantId == tenantId); // Always filter by TenantId first.
|
||||||
|
|
||||||
@ -190,9 +190,9 @@ namespace Marco.Pms.Services.Service
|
|||||||
{
|
{
|
||||||
expensesQuery = expensesQuery.Where(e => expenseFilter.PaidById.Contains(e.PaidById));
|
expensesQuery = expensesQuery.Where(e => expenseFilter.PaidById.Contains(e.PaidById));
|
||||||
}
|
}
|
||||||
if (expenseFilter.ExpenseTypeIds?.Any() == true)
|
if (expenseFilter.ExpenseCategoryIds?.Any() == true)
|
||||||
{
|
{
|
||||||
expensesQuery = expensesQuery.Where(e => expenseFilter.ExpenseTypeIds.Contains(e.ExpensesTypeId));
|
expensesQuery = expensesQuery.Where(e => expenseFilter.ExpenseCategoryIds.Contains(e.ExpenseCategoryId));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only allow filtering by 'CreatedBy' if the user has 'View All' permission.
|
// Only allow filtering by 'CreatedBy' if the user has 'View All' permission.
|
||||||
@ -287,14 +287,14 @@ namespace Marco.Pms.Services.Service
|
|||||||
return ApiResponse<object>.ErrorResponse("Error Occured", ExceptionMapper(ex), 500);
|
return ApiResponse<object>.ErrorResponse("Error Occured", ExceptionMapper(ex), 500);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public async Task<ApiResponse<object>> GetExpenseDetailsAsync(Guid? id, string? financeUId, Employee loggedInEmployee, Guid tenantId)
|
public async Task<ApiResponse<object>> GetExpenseDetailsAsync(Guid? id, string? expenseUId, Employee loggedInEmployee, Guid tenantId)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (!id.HasValue && string.IsNullOrWhiteSpace(financeUId))
|
if (!id.HasValue && string.IsNullOrWhiteSpace(expenseUId))
|
||||||
{
|
{
|
||||||
_logger.LogWarning("User do not provided id nor expenseUId");
|
_logger.LogWarning("Invalid parameters: Both Id and PaymentRequestUID are null or empty.");
|
||||||
return ApiResponse<object>.ErrorResponse("Id or ExpenseUId atleast one must be provided", "Id or ExpenseUId atleast one must be provided", 400);
|
return ApiResponse<object>.ErrorResponse("At least one parameter (Id or expenseUId) must be provided.", "Invalid argument.", 400);
|
||||||
}
|
}
|
||||||
ExpenseDetailsMongoDB? expenseDetails = null;
|
ExpenseDetailsMongoDB? expenseDetails = null;
|
||||||
if (expenseDetails == null)
|
if (expenseDetails == null)
|
||||||
@ -308,9 +308,9 @@ namespace Marco.Pms.Services.Service
|
|||||||
.Include(e => e.PaymentMode)
|
.Include(e => e.PaymentMode)
|
||||||
.Include(e => e.Project)
|
.Include(e => e.Project)
|
||||||
.Include(e => e.PaymentMode)
|
.Include(e => e.PaymentMode)
|
||||||
.Include(e => e.ExpensesType)
|
.Include(e => e.ExpenseCategory)
|
||||||
.Include(e => e.Status)
|
.Include(e => e.Status)
|
||||||
.AsNoTracking().FirstOrDefaultAsync(e => (e.Id == id || e.ExpenseUId == financeUId) && e.TenantId == tenantId);
|
.AsNoTracking().FirstOrDefaultAsync(e => (e.Id == id || e.ExpenseUId == expenseUId) && e.TenantId == tenantId);
|
||||||
|
|
||||||
if (expense == null)
|
if (expense == null)
|
||||||
{
|
{
|
||||||
@ -318,9 +318,9 @@ namespace Marco.Pms.Services.Service
|
|||||||
{
|
{
|
||||||
_logger.LogWarning("User attempted to fetch expense details with ID {ExpenseId}, but not found in both database and cache", id);
|
_logger.LogWarning("User attempted to fetch expense details with ID {ExpenseId}, but not found in both database and cache", id);
|
||||||
}
|
}
|
||||||
else if (!string.IsNullOrWhiteSpace(financeUId))
|
else if (!string.IsNullOrWhiteSpace(expenseUId))
|
||||||
{
|
{
|
||||||
_logger.LogWarning("User attempted to fetch expense details with expenseUId {ExpenseUId}, but not found in both database and cache", financeUId);
|
_logger.LogWarning("User attempted to fetch expense details with expenseUId {ExpenseUId}, but not found in both database and cache", expenseUId);
|
||||||
}
|
}
|
||||||
return ApiResponse<object>.ErrorResponse("Expense Not Found", "Expense Not Found", 404);
|
return ApiResponse<object>.ErrorResponse("Expense Not Found", "Expense Not Found", 404);
|
||||||
}
|
}
|
||||||
@ -387,7 +387,7 @@ namespace Marco.Pms.Services.Service
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logger.LogError(ex, "An unhandled exception occurred while fetching an expense details {ExpenseId} or {ExpenseUId}.", id ?? Guid.Empty, financeUId ?? "");
|
_logger.LogError(ex, "An unhandled exception occurred while fetching an expense details {ExpenseId} or {ExpenseUId}.", id ?? Guid.Empty, expenseUId ?? "EX_00000");
|
||||||
return ApiResponse<object>.ErrorResponse("An internal server error occurred.", ExceptionMapper(ex), 500);
|
return ApiResponse<object>.ErrorResponse("An internal server error occurred.", ExceptionMapper(ex), 500);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -414,7 +414,7 @@ namespace Marco.Pms.Services.Service
|
|||||||
.Include(e => e.Project)
|
.Include(e => e.Project)
|
||||||
.Include(e => e.CreatedBy)
|
.Include(e => e.CreatedBy)
|
||||||
.Include(e => e.Status)
|
.Include(e => e.Status)
|
||||||
.Include(e => e.ExpensesType)
|
.Include(e => e.ExpenseCategory)
|
||||||
.Where(e => e.TenantId == tenantId)
|
.Where(e => e.TenantId == tenantId)
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
|
|
||||||
@ -425,7 +425,7 @@ namespace Marco.Pms.Services.Service
|
|||||||
PaidBy = expenses.Where(e => e.PaidBy != null).Select(e => new { Id = e.PaidBy!.Id, Name = $"{e.PaidBy.FirstName} {e.PaidBy.LastName}" }).Distinct().ToList(),
|
PaidBy = expenses.Where(e => e.PaidBy != null).Select(e => new { Id = e.PaidBy!.Id, Name = $"{e.PaidBy.FirstName} {e.PaidBy.LastName}" }).Distinct().ToList(),
|
||||||
CreatedBy = expenses.Where(e => e.CreatedBy != null).Select(e => new { Id = e.CreatedBy!.Id, Name = $"{e.CreatedBy.FirstName} {e.CreatedBy.LastName}" }).Distinct().ToList(),
|
CreatedBy = expenses.Where(e => e.CreatedBy != null).Select(e => new { Id = e.CreatedBy!.Id, Name = $"{e.CreatedBy.FirstName} {e.CreatedBy.LastName}" }).Distinct().ToList(),
|
||||||
Status = expenses.Where(e => e.Status != null).Select(e => new { Id = e.Status!.Id, Name = e.Status.Name }).Distinct().ToList(),
|
Status = expenses.Where(e => e.Status != null).Select(e => new { Id = e.Status!.Id, Name = e.Status.Name }).Distinct().ToList(),
|
||||||
ExpensesType = expenses.Where(e => e.ExpensesType != null).Select(e => new { Id = e.ExpensesType!.Id, Name = e.ExpensesType.Name }).Distinct().ToList()
|
ExpensesCategory = expenses.Where(e => e.ExpenseCategory != null).Select(e => new { Id = e.ExpenseCategory!.Id, Name = e.ExpenseCategory.Name }).Distinct().ToList()
|
||||||
};
|
};
|
||||||
return ApiResponse<object>.SuccessResponse(response, "Successfully fetched the filter list", 200);
|
return ApiResponse<object>.SuccessResponse(response, "Successfully fetched the filter list", 200);
|
||||||
}
|
}
|
||||||
@ -477,10 +477,10 @@ namespace Marco.Pms.Services.Service
|
|||||||
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
||||||
return await dbContext.Employees.AsNoTracking().FirstOrDefaultAsync(e => e.Id == dto.PaidById);
|
return await dbContext.Employees.AsNoTracking().FirstOrDefaultAsync(e => e.Id == dto.PaidById);
|
||||||
});
|
});
|
||||||
var expenseTypeTask = Task.Run(async () =>
|
var expenseCategoriesTask = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
||||||
return await dbContext.ExpensesTypeMaster.AsNoTracking().FirstOrDefaultAsync(et => et.Id == dto.ExpensesTypeId);
|
return await dbContext.ExpenseCategoryMasters.AsNoTracking().FirstOrDefaultAsync(et => et.Id == dto.ExpenseCategoryId);
|
||||||
});
|
});
|
||||||
var paymentModeTask = Task.Run(async () =>
|
var paymentModeTask = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
@ -515,7 +515,7 @@ namespace Marco.Pms.Services.Service
|
|||||||
|
|
||||||
|
|
||||||
// Await all prerequisite checks at once.
|
// Await all prerequisite checks at once.
|
||||||
await Task.WhenAll(hasUploadPermissionTask, projectTask, expenseTypeTask, paymentModeTask, statusMappingTask, paidByTask, expenseUIdTask);
|
await Task.WhenAll(hasUploadPermissionTask, projectTask, expenseCategoriesTask, paymentModeTask, statusMappingTask, paidByTask, expenseUIdTask);
|
||||||
|
|
||||||
// 2. Aggregate and Check Results
|
// 2. Aggregate and Check Results
|
||||||
if (!await hasUploadPermissionTask)
|
if (!await hasUploadPermissionTask)
|
||||||
@ -526,7 +526,7 @@ namespace Marco.Pms.Services.Service
|
|||||||
|
|
||||||
var validationErrors = new List<string>();
|
var validationErrors = new List<string>();
|
||||||
var project = await projectTask;
|
var project = await projectTask;
|
||||||
var expenseType = await expenseTypeTask;
|
var expenseCategory = await expenseCategoriesTask;
|
||||||
var paymentMode = await paymentModeTask;
|
var paymentMode = await paymentModeTask;
|
||||||
var statusMapping = await statusMappingTask;
|
var statusMapping = await statusMappingTask;
|
||||||
var paidBy = await paidByTask;
|
var paidBy = await paidByTask;
|
||||||
@ -534,10 +534,10 @@ namespace Marco.Pms.Services.Service
|
|||||||
|
|
||||||
if (project == null) validationErrors.Add("Project not found.");
|
if (project == null) validationErrors.Add("Project not found.");
|
||||||
if (paidBy == null) validationErrors.Add("Paid by employee not found");
|
if (paidBy == null) validationErrors.Add("Paid by employee not found");
|
||||||
if (expenseType == null) validationErrors.Add("Expense Type not found.");
|
if (expenseCategory == null) validationErrors.Add("Expense Category not found.");
|
||||||
if (paymentMode == null) validationErrors.Add("Payment Mode not found.");
|
if (paymentMode == null) validationErrors.Add("Payment Mode not found.");
|
||||||
if (statusMapping == null) validationErrors.Add("Default status 'Draft' not found.");
|
if (statusMapping == null) validationErrors.Add("Default status 'Draft' not found.");
|
||||||
if ((expenseType?.IsAttachmentRequried ?? true) && !(dto.BillAttachments?.Any() ?? false)) validationErrors.Add("Bill Attachment is requried, but not found");
|
if ((expenseCategory?.IsAttachmentRequried ?? true) && !(dto.BillAttachments?.Any() ?? false)) validationErrors.Add("Bill Attachment is requried, but not found");
|
||||||
|
|
||||||
if (validationErrors.Any())
|
if (validationErrors.Any())
|
||||||
{
|
{
|
||||||
@ -580,7 +580,7 @@ namespace Marco.Pms.Services.Service
|
|||||||
response.Status = _mapper.Map<ExpensesStatusMasterVM>(statusMapping!.Status);
|
response.Status = _mapper.Map<ExpensesStatusMasterVM>(statusMapping!.Status);
|
||||||
response.NextStatus = _mapper.Map<List<ExpensesStatusMasterVM>>(statusMapping.NextStatus);
|
response.NextStatus = _mapper.Map<List<ExpensesStatusMasterVM>>(statusMapping.NextStatus);
|
||||||
response.PaymentMode = _mapper.Map<PaymentModeMatserVM>(paymentMode);
|
response.PaymentMode = _mapper.Map<PaymentModeMatserVM>(paymentMode);
|
||||||
response.ExpensesType = _mapper.Map<ExpensesTypeMasterVM>(expenseType);
|
response.ExpensesCategory = _mapper.Map<ExpensesCategoryMasterVM>(expenseCategory);
|
||||||
|
|
||||||
_logger.LogInfo("Successfully created Expense {ExpenseId} for Project {ProjectId}.", expense.Id, expense.ProjectId);
|
_logger.LogInfo("Successfully created Expense {ExpenseId} for Project {ProjectId}.", expense.Id, expense.ProjectId);
|
||||||
return ApiResponse<object>.SuccessResponse(response, "Expense created successfully.", 201);
|
return ApiResponse<object>.SuccessResponse(response, "Expense created successfully.", 201);
|
||||||
@ -617,7 +617,7 @@ namespace Marco.Pms.Services.Service
|
|||||||
|
|
||||||
// 1. Fetch Existing Expense with Related Entities (Single Query)
|
// 1. Fetch Existing Expense with Related Entities (Single Query)
|
||||||
var expense = await _context.Expenses
|
var expense = await _context.Expenses
|
||||||
.Include(e => e.ExpensesType)
|
.Include(e => e.ExpenseCategory)
|
||||||
.Include(e => e.Project)
|
.Include(e => e.Project)
|
||||||
.Include(e => e.PaidBy).ThenInclude(e => e!.JobRole)
|
.Include(e => e.PaidBy).ThenInclude(e => e!.JobRole)
|
||||||
.Include(e => e.PaymentMode)
|
.Include(e => e.PaymentMode)
|
||||||
@ -838,7 +838,7 @@ namespace Marco.Pms.Services.Service
|
|||||||
return ApiResponse<object>.ErrorResponse("Invalid Parameters", "Invalid Parameters", 400);
|
return ApiResponse<object>.ErrorResponse("Invalid Parameters", "Invalid Parameters", 400);
|
||||||
}
|
}
|
||||||
var existingExpense = await _context.Expenses
|
var existingExpense = await _context.Expenses
|
||||||
.Include(e => e.ExpensesType)
|
.Include(e => e.ExpenseCategory)
|
||||||
.Include(e => e.Project)
|
.Include(e => e.Project)
|
||||||
.Include(e => e.PaidBy)
|
.Include(e => e.PaidBy)
|
||||||
.ThenInclude(e => e!.JobRole)
|
.ThenInclude(e => e!.JobRole)
|
||||||
@ -1103,6 +1103,29 @@ namespace Marco.Pms.Services.Service
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
var hasViewSelfPermissionTask = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
using var scope = _serviceScopeFactory.CreateScope();
|
||||||
|
var permissionService = scope.ServiceProvider.GetRequiredService<PermissionServices>();
|
||||||
|
return await permissionService.HasPermission(PermissionsMaster.ExpenseViewSelf, loggedInEmployee.Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
var hasViewAllPermissionTask = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
using var scope = _serviceScopeFactory.CreateScope();
|
||||||
|
var permissionService = scope.ServiceProvider.GetRequiredService<PermissionServices>();
|
||||||
|
return await permissionService.HasPermission(PermissionsMaster.ExpenseViewAll, loggedInEmployee.Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
await Task.WhenAll(hasViewSelfPermissionTask, hasViewAllPermissionTask);
|
||||||
|
|
||||||
|
if (!hasViewAllPermissionTask.Result && !hasViewSelfPermissionTask.Result)
|
||||||
|
{
|
||||||
|
// User has neither required permission. Deny access.
|
||||||
|
_logger.LogWarning("Access DENIED for employee {EmployeeId} attempting to get payment request list.", loggedInEmployee.Id);
|
||||||
|
return ApiResponse<object>.SuccessResponse(new List<ExpenseList>(), "You do not have permission to view any payment request.", 200);
|
||||||
|
}
|
||||||
|
|
||||||
// Initial query including the necessary navigation properties and basic multi-tenant/security constraints
|
// Initial query including the necessary navigation properties and basic multi-tenant/security constraints
|
||||||
var paymentRequestQuery = _context.PaymentRequests
|
var paymentRequestQuery = _context.PaymentRequests
|
||||||
.Include(pr => pr.Currency)
|
.Include(pr => pr.Currency)
|
||||||
@ -1120,6 +1143,11 @@ namespace Marco.Pms.Services.Service
|
|||||||
pr.CreatedBy != null &&
|
pr.CreatedBy != null &&
|
||||||
pr.CreatedBy.JobRole != null);
|
pr.CreatedBy.JobRole != null);
|
||||||
|
|
||||||
|
if (hasViewSelfPermissionTask.Result)
|
||||||
|
{
|
||||||
|
paymentRequestQuery = paymentRequestQuery.Where(pr => pr.CreatedById == loggedInEmployee.Id);
|
||||||
|
}
|
||||||
|
|
||||||
// Deserialize and apply advanced filter if provided
|
// Deserialize and apply advanced filter if provided
|
||||||
PaymentRequestFilter? paymentRequestFilter = TryDeserializePaymentRequestFilter(filter);
|
PaymentRequestFilter? paymentRequestFilter = TryDeserializePaymentRequestFilter(filter);
|
||||||
|
|
||||||
@ -1172,7 +1200,7 @@ namespace Marco.Pms.Services.Service
|
|||||||
.Where(pr =>
|
.Where(pr =>
|
||||||
pr.Payee.Contains(searchString) ||
|
pr.Payee.Contains(searchString) ||
|
||||||
pr.Title.Contains(searchString) ||
|
pr.Title.Contains(searchString) ||
|
||||||
($"{pr.UIDPrefix}/{pr.UIDPostfix:D5}").Contains(searchString)
|
(pr.UIDPrefix + "/" + pr.UIDPostfix.ToString().PadLeft(5, '0')).Contains(searchString)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1219,6 +1247,342 @@ namespace Marco.Pms.Services.Service
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<ApiResponse<object>> GetPaymentRequestDetails(Guid? id, string? paymentRequestUId, Employee loggedInEmployee, Guid tenantId)
|
||||||
|
{
|
||||||
|
if (!id.HasValue && string.IsNullOrWhiteSpace(paymentRequestUId))
|
||||||
|
{
|
||||||
|
return ApiResponse<object>.ErrorResponse("User must proivde atleast one parameter", "User must proivde atleast one parameter", 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
var hasViewSelfPermissionTask = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
using var scope = _serviceScopeFactory.CreateScope();
|
||||||
|
var permissionService = scope.ServiceProvider.GetRequiredService<PermissionServices>();
|
||||||
|
return await permissionService.HasPermission(PermissionsMaster.ExpenseViewSelf, loggedInEmployee.Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
var hasViewAllPermissionTask = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
using var scope = _serviceScopeFactory.CreateScope();
|
||||||
|
var permissionService = scope.ServiceProvider.GetRequiredService<PermissionServices>();
|
||||||
|
return await permissionService.HasPermission(PermissionsMaster.ExpenseViewAll, loggedInEmployee.Id);
|
||||||
|
});
|
||||||
|
var hasReviewPermissionTask = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
using var scope = _serviceScopeFactory.CreateScope();
|
||||||
|
var permissionService = scope.ServiceProvider.GetRequiredService<PermissionServices>();
|
||||||
|
return await permissionService.HasPermission(PermissionsMaster.ExpenseReview, loggedInEmployee.Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
var hasApprovePermissionTask = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
using var scope = _serviceScopeFactory.CreateScope();
|
||||||
|
var permissionService = scope.ServiceProvider.GetRequiredService<PermissionServices>();
|
||||||
|
return await permissionService.HasPermission(PermissionsMaster.ExpenseApprove, loggedInEmployee.Id);
|
||||||
|
});
|
||||||
|
var hasProcessPermissionTask = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
using var scope = _serviceScopeFactory.CreateScope();
|
||||||
|
var permissionService = scope.ServiceProvider.GetRequiredService<PermissionServices>();
|
||||||
|
return await permissionService.HasPermission(PermissionsMaster.ExpenseProcess, loggedInEmployee.Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
await Task.WhenAll(hasViewSelfPermissionTask, hasViewAllPermissionTask, hasReviewPermissionTask, hasApprovePermissionTask, hasProcessPermissionTask);
|
||||||
|
|
||||||
|
var hasViewSelfPermission = hasViewSelfPermissionTask.Result;
|
||||||
|
var hasViewAllPermission = hasViewAllPermissionTask.Result;
|
||||||
|
var hasReviewPermission = hasReviewPermissionTask.Result;
|
||||||
|
var hasApprovePermission = hasApprovePermissionTask.Result;
|
||||||
|
var hasProcessPermission = hasProcessPermissionTask.Result;
|
||||||
|
|
||||||
|
|
||||||
|
if (!hasViewSelfPermission && !hasViewAllPermission && !hasReviewPermission && !hasApprovePermission && !hasProcessPermission)
|
||||||
|
{
|
||||||
|
// User has neither required permission. Deny access.
|
||||||
|
_logger.LogWarning("Access DENIED for employee {EmployeeId} attempting to get payment request list.", loggedInEmployee.Id);
|
||||||
|
return ApiResponse<object>.SuccessResponse(new List<ExpenseList>(), "You do not have permission to view any payment request.", 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
var paymentRequest = await _context.PaymentRequests
|
||||||
|
.Include(pr => pr.Currency)
|
||||||
|
.Include(pr => pr.Project)
|
||||||
|
.Include(pr => pr.RecurringPayment)
|
||||||
|
.Include(pr => pr.ExpenseCategory)
|
||||||
|
.Include(pr => pr.ExpenseStatus)
|
||||||
|
.Include(pr => pr.CreatedBy)
|
||||||
|
.ThenInclude(e => e!.JobRole)
|
||||||
|
.Include(pr => pr.UpdatedBy)
|
||||||
|
.ThenInclude(e => e!.JobRole)
|
||||||
|
.Where(pr => (pr.Id == id || (pr.UIDPrefix + "/" + pr.UIDPostfix.ToString().PadLeft(5, '0')) == paymentRequestUId) &&
|
||||||
|
pr.TenantId == tenantId &&
|
||||||
|
pr.Currency != null &&
|
||||||
|
pr.ExpenseCategory != null &&
|
||||||
|
pr.ExpenseStatus != null &&
|
||||||
|
pr.CreatedBy != null &&
|
||||||
|
pr.CreatedBy.JobRole != null).FirstOrDefaultAsync();
|
||||||
|
|
||||||
|
|
||||||
|
if (paymentRequest == null)
|
||||||
|
{
|
||||||
|
return ApiResponse<object>.ErrorResponse("Payment Request not found", "Payment Request not found", 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
var selfCheck = hasViewSelfPermission && !hasViewAllPermission && !hasReviewPermission && !hasApprovePermission && !hasProcessPermission && paymentRequest.CreatedById != loggedInEmployee.Id;
|
||||||
|
if (selfCheck)
|
||||||
|
{
|
||||||
|
// User has neither required permission. Deny access.
|
||||||
|
_logger.LogWarning("Access DENIED for employee {EmployeeId} attempting to get payment request list.", loggedInEmployee.Id);
|
||||||
|
return ApiResponse<object>.SuccessResponse(new List<ExpenseList>(), "You do not have permission to view any payment request.", 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
var nextStatusTask = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||||
|
using var scope = _serviceScopeFactory.CreateScope();
|
||||||
|
var permissionService = scope.ServiceProvider.GetRequiredService<PermissionServices>();
|
||||||
|
|
||||||
|
var nextStatus = await context.ExpensesStatusMapping
|
||||||
|
.Include(esm => esm.NextStatus)
|
||||||
|
.Where(esm => esm.StatusId == paymentRequest.ExpenseStatusId && esm.NextStatus != null)
|
||||||
|
.Select(esm => esm.NextStatus!)
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
var nextStatusIds = nextStatus.Select(esm => esm.Id).ToList();
|
||||||
|
var permissionMapping = await context.StatusPermissionMapping.Where(spm => nextStatusIds.Contains(spm.StatusId)).ToListAsync();
|
||||||
|
List<ExpensesStatusMasterVM> results = new List<ExpensesStatusMasterVM>();
|
||||||
|
foreach (var status in nextStatus)
|
||||||
|
{
|
||||||
|
var permissionIds = permissionMapping.Where(spm => spm.StatusId == status.Id).Select(spm => spm.PermissionId).ToList();
|
||||||
|
var hasPermission = await permissionService.HasPermissionAny(permissionIds, loggedInEmployee.Id);
|
||||||
|
|
||||||
|
var hasStatusPermission = Review == status.Id && loggedInEmployee.Id == paymentRequest.CreatedById;
|
||||||
|
|
||||||
|
if (!hasPermission && !hasStatusPermission)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
var result = _mapper.Map<ExpensesStatusMasterVM>(status);
|
||||||
|
result.PermissionIds = permissionIds;
|
||||||
|
results.Add(result);
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
});
|
||||||
|
|
||||||
|
var documnetTask = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||||
|
var documents = await context.PaymentRequestAttachments
|
||||||
|
.Include(pra => pra.Document)
|
||||||
|
.Where(pra => pra.PaymentRequestId == paymentRequest.Id && pra.Document != null)
|
||||||
|
.Select(pra => pra.Document!)
|
||||||
|
.ToListAsync();
|
||||||
|
return documents.Select(d =>
|
||||||
|
{
|
||||||
|
var result = _mapper.Map<PaymentRequestAttachmentVM>(d);
|
||||||
|
result.Url = _s3Service.GeneratePreSignedUrl(d.S3Key);
|
||||||
|
return result;
|
||||||
|
|
||||||
|
}).ToList();
|
||||||
|
});
|
||||||
|
|
||||||
|
await Task.WhenAll(nextStatusTask, documnetTask);
|
||||||
|
|
||||||
|
var nextStatus = nextStatusTask.Result;
|
||||||
|
|
||||||
|
var attachementVMs = documnetTask.Result;
|
||||||
|
|
||||||
|
var response = _mapper.Map<PaymentRequestDetailsVM>(paymentRequest);
|
||||||
|
response.PaymentRequestUID = $"{paymentRequest.UIDPrefix}/{paymentRequest.UIDPostfix:D5}";
|
||||||
|
response.Attachments = attachementVMs;
|
||||||
|
response.NextStatus = nextStatus;
|
||||||
|
|
||||||
|
return ApiResponse<object>.SuccessResponse(response, "Payment request fetched successfully", 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ApiResponse<object>> GetPaymentRequestDetailsAsync(Guid? id, string? paymentRequestUId, Employee loggedInEmployee, Guid tenantId)
|
||||||
|
{
|
||||||
|
_logger.LogInfo("Start GetPaymentRequestDetailsAsync called by EmployeeId: {EmployeeId} for TenantId: {TenantId} with Id: {Id}, UID: {UID}",
|
||||||
|
loggedInEmployee.Id, tenantId, id ?? Guid.Empty, paymentRequestUId ?? "PY/1125/00000");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Validate input: at least one identifier must be provided
|
||||||
|
if (!id.HasValue && string.IsNullOrWhiteSpace(paymentRequestUId))
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Invalid parameters: Both Id and PaymentRequestUID are null or empty.");
|
||||||
|
return ApiResponse<object>.ErrorResponse("At least one parameter (Id or PaymentRequestUID) must be provided.", "Invalid argument.", 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check user permissions concurrently
|
||||||
|
var hasViewSelfPermissionTask = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
using var scope = _serviceScopeFactory.CreateScope();
|
||||||
|
var permissionService = scope.ServiceProvider.GetRequiredService<PermissionServices>();
|
||||||
|
return await permissionService.HasPermission(PermissionsMaster.ExpenseViewSelf, loggedInEmployee.Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
var hasViewAllPermissionTask = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
using var scope = _serviceScopeFactory.CreateScope();
|
||||||
|
var permissionService = scope.ServiceProvider.GetRequiredService<PermissionServices>();
|
||||||
|
return await permissionService.HasPermission(PermissionsMaster.ExpenseViewAll, loggedInEmployee.Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
var hasReviewPermissionTask = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
using var scope = _serviceScopeFactory.CreateScope();
|
||||||
|
var permissionService = scope.ServiceProvider.GetRequiredService<PermissionServices>();
|
||||||
|
return await permissionService.HasPermission(PermissionsMaster.ExpenseReview, loggedInEmployee.Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
var hasApprovePermissionTask = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
using var scope = _serviceScopeFactory.CreateScope();
|
||||||
|
var permissionService = scope.ServiceProvider.GetRequiredService<PermissionServices>();
|
||||||
|
return await permissionService.HasPermission(PermissionsMaster.ExpenseApprove, loggedInEmployee.Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
var hasProcessPermissionTask = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
using var scope = _serviceScopeFactory.CreateScope();
|
||||||
|
var permissionService = scope.ServiceProvider.GetRequiredService<PermissionServices>();
|
||||||
|
return await permissionService.HasPermission(PermissionsMaster.ExpenseProcess, loggedInEmployee.Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
await Task.WhenAll(hasViewSelfPermissionTask, hasViewAllPermissionTask, hasReviewPermissionTask, hasApprovePermissionTask, hasProcessPermissionTask);
|
||||||
|
|
||||||
|
bool hasViewSelfPermission = hasViewSelfPermissionTask.Result;
|
||||||
|
bool hasViewAllPermission = hasViewAllPermissionTask.Result;
|
||||||
|
bool hasReviewPermission = hasReviewPermissionTask.Result;
|
||||||
|
bool hasApprovePermission = hasApprovePermissionTask.Result;
|
||||||
|
bool hasProcessPermission = hasProcessPermissionTask.Result;
|
||||||
|
|
||||||
|
// Deny access if user has no relevant permissions
|
||||||
|
if (!hasViewSelfPermission && !hasViewAllPermission && !hasReviewPermission && !hasApprovePermission && !hasProcessPermission)
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Access DENIED: Employee {EmployeeId} has no permission to view payment requests.", loggedInEmployee.Id);
|
||||||
|
return ApiResponse<object>.SuccessResponse(new List<ExpenseList>(), "You do not have permission to view any payment request.", 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Query payment request with all necessary navigation properties and validation constraints
|
||||||
|
var paymentRequest = await _context.PaymentRequests
|
||||||
|
.Include(pr => pr.Currency)
|
||||||
|
.Include(pr => pr.Project)
|
||||||
|
.Include(pr => pr.RecurringPayment)
|
||||||
|
.Include(pr => pr.ExpenseCategory)
|
||||||
|
.Include(pr => pr.ExpenseStatus)
|
||||||
|
.Include(pr => pr.CreatedBy).ThenInclude(e => e!.JobRole)
|
||||||
|
.Include(pr => pr.UpdatedBy).ThenInclude(e => e!.JobRole)
|
||||||
|
.Where(pr =>
|
||||||
|
(pr.Id == id || (pr.UIDPrefix + "/" + pr.UIDPostfix.ToString().PadLeft(5, '0')) == paymentRequestUId) &&
|
||||||
|
pr.TenantId == tenantId &&
|
||||||
|
pr.Currency != null &&
|
||||||
|
pr.ExpenseCategory != null &&
|
||||||
|
pr.ExpenseStatus != null &&
|
||||||
|
pr.CreatedBy != null &&
|
||||||
|
pr.CreatedBy.JobRole != null)
|
||||||
|
.FirstOrDefaultAsync();
|
||||||
|
|
||||||
|
if (paymentRequest == null)
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Payment Request not found: Id={Id}, UID={UID}, TenantId={TenantId}", id ?? Guid.Empty, paymentRequestUId ?? "PY/1125/00000", tenantId);
|
||||||
|
return ApiResponse<object>.ErrorResponse("Payment Request not found.", "Payment Request not found.", 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if employee has only "view self" permission but the payment request is created by another employee => deny
|
||||||
|
bool selfCheck = hasViewSelfPermission && !hasViewAllPermission && !hasReviewPermission && !hasApprovePermission && !hasProcessPermission
|
||||||
|
&& paymentRequest.CreatedById != loggedInEmployee.Id;
|
||||||
|
|
||||||
|
if (selfCheck)
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Access DENIED: Employee {EmployeeId} lacks permission to view PaymentRequest {PaymentRequestId} created by another employee.",
|
||||||
|
loggedInEmployee.Id, paymentRequest.Id);
|
||||||
|
return ApiResponse<object>.SuccessResponse(new List<ExpenseList>(), "You do not have permission to view this payment request.", 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Concurrently fetch next possible statuses and related permissions
|
||||||
|
var nextStatusTask = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||||
|
using var scope = _serviceScopeFactory.CreateScope();
|
||||||
|
var permissionService = scope.ServiceProvider.GetRequiredService<PermissionServices>();
|
||||||
|
|
||||||
|
var nextStatuses = await context.ExpensesStatusMapping
|
||||||
|
.Include(esm => esm.NextStatus)
|
||||||
|
.Where(esm => esm.StatusId == paymentRequest.ExpenseStatusId && esm.NextStatus != null)
|
||||||
|
.Select(esm => esm.NextStatus!)
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
var nextStatusIds = nextStatuses.Select(ns => ns.Id).ToList();
|
||||||
|
var permissionMappings = await context.StatusPermissionMapping.Where(spm => nextStatusIds.Contains(spm.StatusId)).ToListAsync();
|
||||||
|
|
||||||
|
var results = new List<ExpensesStatusMasterVM>();
|
||||||
|
|
||||||
|
foreach (var status in nextStatuses)
|
||||||
|
{
|
||||||
|
var permissionIds = permissionMappings.Where(spm => spm.StatusId == status.Id).Select(spm => spm.PermissionId).ToList();
|
||||||
|
bool hasPermission = await permissionService.HasPermissionAny(permissionIds, loggedInEmployee.Id);
|
||||||
|
|
||||||
|
// Special case: allow review status if creator is the logged-in user
|
||||||
|
bool hasStatusPermission = Review == status.Id && loggedInEmployee.Id == paymentRequest.CreatedById;
|
||||||
|
|
||||||
|
if (!hasPermission && !hasStatusPermission)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var mappedStatus = _mapper.Map<ExpensesStatusMasterVM>(status);
|
||||||
|
mappedStatus.PermissionIds = permissionIds;
|
||||||
|
results.Add(mappedStatus);
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Concurrently fetch attachments with pre-signed URLs
|
||||||
|
var documentTask = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||||
|
var documents = await context.PaymentRequestAttachments
|
||||||
|
.Include(pra => pra.Document)
|
||||||
|
.Where(pra => pra.PaymentRequestId == paymentRequest.Id && pra.Document != null)
|
||||||
|
.Select(pra => pra.Document!)
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
return documents.Select(d =>
|
||||||
|
{
|
||||||
|
var attachmentVM = _mapper.Map<PaymentRequestAttachmentVM>(d);
|
||||||
|
attachmentVM.Url = _s3Service.GeneratePreSignedUrl(d.S3Key);
|
||||||
|
return attachmentVM;
|
||||||
|
}).ToList();
|
||||||
|
});
|
||||||
|
|
||||||
|
await Task.WhenAll(nextStatusTask, documentTask);
|
||||||
|
|
||||||
|
var nextStatuses = nextStatusTask.Result;
|
||||||
|
var attachmentVMs = documentTask.Result;
|
||||||
|
|
||||||
|
// Map main response model and populate additional fields
|
||||||
|
var response = _mapper.Map<PaymentRequestDetailsVM>(paymentRequest);
|
||||||
|
response.PaymentRequestUID = $"{paymentRequest.UIDPrefix}/{paymentRequest.UIDPostfix:D5}";
|
||||||
|
response.Attachments = attachmentVMs;
|
||||||
|
response.NextStatus = nextStatuses;
|
||||||
|
|
||||||
|
_logger.LogInfo("Payment request details fetched successfully for PaymentRequestId: {PaymentRequestId}, EmployeeId: {EmployeeId}", paymentRequest.Id, loggedInEmployee.Id);
|
||||||
|
|
||||||
|
return ApiResponse<object>.SuccessResponse(response, "Payment request fetched successfully.", 200);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Error in GetPaymentRequestDetailsAsync for TenantId={TenantId}, EmployeeId={EmployeeId}: {Message}", tenantId, loggedInEmployee.Id, ex.Message);
|
||||||
|
return ApiResponse<object>.ErrorResponse("An error occurred while fetching the payment request details.", ex.Message, 500);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_logger.LogInfo("End GetPaymentRequestDetailsAsync called by EmployeeId: {EmployeeId}", loggedInEmployee.Id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public async Task<ApiResponse<object>> CreatePaymentRequestAsync(PaymentRequestDto model, Employee loggedInEmployee, Guid tenantId)
|
public async Task<ApiResponse<object>> CreatePaymentRequestAsync(PaymentRequestDto model, Employee loggedInEmployee, Guid tenantId)
|
||||||
{
|
{
|
||||||
@ -1337,7 +1701,7 @@ namespace Marco.Pms.Services.Service
|
|||||||
var response = _mapper.Map<PaymentRequestVM>(paymentRequest);
|
var response = _mapper.Map<PaymentRequestVM>(paymentRequest);
|
||||||
response.PaymentRequestUID = $"{paymentRequest.UIDPrefix}/{paymentRequest.UIDPostfix:D5}";
|
response.PaymentRequestUID = $"{paymentRequest.UIDPrefix}/{paymentRequest.UIDPostfix:D5}";
|
||||||
response.Currency = currency;
|
response.Currency = currency;
|
||||||
response.ExpenseCategory = _mapper.Map<ExpensesTypeMasterVM>(expenseCategory);
|
response.ExpenseCategory = _mapper.Map<ExpensesCategoryMasterVM>(expenseCategory);
|
||||||
response.ExpenseStatus = _mapper.Map<ExpensesStatusMasterVM>(expenseStatus);
|
response.ExpenseStatus = _mapper.Map<ExpensesStatusMasterVM>(expenseStatus);
|
||||||
response.Project = _mapper.Map<BasicProjectVM>(project);
|
response.Project = _mapper.Map<BasicProjectVM>(project);
|
||||||
response.CreatedBy = _mapper.Map<BasicEmployeeVM>(loggedInEmployee);
|
response.CreatedBy = _mapper.Map<BasicEmployeeVM>(loggedInEmployee);
|
||||||
@ -1360,7 +1724,6 @@ namespace Marco.Pms.Services.Service
|
|||||||
_logger.LogInfo("End CreatePaymentRequestAsync for EmployeeId: {EmployeeId}", loggedInEmployee.Id);
|
_logger.LogInfo("End CreatePaymentRequestAsync for EmployeeId: {EmployeeId}", loggedInEmployee.Id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<ApiResponse<object>> EditPaymentRequestAsync(Guid id, PaymentRequestDto model, Employee loggedInEmployee, Guid tenantId)
|
public async Task<ApiResponse<object>> EditPaymentRequestAsync(Guid id, PaymentRequestDto model, Employee loggedInEmployee, Guid tenantId)
|
||||||
{
|
{
|
||||||
_logger.LogInfo("Start EditPaymentRequestAsync for PaymentRequestId: {PaymentRequestId}, EmployeeId: {EmployeeId}", id, loggedInEmployee.Id);
|
_logger.LogInfo("Start EditPaymentRequestAsync for PaymentRequestId: {PaymentRequestId}, EmployeeId: {EmployeeId}", id, loggedInEmployee.Id);
|
||||||
@ -1529,9 +1892,8 @@ namespace Marco.Pms.Services.Service
|
|||||||
var response = _mapper.Map<PaymentRequestVM>(paymentRequest);
|
var response = _mapper.Map<PaymentRequestVM>(paymentRequest);
|
||||||
response.PaymentRequestUID = $"{paymentRequest.UIDPrefix}/{paymentRequest.UIDPostfix:D5}";
|
response.PaymentRequestUID = $"{paymentRequest.UIDPrefix}/{paymentRequest.UIDPostfix:D5}";
|
||||||
response.Currency = currency;
|
response.Currency = currency;
|
||||||
response.ExpenseCategory = _mapper.Map<ExpensesTypeMasterVM>(expenseCategory);
|
response.ExpenseCategory = _mapper.Map<ExpensesCategoryMasterVM>(expenseCategory);
|
||||||
response.Project = _mapper.Map<BasicProjectVM>(project);
|
response.Project = _mapper.Map<BasicProjectVM>(project);
|
||||||
response.UpdatedBy = _mapper.Map<BasicEmployeeVM>(loggedInEmployee);
|
|
||||||
|
|
||||||
_logger.LogInfo("PaymentRequest updated successfully with UID: {PaymentRequestUID}", response.PaymentRequestUID);
|
_logger.LogInfo("PaymentRequest updated successfully with UID: {PaymentRequestUID}", response.PaymentRequestUID);
|
||||||
return ApiResponse<object>.SuccessResponse(response, "Payment Request updated successfully.", 200);
|
return ApiResponse<object>.SuccessResponse(response, "Payment Request updated successfully.", 200);
|
||||||
@ -1618,7 +1980,7 @@ namespace Marco.Pms.Services.Service
|
|||||||
List<ExpenseList> expenseList = new List<ExpenseList>();
|
List<ExpenseList> expenseList = new List<ExpenseList>();
|
||||||
var projectIds = model.Select(m => m.ProjectId).ToList();
|
var projectIds = model.Select(m => m.ProjectId).ToList();
|
||||||
var statusIds = model.Select(m => m.StatusId).ToList();
|
var statusIds = model.Select(m => m.StatusId).ToList();
|
||||||
var expensesTypeIds = model.Select(m => m.ExpensesTypeId).ToList();
|
var expenseCategoryIds = model.Select(m => m.ExpenseCategoryId).ToList();
|
||||||
var paymentModeIds = model.Select(m => m.PaymentModeId).ToList();
|
var paymentModeIds = model.Select(m => m.PaymentModeId).ToList();
|
||||||
var createdByIds = model.Select(m => m.CreatedById).ToList();
|
var createdByIds = model.Select(m => m.CreatedById).ToList();
|
||||||
var paidByIds = model.Select(m => m.PaidById).ToList();
|
var paidByIds = model.Select(m => m.PaidById).ToList();
|
||||||
@ -1638,10 +2000,10 @@ namespace Marco.Pms.Services.Service
|
|||||||
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
||||||
return await dbContext.Employees.AsNoTracking().Where(e => createdByIds.Contains(e.Id) && e.TenantId == tenantId).ToListAsync();
|
return await dbContext.Employees.AsNoTracking().Where(e => createdByIds.Contains(e.Id) && e.TenantId == tenantId).ToListAsync();
|
||||||
});
|
});
|
||||||
var expenseTypeTask = Task.Run(async () =>
|
var expenseCategoriesTask = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
await using var dbContext = await _dbContextFactory.CreateDbContextAsync();
|
||||||
return await dbContext.ExpensesTypeMaster.AsNoTracking().Where(et => expensesTypeIds.Contains(et.Id) && et.TenantId == tenantId).ToListAsync();
|
return await dbContext.ExpenseCategoryMasters.AsNoTracking().Where(ec => expenseCategoryIds.Contains(ec.Id) && ec.TenantId == tenantId).ToListAsync();
|
||||||
});
|
});
|
||||||
var paymentModeTask = Task.Run(async () =>
|
var paymentModeTask = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
@ -1685,10 +2047,10 @@ namespace Marco.Pms.Services.Service
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Await all prerequisite checks at once.
|
// Await all prerequisite checks at once.
|
||||||
await Task.WhenAll(projectTask, expenseTypeTask, paymentModeTask, statusMappingTask, paidByTask, createdByTask, statusTask, permissionStatusMappingTask);
|
await Task.WhenAll(projectTask, expenseCategoriesTask, paymentModeTask, statusMappingTask, paidByTask, createdByTask, statusTask, permissionStatusMappingTask);
|
||||||
|
|
||||||
var projects = projectTask.Result;
|
var projects = projectTask.Result;
|
||||||
var expenseTypes = expenseTypeTask.Result;
|
var expenseCategories = expenseCategoriesTask.Result;
|
||||||
var paymentModes = paymentModeTask.Result;
|
var paymentModes = paymentModeTask.Result;
|
||||||
var statusMappings = statusMappingTask.Result;
|
var statusMappings = statusMappingTask.Result;
|
||||||
var permissionStatusMappings = permissionStatusMappingTask.Result;
|
var permissionStatusMappings = permissionStatusMappingTask.Result;
|
||||||
@ -1721,7 +2083,7 @@ namespace Marco.Pms.Services.Service
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
response.PaymentMode = paymentModes.Where(pm => pm.Id == m.PaymentModeId).Select(pm => _mapper.Map<PaymentModeMatserVM>(pm)).FirstOrDefault();
|
response.PaymentMode = paymentModes.Where(pm => pm.Id == m.PaymentModeId).Select(pm => _mapper.Map<PaymentModeMatserVM>(pm)).FirstOrDefault();
|
||||||
response.ExpensesType = expenseTypes.Where(et => et.Id == m.ExpensesTypeId).Select(et => _mapper.Map<ExpensesTypeMasterVM>(et)).FirstOrDefault();
|
response.ExpensesCategory = expenseCategories.Where(ec => ec.Id == m.ExpenseCategoryId).Select(ec => _mapper.Map<ExpensesCategoryMasterVM>(ec)).FirstOrDefault();
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
}).ToList();
|
}).ToList();
|
||||||
@ -1802,7 +2164,7 @@ namespace Marco.Pms.Services.Service
|
|||||||
response.Status = _mapper.Map<ExpensesStatusMasterMongoDB>(status);
|
response.Status = _mapper.Map<ExpensesStatusMasterMongoDB>(status);
|
||||||
}
|
}
|
||||||
response.PaymentMode = _mapper.Map<PaymentModeMatserMongoDB>(model.PaymentMode);
|
response.PaymentMode = _mapper.Map<PaymentModeMatserMongoDB>(model.PaymentMode);
|
||||||
response.ExpensesType = _mapper.Map<ExpensesTypeMasterMongoDB>(model.ExpensesType);
|
response.ExpenseCategory = _mapper.Map<ExpenseCategoryMasterMongoDB>(model.ExpenseCategory);
|
||||||
if (billAttachment != null) response.Documents = billAttachment.Documents;
|
if (billAttachment != null) response.Documents = billAttachment.Documents;
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
|
|||||||
@ -2077,7 +2077,7 @@ namespace Marco.Pms.Services.Service
|
|||||||
{
|
{
|
||||||
// Featching the list of Expenses Type.
|
// Featching the list of Expenses Type.
|
||||||
var typeList = await _context.ExpenseCategoryMasters.Where(et => et.TenantId == tenantId && et.IsActive == isActive).ToListAsync();
|
var typeList = await _context.ExpenseCategoryMasters.Where(et => et.TenantId == tenantId && et.IsActive == isActive).ToListAsync();
|
||||||
var response = _mapper.Map<List<ExpensesTypeMasterVM>>(typeList);
|
var response = _mapper.Map<List<ExpensesCategoryMasterVM>>(typeList);
|
||||||
|
|
||||||
_logger.LogInfo("{Count} records of expense type have been fetched successfully by employee {EmployeeId}", response.Count, loggedInEmployee.Id);
|
_logger.LogInfo("{Count} records of expense type have been fetched successfully by employee {EmployeeId}", response.Count, loggedInEmployee.Id);
|
||||||
return ApiResponse<object>.SuccessResponse(response, $"{response.Count} records of expense type have been fetched successfully.", 200);
|
return ApiResponse<object>.SuccessResponse(response, $"{response.Count} records of expense type have been fetched successfully.", 200);
|
||||||
@ -2107,7 +2107,7 @@ namespace Marco.Pms.Services.Service
|
|||||||
|
|
||||||
_logger.LogInfo("New Expense Type {ExpensesTypeId} was added by employee {EmployeeId}", expensesType.Id, loggedInEmployee.Id);
|
_logger.LogInfo("New Expense Type {ExpensesTypeId} was added by employee {EmployeeId}", expensesType.Id, loggedInEmployee.Id);
|
||||||
|
|
||||||
var response = _mapper.Map<ExpensesTypeMasterVM>(expensesType);
|
var response = _mapper.Map<ExpensesCategoryMasterVM>(expensesType);
|
||||||
return ApiResponse<object>.SuccessResponse(response, "Expense type craeted Successfully", 201);
|
return ApiResponse<object>.SuccessResponse(response, "Expense type craeted Successfully", 201);
|
||||||
}
|
}
|
||||||
catch (DbUpdateException dbEx)
|
catch (DbUpdateException dbEx)
|
||||||
@ -2171,7 +2171,7 @@ namespace Marco.Pms.Services.Service
|
|||||||
}, "ExpenseCategoryMasterModificationLog");
|
}, "ExpenseCategoryMasterModificationLog");
|
||||||
|
|
||||||
// Mapping ExpensesTypeMaster to ExpensesTypeMasterVM
|
// Mapping ExpensesTypeMaster to ExpensesTypeMasterVM
|
||||||
var response = _mapper.Map<ExpensesTypeMasterVM>(expensesType);
|
var response = _mapper.Map<ExpensesCategoryMasterVM>(expensesType);
|
||||||
return ApiResponse<object>.SuccessResponse(response, "Expense type updated Successfully", 200);
|
return ApiResponse<object>.SuccessResponse(response, "Expense type updated Successfully", 200);
|
||||||
}
|
}
|
||||||
catch (DbUpdateException dbEx)
|
catch (DbUpdateException dbEx)
|
||||||
@ -2226,7 +2226,7 @@ namespace Marco.Pms.Services.Service
|
|||||||
}, "ExpenseCategoryMasterModificationLog");
|
}, "ExpenseCategoryMasterModificationLog");
|
||||||
|
|
||||||
// Mapping ExpensesTypeMaster to ExpensesTypeMasterVM
|
// Mapping ExpensesTypeMaster to ExpensesTypeMasterVM
|
||||||
var response = _mapper.Map<ExpensesTypeMasterVM>(expensesType);
|
var response = _mapper.Map<ExpensesCategoryMasterVM>(expensesType);
|
||||||
return ApiResponse<object>.SuccessResponse(response, $"Expense type {action}d Successfully", 200);
|
return ApiResponse<object>.SuccessResponse(response, $"Expense type {action}d Successfully", 200);
|
||||||
}
|
}
|
||||||
catch (DbUpdateException dbEx)
|
catch (DbUpdateException dbEx)
|
||||||
|
|||||||
@ -8,7 +8,7 @@ namespace Marco.Pms.Services.Service.ServiceInterfaces
|
|||||||
{
|
{
|
||||||
#region =================================================================== Expenses Functions ===================================================================
|
#region =================================================================== Expenses Functions ===================================================================
|
||||||
Task<ApiResponse<object>> GetExpensesListAsync(Employee loggedInEmployee, Guid tenantId, string? searchString, string? filter, int pageSize, int pageNumber);
|
Task<ApiResponse<object>> GetExpensesListAsync(Employee loggedInEmployee, Guid tenantId, string? searchString, string? filter, int pageSize, int pageNumber);
|
||||||
Task<ApiResponse<object>> GetExpenseDetailsAsync(Guid? id, string? financeUId, Employee loggedInEmployee, Guid tenantId);
|
Task<ApiResponse<object>> GetExpenseDetailsAsync(Guid? id, string? expenseUId, Employee loggedInEmployee, Guid tenantId);
|
||||||
Task<ApiResponse<object>> GetSupplerNameListAsync(Employee loggedInEmployee, Guid tenantId);
|
Task<ApiResponse<object>> GetSupplerNameListAsync(Employee loggedInEmployee, Guid tenantId);
|
||||||
Task<ApiResponse<object>> GetFilterObjectAsync(Employee loggedInEmployee, Guid tenantId);
|
Task<ApiResponse<object>> GetFilterObjectAsync(Employee loggedInEmployee, Guid tenantId);
|
||||||
Task<ApiResponse<object>> CreateExpenseAsync(CreateExpensesDto dto, Employee loggedInEmployee, Guid tenantId);
|
Task<ApiResponse<object>> CreateExpenseAsync(CreateExpensesDto dto, Employee loggedInEmployee, Guid tenantId);
|
||||||
@ -19,6 +19,7 @@ namespace Marco.Pms.Services.Service.ServiceInterfaces
|
|||||||
|
|
||||||
#region =================================================================== Payment Request Functions ===================================================================
|
#region =================================================================== Payment Request Functions ===================================================================
|
||||||
Task<ApiResponse<object>> GetPaymentRequestListAsync(string? searchString, string? filter, bool isActive, int pageSize, int pageNumber, Employee loggedInEmployee, Guid tenantId);
|
Task<ApiResponse<object>> GetPaymentRequestListAsync(string? searchString, string? filter, bool isActive, int pageSize, int pageNumber, Employee loggedInEmployee, Guid tenantId);
|
||||||
|
Task<ApiResponse<object>> GetPaymentRequestDetailsAsync(Guid? id, string? paymentRequestUId, Employee loggedInEmployee, Guid tenantId);
|
||||||
Task<ApiResponse<object>> CreatePaymentRequestAsync(PaymentRequestDto model, Employee loggedInEmployee, Guid tenantId);
|
Task<ApiResponse<object>> CreatePaymentRequestAsync(PaymentRequestDto model, Employee loggedInEmployee, Guid tenantId);
|
||||||
Task<ApiResponse<object>> EditPaymentRequestAsync(Guid id, PaymentRequestDto model, Employee loggedInEmployee, Guid tenantId);
|
Task<ApiResponse<object>> EditPaymentRequestAsync(Guid id, PaymentRequestDto model, Employee loggedInEmployee, Guid tenantId);
|
||||||
#endregion
|
#endregion
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user