Initial commit: JDE Scoping Tool migration project
Set up repository with legacy .NET Framework 4.8 source (OLD/), new .NET 10 Blazor solution (NEW/), OpenSpec specifications, documentation, and project configuration.
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
namespace JdeScoping.Client.Models;
|
||||
|
||||
/// <summary>
|
||||
/// View model for component lot filter.
|
||||
/// </summary>
|
||||
public class ComponentLotViewModel
|
||||
{
|
||||
public string LotNumber { get; set; } = string.Empty;
|
||||
public string ItemNumber { get; set; } = string.Empty;
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
if (obj is ComponentLotViewModel other)
|
||||
{
|
||||
return LotNumber == other.LotNumber && ItemNumber == other.ItemNumber;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public override int GetHashCode() => HashCode.Combine(LotNumber, ItemNumber);
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
namespace JdeScoping.Client.Models;
|
||||
|
||||
/// <summary>
|
||||
/// View model for data refresh/sync status display.
|
||||
/// </summary>
|
||||
public class DataUpdateViewModel
|
||||
{
|
||||
public DateTime StartDt { get; set; }
|
||||
public DateTime? EndDt { get; set; }
|
||||
|
||||
public int BranchRecords { get; set; }
|
||||
public int ProfitCenterRecords { get; set; }
|
||||
public int WorkCenterRecords { get; set; }
|
||||
public int OrgHierarchyRecords { get; set; }
|
||||
public int StatusCodeRecords { get; set; }
|
||||
public int UserRecords { get; set; }
|
||||
public int ItemRecords { get; set; }
|
||||
public int LotRecords { get; set; }
|
||||
public int WorkOrderRecords { get; set; }
|
||||
public int WorkOrderStepRecords { get; set; }
|
||||
public int WorkOrderComponentRecords { get; set; }
|
||||
|
||||
public bool WasSuccessful { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace JdeScoping.Client.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Login form model with validation.
|
||||
/// </summary>
|
||||
public class LoginModel
|
||||
{
|
||||
[Required(ErrorMessage = "Username is required")]
|
||||
public string Username { get; set; } = string.Empty;
|
||||
|
||||
[Required(ErrorMessage = "Password is required")]
|
||||
public string Password { get; set; } = string.Empty;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
namespace JdeScoping.Client.Models;
|
||||
|
||||
/// <summary>
|
||||
/// View model for operator filter.
|
||||
/// </summary>
|
||||
public class OperatorViewModel
|
||||
{
|
||||
public int AddressNumber { get; set; }
|
||||
public string UserId { get; set; } = string.Empty;
|
||||
public string FullName { get; set; } = string.Empty;
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
if (obj is OperatorViewModel other)
|
||||
{
|
||||
return UserId == other.UserId;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public override int GetHashCode() => UserId.GetHashCode();
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using JdeScoping.Core.ViewModels;
|
||||
|
||||
namespace JdeScoping.Client.Models;
|
||||
|
||||
/// <summary>
|
||||
/// View model for search criteria filters.
|
||||
/// </summary>
|
||||
public class SearchCriteriaViewModel
|
||||
{
|
||||
public DateTime? MinimumDt { get; set; }
|
||||
public DateTime? MaximumDt { get; set; }
|
||||
|
||||
public List<WorkOrderViewModel> WorkOrders { get; set; } = [];
|
||||
public List<ItemViewModel> Items { get; set; } = [];
|
||||
public List<ProfitCenterViewModel> ProfitCenters { get; set; } = [];
|
||||
public List<WorkCenterViewModel> WorkCenters { get; set; } = [];
|
||||
public List<ComponentLotViewModel> ComponentLots { get; set; } = [];
|
||||
public List<OperatorViewModel> Operators { get; set; } = [];
|
||||
public List<PartOperationViewModel> PartOperations { get; set; } = [];
|
||||
|
||||
public bool ExtractMisData { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
namespace JdeScoping.Client.Models;
|
||||
|
||||
/// <summary>
|
||||
/// SignalR message for search status updates.
|
||||
/// </summary>
|
||||
public record SearchUpdate
|
||||
{
|
||||
public int Id { get; init; }
|
||||
public string Name { get; init; } = string.Empty;
|
||||
public string UserName { get; init; } = string.Empty;
|
||||
public string Status { get; init; } = string.Empty;
|
||||
public DateTime? SubmitDt { get; init; }
|
||||
public DateTime? StartDt { get; init; }
|
||||
public DateTime? EndDt { get; init; }
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace JdeScoping.Client.Models;
|
||||
|
||||
/// <summary>
|
||||
/// View model for displaying search information in lists and details.
|
||||
/// </summary>
|
||||
public class SearchViewModel
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Name is required.")]
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public string UserName { get; set; } = string.Empty;
|
||||
public string Status { get; set; } = string.Empty;
|
||||
public DateTime? SubmitDt { get; set; }
|
||||
public DateTime? StartDt { get; set; }
|
||||
public DateTime? EndDt { get; set; }
|
||||
public SearchCriteriaViewModel Criteria { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the background color based on status.
|
||||
/// </summary>
|
||||
public string StatusColor => Status switch
|
||||
{
|
||||
"Error" => "#FF6347",
|
||||
"Ended" => "#90EE90",
|
||||
"Running" => "#87CEEB",
|
||||
_ => "#EEEEEE"
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the search has downloadable results.
|
||||
/// </summary>
|
||||
public bool HasResults => Status == "Ended";
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the search is read-only (already submitted).
|
||||
/// </summary>
|
||||
public bool IsReadOnly => Status != "New";
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace JdeScoping.Client.Models;
|
||||
|
||||
/// <summary>
|
||||
/// SignalR message for processor status updates.
|
||||
/// </summary>
|
||||
public record StatusUpdate
|
||||
{
|
||||
public string Message { get; init; } = string.Empty;
|
||||
public DateTime? Timestamp { get; init; }
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
namespace JdeScoping.Client.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Client-side view model for authenticated user information.
|
||||
/// Mirrors the server-side UserInfo model returned by /api/auth/login and /api/auth/me.
|
||||
/// </summary>
|
||||
public class UserInfoViewModel
|
||||
{
|
||||
/// <summary>
|
||||
/// User's login username.
|
||||
/// </summary>
|
||||
public string Username { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// User's first name.
|
||||
/// </summary>
|
||||
public string FirstName { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// User's last name.
|
||||
/// </summary>
|
||||
public string LastName { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// User's display name (computed on server, provided here for convenience).
|
||||
/// </summary>
|
||||
public string DisplayName { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// User's organization title.
|
||||
/// </summary>
|
||||
public string Title { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// User's email address.
|
||||
/// </summary>
|
||||
public string EmailAddress { get; set; } = string.Empty;
|
||||
}
|
||||
@@ -0,0 +1,276 @@
|
||||
namespace JdeScoping.Client.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a valid combination of search filter criteria.
|
||||
/// Each combination defines which filter panels should be visible for a given search type.
|
||||
/// </summary>
|
||||
public class ValidCombination
|
||||
{
|
||||
public int Id { get; init; }
|
||||
public string Name { get; init; } = string.Empty;
|
||||
public bool Timespan { get; init; }
|
||||
public bool WorkOrder { get; init; }
|
||||
public bool ItemNumber { get; init; }
|
||||
public bool ProfitCenter { get; init; }
|
||||
public bool WorkCenter { get; init; }
|
||||
public bool ComponentLot { get; init; }
|
||||
public bool Operator { get; init; }
|
||||
public bool ItemOperationMis { get; init; }
|
||||
public bool ExtractMis { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the given filter flags match this combination.
|
||||
/// </summary>
|
||||
public bool Matches(
|
||||
bool timespan,
|
||||
bool workOrder,
|
||||
bool itemNumber,
|
||||
bool profitCenter,
|
||||
bool workCenter,
|
||||
bool componentLot,
|
||||
bool @operator,
|
||||
bool itemOperationMis,
|
||||
bool extractMis)
|
||||
{
|
||||
return Timespan == timespan &&
|
||||
WorkOrder == workOrder &&
|
||||
ItemNumber == itemNumber &&
|
||||
ProfitCenter == profitCenter &&
|
||||
WorkCenter == workCenter &&
|
||||
ComponentLot == componentLot &&
|
||||
Operator == @operator &&
|
||||
ItemOperationMis == itemOperationMis &&
|
||||
ExtractMis == extractMis;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all 16 valid search type combinations.
|
||||
/// </summary>
|
||||
public static IReadOnlyList<ValidCombination> GetAll() =>
|
||||
[
|
||||
new ValidCombination
|
||||
{
|
||||
Id = 10,
|
||||
Name = "Work Order",
|
||||
Timespan = false,
|
||||
WorkOrder = true,
|
||||
ItemNumber = false,
|
||||
ProfitCenter = false,
|
||||
WorkCenter = false,
|
||||
ComponentLot = false,
|
||||
Operator = false,
|
||||
ItemOperationMis = false,
|
||||
ExtractMis = false
|
||||
},
|
||||
new ValidCombination
|
||||
{
|
||||
Id = 20,
|
||||
Name = "Component Lot",
|
||||
Timespan = false,
|
||||
WorkOrder = false,
|
||||
ItemNumber = false,
|
||||
ProfitCenter = false,
|
||||
WorkCenter = false,
|
||||
ComponentLot = true,
|
||||
Operator = false,
|
||||
ItemOperationMis = false,
|
||||
ExtractMis = false
|
||||
},
|
||||
new ValidCombination
|
||||
{
|
||||
Id = 30,
|
||||
Name = "Time Span + Profit Center",
|
||||
Timespan = true,
|
||||
WorkOrder = false,
|
||||
ItemNumber = false,
|
||||
ProfitCenter = true,
|
||||
WorkCenter = false,
|
||||
ComponentLot = false,
|
||||
Operator = false,
|
||||
ItemOperationMis = false,
|
||||
ExtractMis = false
|
||||
},
|
||||
new ValidCombination
|
||||
{
|
||||
Id = 40,
|
||||
Name = "Time Span + Work Center",
|
||||
Timespan = true,
|
||||
WorkOrder = false,
|
||||
ItemNumber = false,
|
||||
ProfitCenter = false,
|
||||
WorkCenter = true,
|
||||
ComponentLot = false,
|
||||
Operator = false,
|
||||
ItemOperationMis = false,
|
||||
ExtractMis = false
|
||||
},
|
||||
new ValidCombination
|
||||
{
|
||||
Id = 50,
|
||||
Name = "Time Span + Operator",
|
||||
Timespan = true,
|
||||
WorkOrder = false,
|
||||
ItemNumber = false,
|
||||
ProfitCenter = false,
|
||||
WorkCenter = false,
|
||||
ComponentLot = false,
|
||||
Operator = true,
|
||||
ItemOperationMis = false,
|
||||
ExtractMis = false
|
||||
},
|
||||
new ValidCombination
|
||||
{
|
||||
Id = 60,
|
||||
Name = "Time Span + Profit Center + Item Number",
|
||||
Timespan = true,
|
||||
WorkOrder = false,
|
||||
ItemNumber = true,
|
||||
ProfitCenter = true,
|
||||
WorkCenter = false,
|
||||
ComponentLot = false,
|
||||
Operator = false,
|
||||
ItemOperationMis = false,
|
||||
ExtractMis = false
|
||||
},
|
||||
new ValidCombination
|
||||
{
|
||||
Id = 70,
|
||||
Name = "Time Span + Profit Center + Item/Operation/MIS",
|
||||
Timespan = true,
|
||||
WorkOrder = false,
|
||||
ItemNumber = false,
|
||||
ProfitCenter = true,
|
||||
WorkCenter = false,
|
||||
ComponentLot = false,
|
||||
Operator = false,
|
||||
ItemOperationMis = true,
|
||||
ExtractMis = false
|
||||
},
|
||||
new ValidCombination
|
||||
{
|
||||
Id = 80,
|
||||
Name = "Time Span + Profit Center + Work Order + Item/Operation/MIS",
|
||||
Timespan = true,
|
||||
WorkOrder = true,
|
||||
ItemNumber = false,
|
||||
ProfitCenter = true,
|
||||
WorkCenter = false,
|
||||
ComponentLot = false,
|
||||
Operator = false,
|
||||
ItemOperationMis = true,
|
||||
ExtractMis = false
|
||||
},
|
||||
new ValidCombination
|
||||
{
|
||||
Id = 90,
|
||||
Name = "Time Span + Profit Center + Extract MIS",
|
||||
Timespan = true,
|
||||
WorkOrder = false,
|
||||
ItemNumber = false,
|
||||
ProfitCenter = true,
|
||||
WorkCenter = false,
|
||||
ComponentLot = false,
|
||||
Operator = false,
|
||||
ItemOperationMis = false,
|
||||
ExtractMis = true
|
||||
},
|
||||
new ValidCombination
|
||||
{
|
||||
Id = 100,
|
||||
Name = "Time Span + Work Center + Item Number",
|
||||
Timespan = true,
|
||||
WorkOrder = false,
|
||||
ItemNumber = true,
|
||||
ProfitCenter = false,
|
||||
WorkCenter = true,
|
||||
ComponentLot = false,
|
||||
Operator = false,
|
||||
ItemOperationMis = false,
|
||||
ExtractMis = false
|
||||
},
|
||||
new ValidCombination
|
||||
{
|
||||
Id = 110,
|
||||
Name = "Time Span + Work Center + Extract MIS",
|
||||
Timespan = true,
|
||||
WorkOrder = false,
|
||||
ItemNumber = false,
|
||||
ProfitCenter = false,
|
||||
WorkCenter = true,
|
||||
ComponentLot = false,
|
||||
Operator = false,
|
||||
ItemOperationMis = false,
|
||||
ExtractMis = true
|
||||
},
|
||||
new ValidCombination
|
||||
{
|
||||
Id = 120,
|
||||
Name = "Time Span + Work Center + Item/Operation/MIS",
|
||||
Timespan = true,
|
||||
WorkOrder = false,
|
||||
ItemNumber = false,
|
||||
ProfitCenter = false,
|
||||
WorkCenter = true,
|
||||
ComponentLot = false,
|
||||
Operator = false,
|
||||
ItemOperationMis = true,
|
||||
ExtractMis = false
|
||||
},
|
||||
new ValidCombination
|
||||
{
|
||||
Id = 130,
|
||||
Name = "Time Span + Work Center + Work Order + Item/Operation/MIS",
|
||||
Timespan = true,
|
||||
WorkOrder = true,
|
||||
ItemNumber = false,
|
||||
ProfitCenter = false,
|
||||
WorkCenter = true,
|
||||
ComponentLot = false,
|
||||
Operator = false,
|
||||
ItemOperationMis = true,
|
||||
ExtractMis = false
|
||||
},
|
||||
new ValidCombination
|
||||
{
|
||||
Id = 140,
|
||||
Name = "Time Span + Item Number",
|
||||
Timespan = true,
|
||||
WorkOrder = false,
|
||||
ItemNumber = true,
|
||||
ProfitCenter = false,
|
||||
WorkCenter = false,
|
||||
ComponentLot = false,
|
||||
Operator = false,
|
||||
ItemOperationMis = false,
|
||||
ExtractMis = false
|
||||
},
|
||||
new ValidCombination
|
||||
{
|
||||
Id = 150,
|
||||
Name = "Time Span + Work Center + Operator",
|
||||
Timespan = true,
|
||||
WorkOrder = false,
|
||||
ItemNumber = false,
|
||||
ProfitCenter = false,
|
||||
WorkCenter = true,
|
||||
ComponentLot = false,
|
||||
Operator = true,
|
||||
ItemOperationMis = false,
|
||||
ExtractMis = false
|
||||
},
|
||||
new ValidCombination
|
||||
{
|
||||
Id = 160,
|
||||
Name = "Time Span + Profit Center + Operator",
|
||||
Timespan = true,
|
||||
WorkOrder = false,
|
||||
ItemNumber = false,
|
||||
ProfitCenter = true,
|
||||
WorkCenter = false,
|
||||
ComponentLot = false,
|
||||
Operator = true,
|
||||
ItemOperationMis = false,
|
||||
ExtractMis = false
|
||||
}
|
||||
];
|
||||
}
|
||||
Reference in New Issue
Block a user