Added the purchase invoice related permissions

This commit is contained in:
ashutosh.nehete 2025-12-01 12:07:16 +05:30
parent e92976049e
commit 4b981b6c74
6 changed files with 9723 additions and 8 deletions

View File

@ -1416,6 +1416,7 @@ namespace Marco.Pms.DataAccess.Data
new Module { Id = new Guid("2a231490-bcb1-4bdd-91f1-f25fb7f25b23"), Name = "Employee", Description = "Employee Module", Key = "0971c7fb-6ce1-458a-ae3f-8d3205893637" },
new Module { Id = new Guid("c43db8c7-ab73-47f4-9d3b-f83e81357924"), Name = "Masters", Description = "Masters Module", Key = "504ec132-e6a9-422f-8f85-050602cfce05" },
new Module { Id = new Guid("f482a079-4dec-4f2d-9867-6baf2a4f23d9"), Name = "Tenant", Description = "Tenant Module", Key = "504ec132-e6a9-422f-8f85-050602cfce05" },
new Module { Id = new Guid("74e7af50-d55f-4b59-a724-9847ceb7bc17"), Name = "Inventory", Description = "Inventory Module", Key = "504ec132-e6a9-422f-8f85-050602cfce05" },
new Module { Id = new Guid("0a79687a-86d7-430d-a2d7-8b8603cc76a1"), Name = "Finance", Description = "Finance Module", Key = "504ec132-e6a9-422f-8f85-050602cfce05" }
);
@ -1439,6 +1440,9 @@ namespace Marco.Pms.DataAccess.Data
new Feature { Id = new Guid("39e66f81-efc6-446c-95bd-46bff6cfb606"), Description = "Managing all directory related rights", Name = "Directory Management", ModuleId = new Guid("c43db8c7-ab73-47f4-9d3b-f83e81357924"), IsActive = true },
new Feature { Id = new Guid("6d4c82d6-dbce-48ab-b8b8-f785f4d8c914"), Description = "Managing all organization related rights", Name = "Organization Management", ModuleId = new Guid("c43db8c7-ab73-47f4-9d3b-f83e81357924"), IsActive = true },
// Inventory Module
new Feature { Id = new Guid("271cc47f-7b05-46c7-b5ae-ef0177ec3b60"), Description = "Managing all Purchase invoice related rights", Name = "Purchase Invoice Management", ModuleId = new Guid("74e7af50-d55f-4b59-a724-9847ceb7bc17"), IsActive = true },
// Tenant Module
new Feature { Id = new Guid("2f3509b7-160d-410a-b9b6-daadd96c986d"), Description = "Managing all tenant related rights", Name = "Tenant Management", ModuleId = new Guid("f482a079-4dec-4f2d-9867-6baf2a4f23d9"), IsActive = true }
);
@ -1513,7 +1517,14 @@ namespace Marco.Pms.DataAccess.Data
// Organization Management Feature
new FeaturePermission { Id = new Guid("068cb3c1-49c5-4746-9f29-1fce16e820ac"), FeatureId = new Guid("6d4c82d6-dbce-48ab-b8b8-f785f4d8c914"), IsEnabled = true, Name = "Add Organization", Description = "Allow user to create new organization" },
new FeaturePermission { Id = new Guid("c1ae1363-ab8a-4bd9-a9d1-8c2c6083873a"), FeatureId = new Guid("6d4c82d6-dbce-48ab-b8b8-f785f4d8c914"), IsEnabled = true, Name = "Edit Organization", Description = "Allow the user to update the basic information of the organization" },
new FeaturePermission { Id = new Guid("7a6cf830-0008-4e03-b31d-0d050cb634f4"), FeatureId = new Guid("6d4c82d6-dbce-48ab-b8b8-f785f4d8c914"), IsEnabled = true, Name = "View Organization", Description = "Allow the user to view information of the organization" }
new FeaturePermission { Id = new Guid("7a6cf830-0008-4e03-b31d-0d050cb634f4"), FeatureId = new Guid("6d4c82d6-dbce-48ab-b8b8-f785f4d8c914"), IsEnabled = true, Name = "View Organization", Description = "Allow the user to view information of the organization" },
// Purchase Invoice Management Feature
new FeaturePermission { Id = new Guid("91e09825-512a-465e-82ad-fa355b305585"), FeatureId = new Guid("271cc47f-7b05-46c7-b5ae-ef0177ec3b60"), IsEnabled = true, Name = "View Self Purchase Invoice", Description = "Allows the user to view only the purchase invoices they created." },
new FeaturePermission { Id = new Guid("d6ae78d3-a941-4cc4-8d0a-d40479be4211"), FeatureId = new Guid("271cc47f-7b05-46c7-b5ae-ef0177ec3b60"), IsEnabled = true, Name = "View All Purchase Invoice", Description = "Allows the user to view all purchase invoices across the entire organization." },
new FeaturePermission { Id = new Guid("68ff925d-8ebf-4034-a137-8d3317c56ca1"), FeatureId = new Guid("271cc47f-7b05-46c7-b5ae-ef0177ec3b60"), IsEnabled = true, Name = "Manage Purchase Invoice", Description = "Allows full control to create, edit, and process purchase invoices." },
new FeaturePermission { Id = new Guid("a4b77638-bf31-42bb-afd4-d5bbd15ccadc"), FeatureId = new Guid("271cc47f-7b05-46c7-b5ae-ef0177ec3b60"), IsEnabled = true, Name = "Delete Purchase Invoice", Description = "Allows the user to mark purchase invoices as inactive or void." },
new FeaturePermission { Id = new Guid("b24eba39-4a92-4f7a-b33b-b5308fbc48b9"), FeatureId = new Guid("271cc47f-7b05-46c7-b5ae-ef0177ec3b60"), IsEnabled = true, Name = "Add Delivery Challan", Description = "Allows the user to create delivery challans for purchase invoices." }
);

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,78 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
#pragma warning disable CA1814 // Prefer jagged arrays over multidimensional
namespace Marco.Pms.DataAccess.Migrations
{
/// <inheritdoc />
public partial class Added_Purchase_Invoice_Permissions : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.InsertData(
table: "Modules",
columns: new[] { "Id", "Description", "Key", "Name" },
values: new object[] { new Guid("74e7af50-d55f-4b59-a724-9847ceb7bc17"), "Inventory Module", "504ec132-e6a9-422f-8f85-050602cfce05", "Inventory" });
migrationBuilder.InsertData(
table: "Features",
columns: new[] { "Id", "Description", "IsActive", "ModuleId", "Name" },
values: new object[] { new Guid("271cc47f-7b05-46c7-b5ae-ef0177ec3b60"), "Managing all Purchase invoice related rights", true, new Guid("74e7af50-d55f-4b59-a724-9847ceb7bc17"), "Purchase Invoice Management" });
migrationBuilder.InsertData(
table: "FeaturePermissions",
columns: new[] { "Id", "Description", "FeatureId", "IsEnabled", "Name" },
values: new object[,]
{
{ new Guid("68ff925d-8ebf-4034-a137-8d3317c56ca1"), "Allows full control to create, edit, and process purchase invoices.", new Guid("271cc47f-7b05-46c7-b5ae-ef0177ec3b60"), true, "Manage Purchase Invoice" },
{ new Guid("91e09825-512a-465e-82ad-fa355b305585"), "Allows the user to view only the purchase invoices they created.", new Guid("271cc47f-7b05-46c7-b5ae-ef0177ec3b60"), true, "View Self Purchase Invoice" },
{ new Guid("a4b77638-bf31-42bb-afd4-d5bbd15ccadc"), "Allows the user to mark purchase invoices as inactive or void.", new Guid("271cc47f-7b05-46c7-b5ae-ef0177ec3b60"), true, "Delete Purchase Invoice" },
{ new Guid("b24eba39-4a92-4f7a-b33b-b5308fbc48b9"), "Allows the user to create delivery challans for purchase invoices.", new Guid("271cc47f-7b05-46c7-b5ae-ef0177ec3b60"), true, "Add Delivery Challan" },
{ new Guid("d6ae78d3-a941-4cc4-8d0a-d40479be4211"), "Allows the user to view all purchase invoices across the entire organization.", new Guid("271cc47f-7b05-46c7-b5ae-ef0177ec3b60"), true, "View All Purchase Invoice" }
});
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DeleteData(
table: "FeaturePermissions",
keyColumn: "Id",
keyValue: new Guid("68ff925d-8ebf-4034-a137-8d3317c56ca1"));
migrationBuilder.DeleteData(
table: "FeaturePermissions",
keyColumn: "Id",
keyValue: new Guid("91e09825-512a-465e-82ad-fa355b305585"));
migrationBuilder.DeleteData(
table: "FeaturePermissions",
keyColumn: "Id",
keyValue: new Guid("a4b77638-bf31-42bb-afd4-d5bbd15ccadc"));
migrationBuilder.DeleteData(
table: "FeaturePermissions",
keyColumn: "Id",
keyValue: new Guid("b24eba39-4a92-4f7a-b33b-b5308fbc48b9"));
migrationBuilder.DeleteData(
table: "FeaturePermissions",
keyColumn: "Id",
keyValue: new Guid("d6ae78d3-a941-4cc4-8d0a-d40479be4211"));
migrationBuilder.DeleteData(
table: "Features",
keyColumn: "Id",
keyValue: new Guid("271cc47f-7b05-46c7-b5ae-ef0177ec3b60"));
migrationBuilder.DeleteData(
table: "Modules",
keyColumn: "Id",
keyValue: new Guid("74e7af50-d55f-4b59-a724-9847ceb7bc17"));
}
}
}

