Files
jdescopingtool/openspec/specs/domain-models/spec.md
T
Joseph Doherty 26ff8d9b4f 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.
2026-01-02 07:43:29 -05:00

41 KiB

Domain Models Specification

Purpose

The domain model layer defines the core business entities used throughout the JDE Scoping Tool application, targeting .NET 10 with modern C# patterns. These models represent manufacturing/ERP data from JD Edwards (JDE) and CMS (Sybase) enterprise systems, cached locally in SQL Server for efficient searching. The models serve three primary purposes:

  1. Entity representation - Map database tables to strongly-typed C# classes with nullable reference type annotations
  2. Search criteria - Define filter parameters for complex manufacturing queries
  3. Data transfer - Support serialization for API communication via System.Text.Json and SignalR

Source Reference

Legacy Files Purpose
OLD/DataModel/Models/Search.cs User search request with criteria and results
OLD/DataModel/Models/SearchCriteria.cs JDE data filter criteria definition
OLD/DataModel/Models/SearchStatus.cs Search status enumeration
OLD/DataModel/Models/SearchUpdate.cs SignalR status update message
OLD/DataModel/Models/WorkOrder.cs JDE work order entity
OLD/DataModel/Models/Lot.cs JDE lot entity
OLD/DataModel/Models/LotUsage.cs Cardex entry (lot consumption record)
OLD/DataModel/Models/LotLocation.cs JDE lot location entity
OLD/DataModel/Models/Item.cs JDE item (part type) entity
OLD/DataModel/Models/WorkCenter.cs JDE work center entity
OLD/DataModel/Models/ProfitCenter.cs JDE profit center entity
OLD/DataModel/Models/JdeUser.cs JDE user (operator) entity
OLD/DataModel/Models/Branch.cs JDE branch entity
OLD/DataModel/Models/WorkOrderStep.cs JDE work order step entity
OLD/DataModel/Models/WorkOrderTime.cs F31122 work order time transaction
OLD/DataModel/Models/WorkOrderRouting.cs Work order step transaction
OLD/DataModel/Models/WorkOrderComponent.cs Work order component usage
OLD/DataModel/Models/DataUpdate.cs Cache data update tracking
OLD/DataModel/Models/StatusUpdate.cs Process status update message
OLD/DataModel/Models/StatusCode.cs JDE work order status code
OLD/DataModel/Models/FunctionCode.cs JDE function code
OLD/DataModel/Models/OrgHierarchy.cs Profit center to work center mapping
OLD/DataModel/Models/RouteMaster.cs JDE item router master
OLD/DataModel/Models/MisData.cs CMS MIS data entity
OLD/DataModel/Models/POReceiver.cs JDE PO receiver record
OLD/DataModel/Models/POInspect.cs JDE PO inspect record
OLD/DataModel/Models/DcsLot.cs DCS lot record
OLD/DataModel/Models/CamstarMO.cs Camstar manufacturing order
OLD/DataModel/Models/LDAPEntry.cs LDAP search result (renamed to UserInfo)
OLD/DataModel/Models/IBusinessUnit.cs Business unit interface
OLD/DataModel/Models/QueryTypes.cs Query type definitions
OLD/DataModel/Models/TableSpec.cs Database table specification
OLD/DataModel/Models/ColumnSpec.cs Database column specification

Requirements

Requirement: Search entity

The system SHALL store user search requests containing filter criteria and resulting Excel output, with lazy deserialization of criteria from JSON.

Properties

Property Type Description
ID int Primary key identifier
UserName string Username of user who created search
Name string User-friendly name for the search
Status SearchStatus Current search status (enum)
SubmitDT DateTime? Timestamp when search was submitted
StartDT DateTime? Timestamp when search processing started
EndDT DateTime? Timestamp when search completed
CriteriaJSON string JSON-serialized search criteria
Criteria SearchCriteria Deserialized search criteria object
Results byte[]? Excel file output (VARBINARY), nullable when not yet generated

Business Rules

  • Status MUST be serialized as string using [JsonConverter(typeof(JsonStringEnumConverter))]
  • Criteria is stored as JSON in CriteriaJSON for database persistence
  • Criteria property getter deserializes from CriteriaJSON using System.Text.Json
  • Setter serializes to CriteriaJSON
  • If CriteriaJSON is null or empty, Criteria returns a new empty SearchCriteria
  • Deserialization errors return empty SearchCriteria (fail gracefully)
  • Results contains binary Excel file data only when Status = Ended
  • Results property MUST be annotated as byte[]? since it is null until processing completes

