diff --git a/App.xaml.cs b/App.xaml.cs
index b93ca37..abe4604 100644
--- a/App.xaml.cs
+++ b/App.xaml.cs
@@ -1,6 +1,7 @@
-using System.Windows;
-using System.Threading;
using Microsoft.EntityFrameworkCore;
+using System.Net.Http;
+using System.Threading;
+using System.Windows;
using UtopiaCanteenSystem.Data;
using UtopiaCanteenSystem.Services;
using UtopiaCanteenSystem.ViewModels;
@@ -40,7 +41,9 @@ public partial class App : Application
var configService = new ConfigService();
var employeeLookupService = new EmployeeLookupService(configService);
- var employeePhotoService = new EmployeePhotoService(configService);
+ //var employeePhotoService = new EmployeePhotoService(configService);
+ var httpClient = new HttpClient();
+ var employeePhotoService = new EmployeePhotoService(configService, httpClient);
var menuLookupService = new MenuLookupService(configService);
var mealScheduleService = new ProductionMealScheduleService(configService);
var mealSessionResolver = new DbMealSessionResolver(mealScheduleService);
diff --git a/Models/HrmsEmployeeInfo.cs b/Models/HrmsEmployeeInfo.cs
index 5a166e1..519f8bf 100644
--- a/Models/HrmsEmployeeInfo.cs
+++ b/Models/HrmsEmployeeInfo.cs
@@ -25,4 +25,5 @@ public class HrmsEmployeeInfo
public string DepartmentType { get; set; } = string.Empty;
/// Site from employee_rfid_tag.location_site_id; used for menu lookup (lunch_menu_week).
public string LocationSiteId { get; set; } = string.Empty;
+ public string GradeType { get; set; } = string.Empty;
}
diff --git a/Models/ScanRecord.cs b/Models/ScanRecord.cs
index 8b6a58c..636ec68 100644
--- a/Models/ScanRecord.cs
+++ b/Models/ScanRecord.cs
@@ -46,4 +46,5 @@ public class ScanRecord
public string MealItems { get; set; } = string.Empty;
/// Total price for this scan's meal menu.
public double TotalPrice { get; set; }
+ public string grade_type { get; set; } = string.Empty;
}
diff --git a/Services/EmployeeLookupService.cs b/Services/EmployeeLookupService.cs
index 1c71c25..5551a9d 100644
--- a/Services/EmployeeLookupService.cs
+++ b/Services/EmployeeLookupService.cs
@@ -37,7 +37,8 @@ public class EmployeeLookupService : IEmployeeLookupService
r.created_by AS tag_created_by,
d.title AS department_title,
d.department_type,
- r.location_site_id AS location_site_id
+ r.location_site_id AS location_site_id,
+ r.grade_type AS grade_type
FROM employee_rfid_tag r
JOIN employee e ON e.id = r.parent_document_id
LEFT JOIN department d ON d.id = e.department_id
@@ -68,7 +69,8 @@ public class EmployeeLookupService : IEmployeeLookupService
TagCreatedBy = GetString(reader, 8),
DepartmentTitle = GetString(reader, 9),
DepartmentType = GetString(reader, 10),
- LocationSiteId = GetString(reader, 11)
+ LocationSiteId = GetString(reader, 11),
+ GradeType = GetString(reader, 12)
};
}
diff --git a/Services/EmployeePhotoService.cs b/Services/EmployeePhotoService.cs
index 4272d80..0cb3790 100644
--- a/Services/EmployeePhotoService.cs
+++ b/Services/EmployeePhotoService.cs
@@ -1,6 +1,7 @@
-using System.Collections.Concurrent;
-using System.Text;
using MySqlConnector;
+using System.Collections.Concurrent;
+using System.Net.Http;
+using System.Text;
namespace UtopiaCanteenSystem.Services;
@@ -13,13 +14,83 @@ public class EmployeePhotoService : IEmployeePhotoService
private readonly IConfigService _configService;
private readonly ConcurrentDictionary _cache = new(StringComparer.OrdinalIgnoreCase);
private const int MaxCacheEntries = 50;
+ private readonly HttpClient _httpClient;
- public EmployeePhotoService(IConfigService configService)
+ public EmployeePhotoService(IConfigService configService, HttpClient httpClient)
{
_configService = configService;
+ _httpClient = httpClient;
+ _httpClient = httpClient;
+
}
///
+ //public async Task GetPhotoBytesAsync(string parentDocumentId, CancellationToken cancellationToken = default)
+ //{
+ // if (string.IsNullOrWhiteSpace(parentDocumentId))
+ // return null;
+
+ // var key = parentDocumentId.Trim();
+ // if (_cache.TryGetValue(key, out var cached))
+ // return cached;
+
+ // var connectionString = _configService.GetHrmsLookupConnectionString();
+ // if (string.IsNullOrWhiteSpace(connectionString))
+ // return null;
+
+ // try
+ // {
+ // await using var conn = new MySqlConnection(connectionString);
+ // await conn.OpenAsync(cancellationToken).ConfigureAwait(false);
+
+ // // employee_photo.employee_id stores the employee document id (parent_document_id from employee lookup)
+ // const string sql = "SELECT photo_blob FROM hrms.employee_photo WHERE employee_id = @parentDocumentId LIMIT 1";
+ // await using var cmd = new MySqlCommand(sql, conn);
+ // cmd.Parameters.AddWithValue("@parentDocumentId", key);
+
+ // await using var reader = await cmd.ExecuteReaderAsync(cancellationToken).ConfigureAwait(false);
+ // if (!await reader.ReadAsync(cancellationToken).ConfigureAwait(false))
+ // return null;
+
+ // if (reader.IsDBNull(0))
+ // return null;
+
+ // byte[] blob;
+ // try
+ // {
+ // var len = reader.GetBytes(0, 0, null, 0, 0);
+ // blob = new byte[len];
+ // reader.GetBytes(0, 0, blob, 0, (int)len);
+ // }
+ // catch
+ // {
+ // return null;
+ // }
+
+ // var imageBytes = DecodeBlobToImageBytes(blob);
+ // if (imageBytes == null || imageBytes.Length == 0)
+ // return null;
+
+ // // Cache (evict old if needed)
+ // while (_cache.Count >= MaxCacheEntries && _cache.Count > 0)
+ // {
+ // var first = _cache.Keys.FirstOrDefault();
+ // if (first != null)
+ // _cache.TryRemove(first, out _);
+ // else
+ // break;
+ // }
+ // _cache[key] = imageBytes;
+ // return imageBytes;
+ // }
+ // catch
+ // {
+ // return null;
+ // }
+ //}
+
+
+
public async Task GetPhotoBytesAsync(string parentDocumentId, CancellationToken cancellationToken = default)
{
if (string.IsNullOrWhiteSpace(parentDocumentId))
@@ -29,44 +100,25 @@ public class EmployeePhotoService : IEmployeePhotoService
if (_cache.TryGetValue(key, out var cached))
return cached;
- var connectionString = _configService.GetHrmsLookupConnectionString();
- if (string.IsNullOrWhiteSpace(connectionString))
- return null;
-
try
{
- await using var conn = new MySqlConnection(connectionString);
- await conn.OpenAsync(cancellationToken).ConfigureAwait(false);
+ var url = $"https://portal.utopiaindustries.pk/uind/employee-photo/{Uri.EscapeDataString(key)}.jpeg";
- // employee_photo.employee_id stores the employee document id (parent_document_id from employee lookup)
- const string sql = "SELECT photo_blob FROM hrms.employee_photo WHERE employee_id = @parentDocumentId LIMIT 1";
- await using var cmd = new MySqlCommand(sql, conn);
- cmd.Parameters.AddWithValue("@parentDocumentId", key);
-
- await using var reader = await cmd.ExecuteReaderAsync(cancellationToken).ConfigureAwait(false);
- if (!await reader.ReadAsync(cancellationToken).ConfigureAwait(false))
+ using var response = await _httpClient.GetAsync(url, cancellationToken).ConfigureAwait(false);
+ if (!response.IsSuccessStatusCode)
return null;
- if (reader.IsDBNull(0))
- return null;
-
- byte[] blob;
- try
- {
- var len = reader.GetBytes(0, 0, null, 0, 0);
- blob = new byte[len];
- reader.GetBytes(0, 0, blob, 0, (int)len);
- }
- catch
+ var contentType = response.Content.Headers.ContentType?.MediaType;
+ if (!string.IsNullOrWhiteSpace(contentType) &&
+ !contentType.StartsWith("image/", StringComparison.OrdinalIgnoreCase))
{
return null;
}
- var imageBytes = DecodeBlobToImageBytes(blob);
+ var imageBytes = await response.Content.ReadAsByteArrayAsync(cancellationToken).ConfigureAwait(false);
if (imageBytes == null || imageBytes.Length == 0)
return null;
- // Cache (evict old if needed)
while (_cache.Count >= MaxCacheEntries && _cache.Count > 0)
{
var first = _cache.Keys.FirstOrDefault();
@@ -75,6 +127,7 @@ public class EmployeePhotoService : IEmployeePhotoService
else
break;
}
+
_cache[key] = imageBytes;
return imageBytes;
}
@@ -83,7 +136,6 @@ public class EmployeePhotoService : IEmployeePhotoService
return null;
}
}
-
///
/// Converts blob to image bytes: if blob is UTF-8 "data:image...;base64,<payload>", decodes base64; else treats as raw image.
///
diff --git a/Services/IMenuLookupService.cs b/Services/IMenuLookupService.cs
index cf15353..a96089a 100644
--- a/Services/IMenuLookupService.cs
+++ b/Services/IMenuLookupService.cs
@@ -18,5 +18,7 @@ public interface IMenuLookupService
/// Gets menu items for the given site and specific local date (yyyy-MM-dd).
/// Avoids server time mismatch by not relying on CURDATE().
///
- Task> GetMenuItemsForSiteAndDateAsync(int siteIdNumeric, DateTime menuDateLocal, CancellationToken cancellationToken = default);
+ //Task> GetMenuItemsForSiteAndDateAsync(int siteIdNumeric, DateTime menuDateLocal, CancellationToken cancellationToken = default);
+
+ Task> GetMenuItemsForSiteAndDateAsync(int siteIdNumeric, DateTime menuDateLocal, string gradeType, CancellationToken cancellationToken = default);
}
diff --git a/Services/MenuLookupService.cs b/Services/MenuLookupService.cs
index ec3c804..8d36774 100644
--- a/Services/MenuLookupService.cs
+++ b/Services/MenuLookupService.cs
@@ -7,6 +7,133 @@ namespace UtopiaCanteenSystem.Services;
/// Fetches lunch menu from HRMS: lunch_menu_week (by location_site_id) → lunch_menu_item → menu_item.
/// Uses IConfigService.GetHrmsLookupConnectionString(). Only current week is considered.
///
+//public class MenuLookupService : IMenuLookupService
+//{
+// private readonly IConfigService _configService;
+
+// public MenuLookupService(IConfigService configService)
+// {
+// _configService = configService;
+// }
+
+// ///
+// public async Task> GetMenuItemsForSiteAsync(int siteIdNumeric, CancellationToken cancellationToken = default)
+// {
+// // Backwards-compatible: use today's local date.
+// return await GetMenuItemsForSiteAndDateAsync(siteIdNumeric, DateTime.Today, cancellationToken).ConfigureAwait(false);
+// }
+
+// ///
+// public async Task> GetMenuItemsForSiteAndDateAsync(int siteIdNumeric, DateTime menuDateLocal, CancellationToken cancellationToken = default)
+// {
+// var connectionString = _configService.GetHrmsLookupConnectionString();
+// if (string.IsNullOrWhiteSpace(connectionString))
+// return Array.Empty();
+
+// //const string sql = @"
+// // SELECT DISTINCT mi.id, mi.item_name, mi.item_type, mi.price
+// // FROM lunch_menu_week w
+// // JOIN lunch_menu_item li ON li.lunch_menu_week_id = w.id
+// // JOIN menu_item mi ON mi.id = li.menu_item_id
+// // WHERE w.location_site_id = @siteId
+// // AND CURDATE() BETWEEN w.week_start_date AND w.week_end_date
+// // ORDER BY mi.item_type, mi.item_name";
+
+// const string sql = @"
+// SELECT
+// mi.id,
+// mi.item_name,
+// mi.item_type,
+// mi.price,
+// li.menu_date,
+// li.day_of_week
+// FROM lunch_menu_week w
+// JOIN lunch_menu_item li ON li.lunch_menu_week_id = w.id
+// JOIN menu_item mi ON mi.id = li.menu_item_id
+// WHERE w.location_site_id = @siteId
+// AND @menuDate BETWEEN w.week_start_date AND w.week_end_date
+// AND li.menu_date = @menuDate
+// ORDER BY mi.item_name;";
+
+// //const string sql = @"
+// // SELECT
+// // mi.id,
+// // mi.item_name,
+// // mi.item_type,
+// // mi.price,
+// // li.meal_name,
+// // li.menu_date,
+// // li.day_of_week
+// // FROM lunch_menu_week w
+// // JOIN lunch_menu_item li ON li.lunch_menu_week_id = w.id
+// // JOIN menu_item mi ON mi.id = li.menu_item_id
+// // WHERE w.location_site_id = @siteId
+// // AND @menuDate BETWEEN w.week_start_date AND w.week_end_date
+// // AND li.menu_date = @menuDate
+// // ORDER BY li.meal_name, mi.item_name;";
+
+// await using var conn = new MySqlConnection(connectionString);
+// await conn.OpenAsync(cancellationToken).ConfigureAwait(false);
+// await using var cmd = new MySqlCommand(sql, conn);
+// cmd.Parameters.AddWithValue("@siteId", siteIdNumeric);
+// cmd.Parameters.AddWithValue("@menuDate", menuDateLocal.Date);
+
+// var list = new List();
+// await using var reader = await cmd.ExecuteReaderAsync(cancellationToken).ConfigureAwait(false);
+// while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false))
+// {
+// //list.Add(new HrmsMenuItem
+// //{
+// // MenuItemId = reader.IsDBNull(0) ? 0 : reader.GetInt32(0),
+// // ItemName = GetString(reader, 1),
+// // ItemType = GetString(reader, 2),
+// // Price = GetDecimal(reader, 3)
+// //});
+
+// list.Add(new HrmsMenuItem
+// {
+// MenuItemId = reader.IsDBNull(0) ? 0 : reader.GetInt32(0),
+// ItemName = GetString(reader, 1),
+// ItemType = GetString(reader, 2),
+// Price = GetDecimal(reader, 3),
+// MenuDate = GetString(reader, 4),
+// DayOfWeek = GetString(reader, 5),
+// MealName = string.Empty
+// });
+
+// //list.Add(new HrmsMenuItem
+// //{
+// // MenuItemId = reader.IsDBNull(0) ? 0 : reader.GetInt32(0),
+// // ItemName = GetString(reader, 1),
+// // ItemType = GetString(reader, 2),
+// // Price = GetDecimal(reader, 3),
+
+// // MealName = GetString(reader, 4),
+// // MenuDate = GetString(reader, 5),
+// // DayOfWeek = GetString(reader, 6),
+// //});
+// }
+
+// return list;
+// }
+
+// private static string GetString(MySqlDataReader reader, int ordinal)
+// {
+// if (reader.IsDBNull(ordinal)) return string.Empty;
+// var v = reader.GetValue(ordinal);
+// return v?.ToString() ?? string.Empty;
+// }
+
+// private static decimal GetDecimal(MySqlDataReader reader, int ordinal)
+// {
+// if (reader.IsDBNull(ordinal)) return 0m;
+// var v = reader.GetValue(ordinal);
+// return v is decimal d ? d : Convert.ToDecimal(v);
+// }
+//}
+
+
+
public class MenuLookupService : IMenuLookupService
{
private readonly IConfigService _configService;
@@ -16,80 +143,50 @@ public class MenuLookupService : IMenuLookupService
_configService = configService;
}
- ///
+ // Implementing the method for fetching menu items by site
public async Task> GetMenuItemsForSiteAsync(int siteIdNumeric, CancellationToken cancellationToken = default)
{
// Backwards-compatible: use today's local date.
- return await GetMenuItemsForSiteAndDateAsync(siteIdNumeric, DateTime.Today, cancellationToken).ConfigureAwait(false);
+ return await GetMenuItemsForSiteAndDateAsync(siteIdNumeric, DateTime.Today, "NonManagement", cancellationToken).ConfigureAwait(false);
}
- ///
- public async Task> GetMenuItemsForSiteAndDateAsync(int siteIdNumeric, DateTime menuDateLocal, CancellationToken cancellationToken = default)
+ // Implementing the method for fetching menu items by site, date, and gradeType
+ public async Task> GetMenuItemsForSiteAndDateAsync(int siteIdNumeric, DateTime menuDateLocal, string gradeType, CancellationToken cancellationToken = default)
{
var connectionString = _configService.GetHrmsLookupConnectionString();
if (string.IsNullOrWhiteSpace(connectionString))
return Array.Empty();
- //const string sql = @"
- // SELECT DISTINCT mi.id, mi.item_name, mi.item_type, mi.price
- // FROM lunch_menu_week w
- // JOIN lunch_menu_item li ON li.lunch_menu_week_id = w.id
- // JOIN menu_item mi ON mi.id = li.menu_item_id
- // WHERE w.location_site_id = @siteId
- // AND CURDATE() BETWEEN w.week_start_date AND w.week_end_date
- // ORDER BY mi.item_type, mi.item_name";
-
const string sql = @"
- SELECT
- mi.id,
- mi.item_name,
- mi.item_type,
- mi.price,
- li.menu_date,
- li.day_of_week
- FROM lunch_menu_week w
- JOIN lunch_menu_item li ON li.lunch_menu_week_id = w.id
- JOIN menu_item mi ON mi.id = li.menu_item_id
- WHERE w.location_site_id = @siteId
- AND @menuDate BETWEEN w.week_start_date AND w.week_end_date
- AND li.menu_date = @menuDate
- ORDER BY mi.item_name;";
+ SELECT
+ mi.id,
+ mi.item_name,
+ mi.item_type,
+ mi.price,
+ li.menu_date,
+ li.day_of_week
+ FROM lunch_menu_week w
+ JOIN lunch_menu_item li ON li.lunch_menu_week_id = w.id
+ JOIN menu_item mi ON mi.id = li.menu_item_id
+ WHERE w.location_site_id = @siteId
+ AND @menuDate BETWEEN w.week_start_date AND w.week_end_date
+ AND li.menu_date = @menuDate
+ AND mi.item_for = @itemFor
+ ORDER BY mi.item_name;";
- //const string sql = @"
- // SELECT
- // mi.id,
- // mi.item_name,
- // mi.item_type,
- // mi.price,
- // li.meal_name,
- // li.menu_date,
- // li.day_of_week
- // FROM lunch_menu_week w
- // JOIN lunch_menu_item li ON li.lunch_menu_week_id = w.id
- // JOIN menu_item mi ON mi.id = li.menu_item_id
- // WHERE w.location_site_id = @siteId
- // AND @menuDate BETWEEN w.week_start_date AND w.week_end_date
- // AND li.menu_date = @menuDate
- // ORDER BY li.meal_name, mi.item_name;";
+ var itemFor = GetItemForFromGradeType(gradeType);
await using var conn = new MySqlConnection(connectionString);
await conn.OpenAsync(cancellationToken).ConfigureAwait(false);
await using var cmd = new MySqlCommand(sql, conn);
cmd.Parameters.AddWithValue("@siteId", siteIdNumeric);
cmd.Parameters.AddWithValue("@menuDate", menuDateLocal.Date);
+ cmd.Parameters.AddWithValue("@itemFor", itemFor);
var list = new List();
await using var reader = await cmd.ExecuteReaderAsync(cancellationToken).ConfigureAwait(false);
while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false))
{
- //list.Add(new HrmsMenuItem
- //{
- // MenuItemId = reader.IsDBNull(0) ? 0 : reader.GetInt32(0),
- // ItemName = GetString(reader, 1),
- // ItemType = GetString(reader, 2),
- // Price = GetDecimal(reader, 3)
- //});
-
list.Add(new HrmsMenuItem
{
MenuItemId = reader.IsDBNull(0) ? 0 : reader.GetInt32(0),
@@ -100,23 +197,24 @@ public class MenuLookupService : IMenuLookupService
DayOfWeek = GetString(reader, 5),
MealName = string.Empty
});
-
- //list.Add(new HrmsMenuItem
- //{
- // MenuItemId = reader.IsDBNull(0) ? 0 : reader.GetInt32(0),
- // ItemName = GetString(reader, 1),
- // ItemType = GetString(reader, 2),
- // Price = GetDecimal(reader, 3),
-
- // MealName = GetString(reader, 4),
- // MenuDate = GetString(reader, 5),
- // DayOfWeek = GetString(reader, 6),
- //});
}
return list;
}
+ private static string GetItemForFromGradeType(string? gradeType)
+ {
+ var value = (gradeType ?? string.Empty).Trim().ToLowerInvariant();
+
+ return value switch
+ {
+ "management" => "MANAGEMENT",
+ "nonmanagement" => "NON_MANAGEMENT",
+ "non_management" => "NON_MANAGEMENT",
+ _ => string.Empty
+ };
+ }
+
private static string GetString(MySqlDataReader reader, int ordinal)
{
if (reader.IsDBNull(ordinal)) return string.Empty;
@@ -130,4 +228,4 @@ public class MenuLookupService : IMenuLookupService
var v = reader.GetValue(ordinal);
return v is decimal d ? d : Convert.ToDecimal(v);
}
-}
+}
\ No newline at end of file
diff --git a/Services/RfidService.cs b/Services/RfidService.cs
index 805fda3..7041308 100644
--- a/Services/RfidService.cs
+++ b/Services/RfidService.cs
@@ -327,7 +327,7 @@ public class RfidService : IRfidService
if (int.TryParse(new string(siteIdForSession.Where(char.IsDigit).ToArray()), out var siteNumeric) && siteNumeric > 0)
{
var menuItems = _menuLookup
- .GetMenuItemsForSiteAndDateAsync(siteNumeric, nowLocal.Date)
+ .GetMenuItemsForSiteAndDateAsync(siteNumeric, nowLocal.Date, employee.GradeType)
.GetAwaiter()
.GetResult();
@@ -372,7 +372,8 @@ public class RfidService : IRfidService
DepartmentType = employee.DepartmentType ?? string.Empty,
MealLabel = mealLabel,
MealItems = mealItemsDisplay,
- TotalPrice = totalPrice
+ TotalPrice = totalPrice,
+ grade_type = employee.GradeType ?? string.Empty
};
db.LunchOrderTransactions.Add(record);
db.SaveChanges();
diff --git a/Services/SyncService.cs b/Services/SyncService.cs
index 79bd5e5..e034333 100644
--- a/Services/SyncService.cs
+++ b/Services/SyncService.cs
@@ -67,13 +67,20 @@ public class SyncService : ISyncService
AND order_date = @OrderDate
AND total_cost = @TotalCost
AND created_at = @CreatedAt
+ AND meal_name = @MealName
LIMIT 1";
const string insertOrderSql = @"
INSERT INTO lunch_order
- (employee_id, employee_serial_number, order_date, shift, created_at, total_cost, is_cancelled, cancelled_by, created_by, function_id, department_id, location_site_id)
+ (employee_id, employee_serial_number, order_date, shift, created_at, total_cost, is_cancelled, cancelled_by, created_by, function_id, department_id, location_site_id, meal_name)
VALUES
- (@EmployeeId, @EmployeeSerialNumber, @OrderDate, @Shift, @CreatedAt, @TotalCost, 0, @CancelledBy, @CreatedBy, @FunctionId, @DepartmentId, @LocationSiteId)";
+ (@EmployeeId, @EmployeeSerialNumber, @OrderDate, @Shift, @CreatedAt, @TotalCost, 0, @CancelledBy, @CreatedBy, @FunctionId, @DepartmentId, @LocationSiteId, @MealName)";
+
+ const string updateOrderCodeSql = @"
+ UPDATE lunch_order
+ SET code = @Code
+ WHERE id = @Id";
+
var syncedIds = new List(capacity: toSync.Count);
@@ -103,8 +110,11 @@ public class SyncService : ISyncService
var orderDateLocal = record.ScanTime.ToLocalTime().Date;
var totalCost = Math.Round((decimal)record.TotalPrice, 2, MidpointRounding.AwayFromZero);
- var createdAt = record.TagCreatedAtUtc ?? record.ScanTime;
+ //var createdAt = record.TagCreatedAtUtc ?? record.ScanTime;
+ var createdAt = record.ScanTime.ToLocalTime();
var locationSiteId = SiteIdStringToInt(record.SiteId ?? string.Empty);
+ var mealName = (record.MealLabel ?? string.Empty).Trim();
+ var shift = GetShiftFromMeal(mealName);
await using (var hrmsConn = new MySqlConnection(hrmsConnStr))
{
@@ -117,6 +127,7 @@ public class SyncService : ISyncService
existsCmd.Parameters.AddWithValue("@OrderDate", orderDateLocal);
existsCmd.Parameters.AddWithValue("@TotalCost", totalCost);
existsCmd.Parameters.AddWithValue("@CreatedAt", createdAt);
+ existsCmd.Parameters.AddWithValue("@MealName", mealName);
var existing = await existsCmd.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false);
alreadyExists = existing != null && existing != DBNull.Value;
}
@@ -127,7 +138,7 @@ public class SyncService : ISyncService
orderCmd.Parameters.AddWithValue("@EmployeeId", employeeIdBigint);
orderCmd.Parameters.AddWithValue("@EmployeeSerialNumber", record.UindSerial ?? string.Empty);
orderCmd.Parameters.AddWithValue("@OrderDate", orderDateLocal);
- orderCmd.Parameters.AddWithValue("@Shift", string.Empty);
+ orderCmd.Parameters.AddWithValue("@Shift", shift);
orderCmd.Parameters.AddWithValue("@CreatedAt", createdAt);
orderCmd.Parameters.AddWithValue("@TotalCost", totalCost);
orderCmd.Parameters.AddWithValue("@CancelledBy", string.Empty);
@@ -135,7 +146,19 @@ public class SyncService : ISyncService
orderCmd.Parameters.AddWithValue("@FunctionId", record.FunctionId);
orderCmd.Parameters.AddWithValue("@DepartmentId", record.DepartmentId);
orderCmd.Parameters.AddWithValue("@LocationSiteId", locationSiteId);
+ orderCmd.Parameters.AddWithValue("@MealName", mealName);
await orderCmd.ExecuteNonQueryAsync(cancellationToken).ConfigureAwait(false);
+
+ var insertedId = orderCmd.LastInsertedId;
+ if (insertedId > 0)
+ {
+ var code = GenerateLunchOrderCode(insertedId, createdAt);
+
+ await using var updateCodeCmd = new MySqlCommand(updateOrderCodeSql, hrmsConn);
+ updateCodeCmd.Parameters.AddWithValue("@Code", code);
+ updateCodeCmd.Parameters.AddWithValue("@Id", insertedId);
+ await updateCodeCmd.ExecuteNonQueryAsync(cancellationToken).ConfigureAwait(false);
+ }
}
}
@@ -170,6 +193,26 @@ public class SyncService : ISyncService
}
}
+ private static string GenerateLunchOrderCode(long id, DateTime date)
+ {
+ return $"LO-{date:yyyy-MM}-{id:D6}";
+ }
+
+
+ private static string GetShiftFromMeal(string mealName)
+ {
+ if (string.IsNullOrWhiteSpace(mealName))
+ return string.Empty;
+
+ mealName = mealName.Trim().ToLowerInvariant();
+
+ return mealName switch
+ {
+ "breakfast" => "MORNING",
+ "lunch" => "MORNING",
+ _ => "EVENING"
+ };
+ }
private static int SiteIdStringToInt(string siteId)
{
try
diff --git a/ViewModels/ScannerDashboardViewModel.cs b/ViewModels/ScannerDashboardViewModel.cs
index d92c067..7048ea3 100644
--- a/ViewModels/ScannerDashboardViewModel.cs
+++ b/ViewModels/ScannerDashboardViewModel.cs
@@ -923,6 +923,13 @@ public partial class ScannerDashboardViewModel : ObservableObject
}
}
+ private static string ToExcelText(string? value)
+ {
+ var safe = value ?? string.Empty;
+ safe = safe.Replace("\"", "\"\"");
+ return $"=\"{safe}\"";
+ }
+
private static string BuildCsvFromScanRecords(IReadOnlyList records)
{
var sb = new StringBuilder();
@@ -931,7 +938,7 @@ public partial class ScannerDashboardViewModel : ObservableObject
{
sb.Append(r.Id);
sb.Append(',');
- sb.Append(EscapeCsv(r.CardId));
+ sb.Append(ToExcelText(r.CardId));
sb.Append(',');
sb.Append(EscapeCsv(r.ScanTime.ToString("O", CultureInfo.InvariantCulture)));
sb.Append(',');