adding clock in break and out command

This commit is contained in:
Tim G. | SnapixLP 2025-06-06 02:01:54 +02:00
parent 2645d698d7
commit 536de50e4c
6 changed files with 280 additions and 105 deletions

View File

@ -2,7 +2,7 @@
public enum EmployeeState public enum EmployeeState
{ {
WORKING, OUT,
IN,
BREAK, BREAK,
AWAY,
} }

View File

@ -193,7 +193,7 @@ public class Server
return Task.FromException<Employee>(new Exception("Failed to get logged in employee.")); return Task.FromException<Employee>(new Exception("Failed to get logged in employee."));
} }
public Task<string> clockIn(Employee employee) public Task<string> ClockIn(Employee? employee = null)
{ {
var commandResult = ExecuteCommandAsync("clock in").Result; var commandResult = ExecuteCommandAsync("clock in").Result;
if (commandResult == "success") if (commandResult == "success")
@ -202,7 +202,7 @@ public class Server
} }
return Task.FromException<string>(new Exception("Failed to clock in.")); return Task.FromException<string>(new Exception("Failed to clock in."));
} }
public Task<string> clockOut(Employee employee) public Task<string> ClockOut(Employee? employee = null)
{ {
var commandResult = ExecuteCommandAsync("clock out").Result; var commandResult = ExecuteCommandAsync("clock out").Result;
if (commandResult == "success") if (commandResult == "success")
@ -214,7 +214,7 @@ public class Server
return Task.FromException<string>(new Exception("Failed to clock out.")); return Task.FromException<string>(new Exception("Failed to clock out."));
} }
} }
public Task<string> clockBreak(Employee employee) public Task<string> ClockBreak(Employee? employee = null)
{ {
var commandResult = ExecuteCommandAsync("clock break").Result; var commandResult = ExecuteCommandAsync("clock break").Result;
if (commandResult == "success") if (commandResult == "success")

View File

@ -43,7 +43,7 @@ public class BackendServer : DX86.TcpServer
JsonMessage? jsonMessage; JsonMessage? jsonMessage;
if (message.StartsWith("{") && message.EndsWith("}")) if (message.StartsWith("{") && message.EndsWith("}"))
{ {
this.SendMessageAsync(client, "Command received\n"); //this.SendMessageAsync(client, "Command received\n");
try try
{ {
jsonMessage = JsonSerializer.Deserialize<JsonMessage>(message); jsonMessage = JsonSerializer.Deserialize<JsonMessage>(message);

View File

@ -170,6 +170,123 @@ public class CommandLibrary
return self.ToJson(); return self.ToJson();
} }
[Command("clock")]
public static string ClockCommand(string[] args, TcpClient? client, TcpServer? socket)
{
// 1) Argument check
if (args.Length < 1)
throw new CommandException("Missing argument: usage is clock <in|out|break>");
string desired = args[0].ToLowerInvariant();
int desiredState;
switch (desired)
{
case "in":
desiredState = 1;
break;
case "out":
desiredState = 0;
break;
case "break":
desiredState = 2;
break;
default:
throw new CommandException("Invalid argument. Use in, out, or break.");
}
// 2) Verify client/socket
if (client == null || socket == null)
throw new CommandException("No client connection detected.");
if (!socket.LoggedInClients.TryGetValue(client, out var employeeCode))
throw new CommandException("User not logged in.");
// 3) Look up the employee by Code to get Id and current state
var empParams = new Dictionary<string, object> { { "Code", employeeCode } };
string empResultJson = Program.mySql.Get("employees", empParams);
using var empDoc = JsonDocument.Parse(empResultJson);
bool empError = empDoc.RootElement.GetProperty("error").GetBoolean();
if (empError)
{
string dbMsg = empDoc.RootElement.GetProperty("data").GetString() ?? "Unknown DB error";
Program.messageSender.Error($"[ClockCommand] DB error when looking up employee: {dbMsg}");
throw new CommandException("Internal error while fetching employee data.");
}
var empArray = empDoc.RootElement.GetProperty("data");
if (empArray.GetArrayLength() == 0)
throw new CommandException("Logged-in user not found in database.");
var empRow = empArray[0];
int employeeId = empRow.GetProperty("Id").GetInt32();
int currentState = empRow.GetProperty("EmployeeState").GetInt32();
// 4) Validate state transition
if (currentState == desiredState)
throw new CommandException($"Already {(desiredState == 0 ? "OUT" : desiredState == 1 ? "IN" : "on BREAK")}.");
bool valid = false;
switch (currentState)
{
case 0: // OUT → only IN
valid = (desiredState == 1);
break;
case 1: // IN → OUT or BREAK
valid = (desiredState == 0 || desiredState == 2);
break;
case 2: // BREAK → only IN
valid = (desiredState == 1);
break;
}
if (!valid)
throw new CommandException("Invalid transition from current status.");
// 5) Update employees.EmployeeState to desiredState
var updateData = new Dictionary<string, object>
{
{ "EmployeeState", desiredState }
};
var whereData = new Dictionary<string, object>
{
{ "Id", employeeId }
};
string updateJson = Program.mySql.Update("employees", updateData, whereData);
using (var updateDoc = JsonDocument.Parse(updateJson))
{
bool updError = updateDoc.RootElement.GetProperty("error").GetBoolean();
if (updError)
{
string dbMsg = updateDoc.RootElement.GetProperty("data").GetString() ?? "Unknown DB error";
Program.messageSender.Error($"[ClockCommand] DB error when updating state: {dbMsg}");
throw new CommandException("Internal error while updating status.");
}
}
// 6) Insert into employee_state_history
var historyData = new Dictionary<string, object>
{
{ "EmployeeId", employeeId },
{ "NewState", desiredState }
};
string historyJson = Program.mySql.Insert("employee_state_history", historyData);
using (var histDoc = JsonDocument.Parse(historyJson))
{
bool histError = histDoc.RootElement.GetProperty("error").GetBoolean();
if (histError)
{
string dbMsg = histDoc.RootElement.GetProperty("data").GetString() ?? "Unknown DB error";
Program.messageSender.Error($"[ClockCommand] DB error when logging history: {dbMsg}");
throw new CommandException("Internal error while logging status change.");
}
}
// 7) Return success
return "success";
}
#endregion #endregion
#region Administration Commands #region Administration Commands

View File

@ -31,6 +31,7 @@ namespace Server;
ServerLoop(); ServerLoop();
} }
#region MySQL Initialization
private static MySQL LoadOrInitDatabase() private static MySQL LoadOrInitDatabase()
{ {
var cfg = DbConfig.Load(); var cfg = DbConfig.Load();
@ -54,19 +55,18 @@ namespace Server;
return InitializeDatabase(username, password, server, port, database); return InitializeDatabase(username, password, server, port, database);
} }
} }
/// <summary> /// <summary>
/// Creates a new MySQL connection, runs the CREATE TABLE DDL, /// Creates a new MySQL connection, runs the CREATE TABLE DDL,
/// saves credentials in config.json, and returns the MySQL instance. /// saves credentials in config.json, and returns the MySQL instance.
/// </summary> /// </summary>
private static MySQL InitializeDatabase( private static MySQL InitializeDatabase(
string username, string username,
string password, string password,
string server, string server,
string port, string port,
string database string database
) )
{ {
// 1) Instantiate MySQL (will exit on failure) // 1) Instantiate MySQL (will exit on failure)
var db = new MySQL(username, password, server, port, database, messageSender); var db = new MySQL(username, password, server, port, database, messageSender);
string createEmployeesTable = @" string createEmployeesTable = @"
@ -139,6 +139,41 @@ private static MySQL InitializeDatabase(
} }
messageSender.Log("[Program] 'employee_pins' table is ready."); messageSender.Log("[Program] 'employee_pins' table is ready.");
// 3) Neue Tabelle für StatusHistorie anlegen:
string createStateHistoryTable = @"
CREATE TABLE IF NOT EXISTS `employee_state_history` (
`HistoryId` INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
`EmployeeId` INT NOT NULL,
`NewState` INT NOT NULL,
`ChangeTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (`EmployeeId`)
REFERENCES `employees`(`Id`)
ON DELETE CASCADE
ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
";
Program.messageSender.Log("[Program] Ensuring 'employee_state_history' table exists…");
var historyResultJson = db.ExecuteNonQuery(createStateHistoryTable);
try
{
using var doc = JsonDocument.Parse(historyResultJson);
bool histError = doc.RootElement.GetProperty("error").GetBoolean();
if (histError)
{
string dbMsg = doc.RootElement.GetProperty("data").GetString() ?? "Unknown DB error";
Program.messageSender.Error("[Program] Failed to create 'employee_state_history' table: " + dbMsg);
Environment.Exit(1);
}
}
catch (Exception ex)
{
Program.messageSender.Error("[Program] Could not parse state history CREATE TABLE response: " + ex.Message);
Program.messageSender.Error("[Program] Raw response: " + historyResultJson);
Environment.Exit(1);
}
Program.messageSender.Log("[Program] 'employee_state_history' table is ready.");
// … (any further tables) … // … (any further tables) …
// 3) Save the new credentials (including port) into config.json: // 3) Save the new credentials (including port) into config.json:
@ -154,7 +189,9 @@ private static MySQL InitializeDatabase(
messageSender.Log("[Program] Saved DB configuration to config.json."); messageSender.Log("[Program] Saved DB configuration to config.json.");
return db; return db;
} }
#endregion
private static void ServerLoop() private static void ServerLoop()
{ {

View File

@ -81,6 +81,27 @@ public class Tester
$"Forename: {employee.Forename}", $"Forename: {employee.Forename}",
}); });
} }
else if (command == "clock in")
{
string response = await server.ClockIn();
// split response into string[] at \n
var responseLines = response.Split('\n').ToList();
await messageBox.ShowAsync("Command Result: clock in", responseLines);
}
else if (command == "clock out")
{
string response = await server.ClockOut();
// split response into string[] at \n
var responseLines = response.Split('\n').ToList();
await messageBox.ShowAsync("Command Result: clock out", responseLines);
}
else if (command == "clock break")
{
string response = await server.ClockBreak();
// split response into string[] at \n
var responseLines = response.Split('\n').ToList();
await messageBox.ShowAsync("Command Result: clock break", responseLines);
}
} }
catch (Exception ex) catch (Exception ex)
{ {