Initial commit: JDE Scoping Tool migration project
Set up repository with legacy .NET Framework 4.8 source (OLD/), new .NET 10 Blazor solution (NEW/), OpenSpec specifications, documentation, and project configuration.
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
using JdeScoping.Core.Models;
|
||||
using JdeScoping.Core.Models.Inventory;
|
||||
using JdeScoping.Core.ViewModels;
|
||||
|
||||
namespace JdeScoping.Core.Extensions;
|
||||
|
||||
/// <summary>
|
||||
/// Extension methods for Item entity
|
||||
/// </summary>
|
||||
public static class ItemExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts an Item entity to its ViewModel projection
|
||||
/// </summary>
|
||||
/// <param name="item">Item entity to convert</param>
|
||||
/// <returns>ItemViewModel projection</returns>
|
||||
public static ItemViewModel ToViewModel(this Item item)
|
||||
{
|
||||
return new ItemViewModel
|
||||
{
|
||||
ItemNumber = item.ItemNumber,
|
||||
Description = item.Description
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a collection of Item entities to ViewModels
|
||||
/// </summary>
|
||||
/// <param name="items">Collection of Item entities</param>
|
||||
/// <returns>Collection of ItemViewModel projections</returns>
|
||||
public static IEnumerable<ItemViewModel> ToViewModels(this IEnumerable<Item> items)
|
||||
{
|
||||
return items.Select(i => i.ToViewModel());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
using JdeScoping.Core.Models;
|
||||
using JdeScoping.Core.Models.Organization;
|
||||
using JdeScoping.Core.ViewModels;
|
||||
|
||||
namespace JdeScoping.Core.Extensions;
|
||||
|
||||
/// <summary>
|
||||
/// Extension methods for JdeUser entity
|
||||
/// </summary>
|
||||
public static class JdeUserExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts a JdeUser entity to its ViewModel projection
|
||||
/// </summary>
|
||||
/// <param name="jdeUser">JdeUser entity to convert</param>
|
||||
/// <returns>JdeUserViewModel projection</returns>
|
||||
public static JdeUserViewModel ToViewModel(this JdeUser jdeUser)
|
||||
{
|
||||
return new JdeUserViewModel
|
||||
{
|
||||
AddressNumber = jdeUser.AddressNumber,
|
||||
UserId = jdeUser.UserId,
|
||||
FullName = jdeUser.FullName
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a collection of JdeUser entities to ViewModels
|
||||
/// </summary>
|
||||
/// <param name="jdeUsers">Collection of JdeUser entities</param>
|
||||
/// <returns>Collection of JdeUserViewModel projections</returns>
|
||||
public static IEnumerable<JdeUserViewModel> ToViewModels(this IEnumerable<JdeUser> jdeUsers)
|
||||
{
|
||||
return jdeUsers.Select(u => u.ToViewModel());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
using JdeScoping.Core.Models;
|
||||
using JdeScoping.Core.Models.Inventory;
|
||||
using JdeScoping.Core.ViewModels;
|
||||
|
||||
namespace JdeScoping.Core.Extensions;
|
||||
|
||||
/// <summary>
|
||||
/// Extension methods for Lot entity
|
||||
/// </summary>
|
||||
public static class LotExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts a Lot entity to its ViewModel projection
|
||||
/// </summary>
|
||||
/// <param name="lot">Lot entity to convert</param>
|
||||
/// <returns>LotViewModel projection</returns>
|
||||
public static LotViewModel ToViewModel(this Lot lot)
|
||||
{
|
||||
return new LotViewModel
|
||||
{
|
||||
LotNumber = lot.LotNumber,
|
||||
ItemNumber = lot.ItemNumber
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a collection of Lot entities to ViewModels
|
||||
/// </summary>
|
||||
/// <param name="lots">Collection of Lot entities</param>
|
||||
/// <returns>Collection of LotViewModel projections</returns>
|
||||
public static IEnumerable<LotViewModel> ToViewModels(this IEnumerable<Lot> lots)
|
||||
{
|
||||
return lots.Select(l => l.ToViewModel());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
using JdeScoping.Core.Models;
|
||||
using JdeScoping.Core.Models.Organization;
|
||||
using JdeScoping.Core.ViewModels;
|
||||
|
||||
namespace JdeScoping.Core.Extensions;
|
||||
|
||||
/// <summary>
|
||||
/// Extension methods for ProfitCenter entity
|
||||
/// </summary>
|
||||
public static class ProfitCenterExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts a ProfitCenter entity to its ViewModel projection
|
||||
/// </summary>
|
||||
/// <param name="profitCenter">ProfitCenter entity to convert</param>
|
||||
/// <returns>ProfitCenterViewModel projection</returns>
|
||||
public static ProfitCenterViewModel ToViewModel(this ProfitCenter profitCenter)
|
||||
{
|
||||
return new ProfitCenterViewModel
|
||||
{
|
||||
Code = profitCenter.Code,
|
||||
Description = profitCenter.Description
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a collection of ProfitCenter entities to ViewModels
|
||||
/// </summary>
|
||||
/// <param name="profitCenters">Collection of ProfitCenter entities</param>
|
||||
/// <returns>Collection of ProfitCenterViewModel projections</returns>
|
||||
public static IEnumerable<ProfitCenterViewModel> ToViewModels(this IEnumerable<ProfitCenter> profitCenters)
|
||||
{
|
||||
return profitCenters.Select(pc => pc.ToViewModel());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
using JdeScoping.Core.Models;
|
||||
using JdeScoping.Core.Models.Organization;
|
||||
using JdeScoping.Core.ViewModels;
|
||||
|
||||
namespace JdeScoping.Core.Extensions;
|
||||
|
||||
/// <summary>
|
||||
/// Extension methods for WorkCenter entity
|
||||
/// </summary>
|
||||
public static class WorkCenterExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts a WorkCenter entity to its ViewModel projection
|
||||
/// </summary>
|
||||
/// <param name="workCenter">WorkCenter entity to convert</param>
|
||||
/// <returns>WorkCenterViewModel projection</returns>
|
||||
public static WorkCenterViewModel ToViewModel(this WorkCenter workCenter)
|
||||
{
|
||||
return new WorkCenterViewModel
|
||||
{
|
||||
Code = workCenter.Code,
|
||||
Description = workCenter.Description
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a collection of WorkCenter entities to ViewModels
|
||||
/// </summary>
|
||||
/// <param name="workCenters">Collection of WorkCenter entities</param>
|
||||
/// <returns>Collection of WorkCenterViewModel projections</returns>
|
||||
public static IEnumerable<WorkCenterViewModel> ToViewModels(this IEnumerable<WorkCenter> workCenters)
|
||||
{
|
||||
return workCenters.Select(wc => wc.ToViewModel());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
using JdeScoping.Core.Models;
|
||||
using JdeScoping.Core.Models.WorkOrders;
|
||||
using JdeScoping.Core.ViewModels;
|
||||
|
||||
namespace JdeScoping.Core.Extensions;
|
||||
|
||||
/// <summary>
|
||||
/// Extension methods for WorkOrder entity
|
||||
/// </summary>
|
||||
public static class WorkOrderExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts a WorkOrder entity to its ViewModel projection
|
||||
/// </summary>
|
||||
/// <param name="workOrder">WorkOrder entity to convert</param>
|
||||
/// <returns>WorkOrderViewModel projection</returns>
|
||||
public static WorkOrderViewModel ToViewModel(this WorkOrder workOrder)
|
||||
{
|
||||
return new WorkOrderViewModel
|
||||
{
|
||||
WorkOrderNumber = workOrder.WorkOrderNumber,
|
||||
ItemNumber = workOrder.ItemNumber
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a collection of WorkOrder entities to ViewModels
|
||||
/// </summary>
|
||||
/// <param name="workOrders">Collection of WorkOrder entities</param>
|
||||
/// <returns>Collection of WorkOrderViewModel projections</returns>
|
||||
public static IEnumerable<WorkOrderViewModel> ToViewModels(this IEnumerable<WorkOrder> workOrders)
|
||||
{
|
||||
return workOrders.Select(wo => wo.ToViewModel());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
namespace JdeScoping.Core.Helpers;
|
||||
|
||||
/// <summary>
|
||||
/// Converts between JDE date (CYYDDD) and time (HHMMSS) formats and DateTime.
|
||||
/// </summary>
|
||||
public static class JdeDateConverter
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts DateTime to JDE date format (CYYDDD).
|
||||
/// </summary>
|
||||
/// <param name="dateTime">DateTime to convert.</param>
|
||||
/// <returns>JDE date in CYYDDD format.</returns>
|
||||
public static int ToJdeDate(this DateTime dateTime)
|
||||
{
|
||||
// CYYDDD format: C = century (0=1900s, 1=2000s), YY = year, DDD = day of year
|
||||
int century = (dateTime.Year - 1900) / 100;
|
||||
int yearInCentury = (dateTime.Year - 1900) % 100;
|
||||
int dayOfYear = dateTime.DayOfYear;
|
||||
|
||||
return (century * 100000) + (yearInCentury * 1000) + dayOfYear;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts DateTime to JDE time format (HHMMSS).
|
||||
/// </summary>
|
||||
/// <param name="dateTime">DateTime to convert.</param>
|
||||
/// <returns>JDE time in HHMMSS format.</returns>
|
||||
public static int ToJdeTime(this DateTime dateTime)
|
||||
{
|
||||
return (dateTime.Hour * 10000) + (dateTime.Minute * 100) + dateTime.Second;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts JDE date (CYYDDD) to DateTime.
|
||||
/// Returns null for zero or invalid values.
|
||||
/// </summary>
|
||||
/// <param name="jdeDate">JDE date in CYYDDD format (C=century, YY=year, DDD=day of year)</param>
|
||||
/// <returns>DateTime or null if invalid</returns>
|
||||
public static DateTime? ToDateTime(int jdeDate)
|
||||
{
|
||||
return ToDateTime(jdeDate, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts JDE date (CYYDDD) and time (HHMMSS) to DateTime.
|
||||
/// Returns null for zero or invalid values (changed from legacy 1900-01-01).
|
||||
/// </summary>
|
||||
/// <param name="jdeDate">JDE date in CYYDDD format (C=century, YY=year, DDD=day of year)</param>
|
||||
/// <param name="jdeTime">JDE time in HHMMSS format</param>
|
||||
/// <returns>DateTime or null if invalid</returns>
|
||||
public static DateTime? ToDateTime(int jdeDate, int jdeTime)
|
||||
{
|
||||
if (jdeDate <= 0)
|
||||
return null;
|
||||
|
||||
try
|
||||
{
|
||||
// CYYDDD format: C = century (0=1900s, 1=2000s), YY = year, DDD = day of year
|
||||
int century = jdeDate / 100000;
|
||||
int yearInCentury = (jdeDate / 1000) % 100;
|
||||
int dayOfYear = jdeDate % 1000;
|
||||
|
||||
int year = 1900 + (century * 100) + yearInCentury;
|
||||
|
||||
if (dayOfYear < 1 || dayOfYear > 366)
|
||||
return null;
|
||||
|
||||
var date = new DateTime(year, 1, 1).AddDays(dayOfYear - 1);
|
||||
|
||||
// Validate the resulting year matches what we calculated
|
||||
// (handles leap year edge case where day 366 might push to next year)
|
||||
if (date.Year != year)
|
||||
return null;
|
||||
|
||||
// Add time component if provided
|
||||
if (jdeTime > 0)
|
||||
{
|
||||
int hours = jdeTime / 10000;
|
||||
int minutes = (jdeTime / 100) % 100;
|
||||
int seconds = jdeTime % 100;
|
||||
|
||||
if (hours >= 0 && hours < 24 && minutes >= 0 && minutes < 60 && seconds >= 0 && seconds < 60)
|
||||
{
|
||||
date = date.AddHours(hours).AddMinutes(minutes).AddSeconds(seconds);
|
||||
}
|
||||
}
|
||||
|
||||
return date;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
using JdeScoping.Core.Models;
|
||||
|
||||
namespace JdeScoping.Core.Interfaces;
|
||||
|
||||
/// <summary>
|
||||
/// Authentication service interface
|
||||
/// </summary>
|
||||
public interface IAuthService
|
||||
{
|
||||
/// <summary>
|
||||
/// Authenticates a user with the given credentials
|
||||
/// </summary>
|
||||
/// <param name="username">Username</param>
|
||||
/// <param name="password">Password</param>
|
||||
/// <param name="ct">Cancellation token</param>
|
||||
/// <returns>Authentication result</returns>
|
||||
Task<AuthResult> AuthenticateAsync(
|
||||
string username,
|
||||
string password,
|
||||
CancellationToken ct = default);
|
||||
|
||||
/// <summary>
|
||||
/// Gets user information for the given username
|
||||
/// </summary>
|
||||
/// <param name="username">Username to lookup</param>
|
||||
/// <param name="ct">Cancellation token</param>
|
||||
/// <returns>User info if found, null otherwise</returns>
|
||||
Task<UserInfo?> GetUserInfoAsync(
|
||||
string username,
|
||||
CancellationToken ct = default);
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a user is a member of a specific group
|
||||
/// </summary>
|
||||
/// <param name="username">Username to check</param>
|
||||
/// <param name="groupName">Group name or DN to check membership</param>
|
||||
/// <param name="ct">Cancellation token</param>
|
||||
/// <returns>True if user is in the group, false otherwise</returns>
|
||||
Task<bool> IsInGroupAsync(
|
||||
string username,
|
||||
string groupName,
|
||||
CancellationToken ct = default);
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
namespace JdeScoping.Core.Interfaces;
|
||||
|
||||
/// <summary>
|
||||
/// Generic JDE business unit interface shared by WorkCenter and ProfitCenter
|
||||
/// </summary>
|
||||
public interface IBusinessUnit
|
||||
{
|
||||
/// <summary>
|
||||
/// Business unit unique code
|
||||
/// </summary>
|
||||
string Code { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Business unit description
|
||||
/// </summary>
|
||||
string Description { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Timestamp of last update to business unit
|
||||
/// </summary>
|
||||
DateTime? LastUpdateDt { get; }
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using JdeScoping.Core.Models;
|
||||
using JdeScoping.Core.Models.Quality;
|
||||
|
||||
namespace JdeScoping.Core.Interfaces;
|
||||
|
||||
/// <summary>
|
||||
/// Interface for fetching data from CMS source system.
|
||||
/// </summary>
|
||||
public interface ICmsDataSource
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets MIS data from CMS as an async stream.
|
||||
/// </summary>
|
||||
/// <param name="minimumDt">Minimum update timestamp for incremental fetch. Null for full fetch.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
IAsyncEnumerable<MisData> GetMisDataAsync(DateTime? minimumDt = null, CancellationToken cancellationToken = default);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
namespace JdeScoping.Core.Interfaces;
|
||||
|
||||
/// <summary>
|
||||
/// Service for generating Excel export files from search data.
|
||||
/// </summary>
|
||||
public interface IExcelExportService
|
||||
{
|
||||
/// <summary>
|
||||
/// Generates an Excel file from the provided search model.
|
||||
/// </summary>
|
||||
/// <param name="search">Search model with criteria and results.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>Excel file as byte array.</returns>
|
||||
Task<byte[]> GenerateAsync(object search, CancellationToken cancellationToken = default);
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using JdeScoping.Core.ViewModels;
|
||||
|
||||
namespace JdeScoping.Core.Interfaces;
|
||||
|
||||
/// <summary>
|
||||
/// Service for parsing Excel files uploaded by users.
|
||||
/// </summary>
|
||||
public interface IExcelParserService
|
||||
{
|
||||
/// <summary>
|
||||
/// Parses work order numbers from an Excel file.
|
||||
/// </summary>
|
||||
/// <param name="fileStream">Excel file stream.</param>
|
||||
/// <returns>List of work order numbers.</returns>
|
||||
List<long> ParseWorkOrders(Stream fileStream);
|
||||
|
||||
/// <summary>
|
||||
/// Parses item numbers from an Excel file.
|
||||
/// </summary>
|
||||
/// <param name="fileStream">Excel file stream.</param>
|
||||
/// <returns>List of item numbers.</returns>
|
||||
List<string> ParseItems(Stream fileStream);
|
||||
|
||||
/// <summary>
|
||||
/// Parses component lot/item pairs from an Excel file.
|
||||
/// </summary>
|
||||
/// <param name="fileStream">Excel file stream.</param>
|
||||
/// <returns>List of lot view models with LotNumber and ItemNumber.</returns>
|
||||
List<LotViewModel> ParseComponentLots(Stream fileStream);
|
||||
|
||||
/// <summary>
|
||||
/// Parses part operations from an Excel file.
|
||||
/// </summary>
|
||||
/// <param name="fileStream">Excel file stream.</param>
|
||||
/// <returns>List of part operation view models.</returns>
|
||||
List<PartOperationViewModel> ParsePartOperations(Stream fileStream);
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
namespace JdeScoping.Core.Interfaces;
|
||||
|
||||
/// <summary>
|
||||
/// Service for generating Excel template files for data entry.
|
||||
/// </summary>
|
||||
public interface IExcelTemplateService
|
||||
{
|
||||
/// <summary>
|
||||
/// Generates an Excel file with a single column of data.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of data items.</typeparam>
|
||||
/// <param name="data">Data items to write.</param>
|
||||
/// <param name="headerText">Header text for the column.</param>
|
||||
/// <returns>Excel file as byte array.</returns>
|
||||
byte[] GenerateSingleColumn<T>(IEnumerable<T> data, string headerText);
|
||||
|
||||
/// <summary>
|
||||
/// Generates an Excel file with multiple columns of data.
|
||||
/// </summary>
|
||||
/// <param name="data">2D array of data (rows x columns).</param>
|
||||
/// <param name="headers">Header text for each column.</param>
|
||||
/// <returns>Excel file as byte array.</returns>
|
||||
byte[] GenerateMultiColumn(object?[][] data, string[] headers);
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
using JdeScoping.Core.Models;
|
||||
using JdeScoping.Core.Models.Inventory;
|
||||
using JdeScoping.Core.Models.Organization;
|
||||
using JdeScoping.Core.Models.WorkOrders;
|
||||
|
||||
namespace JdeScoping.Core.Interfaces;
|
||||
|
||||
/// <summary>
|
||||
/// Interface for fetching data from JDE (JD Edwards) source system.
|
||||
/// </summary>
|
||||
public interface IJdeDataSource
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets work orders from JDE as an async stream.
|
||||
/// </summary>
|
||||
/// <param name="minimumDt">Minimum update timestamp for incremental fetch. Null for full fetch.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
IAsyncEnumerable<WorkOrder> GetWorkOrdersAsync(DateTime? minimumDt = null, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Gets lot usage records from JDE as an async stream.
|
||||
/// </summary>
|
||||
/// <param name="minimumDt">Minimum update timestamp for incremental fetch. Null for full fetch.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
IAsyncEnumerable<LotUsage> GetLotUsagesAsync(DateTime? minimumDt = null, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Gets lots from JDE as an async stream.
|
||||
/// </summary>
|
||||
/// <param name="minimumDt">Minimum update timestamp for incremental fetch. Null for full fetch.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
IAsyncEnumerable<Lot> GetLotsAsync(DateTime? minimumDt = null, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Gets items from JDE as an async stream.
|
||||
/// </summary>
|
||||
/// <param name="minimumDt">Minimum update timestamp for incremental fetch. Null for full fetch.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
IAsyncEnumerable<Item> GetItemsAsync(DateTime? minimumDt = null, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Gets work centers from JDE as an async stream.
|
||||
/// </summary>
|
||||
/// <param name="minimumDt">Minimum update timestamp for incremental fetch. Null for full fetch.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
IAsyncEnumerable<WorkCenter> GetWorkCentersAsync(DateTime? minimumDt = null, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Gets profit centers from JDE as an async stream.
|
||||
/// </summary>
|
||||
/// <param name="minimumDt">Minimum update timestamp for incremental fetch. Null for full fetch.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
IAsyncEnumerable<ProfitCenter> GetProfitCentersAsync(DateTime? minimumDt = null, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Gets JDE users as an async stream.
|
||||
/// </summary>
|
||||
/// <param name="minimumDt">Minimum update timestamp for incremental fetch. Null for full fetch.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
IAsyncEnumerable<JdeUser> GetUsersAsync(DateTime? minimumDt = null, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Gets branches from JDE as an async stream.
|
||||
/// </summary>
|
||||
/// <param name="minimumDt">Minimum update timestamp for incremental fetch. Null for full fetch.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
IAsyncEnumerable<Branch> GetBranchesAsync(DateTime? minimumDt = null, CancellationToken cancellationToken = default);
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
using JdeScoping.Core.Models.Infrastructure;
|
||||
|
||||
namespace JdeScoping.Core.Interfaces;
|
||||
|
||||
/// <summary>
|
||||
/// Data sync operations for LotFinder SQL Server cache database.
|
||||
/// </summary>
|
||||
public partial interface ILotFinderRepository
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the latest data update record per table/type combination.
|
||||
/// </summary>
|
||||
/// <param name="ct">Cancellation token.</param>
|
||||
/// <returns>Latest data updates.</returns>
|
||||
Task<List<DataUpdate>> GetLastDataUpdatesAsync(CancellationToken ct = default);
|
||||
|
||||
/// <summary>
|
||||
/// Gets table schema specification for dynamic SQL generation.
|
||||
/// </summary>
|
||||
/// <param name="tableName">Table name.</param>
|
||||
/// <param name="ct">Cancellation token.</param>
|
||||
/// <returns>Table specification with columns and primary key.</returns>
|
||||
Task<TableSpec> GetTableSpecAsync(string tableName, CancellationToken ct = default);
|
||||
|
||||
/// <summary>
|
||||
/// Rebuilds all indices on a table with fillfactor of 95.
|
||||
/// Table name is validated against whitelist for SQL injection prevention.
|
||||
/// </summary>
|
||||
/// <param name="tableName">Table name (must be in whitelist).</param>
|
||||
/// <param name="ct">Cancellation token.</param>
|
||||
/// <exception cref="ArgumentException">Thrown if table name is not in whitelist.</exception>
|
||||
Task RebuildIndicesAsync(string tableName, CancellationToken ct = default);
|
||||
|
||||
/// <summary>
|
||||
/// Post-processes imported MIS data to set obsolete dates.
|
||||
/// </summary>
|
||||
/// <param name="ct">Cancellation token.</param>
|
||||
Task PostProcessMisDataAsync(CancellationToken ct = default);
|
||||
|
||||
/// <summary>
|
||||
/// Performs bulk insert of records into a table.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Record type.</typeparam>
|
||||
/// <param name="tableName">Target table name.</param>
|
||||
/// <param name="records">Records to insert.</param>
|
||||
/// <param name="ct">Cancellation token.</param>
|
||||
/// <returns>Number of records inserted.</returns>
|
||||
Task<int> BulkInsertAsync<T>(string tableName, IEnumerable<T> records, CancellationToken ct = default);
|
||||
|
||||
/// <summary>
|
||||
/// Truncates a table, removing all records.
|
||||
/// </summary>
|
||||
/// <param name="tableName">Table name.</param>
|
||||
/// <param name="ct">Cancellation token.</param>
|
||||
Task TruncateTableAsync(string tableName, CancellationToken ct = default);
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
using JdeScoping.Core.Models;
|
||||
using JdeScoping.Core.Models.Inventory;
|
||||
using JdeScoping.Core.Models.Organization;
|
||||
using JdeScoping.Core.Models.WorkOrders;
|
||||
using JdeScoping.Core.ViewModels;
|
||||
|
||||
namespace JdeScoping.Core.Interfaces;
|
||||
|
||||
/// <summary>
|
||||
/// Reference data lookup operations for LotFinder SQL Server cache database.
|
||||
/// </summary>
|
||||
public partial interface ILotFinderRepository
|
||||
{
|
||||
/// <summary>
|
||||
/// Searches items by number or description.
|
||||
/// </summary>
|
||||
/// <param name="filter">Search filter.</param>
|
||||
/// <param name="ct">Cancellation token.</param>
|
||||
/// <returns>Top 25 matching items.</returns>
|
||||
Task<List<Item>> SearchItemsAsync(string filter, CancellationToken ct = default);
|
||||
|
||||
/// <summary>
|
||||
/// Looks up items by exact item numbers.
|
||||
/// </summary>
|
||||
/// <param name="itemNumbers">Item numbers to match.</param>
|
||||
/// <param name="ct">Cancellation token.</param>
|
||||
/// <returns>Matching items.</returns>
|
||||
Task<List<Item>> LookupItemsAsync(List<string> itemNumbers, CancellationToken ct = default);
|
||||
|
||||
/// <summary>
|
||||
/// Looks up work orders by work order numbers.
|
||||
/// </summary>
|
||||
/// <param name="workorderNumbers">Work order numbers to match.</param>
|
||||
/// <param name="ct">Cancellation token.</param>
|
||||
/// <returns>Matching work orders.</returns>
|
||||
Task<List<WorkOrder>> LookupWorkordersAsync(List<long> workorderNumbers, CancellationToken ct = default);
|
||||
|
||||
/// <summary>
|
||||
/// Searches work centers by code or description.
|
||||
/// </summary>
|
||||
/// <param name="filter">Search filter.</param>
|
||||
/// <param name="ct">Cancellation token.</param>
|
||||
/// <returns>Top 25 matching work centers.</returns>
|
||||
Task<List<WorkCenter>> SearchWorkCentersAsync(string filter, CancellationToken ct = default);
|
||||
|
||||
/// <summary>
|
||||
/// Looks up work centers by codes.
|
||||
/// </summary>
|
||||
/// <param name="codes">Work center codes to match.</param>
|
||||
/// <param name="ct">Cancellation token.</param>
|
||||
/// <returns>Matching work centers.</returns>
|
||||
Task<List<WorkCenter>> LookupWorkCentersAsync(List<string> codes, CancellationToken ct = default);
|
||||
|
||||
/// <summary>
|
||||
/// Searches profit centers by code or description.
|
||||
/// </summary>
|
||||
/// <param name="filter">Search filter.</param>
|
||||
/// <param name="ct">Cancellation token.</param>
|
||||
/// <returns>Top 25 matching profit centers.</returns>
|
||||
Task<List<ProfitCenter>> SearchProfitCentersAsync(string filter, CancellationToken ct = default);
|
||||
|
||||
/// <summary>
|
||||
/// Looks up profit centers by codes.
|
||||
/// </summary>
|
||||
/// <param name="codes">Profit center codes to match.</param>
|
||||
/// <param name="ct">Cancellation token.</param>
|
||||
/// <returns>Matching profit centers.</returns>
|
||||
Task<List<ProfitCenter>> LookupProfitCentersAsync(List<string> codes, CancellationToken ct = default);
|
||||
|
||||
/// <summary>
|
||||
/// Searches users by user ID, full name, or address number.
|
||||
/// </summary>
|
||||
/// <param name="filter">Search filter.</param>
|
||||
/// <param name="ct">Cancellation token.</param>
|
||||
/// <returns>Top 25 matching users.</returns>
|
||||
Task<List<JdeUser>> SearchUsersAsync(string filter, CancellationToken ct = default);
|
||||
|
||||
/// <summary>
|
||||
/// Looks up users by user IDs or address numbers.
|
||||
/// </summary>
|
||||
/// <param name="userIds">User IDs or address numbers to match.</param>
|
||||
/// <param name="ct">Cancellation token.</param>
|
||||
/// <returns>Matching users.</returns>
|
||||
Task<List<JdeUser>> LookupUsersAsync(List<string> userIds, CancellationToken ct = default);
|
||||
|
||||
/// <summary>
|
||||
/// Looks up lots by lot number and item number.
|
||||
/// </summary>
|
||||
/// <param name="lots">Lot/item combinations to match.</param>
|
||||
/// <param name="ct">Cancellation token.</param>
|
||||
/// <returns>Matching lots.</returns>
|
||||
Task<List<Lot>> LookupLotsAsync(List<LotViewModel> lots, CancellationToken ct = default);
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
using JdeScoping.Core.Models.Enums;
|
||||
using JdeScoping.Core.Models.Search;
|
||||
|
||||
namespace JdeScoping.Core.Interfaces;
|
||||
|
||||
/// <summary>
|
||||
/// Search management operations for LotFinder SQL Server cache database.
|
||||
/// </summary>
|
||||
public partial interface ILotFinderRepository
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets all searches for a specific user.
|
||||
/// </summary>
|
||||
/// <param name="userName">User name to match.</param>
|
||||
/// <param name="ct">Cancellation token.</param>
|
||||
/// <returns>List of user's searches (lightweight - no criteria or results).</returns>
|
||||
Task<List<Search>> GetUserSearchesAsync(string userName, CancellationToken ct = default);
|
||||
|
||||
/// <summary>
|
||||
/// Gets all searches pending processing (Status less than 3).
|
||||
/// </summary>
|
||||
/// <param name="ct">Cancellation token.</param>
|
||||
/// <returns>List of queued searches ordered by SubmitDT (FIFO).</returns>
|
||||
Task<List<Search>> GetQueuedSearchesAsync(CancellationToken ct = default);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a single search by ID with criteria.
|
||||
/// </summary>
|
||||
/// <param name="id">Search ID.</param>
|
||||
/// <param name="ct">Cancellation token.</param>
|
||||
/// <returns>Search with criteria or null if not found.</returns>
|
||||
Task<Search?> GetSearchAsync(int id, CancellationToken ct = default);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Excel results binary for a completed search.
|
||||
/// </summary>
|
||||
/// <param name="id">Search ID.</param>
|
||||
/// <param name="ct">Cancellation token.</param>
|
||||
/// <returns>Excel file bytes or null if not found.</returns>
|
||||
Task<byte[]?> GetSearchResultsAsync(int id, CancellationToken ct = default);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new search request.
|
||||
/// </summary>
|
||||
/// <param name="search">Search to submit.</param>
|
||||
/// <param name="ct">Cancellation token.</param>
|
||||
/// <returns>Generated search ID.</returns>
|
||||
Task<int> SubmitSearchAsync(Search search, CancellationToken ct = default);
|
||||
|
||||
/// <summary>
|
||||
/// Updates the status of a search.
|
||||
/// </summary>
|
||||
/// <param name="id">Search ID.</param>
|
||||
/// <param name="status">New status.</param>
|
||||
/// <param name="ct">Cancellation token.</param>
|
||||
Task UpdateSearchStatusAsync(int id, SearchStatus status, CancellationToken ct = default);
|
||||
|
||||
/// <summary>
|
||||
/// Stores the Excel results for a completed search.
|
||||
/// </summary>
|
||||
/// <param name="id">Search ID.</param>
|
||||
/// <param name="results">Excel file bytes.</param>
|
||||
/// <param name="ct">Cancellation token.</param>
|
||||
Task UpdateSearchResultsAsync(int id, byte[] results, CancellationToken ct = default);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace JdeScoping.Core.Interfaces;
|
||||
|
||||
/// <summary>
|
||||
/// Repository for accessing LotFinder data from the local SQL Server cache.
|
||||
/// </summary>
|
||||
public partial interface ILotFinderRepository
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
namespace JdeScoping.Core.Interfaces;
|
||||
|
||||
/// <summary>
|
||||
/// Processor for executing user search requests.
|
||||
/// </summary>
|
||||
public interface ISearchProcessor
|
||||
{
|
||||
/// <summary>
|
||||
/// Processes a queued search request.
|
||||
/// </summary>
|
||||
Task ProcessSearchAsync(int searchId, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the next pending search to process.
|
||||
/// </summary>
|
||||
Task<int?> GetNextPendingSearchAsync(CancellationToken cancellationToken = default);
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
namespace JdeScoping.Core.Interfaces;
|
||||
|
||||
/// <summary>
|
||||
/// Processor for data synchronization from JDE/CMS to local cache.
|
||||
/// </summary>
|
||||
public interface IUpdateProcessor
|
||||
{
|
||||
/// <summary>
|
||||
/// Runs a mass (full) data refresh.
|
||||
/// </summary>
|
||||
Task RunMassRefreshAsync(CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Runs a daily incremental data refresh.
|
||||
/// </summary>
|
||||
Task RunDailyRefreshAsync(CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Runs an hourly data refresh.
|
||||
/// </summary>
|
||||
Task RunHourlyRefreshAsync(CancellationToken cancellationToken = default);
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Cronos" Version="0.11.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="10.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="10.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="10.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options" Version="10.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="10.0.1" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,12 @@
|
||||
namespace JdeScoping.Core.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Result of an authentication attempt
|
||||
/// </summary>
|
||||
/// <param name="Success">Whether authentication was successful</param>
|
||||
/// <param name="User">User info if successful, null otherwise</param>
|
||||
/// <param name="ErrorMessage">Error message if failed, null otherwise</param>
|
||||
public record AuthResult(
|
||||
bool Success,
|
||||
UserInfo? User,
|
||||
string? ErrorMessage);
|
||||
@@ -0,0 +1,35 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace JdeScoping.Core.Models.Enums;
|
||||
|
||||
/// <summary>
|
||||
/// Status of a search request
|
||||
/// </summary>
|
||||
[JsonConverter(typeof(JsonStringEnumConverter))]
|
||||
public enum SearchStatus
|
||||
{
|
||||
/// <summary>
|
||||
/// Search has been created but not yet submitted
|
||||
/// </summary>
|
||||
New = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Search has been submitted and is queued for processing
|
||||
/// </summary>
|
||||
Queued = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Search processing is running
|
||||
/// </summary>
|
||||
Running = 2,
|
||||
|
||||
/// <summary>
|
||||
/// Search processing has completed successfully
|
||||
/// </summary>
|
||||
Ended = 3,
|
||||
|
||||
/// <summary>
|
||||
/// Search processing encountered an error
|
||||
/// </summary>
|
||||
Error = 4
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace JdeScoping.Core.Models.Enums;
|
||||
|
||||
/// <summary>
|
||||
/// Types of data synchronization updates
|
||||
/// </summary>
|
||||
[JsonConverter(typeof(JsonStringEnumConverter))]
|
||||
public enum UpdateTypes
|
||||
{
|
||||
/// <summary>
|
||||
/// Hourly incremental update
|
||||
/// </summary>
|
||||
Hourly = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Daily update
|
||||
/// </summary>
|
||||
Daily = 2,
|
||||
|
||||
/// <summary>
|
||||
/// Mass (full) data refresh
|
||||
/// </summary>
|
||||
Mass = 3
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
namespace JdeScoping.Core.Models.Infrastructure;
|
||||
|
||||
/// <summary>
|
||||
/// Database column specification
|
||||
/// </summary>
|
||||
public class ColumnSpec
|
||||
{
|
||||
/// <summary>
|
||||
/// Column name
|
||||
/// </summary>
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Column definition (SQL type and constraints)
|
||||
/// </summary>
|
||||
public string Definition { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
public ColumnSpec()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor with name and definition
|
||||
/// </summary>
|
||||
/// <param name="name">Column name</param>
|
||||
/// <param name="definition">Column definition</param>
|
||||
public ColumnSpec(string name, string definition)
|
||||
{
|
||||
Name = name;
|
||||
Definition = definition;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
using JdeScoping.Core.Models.Enums;
|
||||
|
||||
namespace JdeScoping.Core.Models.Infrastructure;
|
||||
|
||||
/// <summary>
|
||||
/// Cache data update tracking entity
|
||||
/// </summary>
|
||||
public class DataUpdate
|
||||
{
|
||||
/// <summary>
|
||||
/// PK ID of record
|
||||
/// </summary>
|
||||
public int Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Name of source system (JDE/CMS/etc)
|
||||
/// </summary>
|
||||
public string SourceSystem { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Name of source data (WORK_ORDER, WORK_ORDER_STEP, etc)
|
||||
/// </summary>
|
||||
public string SourceData { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Cache table name
|
||||
/// </summary>
|
||||
public string TableName { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Timestamp at start of update
|
||||
/// </summary>
|
||||
public DateTime StartDt { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Timestamp at end of update
|
||||
/// </summary>
|
||||
public DateTime EndDt { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Type of data update (Hourly, Daily, Mass)
|
||||
/// </summary>
|
||||
public UpdateTypes UpdateType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether the update was successful
|
||||
/// </summary>
|
||||
public bool WasSuccessful { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Number of records in update
|
||||
/// </summary>
|
||||
public long NumberRecords { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
namespace JdeScoping.Core.Models.Infrastructure;
|
||||
|
||||
/// <summary>
|
||||
/// Static query type definitions
|
||||
/// </summary>
|
||||
public partial class QueryTypes
|
||||
{
|
||||
/// <summary>
|
||||
/// Work Order - Filter by work order only
|
||||
/// </summary>
|
||||
public static QueryTypes WorkOrder { get; } = new("WorkOrder", "Work Order", 10)
|
||||
{
|
||||
WorkOrderFilter = true
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Component Lot - Filter by component lot only
|
||||
/// </summary>
|
||||
public static QueryTypes ComponentLot { get; } = new("ComponentLot", "Component Lot", 20)
|
||||
{
|
||||
ComponentLotFilter = true
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Time Span + Profit Center
|
||||
/// </summary>
|
||||
public static QueryTypes TimeSpanProfitCenter { get; } = new("TimeSpanProfitCenter", "Time Span + Profit Center", 30)
|
||||
{
|
||||
TimeSpanFilter = true,
|
||||
ProfitCenterFilter = true
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Time Span + Work Center
|
||||
/// </summary>
|
||||
public static QueryTypes TimeSpanWorkCenter { get; } = new("TimeSpanWorkCenter", "Time Span + Work Center", 40)
|
||||
{
|
||||
TimeSpanFilter = true,
|
||||
WorkCenterFilter = true
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Time Span + Operator
|
||||
/// </summary>
|
||||
public static QueryTypes TimeSpanOperator { get; } = new("TimeSpanOperator", "Time Span + Operator", 50)
|
||||
{
|
||||
TimeSpanFilter = true,
|
||||
OperatorFilter = true
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Time Span + Profit Center + Item Number
|
||||
/// </summary>
|
||||
public static QueryTypes TimeSpanProfitCenterItem { get; } = new("TimeSpanProfitCenterItem", "Time Span + Profit Center + Item Number", 60)
|
||||
{
|
||||
TimeSpanFilter = true,
|
||||
ItemNumberFilter = true,
|
||||
ProfitCenterFilter = true
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Time Span + Profit Center + Item/Operation/MIS
|
||||
/// </summary>
|
||||
public static QueryTypes TimeSpanProfitCenterIOM { get; } = new("TimeSpanProfitCenterIOM", "Time Span + Profit Center + Item/Operation/MIS", 70)
|
||||
{
|
||||
TimeSpanFilter = true,
|
||||
ProfitCenterFilter = true,
|
||||
ItemOperationMisFilter = true
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Time Span + Profit Center + Work Order + Item/Operation/MIS
|
||||
/// </summary>
|
||||
public static QueryTypes TimeSpanProfitCenterWorkOrderIOM { get; } = new("TimeSpanProfitCenterWorkOrderIOM", "Time Span + Profit Center + Work Order + Item/Operation/MIS", 80)
|
||||
{
|
||||
TimeSpanFilter = true,
|
||||
WorkOrderFilter = true,
|
||||
ProfitCenterFilter = true,
|
||||
ItemOperationMisFilter = true
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Time Span + Profit Center + Extract MIS
|
||||
/// </summary>
|
||||
public static QueryTypes TimeSpanProfitCenterExtractMIS { get; } = new("TimeSpanProfitCenterExtractMIS", "Time Span + Profit Center + Extract MIS", 90)
|
||||
{
|
||||
TimeSpanFilter = true,
|
||||
ProfitCenterFilter = true,
|
||||
ExtractMisFilter = true
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Time Span + Work Center + Item Number
|
||||
/// </summary>
|
||||
public static QueryTypes TimeSpanWorkCenterItem { get; } = new("TimeSpanWorkCenterItem", "Time Span + Work Center + Item Number", 100)
|
||||
{
|
||||
TimeSpanFilter = true,
|
||||
ItemNumberFilter = true,
|
||||
WorkCenterFilter = true
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Time Span + Work Center + Extract MIS
|
||||
/// </summary>
|
||||
public static QueryTypes TimeSpanWorkCenterExtractMIS { get; } = new("TimeSpanWorkCenterExtractMIS", "Time Span + Work Center + Extract MIS", 110)
|
||||
{
|
||||
TimeSpanFilter = true,
|
||||
WorkCenterFilter = true,
|
||||
ExtractMisFilter = true
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Time Span + Work Center + Item/Operation/MIS
|
||||
/// </summary>
|
||||
public static QueryTypes TimeSpanWorkCenterIOM { get; } = new("TimeSpanWorkCenterIOM", "Time Span + Work Center + Item/Operation/MIS", 120)
|
||||
{
|
||||
TimeSpanFilter = true,
|
||||
WorkCenterFilter = true,
|
||||
ItemOperationMisFilter = true
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Time Span + Work Center + Work Order + Item/Operation/MIS
|
||||
/// </summary>
|
||||
public static QueryTypes TimeSpanWorkCenterWorkOrderIOM { get; } = new("TimeSpanWorkCenterWorkOrderIOM", "Time Span + Work Center + Work Order + Item/Operation/MIS", 130)
|
||||
{
|
||||
TimeSpanFilter = true,
|
||||
WorkOrderFilter = true,
|
||||
WorkCenterFilter = true,
|
||||
ItemOperationMisFilter = true
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Time Span + Item Number
|
||||
/// </summary>
|
||||
public static QueryTypes TimeSpanItem { get; } = new("TimeSpanItem", "Time Span + Item Number", 140)
|
||||
{
|
||||
TimeSpanFilter = true,
|
||||
ItemNumberFilter = true
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Time Span + Work Center + Operator
|
||||
/// </summary>
|
||||
public static QueryTypes TimeSpanWorkCenterOperator { get; } = new("TimeSpanWorkCenterOperator", "Time Span + Work Center + Operator", 150)
|
||||
{
|
||||
TimeSpanFilter = true,
|
||||
WorkCenterFilter = true,
|
||||
OperatorFilter = true
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Time Span + Profit Center + Operator
|
||||
/// </summary>
|
||||
public static QueryTypes TimeSpanProfitCenterOperator { get; } = new("TimeSpanProfitCenterOperator", "Time Span + Profit Center + Operator", 160)
|
||||
{
|
||||
TimeSpanFilter = true,
|
||||
ProfitCenterFilter = true,
|
||||
OperatorFilter = true
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
using JdeScoping.Core.Models.Search;
|
||||
|
||||
namespace JdeScoping.Core.Models.Infrastructure;
|
||||
|
||||
/// <summary>
|
||||
/// Query type definition with filter flags.
|
||||
/// Defines valid combinations of search filters that can be applied together.
|
||||
/// </summary>
|
||||
public partial class QueryTypes
|
||||
{
|
||||
/// <summary>
|
||||
/// Query type unique code
|
||||
/// </summary>
|
||||
public string Code { get; private set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Query type display name
|
||||
/// </summary>
|
||||
public string Name { get; private set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Sort order index for display
|
||||
/// </summary>
|
||||
public int OrderIndex { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether this query type supports time span filtering
|
||||
/// </summary>
|
||||
public bool TimeSpanFilter { get; private init; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether this query type supports work order filtering
|
||||
/// </summary>
|
||||
public bool WorkOrderFilter { get; private init; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether this query type supports item number filtering
|
||||
/// </summary>
|
||||
public bool ItemNumberFilter { get; private init; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether this query type supports profit center filtering
|
||||
/// </summary>
|
||||
public bool ProfitCenterFilter { get; private init; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether this query type supports work center filtering
|
||||
/// </summary>
|
||||
public bool WorkCenterFilter { get; private init; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether this query type supports component lot filtering
|
||||
/// </summary>
|
||||
public bool ComponentLotFilter { get; private init; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether this query type supports operator filtering
|
||||
/// </summary>
|
||||
public bool OperatorFilter { get; private init; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether this query type supports item/operation/MIS filtering
|
||||
/// </summary>
|
||||
public bool ItemOperationMisFilter { get; private init; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether this query type supports MIS data extraction
|
||||
/// </summary>
|
||||
public bool ExtractMisFilter { get; private init; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether this query type supports received item number IIS filtering
|
||||
/// </summary>
|
||||
public bool ReceivedItemNumberIisFilter { get; private init; }
|
||||
|
||||
/// <summary>
|
||||
/// Static dictionary of all defined query types
|
||||
/// </summary>
|
||||
private static readonly Dictionary<string, QueryTypes> _definedTypes = new();
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor for serialization
|
||||
/// </summary>
|
||||
public QueryTypes()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor with code, name, and order index
|
||||
/// </summary>
|
||||
private QueryTypes(string code, string name, int orderIndex)
|
||||
{
|
||||
Code = code;
|
||||
Name = name;
|
||||
OrderIndex = orderIndex;
|
||||
_definedTypes[code] = this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Identifies the appropriate query type based on search criteria flags.
|
||||
/// </summary>
|
||||
/// <param name="criteria">Search criteria to evaluate</param>
|
||||
/// <returns>Matching QueryTypes or null if no match found</returns>
|
||||
public static QueryTypes? Identify(SearchCriteria criteria)
|
||||
{
|
||||
if (criteria == null)
|
||||
return null;
|
||||
|
||||
// Determine which filters are active
|
||||
bool hasTimeSpan = criteria.MinimumDt.HasValue || criteria.MaximumDt.HasValue;
|
||||
bool hasWorkOrder = criteria.WorkOrderNumbers?.Count > 0;
|
||||
bool hasItemNumber = criteria.ItemNumbers?.Count > 0;
|
||||
bool hasProfitCenter = criteria.ProfitCenters?.Count > 0;
|
||||
bool hasWorkCenter = criteria.WorkCenters?.Count > 0;
|
||||
bool hasComponentLot = criteria.ComponentLotNumbers?.Count > 0;
|
||||
bool hasOperator = criteria.OperatorIDs?.Count > 0;
|
||||
bool hasItemOperationMis = criteria.PartOperations?.Count > 0;
|
||||
bool hasExtractMis = criteria.ExtractMisData;
|
||||
|
||||
// Find matching query type
|
||||
foreach (var queryType in _definedTypes.Values)
|
||||
{
|
||||
if (queryType.Matches(hasTimeSpan, hasWorkOrder, hasItemNumber, hasProfitCenter,
|
||||
hasWorkCenter, hasComponentLot, hasOperator, hasItemOperationMis, hasExtractMis))
|
||||
{
|
||||
return queryType;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the given filter flags match this query type's configuration.
|
||||
/// </summary>
|
||||
private bool Matches(bool timeSpan, bool workOrder, bool itemNumber, bool profitCenter,
|
||||
bool workCenter, bool componentLot, bool operatorFilter, bool itemOperationMis, bool extractMis)
|
||||
{
|
||||
return TimeSpanFilter == timeSpan &&
|
||||
WorkOrderFilter == workOrder &&
|
||||
ItemNumberFilter == itemNumber &&
|
||||
ProfitCenterFilter == profitCenter &&
|
||||
WorkCenterFilter == workCenter &&
|
||||
ComponentLotFilter == componentLot &&
|
||||
OperatorFilter == operatorFilter &&
|
||||
ItemOperationMisFilter == itemOperationMis &&
|
||||
ExtractMisFilter == extractMis;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all defined query types as a read-only dictionary
|
||||
/// </summary>
|
||||
public static IReadOnlyDictionary<string, QueryTypes> DefinedTypes => _definedTypes;
|
||||
|
||||
/// <summary>
|
||||
/// Gets all defined query types sorted by OrderIndex
|
||||
/// </summary>
|
||||
public static IEnumerable<QueryTypes> GetAll() =>
|
||||
_definedTypes.Values.OrderBy(qt => qt.OrderIndex);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a query type by its code
|
||||
/// </summary>
|
||||
/// <param name="code">The query type code</param>
|
||||
/// <returns>The matching QueryTypes or null if not found</returns>
|
||||
public static QueryTypes? GetByCode(string code) =>
|
||||
_definedTypes.TryGetValue(code, out var queryType) ? queryType : null;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
namespace JdeScoping.Core.Models.Infrastructure;
|
||||
|
||||
/// <summary>
|
||||
/// Generic process status update message
|
||||
/// </summary>
|
||||
public class StatusUpdate
|
||||
{
|
||||
/// <summary>
|
||||
/// Status message to display
|
||||
/// </summary>
|
||||
public string Message { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Timestamp when message was generated
|
||||
/// </summary>
|
||||
public DateTime Timestamp { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
public StatusUpdate()
|
||||
{
|
||||
Timestamp = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor with message
|
||||
/// </summary>
|
||||
/// <param name="message">Status message</param>
|
||||
public StatusUpdate(string message)
|
||||
{
|
||||
Message = message;
|
||||
Timestamp = DateTime.UtcNow;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
namespace JdeScoping.Core.Models.Infrastructure;
|
||||
|
||||
/// <summary>
|
||||
/// Database table specification for dynamic SQL generation
|
||||
/// </summary>
|
||||
public class TableSpec
|
||||
{
|
||||
/// <summary>
|
||||
/// Table name
|
||||
/// </summary>
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Temporary table name (computed as # + Name)
|
||||
/// </summary>
|
||||
public string TempTableName => $"#{Name}";
|
||||
|
||||
/// <summary>
|
||||
/// Table columns
|
||||
/// </summary>
|
||||
public List<ColumnSpec> Columns { get; set; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// Table columns that form the primary key
|
||||
/// </summary>
|
||||
public List<ColumnSpec> PrimaryKey { get; set; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
public TableSpec()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor with table name
|
||||
/// </summary>
|
||||
/// <param name="name">Table name</param>
|
||||
public TableSpec(string name)
|
||||
{
|
||||
Name = name;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates SQL for creating an index on the primary key (stub)
|
||||
/// </summary>
|
||||
/// <returns>SQL CREATE INDEX statement</returns>
|
||||
public string GenerateIndex()
|
||||
{
|
||||
// Stub implementation - to be expanded based on spec
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates SQL for dropping the table (stub)
|
||||
/// </summary>
|
||||
/// <returns>SQL DROP TABLE statement</returns>
|
||||
public string GenerateDrop()
|
||||
{
|
||||
// Stub implementation - to be expanded based on spec
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates SQL for creating the table (stub)
|
||||
/// </summary>
|
||||
/// <returns>SQL CREATE TABLE statement</returns>
|
||||
public string GenerateCreate()
|
||||
{
|
||||
// Stub implementation - to be expanded based on spec
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a column specification by name (stub)
|
||||
/// </summary>
|
||||
/// <param name="columnName">Name of column to find</param>
|
||||
/// <returns>ColumnSpec or null if not found</returns>
|
||||
public ColumnSpec? GetColumn(string columnName)
|
||||
{
|
||||
return Columns.Find(c => c.Name == columnName);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
using JdeScoping.Core.Helpers;
|
||||
|
||||
namespace JdeScoping.Core.Models.Inventory;
|
||||
|
||||
/// <summary>
|
||||
/// JDE item (part type) master entity
|
||||
/// </summary>
|
||||
public class Item
|
||||
{
|
||||
/// <summary>
|
||||
/// Item unique short number
|
||||
/// </summary>
|
||||
public long ShortItemNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Item unique number
|
||||
/// </summary>
|
||||
public string ItemNumber { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Item description
|
||||
/// </summary>
|
||||
public string Description { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Item master planning family
|
||||
/// </summary>
|
||||
public string? PlanningFamily { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Item master stocking type code
|
||||
/// </summary>
|
||||
public string? StockingType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// JDE date of last update to record (private backing field for Dapper mapping)
|
||||
/// </summary>
|
||||
private int LastUpdateDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// JDE time of day of last update to record (private backing field for Dapper mapping)
|
||||
/// </summary>
|
||||
private int LastUpdateTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Timestamp of last update to record (computed from JDE date/time)
|
||||
/// </summary>
|
||||
public DateTime? LastUpdateDt => JdeDateConverter.ToDateTime(LastUpdateDate, LastUpdateTime);
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
using JdeScoping.Core.Helpers;
|
||||
|
||||
namespace JdeScoping.Core.Models.Inventory;
|
||||
|
||||
/// <summary>
|
||||
/// JDE lot entity
|
||||
/// </summary>
|
||||
public class Lot
|
||||
{
|
||||
/// <summary>
|
||||
/// Lot unique number
|
||||
/// </summary>
|
||||
public string LotNumber { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Business unit unique code
|
||||
/// </summary>
|
||||
public string BranchCode { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Short item number
|
||||
/// </summary>
|
||||
public long ShortItemNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Item number
|
||||
/// </summary>
|
||||
public string ItemNumber { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Supplier address number
|
||||
/// </summary>
|
||||
public long SupplierCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Lot status code
|
||||
/// </summary>
|
||||
public char StatusCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Memo line 1
|
||||
/// </summary>
|
||||
public string? Memo1 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Memo line 2
|
||||
/// </summary>
|
||||
public string? Memo2 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Memo line 3
|
||||
/// </summary>
|
||||
public string? Memo3 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// JDE date of last update to record (private backing field for Dapper mapping)
|
||||
/// </summary>
|
||||
private int LastUpdateDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// JDE time of day of last update to record (private backing field for Dapper mapping)
|
||||
/// </summary>
|
||||
private int LastUpdateTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Timestamp of last update to record (computed from JDE date/time)
|
||||
/// </summary>
|
||||
public DateTime? LastUpdateDt => JdeDateConverter.ToDateTime(LastUpdateDate, LastUpdateTime);
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
namespace JdeScoping.Core.Models.Inventory;
|
||||
|
||||
/// <summary>
|
||||
/// JDE lot location entity
|
||||
/// </summary>
|
||||
public class LotLocation
|
||||
{
|
||||
/// <summary>
|
||||
/// Lot unique number
|
||||
/// </summary>
|
||||
public string LotNumber { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Short item number
|
||||
/// </summary>
|
||||
public long ShortItemNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Business unit unique code
|
||||
/// </summary>
|
||||
public string BranchCode { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Location code where lot is located
|
||||
/// </summary>
|
||||
public string Location { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Timestamp of last update to record
|
||||
/// </summary>
|
||||
public DateTime? LastUpdateDt { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
using JdeScoping.Core.Helpers;
|
||||
|
||||
namespace JdeScoping.Core.Models.Inventory;
|
||||
|
||||
/// <summary>
|
||||
/// Cardex (lot usage) entry entity
|
||||
/// </summary>
|
||||
public class LotUsage
|
||||
{
|
||||
/// <summary>
|
||||
/// Record unique / PK ID
|
||||
/// </summary>
|
||||
public long UniqueId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Work order unique number
|
||||
/// </summary>
|
||||
public long WorkOrderNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Lot number of component
|
||||
/// </summary>
|
||||
public string LotNumber { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Component issuance branch code
|
||||
/// </summary>
|
||||
public string BranchCode { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Component item short number
|
||||
/// </summary>
|
||||
public long ShortItemNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Transaction quantity
|
||||
/// </summary>
|
||||
public decimal Quantity { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// JDE date of last update to record (private backing field for Dapper mapping)
|
||||
/// </summary>
|
||||
private int LastUpdateDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// JDE time of day of last update to record (private backing field for Dapper mapping)
|
||||
/// </summary>
|
||||
private int LastUpdateTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Timestamp of last update to record (computed from JDE date/time)
|
||||
/// </summary>
|
||||
public DateTime? LastUpdateDt => JdeDateConverter.ToDateTime(LastUpdateDate, LastUpdateTime);
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
namespace JdeScoping.Core.Models.Lookup;
|
||||
|
||||
/// <summary>
|
||||
/// JDE function code lookup entity
|
||||
/// </summary>
|
||||
public class FunctionCode
|
||||
{
|
||||
/// <summary>
|
||||
/// Unique function code
|
||||
/// </summary>
|
||||
public string Code { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Function description
|
||||
/// </summary>
|
||||
public string Description { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Timestamp of last update to record
|
||||
/// </summary>
|
||||
public DateTime? LastUpdateDt { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
using JdeScoping.Core.Helpers;
|
||||
|
||||
namespace JdeScoping.Core.Models.Lookup;
|
||||
|
||||
/// <summary>
|
||||
/// JDE work order status code lookup entity
|
||||
/// </summary>
|
||||
public class StatusCode
|
||||
{
|
||||
/// <summary>
|
||||
/// Status code unique code
|
||||
/// </summary>
|
||||
public string Code { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Status code description
|
||||
/// </summary>
|
||||
public string Description { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// JDE date of last update to record (private backing field for Dapper mapping)
|
||||
/// </summary>
|
||||
private int LastUpdateDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// JDE time of day of last update to record (private backing field for Dapper mapping)
|
||||
/// </summary>
|
||||
private int LastUpdateTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Timestamp of last update to record (computed from JDE date/time)
|
||||
/// </summary>
|
||||
public DateTime? LastUpdateDt => JdeDateConverter.ToDateTime(LastUpdateDate, LastUpdateTime);
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
using JdeScoping.Core.Helpers;
|
||||
|
||||
namespace JdeScoping.Core.Models.Organization;
|
||||
|
||||
/// <summary>
|
||||
/// JDE branch entity
|
||||
/// </summary>
|
||||
public class Branch
|
||||
{
|
||||
/// <summary>
|
||||
/// Branch unique code
|
||||
/// </summary>
|
||||
public string Code { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Branch description
|
||||
/// </summary>
|
||||
public string Description { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// JDE date of last update to record (private backing field for Dapper mapping)
|
||||
/// </summary>
|
||||
private int LastUpdateDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// JDE time of day of last update to record (private backing field for Dapper mapping)
|
||||
/// </summary>
|
||||
private int LastUpdateTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Timestamp of last update to record (computed from JDE date/time)
|
||||
/// </summary>
|
||||
public DateTime? LastUpdateDt => JdeDateConverter.ToDateTime(LastUpdateDate, LastUpdateTime);
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
using JdeScoping.Core.Helpers;
|
||||
|
||||
namespace JdeScoping.Core.Models.Organization;
|
||||
|
||||
/// <summary>
|
||||
/// JDE user (operator) entity
|
||||
/// </summary>
|
||||
public class JdeUser
|
||||
{
|
||||
/// <summary>
|
||||
/// User unique address number
|
||||
/// </summary>
|
||||
public long AddressNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// User unique login ID
|
||||
/// </summary>
|
||||
public string UserId { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// User's full name (last, first [middle initial])
|
||||
/// </summary>
|
||||
public string FullName { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// JDE date of last update to record (private backing field for Dapper mapping)
|
||||
/// </summary>
|
||||
private int LastUpdateDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// JDE time of day of last update to record (private backing field for Dapper mapping)
|
||||
/// </summary>
|
||||
private int LastUpdateTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Timestamp of last update to record (computed from JDE date/time)
|
||||
/// </summary>
|
||||
public DateTime? LastUpdateDt => JdeDateConverter.ToDateTime(LastUpdateDate, LastUpdateTime);
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
using JdeScoping.Core.Helpers;
|
||||
|
||||
namespace JdeScoping.Core.Models.Organization;
|
||||
|
||||
/// <summary>
|
||||
/// Organization hierarchy (profit center to work center mapping) entity
|
||||
/// </summary>
|
||||
public class OrgHierarchy
|
||||
{
|
||||
/// <summary>
|
||||
/// Work center unique code
|
||||
/// </summary>
|
||||
public string WorkCenterCode { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Branch unit code
|
||||
/// </summary>
|
||||
public string BranchCode { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Profit center unique code
|
||||
/// </summary>
|
||||
public string ProfitCenterCode { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// JDE date of last update to record (private backing field for Dapper mapping)
|
||||
/// </summary>
|
||||
private int LastUpdateDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// JDE time of day of last update to record (private backing field for Dapper mapping)
|
||||
/// </summary>
|
||||
private int LastUpdateTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Timestamp of last update to record (computed from JDE date/time)
|
||||
/// </summary>
|
||||
public DateTime? LastUpdateDt => JdeDateConverter.ToDateTime(LastUpdateDate, LastUpdateTime);
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
using JdeScoping.Core.Helpers;
|
||||
using JdeScoping.Core.Interfaces;
|
||||
|
||||
namespace JdeScoping.Core.Models.Organization;
|
||||
|
||||
/// <summary>
|
||||
/// JDE profit center entity
|
||||
/// </summary>
|
||||
public class ProfitCenter : IBusinessUnit
|
||||
{
|
||||
/// <summary>
|
||||
/// Profit center unique code
|
||||
/// </summary>
|
||||
public string Code { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Profit center description
|
||||
/// </summary>
|
||||
public string Description { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// JDE date of last update to record (private backing field for Dapper mapping)
|
||||
/// </summary>
|
||||
private int LastUpdateDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// JDE time of day of last update to record (private backing field for Dapper mapping)
|
||||
/// </summary>
|
||||
private int LastUpdateTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Timestamp of last update to record (computed from JDE date/time)
|
||||
/// </summary>
|
||||
public DateTime? LastUpdateDt => JdeDateConverter.ToDateTime(LastUpdateDate, LastUpdateTime);
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
using JdeScoping.Core.Helpers;
|
||||
|
||||
namespace JdeScoping.Core.Models.Organization;
|
||||
|
||||
/// <summary>
|
||||
/// JDE item router master entity
|
||||
/// </summary>
|
||||
public class RouteMaster
|
||||
{
|
||||
/// <summary>
|
||||
/// Unique code for branch
|
||||
/// </summary>
|
||||
public string BranchCode { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Unique number for item
|
||||
/// </summary>
|
||||
public string ItemNumber { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Router type
|
||||
/// </summary>
|
||||
public string RoutingType { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Job step operation number
|
||||
/// </summary>
|
||||
public decimal SequenceNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Job step function code
|
||||
/// </summary>
|
||||
public string FunctionCode { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Work center unique code
|
||||
/// </summary>
|
||||
public string WorkCenterCode { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// JDE date representation of date record effectivity starts (private backing field for Dapper mapping)
|
||||
/// </summary>
|
||||
private int StartDateDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Date record effectivity starts (computed from JDE date)
|
||||
/// </summary>
|
||||
public DateTime? StartDate => JdeDateConverter.ToDateTime(StartDateDate);
|
||||
|
||||
/// <summary>
|
||||
/// JDE date representation of date record effectivity ends (private backing field for Dapper mapping)
|
||||
/// </summary>
|
||||
private int? EndDateDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Date record effectivity ends (computed from JDE date, nullable)
|
||||
/// </summary>
|
||||
public DateTime? EndDate => EndDateDate.HasValue ? JdeDateConverter.ToDateTime(EndDateDate.Value) : null;
|
||||
|
||||
/// <summary>
|
||||
/// JDE date of last update to record (private backing field for Dapper mapping)
|
||||
/// </summary>
|
||||
private int LastUpdateDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// JDE time of day of last update to record (private backing field for Dapper mapping)
|
||||
/// </summary>
|
||||
private int LastUpdateTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Timestamp of last update to record (computed from JDE date/time)
|
||||
/// </summary>
|
||||
public DateTime? LastUpdateDt => JdeDateConverter.ToDateTime(LastUpdateDate, LastUpdateTime);
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
using JdeScoping.Core.Helpers;
|
||||
using JdeScoping.Core.Interfaces;
|
||||
|
||||
namespace JdeScoping.Core.Models.Organization;
|
||||
|
||||
/// <summary>
|
||||
/// JDE work center entity
|
||||
/// </summary>
|
||||
public class WorkCenter : IBusinessUnit
|
||||
{
|
||||
/// <summary>
|
||||
/// Work center unique code
|
||||
/// </summary>
|
||||
public string Code { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Work center description
|
||||
/// </summary>
|
||||
public string Description { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// JDE date of last update to record (private backing field for Dapper mapping)
|
||||
/// </summary>
|
||||
private int LastUpdateDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// JDE time of day of last update to record (private backing field for Dapper mapping)
|
||||
/// </summary>
|
||||
private int LastUpdateTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Timestamp of last update to record (computed from JDE date/time)
|
||||
/// </summary>
|
||||
public DateTime? LastUpdateDt => JdeDateConverter.ToDateTime(LastUpdateDate, LastUpdateTime);
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
namespace JdeScoping.Core.Models.Quality;
|
||||
|
||||
/// <summary>
|
||||
/// CMS MIS data entity
|
||||
/// </summary>
|
||||
public class MisData
|
||||
{
|
||||
/// <summary>
|
||||
/// Item unique number
|
||||
/// </summary>
|
||||
public string ItemNumber { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Branch unique code
|
||||
/// </summary>
|
||||
public string BranchCode { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Operation job step number
|
||||
/// </summary>
|
||||
public string SequenceNumber { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// MIS unique number
|
||||
/// </summary>
|
||||
public string MisNumber { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// MIS revision ID
|
||||
/// </summary>
|
||||
public string? RevId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Characteristic number
|
||||
/// </summary>
|
||||
public string CharNumber { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Test description
|
||||
/// </summary>
|
||||
public string? TestDescription { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Type of sampling
|
||||
/// </summary>
|
||||
public string? SamplingType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Sampling selection value
|
||||
/// </summary>
|
||||
public string? SamplingValue { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Tools and gauges for MIS
|
||||
/// </summary>
|
||||
public string? ToolsGauges { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Work instructions for MIS
|
||||
/// </summary>
|
||||
public string? WorkInstructions { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// MIS release status
|
||||
/// </summary>
|
||||
public string Status { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// MIS release date
|
||||
/// </summary>
|
||||
public DateTime? ReleaseDate { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using JdeScoping.Core.Models.Enums;
|
||||
|
||||
namespace JdeScoping.Core.Models.Search;
|
||||
|
||||
/// <summary>
|
||||
/// User search request entity
|
||||
/// </summary>
|
||||
public class Search
|
||||
{
|
||||
/// <summary>
|
||||
/// PK ID of search
|
||||
/// </summary>
|
||||
public int Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// User name of user that created search
|
||||
/// </summary>
|
||||
public string UserName { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// User-friendly name for search
|
||||
/// </summary>
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Current search status
|
||||
/// </summary>
|
||||
[JsonConverter(typeof(JsonStringEnumConverter))]
|
||||
public SearchStatus Status { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Timestamp search was submitted
|
||||
/// </summary>
|
||||
public DateTime? SubmitDt { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Timestamp search was started
|
||||
/// </summary>
|
||||
public DateTime? StartDt { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Timestamp search was completed
|
||||
/// </summary>
|
||||
public DateTime? EndDt { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// JSON-packed search criteria (stored in database)
|
||||
/// </summary>
|
||||
public string CriteriaJson { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Search criteria (deserialized from CriteriaJSON)
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public SearchCriteria? Criteria
|
||||
{
|
||||
get
|
||||
{
|
||||
if (string.IsNullOrEmpty(CriteriaJson))
|
||||
return null;
|
||||
|
||||
try
|
||||
{
|
||||
return JsonSerializer.Deserialize<SearchCriteria>(CriteriaJson);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
set
|
||||
{
|
||||
CriteriaJson = value != null
|
||||
? JsonSerializer.Serialize(value)
|
||||
: string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Excel search results file (binary)
|
||||
/// </summary>
|
||||
public byte[]? Results { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
using JdeScoping.Core.ViewModels;
|
||||
|
||||
namespace JdeScoping.Core.Models.Search;
|
||||
|
||||
/// <summary>
|
||||
/// JDE data filter criteria for search requests
|
||||
/// </summary>
|
||||
public class SearchCriteria
|
||||
{
|
||||
/// <summary>
|
||||
/// Minimum timestamp to include in search results
|
||||
/// </summary>
|
||||
public DateTime? MinimumDt { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Maximum timestamp to include in search results
|
||||
/// </summary>
|
||||
public DateTime? MaximumDt { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Collection of work order numbers to include
|
||||
/// </summary>
|
||||
public List<long> WorkOrderNumbers { get; set; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// Collection of item numbers to include
|
||||
/// </summary>
|
||||
public List<string> ItemNumbers { get; set; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// Collection of profit center codes to include
|
||||
/// </summary>
|
||||
public List<string> ProfitCenters { get; set; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// Collection of work center codes to include
|
||||
/// </summary>
|
||||
public List<string> WorkCenters { get; set; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// Collection of operator IDs to include
|
||||
/// </summary>
|
||||
public List<string> OperatorIDs { get; set; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// Collection of component lot numbers to include (for upper level lot filtering)
|
||||
/// </summary>
|
||||
public List<LotViewModel> ComponentLotNumbers { get; set; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not to extract MIS data from CMS
|
||||
/// </summary>
|
||||
public bool ExtractMisData { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// List of part/operation/MIS combinations for filtering
|
||||
/// </summary>
|
||||
public List<PartOperationViewModel> PartOperations { get; set; } = [];
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using JdeScoping.Core.Models.Enums;
|
||||
|
||||
namespace JdeScoping.Core.Models.Search;
|
||||
|
||||
/// <summary>
|
||||
/// Search status update message for SignalR notifications
|
||||
/// </summary>
|
||||
public class SearchUpdate
|
||||
{
|
||||
/// <summary>
|
||||
/// Search PK ID
|
||||
/// </summary>
|
||||
public int Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// User name of user that submitted search
|
||||
/// </summary>
|
||||
public string UserName { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Name of the search
|
||||
/// </summary>
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Search status code
|
||||
/// </summary>
|
||||
[JsonConverter(typeof(JsonStringEnumConverter))]
|
||||
public SearchStatus Status { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Timestamp search was submitted
|
||||
/// </summary>
|
||||
public DateTime? SubmitDt { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Timestamp search was started
|
||||
/// </summary>
|
||||
public DateTime? StartDt { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Timestamp search was completed
|
||||
/// </summary>
|
||||
public DateTime? EndDt { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Timestamp when this update was generated
|
||||
/// </summary>
|
||||
public DateTime Timestamp { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
public SearchUpdate()
|
||||
{
|
||||
Timestamp = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor that copies values from a Search entity
|
||||
/// </summary>
|
||||
/// <param name="search">Search to copy values from</param>
|
||||
public SearchUpdate(Search search)
|
||||
{
|
||||
Id = search.Id;
|
||||
UserName = search.UserName;
|
||||
Name = search.Name;
|
||||
Status = search.Status;
|
||||
SubmitDt = search.SubmitDt;
|
||||
StartDt = search.StartDt;
|
||||
EndDt = search.EndDt;
|
||||
Timestamp = DateTime.UtcNow;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
namespace JdeScoping.Core.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Authenticated user information entity (replaces legacy LDAPEntry)
|
||||
/// </summary>
|
||||
public class UserInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// LDAP Distinguished Name
|
||||
/// </summary>
|
||||
public string Dn { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// User's login username
|
||||
/// </summary>
|
||||
public string Username { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// User's first name
|
||||
/// </summary>
|
||||
public string FirstName { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// User's last name
|
||||
/// </summary>
|
||||
public string LastName { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// User's display name (computed property)
|
||||
/// Falls back to Username if FirstName and LastName are both empty
|
||||
/// </summary>
|
||||
public string DisplayName
|
||||
{
|
||||
get
|
||||
{
|
||||
if (string.IsNullOrEmpty(LastName) && string.IsNullOrEmpty(FirstName))
|
||||
{
|
||||
return Username;
|
||||
}
|
||||
|
||||
return $"{FirstName} {LastName}".Trim();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// User's organization title
|
||||
/// </summary>
|
||||
public string Title { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// User's email address
|
||||
/// </summary>
|
||||
public string EmailAddress { get; set; } = string.Empty;
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
using JdeScoping.Core.Helpers;
|
||||
|
||||
namespace JdeScoping.Core.Models.WorkOrders;
|
||||
|
||||
/// <summary>
|
||||
/// JDE work order entity
|
||||
/// </summary>
|
||||
public class WorkOrder
|
||||
{
|
||||
/// <summary>
|
||||
/// Work order unique number
|
||||
/// </summary>
|
||||
public long WorkOrderNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Work order branch code
|
||||
/// </summary>
|
||||
public string BranchCode { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Work order assigned lot number
|
||||
/// </summary>
|
||||
public string? LotNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Work order item number
|
||||
/// </summary>
|
||||
public string ItemNumber { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Work order short item number
|
||||
/// </summary>
|
||||
public long ShortItemNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Work order's parent unique number
|
||||
/// </summary>
|
||||
public string? ParentWorkOrderNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Order quantity
|
||||
/// </summary>
|
||||
public decimal OrderQuantity { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Quantity on hold
|
||||
/// </summary>
|
||||
public decimal HeldQuantity { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Quantity shipped
|
||||
/// </summary>
|
||||
public decimal ShippedQuantity { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Work order status code
|
||||
/// </summary>
|
||||
public string StatusCode { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Date of last update to status code
|
||||
/// </summary>
|
||||
public DateTime? StatusCodeUpdateDt { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Date work order was issued
|
||||
/// </summary>
|
||||
public DateTime IssueDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Date work order was started
|
||||
/// </summary>
|
||||
public DateTime StartDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Work order routing type
|
||||
/// </summary>
|
||||
public string RoutingType { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// JDE date of last update to record (private backing field for Dapper mapping)
|
||||
/// </summary>
|
||||
private int LastUpdateDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// JDE time of day of last update to record (private backing field for Dapper mapping)
|
||||
/// </summary>
|
||||
private int LastUpdateTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Timestamp of last update to record (computed from JDE date/time)
|
||||
/// </summary>
|
||||
public DateTime? LastUpdateDt => JdeDateConverter.ToDateTime(LastUpdateDate, LastUpdateTime);
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
using JdeScoping.Core.Helpers;
|
||||
|
||||
namespace JdeScoping.Core.Models.WorkOrders;
|
||||
|
||||
/// <summary>
|
||||
/// Work order component usage entity
|
||||
/// </summary>
|
||||
public class WorkOrderComponent
|
||||
{
|
||||
/// <summary>
|
||||
/// Record unique / PK ID
|
||||
/// </summary>
|
||||
public long UniqueId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Work order unique number
|
||||
/// </summary>
|
||||
public long WorkOrderNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Lot number of component
|
||||
/// </summary>
|
||||
public string? LotNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Component issuance branch code
|
||||
/// </summary>
|
||||
public string BranchCode { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Component item short number
|
||||
/// </summary>
|
||||
public long? ShortItemNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Transaction quantity
|
||||
/// </summary>
|
||||
public decimal Quantity { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// JDE date of last update to record (private backing field for Dapper mapping)
|
||||
/// </summary>
|
||||
private int LastUpdateDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// JDE time of day of last update to record (private backing field for Dapper mapping)
|
||||
/// </summary>
|
||||
private int LastUpdateTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Timestamp of last update to record (computed from JDE date/time)
|
||||
/// </summary>
|
||||
public DateTime? LastUpdateDt => JdeDateConverter.ToDateTime(LastUpdateDate, LastUpdateTime);
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
using JdeScoping.Core.Helpers;
|
||||
|
||||
namespace JdeScoping.Core.Models.WorkOrders;
|
||||
|
||||
/// <summary>
|
||||
/// Work order step transaction (routing) entity
|
||||
/// </summary>
|
||||
public class WorkOrderRouting
|
||||
{
|
||||
/// <summary>
|
||||
/// Transaction user ID
|
||||
/// </summary>
|
||||
public string UserId { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Transaction batch number
|
||||
/// </summary>
|
||||
public string BatchNumber { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Transaction number
|
||||
/// </summary>
|
||||
public string TransactionNumber { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Transaction line number
|
||||
/// </summary>
|
||||
public int LineNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Operation sequence number
|
||||
/// </summary>
|
||||
public decimal StepNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Unique code for work center
|
||||
/// </summary>
|
||||
public string WorkCenterCode { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Unique number for work order
|
||||
/// </summary>
|
||||
public long WorkOrderNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Work order routing type
|
||||
/// </summary>
|
||||
public string RoutingType { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Unique code for branch
|
||||
/// </summary>
|
||||
public string BranchCode { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Operation sequence description
|
||||
/// </summary>
|
||||
public string? StepDescription { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Operation function code
|
||||
/// </summary>
|
||||
public string FunctionCode { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// JDE date representation of transaction original date (private backing field for Dapper mapping)
|
||||
/// </summary>
|
||||
private int TransactionDateDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Transaction original date (computed from JDE date)
|
||||
/// </summary>
|
||||
public DateTime? TransactionDate => JdeDateConverter.ToDateTime(TransactionDateDate);
|
||||
|
||||
/// <summary>
|
||||
/// JDE date of last update to record (private backing field for Dapper mapping)
|
||||
/// </summary>
|
||||
private int LastUpdateDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// JDE time of day of last update to record (private backing field for Dapper mapping)
|
||||
/// </summary>
|
||||
private int LastUpdateTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Timestamp of last update to record (computed from JDE date/time)
|
||||
/// </summary>
|
||||
public DateTime? LastUpdateDt => JdeDateConverter.ToDateTime(LastUpdateDate, LastUpdateTime);
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
using JdeScoping.Core.Helpers;
|
||||
|
||||
namespace JdeScoping.Core.Models.WorkOrders;
|
||||
|
||||
/// <summary>
|
||||
/// JDE work order operation step entity
|
||||
/// </summary>
|
||||
public class WorkOrderStep
|
||||
{
|
||||
/// <summary>
|
||||
/// Unique number for work order
|
||||
/// </summary>
|
||||
public long WorkOrderNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Unique code for branch
|
||||
/// </summary>
|
||||
public string BranchCode { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Unique code for work center
|
||||
/// </summary>
|
||||
public string WorkCenterCode { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Operation sequence number
|
||||
/// </summary>
|
||||
public decimal StepNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Operation sequence description
|
||||
/// </summary>
|
||||
public string? StepDescription { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Function operation description (long text)
|
||||
/// </summary>
|
||||
public string? FunctionOperationDescription { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Operation sequence type code
|
||||
/// </summary>
|
||||
public string StepTypeCode { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Timestamp when work step began
|
||||
/// </summary>
|
||||
public DateTime? StartDt { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Timestamp when work step ended
|
||||
/// </summary>
|
||||
public DateTime? EndDt { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Operation function code
|
||||
/// </summary>
|
||||
public string FunctionCode { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Quantity scrapped/cancelled
|
||||
/// </summary>
|
||||
public decimal ScrappedQuantity { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// JDE date of last update to record (private backing field for Dapper mapping)
|
||||
/// </summary>
|
||||
private int LastUpdateDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// JDE time of day of last update to record (private backing field for Dapper mapping)
|
||||
/// </summary>
|
||||
private int LastUpdateTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Timestamp of last update to record (computed from JDE date/time)
|
||||
/// </summary>
|
||||
public DateTime? LastUpdateDt => JdeDateConverter.ToDateTime(LastUpdateDate, LastUpdateTime);
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
using JdeScoping.Core.Helpers;
|
||||
|
||||
namespace JdeScoping.Core.Models.WorkOrders;
|
||||
|
||||
/// <summary>
|
||||
/// F31122 work order time transaction record
|
||||
/// </summary>
|
||||
public class WorkOrderTime
|
||||
{
|
||||
/// <summary>
|
||||
/// Unique ID for record
|
||||
/// </summary>
|
||||
public long UniqueId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Unique number for work order
|
||||
/// </summary>
|
||||
public long WorkOrderNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Unique code for branch
|
||||
/// </summary>
|
||||
public string BranchCode { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Unique code for work center
|
||||
/// </summary>
|
||||
public string WorkCenterCode { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Operation sequence number
|
||||
/// </summary>
|
||||
public decimal StepNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Unique address number for user/operator
|
||||
/// </summary>
|
||||
public long AddressNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// G/L date entry was processed
|
||||
/// </summary>
|
||||
public DateTime? GlDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// JDE date of last update to record (private backing field for Dapper mapping)
|
||||
/// </summary>
|
||||
private int LastUpdateDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// JDE time of day of last update to record (private backing field for Dapper mapping)
|
||||
/// </summary>
|
||||
private int LastUpdateTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Timestamp of last update to record (computed from JDE date/time)
|
||||
/// </summary>
|
||||
public DateTime? LastUpdateDt => JdeDateConverter.ToDateTime(LastUpdateDate, LastUpdateTime);
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
namespace JdeScoping.Core.Options;
|
||||
|
||||
/// <summary>
|
||||
/// Authentication configuration options
|
||||
/// </summary>
|
||||
public class AuthOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Configuration section name
|
||||
/// </summary>
|
||||
public const string SectionName = "Auth";
|
||||
|
||||
/// <summary>
|
||||
/// Enable fake authentication for development.
|
||||
/// When true, any credentials are accepted.
|
||||
/// </summary>
|
||||
public bool UseFakeAuth { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Name of the authentication cookie.
|
||||
/// </summary>
|
||||
public string CookieName { get; set; } = "ScopingTool.Auth";
|
||||
|
||||
/// <summary>
|
||||
/// Cookie expiration in minutes (default: 8 hours).
|
||||
/// </summary>
|
||||
public int CookieExpirationMinutes { get; set; } = 480;
|
||||
|
||||
/// <summary>
|
||||
/// Optional list of usernames that bypass group check.
|
||||
/// Use sparingly for admin/testing purposes.
|
||||
/// </summary>
|
||||
public string[] AdminBypassUsers { get; set; } = [];
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
namespace JdeScoping.Core.Options;
|
||||
|
||||
/// <summary>
|
||||
/// Configuration options for data source selection (Oracle vs file-based).
|
||||
/// </summary>
|
||||
public class DataSourceOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Configuration section name in appsettings.json.
|
||||
/// </summary>
|
||||
public const string SectionName = "DataSource";
|
||||
|
||||
/// <summary>
|
||||
/// Use file-based data sources instead of Oracle for development.
|
||||
/// </summary>
|
||||
public bool UseFileDataSource { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Directory containing JSON data files for file-based data source.
|
||||
/// </summary>
|
||||
public string FileDirectory { get; set; } = "DevData";
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
namespace JdeScoping.Core.Options;
|
||||
|
||||
/// <summary>
|
||||
/// Configuration options for data synchronization background jobs.
|
||||
/// </summary>
|
||||
public class DataSyncOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Configuration section name in appsettings.json.
|
||||
/// </summary>
|
||||
public const string SectionName = "DataSync";
|
||||
|
||||
/// <summary>
|
||||
/// Cron schedule for mass (full) data refresh. Empty string disables the schedule.
|
||||
/// </summary>
|
||||
public string MassRefreshCronSchedule { get; set; } = "0 0 6 * * SAT";
|
||||
|
||||
/// <summary>
|
||||
/// Cron schedule for daily incremental data refresh. Empty string disables the schedule.
|
||||
/// </summary>
|
||||
public string DailyRefreshCronSchedule { get; set; } = "0 0 4 * * *";
|
||||
|
||||
/// <summary>
|
||||
/// Cron schedule for hourly data refresh. Empty string disables the schedule.
|
||||
/// </summary>
|
||||
public string HourlyRefreshCronSchedule { get; set; } = "0 0 * * * *";
|
||||
|
||||
/// <summary>
|
||||
/// Maximum number of concurrent update operations.
|
||||
/// </summary>
|
||||
public int MaxConcurrentUpdates { get; set; } = 4;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
namespace JdeScoping.Core.Options;
|
||||
|
||||
/// <summary>
|
||||
/// Configuration options for Excel export functionality.
|
||||
/// </summary>
|
||||
public class ExcelExportOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Configuration section name in appsettings.json.
|
||||
/// </summary>
|
||||
public const string SectionName = "ExcelExport";
|
||||
|
||||
/// <summary>
|
||||
/// Directory for temporary Excel files.
|
||||
/// </summary>
|
||||
public string TempDirectory { get; set; } = "/tmp/lotfinder";
|
||||
|
||||
/// <summary>
|
||||
/// Maximum number of rows per Excel sheet.
|
||||
/// </summary>
|
||||
public int MaxRowsPerSheet { get; set; } = 1048576;
|
||||
|
||||
/// <summary>
|
||||
/// Default date format for Excel cells.
|
||||
/// </summary>
|
||||
public string DefaultDateFormat { get; set; } = "yyyy-MM-dd HH:mm:ss";
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
namespace JdeScoping.Core.Options;
|
||||
|
||||
/// <summary>
|
||||
/// LDAP configuration options for authentication
|
||||
/// </summary>
|
||||
public class LdapOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Configuration section name
|
||||
/// </summary>
|
||||
public const string SectionName = "Ldap";
|
||||
|
||||
/// <summary>
|
||||
/// LDAP server URLs (supports multiple for failover).
|
||||
/// Example: ["ldap.corp.example.com", "ldap2.corp.example.com"]
|
||||
/// </summary>
|
||||
public string[] ServerUrls { get; set; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// Distinguished name of required group for access.
|
||||
/// Example: "CN=ScopingTool-Users,OU=Groups,DC=corp,DC=example,DC=com"
|
||||
/// </summary>
|
||||
public string GroupDn { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// LDAP search base for user lookups.
|
||||
/// Example: "DC=corp,DC=example,DC=com"
|
||||
/// </summary>
|
||||
public string SearchBase { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Connection timeout in seconds.
|
||||
/// </summary>
|
||||
public int ConnectionTimeoutSeconds { get; set; } = 30;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace JdeScoping.Core.Options;
|
||||
|
||||
public class SearchOptions
|
||||
{
|
||||
public int MaxResultRows { get; set; } = 100000;
|
||||
public int TimeoutSeconds { get; set; } = 300;
|
||||
public int MaxConcurrentSearches { get; set; } = 5;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
namespace JdeScoping.Core.Options;
|
||||
|
||||
/// <summary>
|
||||
/// Configuration options for search processing background service.
|
||||
/// </summary>
|
||||
public class SearchProcessingOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Configuration section name in appsettings.json.
|
||||
/// </summary>
|
||||
public const string SectionName = "SearchProcessing";
|
||||
|
||||
/// <summary>
|
||||
/// Interval in seconds between polling for new search requests.
|
||||
/// </summary>
|
||||
public int PollingIntervalSeconds { get; set; } = 5;
|
||||
|
||||
/// <summary>
|
||||
/// Maximum number of concurrent search operations.
|
||||
/// </summary>
|
||||
public int MaxConcurrentSearches { get; set; } = 2;
|
||||
|
||||
/// <summary>
|
||||
/// Search operation timeout in minutes.
|
||||
/// </summary>
|
||||
public int SearchTimeoutMinutes { get; set; } = 30;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
namespace JdeScoping.Core.ViewModels;
|
||||
|
||||
/// <summary>
|
||||
/// View model for item projection
|
||||
/// </summary>
|
||||
public class ItemViewModel
|
||||
{
|
||||
/// <summary>
|
||||
/// Item unique number
|
||||
/// </summary>
|
||||
public string ItemNumber { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Item description
|
||||
/// </summary>
|
||||
public string Description { get; set; } = string.Empty;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
namespace JdeScoping.Core.ViewModels;
|
||||
|
||||
/// <summary>
|
||||
/// View model for JDE user projection
|
||||
/// </summary>
|
||||
public class JdeUserViewModel
|
||||
{
|
||||
/// <summary>
|
||||
/// User unique address number
|
||||
/// </summary>
|
||||
public long AddressNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// User unique ID
|
||||
/// </summary>
|
||||
public string UserId { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// User's full name (last, first [middle initial])
|
||||
/// </summary>
|
||||
public string FullName { get; set; } = string.Empty;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
namespace JdeScoping.Core.ViewModels;
|
||||
|
||||
/// <summary>
|
||||
/// View model for lot projection
|
||||
/// </summary>
|
||||
public class LotViewModel
|
||||
{
|
||||
/// <summary>
|
||||
/// Lot unique number
|
||||
/// </summary>
|
||||
public string LotNumber { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Item number
|
||||
/// </summary>
|
||||
public string ItemNumber { get; set; } = string.Empty;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
namespace JdeScoping.Core.ViewModels;
|
||||
|
||||
/// <summary>
|
||||
/// View model for part (item number) / operation (job step number) / MIS combination
|
||||
/// </summary>
|
||||
public class PartOperationViewModel
|
||||
{
|
||||
/// <summary>
|
||||
/// Part's item number
|
||||
/// </summary>
|
||||
public string ItemNumber { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Operation's job step number
|
||||
/// </summary>
|
||||
public string OperationNumber { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// MIS number
|
||||
/// </summary>
|
||||
public string MisNumber { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// MIS revision (named MisRevision for JSON compatibility with legacy)
|
||||
/// </summary>
|
||||
public string MisRevision { get; set; } = string.Empty;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
namespace JdeScoping.Core.ViewModels;
|
||||
|
||||
/// <summary>
|
||||
/// View model for profit center projection
|
||||
/// </summary>
|
||||
public class ProfitCenterViewModel
|
||||
{
|
||||
/// <summary>
|
||||
/// Profit center unique code
|
||||
/// </summary>
|
||||
public string Code { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Profit center description
|
||||
/// </summary>
|
||||
public string Description { get; set; } = string.Empty;
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using JdeScoping.Core.Models;
|
||||
using JdeScoping.Core.Models.Enums;
|
||||
using JdeScoping.Core.Models.Search;
|
||||
|
||||
namespace JdeScoping.Core.ViewModels;
|
||||
|
||||
/// <summary>
|
||||
/// View model for search projection
|
||||
/// </summary>
|
||||
public class SearchViewModel
|
||||
{
|
||||
/// <summary>
|
||||
/// PK ID of search
|
||||
/// </summary>
|
||||
public int Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// User name of user that created search
|
||||
/// </summary>
|
||||
public string UserName { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// User-friendly name for search
|
||||
/// </summary>
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Current search status
|
||||
/// </summary>
|
||||
[JsonConverter(typeof(JsonStringEnumConverter))]
|
||||
public SearchStatus Status { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Timestamp search was submitted
|
||||
/// </summary>
|
||||
public DateTime? SubmitDt { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Timestamp search was started
|
||||
/// </summary>
|
||||
public DateTime? StartDt { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Timestamp search was completed
|
||||
/// </summary>
|
||||
public DateTime? EndDt { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Search criteria
|
||||
/// </summary>
|
||||
public SearchCriteria? Criteria { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
public SearchViewModel()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor that copies values from a Search entity
|
||||
/// </summary>
|
||||
/// <param name="search">Search to copy values from</param>
|
||||
public SearchViewModel(Search search)
|
||||
{
|
||||
if (search == null) return;
|
||||
|
||||
Id = search.Id;
|
||||
UserName = search.UserName;
|
||||
Name = search.Name;
|
||||
Status = search.Status;
|
||||
SubmitDt = search.SubmitDt;
|
||||
StartDt = search.StartDt;
|
||||
EndDt = search.EndDt;
|
||||
Criteria = search.Criteria;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts this view model to a Search entity
|
||||
/// </summary>
|
||||
/// <returns>Search entity</returns>
|
||||
public Search ToEntity()
|
||||
{
|
||||
return new Search
|
||||
{
|
||||
Id = Id,
|
||||
UserName = UserName,
|
||||
Name = Name,
|
||||
Status = Status,
|
||||
SubmitDt = SubmitDt,
|
||||
StartDt = StartDt,
|
||||
EndDt = EndDt,
|
||||
Criteria = Criteria
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
using JdeScoping.Core.Models;
|
||||
using JdeScoping.Core.Models.Inventory;
|
||||
using JdeScoping.Core.Models.Organization;
|
||||
using JdeScoping.Core.Models.WorkOrders;
|
||||
|
||||
namespace JdeScoping.Core.ViewModels;
|
||||
|
||||
/// <summary>
|
||||
/// Extension methods for converting models to view models
|
||||
/// </summary>
|
||||
public static class ViewModelExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts an Item to ItemViewModel
|
||||
/// </summary>
|
||||
public static ItemViewModel ToViewModel(this Item item)
|
||||
{
|
||||
return new ItemViewModel
|
||||
{
|
||||
ItemNumber = item.ItemNumber,
|
||||
Description = item.Description
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a ProfitCenter to ProfitCenterViewModel
|
||||
/// </summary>
|
||||
public static ProfitCenterViewModel ToViewModel(this ProfitCenter profitCenter)
|
||||
{
|
||||
return new ProfitCenterViewModel
|
||||
{
|
||||
Code = profitCenter.Code,
|
||||
Description = profitCenter.Description
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a WorkCenter to WorkCenterViewModel
|
||||
/// </summary>
|
||||
public static WorkCenterViewModel ToViewModel(this WorkCenter workCenter)
|
||||
{
|
||||
return new WorkCenterViewModel
|
||||
{
|
||||
Code = workCenter.Code,
|
||||
Description = workCenter.Description
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a JdeUser to JdeUserViewModel
|
||||
/// </summary>
|
||||
public static JdeUserViewModel ToViewModel(this JdeUser user)
|
||||
{
|
||||
return new JdeUserViewModel
|
||||
{
|
||||
AddressNumber = user.AddressNumber,
|
||||
UserId = user.UserId,
|
||||
FullName = user.FullName
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a WorkOrder to WorkOrderViewModel
|
||||
/// </summary>
|
||||
public static WorkOrderViewModel ToViewModel(this WorkOrder workOrder)
|
||||
{
|
||||
return new WorkOrderViewModel
|
||||
{
|
||||
WorkOrderNumber = workOrder.WorkOrderNumber,
|
||||
ItemNumber = workOrder.ItemNumber
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a Lot to LotViewModel
|
||||
/// </summary>
|
||||
public static LotViewModel ToViewModel(this Lot lot)
|
||||
{
|
||||
return new LotViewModel
|
||||
{
|
||||
LotNumber = lot.LotNumber,
|
||||
ItemNumber = lot.ItemNumber
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
namespace JdeScoping.Core.ViewModels;
|
||||
|
||||
/// <summary>
|
||||
/// View model for work center projection
|
||||
/// </summary>
|
||||
public class WorkCenterViewModel
|
||||
{
|
||||
/// <summary>
|
||||
/// Work center unique code
|
||||
/// </summary>
|
||||
public string Code { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Work center description
|
||||
/// </summary>
|
||||
public string Description { get; set; } = string.Empty;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
namespace JdeScoping.Core.ViewModels;
|
||||
|
||||
/// <summary>
|
||||
/// View model for work order projection
|
||||
/// </summary>
|
||||
public class WorkOrderViewModel
|
||||
{
|
||||
/// <summary>
|
||||
/// Work order unique number
|
||||
/// </summary>
|
||||
public long WorkOrderNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Work order item number
|
||||
/// </summary>
|
||||
public string ItemNumber { get; set; } = string.Empty;
|
||||
}
|
||||
Reference in New Issue
Block a user