Added the New API to convert payment request to expense
This commit is contained in:
parent
18d20e74db
commit
ff66d59472
7434
Marco.Pms.DataAccess/Migrations/20251104095438_Added_IsExpenseCreated_In_Payment_Request_Table.Designer.cs
generated
Normal file
7434
Marco.Pms.DataAccess/Migrations/20251104095438_Added_IsExpenseCreated_In_Payment_Request_Table.Designer.cs
generated
Normal file
File diff suppressed because one or more lines are too long
@ -0,0 +1,76 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Marco.Pms.DataAccess.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class Added_IsExpenseCreated_In_Payment_Request_Table : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AlterColumn<DateTime>(
|
||||||
|
name: "LatestPRGeneratedAt",
|
||||||
|
table: "RecurringPayments",
|
||||||
|
type: "datetime(6)",
|
||||||
|
nullable: true,
|
||||||
|
oldClrType: typeof(DateTime),
|
||||||
|
oldType: "datetime(6)");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<bool>(
|
||||||
|
name: "IsExpenseCreated",
|
||||||
|
table: "PaymentRequests",
|
||||||
|
type: "tinyint(1)",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: false);
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<string>(
|
||||||
|
name: "ExpenseUId",
|
||||||
|
table: "Expenses",
|
||||||
|
type: "longtext",
|
||||||
|
nullable: true,
|
||||||
|
oldClrType: typeof(string),
|
||||||
|
oldType: "longtext")
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4")
|
||||||
|
.OldAnnotation("MySql:CharSet", "utf8mb4");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "IsExpenseCreated",
|
||||||
|
table: "PaymentRequests");
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<DateTime>(
|
||||||
|
name: "LatestPRGeneratedAt",
|
||||||
|
table: "RecurringPayments",
|
||||||
|
type: "datetime(6)",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified),
|
||||||
|
oldClrType: typeof(DateTime),
|
||||||
|
oldType: "datetime(6)",
|
||||||
|
oldNullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.UpdateData(
|
||||||
|
table: "Expenses",
|
||||||
|
keyColumn: "ExpenseUId",
|
||||||
|
keyValue: null,
|
||||||
|
column: "ExpenseUId",
|
||||||
|
value: "");
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<string>(
|
||||||
|
name: "ExpenseUId",
|
||||||
|
table: "Expenses",
|
||||||
|
type: "longtext",
|
||||||
|
nullable: false,
|
||||||
|
oldClrType: typeof(string),
|
||||||
|
oldType: "longtext",
|
||||||
|
oldNullable: true)
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4")
|
||||||
|
.OldAnnotation("MySql:CharSet", "utf8mb4");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2347,7 +2347,6 @@ namespace Marco.Pms.DataAccess.Migrations
|
|||||||
.HasColumnType("char(36)");
|
.HasColumnType("char(36)");
|
||||||
|
|
||||||
b.Property<string>("ExpenseUId")
|
b.Property<string>("ExpenseUId")
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("longtext");
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
b.Property<string>("GSTNumber")
|
b.Property<string>("GSTNumber")
|
||||||
@ -2602,6 +2601,9 @@ namespace Marco.Pms.DataAccess.Migrations
|
|||||||
b.Property<bool>("IsAdvancePayment")
|
b.Property<bool>("IsAdvancePayment")
|
||||||
.HasColumnType("tinyint(1)");
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.Property<bool>("IsExpenseCreated")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
b.Property<DateTime?>("PaidAt")
|
b.Property<DateTime?>("PaidAt")
|
||||||
.HasColumnType("datetime(6)");
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
@ -2727,7 +2729,7 @@ namespace Marco.Pms.DataAccess.Migrations
|
|||||||
b.Property<bool>("IsVariable")
|
b.Property<bool>("IsVariable")
|
||||||
.HasColumnType("tinyint(1)");
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
b.Property<DateTime>("LatestPRGeneratedAt")
|
b.Property<DateTime?>("LatestPRGeneratedAt")
|
||||||
.HasColumnType("datetime(6)");
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
b.Property<string>("NotifyTo")
|
b.Property<string>("NotifyTo")
|
||||||
|
|||||||
13
Marco.Pms.Model/Dtos/Expenses/ExpenseConversionDto.cs
Normal file
13
Marco.Pms.Model/Dtos/Expenses/ExpenseConversionDto.cs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
using Marco.Pms.Model.Utilities;
|
||||||
|
|
||||||
|
namespace Marco.Pms.Model.Dtos.Expenses
|
||||||
|
{
|
||||||
|
public class ExpenseConversionDto
|
||||||
|
{
|
||||||
|
public required Guid PaymentRequestId { get; set; }
|
||||||
|
public required Guid PaymentModeId { get; set; }
|
||||||
|
public string? Location { get; set; }
|
||||||
|
public string? GSTNumber { get; set; }
|
||||||
|
public List<FileUploadModel>? BillAttachments { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -56,7 +56,7 @@ namespace Marco.Pms.Model.Expenses
|
|||||||
public DateTime CreatedAt { get; set; }
|
public DateTime CreatedAt { get; set; }
|
||||||
public string? TransactionId { get; set; }
|
public string? TransactionId { get; set; }
|
||||||
public string Description { get; set; } = string.Empty;
|
public string Description { get; set; } = string.Empty;
|
||||||
public string ExpenseUId { get; set; } = string.Empty;
|
public string? ExpenseUId { get; set; }
|
||||||
public string? Location { get; set; }
|
public string? Location { get; set; }
|
||||||
public string? GSTNumber { get; set; }
|
public string? GSTNumber { get; set; }
|
||||||
public string SupplerName { get; set; } = string.Empty;
|
public string SupplerName { get; set; } = string.Empty;
|
||||||
|
|||||||
@ -51,6 +51,7 @@ namespace Marco.Pms.Model.Expenses
|
|||||||
[ValidateNever]
|
[ValidateNever]
|
||||||
[ForeignKey("PaidById")]
|
[ForeignKey("PaidById")]
|
||||||
public Employee? PaidBy { get; set; }
|
public Employee? PaidBy { get; set; }
|
||||||
|
public bool IsExpenseCreated { get; set; } = false;
|
||||||
public bool IsActive { get; set; }
|
public bool IsActive { get; set; }
|
||||||
public DateTime CreatedAt { get; set; }
|
public DateTime CreatedAt { get; set; }
|
||||||
public Guid CreatedById { get; set; }
|
public Guid CreatedById { get; set; }
|
||||||
|
|||||||
@ -24,7 +24,7 @@ namespace Marco.Pms.Model.Expenses
|
|||||||
public CurrencyMaster? Currency { get; set; }
|
public CurrencyMaster? Currency { get; set; }
|
||||||
public double Amount { get; set; }
|
public double Amount { get; set; }
|
||||||
public DateTime StrikeDate { get; set; }
|
public DateTime StrikeDate { get; set; }
|
||||||
public DateTime LatestPRGeneratedAt { get; set; }
|
public DateTime? LatestPRGeneratedAt { get; set; }
|
||||||
public Guid? ProjectId { get; set; }
|
public Guid? ProjectId { get; set; }
|
||||||
|
|
||||||
[ValidateNever]
|
[ValidateNever]
|
||||||
|
|||||||
@ -32,5 +32,6 @@ namespace Marco.Pms.Model.ViewModels.Expenses
|
|||||||
public List<PaymentRequestUpdateLog>? UpdateLogs { get; set; }
|
public List<PaymentRequestUpdateLog>? UpdateLogs { get; set; }
|
||||||
public List<PaymentRequestAttachmentVM>? Attachments { get; set; }
|
public List<PaymentRequestAttachmentVM>? Attachments { get; set; }
|
||||||
public bool IsActive { get; set; }
|
public bool IsActive { get; set; }
|
||||||
|
public bool IsExpenseCreated { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -24,5 +24,6 @@ namespace Marco.Pms.Model.ViewModels.Expenses
|
|||||||
public DateTime CreatedAt { get; set; }
|
public DateTime CreatedAt { get; set; }
|
||||||
public BasicEmployeeVM? CreatedBy { get; set; }
|
public BasicEmployeeVM? CreatedBy { get; set; }
|
||||||
public bool IsActive { get; set; }
|
public bool IsActive { get; set; }
|
||||||
|
public bool IsExpenseCreated { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -172,6 +172,19 @@ namespace Marco.Pms.Services.Controllers
|
|||||||
return StatusCode(response.StatusCode, response);
|
return StatusCode(response.StatusCode, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpPost("payment-request/expense/create")]
|
||||||
|
public async Task<IActionResult> ChangeToExpanseFromPaymentRequest(ExpenseConversionDto model)
|
||||||
|
{
|
||||||
|
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
||||||
|
var response = await _expensesService.ChangeToExpanseFromPaymentRequestAsync(model, loggedInEmployee, tenantId);
|
||||||
|
if (response.Success)
|
||||||
|
{
|
||||||
|
var notification = new { LoggedInUserId = loggedInEmployee.Id, Keyword = "Expanse", Response = response.Data };
|
||||||
|
await _signalR.SendNotificationAsync(notification);
|
||||||
|
}
|
||||||
|
return StatusCode(response.StatusCode, response);
|
||||||
|
}
|
||||||
|
|
||||||
[HttpPost("payment-request/action")]
|
[HttpPost("payment-request/action")]
|
||||||
public async Task<IActionResult> ChangePaymentRequestStatus([FromBody] PaymentRequestRecordDto model)
|
public async Task<IActionResult> ChangePaymentRequestStatus([FromBody] PaymentRequestRecordDto model)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -931,7 +931,7 @@ namespace Marco.Pms.Services.Service
|
|||||||
|
|
||||||
var existingEntityBson = _updateLogHelper.EntityToBsonDocument(existingExpense); // Capture state for audit log BEFORE changes
|
var existingEntityBson = _updateLogHelper.EntityToBsonDocument(existingExpense); // Capture state for audit log BEFORE changes
|
||||||
_mapper.Map(model, existingExpense);
|
_mapper.Map(model, existingExpense);
|
||||||
_context.Entry(existingExpense).State = EntityState.Modified;
|
existingExpense.StatusId = Draft;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -1903,6 +1903,171 @@ namespace Marco.Pms.Services.Service
|
|||||||
return ApiResponse<object>.SuccessResponse(responseDto, "Status updated, but audit logging or cache update failed.");
|
return ApiResponse<object>.SuccessResponse(responseDto, "Status updated, but audit logging or cache update failed.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public async Task<ApiResponse<object>> ChangeToExpanseFromPaymentRequestAsync(ExpenseConversionDto model, Employee loggedInEmployee, Guid tenantId)
|
||||||
|
{
|
||||||
|
_logger.LogInfo("Start ChangeToExpanseFromPaymentRequestAsync called by EmployeeId: {EmployeeId} for TenantId: {TenantId} PaymentRequestId: {PaymentRequestId}",
|
||||||
|
loggedInEmployee.Id, tenantId, model.PaymentRequestId);
|
||||||
|
|
||||||
|
await using var transaction = await _context.Database.BeginTransactionAsync();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Retrieve payment request with required navigation property and validation
|
||||||
|
var paymentRequest = await _context.PaymentRequests
|
||||||
|
.Include(pr => pr.ExpenseCategory)
|
||||||
|
.FirstOrDefaultAsync(pr =>
|
||||||
|
pr.Id == model.PaymentRequestId &&
|
||||||
|
pr.ProjectId.HasValue &&
|
||||||
|
pr.ExpenseCategoryId.HasValue &&
|
||||||
|
pr.PaidById.HasValue &&
|
||||||
|
pr.PaidAt.HasValue &&
|
||||||
|
pr.ExpenseCategory != null &&
|
||||||
|
pr.TenantId == tenantId &&
|
||||||
|
pr.IsActive);
|
||||||
|
|
||||||
|
if (paymentRequest == null)
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Payment request not found for Id: {PaymentRequestId}, TenantId: {TenantId}", model.PaymentRequestId, tenantId);
|
||||||
|
return ApiResponse<object>.ErrorResponse("Payment request not found.", "Payment request not found.", 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check payment request status for eligibility to convert
|
||||||
|
if (paymentRequest.ExpenseStatusId != Processed)
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Payment request {PaymentRequestId} status is not processed. Current status: {StatusId}", paymentRequest.Id, paymentRequest.ExpenseStatusId);
|
||||||
|
return ApiResponse<object>.ErrorResponse("Payment is not processed.", "Payment is not processed.", 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify attachment requirements
|
||||||
|
var hasAttachments = model.BillAttachments?.Any() ?? false;
|
||||||
|
|
||||||
|
if (!hasAttachments && paymentRequest.ExpenseCategory!.IsAttachmentRequried)
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Attachment is required for ExpenseCategory {ExpenseCategoryId} but no attachments provided.", paymentRequest.ExpenseCategoryId);
|
||||||
|
return ApiResponse<object>.ErrorResponse("Attachment is required.", "Attachment is required.", 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Concurrently fetch status update logs and expense statuses required for logging and state transition
|
||||||
|
var statusUpdateLogTask = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||||
|
return await context.StatusUpdateLogs
|
||||||
|
.Where(sul => sul.EntityId == paymentRequest.Id && sul.TenantId == tenantId)
|
||||||
|
.OrderByDescending(sul => sul.UpdatedAt)
|
||||||
|
.ToListAsync();
|
||||||
|
});
|
||||||
|
|
||||||
|
var expenseStatusTask = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||||
|
return await context.ExpensesStatusMaster.ToListAsync();
|
||||||
|
});
|
||||||
|
|
||||||
|
await Task.WhenAll(statusUpdateLogTask, expenseStatusTask);
|
||||||
|
|
||||||
|
var statusUpdateLogs = statusUpdateLogTask.Result;
|
||||||
|
var expenseStatuses = expenseStatusTask.Result;
|
||||||
|
|
||||||
|
// Generate Expense UID with prefix for current period
|
||||||
|
string uIDPrefix = $"EX/{DateTime.Now:MM.yy}";
|
||||||
|
|
||||||
|
var lastExpense = await _context.Expenses
|
||||||
|
.Where(e => e.UIDPrefix == uIDPrefix)
|
||||||
|
.OrderByDescending(e => e.UIDPostfix)
|
||||||
|
.FirstOrDefaultAsync();
|
||||||
|
|
||||||
|
int uIDPostfix = lastExpense == null ? 1 : (lastExpense.UIDPostfix + 1);
|
||||||
|
|
||||||
|
// Get user IDs involved in review, approval, and processing from logs for audit trail linking
|
||||||
|
var reviewedLog = statusUpdateLogs.FirstOrDefault(sul => sul.NextStatusId == Approve || sul.NextStatusId == RejectedByReviewer);
|
||||||
|
var approvedLog = statusUpdateLogs.FirstOrDefault(sul => sul.NextStatusId == ProcessPending || sul.NextStatusId == RejectedByApprover);
|
||||||
|
var processedLog = statusUpdateLogs.FirstOrDefault(sul => sul.NextStatusId == Processed);
|
||||||
|
|
||||||
|
// Create new Expense record replicating required data from PaymentRequest and input model
|
||||||
|
var expense = new Expenses
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
UIDPrefix = uIDPrefix,
|
||||||
|
UIDPostfix = uIDPostfix,
|
||||||
|
ProjectId = paymentRequest.ProjectId!.Value,
|
||||||
|
ExpenseCategoryId = paymentRequest.ExpenseCategoryId!.Value,
|
||||||
|
PaymentModeId = model.PaymentModeId,
|
||||||
|
PaidById = paymentRequest.PaidById!.Value,
|
||||||
|
CreatedById = loggedInEmployee.Id,
|
||||||
|
ReviewedById = reviewedLog?.UpdatedById,
|
||||||
|
ApprovedById = approvedLog?.UpdatedById,
|
||||||
|
ProcessedById = processedLog?.UpdatedById,
|
||||||
|
TransactionDate = paymentRequest.PaidAt!.Value,
|
||||||
|
Description = paymentRequest.Description,
|
||||||
|
CreatedAt = DateTime.UtcNow,
|
||||||
|
TransactionId = paymentRequest.PaidTransactionId,
|
||||||
|
Location = model.Location,
|
||||||
|
GSTNumber = model.GSTNumber,
|
||||||
|
SupplerName = paymentRequest.Payee,
|
||||||
|
Amount = paymentRequest.Amount,
|
||||||
|
TDSPercentage = paymentRequest.TDSPercentage,
|
||||||
|
PaymentRequestId = paymentRequest.Id,
|
||||||
|
StatusId = Processed,
|
||||||
|
PreApproved = false,
|
||||||
|
IsActive = true,
|
||||||
|
TenantId = tenantId
|
||||||
|
};
|
||||||
|
|
||||||
|
_context.Expenses.Add(expense);
|
||||||
|
|
||||||
|
// Prepare ExpenseLog entries for each relevant previous status update log with reduced timestamp to preserve order
|
||||||
|
var millisecondsOffset = 60;
|
||||||
|
var expenseLogs = statusUpdateLogs
|
||||||
|
.Where(sul => expenseStatuses.Any(es => es.Id == sul.NextStatusId))
|
||||||
|
.Select(sul =>
|
||||||
|
{
|
||||||
|
var nextStatus = expenseStatuses.FirstOrDefault(es => es.Id == sul.NextStatusId);
|
||||||
|
var log = new ExpenseLog
|
||||||
|
{
|
||||||
|
ExpenseId = expense.Id,
|
||||||
|
Action = $"Status changed to '{nextStatus?.Name}'",
|
||||||
|
UpdatedById = loggedInEmployee.Id,
|
||||||
|
UpdateAt = DateTime.UtcNow.AddMilliseconds(millisecondsOffset),
|
||||||
|
Comment = $"Status changed to '{nextStatus?.Name}'",
|
||||||
|
TenantId = tenantId
|
||||||
|
};
|
||||||
|
millisecondsOffset -= 1;
|
||||||
|
return log;
|
||||||
|
}).ToList();
|
||||||
|
|
||||||
|
_context.ExpenseLogs.AddRange(expenseLogs);
|
||||||
|
|
||||||
|
// Process and upload bill attachments if present
|
||||||
|
if (hasAttachments)
|
||||||
|
{
|
||||||
|
await ProcessAndUploadAttachmentsAsync(model.BillAttachments!, expense, loggedInEmployee.Id, tenantId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mark the payment request as converted to expense to prevent duplicates
|
||||||
|
paymentRequest.IsExpenseCreated = true;
|
||||||
|
|
||||||
|
// Persist all changes within transaction to ensure atomicity
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
|
||||||
|
await transaction.CommitAsync();
|
||||||
|
|
||||||
|
_logger.LogInfo("Expense converted successfully from PaymentRequestId: {PaymentRequestId} by EmployeeId: {EmployeeId}", paymentRequest.Id, loggedInEmployee.Id);
|
||||||
|
|
||||||
|
return ApiResponse<object>.SuccessResponse(model, "Expense created successfully.", 201);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Error in ChangeToExpanseFromPaymentRequestAsync for PaymentRequestId: {PaymentRequestId}, TenantId: {TenantId}, EmployeeId: {EmployeeId}: {Message}",
|
||||||
|
model.PaymentRequestId, tenantId, loggedInEmployee.Id, ex.Message);
|
||||||
|
await transaction.RollbackAsync();
|
||||||
|
return ApiResponse<object>.ErrorResponse("An error occurred while converting payment request to expense.", ex.Message, 500);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_logger.LogInfo("End ChangeToExpanseFromPaymentRequestAsync called by 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);
|
||||||
|
|||||||
@ -24,6 +24,7 @@ namespace Marco.Pms.Services.Service.ServiceInterfaces
|
|||||||
Task<ApiResponse<object>> GetPaymentRequestFilterObjectAsync(Employee loggedInEmployee, Guid tenantId);
|
Task<ApiResponse<object>> GetPaymentRequestFilterObjectAsync(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>> ChangePaymentRequestStatusAsync(PaymentRequestRecordDto model, Employee loggedInEmployee, Guid tenantId);
|
Task<ApiResponse<object>> ChangePaymentRequestStatusAsync(PaymentRequestRecordDto model, Employee loggedInEmployee, Guid tenantId);
|
||||||
|
Task<ApiResponse<object>> ChangeToExpanseFromPaymentRequestAsync(ExpenseConversionDto 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