Compare commits

...

33 Commits

Author SHA1 Message Date
aa37ca4b28 add: enhance deployment status validation in ChangeDeployStatusProject command and include Activities in ProjectDeployBoardList query 2025-12-30 17:19:59 +03:30
45615684ed add: enhance skill calculation in ProjectDeployBoardDetailsQueryHandler and refine query conditions in ProjectDeployBoardListQueryHandler 2025-12-30 15:55:57 +03:30
94955ea1b4 add: update GetProjectDeployBoardDetails method to use ProjectDeployBoardDetailsQuery 2025-12-30 12:54:53 +03:30
656bb49fab add: remove GetByIdAsync method and add Id property to ProjectDeployBoardListItem 2025-12-30 12:30:06 +03:30
fb5b98bf25 add: update UpdateDeployStatus method to archive project phase upon deployment 2025-12-30 11:54:56 +03:30
1e733f3f20 add: implement ChangeDeployStatusProject command and handler for updating project deployment status 2025-12-30 11:10:40 +03:30
d855684cd7 add: implement AutoUpdateDeployStatusCommand for automatic deployment status updates 2025-12-29 12:16:51 +03:30
9e5e8d8e5d refactor: improve code formatting and structure in ProjectController 2025-12-29 11:45:32 +03:30
9eefdd8fd1 add: implement GetProjectDeployBoardDetails endpoint for retrieving project board details 2025-12-29 10:27:23 +03:30
2159901614 add: implement ProjectDeployBoardDetailsQuery and its handler with validation for project phase details 2025-12-27 19:42:13 +03:30
7ce7854091 add: include DeployStatus in ProjectDeployBoardListItem for deployment status tracking 2025-12-27 16:26:07 +03:30
4c638cbdae add: implement DeployStatus and IsArchived properties in ProjectPhase, and create ProjectDeployBoardListQueryHandler for project deployment management 2025-12-27 13:59:37 +03:30
39a5918a11 add: implement ProjectDeployBoardListQueryHandler and initialize GetProjectsListQueryHandler structure 2025-12-24 18:55:01 +03:30
b9e271de1a fix: update OccurredOn property to use DateTime.Now instead of DateTime.UtcNow in event records 2025-12-23 15:00:18 +03:30
e661bc2dcb add: enhance ProjectBoardListQueryHandler and ProjectPhase to manage task section statuses and deployment states 2025-12-23 14:52:41 +03:30
1bfe41418b add: enhance ProjectBoardDetailResponse to include RemainingTime and user time details 2025-12-22 19:51:21 +03:30
6a446d5972 add: implement AutoStopOverTimeTaskSections command and related functionality 2025-12-22 19:13:34 +03:30
12fab5a9a5 add {id:guid} convention for controllers 2025-12-20 20:57:34 +03:30
20dd8f64f4 add: include OneMonthWithoutTax and OneMonthTax properties in InstitutionContractPrintViewModel 2025-12-20 20:28:08 +03:30
b827493306 refactor: remove unused discount-related classes from IInstitutionContractApplicationpnpm 2025-12-20 20:12:31 +03:30
04c65eae93 Merge branch 'Feature/institution-contract/print'
# Conflicts:
#	CompanyManagment.App.Contracts/InstitutionContract/IInstitutionContractApplication.cs
2025-12-20 20:10:30 +03:30
b4526a4338 Merge branch 'Feature/institution-contract/verify-mannually' 2025-12-20 20:09:13 +03:30
2d879ce80a fix: update workshop identification logic in InstitutionContractApplication 2025-12-20 20:06:28 +03:30
56e79d2099 fix: correct ContractAmountWithTax calculation for old contracts 2025-12-20 19:38:32 +03:30
93891f3837 add one month more details for InstitutionContract.cs print 2025-12-20 19:18:27 +03:30
SamSys
5bdfbc572b add next deploy and contractingParty add to workshop on AndroidApk page 2025-12-20 18:42:53 +03:30
4385a65cbc feat: add manual verification endpoint for institution contracts 2025-12-20 18:27:59 +03:30
722f8dae7c feat: implement manual verification for institution contracts and add signing type handling 2025-12-20 18:27:17 +03:30
SamSys
07113353c4 add uploadFrontEnd btn to AndroidApk page 2025-12-20 16:01:07 +03:30
8c6336b9bd fix: correct IsOldContract logic to properly identify old contracts 2025-12-20 14:35:02 +03:30
20e3d454cf feat: add ContractAmountWithTax calculation and update related references 2025-12-20 13:35:52 +03:30
2bf31db6b2 fix: enhance parameter binding logic for route parameters 2025-12-20 12:05:34 +03:30
7a4a6de84f feat: add OneMonthPrice to institution contract details 2025-12-20 10:56:36 +03:30
53 changed files with 13574 additions and 264 deletions

View File

@@ -98,6 +98,11 @@ public class InstitutionContract : EntityBase
// مبلغ قرارداد
public double ContractAmount { get; private set; }
public double ContractAmountWithTax => !IsOldContract ? ContractAmount + ContractAmountTax
: ContractAmount;
public double ContractAmountTax => ContractAmount*0.10;
//خسارت روزانه
public double DailyCompenseation { get; private set; }
@@ -159,6 +164,10 @@ public class InstitutionContract : EntityBase
public List<InstitutionContractAmendment> Amendments { get; private set; }
public InstitutionContractSigningType? SigningType { get; private set; }
public bool IsOldContract => LawId== 0;
public InstitutionContract()
{
ContactInfoList = [];
@@ -262,6 +271,10 @@ public class InstitutionContract : EntityBase
{
WorkshopGroup = null;
}
public void SetSigningType(InstitutionContractSigningType signingType)
{
SigningType = signingType;
}
}
public class InstitutionContractAmendment : EntityBase

View File

@@ -10,13 +10,15 @@ public class InstitutionContractWorkshopCurrent:InstitutionContractWorkshopBase
public InstitutionContractWorkshopCurrent(string workshopName, bool hasRollCallPlan,
bool hasRollCallPlanInPerson, bool hasCustomizeCheckoutPlan, bool hasContractPlan,
bool hasContractPlanInPerson, bool hasInsurancePlan, bool hasInsurancePlanInPerson,
int personnelCount, double price,long institutionContractWorkshopGroupId,InstitutionContractWorkshopGroup workshopGroup,long workshopId) : base(workshopName, hasRollCallPlan,
int personnelCount, double price,long institutionContractWorkshopGroupId,
InstitutionContractWorkshopGroup workshopGroup,long workshopId,long initialWorkshopId) : base(workshopName, hasRollCallPlan,
hasRollCallPlanInPerson, hasCustomizeCheckoutPlan, hasContractPlan,
hasContractPlanInPerson, hasInsurancePlan, hasInsurancePlanInPerson, personnelCount, price)
{
InstitutionContractWorkshopGroupId = institutionContractWorkshopGroupId;
WorkshopGroup = workshopGroup;
WorkshopId = workshopId;
InitialWorkshopId = initialWorkshopId;
}
public long InstitutionContractWorkshopGroupId { get; private set; }
public InstitutionContractWorkshopGroup WorkshopGroup { get; private set; }

View File

@@ -37,4 +37,10 @@ public class InstitutionContractWorkshopGroup : EntityBase
CurrentWorkshops = updatedDetails.ToList();
LastModifiedDate = DateTime.Now;
}
public void AddCurrentWorkshop(InstitutionContractWorkshopCurrent currentWorkshop)
{
CurrentWorkshops.Add(currentWorkshop);
LastModifiedDate = DateTime.Now;
}
}

View File

@@ -31,7 +31,7 @@ public class InstitutionContractWorkshopInitial:InstitutionContractWorkshopBase
WorkshopCreated = true;
WorkshopCurrent = new InstitutionContractWorkshopCurrent(WorkshopName,Services.RollCall,Services.RollCallInPerson,
Services.CustomizeCheckout,Services.Contract,Services.ContractInPerson,Services.Insurance,
Services.InsuranceInPerson,PersonnelCount,Price,InstitutionContractWorkshopGroupId,WorkshopGroup,workshopId);
Services.InsuranceInPerson,PersonnelCount,Price,InstitutionContractWorkshopGroupId,WorkshopGroup,workshopId,id);
WorkshopCurrent.SetEmployers(Employers.Select(x=>x.EmployerId).ToList());
}

View File

@@ -316,7 +316,10 @@ public class Workshop : EntityBase
IsStaticCheckout = isStaticCheckout;
}
public void AddContractingPartyId(long contractingPartyId)
{
ContractingPartyId = contractingPartyId;
}
public void Active(string archiveCode)
{
this.IsActive = true;

View File

@@ -0,0 +1,17 @@
namespace CompanyManagment.App.Contracts.InstitutionContract;
public enum InstitutionContractSigningType
{
/// <summary>
/// قدیمی
/// </summary>
Legacy = 0,
/// <summary>
/// الکترونیکی با کد یکبار مصرف
/// </summary>
OtpBased = 1,
/// <summary>
/// به صورت فیزیکی
/// </summary>
Physical = 2
}

View File

@@ -7,7 +7,6 @@ using System.Threading.Tasks;
using _0_Framework.Application;
using _0_Framework.Application.Sms;
using CompanyManagment.App.Contracts.Checkout;
using CompanyManagment.App.Contracts.Law;
using CompanyManagment.App.Contracts.TemporaryClientRegistration;
using CompanyManagment.App.Contracts.Workshop;
using CompanyManagment.App.Contracts.WorkshopPlan;
@@ -260,154 +259,13 @@ public interface IInstitutionContractApplication
/// <returns></returns>
Task<InstitutionContractPrintViewModel> PrintOneAsync(long id);
Task<OperationResult> SetPendingWorkflow(long entityId);
Task<OperationResult> SetPendingWorkflow(long entityId,InstitutionContractSigningType signingType);
Task<long> GetIdByInstallmentId(long installmentId);
}
public class InstitutionContractDiscountResponse
{
public InstitutionContractDiscountOneTimeViewModel OneTime { get; set; }
public InstitutionContractDiscountMonthlyViewModel Monthly { get; set; }
}
public class InstitutionContractDiscountMonthlyViewModel:InstitutionContractDiscountOneTimeViewModel
{
public List<MonthlyInstallment> Installments { get; set; }
}
public class InstitutionContractDiscountOneTimeViewModel
{
/// <summary>
/// مجموع مبالغ
/// تایید قرارداد مالی به صورت دستی
/// </summary>
public string TotalAmount { get; set; }
/// <summary>
/// ارزش افزوده
/// </summary>
public string Tax { get; set; }
/// <summary>
/// مبلغ قابل پرداخت
/// </summary>
public string PaymentAmount { get; set; }
public string DiscountedAmount { get; set; }
public int DiscountPercetage { get; set; }
public string Obligation { get; set; }
public string OneMonthAmount { get; set; }
}
public class InstitutionContractResetDiscountForCreateRequest
{
public int DiscountPercentage { get; set; }
public double TotalAmount { get; set; }
public bool IsInstallment { get; set; }
public InstitutionContractDuration Duration { get; set; }
public double OneMonthAmount { get; set; }
}
public class InstitutionContractSetDiscountForExtensionRequest
{
public Guid TempId { get; set; }
public int DiscountPercentage { get; set; }
public double TotalAmount { get; set; }
public bool IsInstallment { get; set; }
}
public class InstitutionContractResetDiscountForExtensionRequest
{
public Guid TempId { get; set; }
public bool IsInstallment { get; set; }
}
public class InstitutionContractSetDiscountRequest
{
public int DiscountPercentage { get; set; }
public double TotalAmount { get; set; }
public InstitutionContractDuration Duration { get; set; }
public double OneMonthAmount { get; set; }
public bool IsInstallment { get; set; }
}
public class InstitutionContractPrintViewModel
{
public InstitutionContratVerificationParty FirstParty { get; set; }
public InstitutionContratVerificationParty SecondParty { get; set; }
public string ContractNo { get; set; }
public string CreationDate { get; set; }
public string ContractStart { get; set; }
public string ContractEnd { get; set; }
public List<GetInstitutionVerificationDetailsWorkshopsViewModel> Workshops { get; set; }
public string TotalPrice { get; set; }
public string TaxPrice { get; set; }
public string PaymentPrice { get; set; }
public string VerifyCode { get; set; }
public string VerifyDate { get; set; }
public string VerifyTime { get; set; }
public string VerifierFullName { get; set; }
public string VerifierPhoneNumber { get; set; }
public LawViewModel LawViewModel { get; set; }
public string Obligation { get; set; }
}
public class InsertAmendmentTempWorkshopResponse
{
public Guid WorkshopTempId { get; set; }
public string Amount { get; set; }
}
public class InstitutionContractAmendmentWorkshopsResponse
{
/// <summary>
///
/// </summary>
public List<InstitutionContractAmendmentTempWorkshopViewModel> Workshops { get; set; }
public Guid TempId { get; set; }
/// <param name="institutionContractId"></param>
/// <returns></returns>
Task<OperationResult> VerifyInstitutionContractManually(long institutionContractId);
}
public class InstitutionContractSelectListViewModel : SelectListViewModel;
public class InstitutionContractExtensionInquiryResponse
{
public long Id { get; set; }
public string FName { get; set; }
public string LName { get; set; }
public string DateOfBirthFa { get; set; }
public string FatherName { get; set; }
public string IdNumberSerial { get; set; }
public string IdNumber { get; set; }
public string Address { get; set; }
public string Phone { get; set; }
public string City { get; set; }
public string State { get; set; }
public long RepresentativeId { get; set; }
public string NationalCode { get; set; }
}
public class InstitutionContractExtensionPaymentMonthly:InstitutionContractExtensionPaymentOneTime
{
public List<MonthlyInstallment> Installments { get; set; }
}
public class InstitutionContractExtensionPaymentOneTime
{
/// <summary>
/// مجموع مبالغ
/// </summary>
public string TotalAmount { get; set; }
/// <summary>
/// ارزش افزوده
/// </summary>
public string Tax { get; set; }
/// <summary>
/// مبلغ قابل پرداخت
/// </summary>
public string PaymentAmount { get; set; }
}