View File

@ -2042,6 +2042,46 @@ namespace Marco.Pms.DataAccess.Migrations
FeatureId = new Guid("6d4c82d6-dbce-48ab-b8b8-f785f4d8c914"),
IsEnabled = true,
Name = "View Organization"
},
new
{
Id = new Guid("91e09825-512a-465e-82ad-fa355b305585"),
Description = "Allows the user to view only the purchase invoices they created.",
FeatureId = new Guid("271cc47f-7b05-46c7-b5ae-ef0177ec3b60"),
IsEnabled = true,
Name = "View Self Purchase Invoice"
},
new
{
Id = new Guid("d6ae78d3-a941-4cc4-8d0a-d40479be4211"),
Description = "Allows the user to view all purchase invoices across the entire organization.",
FeatureId = new Guid("271cc47f-7b05-46c7-b5ae-ef0177ec3b60"),
IsEnabled = true,
Name = "View All Purchase Invoice"
},
new
{
Id = new Guid("68ff925d-8ebf-4034-a137-8d3317c56ca1"),
Description = "Allows full control to create, edit, and process purchase invoices.",
FeatureId = new Guid("271cc47f-7b05-46c7-b5ae-ef0177ec3b60"),
IsEnabled = true,
Name = "Manage Purchase Invoice"
},
new
{
Id = new Guid("a4b77638-bf31-42bb-afd4-d5bbd15ccadc"),
Description = "Allows the user to mark purchase invoices as inactive or void.",
FeatureId = new Guid("271cc47f-7b05-46c7-b5ae-ef0177ec3b60"),
IsEnabled = true,
Name = "Delete Purchase Invoice"
},
new
{
Id = new Guid("b24eba39-4a92-4f7a-b33b-b5308fbc48b9"),
Description = "Allows the user to create delivery challans for purchase invoices.",
FeatureId = new Guid("271cc47f-7b05-46c7-b5ae-ef0177ec3b60"),
IsEnabled = true,
Name = "Add Delivery Challan"
});
});
@ -3641,6 +3681,14 @@ namespace Marco.Pms.DataAccess.Migrations
Name = "Organization Management"
},
new
{
Id = new Guid("271cc47f-7b05-46c7-b5ae-ef0177ec3b60"),
Description = "Managing all Purchase invoice related rights",
IsActive = true,
ModuleId = new Guid("74e7af50-d55f-4b59-a724-9847ceb7bc17"),
Name = "Purchase Invoice Management"
},
new
{
Id = new Guid("2f3509b7-160d-410a-b9b6-daadd96c986d"),
Description = "Managing all tenant related rights",
@ -3832,6 +3880,13 @@ namespace Marco.Pms.DataAccess.Migrations
Name = "Tenant"
},
new
{
Id = new Guid("74e7af50-d55f-4b59-a724-9847ceb7bc17"),
Description = "Inventory Module",
Key = "504ec132-e6a9-422f-8f85-050602cfce05",
Name = "Inventory"
},
new
{
Id = new Guid("0a79687a-86d7-430d-a2d7-8b8603cc76a1"),
Description = "Finance Module",

View File

@ -60,6 +60,11 @@
public static readonly Guid AddOrganization = Guid.Parse("068cb3c1-49c5-4746-9f29-1fce16e820ac");
public static readonly Guid EditOrganization = Guid.Parse("c1ae1363-ab8a-4bd9-a9d1-8c2c6083873a");
public static readonly Guid ViewOrganization = Guid.Parse("7a6cf830-0008-4e03-b31d-0d050cb634f4");
public static readonly Guid ViewSelfPurchaseInvoice = Guid.Parse("91e09825-512a-465e-82ad-fa355b305585");
public static readonly Guid ViewAllPurchaseInvoice = Guid.Parse("d6ae78d3-a941-4cc4-8d0a-d40479be4211");
public static readonly Guid ManagePurchaseInvoice = Guid.Parse("68ff925d-8ebf-4034-a137-8d3317c56ca1");
public static readonly Guid DeletePurchaseInvoice = Guid.Parse("a4b77638-bf31-42bb-afd4-d5bbd15ccadc");
public static readonly Guid AddDeliveryChallan = Guid.Parse("b24eba39-4a92-4f7a-b33b-b5308fbc48b9");
}
}