Scenario: Lazy deserialization of Criteria

  • WHEN Search.CriteriaJSON = '{"MinimumDT":"2024-01-01"}' and Criteria is accessed
  • THEN Criteria.MinimumDT = 2024-01-01

Scenario: Handle empty CriteriaJSON

  • WHEN Search.CriteriaJSON = null and Criteria is accessed
  • THEN Criteria returns new SearchCriteria() with all empty lists

Requirement: SearchCriteria entity

The system SHALL provide filter parameters for querying JDE/CMS data.

Properties

Property Type Description
MinimumDT DateTime? Minimum timestamp to include
MaximumDT DateTime? Maximum timestamp to include
WorkOrderNumbers List<long> Work order numbers to filter
ItemNumbers List<string> Item numbers to filter
ProfitCenters List<string> Profit center codes to filter
WorkCenters List<string> Work center codes to filter
OperatorIDs List<string> Operator IDs to filter
ComponentLotNumbers List<LotViewModel> Component lot numbers to filter
ExtractMisData bool Whether to extract MIS data
PartOperations List<PartOperationViewModel> Part/operation combinations for MIS filtering

Business Rules

  • All list properties MUST be initialized to empty lists in constructor
  • Note: Legacy has no validation - filter criteria can all be empty (validation is application-layer decision)
  • ComponentLotNumbers references LotViewModel (lot number + item number pair)
  • PartOperations references PartOperationViewModel (item number + operation number + MIS number + revision)

Scenario: Filter by work order numbers

  • WHEN search criteria has WorkOrderNumbers = [123456, 789012] and search executes
  • THEN only records matching those work order numbers are returned

Scenario: Filter by date range

  • WHEN search criteria has MinimumDT = 2024-01-01 and MaximumDT = 2024-12-31 and search executes
  • THEN only records within that date range are returned

Requirement: SearchStatus enumeration

The system SHALL provide an enumeration of search processing states.

Values

Value Code Description
New 0 Search created but not submitted
Submitted 1 Search queued for processing
Started 2 Search processing in progress
Ended 3 Search completed successfully
Error 4 Search failed with error

Business Rules

  • Status transitions follow: New -> Submitted -> Started -> (Ended | Error)
  • MUST be serialized as string in JSON (not integer) using [JsonConverter(typeof(JsonStringEnumConverter))]

Example: System.Text.Json enum serialization

using System.Text.Json.Serialization;

[JsonConverter(typeof(JsonStringEnumConverter))]
public enum SearchStatus
{
    New = 0,
    Submitted = 1,
    Started = 2,
    Ended = 3,
    Error = 4
}

Scenario: Valid status transition

  • WHEN a search has Status = Submitted and processing begins
  • THEN Status can transition to Started

Scenario: Serialize status as string

  • WHEN a search has Status = Ended and is serialized to JSON
  • THEN status appears as "Ended" (string), not 3 (integer)

Requirement: SearchUpdate entity

The system SHALL provide a real-time status update message for ASP.NET Core SignalR broadcast with factory method construction.

Properties

Property Type Description
ID int Search primary key
UserName string Username of search submitter
Name string Search name
Status SearchStatus Current status
SubmitDT DateTime? Submit timestamp
StartDT DateTime? Start timestamp
EndDT DateTime? End timestamp
Timestamp DateTime When update was generated
HasResults bool Indicates if search has Results

Business Rules

  • Primary constructor: SearchUpdate(Search search) copies all fields and sets Timestamp
  • Timestamp MUST be set to DateTime.UtcNow when update is created
  • Status MUST be serialized as string for JSON via [JsonConverter(typeof(JsonStringEnumConverter))]
  • HasResults is computed: Status == SearchStatus.Ended && search.Results != null
  • WHEN SearchUpdate is created from a Search with ID=1, Status=Ended
  • THEN SearchUpdate.ID = 1, SearchUpdate.Status = Ended, SearchUpdate.Timestamp = current UTC time

Scenario: HasResults computation

  • WHEN SearchUpdate is created from Search with Status=Ended and Results is not null
  • THEN HasResults = true

Requirement: WorkOrder entity

The system SHALL provide a JDE work order entity representing a manufacturing order.

Properties

Property Type Description
WorkOrderNumber long Unique work order identifier
BranchCode string Branch/plant code
LotNumber string? Assigned lot number (nullable)
ItemNumber string Product item number
ShortItemNumber long Numeric item identifier
ParentWorkOrderNumber string? Parent work order (if sub-assembly, nullable)
OrderQuantity decimal Quantity ordered
HeldQuantity decimal Quantity on hold
ShippedQuantity decimal Quantity shipped
StatusCode string Work order status
StatusCodeUpdateDT DateTime? Last status update timestamp
IssueDate DateTime Date work order was issued
StartDate DateTime Date work order was started
RoutingType string Routing type code
LastUpdateDT DateTime Computed from JDE date/time fields

