Files
thetool/application/WarehouseProject/WarehouseProjectController.php

381 lines
15 KiB
PHP

<?php
class WarehouseProjectController extends TTCrud {
protected string $headerTitle = 'Projekte';
protected string $singleText = 'Projekt';
protected bool $createText = false;
//@formatter:off
protected array $columns = [
['key' => 'id', 'text' => 'ID', 'table' => false, 'modal' => false],
['key' => 'projectNumber', 'text' => 'Projekt-Nr.', 'required' => false, 'modal' => ['disabled' => true, 'placeholder' => 'Wird automatisch generiert']],
['key' => 'title', 'text' => 'Bezeichnung', 'required' => true],
['key' => 'status', 'text' => 'Status', 'required' => true, 'modal' => ['type' => 'select', 'items' => [
['value' => 'new', 'text' => 'Neu'],
['value' => 'wip', 'text' => 'In Bearbeitung'],
['value' => 'finished', 'text' => 'Abgeschlossen'],
['value' => 'cancelled', 'text' => 'Storniert'],
]], 'table' => ['filter' => 'select']],
['key' => 'startDate', 'text' => 'Startdatum', 'required' => true, 'modal' => ['type' => 'date'], 'table' => ['filter' => 'date']],
['key' => 'endDate', 'text' => 'Enddatum', 'required' => true, 'modal' => ['type' => 'date'], 'table' => ['filter' => 'date']],
['key' => 'financials', 'text' => 'Gesamtsumme', 'required' => false, 'modal' => ['disabled' => true], 'table' => ['formatter' => 'formatPrice']],
['key' => 'storageLocation', 'text' => 'Lagerort', 'required' => false],
['key' => 'externalTeam', 'text' => 'Externes Team', 'required' => false, 'modal' => ['type' => 'textarea'], 'table' => false],
['key' => 'description', 'text' => 'Beschreibung', 'required' => false, 'modal' => ['type' => 'textarea'], 'table' => false],
['key' => 'create', 'text' => 'Erstellt', 'required' => false, 'modal' => false, 'table' => ['formatter' => 'formatDate']],
['key' => 'actions', 'text' => 'Aktionen', 'required' => false, 'modal' => false, 'table' => ['filter' => false, 'sortable' => false, 'class' => 'text-center']],
];
//@formatter:on
protected array $permissionCheck = ['WarehouseUser'];
protected array $additionalJSVariables = ['WAREHOUSE_ADMIN' => false];
protected function prepareCrudConfig(): void {
if ($this->user->can('WarehouseAdmin')) {
$this->additionalJSVariables['WAREHOUSE_ADMIN'] = true;
}
}
private array $tempInternalTeam = [];
protected function beforeCreate(): bool {
$json = json_decode(file_get_contents('php://input'), true);
if ($json) {
$this->postData = array_merge($this->postData ?? [], $json);
}
if (isset($this->postData['internalTeam'])) {
$this->tempInternalTeam = $this->postData['internalTeam'];
unset($this->postData['internalTeam']);
}
$this->postData['projectNumber'] = WarehouseProjectModel::getNextProjectNumber();
// Ensure defaults if not provided
if (!isset($this->postData['status'])) $this->postData['status'] = 'new';
if (!isset($this->postData['financials'])) $this->postData['financials'] = 0.00;
return true;
}
protected function afterCreate($id): void
{
WarehouseProjectJournalModel::create([
'projectId' => $id,
'text' => 'Projekt erstellt.',
'createBy' => $this->user->id,
'create' => time()
]);
// Handle initial Internal Team
if (!empty($this->tempInternalTeam) && is_array($this->tempInternalTeam)) {
foreach ($this->tempInternalTeam as $userId) {
WarehouseProjectMemberModel::create([
'projectId' => $id,
'userId' => $userId,
'create' => time()
]);
$u = UserModel::getOne($userId);
$this->logJournal($id, "Teammitglied initial hinzugefügt: " . ($u ? $u->name : $userId));
}
}
}
protected function afterUpdate($postData): void
{
$id = $postData['id'];
// Simple journaling of main record update
WarehouseProjectJournalModel::create([
'projectId' => $id,
'text' => 'Projektstammdaten aktualisiert.',
'createBy' => $this->user->id,
'create' => time()
]);
}
// --- API for Vue ---
public function getProjectDetailsAction() {
$id = $this->request->id;
if (!$id) self::sendError("Projekt ID fehlt");
$project = WarehouseProjectModel::get($id);
if (!$project) self::sendError("Projekt nicht gefunden");
self::returnJson(['project' => $project]);
}
public function getTasksAction() {
$projectId = $this->request->id;
if (!$projectId) self::sendError("Projekt ID fehlt");
$tasks = WarehouseProjectTaskModel::getAll(['projectId' => $projectId], null, 0, ['key' => 'order', 'order' => 'ASC']);
foreach ($tasks as $task) {
if ($task->assignedUserId) {
$user = UserModel::getOne($task->assignedUserId);
$task->assignedUserName = $user ? $user->name : 'Unbekannt';
} else {
$task->assignedUserName = null;
}
}
self::returnJson($tasks);
}
public function saveTaskAction() {
$data = json_decode(file_get_contents('php://input'), true);
$projectId = $data['projectId'] ?? null;
if (!$projectId) self::sendError("Projekt ID fehlt");
$taskData = [
'projectId' => $projectId,
'title' => $data['title'],
'description' => $data['description'] ?? '',
'status' => $data['status'] ?? 'todo',
'assignedUserId' => !empty($data['assignedUserId']) ? $data['assignedUserId'] : null,
'createBy' => $this->user->id,
'create' => time()
];
if (!empty($data['id'])) {
$existingTask = WarehouseProjectTaskModel::get($data['id']);
if (!$existingTask) self::sendError("Aufgabe nicht gefunden");
// Merge existing data with new data to ensure all required fields are present
$updatedData = array_merge((array)$existingTask, $taskData);
$updatedData['id'] = $data['id']; // Ensure ID is in the data for update
// update method expects an array with 'id' key for update.
WarehouseProjectTaskModel::update($updatedData);
$this->logJournal($projectId, "Aufgabe aktualisiert: {$data['title']}");
} else {
// Get max order to append
$count = WarehouseProjectTaskModel::count(['projectId' => $projectId]);
$taskData['order'] = $count + 1;
WarehouseProjectTaskModel::create($taskData);
$this->logJournal($projectId, "Aufgabe erstellt: {$data['title']}");
}
self::returnJson(['success' => true]);
}
public function updateTaskStatusAction() {
$data = json_decode(file_get_contents('php://input'), true);
if (empty($data['id']) || empty($data['status'])) self::sendError("Daten fehlen");
$task = WarehouseProjectTaskModel::get($data['id']);
if ($task) {
// Retrieve existing task data to preserve projectId and other required fields
$updatedData = (array)$task;
$updatedData['status'] = $data['status'];
// WarehouseProjectTaskModel::update expects an array with 'id' key for update.
WarehouseProjectTaskModel::update($updatedData);
$this->logJournal($task->projectId, "Aufgabenstatus '{$task->title}' geändert auf {$data['status']}");
}
self::returnJson(['success' => true]);
}
public function deleteTaskAction() {
$id = $this->request->id;
if (!$id) self::sendError("ID fehlt");
$task = WarehouseProjectTaskModel::get($id);
if ($task) {
WarehouseProjectTaskModel::delete($id);
$this->logJournal($task->projectId, "Aufgabe gelöscht: {$task->title}");
}
self::returnJson(['success' => true]);
}
public function getTeamAction() {
$projectId = $this->request->id;
if (!$projectId) self::sendError("ID fehlt");
$members = WarehouseProjectMemberModel::getAll(['projectId' => $projectId]);
$users = [];
foreach($members as $m) {
$u = UserModel::getOne($m->userId);
if ($u) {
$users[] = [
'memberId' => $m->id,
'userId' => $u->id,
'name' => $u->name,
'role' => $m->role
];
}
}
self::returnJson($users);
}
public function addTeamMemberAction() {
$data = json_decode(file_get_contents('php://input'), true);
if (empty($data['projectId']) || empty($data['userId'])) self::sendError("Daten fehlen");
$exists = WarehouseProjectMemberModel::count(['projectId' => $data['projectId'], 'userId' => $data['userId']]);
if ($exists > 0) self::sendError("Benutzer bereits im Team");
WarehouseProjectMemberModel::create([
'projectId' => $data['projectId'],
'userId' => $data['userId'],
'role' => $data['role'] ?? null,
'create' => time()
]);
$u = UserModel::getOne($data['userId']);
$this->logJournal($data['projectId'], "Teammitglied hinzugefügt: " . ($u ? $u->name : $data['userId']));
self::returnJson(['success' => true]);
}
public function removeTeamMemberAction() {
$id = $this->request->id;
$member = WarehouseProjectMemberModel::get($id);
if ($member) {
$u = UserModel::getOne($member->userId);
WarehouseProjectMemberModel::delete($id);
$this->logJournal($member->projectId, "Teammitglied entfernt: " . ($u ? $u->name : $member->userId));
}
self::returnJson(['success' => true]);
}
public function getAvailableOrderRequestsAction() {
// Return open requests (not done, not cancelled)
// You might want to filter out ones already linked to THIS project, but maybe not strictly necessary.
$requests = WarehouseOrderRequest::getAll([], 100, 0, ['key' => 'create', 'order' => 'DESC']);
$available = [];
foreach($requests as $r) {
if (!$r->done && !$r->cancelled) {
$available[] = [
'id' => $r->id,
'purpose' => $r->purpose,
'create' => $r->create
];
}
}
self::returnJson($available);
}
public function getLinkedOrdersAction() {
$projectId = $this->request->id;
if (!$projectId) self::sendError("ID fehlt");
$links = WarehouseProjectOrderRequestModel::getAll(['projectId' => $projectId]);
$result = [];
foreach($links as $l) {
$req = WarehouseOrderRequest::get($l->orderRequestId);
if ($req) {
$positions = json_decode($req->positions, true);
// Resolve actual Orders
$orders = [];
$ids = [];
if (!empty($req->linkedOrderIds)) {
// Check if it is JSON array
$decoded = json_decode($req->linkedOrderIds, true);
if (is_array($decoded)) {
$ids = $decoded;
} else {
// Fallback to comma separated
$ids = explode(',', $req->linkedOrderIds);
}
}
foreach($ids as $oid) {
$oid = trim($oid);
if (empty($oid)) continue;
$o = WarehouseOrderModel::get($oid);
if ($o) {
$orders[] = [
'id' => $o->id,
'orderNumber' => $o->orderNumber,
'status' => $o->status,
'distributorId' => $o->distributorId
];
}
}
$result[] = [
'linkId' => $l->id,
'requestId' => $req->id,
'purpose' => $req->purpose,
'create' => $req->create,
'status' => $req->done ? 'done' : ($req->cancelled ? 'cancelled' : 'open'),
'positionsCount' => is_array($positions) ? count($positions) : 0,
'orders' => $orders
];
}
}
self::returnJson($result);
}
public function linkOrderAction() {
$data = json_decode(file_get_contents('php://input'), true);
if (empty($data['projectId']) || empty($data['orderId'])) self::sendError("Daten fehlen");
$order = WarehouseOrderRequest::get($data['orderId']);
if (!$order) self::sendError("Bestellwunsch nicht gefunden");
WarehouseProjectOrderRequestModel::create([
'projectId' => $data['projectId'],
'orderRequestId' => $data['orderId'],
'create' => time()
]);
$this->logJournal($data['projectId'], "Bestellwunsch #{$data['orderId']} verknüpft.");
self::returnJson(['success' => true]);
}
public function unlinkOrderAction() {
$id = $this->request->id;
$link = WarehouseProjectOrderRequestModel::get($id);
if ($link) {
WarehouseProjectOrderRequestModel::delete($id);
$this->logJournal($link->projectId, "Bestellwunsch #{$link->orderRequestId} Verknüpfung aufgehoben.");
}
self::returnJson(['success' => true]);
}
public function createJournalEntryAction() {
$data = json_decode(file_get_contents('php://input'), true);
if (empty($data['projectId'])) self::sendError("Projekt ID fehlt");
$this->logJournal($data['projectId'], $data['message'] ?? '');
self::returnJson(['success' => true]);
}
public function getJournalAction() {
$projectId = $this->request->id;
$logs = WarehouseProjectJournalModel::getAll(['projectId' => $projectId], null, 0, ['order' => 'DESC', 'key' => 'create']);
foreach($logs as $log) {
$u = UserModel::getOne($log->createBy);
$log->userName = $u ? $u->name : 'System';
}
self::returnJson($logs);
}
private function logJournal($projectId, $text) {
WarehouseProjectJournalModel::create([
'projectId' => $projectId,
'text' => $text,
'createBy' => $this->user->id,
'create' => time()
]);
}
// Users for Team Selection
public function getUsersAction() {
$users = array_map(function($u) {
return ['id' => $u->id, 'name' => $u->name];
}, UserModel::search(['employee' => true]));
self::returnJson($users);
}
}