View File

@@ -0,0 +1,9 @@
using System;
namespace CompanyManagment.App.Contracts.InstitutionContract;
public class InsertAmendmentTempWorkshopResponse
{
public Guid WorkshopTempId { get; set; }
public string Amount { get; set; }
}

View File

@@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
namespace CompanyManagment.App.Contracts.InstitutionContract;
public class InstitutionContractAmendmentWorkshopsResponse
{
/// <summary>
///
/// </summary>
public List<InstitutionContractAmendmentTempWorkshopViewModel> Workshops { get; set; }
public Guid TempId { get; set; }
}

View File

@@ -0,0 +1,38 @@
using System.Collections.Generic;
using CompanyManagment.App.Contracts.TemporaryClientRegistration;
namespace CompanyManagment.App.Contracts.InstitutionContract;
public class InstitutionContractDiscountResponse
{
public InstitutionContractDiscountOneTimeViewModel OneTime { get; set; }
public InstitutionContractDiscountMonthlyViewModel Monthly { get; set; }
}
public class InstitutionContractDiscountMonthlyViewModel:InstitutionContractDiscountOneTimeViewModel
{
public List<MonthlyInstallment> Installments { get; set; }
}
public class InstitutionContractDiscountOneTimeViewModel
{
/// <summary>
/// مجموع مبالغ
/// </summary>
public string TotalAmount { get; set; }
/// <summary>
/// ارزش افزوده
/// </summary>
public string Tax { get; set; }
/// <summary>
/// مبلغ قابل پرداخت
/// </summary>
public string PaymentAmount { get; set; }
public string DiscountedAmount { get; set; }
public int DiscountPercetage { get; set; }
public string Obligation { get; set; }
public string OneMonthAmount { get; set; }
}

View File

@@ -0,0 +1,18 @@
namespace CompanyManagment.App.Contracts.InstitutionContract;
public class InstitutionContractExtensionInquiryResponse
{
public long Id { get; set; }
public string FName { get; set; }
public string LName { get; set; }
public string DateOfBirthFa { get; set; }
public string FatherName { get; set; }
public string IdNumberSerial { get; set; }
public string IdNumber { get; set; }
public string Address { get; set; }
public string Phone { get; set; }
public string City { get; set; }
public string State { get; set; }
public long RepresentativeId { get; set; }
public string NationalCode { get; set; }
}

View File

@@ -0,0 +1,24 @@
using System.Collections.Generic;
using CompanyManagment.App.Contracts.TemporaryClientRegistration;
namespace CompanyManagment.App.Contracts.InstitutionContract;
public class InstitutionContractExtensionPaymentMonthly:InstitutionContractExtensionPaymentOneTime
{
public List<MonthlyInstallment> Installments { get; set; }
}
public class InstitutionContractExtensionPaymentOneTime
{
/// <summary>
/// مجموع مبالغ
/// </summary>
public string TotalAmount { get; set; }
/// <summary>
/// ارزش افزوده
/// </summary>
public string Tax { get; set; }
/// <summary>
/// مبلغ قابل پرداخت
/// </summary>
public string PaymentAmount { get; set; }
}

View File

@@ -0,0 +1,28 @@
using System.Collections.Generic;
using CompanyManagment.App.Contracts.Law;
namespace CompanyManagment.App.Contracts.InstitutionContract;
public class InstitutionContractPrintViewModel
{
public InstitutionContratVerificationParty FirstParty { get; set; }
public InstitutionContratVerificationParty SecondParty { get; set; }
public string ContractNo { get; set; }
public string CreationDate { get; set; }
public string ContractStart { get; set; }
public string ContractEnd { get; set; }
public List<GetInstitutionVerificationDetailsWorkshopsViewModel> Workshops { get; set; }
public string TotalPrice { get; set; }
public string TaxPrice { get; set; }
public string PaymentPrice { get; set; }
public string OneMonthPrice { get; set; }
public string VerifyCode { get; set; }
public string VerifyDate { get; set; }
public string VerifyTime { get; set; }
public string VerifierFullName { get; set; }
public string VerifierPhoneNumber { get; set; }
public LawViewModel LawViewModel { get; set; }
public string Obligation { get; set; }
public string OneMonthWithoutTax { get; set; }
public string OneMonthTax { get; set; }
}

View File

@@ -0,0 +1,10 @@
namespace CompanyManagment.App.Contracts.InstitutionContract;
public class InstitutionContractResetDiscountForCreateRequest
{
public int DiscountPercentage { get; set; }
public double TotalAmount { get; set; }
public bool IsInstallment { get; set; }
public InstitutionContractDuration Duration { get; set; }
public double OneMonthAmount { get; set; }
}

View File

@@ -0,0 +1,9 @@
using System;
namespace CompanyManagment.App.Contracts.InstitutionContract;
public class InstitutionContractResetDiscountForExtensionRequest
{
public Guid TempId { get; set; }
public bool IsInstallment { get; set; }
}

View File

@@ -0,0 +1,5 @@
using _0_Framework.Application;
namespace CompanyManagment.App.Contracts.InstitutionContract;
public class InstitutionContractSelectListViewModel : SelectListViewModel;

View File

@@ -0,0 +1,11 @@
using System;
namespace CompanyManagment.App.Contracts.InstitutionContract;
public class InstitutionContractSetDiscountForExtensionRequest
{
public Guid TempId { get; set; }
public int DiscountPercentage { get; set; }
public double TotalAmount { get; set; }
public bool IsInstallment { get; set; }
}

View File

@@ -0,0 +1,10 @@
namespace CompanyManagment.App.Contracts.InstitutionContract;
public class InstitutionContractSetDiscountRequest
{
public int DiscountPercentage { get; set; }
public double TotalAmount { get; set; }
public InstitutionContractDuration Duration { get; set; }
public double OneMonthAmount { get; set; }
public bool IsInstallment { get; set; }
}

View File

@@ -1537,7 +1537,7 @@ public class InstitutionContractApplication : IInstitutionContractApplication
return (await _institutionContractRepository.PrintAllAsync([id])).FirstOrDefault();
}
public async Task<OperationResult> SetPendingWorkflow(long entityId)
public async Task<OperationResult> SetPendingWorkflow(long entityId,InstitutionContractSigningType signingType)
{
var op = new OperationResult();
var institutionContract = await _institutionContractRepository.GetIncludeWorkshopDetailsAsync(entityId);
@@ -1551,6 +1551,30 @@ public class InstitutionContractApplication : IInstitutionContractApplication
return op.Failed("وضعیت قرارداد مالی برای این عملیات مناسب نمی باشد");
}
var initialCreatedWorkshops = institutionContract.WorkshopGroup.InitialWorkshops
.Where(x => x.WorkshopCreated && x.WorkshopId is > 0).ToList();
var currentWorkshops = institutionContract.WorkshopGroup.CurrentWorkshops.ToList();
foreach (var createdWorkshop in initialCreatedWorkshops)
{
if (currentWorkshops.Any(x => x.WorkshopId == createdWorkshop.WorkshopId))
{
continue;
}
var currentWorkshop = new InstitutionContractWorkshopCurrent(createdWorkshop.WorkshopName,
createdWorkshop.Services.RollCall, createdWorkshop.Services.RollCallInPerson,
createdWorkshop.Services.CustomizeCheckout, createdWorkshop.Services.Contract,
createdWorkshop.Services.ContractInPerson, createdWorkshop.Services.Insurance,
createdWorkshop.Services.InsuranceInPerson,createdWorkshop.PersonnelCount, createdWorkshop.Price,
createdWorkshop.InstitutionContractWorkshopGroupId,createdWorkshop.WorkshopGroup,
createdWorkshop.WorkshopId!.Value, createdWorkshop.id);
institutionContract.WorkshopGroup.AddCurrentWorkshop(currentWorkshop);
}
if (institutionContract.WorkshopGroup.InitialWorkshops.All(x => x.WorkshopCreated && x.WorkshopId is > 0))
{
institutionContract.Verified();
@@ -1560,6 +1584,8 @@ public class InstitutionContractApplication : IInstitutionContractApplication
institutionContract.SetPendingWorkflow();
}
institutionContract.SetSigningType(signingType);
await _institutionContractRepository.SaveChangesAsync();
return op.Succcedded();
}
@@ -1569,6 +1595,28 @@ public class InstitutionContractApplication : IInstitutionContractApplication
return await _institutionContractRepository.GetIdByInstallmentId(installmentId);
}
public async Task<OperationResult> VerifyInstitutionContractManually(long institutionContractId)
{
var op = new OperationResult();
var institutionContract =await _institutionContractRepository
.GetIncludeWorkshopDetailsAsync(institutionContractId);
if (institutionContract == null)
return op.Failed("قرارداد مالی یافت نشد");
if (institutionContract.VerificationStatus == InstitutionContractVerificationStatus.Verified)
return op.Failed("قرارداد مالی قبلا تایید شده است");
var transaction = await _institutionContractRepository.BeginTransactionAsync();
await SetPendingWorkflow(institutionContractId,InstitutionContractSigningType.Physical);
await transaction.CommitAsync();
await _institutionContractRepository.SaveChangesAsync();
return op.Succcedded();
}
private async Task<OperationResult<PersonalContractingParty>> CreateLegalContractingPartyEntity(
CreateInstitutionContractLegalPartyRequest request, long representativeId, string address, string city,
string state)

View File

@@ -35,6 +35,10 @@ public class InstitutionContractMapping : IEntityTypeConfiguration<InstitutionCo
builder.Property(x => x.VerificationStatus).HasConversion<string>().HasMaxLength(122);
builder.Property(x=>x.SigningType).HasConversion<string>()
.HasMaxLength(25)
.IsRequired(false);
builder.HasMany(x => x.Installments)
.WithOne(x => x.InstitutionContract)
.HasForeignKey(x => x.InstitutionContractId);
@@ -45,5 +49,10 @@ public class InstitutionContractMapping : IEntityTypeConfiguration<InstitutionCo
builder.HasMany(x => x.Amendments).WithOne(x => x.InstitutionContract)
.HasForeignKey(x => x.InstitutionContractId);
builder.Ignore(x => x.ContractAmountWithTax);
builder.Ignore(x => x.ContractAmountTax);
builder.Ignore(x => x.ContractAmountTax);
}
}

View File

@@ -0,0 +1,29 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace CompanyManagment.EFCore.Migrations
{
/// <inheritdoc />
public partial class addsigningTypeforinstitutioncontract : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "SigningType",
table: "InstitutionContracts",
type: "nvarchar(25)",
maxLength: 25,
nullable: true);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "SigningType",
table: "InstitutionContracts");
}
}
}

View File

@@ -3462,6 +3462,10 @@ namespace CompanyManagment.EFCore.Migrations
.HasMaxLength(1)
.HasColumnType("nvarchar(1)");
b.Property<string>("SigningType")
.HasMaxLength(25)
.HasColumnType("nvarchar(25)");
b.Property<string>("State")
.HasMaxLength(20)
.HasColumnType("nvarchar(20)");

View File

