26ff8d9b4f
Set up repository with legacy .NET Framework 4.8 source (OLD/), new .NET 10 Blazor solution (NEW/), OpenSpec specifications, documentation, and project configuration.
1150 lines
41 KiB
Markdown
1150 lines
41 KiB
Markdown
# 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
|
|
|
|
```csharp
|
|
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`
|
|
|
|
#### Scenario: Create SearchUpdate from Search
|
|
- **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:
|
|
|
|
```xml
|
|
<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
|
|
|
|
```csharp
|
|
// 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:
|
|
|
|
```csharp
|
|
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
|