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,277 @@
|
||||
# Domain Models Design
|
||||
|
||||
## Overview
|
||||
|
||||
This document describes the design approach for implementing domain model entities in the JDE Scoping Tool .NET 10 migration.
|
||||
|
||||
## Project Organization
|
||||
|
||||
All domain models reside in the `JdeScoping.Core` project:
|
||||
|
||||
```
|
||||
JdeScoping.Core/
|
||||
├── Models/
|
||||
│ ├── Enums/
|
||||
│ │ ├── SearchStatus.cs # Search processing states
|
||||
│ │ └── UpdateTypes.cs # Data sync frequency types
|
||||
│ │
|
||||
│ ├── Search.cs # User search request entity
|
||||
│ ├── SearchCriteria.cs # Filter parameters for queries
|
||||
│ ├── SearchUpdate.cs # SignalR status update DTO
|
||||
│ │
|
||||
│ ├── WorkOrder.cs # JDE work order entity
|
||||
│ ├── WorkOrderStep.cs # Work order operation step
|
||||
│ ├── WorkOrderTime.cs # F31122 time transaction
|
||||
│ ├── WorkOrderComponent.cs # Component usage
|
||||
│ ├── WorkOrderRouting.cs # Step transaction
|
||||
│ │
|
||||
│ ├── Lot.cs # JDE lot entity
|
||||
│ ├── LotUsage.cs # Cardex consumption record
|
||||
│ ├── LotLocation.cs # Lot location tracking
|
||||
│ │
|
||||
│ ├── Item.cs # JDE item master
|
||||
│ ├── WorkCenter.cs # JDE work center (IBusinessUnit)
|
||||
│ ├── ProfitCenter.cs # JDE profit center (IBusinessUnit)
|
||||
│ ├── Branch.cs # JDE branch entity
|
||||
│ ├── JdeUser.cs # JDE operator entity
|
||||
│ ├── StatusCode.cs # Work order status lookup
|
||||
│ ├── FunctionCode.cs # Function code lookup
|
||||
│ │
|
||||
│ ├── DataUpdate.cs # Cache refresh tracking
|
||||
│ ├── OrgHierarchy.cs # Profit center to work center mapping
|
||||
│ ├── RouteMaster.cs # Item router master
|
||||
│ ├── StatusUpdate.cs # Generic process status message
|
||||
│ │
|
||||
│ ├── MisData.cs # CMS MIS data entity
|
||||
│ │
|
||||
│ ├── UserInfo.cs # Authenticated user info
|
||||
│ │
|
||||
│ ├── POReceiver.cs # PO receiver record
|
||||
│ ├── POInspect.cs # PO inspection record
|
||||
│ ├── DcsLot.cs # DCS lot record
|
||||
│ ├── CamstarMO.cs # Camstar manufacturing order
|
||||
│ │
|
||||
│ ├── QueryTypes.cs # Query type definitions
|
||||
│ ├── TableSpec.cs # Dynamic SQL table spec
|
||||
│ └── ColumnSpec.cs # Column specification
|
||||
│
|
||||
├── Interfaces/
|
||||
│ └── IBusinessUnit.cs # WorkCenter/ProfitCenter interface
|
||||
│
|
||||
├── ViewModels/
|
||||
│ ├── WorkOrderViewModel.cs # WorkOrder projection
|
||||
│ ├── LotViewModel.cs # Lot projection
|
||||
│ ├── ItemViewModel.cs # Item projection
|
||||
│ ├── WorkCenterViewModel.cs # WorkCenter projection
|
||||
│ ├── ProfitCenterViewModel.cs # ProfitCenter projection
|
||||
│ ├── JdeUserViewModel.cs # JdeUser projection
|
||||
│ └── PartOperationViewModel.cs # Item/operation/MIS combination
|
||||
│
|
||||
├── Extensions/
|
||||
│ ├── WorkOrderExtensions.cs # WorkOrder.ToViewModel()
|
||||
│ ├── LotExtensions.cs # Lot.ToViewModel()
|
||||
│ ├── ItemExtensions.cs # Item.ToViewModel()
|
||||
│ ├── WorkCenterExtensions.cs # WorkCenter.ToViewModel()
|
||||
│ ├── ProfitCenterExtensions.cs # ProfitCenter.ToViewModel()
|
||||
│ └── JdeUserExtensions.cs # JdeUser.ToViewModel()
|
||||
│
|
||||
└── Helpers/
|
||||
└── JdeDateConverter.cs # JDE date/time conversion
|
||||
```
|
||||
|
||||
## Design Patterns
|
||||
|
||||
### Nullable Reference Types
|
||||
|
||||
The project has `<Nullable>enable</Nullable>` in the .csproj. All properties follow these patterns:
|
||||
|
||||
| Pattern | Example | Usage |
|
||||
|---------|---------|-------|
|
||||
| Required property | `public string Name { get; set; } = string.Empty;` | Non-null, initialized |
|
||||
| Optional property | `public string? Description { get; set; }` | Explicitly nullable |
|
||||
| Collection property | `public List<string> Items { get; set; } = [];` | Never null, empty default |
|
||||
| Nullable byte array | `public byte[]? Results { get; set; }` | Null until populated |
|
||||
|
||||
### System.Text.Json Serialization
|
||||
|
||||
All enums that may be serialized use the string converter:
|
||||
|
||||
```csharp
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
[JsonConverter(typeof(JsonStringEnumConverter))]
|
||||
public enum SearchStatus
|
||||
{
|
||||
New = 0,
|
||||
Submitted = 1,
|
||||
Started = 2,
|
||||
Ended = 3,
|
||||
Error = 4
|
||||
}
|
||||
```
|
||||
|
||||
This ensures JSON output is `"Status": "Ended"` instead of `"Status": 3`.
|
||||
|
||||
### JDE Date Conversion Pattern
|
||||
|
||||
JDE stores dates as integers in CYYDDD format (century + year + day of year) and times as HHMMSS:
|
||||
|
||||
```csharp
|
||||
public static class JdeDateConverter
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts JDE date (CYYDDD) and time (HHMMSS) to DateTime.
|
||||
/// Returns null for zero or invalid values (changed from legacy 1900-01-01).
|
||||
/// </summary>
|
||||
public static DateTime? ToDateTime(int jdeDate, int jdeTime = 0)
|
||||
{
|
||||
if (jdeDate <= 0)
|
||||
return null;
|
||||
|
||||
try
|
||||
{
|
||||
// CYYDDD format: C = century (0=1900s, 1=2000s), YY = year, DDD = day of year
|
||||
int century = jdeDate / 100000;
|
||||
int yearInCentury = (jdeDate / 1000) % 100;
|
||||
int dayOfYear = jdeDate % 1000;
|
||||
|
||||
int year = 1900 + (century * 100) + yearInCentury;
|
||||
|
||||
if (dayOfYear < 1 || dayOfYear > 366)
|
||||
return null;
|
||||
|
||||
var date = new DateTime(year, 1, 1).AddDays(dayOfYear - 1);
|
||||
|
||||
// Add time component if provided
|
||||
if (jdeTime > 0)
|
||||
{
|
||||
int hours = jdeTime / 10000;
|
||||
int minutes = (jdeTime / 100) % 100;
|
||||
int seconds = jdeTime % 100;
|
||||
|
||||
if (hours >= 0 && hours < 24 && minutes >= 0 && minutes < 60 && seconds >= 0 && seconds < 60)
|
||||
{
|
||||
date = date.AddHours(hours).AddMinutes(minutes).AddSeconds(seconds);
|
||||
}
|
||||
}
|
||||
|
||||
return date;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Entity Computed Properties
|
||||
|
||||
Entities with JDE date fields use private backing fields and computed public properties:
|
||||
|
||||
```csharp
|
||||
public class WorkOrder
|
||||
{
|
||||
// Private backing fields (mapped from database via Dapper)
|
||||
private int LastUpdateDate { get; set; }
|
||||
private int LastUpdateTime { get; set; }
|
||||
|
||||
// Public computed property
|
||||
public DateTime? LastUpdateDT => JdeDateConverter.ToDateTime(LastUpdateDate, LastUpdateTime);
|
||||
|
||||
// Other properties...
|
||||
public long WorkOrderNumber { get; set; }
|
||||
public string ItemNumber { get; set; } = string.Empty;
|
||||
}
|
||||
```
|
||||
|
||||
### ToViewModel Extension Methods
|
||||
|
||||
Projections are implemented as extension methods for separation of concerns:
|
||||
|
||||
```csharp
|
||||
public static class WorkOrderExtensions
|
||||
{
|
||||
public static WorkOrderViewModel ToViewModel(this WorkOrder workOrder)
|
||||
{
|
||||
return new WorkOrderViewModel
|
||||
{
|
||||
WorkOrderNumber = workOrder.WorkOrderNumber,
|
||||
ItemNumber = workOrder.ItemNumber
|
||||
};
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### IBusinessUnit Interface
|
||||
|
||||
WorkCenter and ProfitCenter share a common interface:
|
||||
|
||||
```csharp
|
||||
public interface IBusinessUnit
|
||||
{
|
||||
string Code { get; }
|
||||
string Description { get; }
|
||||
DateTime? LastUpdateDT { get; }
|
||||
}
|
||||
|
||||
public class WorkCenter : IBusinessUnit
|
||||
{
|
||||
public string Code { get; set; } = string.Empty;
|
||||
public string Description { get; set; } = string.Empty;
|
||||
|
||||
private int LastUpdateDate { get; set; }
|
||||
private int LastUpdateTime { get; set; }
|
||||
public DateTime? LastUpdateDT => JdeDateConverter.ToDateTime(LastUpdateDate, LastUpdateTime);
|
||||
}
|
||||
```
|
||||
|
||||
## Classes vs Records
|
||||
|
||||
| Type | Pattern | Rationale |
|
||||
|------|---------|-----------|
|
||||
| Database entities | `class` | Mutable for Dapper mapping, private setters for computed fields |
|
||||
| ViewModels | `record` or `class` | Immutable DTOs, but class is fine for simple projections |
|
||||
| SearchUpdate | `class` with init | Constructor sets Timestamp to UtcNow |
|
||||
| Enums | `enum` | Standard enumeration with JsonStringEnumConverter |
|
||||
|
||||
## Existing Code Reconciliation
|
||||
|
||||
The existing `JdeScoping.Core/Models/` contains placeholder implementations that differ from the spec:
|
||||
|
||||
| Existing File | Action | Notes |
|
||||
|---------------|--------|-------|
|
||||
| Search.cs | Replace | Different property names, missing CriteriaJSON/Criteria pattern |
|
||||
| WorkOrder.cs | Replace | Simplified placeholder, missing JDE-specific fields |
|
||||
| Item.cs | Replace | Missing ShortItemNumber, nullable annotations |
|
||||
| Lot.cs | Replace | Placeholder implementation |
|
||||
| LotUsage.cs | Replace | Placeholder implementation |
|
||||
| WorkCenter.cs | Replace | Missing IBusinessUnit interface |
|
||||
| JdeUser.cs | Replace | Placeholder implementation |
|
||||
|
||||
## Migration from Legacy
|
||||
|
||||
| Legacy Pattern | New Pattern | Rationale |
|
||||
|----------------|-------------|-----------|
|
||||
| `DataModel.Models` namespace | `JdeScoping.Core.Models` | .NET naming conventions |
|
||||
| Newtonsoft.Json attributes | System.Text.Json attributes | Built-in .NET serialization |
|
||||
| `[JsonConverter(typeof(StringEnumConverter))]` | `[JsonConverter(typeof(JsonStringEnumConverter))]` | System.Text.Json |
|
||||
| `LDAPEntry` class | `UserInfo` class | Modern auth pattern naming |
|
||||
| Invalid JDE dates -> 1900-01-01 | Invalid JDE dates -> null | Explicit null handling |
|
||||
| ToViewModel() on entity | Extension method | Separation of concerns |
|
||||
|
||||
## File Structure Summary
|
||||
|
||||
After implementation, the Models folder structure:
|
||||
|
||||
```
|
||||
JdeScoping.Core/Models/
|
||||
├── Enums/ (2 files)
|
||||
├── [Entity classes] (27 files)
|
||||
├── Interfaces/ (1 file - moved from Models)
|
||||
├── ViewModels/ (7 files)
|
||||
├── Extensions/ (6 files)
|
||||
└── Helpers/ (1 file)
|
||||
```
|
||||
|
||||
Total: ~44 new/modified files in JdeScoping.Core
|
||||
Reference in New Issue
Block a user