@@ -4,9 +4,7 @@ using _0_Framework.Application.Sms;
using _0_Framework.Exceptions;
using _0_Framework.InfraStructure;
using Company.Domain.ContarctingPartyAgg;
using Company.Domain.ContractingPartyAccountAgg;
using Company.Domain.empolyerAgg;
using Company.Domain.FinancialInvoiceAgg;
using Company.Domain.FinancialStatmentAgg;
using Company.Domain.FinancialTransactionAgg;
using Company.Domain.InstitutionContractAgg;
@@ -17,7 +15,6 @@ using Company.Domain.InstitutionPlanAgg;
using Company.Domain.SmsResultAgg;
using Company.Domain.WorkshopAgg;
using CompanyManagment.App.Contracts.Employer;
using CompanyManagment.App.Contracts.FinancialInvoice;
using CompanyManagment.App.Contracts.FinancialStatment;
using CompanyManagment.App.Contracts.FinancilTransaction;
using CompanyManagment.App.Contracts.Hubs;
@@ -26,30 +23,17 @@ using CompanyManagment.App.Contracts.InstitutionContractContactinfo;
using CompanyManagment.App.Contracts.Law;
using CompanyManagment.App.Contracts.TemporaryClientRegistration;
using CompanyManagment.App.Contracts.Workshop;
using CompanyManagment.App.Contracts.WorkshopPlan;
using CompanyManagment.EFCore.Migrations;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SignalR;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using MongoDB.Driver;
using OfficeOpenXml.Packaging.Ionic.Zip;
using PersianTools.Core;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Diagnostics.Metrics;
using System.Drawing;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using static Microsoft.EntityFrameworkCore.DbLoggerCategory.Database;
using static System.Runtime.InteropServices.JavaScript.JSType;
using ContractingPartyAccount = Company.Domain.ContractingPartyAccountAgg.ContractingPartyAccount;
using FinancialStatment = Company.Domain.FinancialStatmentAgg.FinancialStatment;
using String = System.String;
@@ -1375,7 +1359,7 @@ public class InstitutionContractRepository : RepositoryBase<long, InstitutionCon
.Count(l => l.StartWorkDate <= DateTime.Now && l.LeftWorkDate >= DateTime.Now);
return new GetInstitutionContractListItemsViewModel()
{
ContractAmount = x.contract.ContractAmount,
ContractAmount = x.contract.ContractAmountWithTax,
Balance = statement?.FinancialTransactionList.Sum(ft => ft.Deptor - ft.Creditor) ?? 0,
WorkshopsCount = workshops.Count(),
ContractStartFa = x.contract.ContractStartGr.ToFarsi(),
@@ -1395,9 +1379,7 @@ public class InstitutionContractRepository : RepositoryBase<long, InstitutionCon
Workshops = workshopDetails,
IsInPersonContract = x.contract.WorkshopGroup?.CurrentWorkshops
.Any(y => y.Services.ContractInPerson) ?? true,
IsOldContract = x.contract.WorkshopGroup?.CurrentWorkshops == null
|| x.contract.WorkshopGroup.CurrentWorkshops.Count == 0
|| x.contract.WorkshopGroup.CurrentWorkshops.Any(y => y.Price == 0)
IsOldContract = x.contract.SigningType == InstitutionContractSigningType.Legacy
};
}).ToList()
};
@@ -3216,6 +3198,9 @@ public class InstitutionContractRepository : RepositoryBase<long, InstitutionCon
PaymentPrice = institution.TotalAmount.ToMoney(),
TotalPrice = (institution.TotalAmount - institution.ValueAddedTax).ToMoney(),
TaxPrice = institution.ValueAddedTax.ToMoney(),
OneMonthPrice = institution.ContractAmountWithTax.ToMoney(),
OneMonthWithoutTax = institution.ContractAmount.ToMoney(),
OneMonthTax = institution.ContractAmountTax.ToMoney(),
VerifierFullName = institution.VerifierFullName,
VerifierPhoneNumber = institution.VerifierPhoneNumber,
VerifyCode = institution.VerifyCode,
@@ -4774,6 +4759,7 @@ public class InstitutionContractRepository : RepositoryBase<long, InstitutionCon
.Select(x => x.id).FirstOrDefaultAsync();
}
#endregion

View File

@@ -0,0 +1,49 @@
using GozareshgirProgramManager.Application._Common.Interfaces;
using GozareshgirProgramManager.Application._Common.Models;
using GozareshgirProgramManager.Domain._Common;
using GozareshgirProgramManager.Domain.ProjectAgg.Enums;
using GozareshgirProgramManager.Domain.ProjectAgg.Repositories;
using Microsoft.EntityFrameworkCore;
namespace GozareshgirProgramManager.Application.Modules.Projects.Commands.AutoStopOverTimeTaskSections;
public record AutoStopOverTimeTaskSectionsCommand : IBaseCommand;
public class AutoStopOverTimeTaskSectionsCommandHandler : IBaseCommandHandler<AutoStopOverTimeTaskSectionsCommand>
{
private readonly ITaskSectionRepository _taskSectionRepository;
private readonly IUnitOfWork _unitOfWork;
public AutoStopOverTimeTaskSectionsCommandHandler(ITaskSectionRepository taskSectionRepository,
IUnitOfWork unitOfWork)
{
_taskSectionRepository = taskSectionRepository;
_unitOfWork = unitOfWork;
}
public async Task<OperationResult> Handle(AutoStopOverTimeTaskSectionsCommand request,
CancellationToken cancellationToken)
{
try
{
// دریافت تمام تسک‌های در حال انجام
var taskSections = await _taskSectionRepository.GetActiveSectionsIncludeAllAsync(cancellationToken);
foreach (var taskSection in taskSections)
{
// استفاده از متد Domain برای بررسی و متوقف کردن خودکار
taskSection.AutoStopIfOverTime();
}
// ذخیره تغییرات در دیتابیس
await _unitOfWork.SaveChangesAsync(cancellationToken);
return OperationResult.Success();
}
catch (Exception ex)
{
return OperationResult.Failure($"خطا در ناتمام کردن تسک‌های overtime: {ex.Message}");
}
}
}

View File

@@ -0,0 +1,52 @@
using System.Linq;
using GozareshgirProgramManager.Application._Common.Interfaces;
using GozareshgirProgramManager.Application._Common.Models;
using GozareshgirProgramManager.Domain.ProjectAgg.Entities;
using GozareshgirProgramManager.Domain.ProjectAgg.Enums;
using Microsoft.EntityFrameworkCore;
namespace GozareshgirProgramManager.Application.Modules.Projects.Commands.AutoUpdateDeployStatus;
public record AutoUpdateDeployStatusCommand : IBaseCommand;
public class AutoUpdateDeployStatusCommandHandler : IBaseCommandHandler<AutoUpdateDeployStatusCommand>
{
private readonly IProgramManagerDbContext _dbContext;
public AutoUpdateDeployStatusCommandHandler(IProgramManagerDbContext dbContext)
{
_dbContext = dbContext;
}
public async Task<OperationResult> Handle(AutoUpdateDeployStatusCommand request,
CancellationToken cancellationToken)
{
// Fetch all sections whose phase is still marked as not completed
var sections = await _dbContext.TaskSections
.Include(ts => ts.Task)
.ThenInclude(t => t.Phase)
.Where(ts => ts.Task.Phase.DeployStatus == ProjectDeployStatus.NotCompleted)
.ToListAsync(cancellationToken);
if (sections.Count == 0)
return OperationResult.Success();
var phasesToUpdate = sections
.GroupBy(ts => ts.Task.PhaseId)
.Where(g => g.All(s => s.Status == TaskSectionStatus.Completed))
.Select(g => g.First().Task.Phase)
.Distinct()
.ToList();
if (phasesToUpdate.Count == 0)
return OperationResult.Success();
foreach (var phase in phasesToUpdate)
{
phase.UpdateDeployStatus(ProjectDeployStatus.PendingDevDeploy);
}
await _dbContext.SaveChangesAsync(cancellationToken);
return OperationResult.Success();
}
}

View File

@@ -0,0 +1,44 @@
using GozareshgirProgramManager.Application._Common.Interfaces;
using GozareshgirProgramManager.Application._Common.Models;
using GozareshgirProgramManager.Domain._Common;
using GozareshgirProgramManager.Domain.ProjectAgg.Entities;
using GozareshgirProgramManager.Domain.ProjectAgg.Repositories;
namespace GozareshgirProgramManager.Application.Modules.Projects.Commands.ChangeDeployStatusProject;
public record ChangeDeployStatusProjectCommand(Guid PhaseId, ProjectDeployStatus Status):IBaseCommand;
public class ChangeDeployStatusProjectCommandHandler : IBaseCommandHandler<ChangeDeployStatusProjectCommand>
{
private readonly IProjectRepository _projectRepository;
private readonly IProjectPhaseRepository _projectPhaseRepository;
private readonly IUnitOfWork _unitOfWork;
public ChangeDeployStatusProjectCommandHandler(IProjectRepository projectRepository, IUnitOfWork unitOfWork, IProjectPhaseRepository projectPhaseRepository)
{
_projectRepository = projectRepository;
_unitOfWork = unitOfWork;
_projectPhaseRepository = projectPhaseRepository;
}
public async Task<OperationResult> Handle(ChangeDeployStatusProjectCommand request, CancellationToken cancellationToken)
{
var project = await _projectPhaseRepository.GetByIdAsync(request.PhaseId, cancellationToken);
if (project == null)
return OperationResult.NotFound("بخش مورد نظر یافت نشد");
if (project.DeployStatus == ProjectDeployStatus.NotCompleted)
{
return OperationResult.Failure("وضعیت استقرار نمی‌تواند از حالت 'تایید نشده' تغییر کند.");
}
if (request.Status == ProjectDeployStatus.NotCompleted)
{
return OperationResult.Failure("وضعیت استقرار نمی‌تواند به حالت 'تایید نشده' تغییر کند.");
}
project.UpdateDeployStatus(request.Status);
await _unitOfWork.SaveChangesAsync(cancellationToken);
return OperationResult.Success();
}
}

View File

@@ -1,3 +1,4 @@
using System.Globalization;
using GozareshgirProgramManager.Application._Common.Interfaces;
using GozareshgirProgramManager.Application._Common.Models;
using GozareshgirProgramManager.Domain._Common;
@@ -7,21 +8,23 @@ namespace GozareshgirProgramManager.Application.Modules.Projects.Queries.Project
public record ProjectBoardDetailQuery(Guid SectionId) : IBaseQuery<ProjectBoardDetailResponse>;
public record ProjectBoardDetailResponse(List<ProjectBoardDetailUserResponse> Users, string TotalTime);
public record ProjectBoardDetailResponse(List<ProjectBoardDetailUserResponse> Users, string TotalTime,string RemainingTime );
public record ProjectBoardDetailUserResponse
{
public List<ProjectBoardDetailUserHistoryResponse> Histories { get; set; } = new();
public string UserFullName { get; set; }
public long UserId { get; set; }
public List<ProjectBoardDetailUserHistoryResponse> Histories { get; init; }
public string UserFullName { get; init; }
public string TotalTime { get; init; }
public string SpentTime { get; init; }
public long UserId { get; init; }
}
public class ProjectBoardDetailUserHistoryResponse
public record ProjectBoardDetailUserHistoryResponse
{
public string Date { get; set; }
public string startTime { get; set; }
public string EndTime { get; set; }
public string TotalTime { get; set; }
public string Date { get; init; }
public string startTime { get; init; }
public string EndTime { get; init; }
public string TotalTime { get; init; }
}
public class ProjectBoardDetailQueryHandler : IBaseQueryHandler<ProjectBoardDetailQuery, ProjectBoardDetailResponse>
@@ -38,6 +41,7 @@ public class ProjectBoardDetailQueryHandler : IBaseQueryHandler<ProjectBoardDeta
{
var section = await _programManagerDbContext.TaskSections
.Include(x => x.Activities)
.Include(x=>x.AdditionalTimes)
.FirstOrDefaultAsync(x => x.Id == request.SectionId, cancellationToken: cancellationToken);
if (section == null)
@@ -49,16 +53,22 @@ public class ProjectBoardDetailQueryHandler : IBaseQueryHandler<ProjectBoardDeta
.Where(x => userIds.Contains(x.Id))
.ToDictionaryAsync(x => x.Id, x => x.FullName, cancellationToken);
var totalTimeSpan = section.Activities
var totalActivityTimeSpan = section.Activities
.Select(x => x.GetTimeSpent())
.Aggregate(TimeSpan.Zero, (sum, next) => sum.Add(next));
var finalTime = section.FinalEstimatedHours;
var remainingTimeSpan = finalTime >= totalActivityTimeSpan
? TimeSpan.FromTicks(finalTime.Ticks - totalActivityTimeSpan.Ticks)
: TimeSpan.Zero;
var users = section.Activities.GroupBy(x => x.UserId).Select(x =>
{
return new ProjectBoardDetailUserResponse()
{
UserId = x.Key,
UserFullName = usersDict[x.Key],
TotalTime = TimeSpan.FromTicks(x.Sum(h=>h.GetTimeSpent().Ticks)).TotalHours.ToString(CultureInfo.InvariantCulture),
Histories = x.Select(h => new ProjectBoardDetailUserHistoryResponse()
{
Date = h.StartDate.ToFarsi(),
@@ -68,7 +78,8 @@ public class ProjectBoardDetailQueryHandler : IBaseQueryHandler<ProjectBoardDeta
}).ToList()
};
}).ToList();
var response = new ProjectBoardDetailResponse(users, $"{(int)totalTimeSpan.TotalHours}:{totalTimeSpan.Minutes:D2}");
var response = new ProjectBoardDetailResponse(users, $"{(int)totalActivityTimeSpan.TotalHours}:{totalActivityTimeSpan.Minutes:D2}",
$"{(int)remainingTimeSpan.TotalHours}:{remainingTimeSpan.Minutes:D2}");
return OperationResult<ProjectBoardDetailResponse>.Success(response);
}
}

