179 lines
7.9 KiB
C#
179 lines
7.9 KiB
C#
using Marco.Pms.Model.MongoDBModels.Expenses;
|
|
using Marco.Pms.Model.Utilities;
|
|
using Microsoft.Extensions.Configuration;
|
|
using MongoDB.Bson;
|
|
using MongoDB.Driver;
|
|
|
|
namespace Marco.Pms.Helpers.CacheHelper
|
|
{
|
|
public class ExpenseCache
|
|
{
|
|
private readonly IMongoCollection<ExpenseDetailsMongoDB> _collection;
|
|
public ExpenseCache(IConfiguration configuration)
|
|
{
|
|
|
|
var connectionString = configuration["MongoDB:ConnectionString"];
|
|
var mongoUrl = new MongoUrl(connectionString);
|
|
var client = new MongoClient(mongoUrl); // Your MongoDB connection string
|
|
var mongoDB = client.GetDatabase(mongoUrl.DatabaseName); // Your MongoDB Database name
|
|
_collection = mongoDB.GetCollection<ExpenseDetailsMongoDB>("Expenses");
|
|
}
|
|
public async Task AddExpenseToCacheAsync(ExpenseDetailsMongoDB expense)
|
|
{
|
|
await _collection.InsertOneAsync(expense);
|
|
|
|
await InitializeCollectionAsync();
|
|
}
|
|
public async Task AddExpensesListToCacheAsync(List<ExpenseDetailsMongoDB> expenses)
|
|
{
|
|
// 1. Add a guard clause to avoid an unnecessary database call for an empty list.
|
|
if (expenses == null || !expenses.Any())
|
|
{
|
|
return;
|
|
}
|
|
|
|
// 2. Perform the insert operation. This is the only responsibility of this method.
|
|
await _collection.InsertManyAsync(expenses);
|
|
await InitializeCollectionAsync();
|
|
}
|
|
public async Task<(int totalPages, long totalCount, List<ExpenseDetailsMongoDB> expenseList)> GetExpenseListFromCacheAsync(Guid tenantId, Guid loggedInEmployeeId, bool viewAll,
|
|
bool viewSelf, int pageNumber, int pageSize, ExpensesFilter? expenseFilter, string? searchString)
|
|
{
|
|
var filterBuilder = Builders<ExpenseDetailsMongoDB>.Filter;
|
|
var filter = filterBuilder.Empty;
|
|
|
|
// Permission-based filter
|
|
if (!viewAll && viewSelf)
|
|
{
|
|
filter &= filterBuilder.Eq(e => e.CreatedBy.Id, loggedInEmployeeId.ToString());
|
|
}
|
|
else
|
|
{
|
|
filter &= filterBuilder.Or(
|
|
filterBuilder.Ne(e => e.CreatedBy.Id, loggedInEmployeeId.ToString()),
|
|
filterBuilder.Ne(e => e.Status.Id, "297e0d8f-f668-41b5-bfea-e03b354251c8")
|
|
);
|
|
}
|
|
|
|
// Apply filters
|
|
|
|
if (expenseFilter != null)
|
|
{
|
|
if (expenseFilter.StartDate.HasValue && expenseFilter.EndDate.HasValue && expenseFilter.IsTransactionDate == false)
|
|
{
|
|
filter &= filterBuilder.Gte(e => e.CreatedAt, expenseFilter.StartDate.Value.Date)
|
|
& filterBuilder.Lte(e => e.CreatedAt, expenseFilter.EndDate.Value.Date.AddDays(1).AddTicks(-1));
|
|
}
|
|
|
|
if (expenseFilter.StartDate.HasValue && expenseFilter.EndDate.HasValue && expenseFilter.IsTransactionDate)
|
|
{
|
|
filter &= filterBuilder.Gte(e => e.TransactionDate, expenseFilter.StartDate.Value.Date)
|
|
& filterBuilder.Lte(e => e.TransactionDate, expenseFilter.EndDate.Value.Date.AddDays(1).AddTicks(-1));
|
|
}
|
|
|
|
if (expenseFilter.ProjectIds?.Any() == true)
|
|
{
|
|
filter &= filterBuilder.In(e => e.Project.Id, expenseFilter.ProjectIds.Select(p => p.ToString()).ToList());
|
|
}
|
|
|
|
if (expenseFilter.StatusIds?.Any() == true)
|
|
{
|
|
filter &= filterBuilder.In(e => e.Status.Id, expenseFilter.StatusIds.Select(p => p.ToString()).ToList());
|
|
}
|
|
|
|
if (expenseFilter.PaidById?.Any() == true)
|
|
{
|
|
filter &= filterBuilder.In(e => e.PaidBy.Id, expenseFilter.PaidById.Select(p => p.ToString()).ToList());
|
|
}
|
|
|
|
if (expenseFilter.CreatedByIds?.Any() == true && viewAll)
|
|
{
|
|
filter &= filterBuilder.In(e => e.CreatedBy.Id, expenseFilter.CreatedByIds.Select(p => p.ToString()).ToList());
|
|
}
|
|
}
|
|
|
|
if (!string.IsNullOrWhiteSpace(searchString))
|
|
{
|
|
var searchPattern = new BsonRegularExpression(searchString, "i");
|
|
|
|
// The base text searches remain the same
|
|
var searchClauses = new List<FilterDefinition<ExpenseDetailsMongoDB>>
|
|
{
|
|
filterBuilder.Regex(e => e.Description, searchPattern),
|
|
filterBuilder.Regex(e => e.TransactionId, searchPattern)
|
|
};
|
|
|
|
// Build the complex filter for PaidBy.FullName
|
|
var paidByFilter = new BsonDocument("$expr",
|
|
new BsonDocument("$regexMatch", new BsonDocument
|
|
{
|
|
{ "input", new BsonDocument("$concat", new BsonArray { "$PaidBy.FirstName", " ", "$PaidBy.LastName" }) },
|
|
{ "regex", searchString }, // BsonRegularExpression can't be used here, pass the string
|
|
{ "options", "i" } // Case-insensitivity option
|
|
})
|
|
);
|
|
searchClauses.Add(paidByFilter);
|
|
|
|
// Build the complex filter for CreatedBy.FullName
|
|
var createdByFilter = new BsonDocument("$expr",
|
|
new BsonDocument("$regexMatch", new BsonDocument
|
|
{
|
|
{ "input", new BsonDocument("$concat", new BsonArray { "$CreatedBy.FirstName", " ", "$CreatedBy.LastName" }) },
|
|
{ "regex", searchString },
|
|
{ "options", "i" }
|
|
})
|
|
);
|
|
searchClauses.Add(createdByFilter);
|
|
|
|
// Combine all clauses with an OR
|
|
filter &= filterBuilder.Or(searchClauses);
|
|
}
|
|
|
|
// Total count
|
|
var totalCount = await _collection.CountDocumentsAsync(filter);
|
|
var totalPages = (int)Math.Ceiling((double)totalCount / pageSize);
|
|
|
|
// Fetch paginated data
|
|
var expenses = await _collection
|
|
.Find(filter)
|
|
.Skip((pageNumber - 1) * pageSize)
|
|
.Limit(pageSize)
|
|
.SortByDescending(e => e.CreatedAt)
|
|
.ToListAsync();
|
|
|
|
return (totalPages, totalCount, expenses);
|
|
}
|
|
|
|
public async Task<ExpenseDetailsMongoDB> GetExpenseDetailsByIdAsync(Guid id, Guid tenantId)
|
|
{
|
|
var filter = Builders<ExpenseDetailsMongoDB>.Filter.And(
|
|
Builders<ExpenseDetailsMongoDB>.Filter.Eq(e => e.Id, id.ToString()),
|
|
Builders<ExpenseDetailsMongoDB>.Filter.Eq(e => e.TenantId, tenantId.ToString())
|
|
);
|
|
var expense = await _collection.Find(filter).FirstOrDefaultAsync();
|
|
|
|
return expense;
|
|
}
|
|
|
|
public async Task<bool> DeleteExpenseFromCacheAsync(Guid id, Guid tenantId)
|
|
{
|
|
var filter = Builders<ExpenseDetailsMongoDB>.Filter.And(
|
|
Builders<ExpenseDetailsMongoDB>.Filter.Eq(e => e.Id, id.ToString()),
|
|
Builders<ExpenseDetailsMongoDB>.Filter.Eq(e => e.TenantId, tenantId.ToString())
|
|
);
|
|
var result = await _collection.DeleteOneAsync(filter);
|
|
return result.DeletedCount > 0;
|
|
}
|
|
private async Task InitializeCollectionAsync()
|
|
{
|
|
var indexKeys = Builders<ExpenseDetailsMongoDB>.IndexKeys.Ascending(x => x.ExpireAt);
|
|
var indexOptions = new CreateIndexOptions
|
|
{
|
|
ExpireAfter = TimeSpan.Zero // required for fixed expiration time
|
|
};
|
|
var indexModel = new CreateIndexModel<ExpenseDetailsMongoDB>(indexKeys, indexOptions);
|
|
await _collection.Indexes.CreateOneAsync(indexModel);
|
|
}
|
|
}
|
|
}
|