26ff8d9b4f
Set up repository with legacy .NET Framework 4.8 source (OLD/), new .NET 10 Blazor solution (NEW/), OpenSpec specifications, documentation, and project configuration.
278 lines
10 KiB
Markdown
278 lines
10 KiB
Markdown
# 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
|