Relationships

  • References Item via ItemNumber/ShortItemNumber
  • References Branch via BranchCode
  • References StatusCode via StatusCode
  • Parent-child relationship via ParentWorkOrderNumber
  • Has many WorkOrderStep records
  • Has many WorkOrderTime records
  • Has many WorkOrderComponent records
  • Has many LotUsage records

Business Rules

  • LastUpdateDT is computed property using JDE date conversion helpers
  • LastUpdateDate and LastUpdateTime are private (JDE-specific format)
  • ToViewModel() projects to WorkOrderViewModel (WorkOrderNumber, ItemNumber)
  • LotNumber and ParentWorkOrderNumber SHOULD be annotated as nullable (string?)

Scenario: Create work order from JDE data

  • WHEN JDE data has LastUpdateDate = 124365 and LastUpdateTime = 143052 and is mapped to WorkOrder entity
  • THEN LastUpdateDT = 2024-12-30 14:30:52

Scenario: Navigate to parent work order

  • WHEN work order 12345 has ParentWorkOrderNumber = "11111" and the parent-child relationship is traversed
  • THEN the parent work order 11111 is accessible

Scenario: Project to ViewModel

  • WHEN a WorkOrder with WorkOrderNumber = 12345, ItemNumber = "ABC123" calls ToViewModel()
  • THEN WorkOrderViewModel contains only WorkOrderNumber and ItemNumber

Requirement: Lot entity

The system SHALL provide a JDE lot entity representing a tracked batch of materials.

Properties

Property Type Description
LotNumber string Unique lot identifier
BranchCode string Business unit code
ShortItemNumber long Numeric item identifier
ItemNumber string Item number
SupplierCode long Supplier address number
StatusCode char Single-character lot status
Memo1 string? Memo line 1 (nullable)
Memo2 string? Memo line 2 (nullable)
Memo3 string? Memo line 3 (nullable)
LastUpdateDT DateTime Computed from JDE date/time

Relationships

  • References Item via ItemNumber/ShortItemNumber
  • References Branch via BranchCode
  • Has many LotLocation records
  • Has many LotUsage records

Business Rules

  • StatusCode is single character (not string)
  • ToViewModel() projects to LotViewModel (LotNumber, ItemNumber)
  • Memo fields SHOULD be annotated as nullable (string?)

Scenario: Lot with single-character status

  • WHEN a lot has StatusCode = 'A' (active) and the lot entity is read
  • THEN StatusCode is char type, not string

Scenario: Project lot to ViewModel

  • WHEN a Lot with LotNumber = "LOT001", ItemNumber = "ITEM123" calls ToViewModel()
  • THEN LotViewModel contains LotNumber and ItemNumber only

Requirement: LotUsage entity

The system SHALL provide a cardex entry recording component consumption in work orders.

Properties

Property Type Description
UniqueID long Primary key identifier
WorkOrderNumber long Associated work order
LotNumber string Component lot number
BranchCode string Branch code
ShortItemNumber long Component item number
Quantity decimal Transaction quantity
LastUpdateDT DateTime Computed from JDE date/time

Relationships

  • References WorkOrder via WorkOrderNumber
  • References Lot via LotNumber
  • References Item via ShortItemNumber

Requirement: LotLocation entity

The system SHALL provide JDE lot location tracking.

Properties

Property Type Description
LotNumber string Lot identifier
ShortItemNumber long Item identifier
BranchCode string Business unit code
Location string Physical location code
LastUpdateDT DateTime Last update timestamp

Relationships

  • References Lot via LotNumber
  • References Item via ShortItemNumber
  • References Branch via BranchCode

Requirement: Item entity

The system SHALL provide a JDE item (part type) master entity.

Properties

Property Type Description
ShortItemNumber long Unique numeric identifier
ItemNumber string Alphanumeric item number
Description string Item description
PlanningFamily string? Master planning family (nullable)
StockingType string? Stocking type code (nullable)
LastUpdateDT DateTime Computed from JDE date/time

Business Rules

  • ShortItemNumber is the numeric key used in JDE joins
  • ItemNumber is the human-readable identifier
  • ToViewModel() projects to ItemViewModel (ItemNumber, Description)

