Commit Graph

65 Commits

Author SHA1 Message Date
Joseph Doherty c626ffbd69 test: add edge case tests to ApiClientBaseTests
Add 7 edge case tests for ApiClientBase:
- GetAsync_Returns200_EmptyBody_MapsToApiError
- GetAsync_Returns200_InvalidJson_MapsToApiError
- GetAsync_Returns204_ForUnitType_MapsToSuccess
- GetAsync_Returns204_ForNonUnitType_MapsToApiError
- GetAsync_NetworkException_MapsToApiError
- GetAsync_Timeout_MapsToApiError
- GetAsync_Returns400_WithoutValidationFormat_MapsToApiError

Also fix bug in ApiClientBase where 204 NoContent for Unit type
failed due to incorrect type casting. The implicit conversion from
Unit to ApiResult<Unit> must be applied before the runtime cast.
2026-01-06 11:23:54 -05:00
Joseph Doherty 6bd6138b2a chore(client): add Extensions namespace to global imports
Add @using JdeScoping.Client.Extensions to _Imports.razor so that
extension methods (like ViewModelMappingExtensions) are available
globally in Razor components without explicit using statements.
2026-01-06 10:39:44 -05:00
Joseph Doherty 4e1cd2c221 chore(client): delete old service files replaced by API clients
Delete old service interfaces and implementations that have been
replaced by the new typed API clients:
- ISearchService/SearchService -> ISearchApiClient/SearchApiClient
- ILookupService/LookupService -> ILookupApiClient/LookupApiClient
- IFileService/FileService -> IFileApiClient/FileApiClient

Also remove unused IFileService injection from SearchEdit.razor
(download functionality now uses SearchApi.GetResultsAsync).
2026-01-06 10:38:41 -05:00
Joseph Doherty 6701da137d chore(client): remove old service registrations
Remove ISearchService, ILookupService, and IFileService registrations
from Program.cs as these are now replaced by the typed API clients
(ISearchApiClient, ILookupApiClient, IFileApiClient).
2026-01-06 10:37:15 -05:00
Joseph Doherty 828034d0e2 feat(client): migrate PartOperationFilterPanel to API clients 2026-01-06 10:35:33 -05:00
Joseph Doherty 251e2f910f feat(client): migrate ComponentLotFilterPanel to API clients 2026-01-06 10:34:33 -05:00
Joseph Doherty ead947bf57 feat(client): migrate WorkOrderFilterPanel to API clients 2026-01-06 10:33:36 -05:00
Joseph Doherty 8e05afb34f feat(client): migrate OperatorFilterPanel to API clients 2026-01-06 10:32:54 -05:00
Joseph Doherty ee6afc9e4e feat(client): migrate ProfitCenterFilterPanel to API clients 2026-01-06 10:32:25 -05:00
Joseph Doherty f49390ad01 feat(client): migrate WorkCenterFilterPanel to API clients 2026-01-06 10:31:58 -05:00
Joseph Doherty a6348c4268 feat(client): migrate ItemNumberFilterPanel to API clients
Update ItemNumberFilterPanel.razor to use ILookupApiClient and IFileApiClient
instead of legacy ILookupService and IFileService interfaces. All methods now
use the result.Switch() pattern for proper ApiResult error handling.
2026-01-06 10:30:20 -05:00
Joseph Doherty 20f9a1c683 feat(client): migrate MainLayout.razor to IAuthApiClient
- Replace IAuthService with IAuthApiClient for logout functionality
- Add @using JdeScoping.Core.ApiContracts
- LogoutAsync now calls AuthApi.LogoutAsync() and navigates to login
  regardless of API result
