38438-vm/import_labour.php
2026-02-15 16:51:04 +00:00

186 lines
8.1 KiB
PHP

<?php
require_once 'db/config.php';
$pageTitle = 'Import Labour Activities';
$message = '';
$error = '';
$results = [];
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['csv_file'])) {
$file = $_FILES['csv_file'];
if ($file['error'] !== UPLOAD_ERR_OK) {
$error = 'File upload failed.';
} else {
$handle = fopen($file['tmp_name'], 'r');
$header = fgetcsv($handle);
$expected = ['project_code', 'employee_email', 'date', 'hours', 'labour_type', 'evidence_type', 'notes'];
if (!$header || count(array_intersect($expected, $header)) < 1) {
$error = 'Invalid CSV format. Please use the provided template.';
} else {
$columnMap = array_flip($header);
// Pre-fetch lookups
$projects = [];
$stmt = db()->query("SELECT id, code FROM projects WHERE tenant_id = 1");
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) $projects[$row['code']] = $row['id'];
$employees = [];
$stmt = db()->query("SELECT id, email FROM employees WHERE tenant_id = 1");
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) $employees[$row['email']] = $row['id'];
$labourTypes = [];
$stmt = db()->query("SELECT id, name FROM labour_types");
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) $labourTypes[strtolower($row['name'])] = $row['id'];
$evidenceTypes = [];
$stmt = db()->query("SELECT id, name FROM evidence_types");
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) $evidenceTypes[strtolower($row['name'])] = $row['id'];
$rowCount = 0;
$importCount = 0;
$skippedCount = 0;
db()->beginTransaction();
try {
$stmt = db()->prepare("INSERT INTO labour_entries (tenant_id, project_id, employee_id, entry_date, hours, labour_type_id, evidence_type_id, notes) VALUES (?, ?, ?, ?, ?, ?, ?, ?)");
while (($row = fgetcsv($handle)) !== false) {
$rowCount++;
$data = [];
foreach ($expected as $col) {
$data[$col] = isset($columnMap[$col]) && isset($row[$columnMap[$col]]) ? trim($row[$columnMap[$col]]) : '';
}
$rowErrors = [];
$projectId = $projects[$data['project_code']] ?? null;
$employeeId = $employees[$data['employee_email']] ?? null;
$labourTypeId = $labourTypes[strtolower($data['labour_type'])] ?? null;
$evidenceTypeId = $evidenceTypes[strtolower($data['evidence_type'])] ?? 5; // Default to 'None'
if (!$projectId) $rowErrors[] = "Invalid Project Code: " . $data['project_code'];
if (!$employeeId) $rowErrors[] = "Invalid Employee Email: " . $data['employee_email'];
if (!$labourTypeId) $rowErrors[] = "Invalid Labour Type: " . $data['labour_type'];
if (empty($data['date']) || !strtotime($data['date'])) $rowErrors[] = "Invalid Date: " . $data['date'];
if (!is_numeric($data['hours'])) $rowErrors[] = "Invalid Hours: " . $data['hours'];
if (!empty($rowErrors)) {
$skippedCount++;
$results[] = "Row $rowCount: Skipped (" . implode(', ', $rowErrors) . ")";
continue;
}
$stmt->execute([
1,
$projectId,
$employeeId,
date('Y-m-d', strtotime($data['date'])),
$data['hours'],
$labourTypeId,
$evidenceTypeId,
$data['notes']
]);
$importCount++;
}
db()->commit();
$message = "Import completed successfully. $importCount activities imported, $skippedCount skipped.";
} catch (Exception $e) {
db()->rollBack();
$error = 'Database error: ' . $e->getMessage();
}
}
fclose($handle);
}
}
include 'includes/header.php';
?>
<div class="container mt-4">
<div class="d-flex justify-content-between align-items-center mb-4">
<h2><i class="bi bi-clock-history me-2"></i>Import Labour Activities</h2>
<a href="samples/labour_template.csv" class="btn btn-outline-primary btn-sm">
<i class="bi bi-download me-1"></i>Download Template
</a>
</div>
<?php if ($message): ?>
<div class="alert alert-success alert-dismissible fade show" role="alert">
<?= $message ?>
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
<?php endif; ?>
<?php if ($error): ?>
<div class="alert alert-danger alert-dismissible fade show" role="alert">
<?= $error ?>
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
<?php endif; ?>
<div class="row">
<div class="col-md-6">
<div class="card shadow-sm border-0">
<div class="card-body p-4">
<form action="import_labour.php" method="POST" enctype="multipart/form-data">
<div class="mb-4">
<label for="csv_file" class="form-label fw-bold">Select CSV File</label>
<input type="file" class="form-control" id="csv_file" name="csv_file" accept=".csv" required>
<div class="form-text mt-2">
Max file size: 5MB. Only .csv files are allowed.
</div>
</div>
<button type="submit" class="btn btn-primary w-100 py-2">
<i class="bi bi-upload me-2"></i>Upload and Import
</button>
</form>
</div>
</div>
</div>
<div class="col-md-6">
<div class="card shadow-sm border-0 h-100">
<div class="card-header bg-white py-3">
<h5 class="mb-0">Import Instructions</h5>
</div>
<div class="card-body">
<ol class="small text-muted">
<li>Download the CSV template using the button above.</li>
<li>Ensure <strong>Project Code</strong> and <strong>Employee Email</strong> match existing records.</li>
<li><strong>Date</strong> should be in YYYY-MM-DD format.</li>
<li><strong>Labour Type</strong> must match one of:
<ul class="mb-0">
<li>Experimental Development</li>
<li>Technical Support</li>
<li>Technical Planning</li>
</ul>
</li>
<li>Upload and review the logs for any skipped rows.</li>
</ol>
</div>
</div>
</div>
</div>
<?php if (!empty($results)): ?>
<div class="card shadow-sm border-0 mt-4">
<div class="card-header bg-white py-3">
<h5 class="mb-0">Import Logs</h5>
</div>
<div class="card-body">
<div class="list-group list-group-flush small">
<?php foreach ($results as $res): ?>
<div class="list-group-item px-0 border-0 py-1">
<i class="bi bi-exclamation-triangle-fill text-warning me-1"></i><?= $res ?>
</div>
<?php endforeach; ?>
</div>
</div>
</div>
<?php endif; ?>
</div>
<?php include 'includes/footer.php'; ?>