Scenario: Dual identifier pattern

  • WHEN an item has ShortItemNumber = 12345 and ItemNumber = "ABC-123" and joins with work orders
  • THEN ShortItemNumber is used for database joins and ItemNumber is displayed to users

Requirement: WorkCenter entity

The system SHALL provide a JDE work center entity (implements IBusinessUnit).

Properties

Property Type Description
Code string Unique work center code
Description string Work center description
LastUpdateDT DateTime Computed from JDE date/time

Business Rules

  • Implements IBusinessUnit interface
  • ToViewModel() projects to WorkCenterViewModel (Code, Description)

Requirement: ProfitCenter entity

The system SHALL provide a JDE profit center entity (implements IBusinessUnit).

Properties

Property Type Description
Code string Unique profit center code
Description string Profit center description
LastUpdateDT DateTime Computed from JDE date/time

Business Rules

  • Implements IBusinessUnit interface
  • ToViewModel() projects to ProfitCenterViewModel (Code, Description)

Requirement: JdeUser entity

The system SHALL provide a JDE user (operator) entity.

Properties

Property Type Description
AddressNumber long Unique address number
UserID string Login identifier
FullName string Full name (last, first [middle])
LastUpdateDT DateTime Computed from JDE date/time

Business Rules

  • AddressNumber is the JDE primary key
  • UserID is the login identifier
  • ToViewModel() projects to JdeUserViewModel (AddressNumber, UserID, FullName)

Requirement: Branch entity

The system SHALL provide a JDE branch entity.

Properties

Property Type Description
Code string Unique branch code
Description string Branch description
LastUpdateDT DateTime Computed from JDE date/time

Requirement: IBusinessUnit interface

The system SHALL provide an interface for business unit entities (WorkCenter, ProfitCenter).

Properties

Property Type Description
Code string Business unit unique code
Description string Business unit description
LastUpdateDT DateTime Last update timestamp

Requirement: WorkOrderStep entity

The system SHALL provide a JDE work order operation step.

Properties

Property Type Description
WorkOrderNumber long Work order identifier
BranchCode string Branch code
WorkCenterCode string Work center code
StepNumber decimal Operation sequence number
StepDescription string? Step description (nullable)
FunctionOperationDescription string? Long text description (nullable)
StepTypeCode string Operation type
StartDT DateTime? Step start timestamp
EndDT DateTime? Step end timestamp
FunctionCode string Operation function code
ScrappedQuantity decimal Quantity scrapped/cancelled
LastUpdateDT DateTime Computed from JDE date/time

Relationships

  • References WorkOrder via WorkOrderNumber
  • References WorkCenter via WorkCenterCode
  • References FunctionCode via FunctionCode

Requirement: WorkOrderTime entity

The system SHALL provide an F31122 work order time transaction record.

Properties

Property Type Description
UniqueID long Primary key
WorkOrderNumber long Work order identifier
BranchCode string Branch code
WorkCenterCode string Work center code
StepNumber decimal Operation sequence
AddressNumber long Operator address number
GlDate DateTime? G/L processing date
LastUpdateDT DateTime Computed from JDE date/time

Relationships

  • References WorkOrder via WorkOrderNumber
  • References JdeUser via AddressNumber
  • References WorkCenter via WorkCenterCode

Requirement: WorkOrderRouting entity

The system SHALL provide a work order step transaction model.

Properties

Property Type Description
UserID string Transaction user ID
BatchNumber string Transaction batch number
TransactionNumber string Transaction number
LineNumber int Transaction line number
StepNumber decimal Operation sequence
WorkCenterCode string Work center code
WorkOrderNumber long Work order identifier
RoutingType string Routing type
BranchCode string Branch code
StepDescription string? Step description (nullable)
FunctionCode string Function code
TransactionDate DateTime Transaction original date
LastUpdateDT DateTime Computed from JDE date/time

Requirement: WorkOrderComponent entity

The system SHALL provide a work order component usage model.

Properties

Property Type Description
UniqueID long Primary key
WorkOrderNumber long Work order identifier
LotNumber string? Component lot number (nullable)
BranchCode string Branch code
ShortItemNumber long? Component item (nullable)
Quantity decimal Transaction quantity
LastUpdateDT DateTime Computed from JDE date/time

Business Rules

  • ShortItemNumber is nullable (unlike LotUsage)
  • LotNumber SHOULD be annotated as nullable (string?)

Requirement: DataUpdate entity

The system SHALL provide a cache data update tracking entity.

Properties