2026-01-06 10:27:24 -05:00
Joseph Doherty b555f57b72 feat(client): migrate Login.razor to IAuthApiClient
- Replace IAuthService injection with IAuthApiClient
- Keep ICryptoService for credential encryption
- Add AuthStateProvider injection to notify authentication state
- Use result.Switch() pattern for ApiResult<LoginResultModel> handling
- Properly handle ValidationError with FieldErrors dictionary
2026-01-06 10:25:54 -05:00
Joseph Doherty 6054412a77 refactor: move JSON ETL classes to DataSync.Dev
Move dev-only JSON reading infrastructure from DataSync to DataSync.Dev:
- JsonColumnSchema (Models/)
- JsonZstdFileSource (Sources/)
- JsonStreamingDataReader (Sources/)
- Utf8JsonStreamingDataReader (Sources/)

Update namespaces and using statements in all DevEtl files.
2026-01-06 10:25:45 -05:00
Joseph Doherty a77b71e53d feat(client): migrate SearchEdit.razor to ISearchApiClient
- Replace ISearchService with ISearchApiClient
- Add @using for JdeScoping.Core.ApiContracts and JdeScoping.Client.Extensions
- Update LoadSearchAsync to use result.Switch() pattern with ApiResult<T>
- Handle CopySearchId, Id, and new search cases with proper error handling
- Use ToClient() extension method to convert Core to Client SearchViewModel
- Add _errorMessage field and display error alert in UI
- Update SubmitSearchInternalAsync and DownloadResultsAsync for consistency
- Add FormatValidationErrors helper for ValidationError.FieldErrors
2026-01-06 10:23:36 -05:00
Joseph Doherty b86d48657e feat(client): migrate SearchQueue.razor to ISearchApiClient
- Replace ISearchService injection with ISearchApiClient
- Add @using for JdeScoping.Core.ApiContracts and JdeScoping.Client.Extensions
- Update LoadQueueAsync to use result.Switch() pattern with ApiResult<T>
- Add _errorMessage field for error display
- Add RadzenAlert for error message display in UI
2026-01-06 10:19:53 -05:00
Joseph Doherty b08f5418ec feat(client): migrate Searches.razor to ISearchApiClient
- Replace ISearchService injection with ISearchApiClient
- Add @using for JdeScoping.Core.ApiContracts and JdeScoping.Client.Extensions
- Update LoadSearchesAsync to use ApiResult<T>.Switch() pattern
- Add _errorMessage field for error state
- Display RadzenAlert for error conditions
- Use ToClientList() extension method to convert Core->Client view models
2026-01-06 10:18:11 -05:00
Joseph Doherty 81b07ce027 feat: extract DevEtl to JdeScoping.DataSync.Dev project
- Create JdeScoping.DataSync.Dev for sandbox testing ETL code
- Create JdeScoping.DataSync.Dev.Tests for associated tests
- Move 22 source files and 8 test files
- Update namespaces from DevEtl to Dev
- Add both projects to solution
2026-01-06 10:18:09 -05:00
Joseph Doherty 7ad4e3ec1c feat(client): configure HttpClient with AuthRedirectHandler
- Add using statement for JdeScoping.Client.Http namespace
- Register AuthRedirectHandler as a scoped service
- Replace simple HttpClient registration with handler pipeline
- AuthRedirectHandler intercepts 401 responses and redirects to login
- Keep all existing service registrations for backward compatibility
2026-01-06 10:15:48 -05:00
Joseph Doherty ba88450feb feat(client): add ViewModelMappingExtensions for Core<->Client mapping
Add extension methods to convert between Core and Client view models:
- SearchViewModel: Core (enum Status) <-> Client (string Status)
- SearchCriteria: Core (primitive lists) <-> Client (full ViewModels)
- JdeUserViewModel -> OperatorViewModel

