381 lines
15 KiB
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);
|
|
}
|
|
}
|