Property Type Description
ID int Primary key
SourceSystem string Source system name (JDE/CMS)
SourceData string Source data type
TableName string Cache table name
StartDT DateTime Update start timestamp
EndDT DateTime Update end timestamp
UpdateType UpdateTypes Type of update (enum)
WasSuccessful bool Success indicator
NumberRecords long Record count

Business Rules

  • UpdateTypes enum: Hourly (1), Daily (2), Mass (3)
  • Used to track cache refresh status and timing
  • UpdateType MUST use [JsonConverter(typeof(JsonStringEnumConverter))] if serialized

Scenario: Track successful daily update

  • WHEN a daily sync of WorkOrder table completes and DataUpdate is created
  • THEN SourceSystem = "JDE", UpdateType = Daily (2), WasSuccessful = true

Scenario: Track failed mass update

  • WHEN a mass refresh fails with error and DataUpdate is created
  • THEN WasSuccessful = false, NumberRecords = 0

Requirement: UpdateTypes enumeration

The system SHALL provide an enumeration for data update frequency types.

Values

Value Code Description
Hourly 1 Hourly incremental update
Daily 2 Daily incremental update
Mass 3 Full data refresh

Business Rules

  • SHOULD use [JsonConverter(typeof(JsonStringEnumConverter))] if serialized to JSON

Requirement: StatusUpdate entity

The system SHALL provide a generic process status update message (not search-specific).

Properties

Property Type Description
Message string Update message text
Timestamp DateTime Message timestamp

Requirement: StatusCode entity

The system SHALL provide a JDE work order status code lookup.

Properties

Property Type Description
Code string Unique status code
Description string Status description
LastUpdateDT DateTime Computed from JDE date/time

Requirement: FunctionCode entity

The system SHALL provide a JDE function code lookup.

Properties

Property Type Description
Code string Unique function code
Description string Function description
LastUpdateDT DateTime Last update timestamp

Requirement: OrgHierarchy entity

The system SHALL provide organization hierarchy mapping (profit center to work center).

Properties

Property Type Description
WorkCenterCode string Work center code
BranchCode string Branch unit code
ProfitCenterCode string Profit center code
LastUpdateDT DateTime Computed from JDE date/time

Relationships

  • Maps WorkCenter to ProfitCenter
  • References Branch via BranchCode

Requirement: RouteMaster entity

The system SHALL provide a JDE item router master entity.

Properties

Property Type Description
BranchCode string Branch code
ItemNumber string Item number
RoutingType string Router type
SequenceNumber decimal Job step number
FunctionCode string Function code
WorkCenterCode string Work center code
StartDate DateTime Effectivity start date
EndDate DateTime? Effectivity end date (nullable)
LastUpdateDT DateTime Computed from JDE date/time

Business Rules

  • StartDate_Date and EndDate_Date store JDE integer format
  • StartDate and EndDate are computed properties using JDE conversion

Requirement: MisData entity

The system SHALL provide a CMS MIS (Manufacturing Information System) data entity.

Properties

Property Type Description
ItemNumber string Item number
BranchCode string Branch code
SequenceNumber string Operation job step number
MisNumber string MIS unique number
RevID string? MIS revision ID (nullable)
CharNumber string Characteristic number
TestDescription string? Test description (nullable)
SamplingType string? Type of sampling (nullable)
SamplingValue string? Sampling selection value (nullable)
ToolsGauges string? Tools and gauges (nullable)
WorkInstructions string? Work instructions (nullable)
Status string Release status
ReleaseDate DateTime? Release date

Business Rules

  • Sourced from CMS (Sybase), not JDE (Oracle)
  • Only extracted when SearchCriteria.ExtractMisData = true
  • Many string fields SHOULD be annotated as nullable (string?)

Scenario: Extract MIS data when requested

  • WHEN SearchCriteria has ExtractMisData = true and search executes
  • THEN MisData records are fetched from CMS Sybase

Scenario: Skip MIS data when not requested

  • WHEN SearchCriteria has ExtractMisData = false and search executes
  • THEN MisData query is skipped (performance optimization)

Requirement: POReceiver entity

The system SHALL provide a JDE purchase order receiver record.

Properties

Property Type Description
OrderNumber long PO number
OrderCompany string PO company code
OrderSuffix string PO suffix
LineNumber decimal Line number
NumberOfLines int Total lines in PO
InvoiceNumber long Invoice number
BranchCode string Receiving site
LotNumber string? Product lot number (nullable)
ShortItemNumber string Item number (string - legacy type)
DateReceived DateTime Receipt date
Subledger string? Subledger name (nullable)
QtyReceived decimal Quantity received
LastUpdateDT DateTime Last update timestamp