Handles structural differences in criteria where Core uses primitive
lists (List<long>, List<string>) and Client uses full objects.
2026-01-06 10:14:09 -05:00
Joseph Doherty 0b50c03e44 feat(client): add AuthRedirectHandler for global 401 redirect
Add HTTP message handler that intercepts 401 Unauthorized responses
and redirects to the login page with return URL preserved.
2026-01-06 10:11:43 -05:00
Joseph Doherty badc6a43f3 fix(datasync): throw on cancellation in DevEtlRegistry.RunAllAsync 2026-01-03 16:32:29 -05:00
Joseph Doherty 6bd2b3c285 feat(datasync): add DevEtlRegistry for managing development ETL pipelines 2026-01-03 16:28:35 -05:00
Joseph Doherty fd1e5454da feat(datasync): add BranchDevEtl pipeline for Branch table dev loading 2026-01-03 16:24:34 -05:00
Joseph Doherty 2629cb26e0 fix(datasync): add guards and exception safety to JsonZstdFileSource 2026-01-03 16:21:59 -05:00
Joseph Doherty 57a44e0f3a feat(datasync): add JsonZstdFileSource for reading zstd-compressed JSON files 2026-01-03 16:19:28 -05:00
Joseph Doherty 6d2d8134cb fix(datasync): dispose JsonDocument in JsonStreamingDataReader.Read() 2026-01-03 16:17:38 -05:00
Joseph Doherty bd1c2fd656 feat(datasync): add JsonStreamingDataReader for streaming JSON array parsing 2026-01-03 16:14:31 -05:00
Joseph Doherty bf7cfe9bf1 feat(datasync): add JsonColumnSchema record for ETL column metadata 2026-01-03 16:11:00 -05:00
Joseph Doherty 9ff21958bb feat(datasync): add ZstdSharp.Port package for zstd decompression 2026-01-03 16:08:13 -05:00
Joseph Doherty 7dcbacd5ca fix(etl): address Codex MCP review findings for Phase 2
- Filter MERGE SQL columns to only include columns that exist in destination
  (allColumns and updateColumns were using unfiltered source columns)
- Fix schema-qualified table names to use proper [schema].[table] format
  instead of wrapping entire name in single brackets
- Add empty column mapping validation to throw early if no columns intersect
- Add JdeDateTransformer output column collision detection in OnInitialize
- Add TODO comment for WithCommandTimeout (stored but not yet passed to
  destinations)
- Add tests for FormatQualifiedTableName and output column collision
2026-01-03 11:27:07 -05:00
Joseph Doherty fcd8b660fa feat(etl): add WithCommandTimeout to EtlPipelineBuilder with validation 2026-01-03 11:09:28 -05:00
Joseph Doherty 3145fca371 feat(etl): add column mapping to destinations (intersect with dest schema) 2026-01-03 11:06:38 -05:00
Joseph Doherty 0b317c1ffc feat(etl): add commandTimeoutSeconds to destinations 2026-01-03 11:01:12 -05:00
Joseph Doherty 0e07a76438 feat(etl): add ParseTableName and QUOTENAME to CommonScripts
- Add ParseTableName method to parse table names with optional schema
  - Supports: "Table", "dbo.Table", "[dbo].[Table]"
  - Returns (schema, table) tuple, defaults to "dbo" schema
- Update DisableIndexes, RebuildIndexes, UpdateStatistics to:
  - Use QUOTENAME() for SQL injection protection
  - Pass schema and table as parameters via SqlScriptRunner
  - Support non-dbo schemas
- Update CustomSql to accept optional parameters and timeout
- Add comprehensive tests for ParseTableName with various formats
2026-01-03 10:56:05 -05:00
Joseph Doherty 40e458148d feat(etl): add parameters support to SqlScriptRunner 2026-01-03 10:52:33 -05:00
Joseph Doherty 0820a9b024 feat(etl): add collision detection to ColumnRenameTransformer 2026-01-03 10:50:03 -05:00
Joseph Doherty ae84cb3d75 feat(etl): add MapOrdinal and date validation with sentinel to JdeDateTransformer
- Add DefaultInvalidDateSentinel (1900-01-01) for invalid date handling
- Add optional invalidDateSentinel constructor parameter
- Add MapOrdinal override returning -1 for computed DateTime column
- Add GetDataTypeName override returning "datetime" for computed column
- Update ParseJdeDateTime with comprehensive validation:
  - Validate date is positive
  - Validate century (0 or 1)
  - Validate year (0-99)
  - Validate day of year (1-366 and respects leap year)
  - Validate time components (hours 0-23, minutes/seconds 0-59)