View File

@@ -22,8 +22,9 @@ public class ProjectBoardListQueryHandler : IBaseQueryHandler<ProjectBoardListQu
CancellationToken cancellationToken)
{
var currentUserId = _authHelper.GetCurrentUserId();
var queryable = _programManagerDbContext.TaskSections.AsNoTracking()
.Where(x => x.InitialEstimatedHours > TimeSpan.Zero)
.Where(x => x.InitialEstimatedHours > TimeSpan.Zero && x.Status != TaskSectionStatus.Completed)
.Include(x => x.Task)
.ThenInclude(x => x.Phase)
.ThenInclude(x => x.Project)

View File

@@ -0,0 +1,113 @@
using System.Security.AccessControl;
using GozareshgirProgramManager.Application._Common.Interfaces;
using GozareshgirProgramManager.Application._Common.Models;
using Microsoft.EntityFrameworkCore;
namespace GozareshgirProgramManager.Application.Modules.Projects.Queries.ProjectDeployBoardDetail;
public record ProjectDeployBoardDetailsResponse(
ProjectDeployBoardDetailPhaseItem Phase,
List<ProjectDeployBoardDetailTaskItem> Tasks);
public record ProjectDeployBoardDetailPhaseItem(
string Name,
TimeSpan TotalTimeSpan,
TimeSpan DoneTimeSpan);
public record ProjectDeployBoardDetailTaskItem(
string Name,
TimeSpan TotalTimeSpan,
TimeSpan DoneTimeSpan,
List<ProjectDeployBoardDetailItemSkill> Skills)
: ProjectDeployBoardDetailPhaseItem(Name, TotalTimeSpan, DoneTimeSpan);
public record ProjectDeployBoardDetailItemSkill(string OriginalUserFullName, string SkillName, int TimePercentage);
public record ProjectDeployBoardDetailsQuery(Guid PhaseId) : IBaseQuery<ProjectDeployBoardDetailsResponse>;
public class
ProjectDeployBoardDetailsQueryHandler : IBaseQueryHandler<ProjectDeployBoardDetailsQuery,
ProjectDeployBoardDetailsResponse>
{
private readonly IProgramManagerDbContext _dbContext;
public ProjectDeployBoardDetailsQueryHandler(IProgramManagerDbContext dbContext)
{
_dbContext = dbContext;
}
public async Task<OperationResult<ProjectDeployBoardDetailsResponse>> Handle(ProjectDeployBoardDetailsQuery request,
CancellationToken cancellationToken)
{
var phase = await _dbContext.ProjectPhases
.Include(x => x.Tasks)
.ThenInclude(x => x.Sections)
.ThenInclude(x => x.Activities)
.Include(x => x.Tasks)
.ThenInclude(x => x.Sections)
.ThenInclude(x => x.AdditionalTimes)
.Include(x => x.Tasks)
.ThenInclude(x => x.Sections)
.ThenInclude(x => x.Skill)
.FirstOrDefaultAsync(x => x.Id == request.PhaseId, cancellationToken);
if (phase == null)
return OperationResult<ProjectDeployBoardDetailsResponse>.NotFound("بخش اصلی مورد نظر یافت نشد");
var userIds = phase.Tasks
.SelectMany(t => t.Sections)
.Select(s => s.OriginalAssignedUserId)
.Distinct()
.ToList();
var usersDict = await _dbContext.Users
.Where(x => userIds.Contains(x.Id))
.ToDictionaryAsync(x => x.Id, x => x.FullName, cancellationToken);
var tasksRes = phase.Tasks.Select(t =>
{
var totalTime = t.Sections.Select(s => s.FinalEstimatedHours)
.Aggregate(TimeSpan.Zero, (sum, next) => sum.Add(next));
var doneTime = t.Sections.Aggregate(TimeSpan.Zero,
(sum, next) => sum.Add(next.GetTotalTimeSpent()));
var skills = t.Sections
.Select(s =>
{
var originalUserFullName = usersDict.GetValueOrDefault(s.OriginalAssignedUserId,
"کاربر ناشناس");
var skillName = s.Skill?.Name ?? "بدون مهارت";
var totalTimeSpent = s.GetTotalTimeSpent();
var timePercentage = s.FinalEstimatedHours.Ticks > 0
? (int)((totalTimeSpent.Ticks / (double)s.FinalEstimatedHours.Ticks) * 100)
: 0;
return new ProjectDeployBoardDetailItemSkill(
originalUserFullName,
skillName,
timePercentage);
}).ToList();
return new ProjectDeployBoardDetailTaskItem(
t.Name,
totalTime,
doneTime,
skills);
}).ToList();
var totalTimeSpan = tasksRes.Aggregate(TimeSpan.Zero,
(sum, next) => sum.Add(next.TotalTimeSpan));
var doneTimeSpan = tasksRes.Aggregate(TimeSpan.Zero,
(sum, next) => sum.Add(next.DoneTimeSpan));
var phaseRes = new ProjectDeployBoardDetailPhaseItem(phase.Name, totalTimeSpan, doneTimeSpan);
var res = new ProjectDeployBoardDetailsResponse(phaseRes, tasksRes);
return OperationResult<ProjectDeployBoardDetailsResponse>.Success(res);
}
}

View File

@@ -0,0 +1,11 @@
using FluentValidation;
namespace GozareshgirProgramManager.Application.Modules.Projects.Queries.ProjectDeployBoardDetail;
public class ProjectDeployBoardDetailsQueryValidator:AbstractValidator<ProjectDeployBoardDetailsQuery>
{
public ProjectDeployBoardDetailsQueryValidator()
{
RuleFor(x=>x.PhaseId).NotNull().WithMessage("شناسه بخش اصلی نمی‌تواند خالی باشد");
}
}

View File

@@ -0,0 +1,74 @@
using System.Xml.Schema;
using GozareshgirProgramManager.Application._Common.Interfaces;
using GozareshgirProgramManager.Application._Common.Models;
using GozareshgirProgramManager.Application.Modules.Projects.Queries.GetProjectsList;
using GozareshgirProgramManager.Domain.ProjectAgg.Entities;
using GozareshgirProgramManager.Domain.ProjectAgg.Enums;
using Microsoft.EntityFrameworkCore;
namespace GozareshgirProgramManager.Application.Modules.Projects.Queries.ProjectDeployBoardList;
public record ProjectDeployBoardListItem()
{
public Guid Id { get; set; }
public string ProjectName { get; set; }
public string PhaseName { get; set; }
public int TotalTasks { get; set; }
public int DoneTasks { get; set; }
public TimeSpan TotalTimeSpan { get; set; }
public TimeSpan DoneTimeSpan { get; set; }
public ProjectDeployStatus DeployStatus { get; set; }
}
public record GetProjectsDeployBoardListResponse(List<ProjectDeployBoardListItem> Items);
public record GetProjectDeployBoardListQuery():IBaseQuery<GetProjectsDeployBoardListResponse>;
public class ProjectDeployBoardListQueryHandler:IBaseQueryHandler<GetProjectDeployBoardListQuery, GetProjectsDeployBoardListResponse>
{
private readonly IProgramManagerDbContext _dbContext;
private readonly IAuthHelper _authHelper;
public ProjectDeployBoardListQueryHandler(IProgramManagerDbContext dbContext, IAuthHelper authHelper)
{
_dbContext = dbContext;
_authHelper = authHelper;
}
public async Task<OperationResult<GetProjectsDeployBoardListResponse>> Handle(GetProjectDeployBoardListQuery request, CancellationToken cancellationToken)
{
var userId = _authHelper.GetCurrentUserId();
if (userId == null)
{
return OperationResult<GetProjectsDeployBoardListResponse>.NotFound("کاربر یافت نشد");
}
var query =await _dbContext.TaskSections
.Include(x=>x.Activities)
.Include(x=>x.Task)
.ThenInclude(x => x.Phase)
.ThenInclude(x => x.Project)
.AsNoTracking()
.Where(x => x.Status == TaskSectionStatus.Completed
|| x.Status == TaskSectionStatus.PendingForCompletion
|| (x.Task.Phase.DeployStatus != ProjectDeployStatus.NotCompleted
&& x.InitialEstimatedHours>TimeSpan.Zero))
.GroupBy(x=>x.Task.PhaseId).ToListAsync(cancellationToken: cancellationToken);
var list = query.Select(g => new ProjectDeployBoardListItem
{
Id = g.Key,
ProjectName = g.First().Task.Phase.Project.Name,
PhaseName = g.First().Task.Phase.Name,
TotalTasks = g.Select(x => x.TaskId).Distinct().Count(),
DoneTasks = g.Where(x => x.Status == TaskSectionStatus.Completed)
.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
}).ToList();
var response = new GetProjectsDeployBoardListResponse(list);
return OperationResult<GetProjectsDeployBoardListResponse>.Success(response);
}
}

View File

@@ -23,6 +23,7 @@ public class ProjectPhase : ProjectHierarchyNode
ProjectId = projectId;
_tasks = new List<ProjectTask>();
_phaseSections = new List<PhaseSection>();
DeployStatus = ProjectDeployStatus.NotCompleted;
AddDomainEvent(new PhaseCreatedEvent(Id, projectId, name));
}
@@ -36,6 +37,8 @@ public class ProjectPhase : ProjectHierarchyNode
public DateTime? StartDate { get; private set; }
public DateTime? EndDate { get; private set; }
public int OrderIndex { get; private set; }
public bool IsArchived { get; set; }
public ProjectDeployStatus DeployStatus { get; set; }
#region Task Management
@@ -196,4 +199,30 @@ public class ProjectPhase : ProjectHierarchyNode
}
#endregion
public void SetArchived()
{
IsArchived = true;
}
public void SetUnarchived()
{
IsArchived = false;
}
public void UpdateDeployStatus(ProjectDeployStatus status)
{
DeployStatus = status;
if (status == ProjectDeployStatus.Deployed)
{
IsArchived = true;
}
}
}
public enum ProjectDeployStatus
{
NotCompleted,
PendingDevDeploy,
DevDeployed,
PendingDeploy,
Deployed
}

View File

@@ -217,4 +217,39 @@ public class TaskSection : EntityBase<Guid>
var finalEstimate = FinalEstimatedHours;
return totalSpent < finalEstimate;
}
/// <summary>
/// اگر زمان کار شده بیش از تایم تعیین شده باشد، تسک را متوقف می‌کند
/// و EndDate را به طوری تنظیم می‌کند که کل زمان برابر با FinalEstimatedHours شود
/// </summary>
public void AutoStopIfOverTime()
{
if (Status != TaskSectionStatus.InProgress)
return;
var activeActivity = _activities.FirstOrDefault(a => a.IsActive);
if (activeActivity == null)
return;
// محاسبه کل زمان صرف شده تا کنون (بدون فعالیت فعال)
var totalTimeSpentExcludingActive = _activities.Where(a => !a.IsActive).Sum(a => a.GetTimeSpent().Ticks);
var totalTimeSpentTimeSpan = TimeSpan.FromTicks(totalTimeSpentExcludingActive);
var finalEstimate = FinalEstimatedHours;
// اگر زمان صرف شده (بدون فعالیت فعال) + فعالیت فعال > تایم تعیین شده
var activeTimeSpent = activeActivity.GetTimeSpent();
if (totalTimeSpentTimeSpan + activeTimeSpent > finalEstimate)
{
// محاسبه مدت زمانی که این فعالیت باید برای رسیدن به FinalEstimatedHours داشته باشد
var remainingTime = finalEstimate - totalTimeSpentTimeSpan;
// EndDate = StartDate + remainingTime
var adjustedEndDate = activeActivity.StartDate.Add(remainingTime);
// متوقف کردن فعالیت با EndDate دقیق شده
activeActivity.StopWorkWithSpecificTime(adjustedEndDate, "متوقف خودکار - بیش از تایم تعیین شده");
UpdateStatus(TaskSectionStatus.Incomplete);
}
}
}

View File

@@ -40,6 +40,22 @@ public class TaskSectionActivity : EntityBase<Guid>
IsActive = false;
}
/// <summary>
/// متوقف کردن فعالیت با مشخص کردن EndDate دقیق
/// </summary>
public void StopWorkWithSpecificTime(DateTime endDate, string? endNotes = null)
{
if (!IsActive)
throw new InvalidOperationException("این فعالیت قبلاً متوقف شده است.");
if (endDate < StartDate)
throw new InvalidOperationException("تاریخ پایان نمی‌تواند قبل از تاریخ شروع باشد.");
EndDate = endDate;
EndNotes = endNotes;
IsActive = false;
}
public TimeSpan GetTimeSpent()
{
if (IsActive)

View File

@@ -6,5 +6,6 @@ public enum TaskSectionStatus
ReadyToStart = 1, // آماده شروع
InProgress = 2, // درحال انجام
Incomplete = 3, // ناتمام شده
Completed = 4 // تکمیل شده
PendingForCompletion = 4, // در انتظار تکمیل
Completed = 5 // تکمیل شده
}