Requirement: POInspect entity

The system SHALL provide a JDE purchase order inspection record.

Properties

Property Type Description
UniqueID long Primary key
OrderNumber long PO number
OrderCompany string Company code
LineNumber decimal Line number
InvoiceNumber long Invoice number
LotNumber string? Lot number (nullable)
ShortItemNumber string Item number
LastUpdateDT DateTime Last update timestamp

Requirement: DcsLot entity

The system SHALL provide a DCS lot record entity.

Properties

Property Type Description
ItemNumber string Item number
LotNumber string Lot number
LotSuffix string? Lot suffix (nullable)
LastUpdateDT DateTime Last update timestamp

Requirement: CamstarMO entity

The system SHALL provide a Camstar manufacturing order entity.

Properties

Property Type Description
MONumber string Manufacturing order number
LastUpdateDT DateTime Last update timestamp

Requirement: UserInfo entity

The system SHALL provide authenticated user information with computed display name for ASP.NET Core Identity integration.

Properties

Property Type Description
Username string User's login identifier
FirstName string? User's first name (nullable)
LastName string? User's last name (nullable)
DisplayName string Computed display name
Title string? Organization title (nullable)
EmailAddress string? Email address (nullable)

Business Rules

  • DisplayName computation:
    1. If FirstName and LastName both have values: $"{FirstName} {LastName}".Trim()
    2. If only FirstName has value: FirstName.Trim()
    3. If only LastName has value: LastName.Trim()
    4. Otherwise: Username
  • "Has value" means not null and not whitespace-only
  • Used for authentication context, populated from ASP.NET Core Identity claims or LDAP provider
  • DN (Distinguished Name) property removed; use ClaimsPrincipal for identity information

Scenario: Compute display name from both names

  • WHEN UserInfo has FirstName = "John", LastName = "Doe" and DisplayName is accessed
  • THEN DisplayName = "John Doe"

Scenario: Compute display name from first name only

  • WHEN UserInfo has FirstName = "John", LastName = null and DisplayName is accessed
  • THEN DisplayName = "John"

Scenario: Fallback to username when names empty

  • WHEN UserInfo has FirstName = null, LastName = null, Username = "jdoe" and DisplayName is accessed
  • THEN DisplayName = "jdoe"

Requirement: QueryTypes entity

The system SHALL provide query type definitions for search filtering.

Properties

Property Type Description
Code string Query type code
Name string Query type name
OrderIndex int Display order
TimeSpanFilter bool Supports date range filter
WorkOrderFilter bool Supports work order filter
ItemNumberFilter bool Supports item filter
ProfitCenterFilter bool Supports profit center filter
WorkCenterFilter bool Supports work center filter
ComponentLotFilter bool Supports lot filter
OperatorFilter bool Supports operator filter
ItemOperationMISFilter bool Supports item/operation MIS filter
ExtractMISFilter bool Supports MIS extraction
ReceivedItemNumberIISFilter bool Supports received item filter

Business Rules

  • Uses static dictionary for type registration
  • Identify() method maps SearchCriteria to QueryTypes (stub implementation)
  • Predefined type: WorkOrder with WorkOrderFilter = true

Requirement: TableSpec entity

The system SHALL provide a database table specification for dynamic SQL generation.

Properties

Property Type Description
Name string Table name
TempTableName string Computed: #{Name}
Columns List<ColumnSpec> Table columns
PrimaryKey List<ColumnSpec> Primary key columns

Business Rules

  • Constructor initializes Columns and PrimaryKey to empty lists
  • Stub methods: GenerateIndex(), GenerateDrop(), GenerateCreate(), GetColumn()

Requirement: ColumnSpec entity

The system SHALL provide a database column specification.

Properties

Property Type Description
Name string Column name
Definition string Column definition

Requirement: JdeDateConverter helper class

The system SHALL provide a static helper class for converting JDE date/time formats to .NET DateTime.

Methods

Method Signature Description
ToDateTime DateTime? ToDateTime(int jdeDate, int jdeTime = 0) Converts JDE CYYDDD date and HHMMSS time to DateTime

Business Rules

  • Returns null for zero or invalid date values (not 1900-01-01)
  • CYYDDD format: C = century (0=1900s, 1=2000s), YY = year, DDD = day of year
  • HHMMSS format: HH = hours (0-23), MM = minutes (0-59), SS = seconds (0-59)
  • Invalid time values are ignored (date portion still returned)
  • Parse errors return null rather than throwing exceptions

