added subroles and dpi association fixed all pages and migration
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Phinx\Migration\AbstractMigration;
|
||||
|
||||
final class CreateJobSubRolesTable extends AbstractMigration
|
||||
{
|
||||
public function change(): void
|
||||
{
|
||||
$table = $this->table('job_sub_roles', [
|
||||
'id' => false,
|
||||
'primary_key' => ['id'],
|
||||
'collation' => 'utf8mb4_unicode_ci',
|
||||
'encoding' => 'utf8mb4',
|
||||
]);
|
||||
|
||||
$table
|
||||
->addColumn('id', 'integer', [
|
||||
'identity' => true,
|
||||
'signed' => false,
|
||||
])
|
||||
->addColumn('job_role_id', 'integer', [
|
||||
'signed' => false,
|
||||
'null' => false,
|
||||
])
|
||||
->addColumn('name', 'string', [
|
||||
'limit' => 255,
|
||||
'null' => false,
|
||||
])
|
||||
->addColumn('description', 'text', [
|
||||
'null' => true,
|
||||
'default' => null,
|
||||
])
|
||||
->addColumn('sort_order', 'integer', [
|
||||
'signed' => false,
|
||||
'null' => false,
|
||||
'default' => 999,
|
||||
])
|
||||
->addColumn('is_active', 'boolean', [
|
||||
'null' => false,
|
||||
'default' => 1,
|
||||
])
|
||||
->addColumn('created_at', 'timestamp', [
|
||||
'null' => true,
|
||||
'default' => 'CURRENT_TIMESTAMP',
|
||||
])
|
||||
->addColumn('updated_at', 'timestamp', [
|
||||
'null' => true,
|
||||
'default' => 'CURRENT_TIMESTAMP',
|
||||
'update' => 'CURRENT_TIMESTAMP',
|
||||
])
|
||||
->addIndex(['job_role_id'], [
|
||||
'name' => 'idx_job_sub_roles_job_role_id',
|
||||
])
|
||||
->addIndex(['is_active'], [
|
||||
'name' => 'idx_job_sub_roles_is_active',
|
||||
])
|
||||
->addIndex(['sort_order'], [
|
||||
'name' => 'idx_job_sub_roles_sort_order',
|
||||
])
|
||||
->addForeignKey(
|
||||
'job_role_id',
|
||||
'job_roles',
|
||||
'id',
|
||||
[
|
||||
'delete' => 'CASCADE',
|
||||
'update' => 'CASCADE',
|
||||
'constraint' => 'fk_job_sub_roles_job_role',
|
||||
]
|
||||
)
|
||||
->create();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Phinx\Migration\AbstractMigration;
|
||||
|
||||
final class CreatePpeItemsTable extends AbstractMigration
|
||||
{
|
||||
public function change(): void
|
||||
{
|
||||
$table = $this->table('ppe_items', [
|
||||
'id' => false,
|
||||
'primary_key' => ['id'],
|
||||
'collation' => 'utf8mb4_unicode_ci',
|
||||
'encoding' => 'utf8mb4',
|
||||
]);
|
||||
|
||||
$table
|
||||
->addColumn('id', 'integer', [
|
||||
'identity' => true,
|
||||
'signed' => false,
|
||||
])
|
||||
->addColumn('name', 'string', [
|
||||
'limit' => 255,
|
||||
'null' => false,
|
||||
])
|
||||
->addColumn('description', 'text', [
|
||||
'null' => true,
|
||||
'default' => null,
|
||||
])
|
||||
->addColumn('category', 'string', [
|
||||
'limit' => 100,
|
||||
'null' => true,
|
||||
'default' => null,
|
||||
'comment' => 'PPE category, for example Head, Hands, Eyes, Feet, Respiratory',
|
||||
])
|
||||
->addColumn('photo', 'string', [
|
||||
'limit' => 255,
|
||||
'null' => true,
|
||||
'default' => null,
|
||||
'comment' => 'PPE image path or filename',
|
||||
])
|
||||
->addColumn('standard_reference', 'string', [
|
||||
'limit' => 255,
|
||||
'null' => true,
|
||||
'default' => null,
|
||||
'comment' => 'Reference standard, for example EN ISO 20345',
|
||||
])
|
||||
->addColumn('validity_months', 'integer', [
|
||||
'signed' => false,
|
||||
'null' => true,
|
||||
'default' => null,
|
||||
'comment' => 'Default validity in months after assignment',
|
||||
])
|
||||
->addColumn('sort_order', 'integer', [
|
||||
'signed' => false,
|
||||
'null' => false,
|
||||
'default' => 999,
|
||||
])
|
||||
->addColumn('is_active', 'boolean', [
|
||||
'null' => false,
|
||||
'default' => 1,
|
||||
])
|
||||
->addColumn('created_at', 'timestamp', [
|
||||
'null' => true,
|
||||
'default' => 'CURRENT_TIMESTAMP',
|
||||
])
|
||||
->addColumn('updated_at', 'timestamp', [
|
||||
'null' => true,
|
||||
'default' => 'CURRENT_TIMESTAMP',
|
||||
'update' => 'CURRENT_TIMESTAMP',
|
||||
])
|
||||
->addIndex(['category'], [
|
||||
'name' => 'idx_ppe_items_category',
|
||||
])
|
||||
->addIndex(['is_active'], [
|
||||
'name' => 'idx_ppe_items_is_active',
|
||||
])
|
||||
->addIndex(['sort_order'], [
|
||||
'name' => 'idx_ppe_items_sort_order',
|
||||
])
|
||||
->create();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Phinx\Migration\AbstractMigration;
|
||||
|
||||
final class CreateEmployeePpeItemsTable extends AbstractMigration
|
||||
{
|
||||
public function change(): void
|
||||
{
|
||||
$table = $this->table('employee_ppe_items', [
|
||||
'id' => false,
|
||||
'primary_key' => ['id'],
|
||||
'collation' => 'utf8mb4_unicode_ci',
|
||||
'encoding' => 'utf8mb4',
|
||||
]);
|
||||
|
||||
$table
|
||||
->addColumn('id', 'integer', [
|
||||
'identity' => true,
|
||||
'signed' => false,
|
||||
])
|
||||
->addColumn('employee_id', 'integer', [
|
||||
'signed' => false,
|
||||
'null' => false,
|
||||
])
|
||||
->addColumn('ppe_item_id', 'integer', [
|
||||
'signed' => false,
|
||||
'null' => false,
|
||||
])
|
||||
->addColumn('assigned_date', 'date', [
|
||||
'null' => true,
|
||||
'default' => null,
|
||||
])
|
||||
->addColumn('expiry_date', 'date', [
|
||||
'null' => true,
|
||||
'default' => null,
|
||||
])
|
||||
->addColumn('quantity', 'integer', [
|
||||
'signed' => false,
|
||||
'null' => false,
|
||||
'default' => 1,
|
||||
])
|
||||
->addColumn('status', 'enum', [
|
||||
'values' => [
|
||||
'assigned',
|
||||
'returned',
|
||||
'expired',
|
||||
'lost',
|
||||
'damaged',
|
||||
],
|
||||
'null' => false,
|
||||
'default' => 'assigned',
|
||||
])
|
||||
->addColumn('notes', 'text', [
|
||||
'null' => true,
|
||||
'default' => null,
|
||||
])
|
||||
->addColumn('created_at', 'timestamp', [
|
||||
'null' => true,
|
||||
'default' => 'CURRENT_TIMESTAMP',
|
||||
])
|
||||
->addColumn('updated_at', 'timestamp', [
|
||||
'null' => true,
|
||||
'default' => 'CURRENT_TIMESTAMP',
|
||||
'update' => 'CURRENT_TIMESTAMP',
|
||||
])
|
||||
->addIndex(['employee_id'], [
|
||||
'name' => 'idx_employee_ppe_items_employee_id',
|
||||
])
|
||||
->addIndex(['ppe_item_id'], [
|
||||
'name' => 'idx_employee_ppe_items_ppe_item_id',
|
||||
])
|
||||
->addIndex(['status'], [
|
||||
'name' => 'idx_employee_ppe_items_status',
|
||||
])
|
||||
->addIndex(['expiry_date'], [
|
||||
'name' => 'idx_employee_ppe_items_expiry_date',
|
||||
])
|
||||
->addForeignKey(
|
||||
'employee_id',
|
||||
'employees',
|
||||
'id',
|
||||
[
|
||||
'delete' => 'CASCADE',
|
||||
'update' => 'CASCADE',
|
||||
'constraint' => 'fk_employee_ppe_items_employee',
|
||||
]
|
||||
)
|
||||
->addForeignKey(
|
||||
'ppe_item_id',
|
||||
'ppe_items',
|
||||
'id',
|
||||
[
|
||||
'delete' => 'RESTRICT',
|
||||
'update' => 'CASCADE',
|
||||
'constraint' => 'fk_employee_ppe_items_ppe_item',
|
||||
]
|
||||
)
|
||||
->create();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Phinx\Migration\AbstractMigration;
|
||||
|
||||
final class CreateJobSubRolePpeItemsTable extends AbstractMigration
|
||||
{
|
||||
public function change(): void
|
||||
{
|
||||
$table = $this->table('job_sub_role_ppe_items', [
|
||||
'id' => false,
|
||||
'primary_key' => ['id'],
|
||||
'collation' => 'utf8mb4_unicode_ci',
|
||||
'encoding' => 'utf8mb4',
|
||||
]);
|
||||
|
||||
$table
|
||||
->addColumn('id', 'integer', [
|
||||
'identity' => true,
|
||||
'signed' => false,
|
||||
])
|
||||
->addColumn('job_sub_role_id', 'integer', [
|
||||
'signed' => false,
|
||||
'null' => false,
|
||||
])
|
||||
->addColumn('ppe_item_id', 'integer', [
|
||||
'signed' => false,
|
||||
'null' => false,
|
||||
])
|
||||
->addColumn('requirement_type', 'enum', [
|
||||
'values' => [
|
||||
'mandatory',
|
||||
'recommended',
|
||||
'optional',
|
||||
],
|
||||
'null' => false,
|
||||
'default' => 'mandatory',
|
||||
'comment' => 'Defines if the PPE is mandatory, recommended or optional for the sub role',
|
||||
])
|
||||
->addColumn('notes', 'text', [
|
||||
'null' => true,
|
||||
'default' => null,
|
||||
])
|
||||
->addColumn('sort_order', 'integer', [
|
||||
'signed' => false,
|
||||
'null' => false,
|
||||
'default' => 999,
|
||||
])
|
||||
->addColumn('is_active', 'boolean', [
|
||||
'null' => false,
|
||||
'default' => 1,
|
||||
])
|
||||
->addColumn('created_at', 'timestamp', [
|
||||
'null' => true,
|
||||
'default' => 'CURRENT_TIMESTAMP',
|
||||
])
|
||||
->addColumn('updated_at', 'timestamp', [
|
||||
'null' => true,
|
||||
'default' => 'CURRENT_TIMESTAMP',
|
||||
'update' => 'CURRENT_TIMESTAMP',
|
||||
])
|
||||
->addIndex(['job_sub_role_id'], [
|
||||
'name' => 'idx_job_sub_role_ppe_items_sub_role_id',
|
||||
])
|
||||
->addIndex(['ppe_item_id'], [
|
||||
'name' => 'idx_job_sub_role_ppe_items_ppe_item_id',
|
||||
])
|
||||
->addIndex(['requirement_type'], [
|
||||
'name' => 'idx_job_sub_role_ppe_items_requirement_type',
|
||||
])
|
||||
->addIndex(['is_active'], [
|
||||
'name' => 'idx_job_sub_role_ppe_items_is_active',
|
||||
])
|
||||
->addIndex(['job_sub_role_id', 'ppe_item_id'], [
|
||||
'unique' => true,
|
||||
'name' => 'uq_job_sub_role_ppe_item',
|
||||
])
|
||||
->addForeignKey(
|
||||
'job_sub_role_id',
|
||||
'job_sub_roles',
|
||||
'id',
|
||||
[
|
||||
'delete' => 'CASCADE',
|
||||
'update' => 'CASCADE',
|
||||
'constraint' => 'fk_job_sub_role_ppe_items_sub_role',
|
||||
]
|
||||
)
|
||||
->addForeignKey(
|
||||
'ppe_item_id',
|
||||
'ppe_items',
|
||||
'id',
|
||||
[
|
||||
'delete' => 'CASCADE',
|
||||
'update' => 'CASCADE',
|
||||
'constraint' => 'fk_job_sub_role_ppe_items_ppe_item',
|
||||
]
|
||||
)
|
||||
->create();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Phinx\Migration\AbstractMigration;
|
||||
|
||||
final class AddJobSubRoleIdToEmployeesTable extends AbstractMigration
|
||||
{
|
||||
public function change(): void
|
||||
{
|
||||
$table = $this->table('employees');
|
||||
|
||||
$table
|
||||
->addColumn('job_sub_role_id', 'integer', [
|
||||
'signed' => false,
|
||||
'null' => true,
|
||||
'default' => null,
|
||||
'after' => 'job_role_id',
|
||||
])
|
||||
->addIndex(['job_sub_role_id'], [
|
||||
'name' => 'idx_employees_job_sub_role_id',
|
||||
])
|
||||
->addForeignKey(
|
||||
'job_sub_role_id',
|
||||
'job_sub_roles',
|
||||
'id',
|
||||
[
|
||||
'delete' => 'SET_NULL',
|
||||
'update' => 'CASCADE',
|
||||
'constraint' => 'fk_employees_job_sub_role',
|
||||
]
|
||||
)
|
||||
->update();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Phinx\Migration\AbstractMigration;
|
||||
|
||||
final class AddDeliveryFieldsToEmployeePpeItemsTable extends AbstractMigration
|
||||
{
|
||||
public function change(): void
|
||||
{
|
||||
$table = $this->table('employee_ppe_items');
|
||||
|
||||
$table
|
||||
->addColumn('delivered_by', 'string', [
|
||||
'limit' => 255,
|
||||
'null' => true,
|
||||
'default' => null,
|
||||
'after' => 'expiry_date',
|
||||
])
|
||||
->addColumn('created_by', 'integer', [
|
||||
'signed' => false,
|
||||
'null' => true,
|
||||
'default' => null,
|
||||
'after' => 'notes',
|
||||
])
|
||||
->addIndex(['created_by'], [
|
||||
'name' => 'idx_employee_ppe_items_created_by',
|
||||
])
|
||||
->addForeignKey(
|
||||
'created_by',
|
||||
'auth_users',
|
||||
'id',
|
||||
[
|
||||
'delete' => 'SET_NULL',
|
||||
'update' => 'CASCADE',
|
||||
'constraint' => 'fk_employee_ppe_items_created_by',
|
||||
]
|
||||
)
|
||||
->update();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Phinx\Migration\AbstractMigration;
|
||||
|
||||
final class CreateEmployeeJobSubRolesTable extends AbstractMigration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
if (!$this->hasTable('employee_job_sub_roles')) {
|
||||
$table = $this->table('employee_job_sub_roles', [
|
||||
'id' => false,
|
||||
'primary_key' => ['id'],
|
||||
'signed' => false,
|
||||
'collation' => 'utf8mb4_general_ci',
|
||||
'encoding' => 'utf8mb4',
|
||||
]);
|
||||
|
||||
$table
|
||||
->addColumn('id', 'integer', [
|
||||
'identity' => true,
|
||||
'signed' => false,
|
||||
])
|
||||
->addColumn('employee_id', 'integer', [
|
||||
'signed' => false,
|
||||
'null' => false,
|
||||
])
|
||||
->addColumn('job_sub_role_id', 'integer', [
|
||||
'signed' => false,
|
||||
'null' => false,
|
||||
])
|
||||
->addColumn('is_primary', 'boolean', [
|
||||
'null' => false,
|
||||
'default' => false,
|
||||
])
|
||||
->addColumn('created_at', 'timestamp', [
|
||||
'null' => true,
|
||||
'default' => 'CURRENT_TIMESTAMP',
|
||||
])
|
||||
->addIndex(['employee_id', 'job_sub_role_id'], [
|
||||
'unique' => true,
|
||||
'name' => 'uq_employee_subrole',
|
||||
])
|
||||
->addIndex(['employee_id'], [
|
||||
'name' => 'idx_employee_job_sub_roles_employee',
|
||||
])
|
||||
->addIndex(['job_sub_role_id'], [
|
||||
'name' => 'idx_employee_job_sub_roles_subrole',
|
||||
])
|
||||
->addForeignKey(
|
||||
'employee_id',
|
||||
'employees',
|
||||
'id',
|
||||
[
|
||||
'delete' => 'CASCADE',
|
||||
'update' => 'CASCADE',
|
||||
'constraint' => 'fk_employee_job_sub_roles_employee',
|
||||
]
|
||||
)
|
||||
->addForeignKey(
|
||||
'job_sub_role_id',
|
||||
'job_sub_roles',
|
||||
'id',
|
||||
[
|
||||
'delete' => 'CASCADE',
|
||||
'update' => 'CASCADE',
|
||||
'constraint' => 'fk_employee_job_sub_roles_subrole',
|
||||
]
|
||||
)
|
||||
->create();
|
||||
}
|
||||
|
||||
// Import existing single sub-role assignments from employees.job_sub_role_id
|
||||
// into the new bridge table.
|
||||
$this->execute("
|
||||
INSERT IGNORE INTO employee_job_sub_roles
|
||||
(employee_id, job_sub_role_id, is_primary, created_at)
|
||||
SELECT
|
||||
e.id,
|
||||
e.job_sub_role_id,
|
||||
1,
|
||||
NOW()
|
||||
FROM employees e
|
||||
WHERE e.job_sub_role_id IS NOT NULL
|
||||
AND e.job_sub_role_id > 0
|
||||
");
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
if ($this->hasTable('employee_job_sub_roles')) {
|
||||
$this->table('employee_job_sub_roles')->drop()->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,26 +1,38 @@
|
||||
<?php
|
||||
require_once(__DIR__ . '/../hr_auth_check.php');
|
||||
include('../../include/headscript.php');
|
||||
|
||||
header('Content-Type: application/json');
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||
http_response_code(405);
|
||||
echo json_encode(['success' => false, 'message' => 'Metodo non consentito.']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$pdo = DBHandlerSelect::getInstance()->getConnection();
|
||||
|
||||
$id = (int)($_POST['id'] ?? 0);
|
||||
if ($id <= 0) {
|
||||
echo json_encode(['success' => false, 'message' => 'ID DPI non valido.']);
|
||||
exit;
|
||||
}
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
|
||||
try {
|
||||
$stmt = $pdo->prepare("DELETE FROM employee_ppe WHERE id = :id");
|
||||
$stmt->execute(['id' => $id]);
|
||||
echo json_encode(['success' => true]);
|
||||
} catch (Exception $e) {
|
||||
echo json_encode(['success' => false, 'message' => $e->getMessage()]);
|
||||
$pdo = DBHandlerSelect::getInstance()->getConnection();
|
||||
|
||||
$id = (int)($_POST['id'] ?? 0);
|
||||
|
||||
if ($id <= 0) {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => 'ID DPI non valido.'
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
$stmt = $pdo->prepare("
|
||||
UPDATE employee_ppe_items
|
||||
SET status = 'returned',
|
||||
updated_at = NOW()
|
||||
WHERE id = ?
|
||||
");
|
||||
$stmt->execute([$id]);
|
||||
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'message' => 'DPI rimosso correttamente.'
|
||||
]);
|
||||
exit;
|
||||
} catch (Throwable $e) {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => $e->getMessage()
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
@@ -1,82 +1,153 @@
|
||||
<?php
|
||||
require_once(__DIR__ . '/../hr_auth_check.php');
|
||||
include('../../include/headscript.php');
|
||||
|
||||
header('Content-Type: application/json');
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||
http_response_code(405);
|
||||
echo json_encode(['success' => false, 'message' => 'Metodo non consentito.']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$pdo = DBHandlerSelect::getInstance()->getConnection();
|
||||
|
||||
$id = (int)($_POST['id'] ?? 0);
|
||||
$employeeId = (int)($_POST['employee_id'] ?? 0);
|
||||
$itemName = trim($_POST['item_name'] ?? '');
|
||||
$deliveryDate = trim($_POST['delivery_date'] ?? '');
|
||||
$deliveredBy = trim($_POST['delivered_by'] ?? '');
|
||||
$notes = trim($_POST['notes'] ?? '');
|
||||
|
||||
if ($employeeId <= 0) {
|
||||
echo json_encode(['success' => false, 'message' => 'ID dipendente non valido.']);
|
||||
exit;
|
||||
}
|
||||
if ($itemName === '') {
|
||||
echo json_encode(['success' => false, 'message' => 'Il nome del DPI è obbligatorio.']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$deliveryDate = $deliveryDate === '' ? null : $deliveryDate;
|
||||
$deliveredBy = $deliveredBy !== '' ? $deliveredBy : null;
|
||||
$notes = $notes !== '' ? $notes : null;
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
|
||||
try {
|
||||
if ($id > 0) {
|
||||
$stmt = $pdo->prepare("
|
||||
UPDATE employee_ppe
|
||||
SET item_name = :item_name,
|
||||
delivery_date = :delivery_date,
|
||||
delivered_by = :delivered_by,
|
||||
notes = :notes,
|
||||
updated_at = NOW()
|
||||
WHERE id = :id AND employee_id = :eid
|
||||
");
|
||||
$stmt->execute([
|
||||
'item_name' => $itemName,
|
||||
'delivery_date' => $deliveryDate,
|
||||
'delivered_by' => $deliveredBy,
|
||||
'notes' => $notes,
|
||||
'id' => $id,
|
||||
'eid' => $employeeId,
|
||||
$pdo = DBHandlerSelect::getInstance()->getConnection();
|
||||
|
||||
$id = isset($_POST['id']) && $_POST['id'] !== '' ? (int)$_POST['id'] : null;
|
||||
$employeeId = (int)($_POST['employee_id'] ?? 0);
|
||||
$ppeItemId = (int)($_POST['ppe_item_id'] ?? 0);
|
||||
$assignedDate = trim($_POST['assigned_date'] ?? '');
|
||||
$expiryDate = trim($_POST['expiry_date'] ?? '');
|
||||
$deliveredBy = trim($_POST['delivered_by'] ?? '');
|
||||
$status = trim($_POST['status'] ?? 'assigned');
|
||||
$notes = trim($_POST['notes'] ?? '');
|
||||
|
||||
$allowedStatuses = [
|
||||
'assigned',
|
||||
'returned',
|
||||
'expired',
|
||||
'lost',
|
||||
'damaged',
|
||||
];
|
||||
|
||||
if ($employeeId <= 0) {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => 'Dipendente non valido.'
|
||||
]);
|
||||
echo json_encode(['success' => true, 'id' => $id]);
|
||||
exit;
|
||||
}
|
||||
|
||||
$check = $pdo->prepare("SELECT COUNT(*) FROM employees WHERE id = :id");
|
||||
$check->execute(['id' => $employeeId]);
|
||||
if ((int)$check->fetchColumn() === 0) {
|
||||
echo json_encode(['success' => false, 'message' => 'Dipendente non trovato.']);
|
||||
if ($ppeItemId <= 0) {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => 'Selezionare un DPI.'
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
if (!in_array($status, $allowedStatuses, true)) {
|
||||
$status = 'assigned';
|
||||
}
|
||||
|
||||
$checkEmployee = $pdo->prepare("SELECT id FROM employees WHERE id = ? LIMIT 1");
|
||||
$checkEmployee->execute([$employeeId]);
|
||||
|
||||
if (!$checkEmployee->fetchColumn()) {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => 'Dipendente non trovato.'
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
$checkPpe = $pdo->prepare("SELECT id FROM ppe_items WHERE id = ? LIMIT 1");
|
||||
$checkPpe->execute([$ppeItemId]);
|
||||
|
||||
if (!$checkPpe->fetchColumn()) {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => 'DPI non trovato.'
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($id) {
|
||||
$stmt = $pdo->prepare("
|
||||
UPDATE employee_ppe_items
|
||||
SET ppe_item_id = :ppe_item_id,
|
||||
assigned_date = :assigned_date,
|
||||
expiry_date = :expiry_date,
|
||||
delivered_by = :delivered_by,
|
||||
status = :status,
|
||||
notes = :notes,
|
||||
updated_at = NOW()
|
||||
WHERE id = :id
|
||||
AND employee_id = :employee_id
|
||||
");
|
||||
|
||||
$stmt->execute([
|
||||
'ppe_item_id' => $ppeItemId,
|
||||
'assigned_date' => $assignedDate !== '' ? $assignedDate : null,
|
||||
'expiry_date' => $expiryDate !== '' ? $expiryDate : null,
|
||||
'delivered_by' => $deliveredBy !== '' ? $deliveredBy : null,
|
||||
'status' => $status,
|
||||
'notes' => $notes !== '' ? $notes : null,
|
||||
'id' => $id,
|
||||
'employee_id' => $employeeId,
|
||||
]);
|
||||
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'message' => 'DPI aggiornato.'
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
$stmt = $pdo->prepare("
|
||||
INSERT INTO employee_ppe
|
||||
(employee_id, item_name, delivery_date, delivered_by, notes, created_by, created_at, updated_at)
|
||||
INSERT INTO employee_ppe_items
|
||||
(
|
||||
employee_id,
|
||||
ppe_item_id,
|
||||
assigned_date,
|
||||
expiry_date,
|
||||
delivered_by,
|
||||
quantity,
|
||||
status,
|
||||
notes,
|
||||
created_by,
|
||||
created_at,
|
||||
updated_at
|
||||
)
|
||||
VALUES
|
||||
(:employee_id, :item_name, :delivery_date, :delivered_by, :notes, :created_by, NOW(), NOW())
|
||||
(
|
||||
:employee_id,
|
||||
:ppe_item_id,
|
||||
:assigned_date,
|
||||
:expiry_date,
|
||||
:delivered_by,
|
||||
1,
|
||||
:status,
|
||||
:notes,
|
||||
:created_by,
|
||||
NOW(),
|
||||
NOW()
|
||||
)
|
||||
");
|
||||
|
||||
$stmt->execute([
|
||||
'employee_id' => $employeeId,
|
||||
'item_name' => $itemName,
|
||||
'delivery_date' => $deliveryDate,
|
||||
'delivered_by' => $deliveredBy,
|
||||
'notes' => $notes,
|
||||
'created_by' => $currentUserId,
|
||||
'employee_id' => $employeeId,
|
||||
'ppe_item_id' => $ppeItemId,
|
||||
'assigned_date' => $assignedDate !== '' ? $assignedDate : null,
|
||||
'expiry_date' => $expiryDate !== '' ? $expiryDate : null,
|
||||
'delivered_by' => $deliveredBy !== '' ? $deliveredBy : null,
|
||||
'status' => $status,
|
||||
'notes' => $notes !== '' ? $notes : null,
|
||||
'created_by' => isset($iduserlogin) ? (int)$iduserlogin : null,
|
||||
]);
|
||||
|
||||
echo json_encode(['success' => true, 'id' => (int)$pdo->lastInsertId()]);
|
||||
} catch (Exception $e) {
|
||||
echo json_encode(['success' => false, 'message' => $e->getMessage()]);
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'message' => 'DPI assegnato.'
|
||||
]);
|
||||
exit;
|
||||
} catch (Throwable $e) {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => $e->getMessage()
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+1398
-462
File diff suppressed because it is too large
Load Diff
@@ -307,25 +307,13 @@
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (userCan('hr.training_topics.view')) : ?>
|
||||
<li>
|
||||
<a href="training_topics.php">
|
||||
<i class='bx bx-radio-circle'></i>Corsi di Formazione
|
||||
</a>
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (userCan('hr.trainings.view')) : ?>
|
||||
<li>
|
||||
<a href="trainings.php">
|
||||
<i class='bx bx-radio-circle'></i>Storico Formazione
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="training_calendar.php">
|
||||
<i class='bx bx-radio-circle'></i>Calendario Formazione
|
||||
<i class='bx bx-radio-circle'></i>Gestione Formazione
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (userCan('hr.skills.view')) : ?>
|
||||
@@ -393,4 +381,4 @@
|
||||
|
||||
</ul>
|
||||
<!--end navigation-->
|
||||
</div>
|
||||
</div>
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -155,12 +155,19 @@ $dashboardSections = [
|
||||
'open' => false,
|
||||
'buttons' => [
|
||||
[
|
||||
'label' => 'Employees',
|
||||
'label' => 'Dipendenti',
|
||||
'icon' => '👥',
|
||||
'class' => 'btn-employees',
|
||||
'url' => 'employees.php',
|
||||
'permission' => 'hr.employees.view',
|
||||
],
|
||||
[
|
||||
'label' => 'Mansioni',
|
||||
'icon' => '🧩',
|
||||
'class' => 'btn-setup',
|
||||
'url' => 'job-roles.php',
|
||||
'permission' => 'hr.employees.view',
|
||||
],
|
||||
[
|
||||
'label' => 'Departments',
|
||||
'icon' => '🏢',
|
||||
@@ -169,14 +176,14 @@ $dashboardSections = [
|
||||
'permission' => 'hr.departments.view',
|
||||
],
|
||||
[
|
||||
'label' => 'Corsi Formazione',
|
||||
'icon' => '📚',
|
||||
'label' => 'DPI',
|
||||
'icon' => '🦺',
|
||||
'class' => 'btn-setup',
|
||||
'url' => 'training_topics.php',
|
||||
'permission' => 'hr.training_topics.view',
|
||||
'url' => 'ppe-items.php',
|
||||
'permission' => 'hr.employees.view',
|
||||
],
|
||||
[
|
||||
'label' => 'Storico Formazione',
|
||||
'label' => 'Gestione Formazione',
|
||||
'icon' => '🎓',
|
||||
'class' => 'btn-setup',
|
||||
'url' => 'trainings.php',
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
<?php
|
||||
include('../../include/headscript.php');
|
||||
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
|
||||
$pdo = DBHandlerSelect::getInstance()->getConnection();
|
||||
|
||||
function jsonResponse(array $data): void
|
||||
{
|
||||
echo json_encode($data);
|
||||
exit;
|
||||
}
|
||||
|
||||
function normalizeNullableInt($value): ?int
|
||||
{
|
||||
return (isset($value) && $value !== '') ? (int)$value : null;
|
||||
}
|
||||
|
||||
try {
|
||||
$isHrManager = Auth::user()->hasRole('Admin')
|
||||
|| Auth::user()->hasRole('Superuser')
|
||||
|| Auth::user()->hasRole('employee-hr')
|
||||
|| Auth::user()->hasRole('manager');
|
||||
|
||||
if (!$isHrManager) {
|
||||
jsonResponse(['success' => false, 'message' => 'Non autorizzato.']);
|
||||
}
|
||||
|
||||
$employeeId = (int)($_POST['employee_id'] ?? 0);
|
||||
$firstName = trim($_POST['first_name'] ?? '');
|
||||
$lastName = trim($_POST['last_name'] ?? '');
|
||||
$employeeCode = trim($_POST['employee_code'] ?? '');
|
||||
$hireDate = trim($_POST['hire_date'] ?? '');
|
||||
$address = trim($_POST['address'] ?? '');
|
||||
$phone = trim($_POST['phone'] ?? '');
|
||||
$email = trim($_POST['email'] ?? '');
|
||||
$departmentId = normalizeNullableInt($_POST['department_id'] ?? '');
|
||||
$status = trim($_POST['status'] ?? 'active');
|
||||
$authUserId = normalizeNullableInt($_POST['auth_user_id'] ?? '');
|
||||
$roleId = normalizeNullableInt($_POST['role_id'] ?? '');
|
||||
|
||||
$jobSubRoleIds = $_POST['job_sub_role_ids'] ?? [];
|
||||
if (!is_array($jobSubRoleIds)) {
|
||||
$jobSubRoleIds = [$jobSubRoleIds];
|
||||
}
|
||||
|
||||
$jobSubRoleIds = array_values(array_unique(array_filter(array_map('intval', $jobSubRoleIds))));
|
||||
|
||||
if ($employeeId <= 0) {
|
||||
jsonResponse(['success' => false, 'message' => 'ID dipendente non valido.']);
|
||||
}
|
||||
|
||||
if ($firstName === '' || $lastName === '') {
|
||||
jsonResponse(['success' => false, 'message' => 'Nome e cognome sono obbligatori.']);
|
||||
}
|
||||
|
||||
if ($email !== '' && !filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
||||
jsonResponse(['success' => false, 'message' => 'Email non valida.']);
|
||||
}
|
||||
|
||||
if (!in_array($status, ['active', 'inactive', 'suspended'], true)) {
|
||||
$status = 'active';
|
||||
}
|
||||
|
||||
$stmtEmployee = $pdo->prepare('SELECT id FROM employees WHERE id = ? LIMIT 1');
|
||||
$stmtEmployee->execute([$employeeId]);
|
||||
if (!$stmtEmployee->fetchColumn()) {
|
||||
jsonResponse(['success' => false, 'message' => 'Dipendente non trovato.']);
|
||||
}
|
||||
|
||||
$primaryJobRoleId = null;
|
||||
$primaryJobSubRoleId = null;
|
||||
|
||||
if ($jobSubRoleIds) {
|
||||
$placeholders = implode(',', array_fill(0, count($jobSubRoleIds), '?'));
|
||||
$stmtSubRoles = $pdo->prepare("\n SELECT id, job_role_id\n FROM job_sub_roles\n WHERE id IN ($placeholders)\n AND is_active = 1\n ");
|
||||
$stmtSubRoles->execute($jobSubRoleIds);
|
||||
$validRows = $stmtSubRoles->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
$validMap = [];
|
||||
foreach ($validRows as $row) {
|
||||
$validMap[(int)$row['id']] = (int)$row['job_role_id'];
|
||||
}
|
||||
|
||||
$jobSubRoleIds = array_values(array_filter($jobSubRoleIds, static function ($id) use ($validMap) {
|
||||
return isset($validMap[(int)$id]);
|
||||
}));
|
||||
|
||||
if ($jobSubRoleIds) {
|
||||
$primaryJobSubRoleId = (int)$jobSubRoleIds[0];
|
||||
$primaryJobRoleId = $validMap[$primaryJobSubRoleId] ?? null;
|
||||
}
|
||||
}
|
||||
|
||||
$pdo->beginTransaction();
|
||||
|
||||
$stmt = $pdo->prepare("\n UPDATE employees\n SET first_name = :first_name,\n last_name = :last_name,\n employee_code = :employee_code,\n hire_date = :hire_date,\n address = :address,\n phone = :phone,\n email = :email,\n department_id = :department_id,\n job_role_id = :job_role_id,\n job_sub_role_id = :job_sub_role_id,\n status = :status,\n auth_user_id = :auth_user_id,\n updated_at = NOW()\n WHERE id = :employee_id\n ");
|
||||
$stmt->execute([
|
||||
'first_name' => $firstName,
|
||||
'last_name' => $lastName,
|
||||
'employee_code' => $employeeCode !== '' ? $employeeCode : null,
|
||||
'hire_date' => $hireDate !== '' ? $hireDate : null,
|
||||
'address' => $address !== '' ? $address : null,
|
||||
'phone' => $phone !== '' ? $phone : null,
|
||||
'email' => $email !== '' ? $email : null,
|
||||
'department_id' => $departmentId,
|
||||
'job_role_id' => $primaryJobRoleId,
|
||||
'job_sub_role_id' => $primaryJobSubRoleId,
|
||||
'status' => $status,
|
||||
'auth_user_id' => $authUserId,
|
||||
'employee_id' => $employeeId,
|
||||
]);
|
||||
|
||||
$stmtDelete = $pdo->prepare('DELETE FROM employee_job_sub_roles WHERE employee_id = ?');
|
||||
$stmtDelete->execute([$employeeId]);
|
||||
|
||||
if ($jobSubRoleIds) {
|
||||
$stmtInsert = $pdo->prepare("\n INSERT INTO employee_job_sub_roles\n (employee_id, job_sub_role_id, is_primary, created_at)\n VALUES\n (:employee_id, :job_sub_role_id, :is_primary, NOW())\n ");
|
||||
|
||||
foreach ($jobSubRoleIds as $index => $jobSubRoleId) {
|
||||
$stmtInsert->execute([
|
||||
'employee_id' => $employeeId,
|
||||
'job_sub_role_id' => (int)$jobSubRoleId,
|
||||
'is_primary' => $index === 0 ? 1 : 0,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
if ($authUserId !== null && $roleId !== null) {
|
||||
$checkRole = $pdo->prepare('SELECT COUNT(*) FROM auth_roles WHERE id = ?');
|
||||
$checkRole->execute([$roleId]);
|
||||
|
||||
if ((int)$checkRole->fetchColumn() > 0) {
|
||||
$stmtRole = $pdo->prepare('UPDATE auth_users SET role_id = :role_id, updated_at = NOW() WHERE id = :auth_user_id');
|
||||
$stmtRole->execute([
|
||||
'role_id' => $roleId,
|
||||
'auth_user_id' => $authUserId,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
$pdo->commit();
|
||||
|
||||
jsonResponse(['success' => true]);
|
||||
} catch (Throwable $e) {
|
||||
if (isset($pdo) && $pdo->inTransaction()) {
|
||||
$pdo->rollBack();
|
||||
}
|
||||
|
||||
jsonResponse([
|
||||
'success' => false,
|
||||
'message' => $e->getMessage(),
|
||||
]);
|
||||
}
|
||||
@@ -96,7 +96,7 @@
|
||||
</div>
|
||||
|
||||
<!-- Group 3: Responsabili -->
|
||||
<div class="form-section-title">Responsabili</div>
|
||||
<div class="form-section-title">Esecutore</div>
|
||||
<div class="row g-3 mb-4">
|
||||
<div class="col-12">
|
||||
<label for="dlDepartments" class="form-label fw-semibold">Reparti</label>
|
||||
@@ -159,4 +159,4 @@
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -967,7 +967,7 @@ function getContrastTextColor($hexColor)
|
||||
<th>Scadenza</th>
|
||||
<th class="d-none d-lg-table-cell">Verifica</th>
|
||||
<th>Funzione</th>
|
||||
<th>Responsabili</th>
|
||||
<th>Esecutore</th>
|
||||
<th>Stato</th>
|
||||
<th class="text-center" style="width:120px">Azioni</th>
|
||||
</tr>
|
||||
@@ -1435,4 +1435,4 @@ function getContrastTextColor($hexColor)
|
||||
<?php include __DIR__ . '/include/deadline_modal_js.php'; ?>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</html>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 6.0 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 47 KiB |
Reference in New Issue
Block a user