View File

@@ -8,171 +8,171 @@ namespace GozareshgirProgramManager.Domain.ProjectAgg.Events;
// Project Events
public record ProjectCreatedEvent(Guid ProjectId, string Name) : IDomainEvent
{
public DateTime OccurredOn { get; init; } = DateTime.UtcNow;
public DateTime OccurredOn { get; init; } = DateTime.Now;
}
public record ProjectStatusUpdatedEvent(Guid ProjectId, ProjectStatus Status) : IDomainEvent
{
public DateTime OccurredOn { get; init; } = DateTime.UtcNow;
public DateTime OccurredOn { get; init; } = DateTime.Now;
}
public record ProjectAssignedEvent(Guid ProjectId, long UserId) : IDomainEvent
{
public DateTime OccurredOn { get; init; } = DateTime.UtcNow;
public DateTime OccurredOn { get; init; } = DateTime.Now;
}
public record ProjectUnassignedEvent(Guid ProjectId) : IDomainEvent
{
public DateTime OccurredOn { get; init; } = DateTime.UtcNow;
public DateTime OccurredOn { get; init; } = DateTime.Now;
}
// Phase Events
public record PhaseCreatedEvent(Guid PhaseId, Guid ProjectId, string Name) : IDomainEvent
{
public DateTime OccurredOn { get; init; } = DateTime.UtcNow;
public DateTime OccurredOn { get; init; } = DateTime.Now;
}
public record PhaseAddedEvent(Guid PhaseId, Guid ProjectId, string Name) : IDomainEvent
{
public DateTime OccurredOn { get; init; } = DateTime.UtcNow;
public DateTime OccurredOn { get; init; } = DateTime.Now;
}
public record PhaseRemovedEvent(Guid PhaseId, Guid ProjectId) : IDomainEvent
{
public DateTime OccurredOn { get; init; } = DateTime.UtcNow;
public DateTime OccurredOn { get; init; } = DateTime.Now;
}
public record PhaseStatusUpdatedEvent(Guid PhaseId, PhaseStatus Status) : IDomainEvent
{
public DateTime OccurredOn { get; init; } = DateTime.UtcNow;
public DateTime OccurredOn { get; init; } = DateTime.Now;
}
public record PhaseAssignedEvent(Guid PhaseId, long UserId) : IDomainEvent
{
public DateTime OccurredOn { get; init; } = DateTime.UtcNow;
public DateTime OccurredOn { get; init; } = DateTime.Now;
}
public record PhaseUnassignedEvent(Guid PhaseId) : IDomainEvent
{
public DateTime OccurredOn { get; init; } = DateTime.UtcNow;
public DateTime OccurredOn { get; init; } = DateTime.Now;
}
// Task Events
public record TaskCreatedEvent(Guid TaskId, Guid PhaseId, string Name) : IDomainEvent
{
public DateTime OccurredOn { get; init; } = DateTime.UtcNow;
public DateTime OccurredOn { get; init; } = DateTime.Now;
}
public record TaskAddedEvent(Guid TaskId, Guid PhaseId, string Name) : IDomainEvent
{
public DateTime OccurredOn { get; init; } = DateTime.UtcNow;
public DateTime OccurredOn { get; init; } = DateTime.Now;
}
public record TaskRemovedEvent(Guid TaskId, Guid PhaseId) : IDomainEvent
{
public DateTime OccurredOn { get; init; } = DateTime.UtcNow;
public DateTime OccurredOn { get; init; } = DateTime.Now;
}
public record TaskStatusUpdatedEvent(Guid TaskId, TaskStatus Status) : IDomainEvent
{
public DateTime OccurredOn { get; init; } = DateTime.UtcNow;
public DateTime OccurredOn { get; init; } = DateTime.Now;
}
public record TaskPriorityUpdatedEvent(Guid TaskId, TaskPriority Priority) : IDomainEvent
{
public DateTime OccurredOn { get; init; } = DateTime.UtcNow;
public DateTime OccurredOn { get; init; } = DateTime.Now;
}
public record TaskAssignedEvent(Guid TaskId, long UserId) : IDomainEvent
{
public DateTime OccurredOn { get; init; } = DateTime.UtcNow;
public DateTime OccurredOn { get; init; } = DateTime.Now;
}
public record TaskUnassignedEvent(Guid TaskId) : IDomainEvent
{
public DateTime OccurredOn { get; init; } = DateTime.UtcNow;
public DateTime OccurredOn { get; init; } = DateTime.Now;
}
public record TaskSectionAddedEvent(Guid TaskId, Guid SectionId, Guid SkillId) : IDomainEvent
{
public DateTime OccurredOn { get; init; } = DateTime.UtcNow;
public DateTime OccurredOn { get; init; } = DateTime.Now;
}
public record TaskSectionRemovedEvent(Guid TaskId, Guid SectionId) : IDomainEvent
{
public DateTime OccurredOn { get; init; } = DateTime.UtcNow;
public DateTime OccurredOn { get; init; } = DateTime.Now;
}
// TaskSection Events
public record TaskSectionStatusChangedEvent(Guid SectionId, TaskSectionStatus OldStatus,
TaskSectionStatus NewStatus,long UserId) : IDomainEvent
{
public DateTime OccurredOn { get; init; } = DateTime.UtcNow;
public DateTime OccurredOn { get; init; } = DateTime.Now;
}
public record TaskSectionAssignedEvent(Guid SectionId, long UserId) : IDomainEvent
{
public DateTime OccurredOn { get; init; } = DateTime.UtcNow;
public DateTime OccurredOn { get; init; } = DateTime.Now;
}
public record TaskSectionTransferredEvent(Guid SectionId, long FromUserId, long ToUserId) : IDomainEvent
{
public DateTime OccurredOn { get; init; } = DateTime.UtcNow;
public DateTime OccurredOn { get; init; } = DateTime.Now;
}
// Section Events (Legacy - keeping for backward compatibility)
public record ProjectPhaseAddedEvent(Guid ProjectId, Guid PhaseId, string PhaseName) : IDomainEvent
{
public DateTime OccurredOn { get; init; } = DateTime.UtcNow;
public DateTime OccurredOn { get; init; } = DateTime.Now;
}
public record ProjectTaskStatusChangedEvent(Guid SectionId, TaskStatus OldStatus, TaskStatus NewStatus) : IDomainEvent
{
public DateTime OccurredOn { get; init; } = DateTime.UtcNow;
public DateTime OccurredOn { get; init; } = DateTime.Now;
}
public record ProjectSectionAddedEvent(Guid SectionId, Guid TaskId) : IDomainEvent
{
public DateTime OccurredOn { get; init; } = DateTime.UtcNow;
public DateTime OccurredOn { get; init; } = DateTime.Now;
}
public record ProjectSectionAssignedEvent(Guid SectionId, long UserId) : IDomainEvent
{
public DateTime OccurredOn { get; init; } = DateTime.UtcNow;
public DateTime OccurredOn { get; init; } = DateTime.Now;
}
public record ProjectSectionTransferredEvent(Guid SectionId, long FromUserId, long ToUserId) : IDomainEvent
{
public DateTime OccurredOn { get; init; } = DateTime.UtcNow;
public DateTime OccurredOn { get; init; } = DateTime.Now;
}
public record WorkStartedEvent(Guid SectionId, long UserId, DateTime StartTime, string? Notes) : IDomainEvent
{
public DateTime OccurredOn { get; init; } = DateTime.UtcNow;
public DateTime OccurredOn { get; init; } = DateTime.Now;
}
public record WorkStoppedEvent(Guid SectionId, long UserId, DateTime StartTime, DateTime EndTime, TimeSpan Duration, string? Notes) : IDomainEvent
{
public DateTime OccurredOn { get; init; } = DateTime.UtcNow;
public DateTime OccurredOn { get; init; } = DateTime.Now;
}
public record ProjectSectionCompletedEvent(Guid ProjectId, long UserId, TimeSpan TotalTimeSpent, string? Notes) : IDomainEvent
{
public DateTime OccurredOn { get; init; } = DateTime.UtcNow;
public DateTime OccurredOn { get; init; } = DateTime.Now;
}
public record AdditionalTimeAddedEvent(Guid ProjectId, Guid AdditionalTimeId, TimeSpan Hours, string? Reason, long? AddedByUserId) : IDomainEvent
{
public DateTime OccurredOn { get; init; } = DateTime.UtcNow;
public DateTime OccurredOn { get; init; } = DateTime.Now;
}
public record AdditionalTimeRemovedEvent(Guid ProjectId, Guid AdditionalTimeId, TimeSpan RemovedHours) : IDomainEvent
{
public DateTime OccurredOn { get; init; } = DateTime.UtcNow;
public DateTime OccurredOn { get; init; } = DateTime.Now;
}
public record InitialEstimatedTimeUpdatedEvent(Guid ProjectId, TimeSpan OldEstimate, TimeSpan NewEstimate) : IDomainEvent
{
public DateTime OccurredOn { get; init; } = DateTime.UtcNow;
public DateTime OccurredOn { get; init; } = DateTime.Now;
}

View File

@@ -5,7 +5,6 @@ namespace GozareshgirProgramManager.Domain.ProjectAgg.Repositories;
public interface ITaskSectionActivityRepository:IRepository<Guid,TaskSectionActivity>
{
Task<TaskSectionActivity?> GetByIdAsync(Guid id);
Task<List<TaskSectionActivity>> GetBySectionIdAsync(Guid sectionId);
Task<List<TaskSectionActivity>> GetByUserIdAsync(long userId);
Task<List<TaskSectionActivity>> GetActiveByUserAsync(long userId);

View File

@@ -1,3 +1,4 @@
using System.Collections;
using GozareshgirProgramManager.Domain._Common;
using GozareshgirProgramManager.Domain.ProjectAgg.Entities;
@@ -11,4 +12,5 @@ public interface ITaskSectionRepository: IRepository<Guid,TaskSection>
Task<TaskSection?> GetByIdWithFullDataAsync(Guid id, CancellationToken cancellationToken = default);
Task<List<TaskSection>> GetAssignedToUserAsync(long userId);
Task<List<TaskSection>> GetActiveSectionsIncludeAllAsync(CancellationToken cancellationToken);
}

View File