Scenario: Convert valid JDE date

  • WHEN JdeDateConverter.ToDateTime(124365, 143052) is called
  • THEN returns DateTime 2024-12-30 14:30:52

Scenario: Handle zero date

  • WHEN JdeDateConverter.ToDateTime(0, 0) is called
  • THEN returns null

Scenario: Handle invalid day of year

  • WHEN JdeDateConverter.ToDateTime(124400, 0) is called (day 400 is invalid)
  • THEN returns null

Requirement: Extension method file organization

The system SHALL organize ToViewModel extension methods in separate files by entity type.

File Structure

File Extension Methods
WorkOrderExtensions.cs WorkOrder.ToViewModel()
LotExtensions.cs Lot.ToViewModel()
ItemExtensions.cs Item.ToViewModel()
WorkCenterExtensions.cs WorkCenter.ToViewModel()
ProfitCenterExtensions.cs ProfitCenter.ToViewModel()
JdeUserExtensions.cs JdeUser.ToViewModel()

Business Rules

  • Extension methods in JdeScoping.Core.Extensions namespace
  • Each file contains a single static class with extension methods for one entity type
  • Extension methods are the only way entities project to ViewModels (no methods on entities)

Scenario: Use extension method for projection

  • WHEN a WorkOrder entity calls ToViewModel() extension method
  • THEN a WorkOrderViewModel is returned with WorkOrderNumber and ItemNumber

Requirement: ViewModel file organization

The system SHALL organize ViewModel classes in a dedicated ViewModels folder.

File Structure

File ViewModel Class
WorkOrderViewModel.cs WorkOrderViewModel record
LotViewModel.cs LotViewModel record
ItemViewModel.cs ItemViewModel record
WorkCenterViewModel.cs WorkCenterViewModel record
ProfitCenterViewModel.cs ProfitCenterViewModel record
JdeUserViewModel.cs JdeUserViewModel record
PartOperationViewModel.cs PartOperationViewModel record

Business Rules

  • ViewModels in JdeScoping.Core.ViewModels namespace
  • ViewModels are immutable DTOs (prefer record type)
  • ViewModels contain only serializable properties (no computed properties)

Scenario: ViewModel serialization

  • WHEN a WorkOrderViewModel is serialized to JSON
  • THEN all properties are included in the output

Requirement: Enum file organization

The system SHALL organize enum types in a dedicated Enums folder.

File Structure

File Enum Type
SearchStatus.cs SearchStatus enum
UpdateTypes.cs UpdateTypes enum

Business Rules

  • Enums in JdeScoping.Core.Models.Enums namespace
  • All enums that may be serialized MUST have [JsonConverter(typeof(JsonStringEnumConverter))]

Scenario: Enum JSON serialization

  • WHEN SearchStatus.Ended is serialized to JSON
  • THEN the output is "Ended" (string), not 3 (integer)

Nullable Reference Types

The .NET 10 project MUST enable nullable reference types in the project file:

<PropertyGroup>
    <Nullable>enable</Nullable>
</PropertyGroup>

Nullable Annotation Guidelines

Pattern Example Usage
Required property string Name { get; set; } Non-null, must be initialized
Optional property string? Description { get; set; } Can be null
Required with default string Name { get; set; } = string.Empty; Non-null with safe default
Collection property List<string> Items { get; set; } = []; Never null, empty by default

Properties Requiring Nullable Annotation

The following properties SHOULD be annotated as nullable based on business rules:

  • Search.Results -> byte[]?
  • WorkOrder.LotNumber, ParentWorkOrderNumber -> string?
  • Lot.Memo1, Memo2, Memo3 -> string?
  • Item.PlanningFamily, StockingType -> string?
  • WorkOrderStep.StepDescription, FunctionOperationDescription -> string?
  • WorkOrderRouting.StepDescription -> string?
  • WorkOrderComponent.LotNumber -> string?
  • MisData optional fields -> string?
  • UserInfo.FirstName, LastName, Title, EmailAddress -> string?

JDE Date/Time Conversion Pattern

Many JDE entities store dates and times in integer format that must be converted:

JDE Date Format

  • Integer format: CYYDDD (century + year + day of year)
  • Century: 0 = 1900s, 1 = 2000s
  • Example: 124365 = December 30, 2024 (1 + 24 years + 365th day)

JDE Time Format

  • Integer format: HHMMSS
  • Example: 143052 = 14:30:52