View File

@ -4,6 +4,7 @@ using Marco.Pms.Helpers.Utility;
using Marco.Pms.Model.Dtos.Collection;
using Marco.Pms.Model.Dtos.PurchaseInvoice;
using Marco.Pms.Model.Employees;
using Marco.Pms.Model.Entitlements;
using Marco.Pms.Model.Filters;
using Marco.Pms.Model.MongoDBModels.Utility;
using Marco.Pms.Model.OrganizationModel;
@ -47,6 +48,7 @@ namespace Marco.Pms.Services.Service
_s3Service = s3Service;
_mapper = mapper;
}
#region =================================================================== Purchase Invoice Functions ===================================================================
/// <summary>
/// Retrieves a paged list of purchase invoices for a given tenant with support for
@ -65,6 +67,19 @@ namespace Marco.Pms.Services.Service
public async Task<ApiResponse<object>> GetPurchaseInvoiceListAsync(string? searchString, string? filter, bool isActive, int pageSize, int pageNumber, Employee loggedInEmployee, Guid tenantId,
CancellationToken ct)
{
// Check if the employee has the necessary permissions
var viewAllPermissionTask = HasPermissionAsync(PermissionsMaster.ViewAllPurchaseInvoice, loggedInEmployee.Id);
var viewSelfPermissionTask = HasPermissionAsync(PermissionsMaster.ViewSelfPurchaseInvoice, loggedInEmployee.Id);
var viewAllPermission = await viewAllPermissionTask;
var viewSelfPermission = await viewSelfPermissionTask;
if (!viewAllPermission && !viewSelfPermission)
{
_logger.LogWarning("Access Denied: {EmployeeId} do not have permission to view purchase invoice list", loggedInEmployee.Id);
return ApiResponse<object>.ErrorResponse("You do not have permission to view purchase invoice list.", "You do not have permission to view purchase invoice list.", 403);
}
// Basic argument validation and guard clauses
if (tenantId == Guid.Empty)
{
@ -102,6 +117,12 @@ namespace Marco.Pms.Services.Service
var advanceFilter = TryDeserializeFilter(filter);
// Apply filters based on employee permissions
if (!viewAllPermission && viewSelfPermission)
{
query = query.Where(pid => pid.CreatedById == loggedInEmployee.Id);
}
// Apply ordering, default sort, etc. through your custom extension
query = query.ApplyCustomFilters(advanceFilter, "CreatedAt");
@ -290,6 +311,19 @@ namespace Marco.Pms.Services.Service
try
{
// Check if the employee has the necessary permissions
var viewAllPermissionTask = HasPermissionAsync(PermissionsMaster.ViewAllPurchaseInvoice, loggedInEmployee.Id);
var viewSelfPermissionTask = HasPermissionAsync(PermissionsMaster.ViewSelfPurchaseInvoice, loggedInEmployee.Id);
var viewAllPermission = await viewAllPermissionTask;
var viewSelfPermission = await viewSelfPermissionTask;
if (!viewAllPermission && !viewSelfPermission)
{
_logger.LogWarning("Access Denied: {EmployeeId} do not have permission to view purchase invoice details", loggedInEmployee.Id);
return ApiResponse<PurchaseInvoiceDetailsVM>.ErrorResponse("You do not have permission to view purchase invoice details.", "You do not have permission to view purchase invoice details.", 403);
}
await using var context = await _dbContextFactory.CreateDbContextAsync(ct);
// 2. Performance: Use AsNoTracking for read-only queries.
@ -410,6 +444,13 @@ namespace Marco.Pms.Services.Service
try
{
// Check permissions
var manageInvoicesPermission = await HasPermissionAsync(PermissionsMaster.ManagePurchaseInvoice, loggedInEmployee.Id);
if (!manageInvoicesPermission)
{
_logger.LogWarning("Access Denied: {EmployeeId} do not have permission to create a purchase invoice", loggedInEmployee.Id);
return ApiResponse<PurchaseInvoiceListVM>.ErrorResponse("Access Denied", "You do not have permission to create a purchase invoice.", 403);
}
_logger.LogInfo("Initiating Purchase Invoice creation for ProjectId: {ProjectId}, TenantId: {TenantId}", model.ProjectId, tenantId);
// 2. DATA VALIDATION (Fail-Fast Strategy)
@ -660,6 +701,13 @@ namespace Marco.Pms.Services.Service
"The tenant identifier cannot be empty.",
400);
}
// Check if user has permission
var manageInvoicesPermission = await HasPermissionAsync(PermissionsMaster.ManagePurchaseInvoice, loggedInEmployee.Id);
if (!manageInvoicesPermission)
{
_logger.LogWarning("Access Denied: {EmployeeId} do not have permission to update a purchase invoice", loggedInEmployee.Id);
return ApiResponse<object>.ErrorResponse("Access Denied", "You do not have permission to update a purchase invoice.", 403);
}
_logger.LogInfo("Starting UpdatePurchaseInvoiceAsync. InvoiceId: {InvoiceId}, TenantId: {TenantId}, EmployeeId: {EmployeeId}", id, tenantId, loggedInEmployee.Id);
@ -896,6 +944,19 @@ namespace Marco.Pms.Services.Service
try
{
// Check if the employee has the necessary permissions
var viewAllPermissionTask = HasPermissionAsync(PermissionsMaster.ViewAllPurchaseInvoice, loggedInEmployee.Id);
var viewSelfPermissionTask = HasPermissionAsync(PermissionsMaster.ViewSelfPurchaseInvoice, loggedInEmployee.Id);
var viewAllPermission = await viewAllPermissionTask;
var viewSelfPermission = await viewSelfPermissionTask;
if (!viewAllPermission && !viewSelfPermission)
{
_logger.LogWarning("Access Denied: {EmployeeId} do not have permission to view delivery challan list", loggedInEmployee.Id);
return ApiResponse<List<DeliveryChallanVM>>.ErrorResponse("You do not have permission to view delivery challan list.", "You do not have permission to view delivery challan list.", 403);
}
_logger.LogInfo("GetDeliveryChallans: Fetching challans. InvoiceId: {InvoiceId}, Tenant: {TenantId}", purchaseInvoiceId, tenantId);
// 2. Optimized Validation
@ -973,6 +1034,14 @@ namespace Marco.Pms.Services.Service
// Validate inputs before engaging expensive resources (DB/S3).
if (model == null) throw new ArgumentNullException(nameof(model));
// 2. Security Check
var addDeliveryChallanPermission = await HasPermissionAsync(PermissionsMaster.AddDeliveryChallan, loggedInEmployee.Id);
if (!addDeliveryChallanPermission)
{
_logger.LogWarning("Access Denied: {EmployeeId} do not have permission to add delivery challan", loggedInEmployee.Id);
return ApiResponse<DeliveryChallanVM>.ErrorResponse("You do not have permission to add delivery challan.", "You do not have permission to add delivery challan.", 403);
}
// Extract Base64 Data safely
var base64Data = model.Attachment.Base64Data?.Split(',').LastOrDefault();
if (string.IsNullOrWhiteSpace(base64Data))
@ -996,7 +1065,7 @@ namespace Marco.Pms.Services.Service
var attachmentId = Guid.NewGuid();
var deliveryChallanId = Guid.NewGuid();
// 2. Database Read Operations (Scoped Context)
// 3. Database Read Operations (Scoped Context)
// We use a factory to create a short-lived context.
await using var context = await _dbContextFactory.CreateDbContextAsync(ct);
@ -1023,7 +1092,7 @@ namespace Marco.Pms.Services.Service
return ApiResponse<DeliveryChallanVM>.ErrorResponse("Configuration Error", "System configuration for Delivery Challan is missing.", 500);
}
// 3. External Service Call (S3 Upload)
// 4. External Service Call (S3 Upload)
// We upload BEFORE the DB transaction. If this fails, we return error.
// If DB fails later, we must compensate (delete this file).
try
@ -1036,7 +1105,7 @@ namespace Marco.Pms.Services.Service
return ApiResponse<DeliveryChallanVM>.ErrorResponse("Upload Failed", "Failed to upload the attachment to storage.", 502);
}
// 4. Transactional Write Operations
// 5. Transactional Write Operations
// Begin transaction for data consistency across multiple tables.
await using var transaction = await context.Database.BeginTransactionAsync(ct);
@ -1089,7 +1158,7 @@ namespace Marco.Pms.Services.Service
_logger.LogInfo("AddDeliveryChallan: Success. ChallanId: {ChallanId}, Tenant: {TenantId}", deliveryChallanId, tenantId);
// 5. Response Preparation
// 6. Response Preparation
// Map response objects. Ensure the VM matches the generic return type.
var response = _mapper.Map<DeliveryChallanVM>(deliveryChallan);
@ -1112,7 +1181,7 @@ namespace Marco.Pms.Services.Service
}
catch (Exception ex)
{
// 6. Rollback & Compensation
// 7. Rollback & Compensation
await transaction.RollbackAsync(ct);
_logger.LogError(ex, "AddDeliveryChallan: Database transaction failed. Rolling back. Tenant: {TenantId}", tenantId);
@ -1162,6 +1231,19 @@ namespace Marco.Pms.Services.Service
try
{
// Check if the employee has the necessary permissions
var viewAllPermissionTask = HasPermissionAsync(PermissionsMaster.ViewAllPurchaseInvoice, loggedInEmployee.Id);
var viewSelfPermissionTask = HasPermissionAsync(PermissionsMaster.ViewSelfPurchaseInvoice, loggedInEmployee.Id);
var viewAllPermission = await viewAllPermissionTask;
var viewSelfPermission = await viewSelfPermissionTask;
if (!viewAllPermission && !viewSelfPermission)
{
_logger.LogWarning("Access Denied: {EmployeeId} do not have permission to view purchase invoice payment history list", loggedInEmployee.Id);
return ApiResponse<object>.ErrorResponse("You do not have permission to view purchase invoice payment history list.", "You do not have permission to view purchase invoice payment history list.", 403);
}
// Create a short-lived DbContext instance via factory for this operation.
await using var context = await _dbContextFactory.CreateDbContextAsync(ct);
@ -1247,6 +1329,14 @@ namespace Marco.Pms.Services.Service
try
{
// Check permissions
var manageInvoicesPermission = await HasPermissionAsync(PermissionsMaster.ManagePurchaseInvoice, loggedInEmployee.Id);
if (!manageInvoicesPermission)
{
_logger.LogWarning("Access Denied: {EmployeeId} do not have permission to add payments to a purchase invoice", loggedInEmployee.Id);
return ApiResponse<object>.ErrorResponse("Access Denied", "You do not have permission to add payments to a purchase invoice", 403);
}
// Create a short-lived DbContext instance using the factory to ensure proper scope per operation.
await using var context = await _dbContextFactory.CreateDbContextAsync(ct);
@ -1354,6 +1444,16 @@ namespace Marco.Pms.Services.Service
#region =================================================================== Helper Functions ===================================================================
/// <summary>
/// Async permission check helper with scoped DI lifetime
/// </summary>
private async Task<bool> HasPermissionAsync(Guid permission, Guid employeeId)
{
using var scope = _serviceScopeFactory.CreateScope();
var permissionService = scope.ServiceProvider.GetRequiredService<PermissionServices>();
return await permissionService.HasPermission(permission, employeeId);
}
public async Task<PurchaseInvoiceDetails?> GetPurchaseInvoiceByIdAsync(Guid id, Guid tenantId, CancellationToken ct = default)
{
await using var readContext = await _dbContextFactory.CreateDbContextAsync(ct);