@@ -5,7 +5,7 @@ namespace GozareshgirProgramManager.Domain._Common;
public interface IRepository<TKey, T> where T:class
{
T Get(TKey id);
Task<T?> GetByIdAsync(TKey id);
Task<T?> GetByIdAsync(TKey id, CancellationToken cancellationToken = default);
List<T> Get();
IQueryable<T> GetQueryable();
void Create(T entity);

View File

@@ -0,0 +1,865 @@
// <auto-generated />
using System;
using GozareshgirProgramManager.Infrastructure.Persistence.Context;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace GozareshgirProgramManager.Infrastructure.Migrations
{
[DbContext(typeof(ProgramManagerDbContext))]
[Migration("20251227094008_add phase deploy status and is archived")]
partial class addphasedeploystatusandisarchived
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "10.0.1")
.HasAnnotation("Relational:MaxIdentifierLength", 128);
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
modelBuilder.Entity("GozareshgirProgramManager.Domain.CheckoutAgg.Entities.Checkout", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier");
b.Property<DateTime>("CheckoutEndDate")
.HasColumnType("datetime2");
b.Property<DateTime>("CheckoutStartDate")
.HasColumnType("datetime2");
b.Property<DateTime>("CreationDate")
.HasColumnType("datetime2");
b.Property<double>("DeductionFromSalary")
.HasColumnType("float");
b.Property<string>("FullName")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("nvarchar(100)");
b.Property<int>("MandatoryHours")
.HasColumnType("int");
b.Property<int>("Month")
.HasColumnType("int");
b.Property<double>("MonthlySalaryDefined")
.HasColumnType("float");
b.Property<double>("MonthlySalaryPay")
.HasColumnType("float");
b.Property<int>("RemainingHours")
.HasColumnType("int");
b.Property<int>("TotalDaysWorked")
.HasColumnType("int");
b.Property<int>("TotalHoursWorked")
.HasColumnType("int");
b.Property<long>("UserId")
.HasColumnType("bigint");
b.Property<int>("Year")
.HasColumnType("int");
b.HasKey("Id");
b.ToTable("Checkouts", (string)null);
});
modelBuilder.Entity("GozareshgirProgramManager.Domain.CustomerAgg.Customer", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier");
b.Property<DateTime>("CreatedAt")
.HasColumnType("datetime2");
b.Property<DateTime>("CreationDate")
.HasColumnType("datetime2");
b.Property<string>("Email")
.IsRequired()
.HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.HasKey("Id");
b.ToTable("Customers", (string)null);
});
modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.PhaseSection", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier");
b.Property<DateTime>("CreationDate")
.HasColumnType("datetime2");
b.Property<Guid>("PhaseId")
.HasColumnType("uniqueidentifier");
b.Property<Guid>("SkillId")
.HasColumnType("uniqueidentifier");
b.Property<long>("UserId")
.HasColumnType("bigint");
b.HasKey("Id");
b.HasIndex("PhaseId");
b.HasIndex("SkillId");
b.ToTable("PhaseSections");
});
modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.Project", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier");
b.Property<DateTime>("CreationDate")
.HasColumnType("datetime2");
b.Property<string>("Description")
.HasMaxLength(1000)
.HasColumnType("nvarchar(1000)");
b.Property<DateTime?>("EndDate")
.HasColumnType("datetime2");
b.Property<bool>("HasAssignmentOverride")
.HasColumnType("bit");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<DateTime?>("PlannedEndDate")
.HasColumnType("datetime2");
b.Property<DateTime?>("PlannedStartDate")
.HasColumnType("datetime2");
b.Property<DateTime?>("StartDate")
.HasColumnType("datetime2");
b.Property<string>("Status")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("nvarchar(50)");
b.HasKey("Id");
b.ToTable("Projects", (string)null);
});
modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectPhase", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier");
b.Property<DateTime>("CreationDate")
.HasColumnType("datetime2");
b.Property<string>("DeployStatus")
.IsRequired()
.HasMaxLength(30)
.HasColumnType("nvarchar(30)");
b.Property<string>("Description")
.HasMaxLength(1000)
.HasColumnType("nvarchar(1000)");
b.Property<DateTime?>("EndDate")
.HasColumnType("datetime2");
b.Property<bool>("HasAssignmentOverride")
.HasColumnType("bit");
b.Property<bool>("IsArchived")
.HasColumnType("bit");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<int>("OrderIndex")
.HasColumnType("int");
b.Property<Guid>("ProjectId")
.HasColumnType("uniqueidentifier");
b.Property<DateTime?>("StartDate")
.HasColumnType("datetime2");
b.Property<string>("Status")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("nvarchar(50)");
b.HasKey("Id");
b.HasIndex("ProjectId");
b.ToTable("ProjectPhases", (string)null);
});
modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectSection", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier");
b.Property<DateTime>("CreationDate")
.HasColumnType("datetime2");
b.Property<Guid>("ProjectId")
.HasColumnType("uniqueidentifier");
b.Property<Guid>("SkillId")
.HasColumnType("uniqueidentifier");
b.Property<long>("UserId")
.HasColumnType("bigint");
b.HasKey("Id");
b.HasIndex("ProjectId");
b.HasIndex("SkillId");
b.ToTable("ProjectSections");
});
modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectTask", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier");
b.Property<string>("AllocatedTime")
.HasMaxLength(30)
.HasColumnType("nvarchar(30)");
b.Property<DateTime>("CreationDate")
.HasColumnType("datetime2");
b.Property<string>("Description")
.HasMaxLength(1000)
.HasColumnType("nvarchar(1000)");
b.Property<DateTime?>("DueDate")
.HasColumnType("datetime2");
b.Property<DateTime?>("EndDate")
.HasColumnType("datetime2");
b.Property<bool>("HasAssignmentOverride")
.HasColumnType("bit");
b.Property<bool>("HasTimeOverride")
.HasColumnType("bit");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<int>("OrderIndex")
.HasColumnType("int");
b.Property<Guid>("PhaseId")
.HasColumnType("uniqueidentifier");
b.Property<string>("Priority")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("nvarchar(50)");
b.Property<DateTime?>("StartDate")
.HasColumnType("datetime2");
b.Property<string>("Status")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("nvarchar(50)");
b.HasKey("Id");
b.HasIndex("PhaseId");
b.ToTable("ProjectTasks", (string)null);
});
modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier");
b.Property<DateTime>("CreationDate")
.HasColumnType("datetime2");
b.Property<long>("CurrentAssignedUserId")
.HasColumnType("bigint");
b.Property<string>("InitialDescription")
.HasMaxLength(500)
.HasColumnType("nvarchar(500)");
b.Property<string>("InitialEstimatedHours")
.IsRequired()
.HasMaxLength(30)
.HasColumnType("nvarchar(30)");
b.Property<long>("OriginalAssignedUserId")
.HasColumnType("bigint");
b.Property<Guid>("SkillId")
.HasColumnType("uniqueidentifier");
b.Property<string>("Status")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("nvarchar(50)");
b.Property<Guid>("TaskId")
.HasColumnType("uniqueidentifier");
b.HasKey("Id");
b.HasIndex("SkillId");
b.HasIndex("TaskId");
b.ToTable("TaskSections", (string)null);
});
modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSectionActivity", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier");
b.Property<DateTime>("CreationDate")
.HasColumnType("datetime2");
b.Property<DateTime?>("EndDate")
.HasColumnType("datetime2");
b.Property<string>("EndNotes")
.HasMaxLength(1000)
.HasColumnType("nvarchar(1000)");
b.Property<bool>("IsActive")
.HasColumnType("bit");
b.Property<string>("Notes")
.HasMaxLength(1000)
.HasColumnType("nvarchar(1000)");
b.Property<Guid>("SectionId")
.HasColumnType("uniqueidentifier");
b.Property<DateTime>("StartDate")
.HasColumnType("datetime2");
b.Property<long>("UserId")
.HasColumnType("bigint");
b.HasKey("Id");
b.HasIndex("SectionId");
b.ToTable("TaskSectionActivities", (string)null);
});
modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSectionAdditionalTime", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier");
b.Property<DateTime>("AddedAt")
.HasColumnType("datetime2");
b.Property<long?>("AddedByUserId")
.HasColumnType("bigint");
b.Property<DateTime>("CreationDate")
.HasColumnType("datetime2");
b.Property<string>("Hours")
.IsRequired()
.HasMaxLength(30)
.HasColumnType("nvarchar(30)");
b.Property<string>("Reason")
.HasMaxLength(500)
.HasColumnType("nvarchar(500)");
b.Property<Guid?>("TaskSectionId")
.HasColumnType("uniqueidentifier");
b.HasKey("Id");
b.HasIndex("TaskSectionId");
b.ToTable("TaskSectionAdditionalTimes", (string)null);
});
modelBuilder.Entity("GozareshgirProgramManager.Domain.RoleAgg.Entities.Role", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<long>("Id"));
b.Property<DateTime>("CreationDate")
.HasColumnType("datetime2");
b.Property<long?>("GozareshgirRoleId")
.HasColumnType("bigint");
b.Property<string>("RoleName")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("nvarchar(100)");
b.HasKey("Id");
b.ToTable("PmRoles", (string)null);
});
modelBuilder.Entity("GozareshgirProgramManager.Domain.SalaryPaymentSettingAgg.Entities.SalaryPaymentSetting", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<long>("Id"));
b.Property<DateTime>("CreationDate")
.HasColumnType("datetime2");
b.Property<DateTime?>("EndSettingDate")
.HasColumnType("datetime2");
b.Property<bool>("HolidayWorking")
.HasColumnType("bit");
b.Property<double>("MonthlySalary")
.HasColumnType("float");
b.Property<DateTime?>("StartSettingDate")
.HasColumnType("datetime2");
b.Property<long>("UserId")
.HasColumnType("bigint");
b.HasKey("Id");
b.ToTable("SalaryPaymentSetting", (string)null);
});
modelBuilder.Entity("GozareshgirProgramManager.Domain.SkillAgg.Entities.Skill", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier");
b.Property<DateTime>("CreationDate")
.HasColumnType("datetime2");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.HasKey("Id");
b.ToTable("Skills", (string)null);
});
modelBuilder.Entity("GozareshgirProgramManager.Domain.UserAgg.Entities.User", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<long>("Id"));
b.Property<long?>("AccountId")
.HasColumnType("bigint");
b.Property<DateTime>("CreationDate")
.HasColumnType("datetime2");
b.Property<string>("Email")
.HasMaxLength(150)
.HasColumnType("nvarchar(150)");
b.Property<string>("FullName")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("nvarchar(100)");
b.Property<bool>("IsActive")
.HasColumnType("bit");
b.Property<string>("Mobile")
.IsRequired()
.HasMaxLength(20)
.HasColumnType("nvarchar(20)");
b.Property<string>("Password")
.IsRequired()
.HasMaxLength(1000)
.HasColumnType("nvarchar(1000)");
b.Property<string>("ProfilePhotoPath")
.HasMaxLength(500)
.HasColumnType("nvarchar(500)");
b.Property<string>("UserName")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("nvarchar(100)");
b.Property<string>("VerifyCode")
.HasMaxLength(10)
.HasColumnType("nvarchar(10)");
b.HasKey("Id");
b.ToTable("Users", (string)null);
});
modelBuilder.Entity("GozareshgirProgramManager.Domain.UserAgg.Entities.UserRefreshToken", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier");
b.Property<DateTime>("CreationDate")
.HasColumnType("datetime2");
b.Property<DateTime>("ExpiresAt")
.HasColumnType("datetime2");
b.Property<string>("IpAddress")
.HasMaxLength(50)
.HasColumnType("nvarchar(50)");
b.Property<DateTime?>("RevokedAt")
.HasColumnType("datetime2");
b.Property<string>("Token")
.IsRequired()
.HasMaxLength(500)
.HasColumnType("nvarchar(500)");
b.Property<string>("UserAgent")
.HasMaxLength(500)
.HasColumnType("nvarchar(500)");
b.Property<long>("UserId")
.HasColumnType("bigint");
b.HasKey("Id");
b.HasIndex("ExpiresAt");
b.HasIndex("Token")
.IsUnique();
b.HasIndex("UserId");
b.ToTable("UserRefreshTokens", (string)null);
});
modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.PhaseSection", b =>
{
b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectPhase", "Phase")
.WithMany("PhaseSections")
.HasForeignKey("PhaseId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("GozareshgirProgramManager.Domain.SkillAgg.Entities.Skill", "Skill")
.WithMany()
.HasForeignKey("SkillId")
.OnDelete(DeleteBehavior.Restrict);
b.Navigation("Phase");
b.Navigation("Skill");
});
modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectPhase", b =>
{
b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.Project", "Project")
.WithMany("Phases")
.HasForeignKey("ProjectId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Project");
});
modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectSection", b =>
{
b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.Project", "Project")
.WithMany("ProjectSections")
.HasForeignKey("ProjectId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("GozareshgirProgramManager.Domain.SkillAgg.Entities.Skill", "Skill")
.WithMany()
.HasForeignKey("SkillId")
.OnDelete(DeleteBehavior.Restrict);
b.Navigation("Project");
b.Navigation("Skill");
});
modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectTask", b =>
{
b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectPhase", "Phase")
.WithMany("Tasks")
.HasForeignKey("PhaseId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Phase");
});
modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", b =>
{
b.HasOne("GozareshgirProgramManager.Domain.SkillAgg.Entities.Skill", "Skill")
.WithMany("Sections")
.HasForeignKey("SkillId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectTask", "Task")
.WithMany("Sections")
.HasForeignKey("TaskId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Skill");
b.Navigation("Task");
});
modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSectionActivity", b =>
{
b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", "Section")
.WithMany("Activities")
.HasForeignKey("SectionId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Section");
});
modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSectionAdditionalTime", b =>
{
b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", null)
.WithMany("AdditionalTimes")
.HasForeignKey("TaskSectionId");
});
modelBuilder.Entity("GozareshgirProgramManager.Domain.RoleAgg.Entities.Role", b =>
{
b.OwnsMany("GozareshgirProgramManager.Domain.PermissionAgg.Entities.Permission", "Permissions", b1 =>
{
b1.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b1.Property<long>("Id"));
b1.Property<int>("Code")
.HasColumnType("int");
b1.Property<long>("RoleId")
.HasColumnType("bigint");
b1.HasKey("Id");
b1.HasIndex("RoleId");
b1.ToTable("PmRolePermissions", (string)null);
b1.WithOwner("Role")
.HasForeignKey("RoleId");
b1.Navigation("Role");
});
b.Navigation("Permissions");
});
modelBuilder.Entity("GozareshgirProgramManager.Domain.SalaryPaymentSettingAgg.Entities.SalaryPaymentSetting", b =>
{
b.OwnsMany("GozareshgirProgramManager.Domain.SalaryPaymentSettingAgg.Entities.WorkingHours", "WorkingHoursList", b1 =>
{
b1.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b1.Property<long>("Id"));
b1.Property<TimeSpan>("EndShiftOne")
.HasColumnType("time(0)");
b1.Property<TimeSpan>("EndShiftTwo")
.HasColumnType("time(0)");
b1.Property<bool>("HasRestTime")
.HasColumnType("bit");
b1.Property<bool>("HasShiftOne")
.HasColumnType("bit");
b1.Property<bool>("HasShiftTow")
.HasColumnType("bit");
b1.Property<bool>("IsActiveDay")
.HasColumnType("bit");
b1.Property<int>("PersianDayOfWeek")
.HasColumnType("int");
b1.Property<TimeSpan>("RestTime")
.HasColumnType("time(0)");
b1.Property<long>("SalaryPaymentSettingId")
.HasColumnType("bigint");
b1.Property<int>("ShiftDurationInMinutes")
.HasColumnType("int");
b1.Property<TimeSpan>("StartShiftOne")
.HasColumnType("time(0)");
b1.Property<TimeSpan>("StartShiftTwo")
.HasColumnType("time(0)");
b1.HasKey("Id");
b1.HasIndex("SalaryPaymentSettingId");
b1.ToTable("WorkingHours", (string)null);
b1.WithOwner("SalaryPaymentSetting")
.HasForeignKey("SalaryPaymentSettingId");
b1.Navigation("SalaryPaymentSetting");
});
b.Navigation("WorkingHoursList");
});
modelBuilder.Entity("GozareshgirProgramManager.Domain.UserAgg.Entities.User", b =>
{
b.OwnsMany("GozareshgirProgramManager.Domain.RoleUserAgg.RoleUser", "RoleUser", b1 =>
{
b1.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b1.Property<long>("Id"));
b1.Property<long>("RoleId")
.HasColumnType("bigint");
b1.Property<long>("UserId")
.HasColumnType("bigint");
b1.HasKey("Id");
b1.HasIndex("UserId");
b1.ToTable("RoleUsers", (string)null);
b1.WithOwner("User")
.HasForeignKey("UserId");
b1.Navigation("User");
});
b.Navigation("RoleUser");
});
modelBuilder.Entity("GozareshgirProgramManager.Domain.UserAgg.Entities.UserRefreshToken", b =>
{
b.HasOne("GozareshgirProgramManager.Domain.UserAgg.Entities.User", "User")
.WithMany("RefreshTokens")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("User");
});
modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.Project", b =>
{
b.Navigation("Phases");
b.Navigation("ProjectSections");
});
modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectPhase", b =>
{
b.Navigation("PhaseSections");
b.Navigation("Tasks");
});
modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectTask", b =>
{
b.Navigation("Sections");
});
modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", b =>
{
b.Navigation("Activities");
b.Navigation("AdditionalTimes");
});
modelBuilder.Entity("GozareshgirProgramManager.Domain.SkillAgg.Entities.Skill", b =>
{
b.Navigation("Sections");
});
modelBuilder.Entity("GozareshgirProgramManager.Domain.UserAgg.Entities.User", b =>
{
b.Navigation("RefreshTokens");
});
#pragma warning restore 612, 618
}
}
}

