216 lines
9.4 KiB
C#
216 lines
9.4 KiB
C#
using MySqlConnector;
|
|
using UtopiaCanteenSystem.Models;
|
|
|
|
namespace UtopiaCanteenSystem.Services;
|
|
|
|
/// <summary>
|
|
/// Meal schedule CRUD against production HRMS MySQL table hrms.meal_schedule.
|
|
/// Uses IConfigService.GetHrmsLookupConnectionString() (same DB as employee lookup).
|
|
/// Schema: id (bigint), meal_name (varchar), start_time (time), end_time (time), created_at, updated_at, location_site_id (int).
|
|
/// No is_active column; all rows are treated as active.
|
|
/// </summary>
|
|
public class ProductionMealScheduleService : IMealScheduleService
|
|
{
|
|
private readonly IConfigService _configService;
|
|
private const string TableRef = "`hrms`.`meal_schedule`";
|
|
|
|
public ProductionMealScheduleService(IConfigService configService)
|
|
{
|
|
_configService = configService;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public IReadOnlyList<MealSchedule> GetActiveSchedulesForSite(string siteId)
|
|
{
|
|
var connStr = _configService.GetHrmsLookupConnectionString();
|
|
if (string.IsNullOrWhiteSpace(connStr))
|
|
return Array.Empty<MealSchedule>();
|
|
|
|
var siteIdInt = SiteIdStringToInt(siteId);
|
|
var list = new List<MealSchedule>();
|
|
try
|
|
{
|
|
using var conn = new MySqlConnection(connStr);
|
|
conn.Open();
|
|
var sql = $"SELECT id, meal_name, start_time, end_time, created_at, updated_at, location_site_id FROM {TableRef} WHERE location_site_id = @siteId ORDER BY start_time";
|
|
using var cmd = new MySqlCommand(sql, conn);
|
|
cmd.Parameters.AddWithValue("@siteId", siteIdInt);
|
|
using var r = cmd.ExecuteReader();
|
|
while (r.Read())
|
|
list.Add(ReadRow(r));
|
|
}
|
|
catch
|
|
{
|
|
return Array.Empty<MealSchedule>();
|
|
}
|
|
return list;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public async Task<IReadOnlyList<MealSchedule>> GetAllSchedulesAsync(CancellationToken cancellationToken = default)
|
|
{
|
|
var connStr = _configService.GetHrmsLookupConnectionString();
|
|
if (string.IsNullOrWhiteSpace(connStr))
|
|
return Array.Empty<MealSchedule>();
|
|
|
|
var list = new List<MealSchedule>();
|
|
await using var conn = new MySqlConnection(connStr);
|
|
await conn.OpenAsync(cancellationToken).ConfigureAwait(false);
|
|
var sql = $"SELECT id, meal_name, start_time, end_time, created_at, updated_at, location_site_id FROM {TableRef} ORDER BY location_site_id, start_time";
|
|
await using var cmd = new MySqlCommand(sql, conn);
|
|
await using var r = await cmd.ExecuteReaderAsync(cancellationToken).ConfigureAwait(false);
|
|
while (await r.ReadAsync(cancellationToken).ConfigureAwait(false))
|
|
list.Add(ReadRow(r));
|
|
return list;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public async Task<long> CreateAsync(MealSchedule schedule, CancellationToken cancellationToken = default)
|
|
{
|
|
var connStr = _configService.GetHrmsLookupConnectionString();
|
|
if (string.IsNullOrWhiteSpace(connStr))
|
|
throw new InvalidOperationException("HRMS MySQL connection string not configured.");
|
|
|
|
var utc = DateTime.UtcNow;
|
|
var mealName = (schedule.MealName ?? string.Empty).Trim();
|
|
var siteIdInt = SiteIdStringToInt(schedule.LocationSiteId);
|
|
|
|
await using var conn = new MySqlConnection(connStr);
|
|
await conn.OpenAsync(cancellationToken).ConfigureAwait(false);
|
|
var sql = $@"INSERT INTO {TableRef} (meal_name, start_time, end_time, created_at, updated_at, location_site_id)
|
|
VALUES (@mealName, @startTime, @endTime, @createdAt, @updatedAt, @siteId)";
|
|
await using var cmd = new MySqlCommand(sql, conn);
|
|
cmd.Parameters.AddWithValue("@mealName", mealName);
|
|
cmd.Parameters.AddWithValue("@startTime", schedule.StartTime?.Trim() ?? "00:00:00");
|
|
cmd.Parameters.AddWithValue("@endTime", schedule.EndTime?.Trim() ?? "23:59:59");
|
|
cmd.Parameters.AddWithValue("@createdAt", utc);
|
|
cmd.Parameters.AddWithValue("@updatedAt", utc);
|
|
cmd.Parameters.AddWithValue("@siteId", siteIdInt);
|
|
await cmd.ExecuteNonQueryAsync(cancellationToken).ConfigureAwait(false);
|
|
return cmd.LastInsertedId;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public async Task UpdateAsync(MealSchedule schedule, CancellationToken cancellationToken = default)
|
|
{
|
|
var connStr = _configService.GetHrmsLookupConnectionString();
|
|
if (string.IsNullOrWhiteSpace(connStr))
|
|
throw new InvalidOperationException("HRMS MySQL connection string not configured.");
|
|
|
|
var utc = DateTime.UtcNow;
|
|
var mealName = (schedule.MealName ?? string.Empty).Trim();
|
|
var siteIdInt = SiteIdStringToInt(schedule.LocationSiteId);
|
|
|
|
await using var conn = new MySqlConnection(connStr);
|
|
await conn.OpenAsync(cancellationToken).ConfigureAwait(false);
|
|
var sql = $@"UPDATE {TableRef} SET meal_name = @mealName, start_time = @startTime, end_time = @endTime, location_site_id = @siteId, updated_at = @updatedAt WHERE id = @id";
|
|
await using var cmd = new MySqlCommand(sql, conn);
|
|
cmd.Parameters.AddWithValue("@id", schedule.Id);
|
|
cmd.Parameters.AddWithValue("@mealName", mealName);
|
|
cmd.Parameters.AddWithValue("@startTime", schedule.StartTime?.Trim() ?? "00:00:00");
|
|
cmd.Parameters.AddWithValue("@endTime", schedule.EndTime?.Trim() ?? "23:59:59");
|
|
cmd.Parameters.AddWithValue("@siteId", siteIdInt);
|
|
cmd.Parameters.AddWithValue("@updatedAt", utc);
|
|
await cmd.ExecuteNonQueryAsync(cancellationToken).ConfigureAwait(false);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public async Task DeleteAsync(long id, CancellationToken cancellationToken = default)
|
|
{
|
|
var connStr = _configService.GetHrmsLookupConnectionString();
|
|
if (string.IsNullOrWhiteSpace(connStr))
|
|
throw new InvalidOperationException("HRMS MySQL connection string not configured.");
|
|
|
|
await using var conn = new MySqlConnection(connStr);
|
|
await conn.OpenAsync(cancellationToken).ConfigureAwait(false);
|
|
var sql = $"DELETE FROM {TableRef} WHERE id = @id";
|
|
await using var cmd = new MySqlCommand(sql, conn);
|
|
cmd.Parameters.AddWithValue("@id", id);
|
|
await cmd.ExecuteNonQueryAsync(cancellationToken).ConfigureAwait(false);
|
|
}
|
|
|
|
/// <summary>Read row: id (bigint), meal_name, start_time (time), end_time (time), created_at, updated_at, location_site_id (int).</summary>
|
|
private static MealSchedule ReadRow(MySqlDataReader r)
|
|
{
|
|
return new MealSchedule
|
|
{
|
|
Id = r.GetInt64(0),
|
|
MealName = GetString(r, 1),
|
|
MealSession = MealNameToSession(GetString(r, 1)),
|
|
StartTime = GetTimeString(r, 2),
|
|
EndTime = GetTimeString(r, 3),
|
|
CreatedAt = GetDateTime(r, 4),
|
|
UpdatedAt = GetDateTime(r, 5),
|
|
LocationSiteId = IntToSiteIdString(r.IsDBNull(6) ? 0 : r.GetInt32(6)),
|
|
IsActive = true
|
|
};
|
|
}
|
|
|
|
private static string GetString(MySqlDataReader r, int i)
|
|
{
|
|
if (r.IsDBNull(i)) return "";
|
|
return r.GetString(i) ?? "";
|
|
}
|
|
|
|
private static string GetTimeString(MySqlDataReader r, int i)
|
|
{
|
|
if (r.IsDBNull(i)) return "00:00:00";
|
|
var v = r.GetValue(i);
|
|
if (v is TimeSpan ts)
|
|
return ts.ToString(@"hh\:mm\:ss");
|
|
return v?.ToString()?.Trim() ?? "00:00:00";
|
|
}
|
|
|
|
private static DateTime GetDateTime(MySqlDataReader r, int i)
|
|
{
|
|
if (r.IsDBNull(i)) return DateTime.UtcNow;
|
|
var dt = r.GetDateTime(i);
|
|
return dt.Kind == DateTimeKind.Utc ? dt : DateTime.SpecifyKind(dt, DateTimeKind.Utc);
|
|
}
|
|
|
|
private static int MealNameToSession(string mealName)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(mealName)) return 0;
|
|
var n = mealName.Trim();
|
|
// Map legacy names as well as Ramadan labels used in production (Sehri/Iftari)
|
|
if (n.Equals("Breakfast", StringComparison.OrdinalIgnoreCase)
|
|
|| n.Equals("BreakFast", StringComparison.OrdinalIgnoreCase)
|
|
|| n.Equals("Sehri", StringComparison.OrdinalIgnoreCase))
|
|
return (int)MealSession.Breakfast;
|
|
if (n.Equals("Lunch", StringComparison.OrdinalIgnoreCase)
|
|
|| n.Equals("Iftari", StringComparison.OrdinalIgnoreCase)
|
|
|| n.Equals("Iftar", StringComparison.OrdinalIgnoreCase))
|
|
return (int)MealSession.Lunch;
|
|
if (n.Equals("Tea", StringComparison.OrdinalIgnoreCase)) return (int)MealSession.Tea;
|
|
if (n.Equals("Dinner", StringComparison.OrdinalIgnoreCase)) return (int)MealSession.Dinner;
|
|
return 0;
|
|
}
|
|
|
|
private static string MealSessionToName(int mealSession)
|
|
{
|
|
return mealSession switch
|
|
{
|
|
(int)MealSession.Breakfast => "Breakfast",
|
|
(int)MealSession.Lunch => "Lunch",
|
|
(int)MealSession.Tea => "Tea",
|
|
(int)MealSession.Dinner => "Dinner",
|
|
_ => "Breakfast"
|
|
};
|
|
}
|
|
|
|
private static int SiteIdStringToInt(string siteId)
|
|
{
|
|
var s = (siteId ?? "").Trim();
|
|
if (string.IsNullOrEmpty(s)) return 0;
|
|
var digits = new string(s.Where(char.IsDigit).ToArray());
|
|
return int.TryParse(digits, out var n) ? n : 0;
|
|
}
|
|
|
|
/// <summary>Normalize production location_site_id int to display string (e.g. 2 -> "02").</summary>
|
|
private static string IntToSiteIdString(int siteIdInt)
|
|
{
|
|
if (siteIdInt <= 0) return "01";
|
|
return siteIdInt <= 99 ? siteIdInt.ToString("D2") : siteIdInt.ToString();
|
|
}
|
|
}
|