- Add tests for all new functionality
2026-01-03 10:46:19 -05:00
Joseph Doherty 577e67ec64 feat(etl): add MapOrdinal override to ColumnDropTransformer 2026-01-03 10:35:54 -05:00
Joseph Doherty 506ba5c61d feat(etl): add binary method overrides to DataTransformerBase
Add virtual methods to DataTransformerBase for GetBytes, GetChars,
GetData, and GetDataTypeName that properly handle computed columns
by throwing NotSupportedException when MapOrdinal returns -1.

Update TransformingDataReader to delegate these methods to the
transformer instead of directly to the source reader.
2026-01-03 10:33:13 -05:00
Joseph Doherty f5468d019f feat(etl): add MapOrdinal to IDataTransformer interface
Add MapOrdinal method to the IDataTransformer interface and provide
a default implementation in DataTransformerBase. This enables
transformers to report the mapping between transformed ordinals and
source ordinals, supporting use cases like computed columns which
return -1 to indicate no source ordinal.

- Add MapOrdinal(int, IDataReader) to IDataTransformer interface
- Add virtual MapOrdinal implementation in DataTransformerBase
- Add DataTransformerBaseTests with test for default behavior
2026-01-03 10:28:49 -05:00
Joseph Doherty 27f84fa3c1 feat(etl): add DI registration for ETL pipeline 2026-01-03 09:33:07 -05:00
Joseph Doherty 4c16e62661 feat(etl): implement EtlPipeline and EtlPipelineBuilder
Add pipeline orchestration for ETL operations:
- EtlPipeline: executes source -> transform -> destination flow
- EtlPipelineBuilder: fluent builder for pipeline configuration
- Supports pre/post scripts, multiple transformers
- Returns PipelineResult with step-by-step timing
2026-01-03 09:31:32 -05:00
Joseph Doherty 644e884b21 feat(etl): implement DbBulkMergeDestination for incremental updates 2026-01-03 09:26:43 -05:00
Joseph Doherty 63a0e7cf7e feat(etl): implement DbBulkImportDestination for full table refresh
Add bulk import destination that truncates and loads data using
SqlBulkCopy with configurable batch sizes and streaming support.
2026-01-03 09:22:57 -05:00
Joseph Doherty 8594baf11d feat(etl): implement DbQuerySource for database queries
Adds DbQuerySource, an IImportSource implementation that executes SQL
queries against the LotFinder database. Supports parameterized queries
using anonymous objects and configurable command timeouts.
2026-01-03 09:18:58 -05:00
Joseph Doherty 74c3f37446 feat(etl): implement JdeDateTransformer for Julian date parsing
Add transformer that combines JDE Julian date (CYYDDD) and time (HHMMSS)
columns into a single DateTime column. Includes static ParseJdeDateTime
method for direct date conversion.
2026-01-03 09:16:11 -05:00
Joseph Doherty 81cb0df6bf feat(etl): implement ColumnRenameTransformer
Add transformer for renaming columns in the data stream during ETL.
Supports case-insensitive column name matching and multiple renames.
2026-01-03 09:13:02 -05:00
Joseph Doherty f1b7809a45 feat(etl): implement ColumnDropTransformer
Add a data transformer that removes specified columns from the data stream.
Columns are matched by name (case-insensitive) and multiple columns can be
dropped in a single transformer. Includes comprehensive tests using NSubstitute
for mock IDataReader.
2026-01-03 09:10:54 -05:00
Joseph Doherty 6e7bcadf68 feat(etl): implement TransformingDataReader and DataTransformerBase
Add core transformer infrastructure for the ETL pipeline:
- DataTransformerBase: abstract base class with virtual methods for
  field count, names, types, values, ordinals, and null checking
- TransformingDataReader: IDataReader wrapper that delegates to
  transformer, enabling on-the-fly data transformations
2026-01-03 09:08:17 -05:00