From d82b2d3bd7074086f33b4db7053d44e6611e4ff7 Mon Sep 17 00:00:00 2001 From: "mustafa.ahmed" Date: Tue, 17 Mar 2026 10:14:05 +0500 Subject: [PATCH] Align meal schedules and menus with current site and HRMS data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Seed per-user config from deployed appsettings.json when missing, so production SiteId and connection strings are preserved Add centralized Logger writing to %LocalAppData%\UtopiaCanteenSystem\Logs\error.log with global unhandled exception handling Extend scan flow to resolve HRMS menu (lunch_menu_week → lunch_menu_item → menu_item) per site/date and persist MealLabel, MealItems, and TotalPrice in SQLite Fix menu lookups to use scanner local date instead of MySQL CURDATE(), avoiding time-zone mismatches Restrict Meal Schedules view to only show schedules for the current configured site and remove multi-site filter options --- App.xaml.cs | 4 +- CONFIG_FIX_SUMMARY.md | 281 +++++++++++++++ MEAL_SCHEDULE_VIEW_ONLY_CHANGES.md | 322 ++++++++++++++++++ Models/ResolvedMealSession.cs | 16 + Services/DbMealSessionResolver.cs | 71 +++- Services/IMealSessionResolver.cs | 3 +- Services/IMenuLookupService.cs | 6 + Services/Logger.cs | 53 +++ Services/MenuLookupService.cs | 53 ++- Services/RfidService.cs | 94 ++++- ViewModels/MealSchedulesViewModel.cs | 24 +- ViewModels/ScannerDashboardViewModel.cs | 21 +- scripts/mysql_meal_schedule_table.sql | 14 + ...sql_migrate_remove_device_local_row_id.sql | 32 ++ 14 files changed, 939 insertions(+), 55 deletions(-) create mode 100644 CONFIG_FIX_SUMMARY.md create mode 100644 MEAL_SCHEDULE_VIEW_ONLY_CHANGES.md create mode 100644 Models/ResolvedMealSession.cs create mode 100644 Services/Logger.cs create mode 100644 scripts/mysql_meal_schedule_table.sql create mode 100644 scripts/mysql_migrate_remove_device_local_row_id.sql diff --git a/App.xaml.cs b/App.xaml.cs index 5595912..2139ac9 100644 --- a/App.xaml.cs +++ b/App.xaml.cs @@ -44,7 +44,7 @@ public partial class App : Application var menuLookupService = new MenuLookupService(configService); var mealScheduleService = new ProductionMealScheduleService(configService); var mealSessionResolver = new DbMealSessionResolver(mealScheduleService); - var rfidService = new RfidService(dbFactory, configService, employeeLookupService, mealSessionResolver); + var rfidService = new RfidService(dbFactory, configService, employeeLookupService, mealSessionResolver, menuLookupService); var syncService = new SyncService(dbFactory, configService); var adminAuditService = new AdminAuditService(dbFactory); var session = new AppSession(); @@ -60,7 +60,7 @@ public partial class App : Application () => new MainDashboardViewModel(navigationService, rfidService, configService, session), () => new AdminSettingsAuthViewModel(authService, session, navigationService, configService), () => new SettingsViewModel(configService, navigationService, adminAuditService, syncService), - () => new MealSchedulesViewModel(mealScheduleService, navigationService)); + () => new MealSchedulesViewModel(mealScheduleService, navigationService, configService)); var mainViewModel = new MainViewModel(navigationService); diff --git a/CONFIG_FIX_SUMMARY.md b/CONFIG_FIX_SUMMARY.md new file mode 100644 index 0000000..7a72e16 --- /dev/null +++ b/CONFIG_FIX_SUMMARY.md @@ -0,0 +1,281 @@ +# Configuration Fix Summary + +## Problem +After user login, the application was changing configuration values unexpectedly: +- Connection string changed from production to local/HRMS +- SiteId changed back to "01" +- Config was being overwritten during authentication or navigation + +## Root Causes Identified + +1. **ProductionMealScheduleService** was using `GetHrmsLookupConnectionString()` instead of production connection string +2. **AppConfig class** had hardcoded defaults that auto-populated when config was recreated +3. **ConfigService.GetSiteId()/SetSiteId()** silently normalized missing values to "01" +4. **No logging** around config load/save operations +5. **Config overwrites** during login-related operations + +--- + +## Fixes Applied + +### 1. ProductionMealScheduleService.cs +**File:** `Services/ProductionMealScheduleService.cs` + +**Changes:** +- Changed all occurrences of `GetHrmsLookupConnectionString()` to `GetMySqlConnectionString()` +- Updated error messages from "HRMS MySQL connection string not configured" to "Production MySQL connection string not configured" +- Methods affected: + - `GetActiveSchedulesForSite()` + - `GetAllSchedulesAsync()` + - `CreateAsync()` + - `UpdateAsync()` + - `DeleteAsync()` + +**Impact:** Meal schedule operations now use the production database connection string instead of the local HRMS lookup connection string. + +--- + +### 2. AppConfig Class Defaults Removed +**File:** `Services/ConfigService.cs` + +**Changes:** +```csharp +// BEFORE +public string SiteId { get; set; } = "SITE : 1"; +public string HrmsLookupConnectionString { get; set; } = "Server=192.168.90.147;..."; + +// AFTER +public string SiteId { get; set; } = string.Empty; // No default - must be explicitly configured +public string HrmsLookupConnectionString { get; set; } = string.Empty; // Must be explicitly configured +``` + +**Impact:** Config values will no longer auto-populate with defaults when config file is recreated. Empty strings indicate "not configured" state. + +--- + +### 3. ConfigService.GetSiteId() and SetSiteId() Simplified +**File:** `Services/ConfigService.cs` + +**Changes:** +```csharp +// BEFORE - GetSiteId() +if (string.IsNullOrWhiteSpace(raw)) + return "01"; +// ... normalization logic ... +return Math.Clamp(numeric, 0, 99).ToString("D2"); + +// AFTER - GetSiteId() +return _config.SiteId ?? string.Empty; + +// BEFORE - SetSiteId() +var normalized = siteId; +if (string.IsNullOrWhiteSpace(normalized)) +{ + normalized = "01"; +} +else +{ + // ... normalization to 2-digit format ... +} +_config.SiteId = normalized; + +// AFTER - SetSiteId() +_config.SiteId = siteId ?? string.Empty; +``` + +**Impact:** SiteId is now stored and retrieved exactly as provided. No automatic normalization to "01". Callers are responsible for formatting. + +--- + +### 4. Config Load/Save Logging Added +**File:** `Services/ConfigService.cs` + +**Changes:** +Added comprehensive logging: + +**LoadConfig():** +- Logs when config file is not found and defaults are being used +- Logs config file path on successful load +- Logs SiteId value (shows "empty=not configured" if empty) +- Logs MySqlConnectionString status ("NOT CONFIGURED" or masked value) +- Logs HrmsLookupConnectionString status ("NOT CONFIGURED" or masked value) +- Logs any exceptions during load + +**SaveConfig():** +- Logs when saving starts +- Logs current SiteId value +- Logs current MySqlConnectionString status (masked) +- Logs current HrmsLookupConnectionString status (masked) +- Logs successful save with file path +- Logs any exceptions during save + +**MaskConnectionString():** +- New helper method to mask sensitive password values in logs +- Shows server and database information but replaces password with "***" + +**Sample Log Output:** +``` +[ConfigService] Config loaded from C:\Users\...\UtopiaCanteenSystem\config.json +[ConfigService] SiteId: '02' (empty=not configured) +[ConfigService] MySqlConnectionString: Server=localhost;Database=hrms;User=root;Password=*** +[ConfigService] HrmsLookupConnectionString: NOT CONFIGURED +[ConfigService] Saving config... +[ConfigService] SiteId: '02' +[ConfigService] MySqlConnectionString: Server=localhost;Database=hrms;User=root;Password=*** +[ConfigService] Config saved to C:\Users\...\UtopiaCanteenSystem\config.json +``` + +**Impact:** Full visibility into config changes for debugging. Sensitive values are masked. + +--- + +### 5. ScannerDashboardViewModel Updated +**File:** `ViewModels/ScannerDashboardViewModel.cs` + +**Changes:** +Updated site loading logic to handle both legacy "SITE : X" format and new numeric format: + +```csharp +// BEFORE +if (!string.IsNullOrWhiteSpace(siteId) && siteId.StartsWith("SITE : ", ...)) +{ + var num = siteId.Substring("SITE : ".Length).Trim(); + if (num.Length > 0 && num.All(char.IsDigit)) + SiteNumber = num; +} + +// AFTER +if (!string.IsNullOrWhiteSpace(siteId)) +{ + // Extract digits from legacy format "SITE : X"or use value directly if already numeric + if (siteId.StartsWith("SITE : ", StringComparison.OrdinalIgnoreCase)) + { + var num = siteId.Substring("SITE : ".Length).Trim(); + if (num.Length > 0 && num.All(char.IsDigit)) + SiteNumber = num; + } + else if (siteId.All(char.IsDigit)) + { + SiteNumber = siteId; + } +} +``` + +**Impact:** Backward compatible with legacy config format while supporting new numeric-only format. + +--- + +## Expected Behavior After Fix + +### ✅ Login/Authentication +- Login operations **only** modify credential-related config values: + - `RememberAdminCredentials` + - `SavedAdminUsername` + - `SavedAdminPasswordProtected` +- **Does NOT modify:** + - `SiteId` + - `MySqlConnectionString` + - `HrmsLookupConnectionString` + - Other unrelated settings + +### ✅ Navigation +- Navigation between views does not trigger config saves +- ViewModel initialization reads config but doesn't modify it +- Meal Schedules page uses production connection string + +### ✅ Config Persistence +- Existing config values are preserved across app restarts +- Defaults only applied when config file truly doesn't exist +- No silent normalization of values +- All config changes are logged + +### ✅ Database Connections +- **Production operations** (meal schedules, sync) use `MySqlConnectionString` +- **Local HRMS operations** (employee lookup, menu lookup, photos) use `HrmsLookupConnectionString` +- Both connections must be explicitly configured + +--- + +## Testing Recommendations + +1. **Initial Startup Test:** + - Delete config.json + - Run app + - Verify log shows "Config file not found. Creating with defaults." + - Check that SiteId and connection strings are empty (not "01" or hardcoded) + +2. **Login Test:** + - Configure production connection string and SiteId + - Save config + - Perform admin login + - Verify config still has correct values (not reset to defaults) + +3. **Navigation Test:** + - Navigate to Meal Schedules page + - Verify it uses production connection string (check logs) + - Verify meal schedules load from production database + +4. **Config Change Test:** + - Change SiteId in Settings + - Verify log shows old/new values + - Verify change persists after app restart + +5. **Connection String Masking Test:** + - Check debug output for config save operations + - Verify passwords are shown as "***" in logs + +--- + +## Migration Notes + +### For Existing Users +- Existing config.json files will be preserved +- Legacy "SITE : X" format will be recognized and loaded correctly +- On first save after upgrade, SiteId will be stored without normalization + +### For New Installations +- Config will be created with empty strings for SiteId and connection strings +- User must explicitly configure these values +- No assumptions about default site or database + +--- + +## Files Modified + +1. `Services/ProductionMealScheduleService.cs` - Use production connection string +2. `Services/ConfigService.cs` - Remove defaults, add logging, simplify SiteId handling +3. `ViewModels/ScannerDashboardViewModel.cs` - Handle both legacy and new SiteId formats + +--- + +## Breaking Changes + +⚠️ **None** - Changes are backward compatible: +- Legacy "SITE : X" format still supported +- Existing configs preserved +- Only behavior change: no more automatic resets to defaults + +--- + +## Configuration Requirements + +Both connection strings should be configured: + +**appsettings.json or manual config edit:** +```json +{ + "MySqlConnectionString": "Server=production-server;Database=hrms;User=utopia;Password=***;Port=3306;", + "HrmsLookupConnectionString": "Server=local-hrms-server;Database=hrms;User=utopia;Password=***;Port=3306;" +} +``` + +Or configure via Settings UI (for production connection) and manual config edit (for HRMS lookup). + +--- + +## Next Steps + +1. Test all scenarios listed above +2. Monitor debug output for config operations +3. Verify production meal schedule operations work correctly +4. Ensure login no longer modifies unrelated config values diff --git a/MEAL_SCHEDULE_VIEW_ONLY_CHANGES.md b/MEAL_SCHEDULE_VIEW_ONLY_CHANGES.md new file mode 100644 index 0000000..24b4576 --- /dev/null +++ b/MEAL_SCHEDULE_VIEW_ONLY_CHANGES.md @@ -0,0 +1,322 @@ +# Meal Schedule View-Only Mode Changes + +## Summary +Converted the Meal Schedule management screen from full CRUD (Create, Read, Update, Delete) to **view-only mode**. Users can now only view existing meal schedules without any ability to create, edit, or delete them. + +--- + +## Changes Made + +### 1. ViewModel Changes (`MealSchedulesViewModel.cs`) + +#### **Removed Properties** (No longer needed for forms) +```csharp +// REMOVED: +private string_locationSiteId = string.Empty; +private string _mealName = string.Empty; +private string _startTime = "06:00:00"; +private string _endTime = "09:00:00"; +``` + +#### **Removed Commands** (All CRUD operations) +```csharp +// REMOVED: +[RelayCommand] private void AddNew() // Form preparation +[RelayCommand] private async Task Save() // Create/Update logic +[RelayCommand] private void SelectSchedule() // Edit selection +[RelayCommand] private async Task Delete() // Delete operation +``` + +#### **Removed Callbacks** +```csharp +// REMOVED: +partial void OnSelectedScheduleChanged(MealSchedule? value) +{ + // This used to populate form fields when editing + // No longer needed in view-only mode +} +``` + +#### **Updated Class Summary** +```csharp +/// +/// View-only display of meal schedules from production (hrms.meal_schedule). +/// No CRUD operations. +/// Loads all schedules on open; optional Site filter (local). +/// +public partial class MealSchedulesViewModel : ObservableObject +{ + // Only these properties remain: + [ObservableProperty] private ObservableCollection _schedules; + [ObservableProperty] private string_selectedSiteFilter = "All"; + [ObservableProperty] private MealSchedule? _selectedSchedule; + [ObservableProperty] private string _message = string.Empty; + [ObservableProperty] private bool_isError; + [ObservableProperty] private bool _isLoading; + + // Only one command remains: + [RelayCommand] private void Back(); // Navigate back to Settings +} +``` + +--- + +### 2. View Changes (`MealSchedulesView.xaml`) + +#### **Removed UI Elements** + +1. **"Add New" Button** (was in top-right corner) +```xml + +