View File

@@ -0,0 +1,41 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace GozareshgirProgramManager.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class addphasedeploystatusandisarchived : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "DeployStatus",
table: "ProjectPhases",
type: "nvarchar(30)",
maxLength: 30,
nullable: false,
defaultValue: "");
migrationBuilder.AddColumn<bool>(
name: "IsArchived",
table: "ProjectPhases",
type: "bit",
nullable: false,
defaultValue: false);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "DeployStatus",
table: "ProjectPhases");
migrationBuilder.DropColumn(
name: "IsArchived",
table: "ProjectPhases");
}
}
}

View File

@@ -179,6 +179,11 @@ namespace GozareshgirProgramManager.Infrastructure.Migrations
b.Property<DateTime>("CreationDate")
.HasColumnType("datetime2");
b.Property<string>("DeployStatus")
.IsRequired()
.HasMaxLength(30)
.HasColumnType("nvarchar(30)");
b.Property<string>("Description")
.HasMaxLength(1000)
.HasColumnType("nvarchar(1000)");
@@ -189,6 +194,9 @@ namespace GozareshgirProgramManager.Infrastructure.Migrations
b.Property<bool>("HasAssignmentOverride")
.HasColumnType("bit");
b.Property<bool>("IsArchived")
.HasColumnType("bit");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(200)

View File

@@ -48,6 +48,9 @@ public class ProjectPhaseMapping : IEntityTypeConfiguration<ProjectPhase>
builder.Property(ph => ph.HasAssignmentOverride)
.IsRequired();
builder.Property(x => x.DeployStatus)
.HasConversion<string>().HasMaxLength(30);
// Relationship with Project
builder.HasOne(ph => ph.Project)
.WithMany(p => p.Phases)

View File

@@ -1,4 +1,5 @@
using GozareshgirProgramManager.Domain.ProjectAgg.Entities;
using GozareshgirProgramManager.Domain.ProjectAgg.Enums;
using GozareshgirProgramManager.Domain.ProjectAgg.Repositories;
using GozareshgirProgramManager.Infrastructure.Persistence._Common;
using GozareshgirProgramManager.Infrastructure.Persistence.Context;
@@ -35,4 +36,13 @@ public class TaskSectionRepository:RepositoryBase<Guid,TaskSection>,ITaskSection
.Where(x => x.CurrentAssignedUserId == userId)
.ToListAsync();
}
public Task<List<TaskSection>> GetActiveSectionsIncludeAllAsync(CancellationToken cancellationToken)
{
return _context.TaskSections
.Where(x => x.Status == TaskSectionStatus.InProgress)
.Include(x => x.Activities)
.Include(x => x.AdditionalTimes)
.ToListAsync(cancellationToken);
}
}

View File

@@ -43,9 +43,9 @@ public class RepositoryBase<TKey, T> : IRepository<TKey, T> where T : class
return _context.Find<T>(id);
}
public async Task<T?> GetByIdAsync(TKey id)
public async Task<T?> GetByIdAsync(TKey id, CancellationToken cancellationToken = default)
{
return await _context.Set<T>().FindAsync(id);
return await _context.Set<T>().FindAsync([id], cancellationToken);
}
public List<T> Get()

View File

@@ -1,6 +1,9 @@
using System.Runtime.InteropServices;
using GozareshgirProgramManager.Application._Common.Models;
using GozareshgirProgramManager.Application.Modules.Projects.Commands.AssignProject;
using GozareshgirProgramManager.Application.Modules.Projects.Commands.AutoStopOverTimeTaskSections;
using GozareshgirProgramManager.Application.Modules.Projects.Commands.AutoUpdateDeployStatus;
using GozareshgirProgramManager.Application.Modules.Projects.Commands.ChangeDeployStatusProject;
using GozareshgirProgramManager.Application.Modules.Projects.Commands.ChangeStatusSection;
using GozareshgirProgramManager.Application.Modules.Projects.Commands.CreateProject;
using GozareshgirProgramManager.Application.Modules.Projects.Commands.DeleteProject;
@@ -11,6 +14,8 @@ using GozareshgirProgramManager.Application.Modules.Projects.Queries.GetProjectA
using GozareshgirProgramManager.Application.Modules.Projects.Queries.GetProjectsList;
using GozareshgirProgramManager.Application.Modules.Projects.Queries.ProjectBoardDetail;
using GozareshgirProgramManager.Application.Modules.Projects.Queries.ProjectBoardList;
using GozareshgirProgramManager.Application.Modules.Projects.Queries.ProjectDeployBoardDetail;
using GozareshgirProgramManager.Application.Modules.Projects.Queries.ProjectDeployBoardList;
using GozareshgirProgramManager.Application.Modules.Projects.Queries.ProjectSetTimeDetails;
using MediatR;
using Microsoft.AspNetCore.Mvc;
@@ -28,63 +33,68 @@ public class ProjectController : ProgramManagerBaseController
}
[HttpGet]
public async Task<ActionResult<OperationResult<GetProjectsListResponse>>> Get([FromQuery]GetProjectsListQuery query)
public async Task<ActionResult<OperationResult<GetProjectsListResponse>>> Get(
[FromQuery] GetProjectsListQuery query)
{
var res=await _mediator.Send(query);
var res = await _mediator.Send(query);
return res;
}
[HttpPost]
public async Task<ActionResult<OperationResult>> Create([FromBody] CreateProjectCommand command)
{
var res=await _mediator.Send(command);
var res = await _mediator.Send(command);
return res;
}
[HttpPut]
public async Task<ActionResult<OperationResult>> Edit([FromBody] EditProjectCommand command)
{
var res=await _mediator.Send(command);
var res = await _mediator.Send(command);
return res;
}
[HttpDelete]
public async Task<ActionResult<OperationResult>> Delete([FromQuery] DeleteProjectCommand command)
{
var res=await _mediator.Send(command);
var res = await _mediator.Send(command);
return res;
}
[HttpGet("assign")]
public async Task<ActionResult<OperationResult<GetProjectAssignDetailsResponse>>> GetAssignableProjects(GetProjectAssignDetailsQuery query)
public async Task<ActionResult<OperationResult<GetProjectAssignDetailsResponse>>> GetAssignableProjects(
GetProjectAssignDetailsQuery query)
{
var res=await _mediator.Send(query);
var res = await _mediator.Send(query);
return res;
}
[HttpPost("assign")]
public async Task<ActionResult<OperationResult>> Assign(AssignProjectCommand command)
{
var res=await _mediator.Send(command);
var res = await _mediator.Send(command);
return res;
}
[HttpGet("set-time")]
public async Task<ActionResult<OperationResult<ProjectSetTimeResponse>>> GetSetTimeProjectDetails(ProjectSetTimeDetailsQuery query)
public async Task<ActionResult<OperationResult<ProjectSetTimeResponse>>> GetSetTimeProjectDetails(
ProjectSetTimeDetailsQuery query)
{
var res=await _mediator.Send(query);
var res = await _mediator.Send(query);
return res;
}
[HttpPost("set-time")]
public async Task<ActionResult<OperationResult>> SetTimeProject(SetTimeProjectCommand command)
{
var res=await _mediator.Send(command);
var res = await _mediator.Send(command);
return res;
}
[HttpPost("change-status")]
public async Task<ActionResult<OperationResult>> ChangeStatus(ChangeStatusSectionCommand command)
{
var res = await _mediator.Send(command);
var res = await _mediator.Send(command);
return res;
}
@@ -96,11 +106,16 @@ public class ProjectController : ProgramManagerBaseController
}
[HttpGet("board")]
public async Task<ActionResult<OperationResult<List<ProjectBoardListResponse>>>> GetProjectBoard([FromQuery] ProjectBoardListQuery query)
public async Task<ActionResult<OperationResult<List<ProjectBoardListResponse>>>> GetProjectBoard(
[FromQuery] ProjectBoardListQuery query)
{
// اجرای Command برای متوقف کردن تسک‌های overtime قبل از نمایش
await _mediator.Send(new AutoStopOverTimeTaskSectionsCommand());
var res = await _mediator.Send(query);
return res;
}
[HttpGet("board/details")]
public async Task<ActionResult<OperationResult<ProjectBoardDetailResponse>>> GetProjectBoardDetails(Guid id)
{
@@ -108,4 +123,28 @@ public class ProjectController : ProgramManagerBaseController
var res = await _mediator.Send(query);
return res;
}
[HttpGet("deploy-board")]
public async Task<ActionResult<OperationResult<GetProjectsDeployBoardListResponse>>> GetProjectDeployBoard()
{
// قبل از دریافت دیتا، وضعیت دیپلوی را بر اساس تکمیل شدن تمام سکشن‌ها به‌روزرسانی می‌کنیم
await _mediator.Send(new AutoUpdateDeployStatusCommand());
var request = new GetProjectDeployBoardListQuery();
return await _mediator.Send(request);
}
[HttpGet("deploy-board/details")]
public async Task<ActionResult<OperationResult<ProjectDeployBoardDetailsResponse>>> GetProjectDeployBoardDetails(Guid id)
{
var query = new ProjectDeployBoardDetailsQuery(id);
var res = await _mediator.Send(query);
return res;
}
[HttpPost("deploy-board/change-status")]
public async Task<ActionResult<OperationResult>> ChangeDeployStatus(ChangeDeployStatusProjectCommand command)
{
var res = await _mediator.Send(command);
return res;
}
}

View File

@@ -807,6 +807,13 @@ public class institutionContractController : AdminBaseController
var res =await _institutionContractApplication.PrintOneAsync(id);
return res;
}
[HttpPost("mannual-verify/{id}")]
public async Task<ActionResult<OperationResult>> VerifyInstitutionContractMannualy(long id)
{
var res= await _institutionContractApplication.VerifyInstitutionContractManually(id);
return res;
}
}

View File

@@ -0,0 +1,15 @@
@page
<h4>Deploy Log</h4>
<pre style="
background:#111;
color:#0f0;
padding:15px;
max-height:600px;
overflow:auto;
font-size:13px;
border-radius:6px;">
</pre>

View File

