commit
e467831cfb
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -25,4 +25,5 @@ public class HrmsEmployeeInfo
|
|||
public string DepartmentType { get; set; } = string.Empty;
|
||||
/// <summary>Site from employee_rfid_tag.location_site_id; used for menu lookup (lunch_menu_week).</summary>
|
||||
public string LocationSiteId { get; set; } = string.Empty;
|
||||
public string GradeType { get; set; } = string.Empty;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,4 +46,5 @@ public class ScanRecord
|
|||
public string MealItems { get; set; } = string.Empty;
|
||||
/// <summary>Total price for this scan's meal menu.</summary>
|
||||
public double TotalPrice { get; set; }
|
||||
public string grade_type { get; set; } = string.Empty;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<string, byte[]> _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;
|
||||
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
//public async Task<byte[]?> 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<byte[]?> 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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts blob to image bytes: if blob is UTF-8 "data:image...;base64,<payload>", decodes base64; else treats as raw image.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -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().
|
||||
/// </summary>
|
||||
Task<IReadOnlyList<HrmsMenuItem>> GetMenuItemsForSiteAndDateAsync(int siteIdNumeric, DateTime menuDateLocal, CancellationToken cancellationToken = default);
|
||||
//Task<IReadOnlyList<HrmsMenuItem>> GetMenuItemsForSiteAndDateAsync(int siteIdNumeric, DateTime menuDateLocal, CancellationToken cancellationToken = default);
|
||||
|
||||
Task<IReadOnlyList<HrmsMenuItem>> GetMenuItemsForSiteAndDateAsync(int siteIdNumeric, DateTime menuDateLocal, string gradeType, CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
/// </summary>
|
||||
//public class MenuLookupService : IMenuLookupService
|
||||
//{
|
||||
// private readonly IConfigService _configService;
|
||||
|
||||
// public MenuLookupService(IConfigService configService)
|
||||
// {
|
||||
// _configService = configService;
|
||||
// }
|
||||
|
||||
// /// <inheritdoc />
|
||||
// public async Task<IReadOnlyList<HrmsMenuItem>> GetMenuItemsForSiteAsync(int siteIdNumeric, CancellationToken cancellationToken = default)
|
||||
// {
|
||||
// // Backwards-compatible: use today's local date.
|
||||
// return await GetMenuItemsForSiteAndDateAsync(siteIdNumeric, DateTime.Today, cancellationToken).ConfigureAwait(false);
|
||||
// }
|
||||
|
||||
// /// <inheritdoc />
|
||||
// public async Task<IReadOnlyList<HrmsMenuItem>> GetMenuItemsForSiteAndDateAsync(int siteIdNumeric, DateTime menuDateLocal, CancellationToken cancellationToken = default)
|
||||
// {
|
||||
// var connectionString = _configService.GetHrmsLookupConnectionString();
|
||||
// if (string.IsNullOrWhiteSpace(connectionString))
|
||||
// return Array.Empty<HrmsMenuItem>();
|
||||
|
||||
// //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<HrmsMenuItem>();
|
||||
// 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;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
// Implementing the method for fetching menu items by site
|
||||
public async Task<IReadOnlyList<HrmsMenuItem>> 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);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<IReadOnlyList<HrmsMenuItem>> GetMenuItemsForSiteAndDateAsync(int siteIdNumeric, DateTime menuDateLocal, CancellationToken cancellationToken = default)
|
||||
// Implementing the method for fetching menu items by site, date, and gradeType
|
||||
public async Task<IReadOnlyList<HrmsMenuItem>> GetMenuItemsForSiteAndDateAsync(int siteIdNumeric, DateTime menuDateLocal, string gradeType, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var connectionString = _configService.GetHrmsLookupConnectionString();
|
||||
if (string.IsNullOrWhiteSpace(connectionString))
|
||||
return Array.Empty<HrmsMenuItem>();
|
||||
|
||||
//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<HrmsMenuItem>();
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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<int>(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
|
||||
|
|
|
|||
|
|
@ -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<ScanRecord> 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(',');
|
||||
|
|
|
|||
Loading…
Reference in New Issue