Compare commits
17 Commits
Feature/pr
...
Feature/in
| Author | SHA1 | Date | |
|---|---|---|---|
| 140414b866 | |||
| 4ade9e12a6 | |||
| dd7e816767 | |||
| 1deeff996f | |||
| 8ad296fe61 | |||
|
|
823110ea74 | ||
| 061058cbeb | |||
| c6ed46d8b7 | |||
| 3da7453ece | |||
|
|
9a591fabff | ||
| 9d09ef60f8 | |||
| 0757ac7e74 | |||
|
|
dd5455d80a | ||
| 9360dcad71 | |||
| 1971252713 | |||
| 02cc099104 | |||
| 582da511c6 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -362,3 +362,5 @@ MigrationBackup/
|
||||
# # Fody - auto-generated XML schema
|
||||
# FodyWeavers.xsd
|
||||
.idea
|
||||
/ServiceHost/appsettings.Development.json
|
||||
/ServiceHost/appsettings.json
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Company.Domain.InstitutionContractSendFlagAgg;
|
||||
|
||||
/// <summary>
|
||||
/// Interface برای Repository مربوط به فلگ ارسال قرارداد
|
||||
/// </summary>
|
||||
public interface IInstitutionContractSendFlagRepository
|
||||
{
|
||||
/// <summary>
|
||||
/// ایجاد یک رکورد جدید برای فلگ ارسال قرارداد
|
||||
/// </summary>
|
||||
Task Create(InstitutionContractSendFlag flag);
|
||||
|
||||
/// <summary>
|
||||
/// بازیابی فلگ بر اساس شناسه قرارداد
|
||||
/// </summary>
|
||||
Task<InstitutionContractSendFlag> GetByContractId(long contractId);
|
||||
|
||||
/// <summary>
|
||||
/// بهروزرسانی فلگ ارسال
|
||||
/// </summary>
|
||||
Task Update(InstitutionContractSendFlag flag);
|
||||
|
||||
/// <summary>
|
||||
/// بررسی اینکه آیا قرارداد ارسال شده است
|
||||
/// </summary>
|
||||
Task<bool> IsContractSent(long contractId);
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
using System;
|
||||
using MongoDB.Bson;
|
||||
using MongoDB.Bson.Serialization.Attributes;
|
||||
|
||||
namespace Company.Domain.InstitutionContractSendFlagAgg;
|
||||
|
||||
/// <summary>
|
||||
/// نمایندگی فلگ ارسال قرارداد در MongoDB
|
||||
/// این موجودیت برای ردیابی اینکه آیا قرارداد ارسال شده است استفاده میشود
|
||||
/// </summary>
|
||||
public class InstitutionContractSendFlag
|
||||
{
|
||||
public InstitutionContractSendFlag(long institutionContractId,bool isSent)
|
||||
{
|
||||
Id = Guid.NewGuid();
|
||||
InstitutionContractId = institutionContractId;
|
||||
IsSent = isSent;
|
||||
CreatedDate = DateTime.Now;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// شناسه یکتای MongoDB
|
||||
/// </summary>
|
||||
[BsonId]
|
||||
[BsonRepresentation(BsonType.String)]
|
||||
public Guid Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// شناسه قرارداد در SQL
|
||||
/// </summary>
|
||||
public long InstitutionContractId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// آیا قرارداد ارسال شده است
|
||||
/// </summary>
|
||||
public bool IsSent { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// تاریخ و زمان ارسال
|
||||
/// </summary>
|
||||
public DateTime? SentDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// تاریخ و زمان ایجاد رکورد
|
||||
/// </summary>
|
||||
public DateTime CreatedDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// تاریخ و زمان آخرین بهروزرسانی
|
||||
/// </summary>
|
||||
public DateTime? LastModifiedDate { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// علامتگذاری قرارداد به عنوان ارسالشده
|
||||
/// </summary>
|
||||
public void MarkAsSent()
|
||||
{
|
||||
IsSent = true;
|
||||
SentDate = DateTime.Now;
|
||||
LastModifiedDate = DateTime.Now;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// بازگردانی علامت ارسال
|
||||
/// </summary>
|
||||
public void MarkAsNotSent()
|
||||
{
|
||||
IsSent = false;
|
||||
SentDate = null;
|
||||
LastModifiedDate = DateTime.Now;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// بهروزرسانی علامت آخری اصلاح
|
||||
/// </summary>
|
||||
public void UpdateLastModified()
|
||||
{
|
||||
LastModifiedDate = DateTime.Now;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Company.Domain.InstitutionContractSendFlagAgg;
|
||||
using MongoDB.Driver;
|
||||
|
||||
namespace CompanyManagement.Infrastructure.Mongo.InstitutionContractSendFlagRepo;
|
||||
|
||||
/// <summary>
|
||||
/// Repository برای مدیریت فلگ ارسال قرارداد در MongoDB
|
||||
/// </summary>
|
||||
public class InstitutionContractSendFlagRepository : IInstitutionContractSendFlagRepository
|
||||
{
|
||||
private readonly IMongoCollection<InstitutionContractSendFlag> _collection;
|
||||
|
||||
public InstitutionContractSendFlagRepository(IMongoDatabase database)
|
||||
{
|
||||
_collection = database.GetCollection<InstitutionContractSendFlag>("InstitutionContractSendFlag");
|
||||
}
|
||||
|
||||
public async Task Create(InstitutionContractSendFlag flag)
|
||||
{
|
||||
await _collection.InsertOneAsync(flag);
|
||||
}
|
||||
|
||||
public async Task<InstitutionContractSendFlag> GetByContractId(long contractId)
|
||||
{
|
||||
var filter = Builders<InstitutionContractSendFlag>.Filter
|
||||
.Eq(x => x.InstitutionContractId, contractId);
|
||||
|
||||
return await _collection.Find(filter).FirstOrDefaultAsync();
|
||||
}
|
||||
|
||||
|
||||
public async Task Update(InstitutionContractSendFlag flag)
|
||||
{
|
||||
var filter = Builders<InstitutionContractSendFlag>.Filter
|
||||
.Eq(x => x.InstitutionContractId, flag.InstitutionContractId);
|
||||
|
||||
await _collection.ReplaceOneAsync(filter, flag);
|
||||
}
|
||||
|
||||
public async Task<bool> IsContractSent(long contractId)
|
||||
{
|
||||
var flag = await GetByContractId(contractId);
|
||||
return flag != null && flag.IsSent;
|
||||
}
|
||||
|
||||
public async Task Remove(long contractId)
|
||||
{
|
||||
var filter = Builders<InstitutionContractSendFlag>.Filter
|
||||
.Eq(x => x.InstitutionContractId, contractId);
|
||||
|
||||
await _collection.DeleteOneAsync(filter);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -96,6 +96,8 @@ public class GetInstitutionContractListItemsViewModel
|
||||
/// مبلغ قسط
|
||||
/// </summary>
|
||||
public double InstallmentAmount { get; set; }
|
||||
|
||||
public bool InstitutionContractIsSentFlag { get; set; }
|
||||
}
|
||||
|
||||
public class InstitutionContractListWorkshop
|
||||
|
||||
@@ -148,7 +148,7 @@ public interface IInstitutionContractApplication
|
||||
/// <param name="id">شناسه قرارداد</param>
|
||||
/// <returns>نتیجه عملیات</returns>
|
||||
OperationResult UnSign(long id);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// ایجاد حساب کاربری برای طرف قرارداد
|
||||
/// </summary>
|
||||
@@ -305,6 +305,14 @@ public interface IInstitutionContractApplication
|
||||
Task<InstitutionContractDiscountResponse> SetDiscountForCreation(InstitutionContractSetDiscountForCreationRequest request);
|
||||
Task<InstitutionContractDiscountResponse> ResetDiscountForCreation(InstitutionContractResetDiscountForExtensionRequest request);
|
||||
Task<OperationResult> CreationComplete(InstitutionContractExtensionCompleteRequest request);
|
||||
|
||||
/// <summary>
|
||||
/// تعیین فلگ ارسال قرارداد در MongoDB
|
||||
/// اگر فلگ وجود نداشتند ایجاد میکند
|
||||
/// </summary>
|
||||
/// <param name="request">درخواست تعیین فلگ</param>
|
||||
/// <returns>نتیجه عملیات</returns>
|
||||
Task<OperationResult> SetContractSendFlag(SetInstitutionContractSendFlagRequest request);
|
||||
}
|
||||
|
||||
public class CreationSetContractingPartyResponse
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
namespace CompanyManagment.App.Contracts.InstitutionContract;
|
||||
|
||||
/// <summary>
|
||||
/// درخواست برای تعیین فلگ ارسال قرارداد
|
||||
/// </summary>
|
||||
public class SetInstitutionContractSendFlagRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// شناسه قرارداد
|
||||
/// </summary>
|
||||
public long InstitutionContractId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// آیا قرارداد ارسال شده است
|
||||
/// </summary>
|
||||
public bool IsSent { get; set; }
|
||||
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ using Company.Domain.PaymentTransactionAgg;
|
||||
using Company.Domain.RepresentativeAgg;
|
||||
using Company.Domain.RollCallServiceAgg;
|
||||
using Company.Domain.WorkshopAgg;
|
||||
using Company.Domain.InstitutionContractSendFlagAgg;
|
||||
using CompanyManagment.App.Contracts.FinancialInvoice;
|
||||
using CompanyManagment.App.Contracts.FinancialStatment;
|
||||
using CompanyManagment.App.Contracts.InstitutionContract;
|
||||
@@ -51,6 +52,7 @@ public class InstitutionContractApplication : IInstitutionContractApplication
|
||||
private readonly IPaymentTransactionRepository _paymentTransactionRepository;
|
||||
private readonly IRollCallServiceRepository _rollCallServiceRepository;
|
||||
private readonly ISepehrPaymentGatewayService _sepehrPaymentGatewayService;
|
||||
private readonly IInstitutionContractSendFlagRepository _institutionContractSendFlagRepository;
|
||||
|
||||
|
||||
public InstitutionContractApplication(IInstitutionContractRepository institutionContractRepository,
|
||||
@@ -62,7 +64,8 @@ public class InstitutionContractApplication : IInstitutionContractApplication
|
||||
IAccountApplication accountApplication, ISmsService smsService,
|
||||
IFinancialInvoiceRepository financialInvoiceRepository, IHttpClientFactory httpClientFactory,
|
||||
IPaymentTransactionRepository paymentTransactionRepository, IRollCallServiceRepository rollCallServiceRepository,
|
||||
ISepehrPaymentGatewayService sepehrPaymentGatewayService,ILogger<SepehrPaymentGateway> sepehrGatewayLogger)
|
||||
ISepehrPaymentGatewayService sepehrPaymentGatewayService,ILogger<SepehrPaymentGateway> sepehrGatewayLogger,
|
||||
IInstitutionContractSendFlagRepository institutionContractSendFlagRepository)
|
||||
{
|
||||
_institutionContractRepository = institutionContractRepository;
|
||||
_contractingPartyRepository = contractingPartyRepository;
|
||||
@@ -80,6 +83,7 @@ public class InstitutionContractApplication : IInstitutionContractApplication
|
||||
_rollCallServiceRepository = rollCallServiceRepository;
|
||||
_sepehrPaymentGatewayService = sepehrPaymentGatewayService;
|
||||
_paymentGateway = new SepehrPaymentGateway(httpClientFactory,sepehrGatewayLogger);
|
||||
_institutionContractSendFlagRepository = institutionContractSendFlagRepository;
|
||||
}
|
||||
|
||||
public OperationResult Create(CreateInstitutionContract command)
|
||||
@@ -894,6 +898,7 @@ public class InstitutionContractApplication : IInstitutionContractApplication
|
||||
return opration.Succcedded();
|
||||
}
|
||||
|
||||
|
||||
public void CreateContractingPartyAccount(long contractingPartyid, long accountId)
|
||||
{
|
||||
_institutionContractRepository.CreateContractingPartyAccount(contractingPartyid, accountId);
|
||||
@@ -1820,7 +1825,60 @@ public class InstitutionContractApplication : IInstitutionContractApplication
|
||||
installments.Add(lastInstallment);
|
||||
return installments;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// تعیین فلگ ارسال قرارداد
|
||||
/// اگر فلگ وجود نداشتند ایجاد میکند
|
||||
/// </summary>
|
||||
public async Task<OperationResult> SetContractSendFlag(SetInstitutionContractSendFlagRequest request)
|
||||
{
|
||||
var operationResult = new OperationResult();
|
||||
|
||||
try
|
||||
{
|
||||
// بازیابی قرارداد از SQL
|
||||
var contract = _institutionContractRepository.Get(request.InstitutionContractId);
|
||||
if (contract == null)
|
||||
return operationResult.Failed("قرارداد مورد نظر یافت نشد");
|
||||
|
||||
// بررسی اینکه آیا فلگ در MongoDB وجود دارد
|
||||
var existingFlag = await _institutionContractSendFlagRepository
|
||||
.GetByContractId(request.InstitutionContractId);
|
||||
|
||||
if (existingFlag != null)
|
||||
{
|
||||
// اگر فلگ وجود داشتند، آن را اپدیت کنیم
|
||||
if (request.IsSent)
|
||||
{
|
||||
existingFlag.MarkAsSent();
|
||||
}
|
||||
else
|
||||
{
|
||||
existingFlag.MarkAsNotSent();
|
||||
}
|
||||
existingFlag.UpdateLastModified();
|
||||
await _institutionContractSendFlagRepository.Update(existingFlag);
|
||||
}
|
||||
else
|
||||
{
|
||||
// اگر فلگ وجود ندارد، آن را ایجاد کنیم
|
||||
var newFlag = new InstitutionContractSendFlag(
|
||||
request.InstitutionContractId,
|
||||
request.IsSent
|
||||
);
|
||||
|
||||
await _institutionContractSendFlagRepository.Create(newFlag);
|
||||
}
|
||||
|
||||
return operationResult.Succcedded();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return operationResult.Failed($"خطا در تعیین فلگ ارسال: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region CustomViewModels
|
||||
|
||||
@@ -11,6 +11,7 @@ using Company.Domain.InstitutionContractAgg;
|
||||
using Company.Domain.InstitutionContractAmendmentTempAgg;
|
||||
using Company.Domain.InstitutionContractContactInfoAgg;
|
||||
using Company.Domain.InstitutionContractExtensionTempAgg;
|
||||
using Company.Domain.InstitutionContractSendFlagAgg;
|
||||
using Company.Domain.InstitutionPlanAgg;
|
||||
using Company.Domain.SmsResultAgg;
|
||||
using Company.Domain.WorkshopAgg;
|
||||
@@ -42,6 +43,7 @@ using AccountManagement.Application.Contracts.Account;
|
||||
using Company.Domain.InstitutionContractCreationTempAgg;
|
||||
using Company.Domain.RepresentativeAgg;
|
||||
using Company.Domain.TemporaryClientRegistrationAgg;
|
||||
using Company.Domain.InstitutionContractSendFlagAgg;
|
||||
using ContractingPartyAccount = Company.Domain.ContractingPartyAccountAgg.ContractingPartyAccount;
|
||||
using FinancialStatment = Company.Domain.FinancialStatmentAgg.FinancialStatment;
|
||||
using String = System.String;
|
||||
@@ -57,6 +59,7 @@ public class InstitutionContractRepository : RepositoryBase<long, InstitutionCon
|
||||
private readonly IMongoCollection<InstitutionContractExtensionTemp> _institutionExtensionTemp;
|
||||
private readonly IMongoCollection<InstitutionContractAmendmentTemp> _institutionAmendmentTemp;
|
||||
private readonly IMongoCollection<InstitutionContractCreationTemp> _institutionContractCreationTemp;
|
||||
private readonly IMongoCollection<InstitutionContractSendFlag> _institutionContractSendFlag;
|
||||
private readonly IPlanPercentageRepository _planPercentageRepository;
|
||||
private readonly ISmsService _smsService;
|
||||
private readonly ISmsResultRepository _smsResultRepository;
|
||||
@@ -114,6 +117,8 @@ public class InstitutionContractRepository : RepositoryBase<long, InstitutionCon
|
||||
database.GetCollection<InstitutionContractAmendmentTemp>("InstitutionContractAmendmentTemp");
|
||||
_institutionContractCreationTemp =
|
||||
database.GetCollection<InstitutionContractCreationTemp>("InstitutionContractCreationTemp");
|
||||
_institutionContractSendFlag =
|
||||
database.GetCollection<InstitutionContractSendFlag>("InstitutionContractSendFlag");
|
||||
}
|
||||
|
||||
public EditInstitutionContract GetDetails(long id)
|
||||
@@ -1353,6 +1358,12 @@ public class InstitutionContractRepository : RepositoryBase<long, InstitutionCon
|
||||
.Where(x => contractIds.Contains(x.InstitutionContractId))
|
||||
.ToDictionaryAsync(x => x.InstitutionContractId, x => x);
|
||||
|
||||
// بارگذاری وضعیت ارسال قراردادها از MongoDB - کوئری مستقیم
|
||||
var filter = Builders<InstitutionContractSendFlag>.Filter
|
||||
.In(x => x.InstitutionContractId, contractIds);
|
||||
var sendFlagsList = await _institutionContractSendFlag.Find(filter).ToListAsync();
|
||||
var sendFlags = sendFlagsList.ToDictionary(x => x.InstitutionContractId, x => x.IsSent);
|
||||
|
||||
var financialStatements = _context.FinancialStatments.Include(x => x.FinancialTransactionList)
|
||||
.Where(x => contractingPartyIds.Contains(x.ContractingPartyId)).ToList();
|
||||
var res = new PagedResult<GetInstitutionContractListItemsViewModel>()
|
||||
@@ -1462,7 +1473,8 @@ public class InstitutionContractRepository : RepositoryBase<long, InstitutionCon
|
||||
Workshops = workshopDetails,
|
||||
IsInPersonContract = workshopGroup?.CurrentWorkshops
|
||||
.Any(y => y.Services.ContractInPerson) ?? true,
|
||||
IsOldContract = x.contract.SigningType == InstitutionContractSigningType.Legacy
|
||||
IsOldContract = x.contract.SigningType == InstitutionContractSigningType.Legacy,
|
||||
InstitutionContractIsSentFlag = sendFlags.ContainsKey(x.contract.id) ? sendFlags[x.contract.id] : false
|
||||
};
|
||||
}).ToList()
|
||||
};
|
||||
@@ -6334,10 +6346,10 @@ public class InstitutionContractRepository : RepositoryBase<long, InstitutionCon
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///دریافت لیست پیامک قرادا های آبی بدهکار
|
||||
///دریافت لیست پیامک قراداد های آبی بدهکار
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
//public async Task<List<SmsListData>> GetBlueSmsListData()
|
||||
//public async Task<List<SmsListData>> GetWarningSmsListData()
|
||||
//{
|
||||
|
||||
// var institutionContracts = await _context.InstitutionContractSet.AsQueryable().Select(x => new InstitutionContractViewModel
|
||||
@@ -6358,6 +6370,8 @@ public class InstitutionContractRepository : RepositoryBase<long, InstitutionCon
|
||||
// }).Where(x => x.IsActiveString == "blue" &&
|
||||
// x.ContractAmountDouble > 0).GroupBy(x => x.ContractingPartyId).Select(x => x.First()).ToListAsync();
|
||||
|
||||
// var institutionContractsIds = institutionContracts.Select(x => x.id).ToList();
|
||||
|
||||
// // قرارداد هایی که بطور یکجا پرداخت شده اند
|
||||
// var paidInFull = institutionContracts.Where(x =>
|
||||
// x.SigningType != InstitutionContractSigningType.Legacy && x.IsInstallment == false && x.SigningType != null).ToList();
|
||||
@@ -6376,7 +6390,7 @@ public class InstitutionContractRepository : RepositoryBase<long, InstitutionCon
|
||||
// .Where(x => institutionContracts.Select(ins => ins.Id).Contains(x.InstitutionContractId))
|
||||
// .Where(x => x.SendSms && x.PhoneType == "شماره همراه" && !string.IsNullOrWhiteSpace(x.PhoneNumber) &&
|
||||
// x.PhoneNumber.Length == 11).ToListAsync();
|
||||
// var legalActionSentSms =await _context.SmsResults
|
||||
// var legalActionSentSms = await _context.SmsResults
|
||||
// .Where(x => x.TypeOfSms == "اقدام قضایی").ToListAsync();
|
||||
// var warningSentSms = await _context.SmsResults.Where(x => x.TypeOfSms.Contains("هشدار")).ToListAsync();
|
||||
|
||||
@@ -6389,8 +6403,13 @@ public class InstitutionContractRepository : RepositoryBase<long, InstitutionCon
|
||||
// {
|
||||
// var contractingParty = GetDetails(item.ContractingPartyId);
|
||||
// bool hasLegalActionSentSms = legalActionSentSms.Any(x => x.InstitutionContractId == item.Id);
|
||||
// int year = Convert.ToInt32(item.ContractEndFa.Substring(0, 4));
|
||||
// int month = Convert.ToInt32(item.ContractEndFa.Substring(5, 2));
|
||||
// var endOfContractNextMonthStart = new PersianDateTime(year, month, 1).AddMonths(1);
|
||||
// var endOfContractNextMonthEnd = (($"{endOfContractNextMonthStart}").FindeEndOfMonth()).ToGeorgianDateTime();
|
||||
// var now = DateTime.Now
|
||||
|
||||
// if (!string.IsNullOrWhiteSpace(contractingParty.LName) && !hasLegalActionSentSms)
|
||||
// if (!string.IsNullOrWhiteSpace(contractingParty.LName) && !hasLegalActionSentSms && now.Date <= endOfContractNextMonthEnd.Date)
|
||||
// {
|
||||
// //Thread.Sleep(500);
|
||||
// var partyName = contractingParty.LName;
|
||||
@@ -6425,7 +6444,7 @@ public class InstitutionContractRepository : RepositoryBase<long, InstitutionCon
|
||||
|
||||
// var debtor = transactions.FinancialTransactionViewModels.Sum(x => x.Deptor);
|
||||
// var creditor = transactions.FinancialTransactionViewModels.Sum(x => x.Creditor);
|
||||
|
||||
|
||||
|
||||
// var id = $"{item.ContractingPartyId}";
|
||||
// var aprove = $"{transactions.Id}";
|
||||
@@ -6442,11 +6461,11 @@ public class InstitutionContractRepository : RepositoryBase<long, InstitutionCon
|
||||
|
||||
// foreach (var number in phoneNumbers)
|
||||
// {
|
||||
|
||||
|
||||
// var isLastAlarmSend = _context.SmsResults.Any(x => (
|
||||
// x.ContractingPatyId == contractingParty.Id &&
|
||||
// x.Mobile == number.PhoneNumber) && (x.TypeOfSms == "اقدام قضایی" || x.TypeOfSms == "هشدار دوم"));
|
||||
|
||||
// var t = warningSentSms.Any(x=> x.)
|
||||
// if (!string.IsNullOrWhiteSpace(number.PhoneNumber) &&
|
||||
// number.PhoneNumber.Length == 11 && !isSend && !isLastAlarmSend)
|
||||
// {
|
||||
|
||||
@@ -61,6 +61,7 @@ using Company.Domain.HolidayItemAgg;
|
||||
using Company.Domain.InstitutionContractAgg;
|
||||
using Company.Domain.InstitutionContractContactInfoAgg;
|
||||
using Company.Domain.InstitutionContractExtensionTempAgg;
|
||||
using Company.Domain.InstitutionContractSendFlagAgg;
|
||||
using Company.Domain.InstitutionPlanAgg;
|
||||
using Company.Domain.InsuranceAgg;
|
||||
using Company.Domain.InsuranceEmployeeInfoAgg;
|
||||
@@ -123,6 +124,7 @@ using Company.Domain.ZoneAgg;
|
||||
using CompanyManagement.Infrastructure.Excel.SalaryAid;
|
||||
using CompanyManagement.Infrastructure.Mongo.EmployeeFaceEmbeddingRepo;
|
||||
using CompanyManagement.Infrastructure.Mongo.InstitutionContractInsertTempRepo;
|
||||
using CompanyManagement.Infrastructure.Mongo.InstitutionContractSendFlagRepo;
|
||||
using CompanyManagment.App.Contracts.AdminMonthlyOverview;
|
||||
using CompanyManagment.App.Contracts.AndroidApkVersion;
|
||||
using CompanyManagment.App.Contracts.AuthorizedPerson;
|
||||
@@ -658,6 +660,9 @@ public class PersonalBootstrapper
|
||||
services.AddTransient<ICameraBugReportApplication, CameraBugReportApplication>();
|
||||
services.AddTransient<ICameraBugReportRepository, CameraBugReportRepository>(); // MongoDB Implementation
|
||||
|
||||
// InstitutionContractSendFlag - MongoDB
|
||||
services.AddTransient<IInstitutionContractSendFlagRepository, InstitutionContractSendFlagRepository>();
|
||||
|
||||
services.AddDbContext<CompanyContext>(x => x.UseSqlServer(connectionString));
|
||||
}
|
||||
}
|
||||
@@ -352,7 +352,8 @@ public class SetTimeProjectCommandHandler : IBaseCommandHandler<SetTimeProjectCo
|
||||
private void SetSectionTime(TaskSection section, SetTimeProjectSkillItem sectionItem, long? addedByUserId)
|
||||
{
|
||||
var initData = sectionItem.InitData;
|
||||
var initialTime = TimeSpan.FromHours(initData.Hours);
|
||||
var initialTime = TimeSpan.FromHours(initData.Hours)
|
||||
.Add(TimeSpan.FromMinutes(initData.Minutes));
|
||||
|
||||
if (initialTime <= TimeSpan.Zero)
|
||||
{
|
||||
|
||||
@@ -89,6 +89,7 @@ public class ProjectSectionDto
|
||||
|
||||
public TimeSpan FinalEstimatedHours { get; set; }
|
||||
public TimeSpan TotalTimeSpent { get; set; }
|
||||
public double ProgressPercentage { get; set; }
|
||||
public bool IsCompleted { get; set; }
|
||||
public bool IsInProgress { get; set; }
|
||||
|
||||
|
||||
@@ -166,6 +166,7 @@ public static class ProjectMappingExtensions
|
||||
CreationDate = section.CreationDate,
|
||||
FinalEstimatedHours = section.FinalEstimatedHours,
|
||||
TotalTimeSpent = section.GetTotalTimeSpent(),
|
||||
ProgressPercentage = section.GetProgressPercentage(),
|
||||
IsCompleted = section.IsCompleted(),
|
||||
IsInProgress = section.IsInProgress(),
|
||||
Activities = section.Activities.Select(a => a.ToDto()).ToList(),
|
||||
@@ -188,6 +189,7 @@ public static class ProjectMappingExtensions
|
||||
CreationDate = section.CreationDate,
|
||||
FinalEstimatedHours = section.FinalEstimatedHours,
|
||||
TotalTimeSpent = section.GetTotalTimeSpent(),
|
||||
ProgressPercentage = section.GetProgressPercentage(),
|
||||
IsCompleted = section.IsCompleted(),
|
||||
IsInProgress = section.IsInProgress()
|
||||
// No activities or additional times for summary
|
||||
|
||||
@@ -1,20 +1,28 @@
|
||||
using GozareshgirProgramManager.Domain.ProjectAgg.Enums;
|
||||
|
||||
namespace GozareshgirProgramManager.Application.Modules.Projects.Queries.GetProjectsList;
|
||||
public record GetProjectListDto
|
||||
|
||||
// Base DTO shared across project, phase, and task
|
||||
public class GetProjectItemDto
|
||||
{
|
||||
public Guid Id { get; init; }
|
||||
public string Name { get; init; } = string.Empty;
|
||||
public int Percentage { get; init; }
|
||||
public ProjectHierarchyLevel Level { get; init; }
|
||||
public Guid? ParentId { get; init; }
|
||||
public bool HasFront { get; set; }
|
||||
public bool HasBackend { get; set; }
|
||||
public bool HasDesign { get; set; }
|
||||
public int TotalHours { get; set; }
|
||||
public int Minutes { get; set; }
|
||||
|
||||
public AssignmentStatus Front { get; set; }
|
||||
public AssignmentStatus Backend { get; set; }
|
||||
public AssignmentStatus Design { get; set; }
|
||||
}
|
||||
|
||||
// Project DTO (no extra fields; inherits from base)
|
||||
public class GetProjectDto : GetProjectItemDto
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
// Phase DTO (no extra fields; inherits from base)
|
||||
public class GetPhaseDto : GetProjectItemDto
|
||||
{
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ using GozareshgirProgramManager.Application._Common.Models;
|
||||
using GozareshgirProgramManager.Domain.ProjectAgg.Entities;
|
||||
using GozareshgirProgramManager.Domain.ProjectAgg.Enums;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.Linq;
|
||||
|
||||
namespace GozareshgirProgramManager.Application.Modules.Projects.Queries.GetProjectsList;
|
||||
|
||||
@@ -17,47 +18,47 @@ public class GetProjectsListQueryHandler : IBaseQueryHandler<GetProjectsListQuer
|
||||
|
||||
public async Task<OperationResult<GetProjectsListResponse>> Handle(GetProjectsListQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
List<GetProjectListDto> projects;
|
||||
var projects = new List<GetProjectDto>();
|
||||
var phases = new List<GetPhaseDto>();
|
||||
var tasks = new List<GetTaskDto>();
|
||||
|
||||
switch (request.HierarchyLevel)
|
||||
{
|
||||
case ProjectHierarchyLevel.Project:
|
||||
projects = await GetProjects(request.ParentId, cancellationToken);
|
||||
await SetSkillFlags(projects, cancellationToken);
|
||||
break;
|
||||
case ProjectHierarchyLevel.Phase:
|
||||
projects = await GetPhases(request.ParentId, cancellationToken);
|
||||
phases = await GetPhases(request.ParentId, cancellationToken);
|
||||
await SetSkillFlags(phases, cancellationToken);
|
||||
break;
|
||||
case ProjectHierarchyLevel.Task:
|
||||
projects = await GetTasks(request.ParentId, cancellationToken);
|
||||
tasks = await GetTasks(request.ParentId, cancellationToken);
|
||||
// Tasks don't need SetSkillFlags because they have Sections list
|
||||
break;
|
||||
default:
|
||||
return OperationResult<GetProjectsListResponse>.Failure("سطح سلسله مراتب نامعتبر است");
|
||||
}
|
||||
await SetSkillFlags(projects, cancellationToken);
|
||||
|
||||
var response = new GetProjectsListResponse(projects);
|
||||
var response = new GetProjectsListResponse(projects, phases, tasks);
|
||||
return OperationResult<GetProjectsListResponse>.Success(response);
|
||||
}
|
||||
|
||||
private async Task<List<GetProjectListDto>> GetProjects(Guid? parentId, CancellationToken cancellationToken)
|
||||
private async Task<List<GetProjectDto>> GetProjects(Guid? parentId, CancellationToken cancellationToken)
|
||||
{
|
||||
var query = _context.Projects.AsQueryable();
|
||||
|
||||
// پروژهها سطح بالا هستند و parentId ندارند، فقط در صورت null بودن parentId نمایش داده میشوند
|
||||
if (parentId.HasValue)
|
||||
{
|
||||
return new List<GetProjectListDto>(); // پروژهها parent ندارند
|
||||
return new List<GetProjectDto>();
|
||||
}
|
||||
|
||||
var projects = await query
|
||||
var entities = await query
|
||||
.OrderByDescending(p => p.CreationDate)
|
||||
.ToListAsync(cancellationToken);
|
||||
var result = new List<GetProjectListDto>();
|
||||
|
||||
foreach (var project in projects)
|
||||
var result = new List<GetProjectDto>();
|
||||
foreach (var project in entities)
|
||||
{
|
||||
var (percentage, totalTime) = await CalculateProjectPercentage(project, cancellationToken);
|
||||
result.Add(new GetProjectListDto
|
||||
result.Add(new GetProjectDto
|
||||
{
|
||||
Id = project.Id,
|
||||
Name = project.Name,
|
||||
@@ -68,28 +69,24 @@ public class GetProjectsListQueryHandler : IBaseQueryHandler<GetProjectsListQuer
|
||||
Minutes = totalTime.Minutes,
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private async Task<List<GetProjectListDto>> GetPhases(Guid? parentId, CancellationToken cancellationToken)
|
||||
private async Task<List<GetPhaseDto>> GetPhases(Guid? parentId, CancellationToken cancellationToken)
|
||||
{
|
||||
var query = _context.ProjectPhases.AsQueryable();
|
||||
|
||||
if (parentId.HasValue)
|
||||
{
|
||||
query = query.Where(x => x.ProjectId == parentId);
|
||||
}
|
||||
|
||||
var phases = await query
|
||||
var entities = await query
|
||||
.OrderByDescending(p => p.CreationDate)
|
||||
.ToListAsync(cancellationToken);
|
||||
var result = new List<GetProjectListDto>();
|
||||
|
||||
foreach (var phase in phases)
|
||||
var result = new List<GetPhaseDto>();
|
||||
foreach (var phase in entities)
|
||||
{
|
||||
var (percentage, totalTime) = await CalculatePhasePercentage(phase, cancellationToken);
|
||||
result.Add(new GetProjectListDto
|
||||
result.Add(new GetPhaseDto
|
||||
{
|
||||
Id = phase.Id,
|
||||
Name = phase.Name,
|
||||
@@ -100,28 +97,87 @@ public class GetProjectsListQueryHandler : IBaseQueryHandler<GetProjectsListQuer
|
||||
Minutes = totalTime.Minutes,
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private async Task<List<GetProjectListDto>> GetTasks(Guid? parentId, CancellationToken cancellationToken)
|
||||
private async Task<List<GetTaskDto>> GetTasks(Guid? parentId, CancellationToken cancellationToken)
|
||||
{
|
||||
var query = _context.ProjectTasks.AsQueryable();
|
||||
|
||||
if (parentId.HasValue)
|
||||
{
|
||||
query = query.Where(x => x.PhaseId == parentId);
|
||||
}
|
||||
|
||||
var tasks = await query
|
||||
var entities = await query
|
||||
.OrderByDescending(t => t.CreationDate)
|
||||
.ToListAsync(cancellationToken);
|
||||
var result = new List<GetProjectListDto>();
|
||||
var result = new List<GetTaskDto>();
|
||||
// دریافت تمام Skills
|
||||
var allSkills = await _context.Skills
|
||||
.Select(s => new { s.Id, s.Name })
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
foreach (var task in tasks)
|
||||
foreach (var task in entities)
|
||||
{
|
||||
var (percentage, totalTime) = await CalculateTaskPercentage(task, cancellationToken);
|
||||
result.Add(new GetProjectListDto
|
||||
var sections = await _context.TaskSections
|
||||
.Include(s => s.Activities)
|
||||
.Include(s => s.Skill)
|
||||
.Where(s => s.TaskId == task.Id)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
// جمعآوری تمام userId های مورد نیاز
|
||||
var userIds = sections
|
||||
.Where(s => s.CurrentAssignedUserId > 0)
|
||||
.Select(s => s.CurrentAssignedUserId)
|
||||
.Distinct()
|
||||
.ToList();
|
||||
|
||||
// دریافت اطلاعات کاربران
|
||||
var users = await _context.Users
|
||||
.Where(u => userIds.Contains(u.Id))
|
||||
.Select(u => new { u.Id, u.FullName })
|
||||
.ToDictionaryAsync(u => u.Id, u => u.FullName, cancellationToken);
|
||||
|
||||
// محاسبه SpentTime و RemainingTime
|
||||
var spentTime = TimeSpan.FromTicks(sections.Sum(s => s.Activities.Sum(a => a.GetTimeSpent().Ticks)));
|
||||
var remainingTime = totalTime - spentTime;
|
||||
|
||||
// ساخت section DTOs برای تمام Skills
|
||||
var sectionDtos = allSkills.Select(skill =>
|
||||
{
|
||||
var section = sections.FirstOrDefault(s => s.SkillId == skill.Id);
|
||||
|
||||
if (section == null)
|
||||
{
|
||||
// اگر section وجود نداشت، یک DTO با وضعیت Unassigned برمیگردانیم
|
||||
return new GetTaskSectionDto
|
||||
{
|
||||
Id = Guid.Empty,
|
||||
SkillName = skill.Name ?? string.Empty,
|
||||
SpentTime = TimeSpan.Zero,
|
||||
TotalTime = TimeSpan.Zero,
|
||||
Percentage = 0,
|
||||
UserFullName = string.Empty,
|
||||
AssignmentStatus = AssignmentStatus.Unassigned
|
||||
};
|
||||
}
|
||||
|
||||
// اگر section وجود داشت
|
||||
return new GetTaskSectionDto
|
||||
{
|
||||
Id = section.Id,
|
||||
SkillName = skill.Name ?? string.Empty,
|
||||
SpentTime = TimeSpan.FromTicks(section.Activities.Sum(a => a.GetTimeSpent().Ticks)),
|
||||
TotalTime = section.FinalEstimatedHours,
|
||||
Percentage = (int)section.GetProgressPercentage(),
|
||||
UserFullName = section.CurrentAssignedUserId > 0 && users.ContainsKey(section.CurrentAssignedUserId)
|
||||
? users[section.CurrentAssignedUserId]
|
||||
: string.Empty,
|
||||
AssignmentStatus = GetAssignmentStatus(section)
|
||||
};
|
||||
}).ToList();
|
||||
|
||||
result.Add(new GetTaskDto
|
||||
{
|
||||
Id = task.Id,
|
||||
Name = task.Name,
|
||||
@@ -129,187 +185,175 @@ public class GetProjectsListQueryHandler : IBaseQueryHandler<GetProjectsListQuer
|
||||
ParentId = task.PhaseId,
|
||||
Percentage = percentage,
|
||||
TotalHours = (int)totalTime.TotalHours,
|
||||
Minutes = totalTime.Minutes
|
||||
Minutes = totalTime.Minutes,
|
||||
SpentTime = spentTime,
|
||||
RemainingTime = remainingTime,
|
||||
Sections = sectionDtos,
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private async Task SetSkillFlags(List<GetProjectListDto> projects, CancellationToken cancellationToken)
|
||||
private async Task SetSkillFlags<TItem>(List<TItem> items, CancellationToken cancellationToken) where TItem : GetProjectItemDto
|
||||
{
|
||||
if (!projects.Any())
|
||||
if (!items.Any())
|
||||
return;
|
||||
|
||||
var projectIds = projects.Select(x => x.Id).ToList();
|
||||
var hierarchyLevel = projects.First().Level;
|
||||
|
||||
var ids = items.Select(x => x.Id).ToList();
|
||||
var hierarchyLevel = items.First().Level;
|
||||
switch (hierarchyLevel)
|
||||
{
|
||||
case ProjectHierarchyLevel.Project:
|
||||
await SetSkillFlagsForProjects(projects, projectIds, cancellationToken);
|
||||
await SetSkillFlagsForProjects(items, ids, cancellationToken);
|
||||
break;
|
||||
|
||||
case ProjectHierarchyLevel.Phase:
|
||||
await SetSkillFlagsForPhases(projects, projectIds, cancellationToken);
|
||||
break;
|
||||
|
||||
case ProjectHierarchyLevel.Task:
|
||||
await SetSkillFlagsForTasks(projects, projectIds, cancellationToken);
|
||||
await SetSkillFlagsForPhases(items, ids, cancellationToken);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SetSkillFlagsForProjects(List<GetProjectListDto> projects, List<Guid> projectIds, CancellationToken cancellationToken)
|
||||
|
||||
private async Task SetSkillFlagsForProjects<TItem>(List<TItem> items, List<Guid> projectIds, CancellationToken cancellationToken) where TItem : GetProjectItemDto
|
||||
{
|
||||
var projectSections = await _context.ProjectSections
|
||||
.Include(x => x.Skill)
|
||||
.Where(s => projectIds.Contains(s.ProjectId))
|
||||
// For projects: gather all phases, then tasks, then sections
|
||||
var phases = await _context.ProjectPhases
|
||||
.Where(ph => projectIds.Contains(ph.ProjectId))
|
||||
.Select(ph => ph.Id)
|
||||
.ToListAsync(cancellationToken);
|
||||
var tasks = await _context.ProjectTasks
|
||||
.Where(t => phases.Contains(t.PhaseId))
|
||||
.Select(t => t.Id)
|
||||
.ToListAsync(cancellationToken);
|
||||
var sections = await _context.TaskSections
|
||||
.Include(s => s.Skill)
|
||||
.Where(s => tasks.Contains(s.TaskId))
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
if (!projectSections.Any())
|
||||
return;
|
||||
|
||||
foreach (var project in projects)
|
||||
foreach (var item in items)
|
||||
{
|
||||
var sections = projectSections.Where(s => s.ProjectId == project.Id).ToList();
|
||||
project.HasBackend = sections.Any(x => x.Skill?.Name == "Backend");
|
||||
project.HasFront = sections.Any(x => x.Skill?.Name == "Frontend");
|
||||
project.HasDesign = sections.Any(x => x.Skill?.Name == "UI/UX Design");
|
||||
var relatedPhases = phases; // used for filtering tasks by project
|
||||
var relatedTasks = await _context.ProjectTasks
|
||||
.Where(t => t.PhaseId != Guid.Empty && relatedPhases.Contains(t.PhaseId))
|
||||
.Select(t => t.Id)
|
||||
.ToListAsync(cancellationToken);
|
||||
var itemSections = sections.Where(s => relatedTasks.Contains(s.TaskId));
|
||||
item.Backend = GetAssignmentStatus(itemSections.FirstOrDefault(x => x.Skill?.Name == "Backend"));
|
||||
item.Front = GetAssignmentStatus(itemSections.FirstOrDefault(x => x.Skill?.Name == "Frontend"));
|
||||
item.Design = GetAssignmentStatus(itemSections.FirstOrDefault(x => x.Skill?.Name == "UI/UX Design"));
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SetSkillFlagsForPhases(List<GetProjectListDto> projects, List<Guid> phaseIds, CancellationToken cancellationToken)
|
||||
private async Task SetSkillFlagsForPhases<TItem>(List<TItem> items, List<Guid> phaseIds, CancellationToken cancellationToken) where TItem : GetProjectItemDto
|
||||
{
|
||||
var phaseSections = await _context.PhaseSections
|
||||
.Include(x => x.Skill)
|
||||
.Where(s => phaseIds.Contains(s.PhaseId))
|
||||
// For phases: gather tasks, then sections
|
||||
var tasks = await _context.ProjectTasks
|
||||
.Where(t => phaseIds.Contains(t.PhaseId))
|
||||
.Select(t => t.Id)
|
||||
.ToListAsync(cancellationToken);
|
||||
var sections = await _context.TaskSections
|
||||
.Include(s => s.Skill)
|
||||
.Where(s => tasks.Contains(s.TaskId))
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
if (!phaseSections.Any())
|
||||
return;
|
||||
|
||||
foreach (var phase in projects)
|
||||
foreach (var item in items)
|
||||
{
|
||||
var sections = phaseSections.Where(s => s.PhaseId == phase.Id).ToList();
|
||||
phase.HasBackend = sections.Any(x => x.Skill?.Name == "Backend");
|
||||
phase.HasFront = sections.Any(x => x.Skill?.Name == "Frontend");
|
||||
phase.HasDesign = sections.Any(x => x.Skill?.Name == "UI/UX Design");
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SetSkillFlagsForTasks(List<GetProjectListDto> projects, List<Guid> taskIds, CancellationToken cancellationToken)
|
||||
{
|
||||
var taskSections = await _context.TaskSections
|
||||
.Include(x => x.Skill)
|
||||
.Where(s => taskIds.Contains(s.TaskId))
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
if (!taskSections.Any())
|
||||
return;
|
||||
|
||||
foreach (var task in projects)
|
||||
{
|
||||
var sections = taskSections.Where(s => s.TaskId == task.Id).ToList();
|
||||
task.HasBackend = sections.Any(x => x.Skill?.Name == "Backend");
|
||||
task.HasFront = sections.Any(x => x.Skill?.Name == "Frontend");
|
||||
task.HasDesign = sections.Any(x => x.Skill?.Name == "UI/UX Design");
|
||||
// Filter tasks for this phase
|
||||
var phaseTaskIds = await _context.ProjectTasks
|
||||
.Where(t => t.PhaseId == item.Id)
|
||||
.Select(t => t.Id)
|
||||
.ToListAsync(cancellationToken);
|
||||
var itemSections = sections.Where(s => phaseTaskIds.Contains(s.TaskId));
|
||||
item.Backend = GetAssignmentStatus(itemSections.FirstOrDefault(x => x.Skill?.Name == "Backend"));
|
||||
item.Front = GetAssignmentStatus(itemSections.FirstOrDefault(x => x.Skill?.Name == "Frontend"));
|
||||
item.Design = GetAssignmentStatus(itemSections.FirstOrDefault(x => x.Skill?.Name == "UI/UX Design"));
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<(int Percentage, TimeSpan TotalTime)> CalculateProjectPercentage(Project project, CancellationToken cancellationToken)
|
||||
{
|
||||
// گرفتن تمام فازهای پروژه
|
||||
var phases = await _context.ProjectPhases
|
||||
.Where(ph => ph.ProjectId == project.Id)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
if (!phases.Any())
|
||||
return (0, TimeSpan.Zero);
|
||||
|
||||
// محاسبه درصد هر فاز و میانگینگیری
|
||||
var phasePercentages = new List<int>();
|
||||
var totalTime = TimeSpan.Zero;
|
||||
|
||||
foreach (var phase in phases)
|
||||
{
|
||||
var (phasePercentage, phaseTime) = await CalculatePhasePercentage(phase, cancellationToken);
|
||||
phasePercentages.Add(phasePercentage);
|
||||
totalTime += phaseTime;
|
||||
}
|
||||
|
||||
var averagePercentage = phasePercentages.Any() ? (int)phasePercentages.Average() : 0;
|
||||
return (averagePercentage, totalTime);
|
||||
}
|
||||
|
||||
private async Task<(int Percentage, TimeSpan TotalTime)> CalculatePhasePercentage(ProjectPhase phase, CancellationToken cancellationToken)
|
||||
{
|
||||
// گرفتن تمام تسکهای فاز
|
||||
var tasks = await _context.ProjectTasks
|
||||
.Where(t => t.PhaseId == phase.Id)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
if (!tasks.Any())
|
||||
return (0, TimeSpan.Zero);
|
||||
|
||||
// محاسبه درصد هر تسک و میانگینگیری
|
||||
var taskPercentages = new List<int>();
|
||||
var totalTime = TimeSpan.Zero;
|
||||
|
||||
foreach (var task in tasks)
|
||||
{
|
||||
var (taskPercentage, taskTime) = await CalculateTaskPercentage(task, cancellationToken);
|
||||
taskPercentages.Add(taskPercentage);
|
||||
totalTime += taskTime;
|
||||
}
|
||||
|
||||
var averagePercentage = taskPercentages.Any() ? (int)taskPercentages.Average() : 0;
|
||||
return (averagePercentage, totalTime);
|
||||
}
|
||||
|
||||
private async Task<(int Percentage, TimeSpan TotalTime)> CalculateTaskPercentage(ProjectTask task, CancellationToken cancellationToken)
|
||||
{
|
||||
// گرفتن تمام سکشنهای تسک با activities
|
||||
var sections = await _context.TaskSections
|
||||
.Include(s => s.Activities)
|
||||
.Include(x=>x.AdditionalTimes)
|
||||
.Where(s => s.TaskId == task.Id)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
if (!sections.Any())
|
||||
return (0, TimeSpan.Zero);
|
||||
|
||||
// محاسبه درصد هر سکشن و میانگینگیری
|
||||
var sectionPercentages = new List<int>();
|
||||
var totalTime = TimeSpan.Zero;
|
||||
|
||||
foreach (var section in sections)
|
||||
{
|
||||
var (sectionPercentage, sectionTime) = CalculateSectionPercentage(section);
|
||||
sectionPercentages.Add(sectionPercentage);
|
||||
totalTime += sectionTime;
|
||||
}
|
||||
|
||||
var averagePercentage = sectionPercentages.Any() ? (int)sectionPercentages.Average() : 0;
|
||||
return (averagePercentage, totalTime);
|
||||
}
|
||||
|
||||
private static (int Percentage, TimeSpan TotalTime) CalculateSectionPercentage(TaskSection section)
|
||||
{
|
||||
// محاسبه کل زمان تخمین زده شده (اولیه + اضافی)
|
||||
var totalEstimatedHours = section.FinalEstimatedHours.TotalHours;
|
||||
return ((int)section.GetProgressPercentage(),section.FinalEstimatedHours);
|
||||
}
|
||||
|
||||
// محاسبه کل زمان صرف شده از activities
|
||||
var totalSpentTime = TimeSpan.FromHours(section.Activities.Sum(a => a.GetTimeSpent().TotalHours));
|
||||
private static AssignmentStatus GetAssignmentStatus(TaskSection? section)
|
||||
{
|
||||
// تعیین تکلیف نشده: section وجود ندارد
|
||||
if (section == null)
|
||||
return AssignmentStatus.Unassigned;
|
||||
|
||||
if (totalEstimatedHours <= 0)
|
||||
return (0, section.FinalEstimatedHours);
|
||||
// بررسی وجود user
|
||||
bool hasUser = section.CurrentAssignedUserId > 0;
|
||||
|
||||
// بررسی وجود time (InitialEstimatedHours بزرگتر از صفر باشد)
|
||||
bool hasTime = section.InitialEstimatedHours > TimeSpan.Zero;
|
||||
|
||||
var totalSpentHours = totalSpentTime.TotalHours;
|
||||
// تعیین تکلیف شده: هم user و هم time تعیین شده
|
||||
if (hasUser && hasTime)
|
||||
return AssignmentStatus.Assigned;
|
||||
|
||||
// محاسبه درصد (حداکثر 100%)
|
||||
var percentage = (totalSpentHours / totalEstimatedHours) * 100;
|
||||
return (Math.Min((int)Math.Round(percentage), 100), section.FinalEstimatedHours);
|
||||
// فقط کاربر تعیین شده: user دارد ولی time ندارد
|
||||
if (hasUser && !hasTime)
|
||||
return AssignmentStatus.UserOnly;
|
||||
|
||||
// تعیین تکلیف نشده: نه user دارد نه time
|
||||
return AssignmentStatus.Unassigned;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
namespace GozareshgirProgramManager.Application.Modules.Projects.Queries.GetProjectsList;
|
||||
|
||||
public record GetProjectsListResponse(
|
||||
List<GetProjectListDto> Projects);
|
||||
|
||||
List<GetProjectDto> Projects,
|
||||
List<GetPhaseDto> Phases,
|
||||
List<GetTaskDto> Tasks);
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
using GozareshgirProgramManager.Domain.ProjectAgg.Enums;
|
||||
|
||||
namespace GozareshgirProgramManager.Application.Modules.Projects.Queries.GetProjectsList;
|
||||
|
||||
public class GetTaskDto
|
||||
{
|
||||
public Guid Id { get; init; }
|
||||
public string Name { get; init; } = string.Empty;
|
||||
public int Percentage { get; init; }
|
||||
public ProjectHierarchyLevel Level { get; init; }
|
||||
public Guid? ParentId { get; init; }
|
||||
public int TotalHours { get; set; }
|
||||
public int Minutes { get; set; }
|
||||
|
||||
// Task-specific fields
|
||||
public TimeSpan SpentTime { get; init; }
|
||||
public TimeSpan RemainingTime { get; init; }
|
||||
public List<GetTaskSectionDto> Sections { get; init; }
|
||||
}
|
||||
|
||||
public class GetTaskSectionDto
|
||||
{
|
||||
public Guid Id { get; init; }
|
||||
public string SkillName { get; init; } = string.Empty;
|
||||
public TimeSpan SpentTime { get; init; }
|
||||
public TimeSpan TotalTime { get; init; }
|
||||
public int Percentage { get; init; }
|
||||
public string UserFullName{ get; init; } = string.Empty;
|
||||
public AssignmentStatus AssignmentStatus { get; set; }
|
||||
|
||||
}
|
||||
@@ -53,7 +53,8 @@ public class ProjectBoardListQueryHandler : IBaseQueryHandler<ProjectBoardListQu
|
||||
.ToDictionaryAsync(x => x.Id, x => x.FullName, cancellationToken);
|
||||
|
||||
|
||||
var result = data
|
||||
var result = data .OrderByDescending(x => x.CurrentAssignedUserId == currentUserId)
|
||||
.ThenBy(x => GetStatusOrder(x.Status))
|
||||
.Select(x =>
|
||||
{
|
||||
// محاسبه یکبار برای هر Activity و Cache کردن نتیجه
|
||||
@@ -95,9 +96,6 @@ public class ProjectBoardListQueryHandler : IBaseQueryHandler<ProjectBoardListQu
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
mergedHistories = mergedHistories.OrderByDescending(h => h.IsCurrentUser).ToList();
|
||||
|
||||
return new ProjectBoardListResponse()
|
||||
{
|
||||
Id = x.Id,
|
||||
@@ -108,6 +106,7 @@ public class ProjectBoardListQueryHandler : IBaseQueryHandler<ProjectBoardListQu
|
||||
Progress = new ProjectProgressDto()
|
||||
{
|
||||
CompleteSecond = x.FinalEstimatedHours.TotalSeconds,
|
||||
Percentage = (int)x.GetProgressPercentage(),
|
||||
CurrentSecond = activityTimeData.Sum(a => a.TotalSeconds),
|
||||
Histories = mergedHistories
|
||||
},
|
||||
@@ -116,19 +115,21 @@ public class ProjectBoardListQueryHandler : IBaseQueryHandler<ProjectBoardListQu
|
||||
: users.GetValueOrDefault(x.CurrentAssignedUserId, "ناشناس"),
|
||||
SkillName = x.Skill?.Name??"-",
|
||||
};
|
||||
})
|
||||
.OrderByDescending(r =>
|
||||
{
|
||||
// اگر AssignedUser null نباشد، بررسی کن که برابر current user هست یا نه
|
||||
if (r.AssignedUser != null)
|
||||
{
|
||||
return users.FirstOrDefault(u => u.Value == r.AssignedUser).Key == currentUserId;
|
||||
}
|
||||
// اگر AssignedUser null بود، از OriginalUser بررسی کن
|
||||
return users.FirstOrDefault(u => u.Value == r.OriginalUser).Key == currentUserId;
|
||||
})
|
||||
.ToList();
|
||||
}).ToList();
|
||||
|
||||
return OperationResult<List<ProjectBoardListResponse>>.Success(result);
|
||||
}
|
||||
|
||||
private static int GetStatusOrder(TaskSectionStatus status)
|
||||
{
|
||||
return status switch
|
||||
{
|
||||
TaskSectionStatus.InProgress => 0,
|
||||
TaskSectionStatus.Incomplete => 1,
|
||||
TaskSectionStatus.NotAssigned => 2,
|
||||
TaskSectionStatus.ReadyToStart => 2,
|
||||
TaskSectionStatus.PendingForCompletion => 3,
|
||||
_ => 99
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,7 @@ public class ProjectBoardListResponse
|
||||
public class ProjectProgressDto
|
||||
{
|
||||
public double CurrentSecond { get; set; }
|
||||
public int Percentage { get; set; }
|
||||
public double CompleteSecond { get; set; }
|
||||
public List<ProjectProgressHistoryDto> Histories { get; set; }
|
||||
}
|
||||
|
||||
@@ -12,14 +12,16 @@ public record ProjectDeployBoardDetailsResponse(
|
||||
public record ProjectDeployBoardDetailPhaseItem(
|
||||
string Name,
|
||||
TimeSpan TotalTimeSpan,
|
||||
TimeSpan DoneTimeSpan);
|
||||
TimeSpan DoneTimeSpan,
|
||||
int Percentage);
|
||||
|
||||
public record ProjectDeployBoardDetailTaskItem(
|
||||
string Name,
|
||||
TimeSpan TotalTimeSpan,
|
||||
TimeSpan DoneTimeSpan,
|
||||
int Percentage,
|
||||
List<ProjectDeployBoardDetailItemSkill> Skills)
|
||||
: ProjectDeployBoardDetailPhaseItem(Name, TotalTimeSpan, DoneTimeSpan);
|
||||
: ProjectDeployBoardDetailPhaseItem(Name, TotalTimeSpan, DoneTimeSpan,Percentage);
|
||||
|
||||
public record ProjectDeployBoardDetailItemSkill(string OriginalUserFullName, string SkillName, int TimePercentage);
|
||||
|
||||
@@ -79,22 +81,20 @@ public class
|
||||
|
||||
var skillName = s.Skill?.Name ?? "بدون مهارت";
|
||||
|
||||
var totalTimeSpent = s.GetTotalTimeSpent();
|
||||
|
||||
var timePercentage = s.FinalEstimatedHours.Ticks > 0
|
||||
? (int)((totalTimeSpent.Ticks / (double)s.FinalEstimatedHours.Ticks) * 100)
|
||||
: 0;
|
||||
var timePercentage = (int)s.GetProgressPercentage();
|
||||
|
||||
return new ProjectDeployBoardDetailItemSkill(
|
||||
originalUserFullName,
|
||||
skillName,
|
||||
timePercentage);
|
||||
}).ToList();
|
||||
var taskPercentage = (int)Math.Round(skills.Average(x => x.TimePercentage));
|
||||
|
||||
return new ProjectDeployBoardDetailTaskItem(
|
||||
t.Name,
|
||||
totalTime,
|
||||
doneTime,
|
||||
taskPercentage,
|
||||
skills);
|
||||
}).ToList();
|
||||
|
||||
@@ -104,7 +104,10 @@ public class
|
||||
var doneTimeSpan = tasksRes.Aggregate(TimeSpan.Zero,
|
||||
(sum, next) => sum.Add(next.DoneTimeSpan));
|
||||
|
||||
var phaseRes = new ProjectDeployBoardDetailPhaseItem(phase.Name, totalTimeSpan, doneTimeSpan);
|
||||
var phasePercentage = tasksRes.Average(x => x.Percentage);
|
||||
|
||||
var phaseRes = new ProjectDeployBoardDetailPhaseItem(phase.Name, totalTimeSpan, doneTimeSpan,
|
||||
(int)phasePercentage);
|
||||
|
||||
var res = new ProjectDeployBoardDetailsResponse(phaseRes, tasksRes);
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ public record ProjectDeployBoardListItem()
|
||||
public int DoneTasks { get; set; }
|
||||
public TimeSpan TotalTimeSpan { get; set; }
|
||||
public TimeSpan DoneTimeSpan { get; set; }
|
||||
public int Percentage { get; set; }
|
||||
public ProjectDeployStatus DeployStatus { get; set; }
|
||||
}
|
||||
public record GetProjectsDeployBoardListResponse(List<ProjectDeployBoardListItem> Items);
|
||||
@@ -66,7 +67,8 @@ public class ProjectDeployBoardListQueryHandler:IBaseQueryHandler<GetProjectDepl
|
||||
.Select(x => x.TaskId).Distinct().Count(),
|
||||
TotalTimeSpan = TimeSpan.FromTicks(g.Sum(x => x.InitialEstimatedHours.Ticks)),
|
||||
DoneTimeSpan = TimeSpan.FromTicks(g.Sum(x=>x.GetTotalTimeSpent().Ticks)),
|
||||
DeployStatus = g.First().Task.Phase.DeployStatus
|
||||
DeployStatus = g.First().Task.Phase.DeployStatus,
|
||||
Percentage = (int)Math.Round(g.Average(x => x.GetProgressPercentage()))
|
||||
}).ToList();
|
||||
var response = new GetProjectsDeployBoardListResponse(list);
|
||||
return OperationResult<GetProjectsDeployBoardListResponse>.Success(response);
|
||||
|
||||
@@ -157,6 +157,27 @@ public class TaskSection : EntityBase<Guid>
|
||||
return TimeSpan.FromTicks(_activities.Sum(a => a.GetTimeSpent().Ticks));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// محاسبه درصد پیشرفت بر اساس زمان مصرف شده به تایم برآورد شده
|
||||
/// اگر وضعیت Completed باشد، همیشه 100 درصد برمیگرداند
|
||||
/// </summary>
|
||||
public double GetProgressPercentage()
|
||||
{
|
||||
// اگر تسک کامل شده، همیشه 100 درصد
|
||||
if (Status == TaskSectionStatus.Completed)
|
||||
return 100.0;
|
||||
|
||||
// اگر تایم برآورد شده صفر است، درصد صفر است
|
||||
if (FinalEstimatedHours.TotalHours <= 0)
|
||||
return 0.0;
|
||||
|
||||
var timeSpent = GetTotalTimeSpent();
|
||||
var percentage = (timeSpent.TotalMinutes / FinalEstimatedHours.TotalMinutes) * 100.0;
|
||||
|
||||
// محدود کردن درصد به 100 (در صورتی که زمان مصرف شده بیشتر از تخمین باشد)
|
||||
return Math.Min(percentage, 100.0);
|
||||
}
|
||||
|
||||
public bool IsCompleted()
|
||||
{
|
||||
return Status == TaskSectionStatus.Completed;
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
namespace GozareshgirProgramManager.Domain.ProjectAgg.Enums;
|
||||
|
||||
/// <summary>
|
||||
/// وضعیت تکلیف دهی برای بخشهای مختلف پروژه
|
||||
/// </summary>
|
||||
public enum AssignmentStatus
|
||||
{
|
||||
/// <summary>
|
||||
/// تعیین تکلیف نشده
|
||||
/// </summary>
|
||||
Unassigned = 0,
|
||||
|
||||
/// <summary>
|
||||
/// تعیین تکلیف شده
|
||||
/// </summary>
|
||||
Assigned = 1,
|
||||
|
||||
/// <summary>
|
||||
/// فقط کاربر تعیین شده
|
||||
/// </summary>
|
||||
UserOnly = 2,
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ public class TaskSectionRepository:RepositoryBase<Guid,TaskSection>,ITaskSection
|
||||
{
|
||||
return await _context.TaskSections
|
||||
.Include(x => x.Activities)
|
||||
.Include(x=>x.AdditionalTimes)
|
||||
.FirstOrDefaultAsync(x => x.Id == id, cancellationToken);
|
||||
}
|
||||
|
||||
|
||||
@@ -916,6 +916,17 @@ public class institutionContractController : AdminBaseController
|
||||
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
||||
$"قرارداد های مالی.xlsx");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// تنظیم وضعیت ارسال قرارداد
|
||||
/// </summary>
|
||||
[HttpPost("set-is-sent")]
|
||||
public async Task<ActionResult<OperationResult>> SetIsSent([FromBody] SetInstitutionContractSendFlagRequest request)
|
||||
{
|
||||
var result = await _institutionContractApplication.SetContractSendFlag(request);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class InstitutionContractCreationGetRepresentativeIdResponse
|
||||
@@ -969,4 +980,4 @@ public class VerifyCodeRequest
|
||||
{
|
||||
public long ContractingPartyId { get; set; }
|
||||
public string verifyCode { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -380,13 +380,7 @@ builder.Host.UseSerilog((context, services, configuration) =>
|
||||
.ReadFrom.Configuration(context.Configuration)
|
||||
.ReadFrom.Services(services)
|
||||
.Enrich.FromLogContext();
|
||||
|
||||
// در محیط Development، EF Core Commands را هم لاگ میکنیم
|
||||
if (context.HostingEnvironment.IsDevelopment())
|
||||
{
|
||||
logConfig
|
||||
.MinimumLevel.Override("Microsoft.EntityFrameworkCore.Database.Command", LogEventLevel.Information);
|
||||
}
|
||||
|
||||
|
||||
logConfig.WriteTo.File(
|
||||
path: Path.Combine(logDirectory, "gozareshgir_log.txt"),
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<RazorCompileOnBuild>true</RazorCompileOnBuild>
|
||||
<UserSecretsId>a6049acf-0286-4947-983a-761d06d65f36</UserSecretsId>
|
||||
</PropertyGroup>
|
||||
|
||||
<!--<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
{
|
||||
"DetailedErrors": true,
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft": "Warning",
|
||||
"Microsoft.Hosting.Lifetime": "Information"
|
||||
}
|
||||
},
|
||||
"ConnectionStrings": {
|
||||
//تست
|
||||
//"MesbahDb": "Data Source=DESKTOP-NUE119G\\MSNEW;Initial Catalog=Mesbah_db;Integrated Security=True"
|
||||
|
||||
//server
|
||||
"MesbahDbServer": "Data Source=171.22.24.15;Initial Catalog=mesbah_db;Persist Security Info=False;User ID=ir_db;Password=R2rNp[170]18[3019]#@ATt;TrustServerCertificate=true;",
|
||||
|
||||
//local
|
||||
"MesbahDb": "Data Source=.;Initial Catalog=mesbah_db;Integrated Security=True;TrustServerCertificate=true;",
|
||||
|
||||
//server
|
||||
//"MesbahDb": "Data Source=185.208.175.186;Initial Catalog=mesbah_db;Persist Security Info=False;User ID=ir_db;Password=R2rNp[170]18[3019]#@ATt;TrustServerCertificate=true;",
|
||||
|
||||
//dad-mehr
|
||||
//"MesbahDb": "Data Source=.;Initial Catalog=teamWork;Integrated Security=True;TrustServerCertificate=true;",
|
||||
|
||||
"TestDb": "Data Source=.;Initial Catalog=TestDb;Integrated Security=True;TrustServerCertificate=true;",
|
||||
|
||||
//program_manager_db
|
||||
"ProgramManagerDb": "Data Source=.;Initial Catalog=program_manager_db;Integrated Security=True;TrustServerCertificate=true;",
|
||||
//"ProgramManagerDb": "Data Source=185.208.175.186;Initial Catalog=program_manager_db;Persist Security Info=False;User ID=ir_db;Password=R2rNp[170]18[3019]#@ATt;TrustServerCertificate=true;"
|
||||
"ProgramManagerDbServer": "Data Source=171.22.24.15;Initial Catalog=program_manager_db;Persist Security Info=False;User ID=ir_db;Password=R2rNp[170]18[3019]#@ATt;TrustServerCertificate=true;"
|
||||
//mahan Docker
|
||||
//"MesbahDb": "Data Source=localhost,5069;Initial Catalog=mesbah_db;User ID=sa;Password=YourPassword123;TrustServerCertificate=True;"
|
||||
},
|
||||
|
||||
"GoogleRecaptchaV3": {
|
||||
"SiteKey": "6Lfhp_AnAAAAAB79WkrMoHd1k8ir4m8VvfjE7FTH",
|
||||
"SecretKey": "6Lfhp_AnAAAAANjDDY6DPrbbUQS7k6ZCRmrVP5Lb"
|
||||
},
|
||||
"SmsSecrets": {
|
||||
"ApiKey": "Og5M562igmzJRhQPnq0GdtieYdLgtfikjzxOmeQBPxJjZtyge5Klc046Lfw1mxSa",
|
||||
"SecretKey": "dadmehr"
|
||||
},
|
||||
"Domain": ".dadmehrg.ir",
|
||||
"MongoDb": {
|
||||
"ConnectionString": "mongodb://localhost:27017",
|
||||
"DatabaseName": "Gozareshgir"
|
||||
},
|
||||
"SmsSettings": {
|
||||
"IsTestMode": true,
|
||||
"TestNumbers": [
|
||||
"09116967898"
|
||||
//, "09116067106", "09114221321"
|
||||
]
|
||||
},
|
||||
"InternalApi": {
|
||||
"Local": "https://localhost:7032",
|
||||
"Dadmehrg": "https://api.pm.dadmehrg.ir",
|
||||
"Gozareshgir": "https://api.pm.gozareshgir.ir"
|
||||
},
|
||||
"SepehrGateWayTerminalId": 99213700,
|
||||
"JwtSettings": {
|
||||
"SecretKey": ">3£>^1UBG@yw)QdhRC3$£:;r8~?qpp^oKK4D3a~8L2>enF;lkgh",
|
||||
"Issuer": "GozareshgirApp",
|
||||
"Audience": "GozareshgirUsers",
|
||||
"ExpirationMinutes": 30
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft": "Warning",
|
||||
"Microsoft.Hosting.Lifetime": "Information"
|
||||
}
|
||||
},
|
||||
"ConnectionStrings": {
|
||||
//"MesbahDb": "Data Source=.\\MSSQLSERVER2019;Initial Catalog=mesbah_db;Persist Security Info=False;User ID=mesbah_db;Password=sa142857$@;"
|
||||
"MesbahDb": "Data Source=.;Initial Catalog=mesbah_db;Integrated Security=True;TrustServerCertificate=true;",
|
||||
|
||||
//dad-mehr
|
||||
//"MesbahDb": "Data Source=.;Initial Catalog=teamWork;Integrated Security=True;TrustServerCertificate=true;",
|
||||
|
||||
//testDb
|
||||
"TestDb": "Data Source=.;Initial Catalog=TestDb;Integrated Security=True;TrustServerCertificate=true;",
|
||||
//program_manager_db
|
||||
"ProgramManagerDb": "Data Source=.;Initial Catalog=program_manager_db;Integrated Security=True;TrustServerCertificate=true;"
|
||||
},
|
||||
"BackupOptions": {
|
||||
"DbName": "mesbah_db",
|
||||
"DbBackupZipPath": "c://EveryHourBackupList//",
|
||||
"FastDbBackupZipPath": "c://FastBackupZipList//",
|
||||
"InsuranceListZipPath": "c://Logs//Gozareshgir//"
|
||||
},
|
||||
"faceModels": {
|
||||
"Faces": "c://labels//20//"
|
||||
},
|
||||
"AllowedHosts": "*",
|
||||
//"Domain": ".dad-mehr.ir"
|
||||
"Domain": ".gozareshgir.ir",
|
||||
"MongoDb": {
|
||||
"ConnectionString": "mongodb://localhost:27017",
|
||||
"DatabaseName": "Gozareshgir"
|
||||
},
|
||||
"SmsSettings": {
|
||||
"IsTestMode": false,
|
||||
"TestNumbers": []
|
||||
},
|
||||
"InternalApi": {
|
||||
"Local": "https://localhost:7032",
|
||||
"Dadmehrg": "https://api.pm.dadmehrg.ir",
|
||||
"Gozareshgir": "https://api.pm.gozareshgir.ir"
|
||||
},
|
||||
|
||||
"SepehrGateWayTerminalId": 99213700,
|
||||
"JwtSettings": {
|
||||
"SecretKey": ">3£>^1UBG@yw)QdhRC3$£:;r8~?qpp^oKK4D3a~8L2>enF;lkgh",
|
||||
"Issuer": "GozareshgirApp",
|
||||
"Audience": "GozareshgirUsers",
|
||||
"ExpirationMinutes": 30
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user