add validation and management for additional time entries in SetTimeProjectCommand

This commit is contained in:
2026-02-02 16:07:43 +03:30
parent e2bab8c1ce
commit 7cbb9eef69
3 changed files with 81 additions and 9 deletions

View File

@@ -12,6 +12,7 @@ public record SetTimeProjectCommand(
public class SetTimeSectionTime public class SetTimeSectionTime
{ {
public Guid? Id { get; set; }
public string Description { get; set; } public string Description { get; set; }
public int Hours { get; set; } public int Hours { get; set; }
public int Minutes { get; set; } public int Minutes { get; set; }

View File

@@ -349,6 +349,15 @@ public class SetTimeProjectCommandHandler : IBaseCommandHandler<SetTimeProjectCo
return OperationResult.Success(); return OperationResult.Success();
} }
private void ValidateTotalTimeNotLessThanSpent(TimeSpan newTotalTime, TimeSpan currentTotalSpent)
{
if (newTotalTime < currentTotalSpent)
{
throw new BadRequestException(
$"تایم کل سکشن نمی‌تواند کمتر از زمان مصرف شده ({currentTotalSpent.TotalHours:F2} ساعت) باشد");
}
}
private void SetSectionTime(TaskSection section, SetTimeProjectSkillItem sectionItem, long? addedByUserId) private void SetSectionTime(TaskSection section, SetTimeProjectSkillItem sectionItem, long? addedByUserId)
{ {
var initData = sectionItem.InitData; var initData = sectionItem.InitData;
@@ -363,18 +372,69 @@ public class SetTimeProjectCommandHandler : IBaseCommandHandler<SetTimeProjectCo
// تنظیم زمان اولیه // تنظیم زمان اولیه
section.UpdateInitialEstimatedHours(initialTime, initData.Description); section.UpdateInitialEstimatedHours(initialTime, initData.Description);
section.ClearAdditionalTimes(); // مدیریت هوشمند زمان‌های اضافی
// افزودن زمان‌های اضافی var existingAdditionalTimes = section.AdditionalTimes.ToList();
bool hasAdditionalTime = false; var incomingAdditionalTimes = sectionItem.AdditionalTime ?? [];
foreach (var additionalTime in sectionItem.AdditionalTime) var currentTotalSpent = section.GetTotalTimeSpent();
bool hasRealChange = false;
// حذف آیتم‌هایی که دیگر در لیست نیستند
foreach (var existingTime in existingAdditionalTimes)
{ {
var additionalTimeSpan = TimeSpan.FromHours(additionalTime.Hours).Add(TimeSpan.FromMinutes(additionalTime.Minutes)); var stillExists = incomingAdditionalTimes.Any(x => x.Id == existingTime.Id);
section.AddAdditionalTime(additionalTimeSpan, additionalTime.Description, addedByUserId); if (!stillExists)
hasAdditionalTime = true; {
section.RemoveAdditionalTime(existingTime.Id);
hasRealChange = true;
}
}
// ویرایش یا اضافه کردن آیتم‌های جدید
foreach (var additionalTime in incomingAdditionalTimes)
{
var additionalTimeSpan = TimeSpan.FromHours(additionalTime.Hours)
.Add(TimeSpan.FromMinutes(additionalTime.Minutes));
if (additionalTimeSpan <= TimeSpan.Zero)
continue;
var existingAdditionalTime = existingAdditionalTimes.FirstOrDefault(x => x.Id == additionalTime.Id);
if (existingAdditionalTime != null)
{
// اگر آیتم با این ID وجود دارد، بررسی کن اگر تغییر کرده باشد
if (existingAdditionalTime.HasChanged(additionalTimeSpan, additionalTime.Description))
{
var newTotalTime = section.InitialEstimatedHours
.Add(existingAdditionalTimes
.Where(x => x.Id != existingAdditionalTime.Id)
.Aggregate(TimeSpan.Zero, (acc, x) => acc.Add(x.Hours))
.Add(additionalTimeSpan));
ValidateTotalTimeNotLessThanSpent(newTotalTime, currentTotalSpent);
// ویرایش بدون حذف و ایجاد دوباره
existingAdditionalTime.Update(additionalTimeSpan, additionalTime.Description);
hasRealChange = true;
}
}
else
{
// اگر ID نداشت یا ID جدید بود، اضافه کن
if (additionalTime.Id == null || additionalTime.Id == Guid.Empty)
{
var newTotalTime = section.FinalEstimatedHours.Add(additionalTimeSpan);
ValidateTotalTimeNotLessThanSpent(newTotalTime, currentTotalSpent);
section.AddAdditionalTime(additionalTimeSpan, additionalTime.Description, addedByUserId);
hasRealChange = true;
}
}
} }
// تغییر status به Incomplete فقط اگر زمان اضافی اضافه شده باشد و در وضعیتی غیر از ReadyToStart باشد // تغییر status به Incomplete فقط اگر تغییری واقعی اعمال شده باشد و در وضعیتی غیر از ReadyToStart باشد
if (hasAdditionalTime && section.Status != TaskSectionStatus.ReadyToStart) if (hasRealChange && section.Status != TaskSectionStatus.ReadyToStart)
{ {
// اگر سکشن درحال انجام است، باید متوقف شود قبل از تغییر status // اگر سکشن درحال انجام است، باید متوقف شود قبل از تغییر status
if (section.Status == TaskSectionStatus.InProgress) if (section.Status == TaskSectionStatus.InProgress)

View File

@@ -26,4 +26,15 @@ public class TaskSectionAdditionalTime : EntityBase<Guid>
{ {
Reason = reason; Reason = reason;
} }
public void Update(TimeSpan hours, string? reason = null)
{
Hours = hours;
Reason = reason;
}
public bool HasChanged(TimeSpan newHours, string? newReason)
{
return Hours != newHours || Reason != newReason;
}
} }