Files
thetool/Layout/default/Preorder/Index.php
2025-12-17 16:41:11 +01:00

2535 lines
129 KiB
PHP

<?php
$pagination_baseurl = $this->getUrl($Mod,"Index");
$pagination_baseurl_params = ["filter" => $filter];
$pagination_entity_name = "Vorbestellungen";
?>
<?php include(realpath(dirname(__FILE__)."/../../$mfLayoutPackage")."/header.php"); ?>
<style>
.select2-selection.select2-selection--multiple {
min-height: calc(1.5em + .9rem + 2px);
}
.preorder-campaign-header, .preorder-campaign-header-buttons {
display: flex;
justify-content: space-between;
}
.preorder-campaign-import {
display: flex;
gap: 8px;
justify-content: flex-start;
}
.preorder-campaign-header-buttons {
max-width: 1100px;
}
.tr-highlight {
background-color: #a0eaaf !important;
}
.tr-highlight .status {
border-radius: unset !important;
}
.is-billed-button {
padding:6px;
padding-left: 8px;
padding-right: 8px;
background-color: #25b343;
color: #fff;
}
.set-billed-button {
padding:6px;
padding-left: 8px;
padding-right: 8px;
border: 1px solid #d0d0d0;
}
.set-billed-button:hover {
background-color: #007bff;
color: #fff;
}
@media (max-width: 1720px) {
.preorder-filters .col-sm-12 {
display: flex;
flex-direction: column;
justify-content: flex-end;
}
}
@media (max-width: 576px) {
.preorder-campaign-import, .preorder-campaign-header {
display: grid;
grid-template-columns: 1fr;
grid-gap: 8px;
}
.preorder-campaign-table-wrapper {
overflow-x: auto;
}
.preorder-campaign-header h4 {
text-align: center;
}
.preorder-campaign-header-buttons {
display: grid;
grid-template-columns: 1fr 1fr;
grid-gap: 8px;
}
.preorder-campaign-table-actions {
display: grid;
grid-gap: 4px;
grid-template-columns: auto auto auto;
}
.preorder-campaign-table-actions a {
text-align: center;
font-size: 24px;
}
.preorder-campaign-table-actions a[title="Vorbestellkampagne Löschen"] {
grid-column: 3;
}
}
/* styles for documents */
.document-upload-wrapper {
background: #fdfdfd;
border: 1px solid #e9ecef;
border-radius: .25rem;
}
.document-dropzone {
border: 2px dashed #ced4da;
border-radius: 0.25rem;
padding: 1.5rem;
text-align: center;
background-color: #f8f9fa;
transition: all 0.3s ease;
cursor: pointer;
}
.document-dropzone:hover {
border-color: #007bff;
background-color: #e9ecef;
}
.document-dropzone.active {
border-color: #007bff;
border-style: solid;
}
.document-staging-area {
max-height: 250px;
overflow-y: auto;
}
.document-staging-item {
display: flex;
align-items: flex-start;
padding: 0.75rem;
border: 1px solid #dee2e6;
border-radius: 0.25rem;
margin-bottom: 0.5rem;
background-color: #fff;
}
.doc-staging-icon {
flex-shrink: 0;
width: 30px;
text-align: center;
padding-top: 0.25rem;
}
.doc-staging-details {
flex-grow: 1;
padding: 0 0.5rem;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.doc-staging-filename {
font-size: 0.9em;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.doc-staging-filesize {
font-size: 0.8em;
}
.doc-staging-actions {
flex-shrink: 0;
}
.document-list-wrapper {
min-height: 300px;
}
.doc-spinner {
display: inline-block;
width: 3rem;
height: 3rem;
vertical-align: text-bottom;
border: 0.25em solid currentColor;
border-right-color: transparent;
border-radius: 50%;
animation: doc-spin 0.75s linear infinite;
color: #007bff;
}
@keyframes doc-spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.doc-row-icon i { font-size: 1.5rem; }
.doc-row-icon .fa-file-pdf { color: #dc3545; }
.doc-row-icon .fa-file-image { color: #28a745; }
.doc-row-icon .fa-file-word { color: #007bff; }
.doc-row-icon .fa-file-excel { color: #207245; }
.doc-row-icon .fa-file-archive { color: #ffc107; }
.doc-row-icon .fa-file { color: #6c757d; }
.doc-preview-modal-body img,
.doc-preview-modal-body embed,
.doc-preview-modal-body iframe {
max-width: 100%;
max-height: 75vh;
border: none;
}
</style>
<script>
$(function() {
if (window.matchMedia('(min-width: 576px)').matches) return;
const $pagination = $("ul.pagination");
const $disabled = $pagination.find(".page-item.disabled.points");
if ($disabled.length) {
const $first = $pagination.find(".page-item").first();
const $firstNext = $first.next();
const $last = $pagination.find(".page-item").last();
const $lastPrev = $last.prev();
const $prev = $disabled.prev();
const $next = $disabled.next();
const $keep = $().add($first).add($firstNext).add($last).add($lastPrev).add($prev).add($next).add($disabled);
$pagination.find(".page-item").not($keep).remove();
}
});
$(function() {
function initPreorderDocumentTabs() {
$('.preorder-documents-tab').each(function() {
const tabPane = $(this);
const preorderId = tabPane.data('preorder-id');
if (!preorderId) return;
const dropzone = tabPane.find('.doc-dropzone');
const browseBtn = tabPane.find('.doc-browse-btn');
const fileInput = tabPane.find('.doc-file-input');
const stagingArea = tabPane.find('.doc-staging-area');
const stagingTemplate = tabPane.find('.doc-staging-item-template')[0];
const uploadBtn = tabPane.find('.doc-upload-btn');
const uploadBtnText = tabPane.find('.doc-upload-btn-text');
const uploadSpinner = tabPane.find('.doc-upload-spinner');
const listLoader = tabPane.find('.document-list-loader');
const emptyState = tabPane.find('.document-empty-state');
const listContainer = tabPane.find('.document-list-container');
const listTbody = tabPane.find('.doc-list-tbody');
const listRowTemplate = tabPane.find('.doc-list-row-template')[0];
const modal = tabPane.find('.doc-preview-modal');
const modalTitle = modal.find('.doc-preview-modal-title');
const modalBody = modal.find('.doc-preview-modal-body');
let stagedFiles = new Map();
// --- START FIX 1: Helper function to decode HTML entities ---
function htmlDecode(input) {
if (!input || typeof input !== 'string') return input;
var doc = new DOMParser().parseFromString(input, "text/html");
return doc.documentElement.textContent;
}
// --- END FIX 1 ---
function formatFileSize(bytes, decimals = 2) {
if (bytes === 0) return '0 Bytes';
const k = 1024;
const dm = decimals < 0 ? 0 : decimals;
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
}
function guessMimeType(filename) {
const ext = (filename || '').split('.').pop().toLowerCase();
const mimeTypes = {
'pdf': 'application/pdf',
'jpg': 'image/jpeg',
'jpeg': 'image/jpeg',
'png': 'image/png',
'gif': 'image/gif',
'doc': 'application/msword',
'docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'xls': 'application/vnd.ms-excel',
'xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'zip': 'application/zip',
};
return mimeTypes[ext] || 'application/octet-stream';
}
function getFileIcon(mimeType) {
if (!mimeType) return '<i class="fas fa-file fa-fw"></i>';
const iconMap = {
'image/': 'fa-file-image',
'application/pdf': 'fa-file-pdf',
'word': 'fa-file-word',
'excel': 'fa-file-excel',
'spreadsheet': 'fa-file-excel',
'zip': 'fa-file-archive',
'archive': 'fa-file-archive'
};
for (const key in iconMap) {
if (mimeType.includes(key)) return `<i class="fas ${iconMap[key]} fa-fw"></i>`;
}
return '<i class="fas fa-file fa-fw"></i>';
}
function isPreviewable(mimeType) {
return mimeType.startsWith('image/') || mimeType === 'application/pdf';
}
async function fetchFileMetaData(fileId, description) {
try {
const response = await fetch(`/File/getById?id=${fileId}`);
if (!response.ok) return null;
const data = await response.json();
const mimetype = guessMimeType(data.filename);
return {
id: fileId,
fileId: fileId,
fileName: data.filename,
description: description,
mimetype: mimetype
};
} catch (error) {
return null;
}
}
async function loadDocuments() {
listLoader.show();
listContainer.hide();
emptyState.hide();
listTbody.empty();
let fileObjects = [];
try {
const rawData = tabPane.data('file-objects');
if (typeof rawData === 'string') {
const decodedData = htmlDecode(rawData);
fileObjects = JSON.parse(decodedData);
} else if (Array.isArray(rawData)) {
fileObjects = rawData;
}
} catch (e) {
console.error("Error parsing file objects:", e, tabPane.data('file-objects'));
fileObjects = [];
}
if (fileObjects.length === 0) {
emptyState.show();
listLoader.hide();
return;
}
try {
const fetchPromises = fileObjects.map(obj => fetchFileMetaData(obj.id, obj.description));
const documents = (await Promise.all(fetchPromises)).filter(doc => doc !== null);
if (documents.length === 0) {
emptyState.show();
} else {
documents.forEach(addDocumentRow);
listContainer.show();
}
} catch (error) {
emptyState.find('h5').text('Fehler beim Laden');
emptyState.find('p').text('Die Dokumente konnten nicht geladen werden.');
emptyState.show();
} finally {
listLoader.hide();
}
}
function addDocumentRow(docData, prepend = false) {
const rowClone = listRowTemplate.content.cloneNode(true);
const $row = $(rowClone).find('tr');
$row.attr('data-doc-id', docData.id);
$row.find('.doc-row-icon').html(getFileIcon(docData.mimetype));
$row.find('.doc-row-filename').text(docData.fileName);
$row.find('.doc-row-description').text(docData.description || '');
const previewUrl = `/File/show?id=${docData.fileId}`;
const downloadUrl = `/File/download?id=${docData.fileId}`;
$row.find('.doc-preview-btn').data({
url: previewUrl,
type: docData.mimetype,
filename: docData.fileName
});
$row.find('.doc-download-btn').attr({
href: downloadUrl,
download: docData.fileName
});
if (!isPreviewable(docData.mimetype)) {
$row.find('.doc-preview-btn').addClass('disabled').attr('title', 'Vorschau nicht verfügbar');
}
prepend ? listTbody.prepend($row) : listTbody.append($row);
emptyState.hide();
listContainer.show();
}
tabPane.data('loadDocumentsFunction', loadDocuments);
function handleFiles(files) {
for (const file of files) {
const fileId = `file-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
stagedFiles.set(fileId, file);
const itemClone = stagingTemplate.content.cloneNode(true);
const item = $(itemClone).find('.document-staging-item');
item.attr('data-file-id', fileId);
item.find('.doc-staging-filename').text(file.name);
item.find('.doc-staging-filesize').text(formatFileSize(file.size));
item.find('.doc-staging-icon').html(getFileIcon(file.type));
stagingArea.append(item).show();
}
updateUploadButton();
}
function updateUploadButton() {
if (stagedFiles.size > 0) {
uploadBtnText.text(`${stagedFiles.size} Datei(en) hochladen`);
uploadBtn.show();
} else {
uploadBtn.hide();
stagingArea.hide();
}
}
dropzone.on('dragover', (e) => {
e.preventDefault();
e.stopPropagation();
dropzone.addClass('active');
});
dropzone.on('dragleave', (e) => {
e.preventDefault();
e.stopPropagation();
dropzone.removeClass('active');
});
dropzone.on('drop', (e) => {
e.preventDefault();
e.stopPropagation();
dropzone.removeClass('active');
handleFiles(e.originalEvent.dataTransfer.files);
});
// --- START FIX 2: Modify click handlers ---
browseBtn.on('click', (e) => {
e.preventDefault();
e.stopPropagation(); // Stop this click from bubbling up to the dropzone
fileInput.click();
});
dropzone.on('click', function(e) {
// If the click target was the button or the file input, do nothing.
if ($(e.target).closest('.doc-browse-btn').length > 0 || $(e.target).hasClass('doc-file-input')) {
return;
}
// Otherwise, trigger the file input click.
fileInput.click();
});
// --- END FIX 2 ---
fileInput.on('change', (e) => {
handleFiles(e.target.files);
fileInput.val(null);
});
stagingArea.on('click', '.doc-staging-remove', function() {
const item = $(this).closest('.document-staging-item');
const fileId = item.data('file-id');
stagedFiles.delete(fileId);
item.fadeOut(300, function() {
$(this).remove();
updateUploadButton();
});
});
uploadBtn.on('click', async function() {
let allValid = true;
const formData = new FormData();
formData.append('preorderId', preorderId);
stagingArea.find('.document-staging-item').each(function() {
const item = $(this);
const fileId = item.data('file-id');
const file = stagedFiles.get(fileId);
const descriptionInput = item.find('.doc-staging-description');
const description = descriptionInput.val().trim();
if (!description) {
descriptionInput.addClass('is-invalid');
allValid = false;
} else {
descriptionInput.removeClass('is-invalid');
formData.append('files[]', file, file.name);
formData.append('descriptions[]', description);
}
});
if (!allValid) {
if (window.notify) window.notify('error', 'Bitte füllen Sie alle Beschreibungsfelder aus.');
return;
}
uploadBtn.prop('disabled', true);
uploadSpinner.show();
try {
const response = await fetch('/Preorder/uploadDocuments', {
method: 'POST',
body: formData
});
const result = await response.json();
if (response.ok && result.success) {
if (window.notify) window.notify('success', result.message || 'Dateien erfolgreich hochgeladen.');
stagedFiles.clear();
stagingArea.empty().hide();
updateUploadButton();
if (result.fileObjects) tabPane.data('file-objects', result.fileObjects);
loadDocuments();
} else {
throw new Error(result.message || 'Unbekannter Fehler beim Upload.');
}
} catch (err) {
if (window.notify) window.notify('error', `Upload fehlgeschlagen: ${err.message}`);
} finally {
uploadBtn.prop('disabled', false);
uploadSpinner.hide();
}
});
listTbody.on('click', '.doc-preview-btn', function() {
if ($(this).hasClass('disabled')) return;
const url = $(this).data('url');
const type = $(this).data('type');
const filename = $(this).data('filename');
modalTitle.text(filename);
modalBody.empty();
if (type.startsWith('image/')) {
modalBody.html(`<img src="${url}" class="img-fluid" alt="Vorschau von ${filename}">`);
} else if (type === 'application/pdf') {
window.open(url, '_blank');
return;
} else {
modalBody.html(`<div class="text-center p-5"><i class="fas fa-file-excel fa-3x text-muted mb-3"></i><p>Keine Vorschau für den Dateityp "${type}" verfügbar.</p></div>`);
}
modal.modal('show');
});
});
}
$('a[data-toggle="tab"]').on('shown.bs.tab', function(e) {
const targetId = $(e.target).attr('href');
if (!targetId || !targetId.endsWith('-documents')) return;
const tabPane = $(targetId);
if (tabPane.hasClass('preorder-documents-tab') && tabPane.data('loaded') === false) {
const loaderFunc = tabPane.data('loadDocumentsFunction');
if (typeof loaderFunc === 'function') {
loaderFunc();
tabPane.data('loaded', true);
}
}
});
initPreorderDocumentTabs();
});
</script>
<!-- start page title -->
<div class="row">
<div class="col-12">
<div class="page-title-box">
<div class="page-title-right">
<ol class="breadcrumb m-0">
<li class="breadcrumb-item"><a href="<?=self::getUrl("Dashboard")?>"><?=MFAPPNAME_SLUG?></a></li>
<li class="breadcrumb-item"><a href="<?=self::getUrl("Preordercampaign")?>">Vorbestellkampagnen</a></li>
<li class="breadcrumb-item active">Vorbestellungen</li>
</ol>
</div>
<h4 class="page-title">Vorbestellungen<?=(isset($campaign) && $campaign) ? " - ".$campaign->name : ""?></h4>
</div>
</div>
</div>
<!-- end page title -->
<div class="row">
<div class="col-lg-12">
<div class="card">
<div class="card-body mb-3">
<h4 class="header-title mb-3">Filter</h4>
<form method="get" action="<?=self::getUrl("Preorder")?>" class="preorder-filters">
<div class="row">
<div class="col-sm-12 col-md-2">
<label class="form-label" for="filter_preordercampaign_id">Kampagne</label>
<select name="filter[preordercampaign_id]" id="filter_preordercampaign_id" class="form-control">
<option value="">Alle</option>
<?php foreach($my_campaigns as $c): ?>
<option value="<?=$c->id?>" <?=(isset($campaign) && $c->id == $campaign->id) ? "selected='selected'" : ""?>><?=$c->name?></option>
<?php endforeach; ?>
</select>
</div>
<div class="col-sm-12 col-md-2">
<label class="form-label" for="partner_id">Partner</label>
<select name="filter[partner_id][]" id="filter_partner_id" class="form-control" multiple="multiple">
<?php
// if partner_id is string unset it from filter
if(isset($filter) && array_key_exists("partner_id", $filter) && is_string($filter["partner_id"])) {
unset($filter["partner_id"]);
}
?>
<?php foreach($partners as $partner): ?>
<option value="<?=$partner['partner_id']?>" <?=(isset($filter) && array_key_exists("partner_id", $filter) && in_array($partner['partner_id'], $filter["partner_id"])) ? "selected='selected'" : ""?>><?=$partner['name']?></option>
<?php endforeach; ?>
</select>
</div>
<div class="col-sm-12 col-md-2">
<label class="form-label" for="filter_status">Status</label>
<select name="filter[status][]" id="filter_status" class="form-control" multiple="multiple">
<?php foreach(PreorderstatusModel::getAll() as $status): ?>
<option value="<?=$status->id?>" <?=(isset($filter) && array_key_exists("status", $filter) && in_array($status->id, $filter['status'])) ? "selected='selected'" : ""?>><?=$status->code?> - <?=$status->name?></option>
<?php endforeach; ?>
</select>
</div>
<div class="col-sm-12 col-md-2">
<label class="form-label" for="filter_borderpoint_status">Borderpoint Status</label>
<select name="filter[borderpoint_status]" id="filter_borderpoint_status" class="form-control">
<option></option>
<option value="need_measurement" <?=(isset($filter) && array_key_exists("borderpoint_status", $filter) && $filter["borderpoint_status"] == "need_measurement") ? "selected='selected'" : ""?>>Messung erforderlich</option>
<option value="informed" <?=(isset($filter) && array_key_exists("borderpoint_status", $filter) && $filter["borderpoint_status"] == "informed") ? "selected='selected'" : ""?>>Beauskunftet</option>
<option value="need_digging" <?=(isset($filter) && array_key_exists("borderpoint_status", $filter) && $filter["borderpoint_status"] == "need_digging") ? "selected='selected'" : ""?>>Grabung ausständig</option>
</select>
</div>
<div class="col-sm-12 col-md-2">
<label class="form-label" for="connection_type">Anschlusstyp</label>
<select name="filter[connection_type][]" id="connection_type_id" class="form-control" multiple="multiple">
<?php
$connection_types = ["single-dwelling","multi-dwelling","apartment-building","apartment","business"];
foreach($connection_types as $connection_type): ?>
<option value="<?=$connection_type?>" <?=(isset($filter) && array_key_exists("connection_type", $filter) && in_array($connection_type, $filter["connection_type"])) ? "selected='selected'" : ""?>><?=__($connection_type, "preorder")?></option>
<?php endforeach; ?>
</select>
</div>
<div class="col-sm-12 col-md-2">
<label class="form-label" for="filter_type">Bestelltyp</label>
<select name="filter[type][]" id="filter_type" class="form-control" multiple="multiple">
<option value="interest" <?=(isset($filter) && array_key_exists("type", $filter) && in_array("interest", $filter['type'])) ? "selected='selected'" : ""?>>Interessensbekundung</option>
<option value="provision" <?=(isset($filter) && array_key_exists("type", $filter) && in_array("provision", $filter['type'])) ? "selected='selected'" : ""?>>Vorsorgeanschluss</option>
<option value="order" <?=(isset($filter) && array_key_exists("type", $filter) && in_array("order", $filter['type'])) ? "selected='selected'" : ""?>>Vollanschluss</option>
<option value="legacytransfer" <?=(isset($filter) && array_key_exists("type", $filter) && in_array("legacytransfer", $filter['type'])) ? "selected='selected'" : ""?>>Bestandsübernahme</option>
</select>
</div>
<!-- INFO THIS FILTER IS CURRENTLY HIDDEN -->
<!-- <div class="col-sm-12 col-md-2">-->
<!-- <label class="form-label" for="filter_addon_services">Zusatzdienste</label>-->
<!-- <select name="filter[addon_services]" id="filter_addon_services" class="form-control">-->
<!-- <option></option>-->
<!-- <option value="1" --><?php //=(isset($filter['addon_services']) && $filter['addon_services'] == 1) ? "selected='selected'" : ""?><!-- >Nur mit Zusatzdiensten</option>-->
<!-- </select>-->
<!-- </div>-->
</div>
<div class="row mt-2">
<div class="col-sm-12 col-md-1">
<label class="form-label" for="filter_ucode">Bestellcode</label>
<input type="text" class="form-control" name="filter[ucode]" id="filter_ucode" value="<?=$filter['ucode'] ?? ""?>" />
</div>
<div class="col-sm-12 col-md-1">
<label class="form-label" for="filter_oaid">OAID</label>
<input type="text" class="form-control" name="filter[oaid]" id="filter_oaid" value="<?=$filter['oaid'] ?? ""?>" />
</div>
<div class="col-sm-12 col-md-2">
<label class="form-label" for="filter_workorder_name">Rimo Workorder Name</label>
<input type="text" class="form-control" name="filter[rimo_workorder_name]" id="filter_workorder_name" value="<?=$filter['workorder_name'] ?? ""?>" />
</div>
<div class="col-sm-12 col-md-2">
<label class="form-label" for="filter_address">Anschlussadresse</label>
<input type="text" class="form-control" name="filter[address]" id="filter_address" value="<?=$filter['address'] ?? ""?>" />
</div>
<div class="col-sm-12 col-md-2">
<label class="form-label" for="filter_kunde">Kunde</label>
<input type="text" class="form-control" name="filter[kunde]" id="filter_kunde" value="<?=$filter['kunde'] ?? ""?>" />
</div>
<div class="col-sm-12 col-md-2">
<label class="form-label" for="filter_magic_search">erweiterte Suche</label>
<input type="text" class="form-control" name="filter[magic_search]" id="filter_magic_search" value="<?=$filter['magic_search'] ?? ""?>" />
</div>
<div class="col-sm-12 col-md-2">
<label class="form-label" for="filter_created_from">Zeitraum</label>
<select name="filter[created_from]" id="filter_created_from" class="form-control">
<option value=""></option>
<option value="7" <?=(isset($filter) && array_key_exists("created_from", $filter) && $filter["created_from"] == 7) ? "selected='selected'" : ""?>>7 Tage</option>
<option value="14" <?=(isset($filter) && array_key_exists("created_from", $filter) && $filter["created_from"] == 14) ? "selected='selected'" : ""?>>14 Tage</option>
<option value="30" <?=(isset($filter) && array_key_exists("created_from", $filter) && $filter["created_from"] == 30) ? "selected='selected'" : ""?>>30 Tage</option>
</select>
</div>
</div>
<div class="row mt-2">
<div class="col-sm-12 col-md-1">
<label class="form-label" for="filter_unit_missing">Wohneinheit</label>
<select name="filter[unit_missing]" id="filter_unit_missing" class="form-control">
<option value=""></option>
<option value="yes" <?=(isset($filter) && array_key_exists("unit_missing", $filter) && $filter['unit_missing'] == "yes") ? "selected='selected'" : ""?>>Wohneinheit fehlt</option>
<option value="no" <?=(isset($filter) && array_key_exists("unit_missing", $filter) && $filter['unit_missing'] == "no") ? "selected='selected'" : ""?>>Wohneinheit vorhanden</option>
</select>
</div>
<div class="col-sm-12 col-md-2">
<label class="form-label" for="rimo_home_extref">Wohneinheit Rimo-Extref</label>
<select name="filter[rimo_home_extref]" id="filter_rimo_home_extref" class="form-control">
<option value=""></option>
<option value="0" <?=(isset($filter) && array_key_exists("rimo_home_extref", $filter) && strlen($filter['rimo_home_extref']) && intval($filter['rimo_home_extref']) === 0) ? "selected='selected'" : ""?>>Fehlt</option>
<option value="1" <?=(isset($filter) && array_key_exists("rimo_home_extref", $filter) && intval($filter['rimo_home_extref']) === 1) ? "selected='selected'" : ""?>>Vorhanden</option>
</select>
</div>
<div class="col-sm-12 col-md-1">
<label class="form-label" for="filter_connection_count">Anz. Anschlüsse</label>
<select name="filter[connection_count]" id="filter_connection_count" class="form-control">
<option value=""></option>
<option value="1" <?=(isset($filter) && array_key_exists("connection_count", $filter) && intval($filter['connection_count']) === 1) ? "selected='selected'" : ""?>>1</option>
<option value="2" <?=(isset($filter) && array_key_exists("connection_count", $filter) && intval($filter['connection_count']) === 2) ? "selected='selected'" : ""?>> &gt; 1</option>
</select>
</div>
<div class="col-sm-12 col-md-1">
<label class="form-label" for="filter_borderpoint">Übergabepunkt</label>
<select name="filter[borderpoint]" id="filter_borderpoint" class="form-control">
<option value="all" <?=(isset($filter) && array_key_exists("borderpoint", $filter) && $filter["borderpoint"] == "all") ? "selected='selected'" : ""?>>Alle</option>
<option value="with" <?=(isset($filter) && array_key_exists("borderpoint", $filter) && $filter["borderpoint"] == "with") ? "selected='selected'" : ""?>>Mit</option>
<option value="without" <?=(isset($filter) && array_key_exists("borderpoint", $filter) && $filter["borderpoint"] == "without") ? "selected='selected'" : ""?>>Ohne</option>
</select>
</div>
<div class="col-sm-12 col-md-1">
<label class="form-label" for="filter_rimo_workorder">Rimo Workorder</label>
<select name="filter[rimo_workorder]" id="filter_rimo_workorder" class="form-control">
<option value=""></option>
<option value="0" <?=(isset($filter) && array_key_exists("rimo_workorder", $filter) && strlen($filter['rimo_workorder']) && intval($filter['rimo_workorder']) === 0) ? "selected='selected'" : ""?>>Nicht erstellt</option>
<option value="1" <?=(isset($filter) && array_key_exists("rimo_workorder", $filter) && intval($filter['rimo_workorder']) === 1) ? "selected='selected'" : ""?>>Erstellt</option>
</select>
</div>
<div class="col-sm-12 col-md-1">
<label class="form-label" for="filter_rimo_workorder">Workorder Status</label>
<select name="filter[rimo_workorder_status][]" id="filter_rimo_workorder_status" multiple class="form-control">
<option value="Clarify" <?=(isset($filter) && array_key_exists("rimo_workorder_status", $filter) && is_array($filter['rimo_workorder_status']) && in_array("Clarify", $filter['rimo_workorder_status'])) ? "selected='selected'" : ""?>>Clarify</option>
<option value="Accepted" <?=(isset($filter) && array_key_exists("rimo_workorder_status", $filter) && is_array($filter['rimo_workorder_status'])&& in_array("Accepted", $filter['rimo_workorder_status'])) ? "selected='selected'" : ""?>>Accepted</option>
<option value="Plan released" <?=(isset($filter) && array_key_exists("rimo_workorder_status", $filter) && is_array($filter['rimo_workorder_status'])&& in_array("Plan released", $filter['rimo_workorder_status'])) ? "selected='selected'" : ""?>>Plan released</option>
<option value="Assigned" <?=(isset($filter) && array_key_exists("rimo_workorder_status", $filter) && is_array($filter['rimo_workorder_status'])&& in_array("Assigned", $filter['rimo_workorder_status'])) ? "selected='selected'" : ""?>>Assigned</option>
<option value="Executed" <?=(isset($filter) && array_key_exists("rimo_workorder_status", $filter) && is_array($filter['rimo_workorder_status'])&& in_array("Executed", $filter['rimo_workorder_status'])) ? "selected='selected'" : ""?>>Executed</option>
<option value="Documented" <?=(isset($filter) && array_key_exists("rimo_workorder_status", $filter) && is_array($filter['rimo_workorder_status'])&& in_array("Documented", $filter['rimo_workorder_status'])) ? "selected='selected'" : ""?>>Documented</option>
<option value="Review" <?=(isset($filter) && array_key_exists("rimo_workorder_status", $filter) && is_array($filter['rimo_workorder_status'])&& in_array("Review", $filter['rimo_workorder_status'])) ? "selected='selected'" : ""?>>Review</option>
<option value="Canceled" <?=(isset($filter) && array_key_exists("rimo_workorder_status", $filter) && is_array($filter['rimo_workorder_status'])&& in_array("Canceled", $filter['rimo_workorder_status'])) ? "selected='selected'" : ""?>>Canceled</option>
</select>
</div>
<div class="col-sm-12 col-md-1">
<label class="form-label" for="filter_fcp">FCP</label>
<select name="filter[fcp][]" id="filter_fcp" multiple class="form-control">
<option value="">Kein FCP gefunden</option>
</select>
</div>
<div class="col-sm-12 col-md-2">
<label class="form-label" for="filter_rimo_workorder_team_id">Rimo Workorder Assigned Team</label>
<select name="filter[rimo_workorder_team_id]" id="filter_rimo_workorder_team_id" class="form-control">
<option value=""></option>
<?php foreach(RimoWorkorderModel::getTeams() as $id => $team): ?>
<option value="<?=$id?>" <?=(isset($filter) && array_key_exists("rimo_workorder_team_id", $filter) && $filter["rimo_workorder_team_id"] == $id) ? "selected='selected'" : ""?>><?=$team?></option>
<?php endforeach; ?>
</select>
</div>
<div class="col-sm-12 col-md-2">
<label class="form-label" for="filter_preorder_status_flags">Statusflag</label>
<select name="filter[preorder_status_flags][]" id="filter_preorder_status_flags" multiple class="form-control">
<?php foreach(PreorderStatusflagModel::getAll() as $flag): ?>
<option value="<?=$flag->id?>" <?=(isset($filter) && array_key_exists("preorder_status_flags", $filter) && is_array($filter['preorder_status_flags']) && in_array($flag->id, $filter['preorder_status_flags'])) ? "selected='selected'" : ""?>><?=$flag->name?></option>
<?php endforeach; ?>
</select>
</div>
</div>
<div class="row mt-2">
<div class="col-sm-12 col-md-2">
<label class="form-label" for="datum_von">Datum von</label>
<div class="input-group date" data-provide="datepicker" data-date-format="dd.mm.yyyy" data-date-language="de">
<input type="text" class="form-control" id="datum_von" name="filter[create_from]" value="<?=$filter['create_from'] ?? ""?>">
<div class="input-group-append">
<span class="input-group-text"><i class="fa fa-calendar"></i></span>
</div>
</div>
</div>
<div class="col-sm-12 col-md-2">
<label class="form-label" for="datum_bis">Datum bis</label>
<div class="input-group date" data-provide="datepicker" data-date-format="dd.mm.yyyy" data-date-language="de">
<input type="text" class="form-control" id="datum_bis" name="filter[create_to]" value="<?=$filter['create_to'] ?? ""?>">
<div class="input-group-append">
<span class="input-group-text"><i class="fa fa-calendar"></i></span>
</div>
</div>
</div>
<?php if ($me->isAdmin() || $me->address->id == 209): ?>
<div class="col-sm-12 col-md-2">
<label class="form-label" for="billed">Verrechnet</label>
<select name="filter[billed]" id="filter_billed" class="form-control">
<option value=""></option>
<option value="1" <?=(isset($filter) && array_key_exists("billed", $filter) && strlen($filter['billed']) && intval($filter['billed']) === 1) ? "selected='selected'" : ""?>>Ja</option>
<option value="0" <?=(isset($filter) && array_key_exists("billed", $filter) && strlen($filter['billed']) && intval($filter['billed']) === 0) ? "selected='selected'" : ""?>>Nein</option> </select>
</div>
<div class="col-sm-12 col-md-1">
<label class="form-label" for="attributes_bep_specified">BP festgelegt</label>
<select name="filter[attributes_bep_specified]" id="filter_attributes_bep_specified" class="form-control">
<option value=""></option>
<option value="1" <?=(isset($filter) && array_key_exists("attributes_bep_specified", $filter) && $filter['attributes_bep_specified'] == "1") ? "selected='selected'" : ""?>>Ja</option>
<option value="0" <?=(isset($filter) && array_key_exists("attributes_bep_specified", $filter) && $filter['attributes_bep_specified'] == "0") ? "selected='selected'" : ""?>>Nein</option>
</select>
</div>
<?php endif; ?>
<div class="col-sm-12 col-md-1">
<label class="form-label" for="filter_tool_building_type">Gebäude Typ</label>
<select name="filter[tool_building_type]" id="filter_tool_building_type" class="form-control">
<option value="">Alle</option>
<option value="0" <?=(isset($filter) && array_key_exists("tool_building_type", $filter) && $filter['tool_building_type'] === "0") ? "selected='selected'" : ""?>>Unbekannt</option>
<option value="1" <?=(isset($filter) && array_key_exists("tool_building_type", $filter) && $filter['tool_building_type'] == "1") ? "selected='selected'" : ""?>>EFH</option>
<option value="2" <?=(isset($filter) && array_key_exists("tool_building_type", $filter) && $filter['tool_building_type'] == "2") ? "selected='selected'" : ""?>>MPH</option>
</select>
</div>
</div>
<div class="row mt-2">
<div class="col preorder-campaign-header-buttons">
<button type="submit" class="btn btn-primary">Filter anwenden</button>
<?php if(isset($campaign) && $campaign->id): ?>
<a class="btn btn-secondary" href="<?=self::getUrl("Preorder", "", ['filter' => ['preordercampaign_id' => $campaign->id], "resetFilter" => 1])?>">Filter zurücksetzen</a>
<?php else: ?>
<a class="btn btn-secondary" href="<?=self::getUrl("Preorder", "Index", ["resetFilter" => 1])?>">Filter zurücksetzen</a>
<?php endif; ?>
<?php if(!$me->is("Preorderfront")): ?>
<button type="submit" formaction="<?=self::getUrl("Preorder", "export")?>" id="export-button" class="btn btn-outline-success"><i class="fas fa-download"></i> CSV-Export</button>
<?php endif; ?>
<?php if ($me->isAdmin() || $me->address->id == 209): ?>
<a href="<?=self::getUrl("Preorder", "custom300")?>" class="btn btn-outline-info"><i class="fas fa-envelope"></i> Custom-300 Benachrichtigungen</a>
<?php endif; ?>
<div class="dropdown">
<button class="btn btn-outline-primary dropdown-toggle" type="button" id="dropdownMenuButton" data-bs-toggle="dropdown" aria-expanded="false">
Filter-Vorlagen <i class="fas fa-caret-down"></i>
</button>
<ul class="dropdown-menu" aria-labelledby="dropdownMenuButton">
<li><a class="dropdown-item" href="<?=self::getUrl("Preorder", "Index", ["filter" => ["status" => [21,22,23,24,25], "rimo_workorder" => 1, "borderpoint" => "all"]])?>">Gelöschte Bestellungen mit Workorder</a></li>
<li><a class="dropdown-item" href="<?=self::getUrl("Preorder", "Index", ["filter" => ["preorder_status_flags" => [4], "connection_type" => ["apartment", "apartment-building"], "borderpoint" => "all"]])?>">Wohnung - Verkabelung erledigt</a></li>
<li><a class="dropdown-item" href="<?=self::getUrl("Preorder", "Index", ["filter" => ["status" => [21,22,23,24,25]]])?>">Storniert</a></li>
<?php if ($me->isAdmin() || $me->address->id == 209): ?>
<li><a class="dropdown-item" href="<?=self::getUrl("Preorder", "Index", ["filter" => ["onlyShowCustomMailSent" => 1]])?>">Bestellungen mit gesendeter Custom-300 Benachrichtigung</a></li>
<input type="hidden" name="filter[onlyShowCustomMailSent]" value="<?= (isset($filter['onlyShowCustomMailSent']) && $filter['onlyShowCustomMailSent'] == 1) ? 1 : 0 ?>"/>
<?php endif; ?>
</ul>
</div>
<a id="rimo-types-link" target="_blank" style="display:none" href="#" class="btn btn-outline-success"><i class="fas fa-map-marked-alt"></i>Rimo-Typen Karte anzeigen</a>
</div>
</div>
</form>
</div>
</div>
<div class="card">
<div class="card-body">
<div class="row col" id="map-link">
<a href="#" class="btn btn-success" onclick="refreshMap()"><i class="far fa-map"></i> Übersichtskarte einblenden</a>
</div>
<div class="row hidden" id="map-row">
<div id="preorder-map" style="height:70vh; width: 100%"></div>
<div class="row mt-1">
<div class="col">
<button type="button" class="btn btn-sm btn-outline-secondary" onclick="centerMap()"><i class="far fa-dot-circle fa-fw"></i> Zentrieren</button>
<button type="button" class="btn btn-sm btn-outline-success" onclick="toggleTileset()" title="Zwischen Karte und Satellitenbild umschalten"><i class="far fa-arrow-right-arrow-left fa-fw"></i> Karte/Satellit</button>
</div>
</div>
</div>
</div>
</div>
<div class="card">
<div class="card-body mb-3">
<div class="preorder-campaign-header">
<h4 class="header-title">Liste aller Vorbestellungen<?= (isset($campaign) && $campaign) ? " - " . $campaign->name : "" ?></h4>
<?php if (isset($filter['preordercampaign_id'])): ?>
<div class="float-right">
<a class="btn btn-primary mb-2"
href="<?= self::getUrl("Preorder", "add", ["preordercampaign_id" => $filter['preordercampaign_id']]) ?>"><i
class="fas fa-plus"></i> Neue Vorbestellung anlegen</a>
</div>
<?php endif; ?>
</div>
<?php include(realpath(dirname(__FILE__)."/../")."/tpl/pagination.php"); ?>
<?php include(realpath(dirname(__FILE__)."/../")."/tpl/pagination-summary.php"); ?>
<div class="preorder-campaign-table-wrapper">
<table class="table table-striped table-hover">
<tr>
<?php if(!$me->is(["preorderfront"]) && !$me->is("preorderreadonly")): ?>
<th></th>
<?php endif; ?>
<?php if(!$me->is("preorderfront")): ?><th>Kampagne</th><?php endif; ?>
<th>Bestelltyp<br />Bestellcode</th>
<th>Status</th>
<th>Anschlussadresse</th>
<th>Anschlüsse<br />OAID</th>
<th>Kunde</th>
<th>Kontakt</th>
<th>Partner</th>
<th>Attribute</th>
<th>Erstellt<br />Bearbeitet</th>
<th></th>
<th></th>
</tr>
<?php foreach($preorders as $preorder):
$hasStatus245 = false;
foreach (PreorderstatusModel::getAll() as $status) {
if ($preorder->status_id == $status->id && $status->code == 245) {
$hasStatus245 = true;
break;
}
}
$requiredFlagIds = [1, 3, 4, 5];
$allFlagsChecked = true;
foreach ($requiredFlagIds as $flagId) {
if (!array_key_exists($flagId, $preorder->statusflags) ||
!$preorder->statusflags[$flagId]->value ||
!$preorder->statusflags[$flagId]->value->value) {
$allFlagsChecked = false;
break;
}
}
$doHighlight = $hasStatus245 && $allFlagsChecked;
?>
<tr class="preorder-list-tr <?=($doHighlight) ? " tr-highlight" : ""?>" id="preorder-<?=$preorder->id?>">
<?php if(!$me->is(["preorderfront"]) && !$me->is("preorderreadonly")): ?>
<td class="bg-lightblue border border-end text-center pointer" onclick="togglePreorder(<?=$preorder->id?>); return false;">
<i class="fas fa-fw fa-angle-down"></i>
</td>
<?php endif; ?>
<?php if(!$me->is("preorderfront")): ?>
<td>
<?=$preorder->campaign->name?>
<?php if($preorder->cancel_request && !$preorder->cancel_approved): ?>
<br /><button class="btn btn-sm btn-outline-danger mt-1 cancel-approval-button" onclick="openCancelApproval(<?=$preorder->id?>)"><i class="fas fa-fw fa-eyes text-primary"></i> Kündigungsanfrage<?=($preorder->cancel_request_status_code) ? " (".$preorder->cancel_request_status_code.")" : ""?></button>
<?php endif; ?>
</td>
<?php endif; ?>
<td>
<?=__($preorder->type, "preorder")?><br />
<?=$preorder->ucode?>
</td>
<td class="status">
<?=$preorder->status->code?> - <?=$preorder->status->name?>
<?php foreach(PreorderStatusflagModel::search(['ids' => [3,4]]) as $flag): ?>
<br><input type="checkbox" class="preorder-statusflag-main"
id="preorder-<?=$preorder->id?>-statusflag-<?=$flag->id?>"
data-preorder_id="<?=$preorder->id?>"
data-flag_id="<?=$flag->id?>"
data-flag_code="<?=$flag->code?>"
<?=(array_key_exists($flag->id, $preorder->statusflags) && $preorder->statusflags[$flag->id]->value && $preorder->statusflags[$flag->id]->value->value) ? "checked='checked'" : ""?>
/>
<label class="m-0" style="font-weight: unset!important;" for="preorder-<?=$preorder->id?>-statusflag-<?=$flag->id?>" id="preorder-<?=$preorder->id?>-statusflag-<?=$flag->id?>-text" class="text-nowrap">
<?=$preorder->statusflags[$flag->id]->name?>
</label>
<?php endforeach; ?>
</td>
<?php if($preorder->building_id): ?>
<td><?=$preorder->building->street?><br /><?=$preorder->building->zip?> <?=$preorder->building->city?></td>
<?php elseif($preorder->adb_hausnummer_id): ?>
<td <?=($preorder->address_created) ? "class='alert-warning' title='Adresse manuell angelegt'" : ""?>">
<?=$preorder->adb_hausnummer->strasse->name?>
<?=$preorder->adb_hausnummer->hausnummer?><?=($preorder->adb_hausnummer->stiege) ? "/".$preorder->adb_hausnummer->stiege : ""?><br />
<?=($preorder->adb_wohneinheit_id) ? ((string)$preorder->adb_wohneinheit ? $preorder->adb_wohneinheit."<br />" : "") : "<i class='text-pink'>&lt;keine Wohneinheit&gt;</i><br />"?>
<?=$preorder->adb_hausnummer->plz->plz?>
<?=$preorder->adb_hausnummer->ortschaft->name?><br />
<?=$preorder->adb_hausnummer->strasse->gemeinde->name?>
</td>
<?php else: ?>
<td></td>
<?php endif; ?>
<td>
<?=($preorder->connection_count) ? $preorder->connection_count : 1?><br />
<span class="text-pink"><?=$preorder->oaid?></span>
</td>
<td>
<?=($preorder->company) ? $preorder->company."<br />" : ""?>
<?=($preorder->firstname || $preorder->lastname ) ? $preorder->firstname." ".$preorder->lastname."<br />" : ""?>
<?=$preorder->street?><?=($preorder->housenumber) ? " ".$preorder->housenumber : ""?>
<?=($preorder->block) ? "Block ".$preorder->block : ""?>
<?=($preorder->stiege) ? "Stiege ".$preorder->stiege : ""?>
<?=($preorder->stock) ? "Stock ".$preorder->stock : ""?>
<?=($preorder->tuer) ? "Tür ".$preorder->tuer : ""?>
<br />
<?=$preorder->zip?> <?=$preorder->city?>
</td>
<td>
<?=($preorder->phone) ? $preorder->phone."<br />" : ""?>
<?=($preorder->email) ? $preorder->email : ""?>
</td>
<td><?=($preorder->partner_id) ? $preorder->partner->getCompanyOrName() : ""?></td>
<td>
<label class="m-0" style="font-weight: unset!important;"><input type="checkbox" name="attributes_bep_specified" id="attributes_bep_specified-<?=$preorder->id?>" data-preorder-id="<?=$preorder->id?>" value="1" <?=(is_array($preorder->attribute) && array_key_exists("bep_specified", $preorder->attribute) && $preorder->attribute["bep_specified"]) ? "checked='checked'" : ""?> /> Borderpoint festgelegt</label><br />
<label class="m-0" style="font-weight: unset!important;"><input type="checkbox" name="attributes_inhouse_cabling_supplied" id="attributes_inhouse_cabling_supplied-<?=$preorder->id?>" data-preorder-id="<?=$preorder->id?>" value="1" <?=(is_array($preorder->attribute) && array_key_exists("inhouse_cabling_supplied", $preorder->attribute) && $preorder->attribute["inhouse_cabling_supplied"]) ? "checked='checked'" : ""?> /> Starterpaket erhalten</label>
</td>
<td style="white-space: nowrap" class="text-monospace">
<?=date('d.m.Y H:i', $preorder->create)?><br />
<span id="update-<?=$preorder->id?>"><?=date('d.m.Y H:i', $preorder->edit)?></span>
</td>
<td class="text-nowrap">
<?php if(0): ?>
<?php if(!$me->address->hasPreorderBilling()): ?>
<?php if($preorder->adb_wohneinheit_id && $preorder->adb_wohneinheit->enduser_setup_invoice_date): ?>
<i class="fas fa-euro is-billed-button" title="Herstellungsentgelt verrechnet am <?=(new DateTime($preorder->adb_wohneinheit->enduser_setup_invoice_date))->format("d.m.Y")?>"></i>
<?php else: ?>
<a href="#" class="text-muted" onclick="setBilled(<?=$preorder->id?>)"><i class="fas fa-euro set-billed-button" title="Herstellungsentgelt als verrechnet markieren"></i></a>
<?php endif; ?>
<?php endif; ?>
<?php endif; ?>
<?php if($preorder->adb_wohneinheit_id && is_array($preorder->adb_wohneinheit->rimo_workorders) && count($preorder->adb_wohneinheit->rimo_workorders)):?>
<i class="fas fa-r p-1" title="Rimo Workorder erstellt"></i>
<?php endif; ?>
</td>
<td style="text-align: left; letter-spacing: 4px; font-size: 1.1em;">
<div class="preorder-campaign-table-actions">
<?php if(!$me->is(["preorderfront"]) && !$me->is("preorderreadonly")): ?>
<?php
$contacts = ($preorder->adb_wohneinheit_id && $preorder->adb_wohneinheit && $preorder->adb_wohneinheit->contact) ? json_decode($preorder->adb_wohneinheit->contact, true) : [];
$contactCount = is_array($contacts) ? count($contacts) : 0;
?>
<a href="#" data-home-id="<?=$preorder->adb_wohneinheit_id?>" data-home-contact title="Kontakte bearbeiten<?=$contactCount ? ' (' . $contactCount . ')' : ''?>" style="position: relative; display: inline-block;">
<i class="fas fa-users-cog <?=$contactCount ? 'text-success' : 'text-muted'?>"></i>
<?php if($contactCount): ?>
<span style="position: absolute; top: -8px; right: -8px; background: #28a745; color: white; border-radius: 50%; width: 16px; height: 16px; font-size: 10px; display: flex; align-items: center; justify-content: center; font-weight: bold; padding: 0; box-sizing: border-box;"><?=$contactCount?></span>
<?php endif; ?>
</a>
<a href="<?=self::getUrl("Preorder", "edit", ["id" => $preorder->id])?>"><i class="far fa-edit" title="Vorbestellung Bearbeiten"></i></a>
<?php endif; ?>
<?php if($me->isAdmin()): ?>
<a href="<?=self::getUrl("Preorder", "delete", ["id" => $preorder->id, "filter" => $filter])?>" class="text-danger" onclick="if(!confirm('Vorbestellung wirklich löschen?')) return false;" title="Vorbestellung Löschen"><i class="fas fa-trash"></i></a>
<?php endif; ?>
</div>
</td>
</tr>
<?php if(!$me->is(["preorderfront"]) && !$me->is("preorderreadonly")): ?>
<tr id="preorder-detail-<?=$preorder->id?>" style="display:none; background-color:#fff">
<td colspan="13">
<?php include(realpath(dirname(__FILE__))."/include/preorder-detail.php"); ?>
</td>
</tr>
<tr style="display:none;"></tr>
<?php endif; ?>
<?php endforeach; ?>
</table>
</div>
<?php include(realpath(dirname(__FILE__)."/../")."/tpl/pagination-summary.php"); ?>
<?php include(realpath(dirname(__FILE__)."/../")."/tpl/pagination.php"); ?>
</div>
</div>
</div>
</div>
<div class="modal" tabindex="-1" id="email-log-modal" style="max-height: 100vh;">
<div class="modal-dialog modal-dialog-centered modal-xl">
<div class="modal-content" style="overflow: auto;">
<div class="modal-header">
<h5 class="modal-title">Emailansicht</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div class="row">
<div class="col">
<table class="table">
<tr>
<th>Von:</th>
<td id="email-log-from-value" class="text-monospace"></td>
</tr><tr>
<th>An:</th>
<td id="email-log-to-value" class="text-monospace"></td>
</tr><tr>
<th>Gesendet:</th>
<td id="email-log-sent-value" class="text-monospace"></td>
</tr><tr>
<th>Betreff:</th>
<td id="email-log-subject-value" class="text-monospace"></td>
</tr>
</table>
</div>
</div>
<div class="row mb-3" id="email-log-header-section">
<div class="col">
<a href="#" onclick="displayEmailLogHeaders(); return false;"><i class="fas fa-chevron-right fa-fw"></i> Alle Header anzeigen</a>
<div id="email-log-header-view" class="mt-2 text-monospace hidden" style="min-height: 48px; width:100%; border: 1px solid #ccc; padding: 8px; font-family: sans-serif;"></div>
</div>
</div>
<div class="row mb-2" id="email-log-body-section">
<div class="col">
<iframe id="email-log-body-view" style="height: 50vh; width:100%; border: 1px solid #000; padding: 8px; font-family: sans-serif; overflow-y: auto;"></iframe>
</div>
</div>
<div class="row mb-3 hidden" id="email-log-attachments-section">
<div class="col">
<h5>Dateianhänge</h5>
<ul id="email-log-attachment-list" class="list-group"></ul>
</div>
</div>
</div>
</div>
</div>
</div>
<script type="text/javascript">
$(document).ready(function() {
$(".datepicker").datepicker({
//orientation: "bottom",
language: 'de',
format: "dd.mm.yyyy",
showWeekDays: true,
todayBtn: 'linked',
autoclose: true
});
$("#filter_preordercampaign_id").select2({closeOnSelect: false});
$("#filter_type").select2({closeOnSelect: false});
$("#filter_status").select2({closeOnSelect: false});
$("#filter_partner_id").select2({closeOnSelect: false});
$("#connection_type_id").select2({closeOnSelect: false});
$("#filter_rimo_workorder_status").select2({closeOnSelect: false});
$("#filter_preorder_status_flags").select2({closeOnSelect: false});
var attributes = ["bep_specified", "inhouse_cabling_supplied"];
$(document).ready(function() {
// Toggle dropdown on button click
$('.dropdown-toggle').on('click', function(e) {
e.preventDefault();
$(this).siblings('.dropdown-menu').toggleClass('show');
});
// Close dropdown when clicking outside
$(document).on('click', function(e) {
if (!$(e.target).closest('.dropdown').length) {
$('.dropdown-menu').removeClass('show');
}
});
});
attributes.forEach(function(attrib) {
$("input[name=attributes_" + attrib + "]").change(function(ev) {
// save new value
var cb = $("#" + ev.currentTarget.id);
var value = $(cb).is(":checked") ? 1 : 0;
var preorder_id = $(cb).data("preorder-id");
$.post("<?=self::getUrl("Preorder", "Api")?>", {
do: "saveAttribute",
id: preorder_id,
attribute: attrib,
value: value
},
function(success) {
if(success.status == "OK") {
attributeSuccess(success.result);
} else {
attributeError(success.result.id, success.result.attribute);
}
},
"json"
);
// if attribute is inhouse_cabling_supplied and is checked or unchecked send an api request
// api
// do: setStatusFlag, preorder_id, flag_id: 1, value (0 or 1)
if (attrib == "inhouse_cabling_supplied") {
const code = 145;
$.post("<?=self::getUrl("Preorder", "Api")?>", {
do: "setStatusFlag",
preorder_id: preorder_id,
code: 145,
value: value
},
function(success) {
if(success.status == "OK") {
attributeSuccess(success.result);
} else {
attributeError(success.result.id, success.result.attribute);
}
},
"json"
);
}
});
});
});
function setBilled(pid) {
if(!pid) return;
$.post("<?=self::getUrl("Preorder", "Api")?>", {
do: "setBilled",
id: pid
},
function(success) {
if(success.status == "OK") {
$("#preorder-" + pid + " .set-billed-button").parent().html("<i class='fas fa-euro is-billed-button' title='Herstellungsentgelt verrechnet am " + success.result.date + "'></i>");
}
},
"json"
);
}
function attributeSuccess(result) {
var id = result.id
var attribute = result.attribute
var update = result.update
$("#attributes_" + attribute + "-" + id).parent().removeClass("text-danger");
$("#attributes_" + attribute + "-" + id).parent().addClass("text-success");
if(update) {
$("#update-" + id).text(update);
$("#update-" + id).addClass("text-success")
}
setTimeout(function() {
$("#attributes_" + attribute + "-" + id).parent().removeClass("text-success");
$("#update-" + id).removeClass("text-success")
}, 2000, id, attribute);
}
function attributeError(id, attribute) {
$("#attributes_" + attribute + "-" + id).parent().addClass("text-danger");
$("#attributes_" + attribute + "-" + id).prop("checked", !$("#attributes_" + attribute + "-" + id).is(":checked"));
}
async function submitStatusJournal(pid) {
var text = $("#preorder-" + pid + "-status-journal-input").val();
if(!text) return;
// disable elements
$("#preorder-" + pid + "-status-journal-input").attr("disabled", "disabled");
$("#preorder-" + pid + "-status-journal button").attr("disabled", "disabled");
// save text
await fetch("<?=self::getUrl("Preorder", "Api")?>", {
method: "POST",
headers: {
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'
},
body: new URLSearchParams({
do: "saveStatusJournal",
preorder_id: pid,
text: text
})
}).then(resp => {
if(resp.ok) {
return resp.json();
}
}).then((data) => {
// enable items
$("#preorder-" + pid + "-status-journal-input").attr("disabled", false);
$("#preorder-" + pid + "-status-journal button").attr("disabled", false);
if(data.status == "OK") {
$("#preorder-" + pid + "-status-journal-input").val("");
// get returned data
var new_text = data.result.text;
var creator = data.result.creator;
var create_date = new Date(data.result.create);
var date_ts = create_date.getTime();
var date_string = create_date.toLocaleString("de-DE", {year: "numeric", month: "2-digit", day: "2-digit"}) + " " + String(create_date.getHours()).padStart(2, 0) + ":" + String(create_date.getMinutes()).padStart(2, 0);
// add new journal item
$("#preorder-" + pid + "-status-journal-list").prepend('<tr id="preorder-' + pid + '-status-journal-list-' + date_ts + '"><td class="text-monospace"><small style="white-space: nowrap"><i class="fas fa-clock fa-fw"></i> ' + date_string + '</small> <span style="white-space: nowrap">(' + creator + ')<span></span></td> <td class="text-left">' + new_text + '</td></tr>');
// visual effects
$('#preorder-' + pid + '-status-journal-list-' + date_ts).addClass("text-success").fadeOut(10).fadeIn(400);
setTimeout(() => {$('#preorder-' + pid + '-status-journal-list-' + date_ts).removeClass("text-success")}, 300)
window.notify("success", "Journaleintrag erfolgreich gespeichert.");
} else {
window.notify("error", "Fehler beim Speichern des Journaleintrags");
}
});
return true;
}
/*
* Globals for map display
*/
var borderpoly = [];
<?php if(isset($campaign) && $campaign && $campaign->adb_netzgebiet): ?>
borderpoly = <?=($campaign->adb_netzgebiet->borderpoly) ? $campaign->adb_netzgebiet->borderpoly : "[]"?>;
<?php elseif($me->is("Admin")): ?>
borderpoly = [];
<?php foreach(ADBNetzgebietModel::search(["borderpoly" => true]) as $bp_netz): ?>
borderpoly.push(<?=$bp_netz->borderpoly?>);
<?php endforeach; ?>
<?php endif; ?>
var preorderMap;
var preorders = [];
var fttxlocations = [];
var markers = [];
var markerState = true;
var mapCenterPos = [<?=TT_PLACEHOLDER_GPS_LAT?>, <?=TT_PLACEHOLDER_GPS_LONG?>];
var tileLayers = {};
var tilesets = {
"geolandbasemap": {name: "geolandbasemap", imgtype: "png"},
"bmaporthofoto30cm": {name: "bmaporthofoto30cm", imgtype: "jpeg"}
};
var currentTileset = "geolandbasemap";
function toggleTileset() {
if(currentTileset == "geolandbasemap") {
currentTileset = "bmaporthofoto30cm";
} else {
currentTileset = "geolandbasemap";
}
renderMap(true);
}
function refreshMap() {
// get Preorders and render map
$('#map-link').hide();
$('#map-row').show();
getMapdata();
$([document.documentElement, document.body]).animate({
scrollTop: $("#preorder-map").offset().top - 150
}, 500);
}
function renderMap(tilesetChangeOnly = false) {
if(preorderMap) {
if(!tilesetChangeOnly) {
markers.forEach(function(m) {
preorderMap.removeLayer(m);
});
}
} else {
preorderMap = L.map('preorder-map', {fullscreenControl: true, centerControl: true, switchviewControl: true}).setView([<?=TT_PLACEHOLDER_GPS_LAT?>, <?=TT_PLACEHOLDER_GPS_LONG?>], 12);
}
if(!(currentTileset in tileLayers)) {
tileLayers[currentTileset] = L.tileLayer('https://mapsneu.wien.gv.at/basemap/{id}/normal/google3857/{z}/{y}/{x}.{imgtype}', {
attribution: '&copy; <a href="https://basemap.at">Basemap.at</a>',
minZoom: 6,
maxZoom: 19,
id: tilesets[currentTileset].name,
imgtype: tilesets[currentTileset].imgtype
});
}
tileLayers[currentTileset].addTo(preorderMap);
for(const [name, t] of Object.entries(tilesets)) {
if(name != currentTileset && preorderMap.hasLayer(tileLayers[name])) {
preorderMap.removeLayer(tileLayers[name]);
}
}
L.MakiMarkers.accessToken = '<?=TT_MAPBOX_TILE_API_TOKEN?>';
if(!tilesetChangeOnly) {
addMarkers();
}
}
function addMarkers() {
if(borderpoly) {
var border = L.polygon(borderpoly, {
fillColor: 'blue',
weight: 8,
opacity: 0.5,
color: 'violet', //Outline color
fillOpacity: 0.05
}).addTo(preorderMap);
}
if(!Array.isArray(preorders) | !preorders.length) {
return false;
}
// draw markers and calculate center position
var all_coords = [];
preorders.forEach(function(preorder) {
if(!preorder.gps_lat || !preorder.gps_long) {
return;
}
var gps = [preorder.gps_lat, preorder.gps_long];
all_coords.push(gps);
var icon_color = "#acf0ab";
var icon_name = "home";
if(preorder.type == "interest") {
icon_color = "#ec98a2";
} else if(preorder.type == "provision") {
icon_color = "#ffcd8b";
}
if(preorder.connection_type.match(/^multi/i) || preorder.count > 1) {
icon_name = "town";
} else if(preorder.connection_type.match(/^apartment-building/i)) {
icon_name = "city";
} else if(preorder.connection_type.match(/^business/i)) {
icon_name = "industry";
}
var marker_popup_content = `<?php include(realpath(dirname(__FILE__))."/include/preorder_popup.php");?>`;
// popup fields
const preorder_view_url = `<?=self::getUrl("Preorder")?>/Index?filter[ucode]=${preorder.ucode}#preorder=${preorder.id}`;
[
["PREORDER_URL", preorder_view_url],
["street", preorder.adb_strasse],
["hausnummer", preorder.adb_hausnummer],
["zip", preorder.adb_plz],
["city", preorder.adb_ort],
["type", preorder.type_label],
["typestyle", "color: #000; background-color: " + icon_color],
["adrcd", preorder.adrcd],
["extref", preorder.extref ? preorder.extref : ""],
["gps", (preorder.gps_lat && preorder.gps_long) ? preorder.gps_lat + ", " + preorder.gps_long : ""],
["contact", (preorder.company ? preorder.company + " " : preorder.firstname + " " + preorder.lastname)],
["phone", preorder.phone ? preorder.phone : ""],
["email", preorder.email ? preorder.email : ""],
["connectiontype", preorder.connection_type_label],
["count", preorder.connection_count]
].forEach(function(item) {
marker_popup_content = marker_popup_content.replaceAll("{{" + item[0].toUpperCase() + "}}", item[1]);
});
var icon = L.MakiMarkers.icon({icon: icon_name, color: icon_color, size: "l"});
var marker = L.marker(gps, {icon: icon}).addTo(preorderMap).bindPopup(marker_popup_content);
markers[preorder.id] = marker;
<?php if($me->is("Admin")): ?>
if(preorder.borderpoint_lat && preorder.borderpoint_long) {
var circle = L.circle([preorder.borderpoint_lat,preorder.borderpoint_long], {
color: 'orange',
fillColor: 'aqua',
fillOpacity: 0.8,
radius: 1
}).bindTooltip(preorder.borderpoint_lat + ", " + preorder.borderpoint_long).addTo(preorderMap);
}
/*if(preorder.trenches) {
preorder.trenches.forEach((trench) => {
var trench_line = L.polyline(trench, {
color: "limegreen"
}).addTo(preorderMap);
});
}*/
if(preorder.home_trench) {
var home_line = L.polyline(preorder.home_trench, {
color: "aqua"
}).addTo(preorderMap);
}
<?php endif; ?>
});
//fetch fcps and show on map
getFCPs(preorderMap);
addFttxLocations(preorderMap);
// calculate center position
mapCenterPos = GetCenterFromDegrees(all_coords);
preorderMap.setView(mapCenterPos, 12);
return true;
}
async function getFCPs(map) {
const fcpResponse = await $.get("<?=self::getUrl("Preorder", "Api")?>", {
do: "getFCPsForCampaign",
campaign_id: "<?=$campaign->id?>"
});
if (fcpResponse.status !== "OK" || !fcpResponse.result?.length) return;
const fcpIds = fcpResponse.result.map(fcp => fcp.real_id);
const statsResponse = await $.ajax({
url: "<?=self::getUrl("Preorder", "Api")?>?do=getRimoFcpStats",
type: 'POST',
contentType: 'application/json', // 1. Set the content type to JSON
data: JSON.stringify({ fcp_ids: fcpIds }) // 2. Stringify the data object
});
const stats = statsResponse.status === "OK" ? statsResponse.result : [];
fcpResponse.result.forEach(fcp => {
const icon = L.MakiMarkers.icon({ icon: "viewpoint", color: "yellow", size: "m" });
const marker = L.marker([fcp.lat, fcp.lng], { icon }).addTo(map);
const fcpStat = stats.find(s => parseInt(s.fcp_id) === parseInt(fcp.real_id));
const googleMapsLink = `https://www.google.com/maps/search/?api=1&query=${fcp.lat},${fcp.lng}`;
const statsHtml = !fcpStat ? `<p>Keine Statistiken gefunden.</p>` : `
<div style="margin-bottom: 15px;">
<strong style="display: block; margin-bottom: 5px; color: #555;">Zusammenfassung:</strong>
<span>Buildings: <b>${fcpStat.total_hausnummer_count}</b></span><br>
<span>Homes: <b>${fcpStat.total_wohneinheit_count}</b></span><br>
<span>Bestellungen: <b>${fcpStat.total_active_preorders}</b></span>
</div>
<strong style="display: block; margin-bottom: 5px; color: #555;">Details nach RIMO-Typ:</strong>
<table style="width: 100%; border-collapse: collapse; font-size: 12px;">
<thead>
<tr style="background-color: #f2f2f2; text-align: left;">
<th style="padding: 8px; border: 1px solid #ddd;">Typ</th>
<th style="padding: 8px; border: 1px solid #ddd;">BU</th>
<th style="padding: 8px; border: 1px solid #ddd;">WE</th>
<th style="padding: 8px; border: 1px solid #ddd;">BE</th>
</tr>
</thead>
<tbody>
${Object.entries(fcpStat.counts_by_rimo_type || {}).length ?
Object.entries(fcpStat.counts_by_rimo_type).map(([type, counts], index) => `
<tr style="${index % 2 === 0 ? 'background-color: #ffffff;' : 'background-color: #f9f9f9;'}">
<td style="padding: 8px; border: 1px solid #ddd;">${type}</td>
<td style="padding: 8px; border: 1px solid #ddd;">${counts.hausnummer_count}</td>
<td style="padding: 8px; border: 1px solid #ddd;">${counts.wohneinheit_count}</td>
<td style="padding: 8px; border: 1px solid #ddd;">${counts.preorder_count}</td>
</tr>
`).join('') :
'<tr><td colspan="4" style="padding: 8px; text-align: center; border: 1px solid #ddd;">Keine detaillierten Statistiken verfügbar.</td></tr>'
}
</tbody>
</table>
`;
const popupContent = `
<div style="font-family: Arial, sans-serif; width: 320px; padding: 5px;">
<h3 style="margin-bottom: 10px; color: #333; border-bottom: 1px solid #ddd; padding-bottom: 5px;">
${fcp.text}
</h3>
<a href='${googleMapsLink}' target='_blank' style="color: #007bff; text-decoration: none; margin-bottom: 15px; display: inline-block;">In Google Maps anzeigen</a>
${statsHtml}
</div>
`;
marker.bindPopup(popupContent);
});
}
function addFttxLocations(preorderMap) {
fttx_c = {
"gross planning": "grey",
"detailed planning": "yellow",
"plan released": "deeppink",
"assigend": "aqua",
"executed": "darkblue",
"documented": "lime",
"canceled": "darkred",
};
fttxlocations.forEach(loc => {
if(!loc.gps_lat || !loc.gps_long || !loc.ex_state) return;
var circle = L.circleMarker([loc.gps_lat, loc.gps_long], {
color: fttx_c[loc.ex_state.toLowerCase()],
fillColor: fttx_c[loc.ex_state.toLowerCase()],
fillOpacity: .8,
radius: 6
}).bindTooltip(loc.street + "<br />" + loc.zip + " " + loc.city + "<br /><br />Execution State: " + loc.ex_state).addTo(preorderMap);
})
}
function centerMap() {
preorderMap.setView(mapCenterPos, 12);
}
// gets preorders and calls renderMap()
function getMapdata() {
filter = getFilter();
$.post('<?=self::getUrl("Preorder", "Api")?>', {
'do': "getFilteredPreorders",
filter: filter,
},function(success) {
if(success.status == "OK") {
changes = false;
if(Array.isArray(success.result.preorders)) {
preorders = success.result.preorders;
changes = true;
}
if(Array.isArray(success.result.fttxlocations))
fttxlocations = success.result.fttxlocations;
changes = true;
}
if(changes) {
renderMap();
}
},
'json'
);
}
function getFilter() {
var fields = ['preordercampaign_id', 'status', 'type', 'address', 'kunde', 'address_source'];
var filter = {};
fields.forEach(function(field) {
if(!field) {
return;
}
if(!$('#filter_' + field).length) {
return;
}
let val = $('#filter_' + field).val();
if(val.length) {
filter[field] = val;
}
});
return filter;
}
<?php if(is_array($filter) && count($filter)): ?>
//refreshMap();
<?php endif; ?>
function togglePreorder(id) {
$('#preorder-detail-' + id).toggle();
if($('#preorder-detail-' + id).is(":hidden")) {
$('#preorder-' + id).removeClass("bg-lightblue");
$('#preorder-' + id).removeClass("text-info");
history.replaceState(null, null, ' ');
} else {
$('#preorder-' + id).addClass("text-info");
$('#preorder-' + id).addClass("bg-lightblue");
location.hash = "preorder=" + id;
return false;
}
}
$("input.preorder-statusflag, input.preorder-statusflag-main").change((e) => {
var elem = e.target;
var preorder_id = $(elem).data("preorder_id");
var flag_id = $(elem).data("flag_id");
var flag_code = $(elem).data("flag_code");
var value = $(elem).prop("checked") ? 1 : 0;
$.ajax({
url: "<?=self::getUrl("Preorder", "api")?>",
type: "POST",
data: {
do: "setStatusFlag",
preorder_id: preorder_id,
code: flag_code,
value: value
},
dataType: "json",
context: {
elem: elem,
preorder_id: preorder_id,
flag_id: flag_id,
flag_code: flag_code,
},
success: function (success) {
var textelem = $("#preorder-" + this.preorder_id + "-statusflag-" + this.flag_code + "-text");
if(success.status != "OK") {
notify("error","Fehler beim Speichern des Statusflags");
$(this.elem).prop("checked", !$(this.elem).prop("checked"));
} else {
textelem.removeClass("text-danger").addClass("text-success");
setTimeout(function() {
textelem.removeClass("text-success");
textelem.removeClass("text-success")
}, 2000, textelem);
}
// find all inputs with this data-preorder_id="21969" and data-flag_id="3" and set the text to the new value
// always with their own fields and then select / unselect the checkbox
$("input.preorder-statusflag[data-preorder_id='" + this.preorder_id + "'][data-flag_code='" + this.flag_code + "']").each(function() {
if(value) {
$(this).prop("checked", true);
} else {
$(this).prop("checked", false);
}
});
},
error: function () {
notify("error","Fehler beim Speichern des Statusflags");
$(this.elem).prop("checked", !$(this.elem).prop("checked"));
}
});
});
// navigation
var preorder_id;
var hash = window.location.hash.substr(1);
var match = hash.match(/preorder=(\d+)/);
if(match && match[1]) {
preorder_id = match[1]
togglePreorder(preorder_id);
$('html, body').animate( {scrollTop: $('#preorder-' + preorder_id).offset().top - 230}, 200);
}
/*
* Borderpoint map
*/
var maps = {};
function loadBorderpointMap(id) {
var lat = $("#preorder-detail-" + id + "-map").data("lat");
var long = $("#preorder-detail-" + id + "-map").data("long");
var blat = $("#preorder-detail-" + id + "-map").data("blat");
var blong = $("#preorder-detail-" + id + "-map").data("blong");
var trenches = $("#preorder-detail-" + id + "-map").data("trench");
var home_trench = $("#preorder-detail-" + id + "-map").data("home-trench");
if(!("map-" + id in maps)) {
var map = L.map('preorder-map-' + id).setView([lat, long], 19);
var tileLayer = L.tileLayer('https://mapsneu.wien.gv.at/basemap/{id}/normal/google3857/{z}/{y}/{x}.{imgtype}', {
attribution: '&copy; <a href="https://basemap.at">Basemap.at</a>',
minZoom: 12,
maxZoom: 19,
id: "bmaporthofoto30cm",
imgtype: "jpeg"
}).addTo(map);
var circle = L.circle([lat,long], {
color: 'orange',
fillColor: 'orange',
fillOpacity: 0.5,
radius: 1
}).bindTooltip(lat + ", " + long).addTo(map);
if(trenches) {
trenches.forEach((trench) => {
var trench_line = L.polyline(trench, {
color: "maroon",
weight: 7
}).addTo(map);
});
}
if(home_trench) {
var home_line = L.polyline(home_trench, {
color: "blue",
weight: 7
}).addTo(map);
}
maps["map-" + id] = map;
setTimeout((id) => {maps["map-" + id].invalidateSize()}, 50, id);
}
}
// detail
function togglePortdata(pid) {
$("#preorder-detail-" + pid + "-patchposition-data-form input[name='patch_cluster']").val($("#preorder-detail-" + pid + "-patchposition-data-form input[name='patch_cluster']").data("default"));
$("#preorder-detail-" + pid + "-patchposition-data-form input[name='patch_shelf']").val($("#preorder-detail-" + pid + "-patchposition-data-form input[name='patch_shelf']").data("default"));
$("#preorder-detail-" + pid + "-patchposition-data-form input[name='patch_module']").val($("#preorder-detail-" + pid + "-patchposition-data-form input[name='patch_module']").data("default"));
$("#preorder-detail-" + pid + "-patchposition-port-form input[name='patch_port']").val($("#preorder-detail-" + pid + "-patchposition-port-form input[name='patch_port']").data("default"));
$("#preorder-detail-" + pid + "-patchposition-data-form").toggle();
$("#preorder-detail-" + pid + "-patchposition-string").toggle();
$("#preorder-detail-" + pid + "-patchposition-port-form").toggle();
$("#preorder-detail-" + pid + "-patchposition-port").toggle();
$("#preorder-detail-" + pid + "-patchposition-edit").toggle();
$("#preorder-detail-" + pid + "-patchposition-controls").toggle();
}
function savePortdata(pid) {
if(!pid) return;
var cluster = $("#preorder-detail-" + pid + "-patchposition-data-form input[name='patch_cluster']").val();
var shelf = $("#preorder-detail-" + pid + "-patchposition-data-form input[name='patch_shelf']").val();
var module = $("#preorder-detail-" + pid + "-patchposition-data-form input[name='patch_module']").val();
var port = $("#preorder-detail-" + pid + "-patchposition-port-form input[name='patch_port']").val();
$.post("<?=self::getUrl("Preorder", "Api")?>", {
do: "savePatchposition",
id: pid,
cluster: cluster,
shelf: shelf,
module: module,
port: port
},
(success) => {
if(success.status == "OK") {
var pid = success.result.id;
var default_cluster = $("#preorder-detail-" + pid + "-patchposition-data-form input[name='patch_cluster']").data("default");
var cluster = $("#preorder-detail-" + pid + "-patchposition-data-form input[name='patch_cluster']").val();
var shelf = $("#preorder-detail-" + pid + "-patchposition-data-form input[name='patch_shelf']").val();
var module = $("#preorder-detail-" + pid + "-patchposition-data-form input[name='patch_module']").val();
var port = $("#preorder-detail-" + pid + "-patchposition-port-form input[name='patch_port']").val();
if(!cluster) cluster = default_cluster;
$("#preorder-detail-" + pid + "-patchposition-data-form input[name='patch_cluster']").data("default", cluster);
$("#preorder-detail-" + pid + "-patchposition-data-form input[name='patch_shelf']").data("default", shelf);
$("#preorder-detail-" + pid + "-patchposition-data-form input[name='patch_module']").data("default", module);
$("#preorder-detail-" + pid + "-patchposition-port-form input[name='patch_port']").data("default", port);
$("#preorder-detail-" + pid + "-patchposition-string").text(cluster + "-" + shelf + "-" + module);
$("#preorder-detail-" + pid + "-patchposition-port").text(port);
togglePortdata(pid);
}
},
"json"
);
}
function toggleStatusControl(pid, sid) {
// set select to current status id
$("#preorder-detail-status-" + pid + "-input select").val($("#preorder-detail-status-" + pid + "-text").data("status-id"));
// toggle controls
$("#preorder-detail-status-" + pid + "-text").toggle();
$("#preorder-detail-status-" + pid + "-input").toggle();
return false;
}
function savePreorderStatusControl(pid) {
if(!Number.isInteger(pid) || pid < 1) {
return false;
}
var value = $("#preorder-detail-status-" + pid + "-input select").val();
//console.log("add opacity-5 to ")
$("#preorder-" + pid + "-body").addClass("opacity-5");
$("#preorder-" + pid + "-body .loader-big").show();
// reset loading overlay if request times out
setTimeout(() => {
$("#preorder-" + pid + "-body").removeClass("opacity-5");
$("#preorder-" + pid + "-body .loader-big").hide();
}, 5000);
$.post("<?=self::getUrl("Preorder","Api")?>",
{
'do': "updateStatus",
id: pid,
status_id: value
},
function(success) {
if(success.status == "OK") {
var updates = success.result.updates;
//console.log(updates);
updates.forEach(function(u) {
//console.log(u);
// update detail status text
$("#preorder-detail-status-" + u.id + "-statustext").text(u.code + " - " + u.text);
$("#preorder-detail-status-" + u.id + "-text").addClass("text-success");
setTimeout(() => { $("#preorder-detail-status-" + u.id + "-text").removeClass("text-success") }, 1500);
// update list status text
$("#preorder-" + u.id + " .status").text(u.code + " - " + u.text);
$("#preorder-" + u.id + " .status").addClass("text-success");
setTimeout(() => { $("#preorder-" + u.id + " .status").removeClass("text-success") }, 1500);
// update status id data attribute
$("#preorder-detail-status-" + u.id + "-text").data("status-id", u.sid);
if(u.bcode) {
$("#preorder-detail-building-status-" + u.id).text(u.bcode + " - " + u.btext);
}
if(u.ucode) {
$("#preorder-detail-unit-status-" + u.id).text(u.ucode + " - " + u.utext);
}
if(u.ciftoken) {
$("#preorder-detail-ciftoken-" + u.id).text(u.ciftoken);
}
if(u.cifcableurl) {
$("#preorder-detail-cifcableurl-" + u.id).text(u.cifcableurl);
}
});
/*
if("preorder" in update) {
// update detail status text
$("#preorder-detail-status-" + pid + "-statustext").text(update.preorder.status.code + " - " + update.preorder.status.text);
$("#preorder-detail-status-" + pid + "-text").addClass("text-success");
setTimeout(() => { $("#preorder-detail-status-" + pid + "-text").removeClass("text-success") }, 1500);
// update list status text
$("#preorder-" + pid + " .status").text(update.preorder.status.code + " - " + update.preorder.status.text);
$("#preorder-" + pid + " .status").addClass("text-success");
setTimeout(() => { $("#preorder-" + pid + " .status").removeClass("text-success") }, 1500);
// update status id data attribute
$("#preorder-detail-status-" + pid + "-text").data("status-id", update.preorder.status.id);
}
if("building" in update) {
// update building status text
$("#preorder-detail-building-status-" + pid).text(update.building.status.code + " - " + update.building.status.text);
}
if("unit" in update) {
// update unit status text
$("#preorder-detail-unit-status-" + pid).text(update.unit.status.code + " - " + update.unit.status.text);
}
*/
toggleStatusControl(pid);
}
$("#preorder-" + pid + "-body").removeClass("opacity-5");
$("#preorder-" + pid + "-body .loader-big").hide();
},
'json');
}
function toggleOrderdateControl(pid) {
// set select to current status id
//$("#preorder-detail-orderdate-" + pid + "-input select").val($("#preorder-detail-orderdate-" + pid + "-text").data("orderdate"));
// toggle controls
$("#preorder-detail-orderdate-" + pid + "-text").toggle();
$("#preorder-detail-orderdate-" + pid + "-input").toggle();
return false;
}
function savePreorderOrderdateControl(pid) {
if(!Number.isInteger(pid) || pid < 1) {
return false;
}
var value = $("#preorder-detail-orderdate-" + pid + "-input input").val();
//console.log("add opacity-5 to ")
$("#preorder-" + pid + "-body").addClass("opacity-5");
$("#preorder-" + pid + "-body .loader-big").show();
// reset loading overlay if request times out
setTimeout(() => {
$("#preorder-" + pid + "-body").removeClass("opacity-5");
$("#preorder-" + pid + "-body .loader-big").hide();
}, 5000);
$.post("<?=self::getUrl("Preorder","Api")?>",
{
'do': "saveOrderdate",
id: pid,
order_date: value
},
function(success) {
if(success.status == "OK") {
console.log(success);
var new_orderdate = success.result.order_date;
var pid = success.result.preorder_id;
//console.log(updates);
$("#preorder-detail-orderdate-" + pid + "-textpart").text(new_orderdate);
$("#preorder-detail-orderdate-" + pid + "-input").val(new_orderdate);
$("#preorder-detail-orderdate-" + pid + "-text").addClass("text-success");
setTimeout(() => { $("#preorder-detail-orderdate-" + pid + "-text").removeClass("text-success") }, 1500);
toggleOrderdateControl(pid);
}
$("#preorder-" + pid + "-body").removeClass("opacity-5");
$("#preorder-" + pid + "-body .loader-big").hide();
},
'json');
}
function toggleActivationdateControl(pid) {
// set select to current status id
//$("#preorder-detail-activationdate-" + pid + "-input select").val($("#preorder-detail-activationdate-" + pid + "-text").data("activationdate"));
// toggle controls
$("#preorder-detail-activationdate-" + pid + "-text").toggle();
$("#preorder-detail-activationdate-" + pid + "-input").toggle();
$("#preorder-detail-activation-billing-" + pid).toggle();
return false;
}
function savePreorderActivationdateControl(pid) {
if(!Number.isInteger(pid) || pid < 1) {
return false;
}
var value = $("#preorder-detail-activationdate-" + pid + "-input input").val();
var activation_billing = $("#preorder-detail-activation-billing-" + pid + " input[type='checkbox'").is(":checked") ? 1 : 0;
console.log($("#preorder-detail-activation-billing-" + pid + " input[type='checkbox'"));
console.log(activation_billing);
//console.log("add opacity-5 to ")
$("#preorder-" + pid + "-body").addClass("opacity-5");
$("#preorder-" + pid + "-body .loader-big").show();
// reset loading overlay if request times out
setTimeout(() => {
$("#preorder-" + pid + "-body").removeClass("opacity-5");
$("#preorder-" + pid + "-body .loader-big").hide();
}, 5000);
$.post("<?=self::getUrl("Preorder","Api")?>",
{
'do': "saveActivationdate",
id: pid,
activation_date: value,
activation_billing: activation_billing
},
function(success) {
if(success.status == "OK") {
console.log(success);
var new_activationdate = success.result.activation_date;
var new_activation_billing = success.result.activation_billing;
var pid = success.result.preorder_id;
//console.log(updates);
$("#preorder-detail-activationdate-" + pid + "-textpart").text(new_activationdate);
$("#preorder-detail-activationdate-" + pid + "-input").val(new_activationdate);
console.log($("#preorder-detail-activationdate-" + pid + "-activation-billing-part"));
$("#preorder-detail-activationdate-" + pid + "-activation-billing-part").text("");
if(new_activation_billing) {
$("#preorder-detail-activationdate-" + pid + "-activation-billing-part").text("(Billing ab Aktivierung)");
}
$("#preorder-detail-activationdate-" + pid + "-text").addClass("text-success");
setTimeout(() => { $("#preorder-detail-activationdate-" + pid + "-text").removeClass("text-success") }, 1500);
toggleActivationdateControl(pid);
}
$("#preorder-" + pid + "-body").removeClass("opacity-5");
$("#preorder-" + pid + "-body .loader-big").hide();
},
'json');
}
/*
* Toggle Borderpoint status radio buttons on/off
*/
// get and save initial radio button states
var bpstatus_radiostate = [];
$("input[name^='borderpoint_status_']").each(function(i) {
let match = $(this).attr("name").match(/_(\d+)$/);
let pid = match[1];
bpstatus_radiostate[pid + "-" + $(this).val()] = $(this).is(":checked");
});
// if saved value is checked => uncheck
$("input[name^='borderpoint_status_']").click(async (e) => {
var radio = $(e.target);
var val = radio.val();
console.log(radio.attr("name"));
let match = radio.attr("name").match(/_(\d+)$/);
if(!match || !match[1]) {
return;
}
let pid = match[1];
var new_status;
if(bpstatus_radiostate[pid + "-" + val]) {
new_status = false;
radio.prop("checked", false);
bpstatus_radiostate[pid + "-" + val] = false;
} else {
new_status = true;
radio.prop("checked", true);
for(const [key, value] of Object.entries(bpstatus_radiostate)) {
if(key.startsWith(pid + "-")) {
bpstatus_radiostate[key] = false;
}
}
bpstatus_radiostate[pid + "-" + val] = true;
}
// save new status
await fetch("<?=self::getUrl("Preorder", "Api")?>", {
method: "POST",
headers: {
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'
},
body: new URLSearchParams({
do: "saveBorderpointStatus",
preorder_id: pid,
status_type: val,
value: new_status ? 1 : 0
})
}).then(resp => {
if(resp.ok) {
return resp.json();
}
}).then((data) => {
console.log(data);
console.log(pid);
if(data.status == "OK") {
window.notify("success", "Borderpoint Status gespeichert");
} else {
window.notify("error", "Fehler beim Speichern des Borderpoint Status");
}
});
});
function createWorkorder(pid) {
if(!Number.isInteger(pid) || pid < 1) {
return false;
}
$("#preorder-detail-" + pid + "-rimo button.create-workorder").prop("disabled", true);
$("#preorder-detail-" + pid + "-rimo .workorder-container").append("<img src='<?=self::getResourcePath()?>img/ajax-loader.gif' />");
$.ajax({
url: "<?=self::getUrl("Preorder","Api")?>",
method: "POST",
data: {
do: "createWorkorder",
id: pid,
},
context: {
pid: pid
},
dataType: 'json',
success: function(response) {
if(response.status == "OK") {
wo = response.result;
html = '<h4> \
' + wo.name + ' \
<a href="<?=self::getUrl("RimoWorkorder", "downloadAh")?>?id=' + wo.id + '" onclick="event.preventDefault(); downloadWorkorderAha(' + wo.id + ');"><i class="fas fa-fw fa-file-download ml-2"></i> AHA Blatt</a> \
</h4> \
<table class="table table-sm table-striped" id="preorder-detail-' + wo.preorder_id + '-workorder-' + wo.id + '"> \
<tr> \
<th>Name</th> \
<td class="text-monospace">' + wo.name + '</td> \
</tr><tr> \
<th>External ID</th> \
<td class="text-monospace">' + wo.external_id + '</td> \
</tr><tr> \
<th>Status</th> \
<td>' + wo.status + '</td> \
</tr> \
<tr> \
<th>Zugewiesen an:</th> \
<td>' + wo.assigned_to + '</td> \
</tr> \
<tr> \
<th>Erstellt</th> \
<td class="text-monospace">' + wo.created + '</td> \
</tr> \
</table>';
$("#preorder-detail-" + wo.preorder_id + "-rimo img").remove();
$("#preorder-detail-" + wo.preorder_id + "-rimo .workorder-container img").remove();
$("#preorder-detail-" + wo.preorder_id + "-rimo button.create-workorder").remove();
$("#preorder-detail-" + wo.preorder_id + "-rimo .workorder-container").append(html);
} else {
restoreBlankWorkorderView(this.pid);
window.notify("error", "Workorder konnte nicht erstellt werden!");
}
},
error: function() {
restoreBlankWorkorderView(this.pid);
window.notify("error", "Workorder konnte nicht erstellt werden!");
}
});
return true;
}
function restoreBlankWorkorderView(pid) {
$("#preorder-detail-" + pid + "-rimo .workorder-container img").remove();
$("#preorder-detail-" + pid + "-rimo button.create-workorder").prop("disabled", false);
}
function deleteWorkorder(pid, wid) {
//console.log("in delete workorder");
if(!Number.isInteger(pid) || pid < 1) {
return false;
}
if(!Number.isInteger(wid) || wid < 1) {
return false;
}
$.post("<?=self::getUrl("Preorder","Api")?>",
{
'do': "deleteWorkorder",
id: pid,
wid: wid
},
function(success) {
if(success.status == "OK") {
$("#preorder-detail-" + success.result.id + "-workorder-" + success.result.wid + " td").each(function() {
$(this).html("<em class='text-monospace'>--gelöscht--</em>");
});
$("#preorder-detail-" + success.result.id + "-workorder-" + success.result.wid + "-del").remove();
}
},
'json');
return false;
}
async function downloadWorkorderAha(workorder_id) {
if(!workorder_id) return false;
var filename;
await fetch('<?=self::getUrl("RimoWorkorder", "downloadAha")?>?id=' + workorder_id)
.then(resp => {
const header = resp.headers.get("Content-disposition");
let matches = header.match(/filename=['"]?([^'"]+)/i);
filename = matches[1];
if(!filename) {
window.notify("error", "Fehler beim Download des AH-Blatts");
return false;
}
return resp.blob();
})
.then(blob => {
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.style.display = 'none';
a.href = url;
a.download = filename;
document.body.appendChild(a);
a.click();
window.URL.revokeObjectURL(url);
window.notify("success", "Download gestartet...");
})
.catch(() => {
window.notify("error", "Fehler beim Download des AH-Blatts");
});
}
async function saveRemark(pid, wid) {
if(!pid || !wid) return false;
var new_remark_elem = $("#wo-remark-" + pid + "-" + wid + " input[name='new_remark']");
var new_remark = new_remark_elem.val();
new_remark_elem.prop("readonly", true);
await fetch("<?=self::getUrl("Preorder", "Api")?>", {
method: "POST",
headers: {
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'
},
body: new URLSearchParams({
do: "addWorkorderRemark",
preorder_id: pid,
workorder_id: wid,
remark: new_remark
})
}).then(resp => {
if(resp.ok) {
return resp.json();
}
}).then((data) => {
if(data.status == "OK") {
var remark = data.result.remark.replaceAll("\n", "<br />");
$("#wo-remark-" + pid + "-" + wid + " div.remark-text").html(remark);
new_remark_elem.val("");
window.notify("success", "Bemerkung gespeichert");
} else {
window.notify("error", "Fehler beim Speichern der Bemerkung");
}
});
new_remark_elem.prop("readonly", false);
}
function openCancelApproval(pid) {
console.log(pid);
if($('#preorder-detail-' + pid).is(":hidden")) {
togglePreorder(pid);
}
var mytab = $("a[href='#preorder-detail-" + pid + "-cancelation']");
console.log(mytab);
mytab.tab("show")
}
function approveCancelRequest(pid) {
console.log("approve");
}
function denyCancelRequest(pid) {
console.log("deny");
}
/***********************
* Email Log
***********************/
async function displayEmailLogEmail(preorder_id, email_id) {
$("#email-log-from-value").text("");
$("#email-log-to-value").text("");
$("#email-log-log-sent-value").text("");
$("#email-log-subject-value").text("");
document.getElementById("email-log-body-view").contentWindow.document.open();
document.getElementById("email-log-body-view").contentWindow.document.write("<html><body>&nbsp;</body></html>");
document.getElementById("email-log-body-view").contentWindow.document.close();
$("#email-log-attachments-section").hide();
$("#email-log-attachment-list").empty();
hideEmailLogHeaders();
if(!email_id) return false;
var resp = await fetch("<?=self::getUrl("Preorder", "api", ["do" => "getLoggedEmail"])?>&eid=" + email_id + "&pid=" + preorder_id);
if(!resp.ok) {
notify("error", "Email konnte nicht geladen werden");
return false;
}
var response = await resp.json();
if(!("result" in response) || typeof response.result !== "object") {
notify("error", "Email konnte nicht geladen werden");
return false;
}
var email = response.result;
$("#email-log-from-value").text(email.from);
$("#email-log-to-value").text(email.to);
$("#email-log-sent-value").text(email.sent);
$("#email-log-subject-value").text(email.subject);
if("headers" in email && typeof email.headers === "object" && Object.keys(email.headers).length > 0) {
for (const [key, value] of Object.entries(email.headers)) {
$("#email-log-header-view").append(
"<strong>" + key + "</strong>: "
+ value.replace(/&/g, '&amp;').replace(/"/g, '&quot;').replace(/'/g, '&#39;').replace(/</g, '&lt;').replace(/>/g, '&gt;')
+ "<br/>");
if(key == "From") {
$("#email-log-from-value").text(value);
}
}
}
if("attachments" in email && typeof email.attachments === "object" && Object.keys(email.attachments).length > 0) {
email.attachments.forEach( (item, index) => {
$("#email-log-attachment-list").append('<li class="list-group-item flex-fill p-1" style="border-radius: 0;"><a href="<?=self::getUrl("EmailLog", "downloadContent")?>?aid=' + item.id + '&hash=' + item.hash + '"><span class="filename text-monospace"><i class="far fa-file"></i> ' + item.filename + '</span></a> (' + Math.round((item.filesize/1024/1024)*100)/100 + ' MB)</li>');
});
$("#email-log-attachments-section").show();
}
document.getElementById("email-log-body-view").contentWindow.document.open();
if(email.bodyIsHtml) {
document.getElementById("email-log-body-view").contentWindow.document.write(email.body);
} else {
var html_body = '<html lang="de"><head><meta charset="utf-8"></head><body><p>';
html_body += email.body.replaceAll("\r", "").replaceAll("\n", "<br />");
html_body += '</p></body></html>';
document.getElementById("email-log-body-view").contentWindow.document.write(html_body);
}
document.getElementById("email-log-body-view").contentWindow.document.close();
$("#email-log-modal").modal("show");
}
function displayEmailLogHeaders() {
$("#email-log-header-view").toggleClass("hidden");
if($("#email-log-header-view").hasClass("hidden")) {
$("#email-log-header-section").find("i").addClass("fa-chevron-right").removeClass("fa-chevron-down");
} else {
$("#email-log-header-section").find("i").addClass("fa-chevron-down").removeClass("fa-chevron-right");
}
}
function hideEmailLogHeaders() {
$("#email-log-header-view").empty();
if(!$("#email-log-header-view").hasClass("hidden")) {
$("#email-log-header-view").addClass("hidden");
$("#email-log-header-section").find("i").addClass("fa-chevron-down").removeClass("fa-chevron-right");
}
}
</script>
<script>
$(document).ready(function() {
const fcpSelect = $("#filter_fcp");
const campaignSelect = $("#filter_preordercampaign_id");
const apiUrl = "<?=self::getUrl("Preorder", "Api")?>";
fcpSelect.select2({ data: [], placeholder: "Bitte Kampagne auswählen", allowClear: true });
campaignSelect.on("change", function() {
const campaign_id = $(this).val();
if (!campaign_id) {
fcpSelect.empty().select2({ data: [], placeholder: "Bitte Kampagne auswählen", allowClear: true });
return;
}
$.get(apiUrl, { do: "getFCPsForCampaign", campaign_id: campaign_id }, (success) => {
let fcpData = [];
let opts = { data: [], placeholder: "Bitte Kampagne auswählen", allowClear: true };
if (success?.status === "OK" && Array.isArray(success.result)) {
fcpData = success.result;
fcpData.unshift({ id: "", text: "" });
fcpData.sort((a, b) => {
const aN = a.text.replace(/\D/g, ""), bN = b.text.replace(/\D/g, "");
return aN && bN ? parseInt(aN, 10) - parseInt(bN, 10) : a.text.localeCompare(b.text);
});
opts = { data: fcpData, placeholder: "", allowClear: true };
fcpSelect.empty().select2(opts);
const searchParams = new URLSearchParams(window.location.search);
const fcpValues = searchParams.getAll("filter[fcp][]");
if (fcpValues && fcpValues.length > 0) {
fcpSelect.val(fcpValues).trigger("change");
}
} else {
fcpSelect.empty().select2(opts);
}
}, "json").fail(() => {
fcpSelect.empty().select2({ data: [], placeholder: "Fehler", allowClear: true });
});
});
campaignSelect.trigger("change");
// for the Rimo-Typen Karte <a> only show this <a> button if a preordercampaign is selected and change the display and href dynamically
const rimoTypesLink = $("#rimo-types-link");
function updateRimoTypesLink() {
const campaignId = campaignSelect.val();
if (campaignId) {
rimoTypesLink.show();
rimoTypesLink.attr("href", "<?=self::getUrl("Preorder", "RimoTypeMap")?>?preordercampaign_id=" + campaignId);
} else {
rimoTypesLink.hide();
rimoTypesLink.attr("href", "#");
}
}
campaignSelect.on("change", updateRimoTypesLink);
updateRimoTypesLink();
});
</script>
<script src="<?= self::getResourcePath() ?>js/pages/AddressDB/ADBWohneinheitContactManager.js"></script>
<script src="<?= self::getResourcePath() ?>plugins/axios/axios.min.js"></script>
<script src="<?= self::getResourcePath() ?>plugins/axios/axios.inject.js"></script>
<?php include(realpath(dirname(__FILE__)."/../../$mfLayoutPackage")."/footer.php"); ?>