Edge Cases

  • Invalid/Zero dates: Return null for 0 or invalid date values (changed from legacy 1900-01-01)
  • Parse errors: Return null rather than silently swallowing errors
  • Backing field access: Raw JDE integer values stored in private fields (e.g., TransactionDate_Date)

Implementation Pattern

// Private backing fields (mapped from database)
private int LastUpdateDate { get; }
private int LastUpdateTime { get; }

// Public computed property (nullable for invalid dates)
public DateTime? LastUpdateDT => JdeDateConverter.ToDateTime(LastUpdateDate, LastUpdateTime);

ToViewModel Extension Methods

The ToViewModel() pattern from the legacy codebase is preserved using extension methods:

public static class WorkOrderExtensions
{
    public static WorkOrderViewModel ToViewModel(this WorkOrder workOrder)
    {
        return new WorkOrderViewModel
        {
            WorkOrderNumber = workOrder.WorkOrderNumber,
            ItemNumber = workOrder.ItemNumber
        };
    }
}

Alternative Mapping Approaches

For larger mapping scenarios, consider using a mapping library:

  • AutoMapper: Convention-based mapping with profiles
  • Mapster: Faster alternative with code generation support

The extension method pattern is preferred for simple projections to maintain explicit, testable code.


Migration Notes

Legacy Pattern New Pattern Rationale
DataModel.Models namespace JdeScoping.Core.Models .NET naming conventions
Newtonsoft.Json System.Text.Json Built-in .NET serialization
[JsonConverter(typeof(StringEnumConverter))] [JsonConverter(typeof(JsonStringEnumConverter))] System.Text.Json enum converter
LDAPEntry UserInfo Renamed for modern auth patterns
<Nullable>disable</Nullable> <Nullable>enable</Nullable> Improved null safety
Forms Authentication models ASP.NET Core cookie authentication Modern auth patterns
Private setters for JDE fields Private backing fields Maintain encapsulation
Extension methods for JDE conversion Static helper class JdeDateConverter Cleaner separation
List<T> for collections Consider IReadOnlyList<T> for immutability Defensive design
ToViewModel() methods on entities Extension methods in separate file Separation of concerns
IBusinessUnit interface Consider sealed classes with shared base Modern C# patterns
JDE invalid dates return 1900-01-01 Return null for invalid dates Explicit null handling
SignalR (OWIN-based) ASP.NET Core SignalR Modern SignalR implementation

Resolved Design Decisions

The following questions from the legacy analysis have been resolved:

Question Decision Rationale
Search.Results storage Keep VARBINARY storage Blob storage adds infrastructure complexity; VARBINARY is sufficient for Excel files
SearchCriteria validation Keep validation at service layer Domain models remain clean; validation is application concern
JDE date conversion Use static helper class Dapper type handlers are fragile; explicit conversion is more testable
Entity vs DTO separation Use ToViewModel extension methods Provides separation without class explosion
QueryTypes.Identify() Remove stub; implement at service layer Query type determination belongs in business logic
TableSpec/ColumnSpec Keep for now May be needed for dynamic query generation
MisData source Continue CMS integration Active business requirement
POReceiver.ShortItemNumber as string Preserve as string Intentional legacy typing; document as known quirk
LDAPEntry rename Rename to UserInfo Supports both LDAP and other identity providers
CamstarMO/DcsLot status Keep but mark as optional May be deprecated; implementation can skip if not needed
Status transition enforcement Keep simple enum Add state machine if needed at service layer
SearchUpdate.Timestamp default Always set in constructor Use primary constructor or init required
JDE invalid date handling Return null Explicit null is clearer than magic date
JDE backing fields Expose only DateTime properties Consumers don't need raw JDE integers

Codex Review Findings

The following issues were identified during code review and should be addressed:

SearchCriteria Validation Gap

  • Issue: No validation exists - all criteria lists can be empty
  • Impact: Users could submit searches with no filters, causing full table scans
  • Recommendation: Add service-layer validation requiring at least one filter criterion

JDE Date Edge Cases

  • Issue: Legacy silently returns 1900-01-01 for invalid dates
  • Impact: Difficult to distinguish invalid data from legitimate old dates
  • Recommendation: Return null for invalid JDE dates; update consuming code to handle nulls

POReceiver Type Inconsistency

  • Issue: ShortItemNumber is string in POReceiver but long elsewhere
  • Impact: Potential join/comparison issues
  • Recommendation: Document as intentional legacy behavior; add explicit conversion if needed

QueryTypes Incomplete Implementation

  • Issue: Identify() method is stubbed with no implementation
  • Impact: Query type detection doesn't work
  • Recommendation: Implement at service layer based on populated criteria fields