@@ -2,6 +2,14 @@
@model ServiceHost.Areas.AdminNew.Pages.Company.AndroidApk.IndexModel
@{
ViewData["Title"] = "File Upload";
<style>
.lineDiv {
width: 100%;
height: 2px;
background-image: linear-gradient(to right, #ffffff, #e5e5e5, #cbcbcb, #b2b2b2, #9a9a9a, #9a9a9a, #9a9a9a, #9a9a9a, #b2b2b2, #cbcbcb, #e5e5e5, #ffffff);
margin: 10px;
}
</style>
}
<h1>Upload APK File</h1>
@@ -60,16 +68,85 @@
</form>
<form style="margin:50px" asp-page-handler="PaymentGateWay" id="11" method="post">
<form style="margin:30px" asp-page-handler="PaymentGateWay" id="11" method="post">
<button type="submit">درگاه پرداخت تستی </button>
</form>
<div class="lineDiv"></div>
<div class="row m-t-20">
<div class="col-4"></div>
<div class="col-2">
<form asp-page-handler="UploadFrontEnd" id="12" method="post">
<button type="submit"
class="btn btn-danger"
onclick="return confirm('آیا از انتشار نسخه جدید فرانت مطمئن هستید؟');">
🚀 Deploy Next UI
</button>
</form>
</div>
<div class="col-2">
<button type="button" class="btn btn-outline-secondary"
data-bs-toggle="modal"
data-bs-target="#logModal">
مشاهده لاگ Deploy
</button>
</div>
<div class="col-4"></div>
</div>
<div class="lineDiv"></div>
<div class="modal fade" id="logModal" tabindex="-1">
<div class="modal-dialog modal-xl modal-dialog-scrollable">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Deploy Log</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<pre id="logContent"
style="background: #111;
color: #0f0;
padding: 15px;
font-size: 13px;
text-align: left;
direction: ltr;">
</pre>
</div>
</div>
</div>
</div>
<form style="margin:20px" asp-page-handler="ContractingPartyToWorkshop" id="13" method="post">
<button class="btn btn-outline-secondary" type="submit"> افزودن آی دی طرف حساب به کارگاه </button>
</form>
@if (ViewData["message"] != null)
{
<p>@ViewData["message"]</p>
}
<script>
document.getElementById('logModal')
.addEventListener('show.bs.modal', function () {
fetch('?handler=Log')
.then(r => r.text())
.then(t => {
document.getElementById('logContent').textContent = t;
});
});
</script>
@* <script>

View File

@@ -1,36 +1,40 @@
using _0_Framework.Application;
using _0_Framework.Application.Enums;
using _0_Framework.Application.FaceEmbedding;
using _0_Framework.Application.PaymentGateway;
using _0_Framework.Domain.CustomizeCheckoutShared.Enums;
using AccountManagement.Domain.AccountLeftWorkAgg;
using AccountMangement.Infrastructure.EFCore;
using Company.Domain.AndroidApkVersionAgg;
using Company.Domain.CustomizeCheckoutAgg.ValueObjects;
using Company.Domain.CustomizeCheckoutTempAgg.ValueObjects;
using Company.Domain.InstitutionContractAgg;
using Company.Domain.InstitutionPlanAgg;
using Company.Domain.PaymentTransactionAgg;
using Company.Domain.RewardAgg;
using Company.Domain.RollCallAgg.DomainService;
using CompanyManagement.Infrastructure.Excel.WorkshopsRollCall;
using CompanyManagment.App.Contracts.AndroidApkVersion;
using CompanyManagment.App.Contracts.InstitutionContract;
using CompanyManagment.App.Contracts.PaymentTransaction;
using CompanyManagment.App.Contracts.TemporaryClientRegistration;
using CompanyManagment.EFCore;
using Hangfire;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using System.Net.Http;
using System.Security.Cryptography.Xml;
using System.Text.Json.Serialization;
using _0_Framework.Application.PaymentGateway;
using Company.Domain.InstitutionContractAgg;
using Company.Domain.InstitutionPlanAgg;
using Company.Domain.PaymentTransactionAgg;
using CompanyManagment.App.Contracts.InstitutionContract;
using CompanyManagment.App.Contracts.PaymentTransaction;
using CompanyManagment.App.Contracts.TemporaryClientRegistration;
using Microsoft.Extensions.Options;
using Parbad;
using Parbad.AspNetCore;
using Parbad.Gateway.Sepehr;
using System.ComponentModel.DataAnnotations;
using _0_Framework.Application.Enums;
using _0_Framework.Application.FaceEmbedding;
using CompanyManagement.Infrastructure.Excel.WorkshopsRollCall;
using System.Diagnostics;
using System.Net.Http;
using System.Security.Cryptography.Xml;
using System.Text;
using System.Text.Json.Serialization;
using Microsoft.AspNetCore.Authentication;
using static ServiceHost.Areas.AdminNew.Pages.Company.AndroidApk.IndexModel2;
namespace ServiceHost.Areas.AdminNew.Pages.Company.AndroidApk
@@ -47,6 +51,7 @@ namespace ServiceHost.Areas.AdminNew.Pages.Company.AndroidApk
private readonly IHttpClientFactory _httpClientFactory;
private readonly IOnlinePayment _onlinePayment;
private readonly IFaceEmbeddingService _faceEmbeddingService;
private readonly IAuthHelper _authHelper;
[BindProperty] public IFormFile File { get; set; }
@@ -61,13 +66,18 @@ namespace ServiceHost.Areas.AdminNew.Pages.Company.AndroidApk
[Display(Name = "کد ورژن")]
public string VersionCode { get; set; }
/// <summary>
/// لاگ آپلود فرانت
/// </summary>
public string LogContent { get; set; }
[BindProperty] public ApkType SelectedApkType { get; set; }
[BindProperty] public bool IsForce { get; set; }
public IndexModel(IAndroidApkVersionApplication application, IRollCallDomainService rollCallDomainService,
CompanyContext context, AccountContext accountContext, IHttpClientFactory httpClientFactory,
IOptions<AppSettingConfiguration> appSetting,
ITemporaryClientRegistrationApplication clientRegistrationApplication, IOnlinePayment onlinePayment, IFaceEmbeddingService faceEmbeddingService)
ITemporaryClientRegistrationApplication clientRegistrationApplication, IOnlinePayment onlinePayment, IFaceEmbeddingService faceEmbeddingService, IAuthHelper authHelper)
{
_application = application;
_rollCallDomainService = rollCallDomainService;
@@ -77,6 +87,7 @@ namespace ServiceHost.Areas.AdminNew.Pages.Company.AndroidApk
_clientRegistrationApplication = clientRegistrationApplication;
_onlinePayment = onlinePayment;
_faceEmbeddingService = faceEmbeddingService;
_authHelper = authHelper;
_paymentGateway = new SepehrPaymentGateway(httpClientFactory);
}
@@ -140,11 +151,34 @@ namespace ServiceHost.Areas.AdminNew.Pages.Company.AndroidApk
public async Task<IActionResult> OnPostShiftDateNew()
{
//await UpdateInstitutionContract();
await UpdateFaceEmbeddingNames();
//await UpdateFaceEmbeddingNames();
await SetInstitutionContractSigningType();
ViewData["message"] = "تومام یک";
return Page();
}
private async System.Threading.Tasks.Task SetInstitutionContractSigningType()
{
var query = _context.InstitutionContractSet
.Where(x=>x.VerificationStatus != InstitutionContractVerificationStatus.PendingForVerify);
var otpSigned = query.Where(x=>x.VerifierFullName != null && x.LawId != 0).ToList();
foreach (var institutionContract in otpSigned)
{
institutionContract.SetSigningType(InstitutionContractSigningType.OtpBased);
}
var lagacySigned = query.Where(x=>x.VerifierFullName == null && x.LawId == 0).ToList();
foreach (var institutionContract in lagacySigned)
{
institutionContract.SetSigningType(InstitutionContractSigningType.Legacy);
}
await _context.SaveChangesAsync();
}
public async Task<IActionResult> OnPostShiftDateNew2()
{
//var startRollCall = new DateTime(2025, 3, 21);
@@ -292,6 +326,105 @@ namespace ServiceHost.Areas.AdminNew.Pages.Company.AndroidApk
//TranslateCode(result?.ErrorCode);
return Page();
}
[DisableConcurrentExecution(timeoutInSeconds: 120)]
public async Task<IActionResult> OnPostUploadFrontEnd(CancellationToken cancellationToken)
{
var validAccountId = _authHelper.CurrentAccountId();
if (validAccountId == 2 || validAccountId == 322)
{
var batPath = @"C:\next-ui\deploy-next-ui.bat";
var psi = new ProcessStartInfo
{
FileName = batPath,
UseShellExecute = true, // خیلی مهم
Verb = "runas", // اجرای Administrator
CreateNoWindow = true,
WindowStyle = ProcessWindowStyle.Hidden
};
Process.Start(psi);
TempData["Message"] = "فرآیند Deploy شروع شد. لاگ را بررسی کنید.";
return RedirectToPage();
}
return Forbid();
}
/// <summary>
/// افزودن آی دی طرف حساب به کارگاه
/// </summary>
/// <returns></returns>
[DisableConcurrentExecution(timeoutInSeconds: 120)]
public async Task<IActionResult> OnPostContractingPartyToWorkshop()
{
var workshops = await _context.Workshops.Where(x => x.ContractingPartyId == 0).ToListAsync();
var worskhopEmployeer = await _context.WorkshopEmployers.Include(x => x.Employer).ToListAsync();
var contractingParties = await _context.PersonalContractingParties.ToListAsync();
foreach (var workshop in workshops)
{
var employers = worskhopEmployeer.Where(x => x.WorkshopId == workshop.id);
var contractingPartyIdList = new List<long>();
foreach (var employer in employers)
{
if (contractingParties.Any(x => x.id == employer.Employer.ContractingPartyId))
{
contractingPartyIdList.Add(employer.Employer.ContractingPartyId);
}
}
if (contractingPartyIdList.Count > 0)
{
if (contractingPartyIdList.Count == 1)
{
workshop.AddContractingPartyId(contractingPartyIdList[0]);
await _context.SaveChangesAsync();
}
else
{
var idDistinct = contractingPartyIdList.Distinct().ToList();
if (idDistinct.Count == 1)
{
workshop.AddContractingPartyId(contractingPartyIdList[0]);
await _context.SaveChangesAsync();
}
}
}
}
ViewData["message"] = "آی دی های طرف حساب اضافه شد";
return Page();
}
/// <summary>
/// دریافت لاگ آپلود فرانت
/// </summary>
/// <returns></returns>
public IActionResult OnGetLog()
{
var validAccountId = _authHelper.CurrentAccountId();
if (validAccountId == 2 || validAccountId == 322)
{
var logPath = @"C:\next-ui\log.txt";
if (!System.IO.File.Exists(logPath))
return Content("Log file not found.");
var content = System.IO.File.ReadAllText(logPath, Encoding.UTF8);
return Content(content);
}
return Content("شما مجاز به دیدن لاگ نیستید");
}
public async System.Threading.Tasks.Task OnGetCallback(string? transid, string? cardnumber,
string? tracking_number, string status)
@@ -902,7 +1035,7 @@ namespace ServiceHost.Areas.AdminNew.Pages.Company.AndroidApk
x.PersonnelCount,
x.Price, x.InstitutionContractWorkshopGroupId,
group,
x.WorkshopId.Value);
x.WorkshopId.Value,x.id);
entity.SetEmployers(x.Employers.Select(e => e.EmployerId).ToList());
return entity;

View File

@@ -164,7 +164,7 @@ public class GeneralController : GeneralBaseController
.Where(x => x.Type == FinancialInvoiceItemType.BuyInstitutionContract);
foreach (var editFinancialInvoiceItem in financialItems)
{
await _institutionContractApplication.SetPendingWorkflow(editFinancialInvoiceItem.EntityId);
await _institutionContractApplication.SetPendingWorkflow(editFinancialInvoiceItem.EntityId,InstitutionContractSigningType.OtpBased);
}
var financialInstallmentItems = financialInvoice.Items
.Where(x => x.Type == FinancialInvoiceItemType.BuyInstitutionContractInstallment);
@@ -174,7 +174,7 @@ public class GeneralController : GeneralBaseController
var institutionContractId =
await _institutionContractApplication.GetIdByInstallmentId(
editFinancialInvoiceItem.EntityId);
await _institutionContractApplication.SetPendingWorkflow(institutionContractId);
await _institutionContractApplication.SetPendingWorkflow(institutionContractId,InstitutionContractSigningType.OtpBased);
}
}

View File

@@ -70,7 +70,8 @@ public class ParameterBindingConvention : IApplicationModelConvention
{
if (selector.AttributeRouteModel?.Template != null)
{
if (selector.AttributeRouteModel.Template.Contains($"{{{parameterName}}}", StringComparison.OrdinalIgnoreCase))
if (selector.AttributeRouteModel.Template.Contains($"{{{parameterName}}}", StringComparison.OrdinalIgnoreCase) ||
selector.AttributeRouteModel.Template.Contains($"{{{parameterName}:", StringComparison.OrdinalIgnoreCase))
return true;
}
}
@@ -80,7 +81,8 @@ public class ParameterBindingConvention : IApplicationModelConvention
{
if (selector.AttributeRouteModel?.Template != null)
{
if (selector.AttributeRouteModel.Template.Contains($"{{{parameterName}}}", StringComparison.OrdinalIgnoreCase))
if (selector.AttributeRouteModel.Template.Contains($"{{{parameterName}}}", StringComparison.OrdinalIgnoreCase) ||
selector.AttributeRouteModel.Template.Contains($"{{{parameterName}:", StringComparison.OrdinalIgnoreCase))
return true;
}
}