Merge branch 'master' into fronkdev

This commit is contained in:
Frank Schubert
2024-12-22 14:31:17 +01:00
29 changed files with 1265 additions and 295 deletions
+84 -35
View File
@@ -102,18 +102,20 @@ endforeach;
<div id="calendar-side-div" class="col-12 col-lg-2"> <div id="calendar-side-div" class="col-12 col-lg-2">
<div class="calendar-side-borders-main"> <div class="calendar-side-borders-main">
<h3 class="no-movable" data-id="<?= $Calendar[0]->id ?>" id="calendar-id">Kalender <h3 class="no-movable" data-calendarid="<?= $Calendar[0]->go_calendar_id ?>" data-id="<?= $Calendar[0]->id ?>" id="calendar-id">Kalender
<div class="add-cal-group-div"><i title="Kalendergruppe hinzufügen" <div class="add-cal-group-div"><i title="Kalendergruppe hinzufügen"
class="fa-duotone fa-solid fa-rectangle-history-circle-plus"></i> class="fa-duotone fa-solid fa-rectangle-history-circle-plus"></i>
</div> </div>
</h3> </h3>
<?php <?php
if ($Calendar[0]->groups) : ?> if ($Calendar[0]->groups) :
$Rights = $rights;
?>
<div class="add-cal-group-div-sub"> <div class="add-cal-group-div-sub">
<?php <?php
$groups = json_decode($Calendar[0]->groups, true); $groups = json_decode($Calendar[0]->groups, true);
foreach ($groups as $group) : foreach ($groups as $group) :
?> ?>
<div class="calendar-side-borders-sub mb-2" data-origin="<?= $group['origin'] ?>"> <div class="calendar-side-borders-sub mb-2" data-origin="<?= $group['origin'] ?>">
@@ -131,7 +133,10 @@ endforeach;
</h5> </h5>
<div class="calendar-side-borders-sub-inner <?= ($group['origin']) ? 'data-origin-' . $group['origin'] : '' ?>" <div class="calendar-side-borders-sub-inner <?= ($group['origin']) ? 'data-origin-' . $group['origin'] : '' ?>"
style="<?= ($group['show']) ? '' : 'display:none;' ?>"> style="<?= ($group['show']) ? '' : 'display:none;' ?>">
<?php foreach ($group['calendars'] as $calendar) : ?> <?php foreach ($group['calendars'] as $calendar) :
unset($Rights[$calendar['calendar_id']]);
?>
<div class="form-check text-left ml-2" <div class="form-check text-left ml-2"
data-origin="<?= $calendar['origin'] ?>"> data-origin="<?= $calendar['origin'] ?>">
<input data-calendar_id="<?= $calendar['calendar_id'] ?>" <input data-calendar_id="<?= $calendar['calendar_id'] ?>"
@@ -154,10 +159,52 @@ endforeach;
<?= ($CalendarAll[$calendar['calendar_id']]->user->name) ?: $specialCalendars[$calendar['calendar_id']] ?> <?= ($CalendarAll[$calendar['calendar_id']]->user->name) ?: $specialCalendars[$calendar['calendar_id']] ?>
</label> </label>
</div> </div>
<?php endforeach; ?> <?php endforeach;
// foreach ($Rights as $key => $calendar):
?>
<!---->
<!-- <div class="form-check text-left ml-2"-->
<!-- data-origin="-->
<?php //= $calendar['origin']
?><!--">-->
<!-- <input data-calendar_id="-->
<?php //= $calendar['calendar_id']
?><!--"-->
<!-- class="form-check-input calendar-check"-->
<!-- name="form-check-input" type="checkbox"-->
<!-- --><?php //= ($calendar['checked']) ? 'checked="checked"' : ''
?>
<!-- value="2">-->
<!-- <input-->
<!-- data-calendar_id="-->
<?php //= $calendar['calendar_id']
?><!--"-->
<!-- type="color"-->
<!-- class="form-control-color color-input"-->
<!-- value="-->
<?php //= $Calendar_colors[$key]['bgcolor']
?><!--"-->
<!-- title="Hintergrundfarbe">-->
<!-- <input data-calendar_id="-->
<?php //= $calendar['calendar_id']
?><!--"-->
<!-- type="color"-->
<!-- class="form-control-color color-text-input"-->
<!-- value="-->
<?php //= ($Calendar_colors[$key]['txtcolor']) ? $Calendar_colors[$key]['txtcolor'] : '#000000'
?><!--"-->
<!-- title="Textfarbe">-->
<!-- <label class="calendar-side-label" style="margin-top:2px;">-->
<!-- --><?php //= ($CalendarAll[$key]->user->name) ?: $specialCalendars[$calendar['calendar_id']]
?>
<!-- </label>-->
<!-- </div>-->
<!-- --><?php //endforeach;
?>
</div> </div>
</div> </div>
<?php endforeach; <?php endforeach;
// var_dump($Rights);
?> ?>
</div> </div>
<?php else : ?> <?php else : ?>
@@ -248,24 +295,26 @@ endforeach;
</div> </div>
</h5> </h5>
<div class="calendar-side-borders-sub-inner data-origin-2"> <div class="calendar-side-borders-sub-inner data-origin-2">
<!-- <div style="display:none">--> <!-- <div style="display:none">-->
<!-- <div class="form-check text-left ml-2" data-origin="2">--> <!-- <div class="form-check text-left ml-2" data-origin="2">-->
<!-- <input data-calendar_id="999" class="form-check-input calendar-check"--> <!-- <input data-calendar_id="999" class="form-check-input calendar-check"-->
<!-- name="form-check-input"--> <!-- name="form-check-input"-->
<!-- type="checkbox" value="">--> <!-- type="checkbox" value="">-->
<!-- <input data-calendar_id="999" type="color"--> <!-- <input data-calendar_id="999" type="color"-->
<!-- class="form-control-color color-input"--> <!-- class="form-control-color color-input"-->
<!-- value="--><?php //= ($Calendar_colors[999]['bgcolor']) ?: $specialCalendarColors[999] ?><!--"--> <!-- value="-->
<!-- title="Hintergrundfarbe">--> <?php //= ($Calendar_colors[999]['bgcolor']) ?: $specialCalendarColors[999] ?><!--"-->
<!-- <input data-calendar_id="999" type="color"--> <!-- title="Hintergrundfarbe">-->
<!-- class="form-control-color color-text-input"--> <!-- <input data-calendar_id="999" type="color"-->
<!-- value="--><?php //= ($Calendar_colors[999]['txtcolor']) ? $Calendar_colors[999]['txtcolor'] : '#ffffff' ?><!--"--> <!-- class="form-control-color color-text-input"-->
<!-- title="Textfarbe">--> <!-- value="-->
<!-- <label class="calendar-side-label" for="" style="margin-top:2px;">--> <?php //= ($Calendar_colors[999]['txtcolor']) ? $Calendar_colors[999]['txtcolor'] : '#ffffff' ?><!--"-->
<!-- Abwesenheiten--> <!-- title="Textfarbe">-->
<!-- </label>--> <!-- <label class="calendar-side-label" for="" style="margin-top:2px;">-->
<!-- </div>--> <!-- Abwesenheiten-->
<!-- </div>--> <!-- </label>-->
<!-- </div>-->
<!-- </div>-->
<div class="form-check text-left ml-2" data-origin="2"> <div class="form-check text-left ml-2" data-origin="2">
<input data-calendar_id="998" class="form-check-input calendar-check" <input data-calendar_id="998" class="form-check-input calendar-check"
name="form-check-input" name="form-check-input"
@@ -339,17 +388,18 @@ endforeach;
<input type="text" class="form-control is-require eventmodal-input" id="name"> <input type="text" class="form-control is-require eventmodal-input" id="name">
</div> </div>
</div> </div>
<div class="col-1 text-right">
<label for="location" class="col-form-label fw-medium ">Typ</label>
</div>
<div class="col-3"> <div class="col-3">
<div class="mb-2"> <div class="input-group mb-2">
<span title="Erinnerung" class="input-group-text spanwidht">Typ</span>
<select class="form-control form-select" aria-label="Default select" id="type"> <select class="form-control form-select" aria-label="Default select" id="type">
<option value="1">Termin</option> <option value="1">Termin</option>
<option value="2">IBN</option> <option value="2">IBN</option>
</select> </select>
</div> </div>
</div> </div>
<div class="col-1 text-center">
<i title="Normal" class="fa-duotone privacy-click fa-regular fa-unlock mt-1"></i>
</div>
</div> </div>
<div class="row justify-content-center"> <div class="row justify-content-center">
@@ -361,11 +411,10 @@ endforeach;
<input type="text" class="form-control eventmodal-input" id="location"> <input type="text" class="form-control eventmodal-input" id="location">
</div> </div>
</div> </div>
<div class="col-1 text-right"> <div class="col-4">
<label for="location" class="col-form-label fw-medium ">Anzeige</label> <div class="input-group mb-2">
</div> <span title="Erinnerung" class="input-group-text spanwidht"><i
<div class="col-3"> class="fa-regular fa-eye"></i></span>
<div class="mb-2">
<select class="form-control form-select" aria-label="Default select" id="busy"> <select class="form-control form-select" aria-label="Default select" id="busy">
<option value="1">gebucht</option> <option value="1">gebucht</option>
<option value="0">frei</option> <option value="0">frei</option>
@@ -373,7 +422,6 @@ endforeach;
</select> </select>
</div> </div>
</div> </div>
</div> </div>
<div class="row justify-content-center"> <div class="row justify-content-center">
@@ -439,7 +487,6 @@ endforeach;
</select> </select>
</div> </div>
</div> </div>
</div> </div>
<div class="row justify-content-center mt-2"> <div class="row justify-content-center mt-2">
@@ -541,7 +588,9 @@ endforeach;
</div> </div>
<div class="d-inline-block" id="customer-info-check-info"></div> <div class="d-inline-block" id="customer-info-check-info"></div>
</div> </div>
<select id="customer" class="jumpevent"></select> <div id="relContainer2" style="position:relative">
<select id="customer" class="jumpevent"></select>
</div>
</div> </div>
</div> </div>
</div> </div>
+59 -29
View File
@@ -146,13 +146,20 @@
</select> </select>
</div> </div>
<div class="col-sm-12 col-md-2"> <div class="col-sm-12 col-md-2">
<label class="form-label" for="partner_id">Partner</label> <label class="form-label" for="partner_id">Partner</label>
<select name="filter[partner_id]" id="filter_partner_id" class="form-control"> <select name="filter[partner_id][]" id="filter_partner_id" class="form-control" multiple="multiple">
<option value="">Alle</option> <?php
<?php foreach($partners as $partner): ?> // if partner_id is string unset it from filter
<option value="<?=$partner['partner_id']?>" <?=(isset($filter) && array_key_exists("partner_id", $filter) && $filter["partner_id"] == $partner['partner_id']) ? "selected='selected'" : ""?>><?=$partner['name']?></option> if(isset($filter) && array_key_exists("partner_id", $filter) && is_string($filter["partner_id"])) {
<?php endforeach; ?> 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> </select>
</div> </div>
@@ -164,6 +171,17 @@
<?php endforeach; ?> <?php endforeach; ?>
</select> </select>
</div> </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"> <div class="col-sm-12 col-md-2">
<label class="form-label" for="filter_type">Bestelltyp</label> <label class="form-label" for="filter_type">Bestelltyp</label>
@@ -173,14 +191,15 @@
<option value="order" <?=(isset($filter) && array_key_exists("type", $filter) && in_array("order", $filter['type'])) ? "selected='selected'" : ""?>>Vollanschluss</option> <option value="order" <?=(isset($filter) && array_key_exists("type", $filter) && in_array("order", $filter['type'])) ? "selected='selected'" : ""?>>Vollanschluss</option>
</select> </select>
</div> </div>
<div class="col-sm-12 col-md-2"> <!-- INFO THIS FILTER IS CURRENTLY HIDDEN -->
<label class="form-label" for="filter_addon_services">Zusatzdienste</label> <!-- <div class="col-sm-12 col-md-2">-->
<select name="filter[addon_services]" id="filter_addon_services" class="form-control"> <!-- <label class="form-label" for="filter_addon_services">Zusatzdienste</label>-->
<option></option> <!-- <select name="filter[addon_services]" id="filter_addon_services" class="form-control">-->
<option value="1" <?=(isset($filter['addon_services']) && $filter['addon_services'] == 1) ? "selected='selected'" : ""?>>Nur mit Zusatzdiensten</option> <!-- <option></option>-->
</select> <!-- <option value="1" --><?php //=(isset($filter['addon_services']) && $filter['addon_services'] == 1) ? "selected='selected'" : ""?><!-- >Nur mit Zusatzdiensten</option>-->
</div> <!-- </select>-->
<!-- </div>-->
</div> </div>
<div class="row mt-2"> <div class="row mt-2">
<div class="col-sm-12 col-md-1"> <div class="col-sm-12 col-md-1">
@@ -192,6 +211,11 @@
<label class="form-label" for="filter_oaid">OAID</label> <label class="form-label" for="filter_oaid">OAID</label>
<input type="text" class="form-control" name="filter[oaid]" id="filter_oaid" value="<?=$filter['oaid'] ?? ""?>" /> <input type="text" class="form-control" name="filter[oaid]" id="filter_oaid" value="<?=$filter['oaid'] ?? ""?>" />
</div> </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"> <div class="col-sm-12 col-md-2">
<label class="form-label" for="filter_address">Anschlussadresse</label> <label class="form-label" for="filter_address">Anschlussadresse</label>
@@ -219,15 +243,33 @@
<option value="no" <?=(isset($filter) && array_key_exists("unit_missing", $filter) && $filter['unit_missing'] == "no") ? "selected='selected'" : ""?>>Wohneinheit vorhanden</option> <option value="no" <?=(isset($filter) && array_key_exists("unit_missing", $filter) && $filter['unit_missing'] == "no") ? "selected='selected'" : ""?>>Wohneinheit vorhanden</option>
</select> </select>
</div> </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-2"> <div class="col-sm-12 col-md-1">
<label class="form-label" for="filter_connection_count">Anzahl Anschlüsse</label> <label class="form-label" for="filter_connection_count">Anz. Anschlüsse</label>
<select name="filter[connection_count]" id="filter_connection_count" class="form-control"> <select name="filter[connection_count]" id="filter_connection_count" class="form-control">
<option value=""></option> <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="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> <option value="2" <?=(isset($filter) && array_key_exists("connection_count", $filter) && intval($filter['connection_count']) === 2) ? "selected='selected'" : ""?>> &gt; 1</option>
</select> </select>
</div> </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"> <div class="col-sm-12 col-md-1">
<label class="form-label" for="filter_rimo_workorder">Rimo Workorder</label> <label class="form-label" for="filter_rimo_workorder">Rimo Workorder</label>
@@ -251,11 +293,6 @@
</select> </select>
</div> </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"> <div class="col-sm-12 col-md-2">
<label class="form-label" for="filter_rimo_workorder_team_id">Rimo Workorder Assigned Team</label> <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"> <select name="filter[rimo_workorder_team_id]" id="filter_rimo_workorder_team_id" class="form-control">
@@ -266,15 +303,6 @@
</select> </select>
</div> </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> </div>
<div class="row mt-2"> <div class="row mt-2">
@@ -442,6 +470,8 @@
$(document).ready(function() { $(document).ready(function() {
$("#filter_type").select2({closeOnSelect: false}); $("#filter_type").select2({closeOnSelect: false});
$("#filter_status").select2({closeOnSelect: false}); $("#filter_status").select2({closeOnSelect: false});
$("#filter_partner_id").select2({closeOnSelect: false});
$("#connection_type_id").select2({closeOnSelect: false});
var attributes = ["bep_specified", "inhouse_cabling_supplied"]; var attributes = ["bep_specified", "inhouse_cabling_supplied"];
@@ -98,10 +98,10 @@ TODO: enable option for showing prices
<table style="border-collapse: collapse; width: 100%;" id="invoiceTable"> <table style="border-collapse: collapse; width: 100%;" id="invoiceTable">
<tr style="font-weight: bold; border-bottom: 1px solid black;" class="uneven"> <tr style="font-weight: bold; border-bottom: 1px solid black;" class="uneven">
<th style="text-align: center">Position</th> <th style="text-align: center;padding-right: 6pt">Position</th>
<th style="text-align: right;padding-right: 4pt">Menge</th> <th style="text-align: right;padding-right: 6pt">Menge</th>
<th style="text-align: left;padding-right: 4pt">Einheit</th> <th style="text-align: left;padding-right: 6pt">Einheit</th>
<th style="text-align: center">Artikel</th> <th style="text-align: left">Artikel</th>
<?php if($showPrices): ?> <?php if($showPrices): ?>
<th style="text-align: right;padding-right: 4pt">Preis</th> <th style="text-align: right;padding-right: 4pt">Preis</th>
<?php endif; ?> <?php endif; ?>
@@ -112,7 +112,7 @@ TODO: enable option for showing prices
<td style="text-align: center;"><?= $i + 1 ?></td> <td style="text-align: center;"><?= $i + 1 ?></td>
<td style="text-align: right;padding-right: 8pt"><?=$p["amount"]?> </td> <td style="text-align: right;padding-right: 8pt"><?=$p["amount"]?> </td>
<td style="text-align: left;padding-right: 8pt"><?=$p["articleUnit"]?> </td> <td style="text-align: left;padding-right: 8pt"><?=$p["articleUnit"]?> </td>
<td style="text-align: center;"><b><?=$p["articleTitle"]?></b></td> <td style="text-align: left;"><b><?=$p["articleTitle"]?></b></td>
<?php if($showPrices): ?> <?php if($showPrices): ?>
<td style="text-align: right;padding-right: 8pt"><?=number_format( <td style="text-align: right;padding-right: 8pt"><?=number_format(
$p["price"] * $p["amount"], 2, ",", ".")?> €</td> $p["price"] * $p["amount"], 2, ",", ".")?> €</td>
@@ -123,7 +123,7 @@ TODO: enable option for showing prices
<td></td> <td></td>
<td></td> <td></td>
<td style="text-align: center;"><?= $p["articleDescription"] ?></td> <td style="text-align: left;"><?= $p["articleDescription"] ?></td>
<?php if($showPrices): ?> <?php if($showPrices): ?>
<td></td> <td></td>
<?php endif; ?> <?php endif; ?>
+10 -2
View File
@@ -79,7 +79,15 @@ class AddressController extends mfBaseController {
if(array_key_exists("kunde", $filter) && $filter["kunde"]) { if(array_key_exists("kunde", $filter) && $filter["kunde"]) {
$kunde = $this->db()->escape($filter['kunde']); $kunde = $this->db()->escape($filter['kunde']);
$new_filter['add-where'] .= " AND (company like '%$kunde%' OR firstname like '%$kunde%' OR lastname like '%$kunde%' OR concat(firstname, ' ', lastname) like '%$kunde%' OR concat(lastname, ' ', firstname) like '%$kunde%')"; // if kunde contains ß or ss we want to search both cases but not with % because it can lead to wrong results
if (strpos($kunde, "ß") !== false || strpos($kunde, "ss") !== false) {
$kundeWithSS = str_replace("ß", "ss", $kunde);
$kundeWithoutSS = str_replace("ss", "ß", $kunde);
$new_filter['add-where'] .= " AND (company like '%$kundeWithoutSS%' OR firstname like '%$kundeWithoutSS%' OR lastname like '%$kundeWithoutSS%' OR concat(firstname, ' ', lastname) like '%$kundeWithoutSS%' OR concat(lastname, ' ', firstname) like '%$kundeWithoutSS%')";
$new_filter['add-where'] .= " OR (company like '%$kundeWithSS%' OR firstname like '%$kundeWithSS%' OR lastname like '%$kundeWithSS%' OR concat(firstname, ' ', lastname) like '%$kundeWithSS%' OR concat(lastname, ' ', firstname) like '%$kundeWithSS%')";
} else {
$new_filter['add-where'] .= " AND (company like '%$kunde%' OR firstname like '%$kunde%' OR lastname like '%$kunde%' OR concat(firstname, ' ', lastname) like '%$kunde%' OR concat(lastname, ' ', firstname) like '%$kunde%')";
}
} }
if(!array_key_exists("parents_only", $filter)) { if(!array_key_exists("parents_only", $filter)) {
@@ -110,7 +118,7 @@ class AddressController extends mfBaseController {
$new_filter[$name] = $value; $new_filter[$name] = $value;
} }
} }
return $new_filter; return $new_filter;
} }
@@ -152,6 +152,7 @@ class CalendarApicontroller extends mfBaseApicontroller
$now = floor(microtime(true) * 1000); $now = floor(microtime(true) * 1000);
$timenow = time(); $timenow = time();
while (true) { while (true) {
$colors = $redis->get('thetool_calendar_usercolors_' . $decstring); $colors = $redis->get('thetool_calendar_usercolors_' . $decstring);
if ($colors) { if ($colors) {
$calendarColors = json_decode($colors, true); $calendarColors = json_decode($colors, true);
@@ -172,11 +173,15 @@ class CalendarApicontroller extends mfBaseApicontroller
$message[0]['start_time'] = date('Y-m-d H:i', $json['start_time']); $message[0]['start_time'] = date('Y-m-d H:i', $json['start_time']);
$message[0]['end_time'] = date('Y-m-d H:i', $json['end_time']); $message[0]['end_time'] = date('Y-m-d H:i', $json['end_time']);
} }
$message[0]['name']= $Calendarevent['data'][0]['category']['category'];
$message[0]['description'] = $Calendarevent['data'][0]['description']['description'];
$message[0]['location'] = $Calendarevent['data'][0]['location']['location'];
$message[0]['event_type'] = $Calendarevent['data'][0]['event_type']['event_type']; $message[0]['event_type'] = $Calendarevent['data'][0]['event_type']['event_type'];
$message[0]['attachment'] = $Calendarevent['data'][0]['attachment']['attachment']; $message[0]['attachment'] = $Calendarevent['data'][0]['attachment']['attachment'];
$message[0]['attachments'] = $Calendarevent['data'][0]['attachments']['attachments']; $message[0]['attachments'] = $Calendarevent['data'][0]['attachments']['attachments'];
$message[0]['calendar_name'] = $Calendarevent['data'][0]['calendar_name']['calendar_name']; $message[0]['calendar_name'] = $Calendarevent['data'][0]['calendar_name']['calendar_name'];
$message[0]['isorganizer'] = $Calendarevent['data'][0]['isorganizer']['isorganizer']; $message[0]['isorganizer'] = $Calendarevent['data'][0]['isorganizer']['isorganizer'];
$message[0]['privateflag'] = $Calendarevent['data'][0]['privateflag']['privateflag'];
$message[0]['rrule'] = $Calendarevent['data'][0]['rrule']['rrule']; $message[0]['rrule'] = $Calendarevent['data'][0]['rrule']['rrule'];
$message[0]['duration'] = $Calendarevent['data'][0]['duration']['duration']; $message[0]['duration'] = $Calendarevent['data'][0]['duration']['duration'];
$message[0]['mtime'] = $Calendarevent['data'][0]['mtime']['mtime']; $message[0]['mtime'] = $Calendarevent['data'][0]['mtime']['mtime'];
@@ -189,6 +194,7 @@ class CalendarApicontroller extends mfBaseApicontroller
$message[0]['bgColor'] = $calendarColors[$json['calendar_id']]['bgcolor']; $message[0]['bgColor'] = $calendarColors[$json['calendar_id']]['bgcolor'];
$message[0]['txtColor'] = $calendarColors[$json['calendar_id']]['txtcolor']; $message[0]['txtColor'] = $calendarColors[$json['calendar_id']]['txtcolor'];
$message[0]['rights'] = $rights[$json['calendar_id']]; $message[0]['rights'] = $rights[$json['calendar_id']];
$message[0]['me'] = $decstring;
$result = json_encode($message); $result = json_encode($message);
if (in_array($message[0]['calendar_id'], $allowedCalendar)) { if (in_array($message[0]['calendar_id'], $allowedCalendar)) {
+59 -16
View File
@@ -38,11 +38,30 @@ class CalendarModel
'#c8a7d5', '#aad8d0', '#dcadc3', '#d9e8e5', '#e4d8d5', '#c8a7d5', '#aad8d0', '#dcadc3', '#d9e8e5', '#e4d8d5',
'#b4dcc5', '#b9d1e2', '#a3c1c2', '#cdd2b9', '#e3c8ce', '#b4dcc5', '#b9d1e2', '#a3c1c2', '#cdd2b9', '#e3c8ce',
'#aae2c5', '#c7d0cc', '#d0c0da', '#dbdfc8', '#b4e3d7', '#aae2c5', '#c7d0cc', '#d0c0da', '#dbdfc8', '#b4e3d7',
'#c3e4e3', '#c5c4e3', '#d0b7e5', '#b6e98c', '#e3d1de' '#c3e4e3', '#c5c4e3', '#d0b7e5', '#b6e98c', '#e3d1de',
'#dbbeb3', '#e9aebc', '#b5cae7', '#dec2d4', '#aebbd5',
'#e2baaf', '#b6ebd5', '#a9c4bb', '#d7d2c5', '#d7e3d4'
]; ];
public static $specialCalendarColors = array(997 => '#bd0000', 998 => '#8000A3', 999 => '#08769b'); public static $specialCalendarColors = array(997 => '#bd0000', 998 => '#8000A3', 999 => '#08769b');
public static function convertToSummertime($timestamp)
{
// Create a DateTime object from the Unix timestamp
$date = new DateTime();
$date->setTimestamp($timestamp);
// Set the timezone to Europe/Berlin
$date->setTimezone(new DateTimeZone('Europe/Berlin'));
if ($date->format('I') == 1) {
$cest = 7200;
} else {
$cest = 3600;
}
$unixtimestamp = $date->getTimestamp() + $cest;
// Format the date and time
return date('Y-m-d H:i:s', $unixtimestamp);
}
public static function replace_unicode_sequences($string) public static function replace_unicode_sequences($string)
{ {
@@ -96,16 +115,18 @@ class CalendarModel
$rows = array(); $rows = array();
while ($data = $dbcal->fetch_array($res)) { while ($data = $dbcal->fetch_array($res)) {
if ($data['location']) { if ($data['private'] != 1 || $data['calendar_id'] == $r->cal_id) {
$searchName = $data['name'] . " @" . $data['location']; if ($data['location']) {
} else { $searchName = $data['name'] . " @" . $data['location'];
$searchName = $data['name']; } else {
$searchName = $data['name'];
}
$id = $data['id'] . ";" . date("Y-m-d", $data['start_time']);
$rows[] = array(
'id' => $id,
'text' => $searchName . " (" . date("Y-m-d", $data['start_time']) . ")"
);
} }
$id = $data['id'] . ";" . date("Y-m-d", $data['start_time']);
$rows[] = array(
'id' => $id,
'text' => $searchName . " (" . date("Y-m-d", $data['start_time']) . ")"
);
} }
$json['incomplete_results'] = false; $json['incomplete_results'] = false;
$json['total_count'] = count($rows); $json['total_count'] = count($rows);
@@ -118,7 +139,7 @@ class CalendarModel
public static function getCalendarEvents($me, $id = 0, $r = 0) public static function getCalendarEvents($me, $id = 0, $r = 0)
{ {
$rrulefreq = array('daily' => 'DAILY', 'weekly' => 'WEEKLY', 'relativeMonthly' => 'MONTHLY', 'yearly' => 'YEARLY'); $rrulefreq = array('daily' => 'DAILY', 'weekly' => 'WEEKLY', 'relativeMonthly' => 'MONTHLY', 'yearly' => 'YEARLY', 'absoluteMonthly' => 'absoluteMonthly');
$calendar = self::search(array("user_id" => $me)); $calendar = self::search(array("user_id" => $me));
$standardCalendarColors = CalendarModel::$standardCalendarColors; $standardCalendarColors = CalendarModel::$standardCalendarColors;
$calendarColors = json_decode($calendar[0]->colors, true); $calendarColors = json_decode($calendar[0]->colors, true);
@@ -195,7 +216,11 @@ class CalendarModel
if ($data['recurrence']) { if ($data['recurrence']) {
$recurrence = json_decode($data['recurrence'], true); $recurrence = json_decode($data['recurrence'], true);
$rrule_events= json_decode($data['rrule_events'], true); $rrule_events = json_decode($data['rrule_events'], true);
foreach ($rrule_events as $key => $value) {
$rrule_events[$key]['start'] = self::convertToSummertime(strtotime($value['start']));
$rrule_events[$key]['end'] = self::convertToSummertime(strtotime($value['end']));
}
if ($rrulefreq[$recurrence['pattern']['type']]) { if ($rrulefreq[$recurrence['pattern']['type']]) {
unset ($byweekday); unset ($byweekday);
$freq = $rrulefreq[$recurrence['pattern']['type']]; $freq = $rrulefreq[$recurrence['pattern']['type']];
@@ -237,9 +262,20 @@ class CalendarModel
$txtcolor = "#000"; $txtcolor = "#000";
$colorCounter++; $colorCounter++;
} }
$location = $data['location'];
$eventtype = $data['event_type'];
$description = $data['description'];
if ($calenderRights[$data['calendar_id']]) { if ($calenderRights[$data['calendar_id']]) {
$rights = $calenderRights[$data['calendar_id']]; $rights = $calenderRights[$data['calendar_id']];
$CalendarUsers[$data['calendar_id']] = $data['calendar_name']; $CalendarUsers[$data['calendar_id']] = $data['calendar_name'];
if ($data['private'] == 1 && $calendar[0]->go_calendar_id != $data['calendar_id']) {
$name = "Privat";
$attachment = 0;
$attachmentLinks = "";
$location = "";
$eventtype = "1";
$description = "";
}
$rows[] = array( $rows[] = array(
'id' => array('id' => $data['id']), 'id' => array('id' => $data['id']),
'cstart' => array('cstart' => $starttime), 'cstart' => array('cstart' => $starttime),
@@ -250,14 +286,15 @@ class CalendarModel
'bgColor' => array('bgColor' => $bgcolor), 'bgColor' => array('bgColor' => $bgcolor),
'txtColor' => array('txtColor' => $txtcolor), 'txtColor' => array('txtColor' => $txtcolor),
'rights' => array('rights' => $rights, 'order' => $rights), 'rights' => array('rights' => $rights, 'order' => $rights),
'location' => array('location' => $data['location']), 'location' => array('location' => $location),
'busy' => array('busy' => $data['busy']), 'busy' => array('busy' => $data['busy']),
'privateflag' => array('privateflag' => $data['private']),
'allDay' => array('allDay' => $data['all_day_event']), 'allDay' => array('allDay' => $data['all_day_event']),
'rrule' => array('rrule' => $rrule), 'rrule' => array('rrule' => $rrule),
'rrule_events' => array('rrule_events' => $rrule_events), 'rrule_events' => array('rrule_events' => $rrule_events),
'duration' => array('duration' => $duration), 'duration' => array('duration' => $duration),
'event_type' => array('event_type' => $data['event_type']), 'event_type' => array('event_type' => $eventtype),
'description' => array('description' => ($data['description'])), 'description' => array('description' => ($description)),
'attachment' => array('attachment' => $attachment), 'attachment' => array('attachment' => $attachment),
'attachments' => array('attachments' => $attachmentLinks), 'attachments' => array('attachments' => $attachmentLinks),
'calendar_name' => array('calendar_name' => $data['calendar_name']), 'calendar_name' => array('calendar_name' => $data['calendar_name']),
@@ -466,6 +503,7 @@ WHERE `TimerecordingCategory`.`hourday`!='1' AND `TimerecordingCategory`.`hourda
'customer_info' => array('customer_info' => $data['customer_info']), 'customer_info' => array('customer_info' => $data['customer_info']),
'customer_info_send' => array('customer_info_send' => $data['customer_info_send']), 'customer_info_send' => array('customer_info_send' => $data['customer_info_send']),
'customer_info_reminder' => array('customer_info_reminder' => $data['customer_info_reminder']), 'customer_info_reminder' => array('customer_info_reminder' => $data['customer_info_reminder']),
'privateflag' => array('privateflag' => $data['private'], 'order' => $data['private']),
'isorganizer' => array('isorganizer' => $data['is_organizer']), 'isorganizer' => array('isorganizer' => $data['is_organizer']),
'attendees' => array('attendees' => json_encode($AttendeeArray)), 'attendees' => array('attendees' => json_encode($AttendeeArray)),
'organizer' => array('organizer' => $data['organizer']), 'organizer' => array('organizer' => $data['organizer']),
@@ -539,6 +577,7 @@ WHERE `TimerecordingCategory`.`hourday`!='1' AND `TimerecordingCategory`.`hourda
$busy = ($r->busy); $busy = ($r->busy);
$users = ($r->users); $users = ($r->users);
$attendees = ($r->attendees); $attendees = ($r->attendees);
$privateflag = ($r->privateflag);
foreach ($users as $key => $value) { foreach ($users as $key => $value) {
$user_id = $value; $user_id = $value;
} }
@@ -573,6 +612,9 @@ WHERE `TimerecordingCategory`.`hourday`!='1' AND `TimerecordingCategory`.`hourda
if (isset($allday)) if (isset($allday))
$updateArray['all_day_event'] = $allday; $updateArray['all_day_event'] = $allday;
if (isset($privateflag))
$updateArray['private'] = $privateflag;
if (isset($reminder)) { if (isset($reminder)) {
if ($reminder == 'NULL') if ($reminder == 'NULL')
$updateArray['reminder'] = NULL; $updateArray['reminder'] = NULL;
@@ -733,6 +775,7 @@ WHERE `TimerecordingCategory`.`hourday`!='1' AND `TimerecordingCategory`.`hourda
$users = ($r->users); $users = ($r->users);
$customer_info_reminder_check = 0; $customer_info_reminder_check = 0;
$attendees = ($r->attendees); $attendees = ($r->attendees);
$privateflag = ($r->privateflag);
date_default_timezone_set('Europe/Berlin'); date_default_timezone_set('Europe/Berlin');
header('Content-Type: application/json'); header('Content-Type: application/json');
foreach ($users as $key => $value) { foreach ($users as $key => $value) {
@@ -771,7 +814,7 @@ WHERE `TimerecordingCategory`.`hourday`!='1' AND `TimerecordingCategory`.`hourda
$customer_info_send = NULL; $customer_info_send = NULL;
} }
$dataarray = array("start_time" => $start, 'end_time' => $end, 'name' => $title, 'description' => $description, 'location' => $location, 'calendar_id' => $user_id, 'uuid' => "a5eb79b3-fca7-5378-a09e-" . rand(100000000000, 999999999999), 'user_id' => 1, 'timezone' => 'Europe/Amsterdam', 'all_day_event' => 0, 'repeat_end_time' => 0, 'reminder' => $reminder, 'ctime' => time(), 'cname' => $me->name, 'mtime' => time(), 'mname' => $me->name, 'user_id' => 1, 'busy' => $busy, 'status' => 'CONFIRMED', 'resource_event_id' => 0, 'private' => 0, 'rrule' => '', 'background' => 'EBF1E2', 'files_folder_id' => 0, 'read_only' => 0, 'exception_for_event_id' => 0, 'recurrence_id' => 0, 'is_organizer' => 1, 'event_type' => $type, 'customer' => $customer, 'customer_info' => $customer_info, 'customer_info_send' => $customer_info_send, 'customer_info_reminder' => $customer_info_reminder_check); $dataarray = array("start_time" => $start, 'end_time' => $end, 'name' => $title, 'description' => $description, 'location' => $location, 'calendar_id' => $user_id, 'uuid' => "a5eb79b3-fca7-5378-a09e-" . rand(100000000000, 999999999999), 'user_id' => 1, 'timezone' => 'Europe/Amsterdam', 'all_day_event' => 0, 'repeat_end_time' => 0, 'reminder' => $reminder, 'ctime' => time(), 'cname' => $me->name, 'mtime' => time(), 'mname' => $me->name, 'user_id' => 1, 'busy' => $busy, 'status' => 'CONFIRMED', 'resource_event_id' => 0, 'private' => $privateflag, 'rrule' => '', 'background' => 'EBF1E2', 'files_folder_id' => 0, 'read_only' => 0, 'exception_for_event_id' => 0, 'recurrence_id' => 0, 'is_organizer' => 1, 'event_type' => $type, 'customer' => $customer, 'customer_info' => $customer_info, 'customer_info_send' => $customer_info_send, 'customer_info_reminder' => $customer_info_reminder_check);
$db->insert("cal_events", $dataarray); $db->insert("cal_events", $dataarray);
$event_id = $dataarray['uuid']; $event_id = $dataarray['uuid'];
+6 -4
View File
@@ -231,6 +231,12 @@ class PreorderController extends mfBaseController {
$new_filter['addon_services'] = true; $new_filter['addon_services'] = true;
} }
if(array_key_exists("borderpoint", $filter) && $filter['borderpoint'] === 'with') {
$new_filter['add-where'] .= " AND (adb_hausnummer.borderpoint_lat IS NOT NULL AND adb_hausnummer.borderpoint_long IS NOT NULL)";
} elseif(array_key_exists("borderpoint", $filter) && $filter['borderpoint'] === 'without') {
$new_filter['add-where'] .= " AND (adb_hausnummer.borderpoint_lat IS NULL OR adb_hausnummer.borderpoint_long IS NULL)";
}
if(array_key_exists("address_source", $filter)) { if(array_key_exists("address_source", $filter)) {
if($filter['address_source'] == "manual") { if($filter['address_source'] == "manual") {
$new_filter['address_created'] = true; $new_filter['address_created'] = true;
@@ -293,10 +299,6 @@ class PreorderController extends mfBaseController {
} }
} }
/*if(array_key_exists("attributes", $filter) && count($filter['attributes'])) {
}*/
if(is_array($filter) && count($filter)) { if(is_array($filter) && count($filter)) {
foreach($filter as $name => $value) { foreach($filter as $name => $value) {
$new_filter[$name] = $value; $new_filter[$name] = $value;
@@ -7,6 +7,7 @@ class WarehouseArticleController extends TTCrud {
// @formatter:off // @formatter:off
protected array $columns = [ protected array $columns = [
['key' => 'title', 'text' => 'Titel', 'required' => true, 'table' => ['priority' => 9]], ['key' => 'title', 'text' => 'Titel', 'required' => true, 'table' => ['priority' => 9]],
['key' => 'articleNumber', 'text' => 'Nr.', 'required' => true],
['key' => 'description', 'text' => 'Beschreibung', 'required' => true], ['key' => 'description', 'text' => 'Beschreibung', 'required' => true],
['key' => 'category', 'text' => 'Kategorie', 'required' => true], ['key' => 'category', 'text' => 'Kategorie', 'required' => true],
['key' => 'unit', 'text' => 'Einheit', 'required' => true,'table' => false], // Boolean value ['key' => 'unit', 'text' => 'Einheit', 'required' => true,'table' => false], // Boolean value
@@ -253,6 +254,48 @@ class WarehouseArticleController extends TTCrud {
} }
} }
protected function provArticleNumberImportAction() {
// if method is post and file is set read the csv and var dump json and die
// if method is get return basic html with a form to upload a file and a submit button
if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_FILES['file'])) {
$file = fopen($_FILES['file']['tmp_name'], 'r');
$data = [];
// parse csv as object with first row as keys as header and use key => value
$firstRow = true;
while (($row = fgetcsv($file)) !== false) {
if ($firstRow) {
$header = $row;
$firstRow = false;
continue;
}
$data[] = array_combine($header, $row);
}
// loop through all the data and if PRODUKT 1.ZEILE is set and articleNumber is not set push the last 4 numbers of "EAN 13 Code" to articleNumber of the found article
foreach ($data as $item) {
if (isset($item['PRODUKT 1.ZEILE'])) {
$articles = WarehouseArticleModel::getAll(['title' => $item['PRODUKT 1.ZEILE']]);
if (!empty($articles)) {
$article = (array) WarehouseArticleModel::get($articles[0]->id);
$article['articleNumber'] = substr($item['EAN 13 Code'], -4);
WarehouseArticleModel::update($article);
}
}
}
fclose($file);
die(json_encode(['success' => true]));
}
$html = '<html><head></head><body><form method="post" enctype="multipart/form-data"><input type="file" name="file"><input type="submit"></form></body></html>';
echo $html;
die();
}
protected function prepareOrderAction() { protected function prepareOrderAction() {
// inside post json it will look like // inside post json it will look like
// [ // [
@@ -3,6 +3,7 @@
class WarehouseArticleModel extends TTCrudBaseModel { class WarehouseArticleModel extends TTCrudBaseModel {
public int $id; public int $id;
public string $title; public string $title;
public string $articleNumber;
public string $description; public string $description;
public string $category; public string $category;
public ?float $cheapestPurchasePrice; public ?float $cheapestPurchasePrice;
@@ -28,6 +28,13 @@ class WarehouseEShopController extends TTCrud {
return $this->user->can(["WarehouseEShop"]); return $this->user->can(["WarehouseEShop"]);
} }
protected function prepareCrudConfig() {
if (!$this->user->can('WarehouseAdmin')) {
$this->columns[2]['table'] = false;
}
}
public function getAction() { public function getAction() {
$filter = $this->postData['filters'] ?? []; $filter = $this->postData['filters'] ?? [];
$order = $this->postData['order'] ?? ['key' => null, 'order' => 'ASC']; $order = $this->postData['order'] ?? ['key' => null, 'order' => 'ASC'];
@@ -4,62 +4,70 @@ class WarehouseEShopOrderController extends TTCrud {
protected string $headerTitle = 'Energie Steiermark Bestellungen'; protected string $headerTitle = 'Energie Steiermark Bestellungen';
protected bool $createText = false; protected bool $createText = false;
protected array $columns = [['key' => 'id', 'text' => 'ID', 'modal' => false], //@formatter:off
['key' => 'extRef', 'text' => 'Externe Referenz', 'required' => true], protected array $columns = [
['key' => 'status', ['key' => 'id', 'text' => 'ID', 'modal' => false],
'text' => 'Status', ['key' => 'extRef', 'text' => 'Externe Referenz', 'required' => true],
'required' => true, ['key' => 'status', 'text' => 'Status', 'required' => true, 'modal' => ['type' => 'select', 'items' => [['value' => 'new', 'text' => 'Neu'], ['value' => 'accepted', 'text' => 'An Lieferant übergeben'], ['value' => 'acceptedInternally', 'text' => 'Interne verarbeitung'], ['value' => 'sent', 'text' => 'Gesendet'], ['value' => 'done', 'text' => 'Erledigt'],]], 'table' => ['filter' => 'select']],
'modal' => ['type' => 'select', ['key' => 'shippingNoteStatus', 'text' => 'LS-Status', 'required' => false, 'modal' => false, 'table' => ['filter' => false, 'order' => false]],
'items' => [['value' => 'new', 'text' => 'Neu'], ['key' => 'deliveryMode', 'text' => 'Liefermodus', 'required' => true, 'modal' => ['type' => 'select', 'items' => [['value' => 'singleAddress', 'text' => 'Einzelne Adresse']]]],
['value' => 'accepted', 'text' => 'An Lieferant übergeben'], ['key' => 'deliveryAddressName', 'text' => 'Name', 'required' => true],
['value' => 'acceptedInternally', 'text' => 'Interne verarbeitung'], ['key' => 'deliveryAddressLine', 'text' => 'Adresse', 'required' => true, 'required_length' => 4],
['value' => 'sent', 'text' => 'Gesendet'], ['key' => 'deliveryAddressPLZ', 'text' => 'PLZ', 'required' => true, 'regex' => '/^\d{4}$/'],
['value' => 'done', 'text' => 'Erledigt'],]], ['key' => 'deliveryAddressCity', 'text' => 'Stadt', 'required' => true, 'required_length' => 3],
'table' => ['filter' => 'select']], ['key' => 'trackingNumber', 'text' => 'Trackingnummer', 'required' => false, 'modal' => false],
['key' => 'deliveryMode', ['key' => 'positions', 'text' => 'Positionen', 'required' => false, 'table' => false],
'text' => 'Liefermodus', ['key' => 'create', 'text' => 'Erstellt', 'required' => true, 'modal' => false, 'filter' => 'datetime'],
'required' => true, ['key' => 'createBy', 'text' => 'Erstellt von', 'required' => true, 'table' => ['filter' => 'select'], 'modal' => ['type' => 'select', 'items' => []]],
'modal' => ['type' => 'select', ['key' => 'actions', 'text' => 'Aktionen', 'required' => false, 'modal' => false, 'table' => ['filter' => false, 'sortable' => false, 'class' => 'text-center']]
'items' => [['value' => 'singleAddress', 'text' => 'Einzelne Adresse'], ];
// ['value' => 'multipleAddresses', 'text' => 'Mehrere Adressen'],
]]],
['key' => 'deliveryAddressName', 'text' => 'Name', 'required' => true],
['key' => 'deliveryAddressLine', 'text' => 'Adresse', 'required' => true, 'required_length' => 4],
['key' => 'deliveryAddressPLZ', 'text' => 'PLZ', 'required' => true, 'regex' => '/^\d{4}$/'],
['key' => 'deliveryAddressCity', 'text' => 'Stadt', 'required' => true, 'required_length' => 3],
['key' => 'trackingNumber', 'text' => 'Trackingnummer', 'required' => false, 'modal' => false],
['key' => 'create', 'text' => 'Erstellt', 'required' => true, 'modal' => false, 'filter' => 'datetime'],
['key' => 'createBy',
'text' => 'Erstellt von',
'required' => true,
'table' => ['filter' => 'select'],
'modal' => ['type' => 'select', 'items' => []]],
['key' => 'actions',
'text' => 'Aktionen',
'required' => false,
'modal' => false,
'table' => ['filter' => false, 'sortable' => false, 'class' => 'text-center']],];
protected array $additionalActions = [['key' => 'openHistory', 'title' => 'Historie', 'class' => 'fas fa-history text-primary'], protected array $additionalActions = [
['key' => 'showTrackingHistory', 'title' => 'Tracking Historie', 'class' => 'fas fa-truck text-primary'], ['key' => 'openHistory', 'title' => 'Historie', 'class' => 'fas fa-history text-primary'],
['key' => 'createShippingNote', 'title' => 'Lieferschein erstellen', 'class' => 'fas fa-file-invoice text-primary'], ['key' => 'showTrackingHistory', 'title' => 'Tracking Historie', 'class' => 'fas fa-truck text-primary'],
['key' => 'openSingleOrderEmail', 'title' => 'Bestellbestätigung', 'class' => 'fas fa-envelope text-primary'],]; ['key' => 'createShippingNote', 'title' => 'Lieferschein erstellen', 'class' => 'fas fa-file-invoice text-primary'],
['key' => 'openSingleOrderEmail', 'title' => 'Bestellbestätigung', 'class' => 'fas fa-envelope text-primary']#
];
protected array $infoMessages = ['create' => 'Bestellung wurde erfolgreich erstellt, sie erhalten in Kürze eine Bestätigungsmail', protected array $infoMessages = [
'update' => 'Bestellung wurde aktualisiert', 'create' => 'Bestellung wurde erfolgreich erstellt, sie erhalten in Kürze eine Bestätigungsmail',
'delete' => 'Bestellung wurde gelöscht', 'update' => 'Bestellung wurde aktualisiert',
'noChanges' => 'Keine Änderungen',]; 'delete' => 'Bestellung wurde gelöscht',
'noChanges' => 'Keine Änderungen'
];
//@formatter:on
public function permissionCheck(): bool { public function permissionCheck(): bool {
return $this->user->can(["WarehouseEShop"]); return $this->user->can(["WarehouseEShop"]);
} }
protected function customRowsHandler($rows): array {
$statusToText = [
'new' => 'Neu',
'accepted' => 'Akzeptiert',
'invoiced' => 'Verrechnet',
'in_progress' => 'In Bearbeitung',
];
foreach ($rows as $row) {
$shippingNote = WarehouseShippingNoteModel::getAll(['eShopOrderId' => $row->id]);
if (empty($shippingNote)) {
$row->shippingNoteStatus = 'Kein LS';
} else {
$row->shippingNoteStatus = $statusToText[$shippingNote[0]->status];
}
}
return $rows;
}
protected function prepareCrudConfig() { protected function prepareCrudConfig() {
$users = array_map(function ($user) { $users = array_map(function ($user) {
return ['value' => intval($user->id), 'text' => $user->name]; return ['value' => intval($user->id), 'text' => $user->name];
}, UserModel::search()); }, UserModel::search());
$this->columns[10]['modal']['items'] = $users; $createByIndex = array_search('createBy', array_column($this->columns, 'key'));
$this->columns[$createByIndex]['modal']['items'] = $users;
} }
protected function createShippingNote() { protected function createShippingNote() {
@@ -71,7 +79,9 @@ class WarehouseEShopOrderController extends TTCrud {
$existingShippingNote = WarehouseShippingNoteModel::getAll(['eShopOrderId' => $id]); $existingShippingNote = WarehouseShippingNoteModel::getAll(['eShopOrderId' => $id]);
if (!empty($existingShippingNote)) { if (!empty($existingShippingNote)) {
self::returnJson(['success' => false, 'message' => 'Für diese Bestellung existiert bereits ein Lieferschein', 'shippingNoteId' => $existingShippingNote[0]->id]); self::returnJson(['success' => false,
'message' => 'Für diese Bestellung existiert bereits ein Lieferschein',
'shippingNoteId' => $existingShippingNote[0]->id]);
die(); die();
} }
@@ -120,9 +130,12 @@ class WarehouseEShopOrderController extends TTCrud {
'deliveryAddressLine' => $order->deliveryAddressLine, 'deliveryAddressLine' => $order->deliveryAddressLine,
'deliveryAddressPLZ' => $order->deliveryAddressPLZ, 'deliveryAddressPLZ' => $order->deliveryAddressPLZ,
'deliveryAddressCity' => $order->deliveryAddressCity, 'deliveryAddressCity' => $order->deliveryAddressCity,
'deliveryAddressEMail' => '',
'note' => 'Erstellung aus Energie Steiermark Shop Bestellung #' . $id,
'status' => 'new', 'status' => 'new',
'positions' => $positions, 'positions' => $positions,
'textElements' => '[]', 'textElements' => '[]',
'hoursEntries' => '[]',
'eShopOrderId' => $id, 'eShopOrderId' => $id,
'create' => time(), 'create' => time(),
'createBy' => $this->user->id]); 'createBy' => $this->user->id]);
@@ -277,7 +290,8 @@ class WarehouseEShopOrderController extends TTCrud {
} }
protected function getAllOrderItemsPerOrder(): array { protected function getAllOrderItemsPerOrder(): array {
$items = WarehouseEShopOrderItemModel::getAll(); if (isset($_GET['orderId'])) return WarehouseEShopOrderItemModel::getAll(['orderId' => $_GET['orderId']]);
else $items = WarehouseEShopOrderItemModel::getAll();
$articles = WarehouseArticleModel::getAll(); $articles = WarehouseArticleModel::getAll();
$articlePackets = WarehouseArticlePacketModel::getAll(); $articlePackets = WarehouseArticlePacketModel::getAll();
@@ -384,7 +398,13 @@ class WarehouseEShopOrderController extends TTCrud {
die(json_encode($json)); die(json_encode($json));
} }
protected function beforeCreate(): bool {
unset($this->postData['shippingNoteStatus']);
return true;
}
protected function beforeUpdate($postData): bool { protected function beforeUpdate($postData): bool {
unset($this->postData['shippingNoteStatus']);
(new WarehouseHistoryController)->create($postData, $this->mod); (new WarehouseHistoryController)->create($postData, $this->mod);
return true; return true;
} }
@@ -430,17 +450,17 @@ class WarehouseEShopOrderController extends TTCrud {
} }
protected function readGLSEmailAction() { protected function readGLSEmailAction() {
function decode_utf8($str){ function decode_utf8($str) {
# paterns # paterns
$err="(=\?.{10,13}q\?_?|\?\=)"; $err = "(=\?.{10,13}q\?_?|\?\=)";
$pat = "/=([0-9A-F]{2})/"; $pat = "/=([0-9A-F]{2})/";
$cha="'.chr(hexdec("; $cha = "'.chr(hexdec(";
# erase null signs in string # erase null signs in string
$str = str_replace("\x00", "", $str); $str = str_replace("\x00", "", $str);
# to decode with eval and replace # to decode with eval and replace
eval("\$str='". eval("\$str='" .
preg_replace($pat,$cha."'$1')).'",$str) preg_replace($pat, $cha . "'$1')).'", $str)
."';"); . "';");
# return # return
return $str; return $str;
} }
@@ -571,4 +591,71 @@ class WarehouseEShopOrderController extends TTCrud {
$result = []; $result = [];
} }
protected function updatePositionAction() {
$json = json_decode(file_get_contents('php://input'), true);
$id = intval($json['id']);
$articleId = $json['articleId'] ? intval($json['articleId']) : null;
$articlePacketId = $json['articlePacketId'] ? intval($json['articlePacketId']) : null;
$quantity = intval($json['quantity']);
if (!$id || !$quantity) {
self::returnJson(['success' => false, 'message' => 'Ungültige Daten']);
die();
}
$position = (array) WarehouseEShopOrderItemModel::get($id);
if (!$position) {
self::returnJson(['success' => false, 'message' => 'Position nicht gefunden']);
die();
}
$position['articleId'] = $articleId;
$position['articlePacketId'] = $articlePacketId;
$position['quantity'] = $quantity;
WarehouseEShopOrderItemModel::update($position);
self::returnJson(['success' => true, 'position' => $position]);
}
protected function deletePositionAction() {
$json = json_decode(file_get_contents('php://input'), true);
$id = intval($json['id']);
if (!$id) {
self::returnJson(['success' => false, 'message' => 'Keine ID angegeben']);
die();
}
$position = WarehouseEShopOrderItemModel::get($id);
if (!$position) {
self::returnJson(['success' => false, 'message' => 'Position nicht gefunden']);
die();
}
WarehouseEShopOrderItemModel::delete($id);
self::returnJson(['success' => true, 'message' => 'Position gelöscht']);
}
protected function addPositionAction() {
$json = json_decode(file_get_contents('php://input'), true);
$orderId = intval($json['orderId']);
$articleId = $json['articleId'] ? intval($json['articleId']) : null;
$articlePacketId = $json['articlePacketId'] ? intval($json['articlePacketId']) : null;
$quantity = intval($json['quantity']);
if (!$orderId || !$quantity) {
self::returnJson(['success' => false, 'message' => 'Ungültige Daten']);
die();
}
$position = WarehouseEShopOrderItemModel::create(['orderId' => $orderId,
'articleId' => $articleId,
'articlePacketId' => $articlePacketId,
'quantity' => $quantity]);
$position = (array) WarehouseEShopOrderItemModel::get($position);
self::returnJson(['success' => true, 'position' => $position]);
}
} }
@@ -13,10 +13,10 @@ class WarehouseShippingNoteController extends TTCrud {
['key' => 'deliveryAddressPLZ', 'text' => 'L.-Adr. PLZ', 'required' => true], ['key' => 'deliveryAddressPLZ', 'text' => 'L.-Adr. PLZ', 'required' => true],
['key' => 'deliveryAddressEMail', 'text' => 'L.-Adr. EMail', 'required' => false, 'table' => false], ['key' => 'deliveryAddressEMail', 'text' => 'L.-Adr. EMail', 'required' => false, 'table' => false],
['key' => 'note', 'text' => 'Art der Arbeit', 'required' => true, 'table' => false], ['key' => 'note', 'text' => 'Art der Arbeit', 'required' => true, 'table' => false],
['key' => 'status', 'text' => 'Status', 'required' => true, 'table' => ['filter' => 'select'], 'modal' => ['type' => 'select', 'items' => [['value' => 'new', 'text' => 'Neu'], ['value' => 'inProgress', 'text' => 'In Bearbeitung'], ['value' => 'accepted', 'text' => 'Akzeptiert'], ['value' => 'invoiced', 'text' => 'In Rechnung gestellt'],]]], ['key' => 'status', 'text' => 'Status', 'required' => true, 'table' => ['filter' => 'select'], 'modal' => ['type' => 'select', 'items' => [['value' => 'new', 'text' => 'Neu'], ['value' => 'in_progress', 'text' => 'In Bearbeitung'], ['value' => 'accepted', 'text' => 'Akzeptiert'], ['value' => 'invoiced', 'text' => 'In Rechnung gestellt'],]]],
['key' => 'positions', 'text' => 'Positionen', 'required' => true, 'table' => false, 'modal' => false], ['key' => 'positions', 'text' => 'Positionen', 'required' => true, 'table' => false, 'modal' => false],
['key' => 'create', 'text' => 'Erstellt', 'required' => false, 'modal' => false, 'table' => ['filter' => 'date']], ['key' => 'create', 'text' => 'Erstellt', 'required' => false, 'modal' => ['visible' => false], 'table' => ['filter' => 'date']],
['key' => 'createBy', 'text' => 'Erstellt von', 'required' => true, 'type' => 'autocomplete', 'table' => ['class' => 'text-nowrap', 'filter' => 'select'], 'modal' => ['items' => [], 'type' => 'select',]], ['key' => 'createBy', 'text' => 'Erstellt von', 'required' => false, 'type' => 'autocomplete', 'table' => ['class' => 'text-nowrap', 'filter' => 'select'], 'modal' => ['items' => [], 'type' => 'select',]],
['key' => 'actions', 'text' => 'Aktionen', 'required' => false, 'modal' => false, 'table' => ['filter' => false, 'sortable' => false, 'class' => 'text-center']],]; ['key' => 'actions', 'text' => 'Aktionen', 'required' => false, 'modal' => false, 'table' => ['filter' => false, 'sortable' => false, 'class' => 'text-center']],];
protected array $defaultOrder = ['key' => 'create', 'order' => 'DESC']; protected array $defaultOrder = ['key' => 'create', 'order' => 'DESC'];
@@ -54,6 +54,14 @@ class WarehouseShippingNoteController extends TTCrud {
die(); die();
} }
foreach ($postData['hoursEntries'] as $hoursEntry) {
if (!preg_match('/^[0-9,.]*$/', $hoursEntry['hourCount'])) {
http_response_code(500);
self::returnJson(['success' => false, 'message' => 'Stundenanzahl darf nur Zahlen, Komma oder Punkt enthalten']);
die();
}
}
$postData['positions'] = json_encode($postData['positions']); $postData['positions'] = json_encode($postData['positions']);
return true; return true;
} }
@@ -77,6 +85,13 @@ class WarehouseShippingNoteController extends TTCrud {
die(); die();
} }
foreach ($postData['hoursEntries'] as $hoursEntry) {
if (!preg_match('/^[0-9,.]*$/', $hoursEntry['hourCount'])) {
http_response_code(500);
self::returnJson(['success' => false, 'message' => 'Stundenanzahl darf nur Zahlen, Komma oder Punkt enthalten']);
die();
}
}
$postData['positions'] = json_encode($postData['positions']); $postData['positions'] = json_encode($postData['positions']);
(new WarehouseHistoryController)->create($postData, $this->mod); (new WarehouseHistoryController)->create($postData, $this->mod);
@@ -218,7 +233,16 @@ class WarehouseShippingNoteController extends TTCrud {
foreach (json_decode($shippingNote->positions, true) as $position) { foreach (json_decode($shippingNote->positions, true) as $position) {
if (isset($position['article'])) { if (isset($position['article'])) {
$article = WarehouseArticleModel::get($position['article']); $article = WarehouseArticleModel::get($position['article']);
$position['articleTitle'] = $article->title; if (isset($article->articleNumber)) {
$position['articleTitle'] = $article->articleNumber . " | " . $article->title;
} else {
$position['articleTitle'] = $article->title;
}
if (isset($position['isEnergieMaterial']) && $position['isEnergieMaterial'] == 1) {
$position['articleTitle'] .= " (ESTMK)";
}
$position['articleDescription'] = $article->description === $article->title ? "" : $article->description; $position['articleDescription'] = $article->description === $article->title ? "" : $article->description;
$position['articleUnit'] = $article->unit; $position['articleUnit'] = $article->unit;
$positions[] = $position; $positions[] = $position;
@@ -240,18 +264,27 @@ class WarehouseShippingNoteController extends TTCrud {
$hoursEntries = json_decode($shippingNote->hoursEntries, true); $hoursEntries = json_decode($shippingNote->hoursEntries, true);
foreach ($hoursEntries as $hoursEntry) { foreach ($hoursEntries as $hoursEntry) {
// die(json_encode($hoursEntry)); // die(json_encode($hoursEntry));
$positions[] = [ $articleTitle = "Arbeitsstunden";
'articleTitle' => "Arbeitsstunden", if (isset($hoursEntry['priceType']) && $hoursEntry['priceType'] == 50) {
'articleDescription' => "Datum: ". date("d.m.Y", strtotime($hoursEntry['date'])) . " | Mitarbeiter: " . UserModel::getOne($hoursEntry['userId'])->name, $articleTitle = "Arbeitsstunden (50% Zuschlag)";
'articleUnit' => 'Std.', } elseif (isset($hoursEntry['priceType']) && $hoursEntry['priceType'] == 100) {
'amount' => $hoursEntry['hourCount'], $articleTitle = "Arbeitsstunden (100% Zuschlag)";
'price' => $hoursEntry['hourlyPrice'] * $hoursEntry['hourCount'] ?? 0, }
];
if (floatval(str_replace(",", ".", $hoursEntry['hourCount'])) > 0) {
$positions[] = [
'articleTitle' => $articleTitle,
'articleDescription' => "Datum: ". date("d.m.Y", strtotime($hoursEntry['date'])) . " | Mitarbeiter: " . UserModel::getOne($hoursEntry['userId'])->name,
'articleUnit' => 'Std.',
'amount' => $hoursEntry['hourCount'],
'price' => $hoursEntry['hourlyPrice'] * $hoursEntry['hourCount'] ?? 0,
];
}
if ($hoursEntry['carId']) { if ($hoursEntry['carId']) {
$positions[] = [ $positions[] = [
'articleTitle' => "Fahrkostenpauschale", 'articleTitle' => "Fahrkostenpauschale (hin und retour)",
'articleDescription' => "Fahrzeug: " . TimerecordingCarModel::getOne($hoursEntry['carId'])->number_plate, 'articleDescription' => "Datum: ". date("d.m.Y", strtotime($hoursEntry['date'])) . " | Fahrzeug: " . TimerecordingCarModel::getOne($hoursEntry['carId'])->number_plate,
'articleUnit' => 'Km', 'articleUnit' => 'Km',
'amount' => $hoursEntry['kilometerCount'], 'amount' => $hoursEntry['kilometerCount'],
'price' => 1 * $hoursEntry['kilometerCount'] ?? 0, 'price' => 1 * $hoursEntry['kilometerCount'] ?? 0,
@@ -261,6 +294,21 @@ class WarehouseShippingNoteController extends TTCrud {
} }
usort($positions, function ($a, $b) {
$aHasMitarbeiter = str_contains($a['articleDescription'], 'Mitarbeiter');
$bHasMitarbeiter = str_contains($b['articleDescription'], 'Mitarbeiter');
$aHasFahrzeug = str_contains($a['articleDescription'], 'Fahrzeug');
$bHasFahrzeug = str_contains($b['articleDescription'], 'Fahrzeug');
if ($aHasMitarbeiter && !$bHasMitarbeiter) return -1;
if (!$aHasMitarbeiter && $bHasMitarbeiter) return 1;
if ($aHasFahrzeug && !$bHasFahrzeug) return -1;
if (!$aHasFahrzeug && $bHasFahrzeug) return 1;
return 0;
});
$textElements = []; $textElements = [];
// parse shippingNote.textElements ({"1":true,"2":true}) to array, fetch each text element and put content into array // parse shippingNote.textElements ({"1":true,"2":true}) to array, fetch each text element and put content into array
$shippingNoteTextElements = json_decode($shippingNote->textElements, true); $shippingNoteTextElements = json_decode($shippingNote->textElements, true);
@@ -349,6 +397,28 @@ class WarehouseShippingNoteController extends TTCrud {
self::returnJson(array_values($out)); self::returnJson(array_values($out));
} }
protected function changeStatusAction() {
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
$json = json_decode(file_get_contents('php://input'), true);
$id = $json['id'];
$status = $json['status'];
if (strlen($id) < 1) {
http_response_code(500);
self::returnJson(['success' => false, 'message' => 'Lieferschein wurde nicht gefunden']);
}
$shippingNote = (array) WarehouseShippingNoteModel::get($id);
if ($shippingNote['status'] === 'invoiced') {
http_response_code(500);
self::returnJson(['success' => false, 'message' => 'Status kann nicht geändert werden']);
}
$shippingNote['status'] = $status;
WarehouseShippingNoteModel::update($shippingNote);
self::returnJson(['success' => true, 'message' => 'Status wurde geändert']);
}
//TODO: either move this to TimerecordingCarController or make it better //TODO: either move this to TimerecordingCarController or make it better
protected function timerecordingCarAutoCompleteAction() { protected function timerecordingCarAutoCompleteAction() {
$timerecordingCars = array_map(function ($timerecordingCar) { $timerecordingCars = array_map(function ($timerecordingCar) {
@@ -498,4 +568,4 @@ class WarehouseShippingNoteController extends TTCrud {
self::returnJson(['success' => true, 'distance' => $roundedDistanceKm]); self::returnJson(['success' => true, 'distance' => $roundedDistanceKm]);
} }
} }
@@ -17,8 +17,8 @@ class WarehouseShippingNoteModel extends TTCrudBaseModel {
public ?string $signatureName; public ?string $signatureName;
public ?string $signatureDate; public ?string $signatureDate;
public ?int $eShopOrderId; public ?int $eShopOrderId;
public int $create; public ?int $create;
public int $createBy; public ?int $createBy;
} }
@@ -0,0 +1,33 @@
<?php /** @noinspection ALL */
declare(strict_types=1);
use Phinx\Migration\AbstractMigration;
final class WarehouseModify5 extends AbstractMigration {
public function up(): void {
if ($this->getEnvironment() == "thetool") {
$WarehouseHistory = $this->table("WarehouseHistory", ["signed" => true]);
$WarehouseHistory->changeColumn("old_value", "text", ["null" => true]);
$WarehouseHistory->changeColumn("new_value", "text", ["null" => true]);
$WarehouseHistory->save();
}
if ($this->getEnvironment() == "addressdb") {
}
}
public function down(): void {
if ($this->getEnvironment() == "thetool") {
$WarehouseHistory = $this->table("WarehouseHistory", ["signed" => true]);
$WarehouseHistory->changeColumn("old_value", "string", ["null" => true, "limit" => 255]);
$WarehouseHistory->changeColumn("new_value", "string", ["null" => true, "limit" => 255]);
$WarehouseHistory->save();
}
if ($this->getEnvironment() == "addressdb") {
}
}
}
@@ -0,0 +1,31 @@
<?php /** @noinspection ALL */
declare(strict_types=1);
use Phinx\Migration\AbstractMigration;
final class WarehouseModify6 extends AbstractMigration {
public function up(): void {
if ($this->getEnvironment() == "thetool") {
// add articleNumber varchar 255 to the table WarehouseArticle
$WarehouseArticle = $this->table("WarehouseArticle", ["signed" => true]);
$WarehouseArticle->addColumn("articleNumber", "string", ["null" => false, "limit" => 255]);
$WarehouseArticle->save();
}
if ($this->getEnvironment() == "addressdb") {
}
}
public function down(): void {
if ($this->getEnvironment() == "thetool") {
$WarehouseArticle = $this->table("WarehouseArticle", ["signed" => true]);
$WarehouseArticle->removeColumn("articleNumber");
$WarehouseArticle->save();
}
if ($this->getEnvironment() == "addressdb") {
}
}
}
+10 -6
View File
@@ -165,6 +165,10 @@ class TTCrud extends mfBaseController {
} }
} }
if (method_exists($this, 'customRowsHandler')) {
$rows = $this->customRowsHandler($rows);
}
self::returnJson(["rows" => $rows, self::returnJson(["rows" => $rows,
"autoCompleteData" => $autocompleteData, "autoCompleteData" => $autocompleteData,
"pagination" => ["page" => $page, "pagination" => ["page" => $page,
@@ -201,12 +205,12 @@ class TTCrud extends mfBaseController {
} }
protected function updateAction() { protected function updateAction() {
if (property_exists($this->model, 'createBy') && !isset($this->postData['createBy'])) { // if (property_exists($this->model, 'createBy') && !isset($this->postData['createBy'])) {
$this->postData['createBy'] = $this->user->id; // $this->postData['createBy'] = $this->user->id;
} // }
if (property_exists($this->model, 'create') && !isset($this->postData['create'])) { // if (property_exists($this->model, 'create') && !isset($this->postData['create'])) {
$this->postData['create'] = time(); // $this->postData['create'] = time();
} // }
Helper::validateArray($this->postData, array_merge($this->checkArray, ['id' => ['required' => true]])); Helper::validateArray($this->postData, array_merge($this->checkArray, ['id' => ['required' => true]]));
+37
View File
@@ -50,5 +50,42 @@ class XinonProject {
return $response; return $response;
} }
/**
* Search for support tickets using a global search in Xinon OpenProject.
* @param string $search - The search query.
* @param int $pageSize - The number of results to return.
* @return array - The search results.
*/
public function searchSupportTickets(string $search, int $pageSize = 25): array {
$curl = curl_init();
$baseUrl = 'https://project.xinon.at/api/v3/projects/10/work_packages';
$queryParams = [
'pageSize' => 25,
'filters' => json_encode([['search' => ['operator' => '**', 'values' => [$search]]]])
];
curl_setopt_array($curl, array(
CURLOPT_URL => $baseUrl . '?' . http_build_query($queryParams),
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => '',
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_HTTPHEADER => array('Content-Type: application/json'),
CURLOPT_USERPWD => 'apikey:' . PROJECT_API_KEY
));
$response = curl_exec($curl);
curl_close($curl);
$json = json_decode($response, true);
return $json['_embedded']['elements'];
}
} }
?> ?>
+64 -2
View File
@@ -1,17 +1,19 @@
.fc-event { .fc-event {
border-radius: 2px; border-radius: 2px;
border: none; border: none;
cursor: move; cursor: no-drop;
font-size: 13px; font-size: 13px;
margin: 3px 7px; margin: 3px 7px;
padding: 1px 5px; padding: 1px 5px;
text-align: center; text-align: center;
} }
.fc-timegrid-event-short .fc-event-main-frame { .fc-timegrid-event-short .fc-event-main-frame {
flex-direction: row; flex-direction: row;
overflow: hidden; overflow: hidden;
margin-left: 10px; margin-left: 10px;
} }
.fc-toolbar { .fc-toolbar {
@media (max-width: 767px) { @media (max-width: 767px) {
flex-direction: column; flex-direction: column;
@@ -184,6 +186,18 @@ thead .fc-day-today .fc-scrollgrid-sync-inner .fc-col-header-cell-cushion {
color: #fff; color: #fff;
} }
.fc-scroller-harness-liquid {
overflow: visible;
}
.fc .fc-scroller-harness-liquid {
height: 700px;
}
.card {
overflow: auto;
}
.card-fullscreen { .card-fullscreen {
display: block; display: block;
z-index: 1040; z-index: 1040;
@@ -311,6 +325,12 @@ thead .fc-day-today .fc-scrollgrid-sync-inner .fc-col-header-cell-cushion {
top: 0; top: 0;
} }
.fc-event-attachment-mr {
position: absolute;
right: 11px;
top: 0;
}
.fc-event-type { .fc-event-type {
position: absolute; position: absolute;
top: 0; top: 0;
@@ -322,6 +342,14 @@ thead .fc-day-today .fc-scrollgrid-sync-inner .fc-col-header-cell-cushion {
bottom: -4px; bottom: -4px;
left: -4px; left: -4px;
} }
.fc-event-private {
position: absolute;
top: 0px;
right: -2px;
}
.fc-timegrid-event-short .fc-event-time::after { .fc-timegrid-event-short .fc-event-time::after {
content: ""; content: "";
} }
@@ -498,7 +526,7 @@ thead .fc-day-today .fc-scrollgrid-sync-inner .fc-col-header-cell-cushion {
#calendar-side-div { #calendar-side-div {
max-height: 850px; max-height: 850px;
overflow: scroll; overflow: auto;
} }
/* width */ /* width */
@@ -611,4 +639,38 @@ thead .fc-day-today .fc-scrollgrid-sync-inner .fc-col-header-cell-cushion {
.fa-arrow-right-from-bracket { .fa-arrow-right-from-bracket {
color: #0600ff; color: #0600ff;
cursor: pointer; cursor: pointer;
}
.fa-unlock:after {
color: #000;
opacity: 0.7;
}
.fa-unlock:before {
color: #cd0909;
}
.fa-lock:after {
color: #000;
opacity: 0.7;
}
.modal-body .fa-lock:before {
color: #0ab900;
}
.cal-group-name {
display: inline-block;
max-width: 170px;
margin-left: 10px;
}
.group-checkbox {
margin-left: -28px;
margin-top: 4px;
}
.cursor-alias{
cursor: alias;
} }
+143 -28
View File
@@ -63,6 +63,7 @@ function getOffset(unixTimestamp) {
document.addEventListener('DOMContentLoaded', function () { document.addEventListener('DOMContentLoaded', function () {
let checkbox = $(".form-check-input"); let checkbox = $(".form-check-input");
let visibleCalendars = []; let visibleCalendars = [];
let mycalendar_id = $('#calendar-id').data('calendarid');
visibleCalendars.push(0); visibleCalendars.push(0);
checkbox.each(function () { checkbox.each(function () {
if ($(this).prop('checked')) { if ($(this).prop('checked')) {
@@ -86,6 +87,7 @@ document.addEventListener('DOMContentLoaded', function () {
var duration = null; var duration = null;
var rruleflag = false; var rruleflag = false;
let allDAy; let allDAy;
let cursorclass = "";
$.each($('.calendar-check'), function (index, value) { $.each($('.calendar-check'), function (index, value) {
if ($(this).prop('checked')) { if ($(this).prop('checked')) {
rights = true; rights = true;
@@ -108,7 +110,7 @@ document.addEventListener('DOMContentLoaded', function () {
duration = null; duration = null;
rruleflag = false; rruleflag = false;
category = value.ccategory.ccategory; category = value.ccategory.ccategory;
cursorclass = "";
if (value.calendar_id.calendar_id in calendarRights) { if (value.calendar_id.calendar_id in calendarRights) {
if (calendarRights[value.calendar_id.calendar_id] == 'all') { if (calendarRights[value.calendar_id.calendar_id] == 'all') {
@@ -116,8 +118,18 @@ document.addEventListener('DOMContentLoaded', function () {
} else { } else {
rights = false; rights = false;
} }
if (value.privateflag.privateflag == '1' && mycalendar_id != value.calendar_id.calendar_id) {
rights = false;
}
if (value.isorganizer.isorganizer == '1' && rights) { if (value.isorganizer.isorganizer == '1' && rights) {
movable = true; movable = true;
} else if (rights) {
movable = false;
cursorclass = "cursor-alias";
} else { } else {
movable = false; movable = false;
} }
@@ -147,9 +159,10 @@ document.addEventListener('DOMContentLoaded', function () {
attachments: value.attachments.attachments, attachments: value.attachments.attachments,
calendar_id: value.calendar_id, calendar_id: value.calendar_id,
event_type: value.event_type.event_type, event_type: value.event_type.event_type,
classNames: ['cal-class-group-' + value.calendar_id.calendar_id, 'cal-class-id-' + value.id.id], classNames: ['cal-class-group-' + value.calendar_id.calendar_id, 'cal-class-id-' + value.id.id, cursorclass],
textColor: value.txtColor.txtColor, textColor: value.txtColor.txtColor,
backgroundColor: value.bgColor.bgColor, backgroundColor: value.bgColor.bgColor,
privateflag: value.privateflag.privateflag,
editable: rights, editable: rights,
rruleflag: rruleflag, rruleflag: rruleflag,
dates: rrule, dates: rrule,
@@ -183,9 +196,10 @@ document.addEventListener('DOMContentLoaded', function () {
attachments: value.attachments.attachments, attachments: value.attachments.attachments,
calendar_id: value.calendar_id, calendar_id: value.calendar_id,
event_type: value.event_type.event_type, event_type: value.event_type.event_type,
classNames: ['cal-class-group-' + value.calendar_id.calendar_id, 'cal-class-id-' + value.id.id], classNames: ['cal-class-group-' + value.calendar_id.calendar_id, 'cal-class-id-' + value.id.id, cursorclass],
textColor: value.txtColor.txtColor, textColor: value.txtColor.txtColor,
backgroundColor: value.bgColor.bgColor, backgroundColor: value.bgColor.bgColor,
privateflag: value.privateflag.privateflag,
editable: rights, editable: rights,
rruleflag: rruleflag, rruleflag: rruleflag,
dates: rrule, dates: rrule,
@@ -276,10 +290,12 @@ document.addEventListener('DOMContentLoaded', function () {
schedulerLicenseKey: 'CC-Attribution-NonCommercial-NoDerivatives', schedulerLicenseKey: 'CC-Attribution-NonCommercial-NoDerivatives',
timeZone: 'UTC', timeZone: 'UTC',
locale: 'de', locale: 'de',
height: 'auto',
resourceAreaWidth: '220px', resourceAreaWidth: '220px',
themeSystem: 'bootstrap4', themeSystem: 'bootstrap4',
snapDuration: '00:15:00', snapDuration: '00:15:00',
selectable: true, selectable: true,
weekNumbers: true,
headerToolbar: { headerToolbar: {
left: "prev,today,next", left: "prev,today,next",
center: 'title', center: 'title',
@@ -370,6 +386,13 @@ document.addEventListener('DOMContentLoaded', function () {
} else { } else {
$('#reminder').val('NULL'); $('#reminder').val('NULL');
} }
if (data.data.privateflag.privateflag == 1) {
$('.privacy-click').removeClass('fa-unlock');
$('.privacy-click').removeClass('fa-lock');
$('.privacy-click').addClass('fa-lock');
}
$('#type').val(data.data.type.type); $('#type').val(data.data.type.type);
$('#busy').val(data.data.busy.busy); $('#busy').val(data.data.busy.busy);
isOrganizer = data.data.isorganizer.isorganizer; isOrganizer = data.data.isorganizer.isorganizer;
@@ -388,6 +411,7 @@ document.addEventListener('DOMContentLoaded', function () {
$('#customer').select2({ $('#customer').select2({
placeholder: "Kunden Suche", placeholder: "Kunden Suche",
minimumInputLength: 3, minimumInputLength: 3,
dropdownParent: jQuery('#relContainer2'),
// dropdownParent: $('#EventModal'), // dropdownParent: $('#EventModal'),
language: "de", language: "de",
ajax: { ajax: {
@@ -410,7 +434,7 @@ document.addEventListener('DOMContentLoaded', function () {
} }
if (data.data.customer_info_send.customer_info_send) { if (data.data.customer_info_send.customer_info_send) {
const obj = JSON.parse(data.data.customer_info_send.customer_info_send); const obj = JSON.parse(data.data.customer_info_send.customer_info_send);
$('#customer-info-check-info').html('<i class="fa-sharp-duotone fa-solid fa-circle-info"></i>'); $('#customer-info-check-info').html('<i class="fa-sharp-duotone fa-solid fa-circle-info customer-info-point"></i>');
const unixTime = obj.sendtime; const unixTime = obj.sendtime;
const date = new Date(unixTime * 1000); const date = new Date(unixTime * 1000);
const germanDateTime = date.toLocaleString('de-DE', { const germanDateTime = date.toLocaleString('de-DE', {
@@ -434,7 +458,8 @@ document.addEventListener('DOMContentLoaded', function () {
<div class="text-left"><span class="font-weight-500">gesendet am:</span> ` + germanDateTime + `</div> <div class="text-left"><span class="font-weight-500">gesendet am:</span> ` + germanDateTime + `</div>
`; `;
var tooltip = new Tooltip($('.fa-circle-info'), { console.log(title);
var tooltip = new Tooltip($('.customer-info-point'), {
title: title, title: title,
placement: 'right', placement: 'right',
trigger: 'hover', trigger: 'hover',
@@ -460,7 +485,10 @@ document.addEventListener('DOMContentLoaded', function () {
const datetime = new Date(accept.time * 1000); const datetime = new Date(accept.time * 1000);
const germanDateTime = datetime.toLocaleString('de-DE'); const germanDateTime = datetime.toLocaleString('de-DE');
$('.accepted-status').prop('title', accept.user + ' (' + germanDateTime + ')'); $('.accepted-status').prop('title', accept.user + ' (' + germanDateTime + ')');
} else {
$('.accepted-status').prop('title', '');
} }
$('.accepted-status').addClass('fa-circle-check'); $('.accepted-status').addClass('fa-circle-check');
$('.event-accepted').text('Akzeptiert'); $('.event-accepted').text('Akzeptiert');
} else { } else {
@@ -472,6 +500,7 @@ document.addEventListener('DOMContentLoaded', function () {
$('.show-attendee').show(); $('.show-attendee').show();
$('.show-attendee').data('id', info.event.id); $('.show-attendee').data('id', info.event.id);
} }
if (data.data.attendees.attendees) { if (data.data.attendees.attendees) {
let attendees = JSON.parse(data.data.attendees.attendees); let attendees = JSON.parse(data.data.attendees.attendees);
$.each(attendees, function (index, value) { $.each(attendees, function (index, value) {
@@ -487,6 +516,12 @@ document.addEventListener('DOMContentLoaded', function () {
$('#calendar-attendees').val(attendees).trigger('change'); $('#calendar-attendees').val(attendees).trigger('change');
} }
if (info.event.extendedProps.rruleflag == true) {
$('#delete-event').hide();
$('#update-event').hide();
$('.show-attendee').hide();
}
}); });
if (info.event.extendedProps.clickable) { if (info.event.extendedProps.clickable) {
@@ -611,16 +646,24 @@ document.addEventListener('DOMContentLoaded', function () {
title += '<div class="text-left font-13"><span class="font-weight-500">geändert von </span> ' + info.event.extendedProps['mname'] + '</div>'; title += '<div class="text-left font-13"><span class="font-weight-500">geändert von </span> ' + info.event.extendedProps['mname'] + '</div>';
} }
if ($('.fc-button-active').hasClass('fc-timeGridWeek-button') || $('.fc-button-active').hasClass('fc-timeGridDay-button')) { if ($('.fc-button-active').hasClass('fc-timeGridWeek-button') || $('.fc-button-active').hasClass('fc-timeGridDay-button')) {
if (info.event.extendedProps['attachment']) {
info.el.querySelector(".fc-event-title").insertAdjacentHTML("afterend", "<div class=\"fc-event-attachment\"><i class=\"fa-light fa-paperclip-vertical\"></i></div>");
}
if (info.event.extendedProps['event_type'] == '2') { if (info.event.extendedProps['event_type'] == '2') {
info.el.querySelector(".fc-event-title").insertAdjacentHTML("afterend", "<div class=\"fc-event-type\"><i class=\"fa-light fa-user-helmet-safety\"></i></div>"); info.el.querySelector(".fc-event-title").insertAdjacentHTML("afterend", "<div class=\"fc-event-type\"><i class=\"fa-light fa-user-helmet-safety\"></i></div>");
} }
if (info.event.extendedProps['privateflag'] == 1) {
info.el.querySelector(".fc-event-title").insertAdjacentHTML("afterend", "<div class=\"fc-event-private\"><i class=\"fa-regular fa-event-lock fa-lock\"></i></div>");
}
if (info.event.extendedProps['attachment'] && info.event.extendedProps['privateflag'] == 1) {
info.el.querySelector(".fc-event-title").insertAdjacentHTML("afterend", "<div class=\"fc-event-attachment-mr\"><i class=\"fa-light fa-paperclip-vertical\"></i></div>");
} else if (info.event.extendedProps['attachment']) {
info.el.querySelector(".fc-event-title").insertAdjacentHTML("afterend", "<div class=\"fc-event-attachment\"><i class=\"fa-light fa-paperclip-vertical\"></i></div>");
}
if (info.event.extendedProps['rruleflag']) { if (info.event.extendedProps['rruleflag']) {
info.el.querySelector(".fc-event-title").insertAdjacentHTML("afterend", "<div class=\"fc-event-recurrence\"><i class=\"fa-regular fa-arrows-rotate\"></i></div>"); info.el.querySelector(".fc-event-title").insertAdjacentHTML("afterend", "<div class=\"fc-event-recurrence\"><i class=\"fa-regular fa-arrows-rotate\"></i></div>");
} }
} }
var tooltip = new Tooltip(info.el, { var tooltip = new Tooltip(info.el, {
@@ -784,6 +827,7 @@ if (typeof (EventSource) !== 'undefined') {
// document.getElementById('result').innerHTML += e.data + '<br>'; // document.getElementById('result').innerHTML += e.data + '<br>';
let checkbox = $(".form-check-input"); let checkbox = $(".form-check-input");
let visibleCalendars = []; let visibleCalendars = [];
let mycalendar_id = $('#calendar-id').data('calendarid');
visibleCalendars.push(0); visibleCalendars.push(0);
checkbox.each(function () { checkbox.each(function () {
if ($(this).prop('checked')) { if ($(this).prop('checked')) {
@@ -801,6 +845,7 @@ if (typeof (EventSource) !== 'undefined') {
var rrule = null; var rrule = null;
var duration = null; var duration = null;
var rruleflag = false; var rruleflag = false;
let cursorclass = '';
if (event.rrule) { if (event.rrule) {
rrule = event.rrule; rrule = event.rrule;
duration = event.duration; duration = event.duration;
@@ -814,9 +859,17 @@ if (typeof (EventSource) !== 'undefined') {
} }
if (event.isorganizer == '1' && rights) { if (event.isorganizer == '1' && rights) {
movable = true; movable = true;
} else if (rights) {
cursorclass = "cursor-alias"
movable = false;
} else { } else {
movable = false; movable = false;
} }
if (event.privateflag == '1' && mycalendar_id != event.calendar_id_check.calendar_id) {
rights = false;
movable = false;
}
} }
if (event.change_type == '2' && cevent) { if (event.change_type == '2' && cevent) {
@@ -834,10 +887,11 @@ if (typeof (EventSource) !== 'undefined') {
backgroundColor: event.bgColor, backgroundColor: event.bgColor,
location: event.location, location: event.location,
event_type: event.event_type, event_type: event.event_type,
classNames: ['cal-class-group-' + event.calendar_id, 'cal-class-id-' + event.cal_events_id], classNames: ['cal-class-group-' + event.calendar_id, 'cal-class-id-' + event.cal_events_id, cursorclass],
attachment: event.attachment, attachment: event.attachment,
attachments: event.attachments, attachments: event.attachments,
editable: movable, editable: movable,
privateflag: event.privateflag,
rruleflag: rruleflag, rruleflag: rruleflag,
rrule: rrule, rrule: rrule,
duration: duration, duration: duration,
@@ -863,11 +917,12 @@ if (typeof (EventSource) !== 'undefined') {
editable: false, editable: false,
location: event.location, location: event.location,
event_type: event.event_type, event_type: event.event_type,
classNames: ['cal-class-group-' + event.calendar_id, 'cal-class-id-' + event.cal_events_id], classNames: ['cal-class-group-' + event.calendar_id, 'cal-class-id-' + event.cal_events_id, cursorclass],
attachment: event.attachment, attachment: event.attachment,
attachments: event.attachments, attachments: event.attachments,
calendar_id: event.calendar_id_check, calendar_id: event.calendar_id_check,
resourceId: event.calendar_id, resourceId: event.calendar_id,
privateflag: event.privateflag,
calendar_name: event.calendar_name, calendar_name: event.calendar_name,
clickable: rights, clickable: rights,
mtime: event.mtime, mtime: event.mtime,
@@ -892,8 +947,9 @@ if (typeof (EventSource) !== 'undefined') {
textColor: event.txtColor, textColor: event.txtColor,
backgroundColor: event.bgColor, backgroundColor: event.bgColor,
location: event.location, location: event.location,
privateflag: event.privateflag,
event_type: event.event_type, event_type: event.event_type,
classNames: ['cal-class-group-' + event.calendar_id, 'cal-class-id-' + event.cal_events_id], classNames: ['cal-class-group-' + event.calendar_id, 'cal-class-id-' + event.cal_events_id, cursorclass],
attachment: event.attachment, attachment: event.attachment,
attachments: event.attachments, attachments: event.attachments,
editable: movable, editable: movable,
@@ -918,8 +974,9 @@ if (typeof (EventSource) !== 'undefined') {
color: '#ab0000', color: '#ab0000',
editable: false, editable: false,
location: event.location, location: event.location,
privateflag: event.privateflag,
event_type: event.event_type, event_type: event.event_type,
classNames: ['cal-class-group-' + event.calendar_id, 'cal-class-id-' + event.cal_events_id], classNames: ['cal-class-group-' + event.calendar_id, 'cal-class-id-' + event.cal_events_id, cursorclass],
attachment: event.attachment, attachment: event.attachment,
attachments: event.attachments, attachments: event.attachments,
calendar_id: event.calendar_id_check, calendar_id: event.calendar_id_check,
@@ -986,6 +1043,9 @@ $(document).ready(function () {
$('.attachment-div').empty(); $('.attachment-div').empty();
$('#reminder').val('NULL'); $('#reminder').val('NULL');
$('#type').val('1'); $('#type').val('1');
$('.privacy-click').removeClass('fa-lock');
$('.privacy-click').removeClass('fa-unlock');
$('.privacy-click').addClass('fa-unlock');
$('#customer-info-check-info').empty(); $('#customer-info-check-info').empty();
$('#customer-info-type').val('1'); $('#customer-info-type').val('1');
$('#customer').val(''); $('#customer').val('');
@@ -1061,6 +1121,11 @@ $(document).ready(function () {
var customer_info_type; var customer_info_type;
var customer_info_type_text; var customer_info_type_text;
var customer_info_reminder_check = 0; var customer_info_reminder_check = 0;
var private = $('.privacy-click');
var privateflag = 0;
if (private.hasClass('fa-lock')) {
privateflag = 1;
}
var users = []; var users = [];
if ($('#allday').is(':checked')) { if ($('#allday').is(':checked')) {
@@ -1095,6 +1160,7 @@ $(document).ready(function () {
description: description, description: description,
attachments: attachments, attachments: attachments,
users: users, users: users,
privateflag: privateflag,
attendees: $('#calendar-attendees').val(), attendees: $('#calendar-attendees').val(),
customer: customer, customer: customer,
customer_info_check: customer_info_check, customer_info_check: customer_info_check,
@@ -1149,6 +1215,11 @@ $(document).ready(function () {
var customer_info_type; var customer_info_type;
var customer_info_type_text; var customer_info_type_text;
var customer_info_reminder_check = 0; var customer_info_reminder_check = 0;
var private = $('.privacy-click');
var privateflag = 0;
if (private.hasClass('fa-lock')) {
privateflag = 1;
}
var users = []; var users = [];
if ($('#allday').is(':checked')) { if ($('#allday').is(':checked')) {
@@ -1175,7 +1246,6 @@ $(document).ready(function () {
users.push($(this).val()); users.push($(this).val());
}); });
$.post(requestUpdateUrl, { $.post(requestUpdateUrl, {
id: id, id: id,
start: start, start: start,
@@ -1189,6 +1259,7 @@ $(document).ready(function () {
description: description, description: description,
attachments: attachments, attachments: attachments,
users: users, users: users,
privateflag: privateflag,
attendees: $('#calendar-attendees').val(), attendees: $('#calendar-attendees').val(),
customer: customer, customer: customer,
customer_info_check: customer_info_check, customer_info_check: customer_info_check,
@@ -1276,17 +1347,6 @@ $(document).ready(function () {
var txtcolors = []; var txtcolors = [];
var calendar_id = []; var calendar_id = [];
var thisis = $(this); var thisis = $(this);
if (init === 0) {
var resourceA = calendar.getResourceById(thisis.data('calendar_id'));
if (resourceA) {
var events = resourceA.getEvents();
events.forEach(function (event) {
event.setProp('backgroundColor', thisis.closest('div').find('.color-input').val());
event.setProp('textColor', thisis.closest('div').find('.color-text-input').val());
});
}
calendar.render();
}
$.each($('.color-input'), function (index, value) { $.each($('.color-input'), function (index, value) {
if ($(this).data('calendar_id')) { if ($(this).data('calendar_id')) {
bgcolors.push($(this).closest('div').find('.color-input').val()); bgcolors.push($(this).closest('div').find('.color-input').val());
@@ -1308,6 +1368,10 @@ $(document).ready(function () {
groups: groups groups: groups
}, function (data) { }, function (data) {
}).done(function (data) {
if (init === 0) {
refreshCalendarEvents();
}
}) })
}); });
$('body').on('change', '.calendar-check', function (event, init = 0) { $('body').on('change', '.calendar-check', function (event, init = 0) {
@@ -1440,6 +1504,7 @@ $(document).ready(function () {
placeholder: "Kunden Suche", placeholder: "Kunden Suche",
minimumInputLength: 3, minimumInputLength: 3,
// dropdownParent: $('#EventModal'), // dropdownParent: $('#EventModal'),
dropdownParent: jQuery('#relContainer2'),
language: "de", language: "de",
ajax: { ajax: {
url: requestAddressUrl, url: requestAddressUrl,
@@ -1487,7 +1552,8 @@ $(document).ready(function () {
return { return {
q: params.term, // Der Suchbegriff q: params.term, // Der Suchbegriff
term: params.term, // Der Suchbegriff term: params.term, // Der Suchbegriff
calendars: visibleCalendars // Die dynamische Variable, die du hinzufügen möchtest calendars: visibleCalendars, // Die dynamische Variable, die du hinzufügen möchtest
cal_id: $('#calendar-id').data('calendarid')
}; };
}, },
dataType: 'json', dataType: 'json',
@@ -1591,6 +1657,11 @@ Xinon GMbH`;
let groupname = $.trim($(this).text()); let groupname = $.trim($(this).text());
$(this).html('<input type="text" data-oldname="' + groupname + '" class="form-control cal-group-name-input" value="' + groupname + '">'); $(this).html('<input type="text" data-oldname="' + groupname + '" class="form-control cal-group-name-input" value="' + groupname + '">');
var strLength = $(this).find('.cal-group-name-input').val().length * 2;
$(this).find('.cal-group-name-input')[0].setSelectionRange(strLength, strLength);
$(this).find('.cal-group-name-input').focus();
}); });
$("body").on("click", ".group-checkbox", function () { $("body").on("click", ".group-checkbox", function () {
@@ -1642,14 +1713,28 @@ Xinon GMbH`;
$(this).removeClass('fa-square-arrow-up'); $(this).removeClass('fa-square-arrow-up');
$(this).addClass('fa-square-arrow-down'); $(this).addClass('fa-square-arrow-down');
$(this).closest('.calendar-side-borders-sub').find('.calendar-side-borders-sub-inner').hide(); $(this).closest('.calendar-side-borders-sub').find('.calendar-side-borders-sub-inner').hide();
$(".color-input").eq(0).trigger("change", 1);
} else { } else {
$(this).removeClass('fa-square-arrow-down'); $(this).removeClass('fa-square-arrow-down');
$(this).addClass('fa-square-arrow-up'); $(this).addClass('fa-square-arrow-up');
$(this).closest('.calendar-side-borders-sub').find('.calendar-side-borders-sub-inner').show(); $(this).closest('.calendar-side-borders-sub').find('.calendar-side-borders-sub-inner').show();
$(".color-input").eq(0).trigger("change", 1);
} }
}); });
$("body").on("click", ".privacy-click", function (e) {
if ($(this).hasClass('fa-unlock')) {
$(this).removeClass('fa-unlock');
$(this).addClass('fa-lock');
$(this).prop('title', 'Privat');
} else {
$(this).removeClass('fa-lock');
$(this).addClass('fa-unlock');
$(this).prop('title', 'Normal');
}
});
$("body").on("keyup", ".cal-group-name-input", function (e) { $("body").on("keyup", ".cal-group-name-input", function (e) {
if (e.keyCode === 13) { if (e.keyCode === 13) {
let groupname = $.trim($(this).val()); let groupname = $.trim($(this).val());
@@ -1672,11 +1757,26 @@ Xinon GMbH`;
$(this).closest('div').find('.move-group-div').show(); $(this).closest('div').find('.move-group-div').show();
$(this).closest('div').find('.group-checkbox-div').show(); $(this).closest('div').find('.group-checkbox-div').show();
$(this).closest('.cal-group-name').text($(this).data('oldname')); $(this).closest('.cal-group-name').text($(this).data('oldname'));
} }
} }
}); });
$("body").on("blur", ".cal-group-name-input", function (e) {
let groupname = $.trim($(this).val());
if (groupname.length > 3) {
$(this).closest('div').find('.dropdown-group-div').show();
$(this).closest('div').find('.move-group-div').show();
$(this).closest('div').find('.group-checkbox-div').show();
$(this).closest('.cal-group-name').text(groupname);
$(".color-input").eq(0).trigger("change", 1);
} else {
$(this).closest('div').find('.dropdown-group-div').show();
$(this).closest('div').find('.move-group-div').show();
$(this).closest('div').find('.group-checkbox-div').show();
$(this).closest('.cal-group-name').text($(this).data('oldname'));
}
});
function getGroups() { function getGroups() {
const groups = []; const groups = [];
@@ -1794,6 +1894,7 @@ Xinon GMbH`;
calendar.removeAllEvents(); calendar.removeAllEvents();
let checkbox = $(".calendar-check"); let checkbox = $(".calendar-check");
let visibleCalendars = []; let visibleCalendars = [];
let mycalendar_id = $('#calendar-id').data('calendarid');
visibleCalendars.push(0); visibleCalendars.push(0);
checkbox.each(function () { checkbox.each(function () {
if ($(this).prop('checked')) { if ($(this).prop('checked')) {
@@ -1817,6 +1918,7 @@ Xinon GMbH`;
var duration = null; var duration = null;
var rruleflag = false; var rruleflag = false;
let allDAy = false; let allDAy = false;
let cursorclass = "";
$.each($('.calendar-check'), function (index, value) { $.each($('.calendar-check'), function (index, value) {
if ($(this).prop('checked')) { if ($(this).prop('checked')) {
rights = true; rights = true;
@@ -1838,6 +1940,7 @@ Xinon GMbH`;
duration = null; duration = null;
rruleflag = false; rruleflag = false;
allDAy = false; allDAy = false;
cursorclass = "";
category = value.ccategory.ccategory; category = value.ccategory.ccategory;
if (value.rrule.rrule) { if (value.rrule.rrule) {
rrule = value.rrule.rrule; rrule = value.rrule.rrule;
@@ -1853,9 +1956,19 @@ Xinon GMbH`;
} }
if (value.isorganizer.isorganizer == '1' && rights) { if (value.isorganizer.isorganizer == '1' && rights) {
movable = true; movable = true;
} else if (rights) {
movable = false;
cursorclass = "cursor-alias";
} else { } else {
movable = false; movable = false;
} }
if (value.privateflag.privateflag == '1' && mycalendar_id != value.calendar_id.calendar_id) {
rights = false;
movable = false;
}
if (value.allDay.allDay == "1") { if (value.allDay.allDay == "1") {
allDAy = true; allDAy = true;
} }
@@ -1882,10 +1995,11 @@ Xinon GMbH`;
attachments: value.attachments.attachments, attachments: value.attachments.attachments,
calendar_id: value.calendar_id, calendar_id: value.calendar_id,
event_type: value.event_type.event_type, event_type: value.event_type.event_type,
classNames: ['cal-class-group-' + value.calendar_id.calendar_id, 'cal-class-id-' + value.id.id], classNames: ['cal-class-group-' + value.calendar_id.calendar_id, 'cal-class-id-' + value.id.id, cursorclass],
textColor: value.txtColor.txtColor, textColor: value.txtColor.txtColor,
backgroundColor: value.bgColor.bgColor, backgroundColor: value.bgColor.bgColor,
editable: rights, editable: rights,
privateflag: value.privateflag.privateflag,
rruleflag: rruleflag, rruleflag: rruleflag,
dates: rrule, dates: rrule,
duration: duration, duration: duration,
@@ -1918,10 +2032,11 @@ Xinon GMbH`;
attachments: value.attachments.attachments, attachments: value.attachments.attachments,
calendar_id: value.calendar_id, calendar_id: value.calendar_id,
event_type: value.event_type.event_type, event_type: value.event_type.event_type,
classNames: ['cal-class-group-' + value.calendar_id.calendar_id, 'cal-class-id-' + value.id.id], classNames: ['cal-class-group-' + value.calendar_id.calendar_id, 'cal-class-id-' + value.id.id, cursorclass],
textColor: value.txtColor.txtColor, textColor: value.txtColor.txtColor,
backgroundColor: value.bgColor.bgColor, backgroundColor: value.bgColor.bgColor,
editable: rights, editable: rights,
privateflag: value.privateflag.privateflag,
rruleflag: rruleflag, rruleflag: rruleflag,
dates: rrule, dates: rrule,
duration: duration, duration: duration,
@@ -1,74 +1,235 @@
// noinspection JSUnusedLocalSymbols // noinspection JSUnusedLocalSymbols
const articleAPIUrl = `${window['TT_CONFIG']['BASE_PATH']}/WarehouseArticle/autocomplete`;
const articlePacketAPIUrl = `${window['TT_CONFIG']['BASE_PATH']}/WarehouseArticlePacket/autocomplete`;
Vue.component('warehouse-e-shop-order-modal-positions-mgmt', {
props: {
id: {type: [String, Number], required: true},
}, data() {
return {
window: window,
positions: [],
articleAPIUrl: articleAPIUrl,
articlePacketAPIUrl: articlePacketAPIUrl,
articleNames: {},
articlePacketNames: {},
articleId: null,
articlePacketId: null,
amount: null,
editIndex: null,
}
}, async mounted() {
// get all positions by /WarehouseEShopOrder/getAllItemsPerOrder?orderId=ID
const response = await axios.get(`${window['TT_CONFIG']['BASE_PATH']}/WarehouseEShopOrder/getAllItemsPerOrder?orderId=${this.id}`);
this.positions = response.data;
}, methods: {
async fetchNames() {
console.log("hallohallo");
// TODO: there must be a better way to do this
for (const position of this.positions) {
if (position.articleId) this.$set(this.articleNames, position.articleId, 'Loading...');
if (position.articlePacketId) this.$set(this.articlePacketNames, position.articlePacketId, 'Loading...');
}
const articlePromises = this.positions.filter(position => position.articleId)
.map(position => axios.get(window.TT_CONFIG["BASE_PATH"] + '/WarehouseArticle/autoComplete?searchedID=' + position.articleId));
const articlePacketPromises = this.positions.filter(position => position.articlePacketId)
.map(position => axios.get(window.TT_CONFIG["BASE_PATH"] + '/WarehouseArticlePacket/autoComplete?searchedID=' + position.articlePacketId));
const articleResponses = await Promise.all(articlePromises);
const articlePacketResponses = await Promise.all(articlePacketPromises);
for (const response of articleResponses) {
this.$set(this.articleNames, response.data[0].value, response.data[0].text);
}
for (const response of articlePacketResponses) {
this.$set(this.articlePacketNames, response.data[0].value, response.data[0].text);
}
},
async addPosition() {
if (!this.articleId && !this.articlePacketId) return window.notify('error', 'Bitte wählen Sie einen Artikel oder ein Artikel Packet aus.');
if (this.editIndex !== null) return this.updatePosition();
const response = await axios.post(`${window['TT_CONFIG']['BASE_PATH']}/WarehouseEShopOrder/addPosition`, {
orderId: this.id,
articleId: this.articleId,
articlePacketId: this.articlePacketId,
quantity: this.amount,
});
if (response.data.success) {
this.positions.push(response.data.position);
this.articleId = null;
this.articlePacketId = null;
this.amount = null;
window.notify('success', 'Position hinzugefügt');
} else {
window.notify('error', response.data.message);
}
},
async updatePosition() {
const position = this.positions[this.editIndex];
const response = await axios.post(`${window['TT_CONFIG']['BASE_PATH']}/WarehouseEShopOrder/updatePosition`, {
id: position.id,
articleId: this.articleId,
articlePacketId: this.articlePacketId,
quantity: this.amount,
});
if (response.data.success) {
this.positions[this.editIndex] = response.data.position;
this.articleId = null;
this.articlePacketId = null;
this.amount = null;
this.editIndex = null;
window.notify('success', response.data.message);
} else {
window.notify('error', response.data.message);
}
},
async deletePosition(id) {
const response = await axios.post(`${window['TT_CONFIG']['BASE_PATH']}/WarehouseEShopOrder/deletePosition`, {id});
if (response.data.success) {
this.positions = this.positions.filter(position => position.id !== id);
window.notify('success', response.data.message);
} else {
window.notify('error', response.data.message);
}
},
async editPosition(id) {
const position = this.positions.find(position => position.id === id);
this.articleId = position.articleId;
this.articlePacketId = position.articlePacketId;
this.amount = position.quantity;
this.editIndex = this.positions.indexOf(position);
},
}, watch: {positions: {handler: 'fetchNames', immediate: true}}, //language=Vue
template: `
<div>
<div style="display: grid;grid-template-columns: 2fr 1fr 0.5fr 1fr;grid-gap: 10px;">
<tt-autocomplete v-model="articleId" :api-url="articleAPIUrl" label="Artikel" sm ref="article"/>
<tt-autocomplete v-model="articlePacketId" :api-url="articlePacketAPIUrl" label="Artikel Packet" sm/>
<tt-input v-model="amount" label="Menge" sm/>
<div style="display: flex;flex-direction: column;justify-content: center;padding-top: 13px;">
<button @click="addPosition" class="btn btn-primary">Hinzufügen</button>
</div>
</div>
<div style="display: flex; align-items: center; justify-content: center;">
<table class="table table-striped table-sm" style="width: max-content">
<thead>
<tr>
<th>Artikel</th>
<th>Menge</th>
<th>Aktionen</th>
</tr>
</thead>
<tbody>
<tr v-if="positions.length === 0">
<td colspan="4" class="text-center">Keine Einträge</td>
</tr>
<tr v-for="(position, index) in positions" :key="index">
<td>{{ position.articleId ? articleNames[position.articleId] : position.articlePacketId ? articlePacketNames[position.articlePacketId] :
'Loading...' }}
</td>
<td>{{ position.quantity }}</td>
<td>
<button class="btn btn-sm btn-danger" @click="deletePosition(position.id)">Löschen</button>
<button class="btn btn-sm btn-primary" @click="editPosition(position.id)">Bearbeiten</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
`,
})
Vue.component('warehouse-e-shop-order', { Vue.component('warehouse-e-shop-order', {
//language=Vue //language=Vue
template: ` template: `
<tt-card> <tt-card>
<tt-table-crud @openHistory="historyModal = true; historyModalId = $event.id" <tt-table-crud @openHistory="historyModal = true; historyModalId = $event.id"
@openSingleOrderEmail="openSingleOrderEmailModal = true; singleOrderEmailModalId = $event.id" @openSingleOrderEmail="openSingleOrderEmailModal = true; singleOrderEmailModalId = $event.id"
@createShippingNote="createShippingNote($event.id)" @createShippingNote="createShippingNote($event.id)"
@showTrackingHistory="openTrackingHistoryModal = true; trackingHistoryModalId = $event.id" @showTrackingHistory="openTrackingHistoryModal = true; trackingHistoryModalId = $event.id"
ref="table"> ref="table">
<template v-slot:table-top-buttons> <template v-slot:table-top-buttons>
<button @click="createCSVExportAndMarkAsAccepted" type="button" class="btn btn-outline-success"> <button @click="createCSVExportAndMarkAsAccepted" type="button" class="btn btn-outline-success">
<i class="fas fa-file-excel"></i> <i class="fas fa-file-excel"></i>
Excel Export für neue Bestellungen Excel Export für neue Bestellungen
</button> </button>
</template> </template>
<template v-slot:create="{ row }"> <template v-slot:create="{ row }">
{{ window.moment(row.create * 1000).format('DD.MM.YYYY HH:mm:ss') }} {{ window.moment(row.create * 1000).format('DD.MM.YYYY HH:mm:ss') }}
</template> </template>
<template v-slot:expandedRow="{ row }"> <template v-slot:expandedRow="{ row }">
<div> <div>
<ul class="list-group" v-if="articleItems && articleItems[row.id]"> <ul class="list-group" v-if="articleItems && articleItems[row.id]">
<li class="list-group-item" v-for="item in articleItems[row.id]"> <li class="list-group-item" v-for="item in articleItems[row.id]">
Menge: {{ item.quantity }} | {{ item.articlePacketTitle || item.articleTitle }} Menge: {{ item.quantity }} | {{ item.articlePacketTitle || item.articleTitle }}
</li>
</ul>
</div>
</template>
<template v-slot:positions-modal="{ crudModalData }">
<div>
<warehouse-e-shop-order-modal-positions-mgmt :id="crudModalData.id"/>
</div>
</template>
</tt-table-crud>
<warehouse-history-modal :show.sync="historyModal" :id="historyModalId"/>
<!-- add a tt-modal which just shows some text from the api to show a email for a single order-->
<tt-modal :show.sync="openSingleOrderEmailModal"
:title="'Email für Bestellung ' + singleOrderEmailModalId"
@close="openSingleOrderEmailModal = false"
save-text="E-Mail senden"
@submit="sendSingleOrderEmail"
:delete="false"
>
<div v-if="singleOrderEmailModalId && singleOrderEmailModalText">
<p v-html="singleOrderEmailModalText.body.replaceAll('\\n', '<br>')"></p>
</div>
<!-- else show loader-->
<div v-else>
<tt-loader/>
</div>
</tt-modal>
<tt-modal :show.sync="openTrackingHistoryModal"
:title="'Tracking Historie für Bestellung ' + trackingHistoryModalId"
@close="openTrackingHistoryModal = false"
:delete="false"
:save="false"
>
<div v-if="trackingHistoryModalData">
<ul class="list-group">
<li class="list-group item" v-for="entry in trackingHistoryModalData.history">
<strong>{{ entry.date }} {{ entry.time }}</strong> - {{ entry.evtDscr }}
</li> </li>
</ul> </ul>
</div> </div>
</template>
</tt-table-crud> </tt-modal>
<warehouse-history-modal :show.sync="historyModal" :id="historyModalId"/>
<!-- add a tt-modal which just shows some text from the api to show a email for a single order-->
<tt-modal :show.sync="openSingleOrderEmailModal"
:title="'Email für Bestellung ' + singleOrderEmailModalId"
@close="openSingleOrderEmailModal = false"
save-text="E-Mail senden"
@submit="sendSingleOrderEmail"
:delete="false"
>
<div v-if="singleOrderEmailModalId && singleOrderEmailModalText">
<p v-html="singleOrderEmailModalText.body.replaceAll('\\n', '<br>')"></p>
</div>
<!-- else show loader-->
<div v-else>
<tt-loader/>
</div>
</tt-modal>
<tt-modal :show.sync="openTrackingHistoryModal"
:title="'Tracking Historie für Bestellung ' + trackingHistoryModalId"
@close="openTrackingHistoryModal = false"
:delete="false"
:save="false"
>
<div v-if="trackingHistoryModalData">
<ul class="list-group">
<li class="list-group item" v-for="entry in trackingHistoryModalData.history">
<strong>{{ entry.date }} {{ entry.time }}</strong> - {{ entry.evtDscr }}
</li>
</ul>
</div>
</tt-modal>
</tt-card> </tt-card>
`, data() { `, data() {
return { return {
window: window, window: window,
historyModal: false, historyModal: false,
@@ -79,7 +240,10 @@ Vue.component('warehouse-e-shop-order', {
singleOrderEmailModalText: null, singleOrderEmailModalText: null,
openTrackingHistoryModal: false, openTrackingHistoryModal: false,
trackingHistoryModalId: null, trackingHistoryModalId: null,
trackingHistoryModalData: null, trackingHistoryModalData: null, // modal
positionsEntryArticleId: null,
positionsEntryArticlePacketId: null,
positionsEntryAmount: null,
} }
}, async mounted() { }, async mounted() {
const response = await axios.get(`${window['TT_CONFIG']['BASE_PATH']}/WarehouseEShopOrder/getAllItemsPerOrder`); const response = await axios.get(`${window['TT_CONFIG']['BASE_PATH']}/WarehouseEShopOrder/getAllItemsPerOrder`);
@@ -92,8 +256,7 @@ Vue.component('warehouse-e-shop-order', {
if (response.data.shippingNoteId) { if (response.data.shippingNoteId) {
window.open(`${window['TT_CONFIG']['BASE_PATH']}/WarehouseShippingNote/createPDF?id=${response.data.shippingNoteId}&price=true`, '_blank'); window.open(`${window['TT_CONFIG']['BASE_PATH']}/WarehouseShippingNote/createPDF?id=${response.data.shippingNoteId}&price=true`, '_blank');
} }
}, }, async sendSingleOrderEmail() {
async sendSingleOrderEmail() {
const response = await axios.get(`${window['TT_CONFIG']['BASE_PATH']}/WarehouseEShopOrder/singleOrderEmail?id=${this.singleOrderEmailModalId}`); const response = await axios.get(`${window['TT_CONFIG']['BASE_PATH']}/WarehouseEShopOrder/singleOrderEmail?id=${this.singleOrderEmailModalId}`);
if (response.data.message) { if (response.data.message) {
window.notify(response.data.success === true ? 'success' : 'error', response.data.message); window.notify(response.data.success === true ? 'success' : 'error', response.data.message);
@@ -148,8 +311,7 @@ Vue.component('warehouse-e-shop-order', {
.then(response => this.singleOrderEmailModalText = response.data) .then(response => this.singleOrderEmailModalText = response.data)
.catch(error => window.notify('error', error.response?.data?.message || 'Ein Fehler ist aufgetreten')); .catch(error => window.notify('error', error.response?.data?.message || 'Ein Fehler ist aufgetreten'));
} }
}, }, async trackingHistoryModalId() {
async trackingHistoryModalId() {
this.openTrackingHistoryModal = !!this.trackingHistoryModalId; this.openTrackingHistoryModal = !!this.trackingHistoryModalId;
this.trackingHistoryModalData = null; this.trackingHistoryModalData = null;
if (this.trackingHistoryModalId) { if (this.trackingHistoryModalId) {
@@ -1,9 +1,13 @@
.warehouse-shipping-note-modal-positions-entry-container { .warehouse-shipping-note-modal-positions-entry-container {
display: grid; display: grid;
grid-template-columns: 2fr 1fr 1fr 1fr; grid-template-columns: 2fr 1fr 0.5fr 1fr 1fr;
grid-gap: 10px; grid-gap: 10px;
} }
.warehouse-shipping-note-modal-positions-entry-container.hidePrice {
grid-template-columns: 2fr 1fr 0.5fr 1fr;
}
.warehouse-shipping-note-modal-positions-entry-actions, .warehouse-shipping-note-modal-hours-entry-actions { .warehouse-shipping-note-modal-positions-entry-actions, .warehouse-shipping-note-modal-hours-entry-actions {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@@ -13,12 +17,16 @@
.warehouse-shipping-note-modal-hours-entry-container { .warehouse-shipping-note-modal-hours-entry-container {
display: grid; display: grid;
grid-template-columns: 2fr 1fr 1fr 2fr 1fr 1fr 1fr; grid-template-columns: 2fr 1fr 1fr 1fr 2fr 1fr 1fr 1fr;
grid-gap: 10px; grid-gap: 10px;
} }
.warehouse-shipping-note-modal-hours-entry-container.hideHourlyPrice { .warehouse-shipping-note-modal-hours-entry-container.hideHourlyPrice {
grid-template-columns: 2fr 1fr 1fr 2fr 1fr 1fr; grid-template-columns: 2fr 1fr 1fr 1fr 2fr 1fr 1fr;
}
.warehouse-shipping-note-modal-hours-entry-container.hideHourlyPrice.hideKilometer {
grid-template-columns: 2fr 1fr 1fr 1fr 2fr 1fr;
} }
@media (min-width: 992px) { @media (min-width: 992px) {
@@ -36,10 +44,19 @@
grid-gap: 10px; grid-gap: 10px;
} }
.warehouse-shipping-note-modal-positions-entry-actions, .warehouse-shipping-note-modal-hours-entry-actions { .warehouse-shipping-note-modal-positions-entry-actions {
grid-column: 2; grid-column: 2;
} }
.warehouse-shipping-note-modal-hours-entry-actions {
grid-column: 1 / span 2;
margin-bottom: 8px;
}
.modal .table.table-striped.table-sm button{
margin-bottom: 4px;
}
.signModal > div { .signModal > div {
margin: 0; margin: 0;
width: 100vw; width: 100vw;
@@ -80,7 +80,10 @@ Vue.component('warehouse-shipping-note', {
signingShippingNoteId: null signingShippingNoteId: null
} }
}, },
methods: { mounted() {
// check if get parameter doAction = createNew is set, if so open the modal with 'create' as id
if (window.location.search.includes('doAction=createNew')) {
this.shippingNoteModalId = 'create';
}
} }
}) })
@@ -47,17 +47,19 @@ Vue.component('warehouse-shipping-note-modal-hours-entry', {
hourCount: '', hourCount: '',
kilometerCount: '', kilometerCount: '',
hourlyPrice: '', hourlyPrice: '',
priceType: 'normal',
} }
}, },
//language=Vue //language=Vue
template: ` template: `
<div class="warehouse-shipping-note-modal-hours-entry-container" v-bind:class="{ 'hideHourlyPrice': !showHourlyPrice }"> <div class="warehouse-shipping-note-modal-hours-entry-container" v-bind:class="{ 'hideHourlyPrice': !showHourlyPrice, 'hideKilometer': window.TT_CONFIG['WAREHOUSE_ADMIN'] != true }">
<tt-autocomplete v-model="userId" :api-url="userApiUrl" label="Mitarbeiter" sm/> <tt-autocomplete v-model="userId" :api-url="userApiUrl" label="Mitarbeiter" sm/>
<tt-input v-model="date" label="Datum" type="date" sm/> <tt-input v-model="date" label="Datum" type="date" sm/>
<tt-input v-model="hourCount" label="Stunden" sm/> <tt-input v-model="hourCount" label="Stunden" sm/>
<tt-select v-model="priceType" label="Stundenart" sm :options="[{text: 'Normal', value: 'normal'}, {text: '+50%', value: '50'}, {text: '+100%', value: '100'}]"/>
<tt-autocomplete v-model="carId" :api-url="carApiUrl" label="Fahrzeug" sm/> <tt-autocomplete v-model="carId" :api-url="carApiUrl" label="Fahrzeug" sm/>
<tt-input v-model="hourlyPrice" label="Stundenlohn" type="number" sm v-if="showHourlyPrice"/> <tt-input v-model="hourlyPrice" label="Stundenlohn" type="number" sm v-if="showHourlyPrice"/>
<tt-input :disabled="carId === ''" v-model="kilometerCount" label="Kilometer" sm/> <tt-input v-show="window.TT_CONFIG['WAREHOUSE_ADMIN'] == true" :disabled="carId === ''" v-model="kilometerCount" label="Kilometer" sm/>
<div class="warehouse-shipping-note-modal-hours-entry-actions"> <div class="warehouse-shipping-note-modal-hours-entry-actions">
<button @click="createOrUpdate" class="btn btn-sm btn-primary">Speichern</button> <button @click="createOrUpdate" class="btn btn-sm btn-primary">Speichern</button>
</div> </div>
@@ -74,6 +76,7 @@ Vue.component('warehouse-shipping-note-modal-hours-entry', {
userId: this.userId, userId: this.userId,
date: this.date, date: this.date,
hourCount: this.hourCount, hourCount: this.hourCount,
priceType: this.priceType,
hourlyPrice: this.hourlyPrice || null, hourlyPrice: this.hourlyPrice || null,
carId: this.carId ? this.carId : null, carId: this.carId ? this.carId : null,
kilometerCount: this.carId ? this.kilometerCount : null kilometerCount: this.carId ? this.kilometerCount : null
@@ -103,7 +106,7 @@ Vue.component('warehouse-shipping-note-modal-hours-entry', {
if (!this.userId || this.carId) return; if (!this.userId || this.carId) return;
const response = await axios.get(window.TT_CONFIG["BASE_PATH"] + '/WarehouseShippingNote/timerecordingCarForUser?userId=' + this.userId); const response = await axios.get(window.TT_CONFIG["BASE_PATH"] + '/WarehouseShippingNote/timerecordingCarForUser?userId=' + this.userId);
if (response.data.status === 'USER_NO_CAR') { if (response.data.status === 'USER_NO_CAR') {
this.window.notify('info', 'Kein zugewiesenes Fahrzeug gefunden'); // this.window.notify('info', 'Kein zugewiesenes Fahrzeug gefunden');
this.carId = ''; this.carId = '';
return; return;
} }
@@ -165,7 +168,7 @@ Vue.component('warehouse-shipping-note-modal-hours-view', {
<td>{{ userNames[entry.userId] }}</td> <td>{{ userNames[entry.userId] }}</td>
<td>{{ window.moment(entry.date).format('DD.MM.YYYY') }}</td> <td>{{ window.moment(entry.date).format('DD.MM.YYYY') }}</td>
<td>{{ entry.hourCount }}</td> <td>{{ entry.hourCount }}</td>
<td>{{ entry.kilometerCount }}</td> <td v-show="window.TT_CONFIG['WAREHOUSE_ADMIN'] == true">{{ entry.kilometerCount }}</td>
<td v-if="showHourlyPrice">{{ entry.hourlyPrice }}</td> <td v-if="showHourlyPrice">{{ entry.hourlyPrice }}</td>
<td> <td>
<button class="btn btn-sm btn-danger" @click="$emit('delete', entry)">Löschen</button> <button class="btn btn-sm btn-danger" @click="$emit('delete', entry)">Löschen</button>
@@ -254,21 +257,24 @@ Vue.component('warehouse-shipping-note-modal-positions-entry', {
data() { data() {
return { return {
window: window, window: window,
isAdmin: false,
articleApiUrl: window.TT_CONFIG['BASE_PATH'] + '/WarehouseArticle/autoComplete', articleApiUrl: window.TT_CONFIG['BASE_PATH'] + '/WarehouseArticle/autoComplete',
articlePacketApiUrl: window.TT_CONFIG['BASE_PATH'] + '/WarehouseArticlePacket/autoComplete', articlePacketApiUrl: window.TT_CONFIG['BASE_PATH'] + '/WarehouseArticlePacket/autoComplete',
articleId: '', articleId: '',
articlePacketId: '', articlePacketId: '',
amount: '', amount: '',
price: '', price: '',
isEnergieMaterial: false,
} }
}, },
//language=Vue //language=Vue
template: ` template: `
<div class="warehouse-shipping-note-modal-positions-entry-container"> <div class="warehouse-shipping-note-modal-positions-entry-container" :class="{ 'hidePrice': !isAdmin }">
<tt-autocomplete v-model="articleId" :api-url="articleApiUrl" label="Artikel" sm ref="article"/> <tt-autocomplete v-model="articleId" :api-url="articleApiUrl" label="Artikel" sm ref="article"/>
<!-- <tt-autocomplete v-model="articlePacketId" :api-url="articlePacketApiUrl" label="Artikel Packet" sm/>--> <!-- <tt-autocomplete v-model="articlePacketId" :api-url="articlePacketApiUrl" label="Artikel Packet" sm/>-->
<tt-input v-model="amount" label="Menge" sm/> <tt-input v-model="amount" label="Menge" sm/>
<tt-input v-model="price" label="Preis" type="number" sm/> <tt-checkbox v-model="isEnergieMaterial" label="Energie Material" sm/>
<tt-input v-show="isAdmin" v-model="price" label="Preis" type="number" sm/>
<div class="warehouse-shipping-note-modal-positions-entry-actions"> <div class="warehouse-shipping-note-modal-positions-entry-actions">
<button @click="createOrUpdate" class="btn btn-sm btn-primary">Speichern</button> <button @click="createOrUpdate" class="btn btn-sm btn-primary">Speichern</button>
</div> </div>
@@ -280,8 +286,10 @@ Vue.component('warehouse-shipping-note-modal-positions-entry', {
if (!this.amount) return this.window.notify('error', 'Bitte füllen sie die Menge aus'); if (!this.amount) return this.window.notify('error', 'Bitte füllen sie die Menge aus');
const data = { const data = {
amount: this.amount, amount: this.amount,
isEnergieMaterial: this.isEnergieMaterial,
price: parseFloat(this.price) ?? '' price: parseFloat(this.price) ?? ''
} }
if (isNaN(data.price)) data.price = '';
if (!this.articleId && this.$refs.article.displayValue) { if (!this.articleId && this.$refs.article.displayValue) {
data.articleText = this.$refs.article.displayValue; data.articleText = this.$refs.article.displayValue;
} else if (this.articleId) { } else if (this.articleId) {
@@ -317,6 +325,7 @@ Vue.component('warehouse-shipping-note-modal-positions-view', {
data() { data() {
return { return {
window: window, window: window,
isAdmin: false,
articleNames: {}, articleNames: {},
articlePacketNames: {}, articlePacketNames: {},
} }
@@ -329,7 +338,8 @@ Vue.component('warehouse-shipping-note-modal-positions-view', {
<tr> <tr>
<th>Artikel</th> <th>Artikel</th>
<th>Menge</th> <th>Menge</th>
<th>Preis</th> <th>Energie Material</th>
<th v-if="isAdmin">Preis</th>
<th>Aktionen</th> <th>Aktionen</th>
</tr> </tr>
</thead> </thead>
@@ -342,7 +352,8 @@ Vue.component('warehouse-shipping-note-modal-positions-view', {
position.articleText }} position.articleText }}
</td> </td>
<td>{{ position.amount }}</td> <td>{{ position.amount }}</td>
<td>{{ (position.price?.toFixed(2)) }} €</td> <td>{{ position?.isEnergieMaterial ? 'Ja' : 'Nein' }}</td>
<td v-if="isAdmin">{{ (position.price?.toFixed(2)) }} €</td>
<td> <td>
<button class="btn btn-sm btn-danger" @click="$emit('delete', position)">Löschen</button> <button class="btn btn-sm btn-danger" @click="$emit('delete', position)">Löschen</button>
<button class="btn btn-sm btn-primary" @click="$emit('edit', position)">Bearbeiten</button> <button class="btn btn-sm btn-primary" @click="$emit('edit', position)">Bearbeiten</button>
@@ -497,13 +508,13 @@ Vue.component('warehouse-shipping-note-modal', {
</div> </div>
<!-- TODO: fix these buttons--> <!-- TODO: fix these buttons-->
<template v-slot:footer-prepend v-if="id !== 'create'"> <template v-slot:footer-prepend v-if="id !== 'create'">
<button v-if="window.TT_CONFIG['WAREHOUSE_ADMIN'] == true && status === 'new'" class="btn btn-warning" @click="alert('In Bearbeitung')">In <button v-if="window.TT_CONFIG['WAREHOUSE_ADMIN'] == true && status === 'new'" class="btn btn-warning" @click="changeStatus('in_progress')">In
Bearbeitung Bearbeitung
</button> </button>
<button v-if="window.TT_CONFIG['WAREHOUSE_ADMIN'] == true && (status === 'new' || status === 'in_progress')" class="btn btn-success" <button v-if="window.TT_CONFIG['WAREHOUSE_ADMIN'] == true && (status === 'new' || status === 'in_progress')" class="btn btn-success"
@click="alert('Accepted')">Akzeptieren @click="changeStatus('accepted')">Akzeptieren
</button> </button>
<button v-if="window.TT_CONFIG['WAREHOUSE_ADMIN'] == true && status === 'accepted'" class="btn btn-info" @click="alert('Invoiced')"> <button v-if="window.TT_CONFIG['WAREHOUSE_ADMIN'] == true && status === 'accepted'" class="btn btn-info" @click="changeStatus('invoiced')">
Verrechnet Verrechnet
</button> </button>
<button class="btn btn-info" @click="$emit('open-signing-modal', id)">Unterschreiben</button> <button class="btn btn-info" @click="$emit('open-signing-modal', id)">Unterschreiben</button>
@@ -532,6 +543,17 @@ Vue.component('warehouse-shipping-note-modal', {
this.textElements = []; this.textElements = [];
} }
} }
} else {
const knr = new URLSearchParams(window.location.search).get('knr');
if (knr) {
const response = await axios.get(window.TT_CONFIG["BASE_PATH"] + '/Address/Api?do=findAddress&fibu_primary_account=1&autocomplete=1&q=' + knr);
for (const address of response.data) {
if (address.text.endsWith(`[${knr}]`)) {
this.billAddrId = address.value;
break;
}
}
}
} }
}, },
methods: { methods: {
@@ -544,6 +566,16 @@ Vue.component('warehouse-shipping-note-modal', {
this.window.notify('error', response.data.message || 'Ein Fehler ist aufgetreten'); this.window.notify('error', response.data.message || 'Ein Fehler ist aufgetreten');
} }
}, },
async changeStatus(newStatus) {
const response = await axios.post(window.TT_CONFIG.BASE_PATH + '/WarehouseShippingNote/changeStatus', {id: this.id, status: newStatus});
if (response.data.success) {
this.window.notify('success', response.data.message || 'Erfolgreich aktualisiert');
this.status = newStatus;
this.$emit('close');
} else {
this.window.notify('error', response.data.message || 'Ein Fehler ist aufgetreten');
}
},
async submit() { async submit() {
const data = { const data = {
billingAddressId: this.billAddrId, billingAddressId: this.billAddrId,
@@ -677,8 +709,7 @@ Vue.component('warehouse-shipping-note-modal-address', {
address.deliveryAddressName === this.delAddrName && address.deliveryAddressName === this.delAddrName &&
address.deliveryAddressLine === this.delAddrLine && address.deliveryAddressLine === this.delAddrLine &&
address.deliveryAddressPLZ === this.delAddrPLZ && address.deliveryAddressPLZ === this.delAddrPLZ &&
address.deliveryAddressCity === this.delAddrCity && address.deliveryAddressCity === this.delAddrCity);
address.deliveryAddressEMail === this.delAddrEMail);
if (foundAddress) { if (foundAddress) {
this.addressMode = 'existing'; this.addressMode = 'existing';
this.selectedAddr = foundAddress.id; this.selectedAddr = foundAddress.id;
+1 -1
View File
@@ -6,7 +6,7 @@ document.addEventListener('DOMContentLoaded', () => {
// @formatter:on // @formatter:on
const notyf = new Notyf({ const notyf = new Notyf({
duration: 10000, position: { duration: 6000, position: {
x: 'right', y: 'bottom', x: 'right', y: 'bottom',
}, ripple: true, dismissible: true, fontSize: '32px', }, ripple: true, dismissible: true, fontSize: '32px',
types: [{ types: [{
@@ -1,6 +1,8 @@
//TODO: if autocomplete is focus and the input has not a single character still show "Bitte mindestens 3 Zeichen eingeben" //TODO: if autocomplete is focus and the input has not a single character still show "Bitte mindestens 3 Zeichen eingeben"
//TODO: fix the fetchSuggestions function to not show a loading spinner when the input gets cleared //TODO: fix the fetchSuggestions function to not show a loading spinner when the input gets cleared
//TODO: fix so we can use arrow keys to navigate the suggestions //TODO: fix so we can use arrow keys to navigate the suggestions
// TODO: Implement giving the option without the need of an API || need to use computed property to filter the items
// TODO: Fix the weirdness with timeout and selecting the suggestion
Vue.component('tt-autocomplete', { Vue.component('tt-autocomplete', {
template: ` template: `
@@ -66,9 +68,8 @@ Vue.component('tt-autocomplete', {
</ul> </ul>
</div> </div>
</div> </div>
`, // TODO: Implement giving the option without the need of an API || need to use computed property to filter the items `,
// TODO: Fix the weirdness with timeout and selecting the suggestion props: {
props: {
value: {type: [String, Number]}, value: {type: [String, Number]},
label: {type: String, required: false}, label: {type: String, required: false},
apiUrl: String, apiUrl: String,
@@ -76,19 +77,26 @@ Vue.component('tt-autocomplete', {
items: {type: Array, default: () => []}, items: {type: Array, default: () => []},
sm: {type: Boolean, default: true}, sm: {type: Boolean, default: true},
row: {type: Boolean, default: false}, row: {type: Boolean, default: false},
}, async mounted() {
this.updateDisplayValue().then();
}, data() { }, data() {
return { return {
displayingItems: [], displayValue: '', isLoading: false, showSuggestions: false, cursor: -1, fetchSuggestionsDebounceTimer: null, disableIDFetch: false displayingItems: [],
oldDisplayValue: '',
displayValue: '',
isLoading: false,
showSuggestions: false,
cursor: -1,
fetchSuggestionsDebounceTimer: null,
disableIDFetch: false
}; };
}, watch: { },
value: {handler: 'updateDisplayValue', immediate: true}, async mounted() {
apiUrl() { this.updateDisplayValue().then();
this.fetchSuggestions(); },
methods: {
setOldDisplayValue(newValue, oldValue) {
this.oldDisplayValue = oldValue;
}, },
}, methods: { async updateDisplayValue(newValue, oldValue) {
async updateDisplayValue(newValue) {
if (this.disableIDFetch) { if (this.disableIDFetch) {
this.disableIDFetch = false; this.disableIDFetch = false;
return; return;
@@ -106,7 +114,7 @@ Vue.component('tt-autocomplete', {
this.displayValue = selectedItem ? selectedItem.text : ''; this.displayValue = selectedItem ? selectedItem.text : '';
} else { } else {
this.$emit('input', ''); this.$emit('input', '');
this.displayValue = ''; this.displayValue = this.displayValue.replace(this.oldDisplayValue, '');
} }
}, },
onInput(event) { onInput(event) {
@@ -175,4 +183,9 @@ Vue.component('tt-autocomplete', {
this.$emit('input', ''); this.$emit('input', '');
} }
}, },
watch: {
displayValue: {handler: 'setOldDisplayValue', immediate: true},
value: {handler: 'updateDisplayValue', immediate: true},
apiUrl: {handler: 'fetchSuggestions', immediate: true},
}
}); });
@@ -30,6 +30,8 @@ Vue.component('tt-button', {
'btn-sm': this.sm, 'btn-sm': this.sm,
} }
if (!this.additionalClass) return classes
for (const className of this.additionalClass.split(' ')) { for (const className of this.additionalClass.split(' ')) {
classes[className] = true classes[className] = true
} }
@@ -25,6 +25,7 @@ Vue.component('tt-checkbox', {
<div class="form-group" :class="{'row': row}"> <div class="form-group" :class="{'row': row}">
<slot name="prepend"></slot> <slot name="prepend"></slot>
<label <label
style="width: 100%;text-align: center;"
:class="{'col-form-label': row, 'col-sm-4': row, 'col-form-label-sm': sm && row}" :class="{'col-form-label': row, 'col-sm-4': row, 'col-form-label-sm': sm && row}"
v-if="label" v-if="label"
:for="label">{{ label }}</label> :for="label">{{ label }}</label>
+6 -2
View File
@@ -44,14 +44,18 @@ Vue.component('tt-modal', {
this.$emit('submit') this.$emit('submit')
} }
} }
}, //language=Vue },
data() {
return {window: window, isMobile: navigator.userAgent.match(/(iPad)|(iPhone)|(iPod)|(android)|(webOS)/i) !== null}
},
//language=Vue
template: ` template: `
<div class="modal show d-block" <div class="modal show d-block"
role="dialog" role="dialog"
tabindex="-1" tabindex="-1"
style="background: rgba(0, 0, 0, 0.5);" style="background: rgba(0, 0, 0, 0.5);"
ref="modal" ref="modal"
@mousedown="$emit('update:show', false)" @mousedown="!isMobile ? $emit('update:show', false) : null"
@keydown.esc="$emit('update:show', false)" @keydown.esc="$emit('update:show', false)"
v-if="show"> v-if="show">
<div class="modal-dialog modal-lg modal-dialog-scrollable" role="document" @mousedown.stop> <div class="modal-dialog modal-lg modal-dialog-scrollable" role="document" @mousedown.stop>
+109
View File
@@ -0,0 +1,109 @@
<?php
//require 'vendor/autoload.php';
require("../../config/config.php");
define('FRONKDB_SQLDEBUG', false);
error_reporting(E_ALL & ~(E_NOTICE | E_STRICT | E_DEPRECATED));
require_once(LIBDIR . "/mvcfronk/mfRouter/mfRouter.php");
require_once(LIBDIR . "/mvcfronk/mfBase/mfBaseModel.php");
require_once(LIBDIR . "/mvcfronk/mfBase/mfBaseController.php");
$me = new User(154);
define("INTERNAL_USER_ID", $me->id);
define("INTERNAL_USER_USERNAME", $me->username);
$calendar = CalendarModel::search(array("checkSubscriptions" => 1));
$adminUser = array(89, 173, 167, 8, 6, 9, 5,123);
foreach ($calendar as $cal) {
$allCalendar[$cal->go_calendar_id] = $cal->user_id;
}
foreach ($calendar as $cal) {
$update = 0;
$allCalendarUser = $allCalendar;
unset($newrights);
if (in_array($cal->user_id, $adminUser)) {
$admin = 1;
} else {
$admin = 0;
}
foreach ($allCalendarUser as $key => $value) {
if ($admin == 1 || $key == $cal->go_calendar_id) {
$newrights[$key] = "all";
} else {
$newrights[$key] = "read";
}
}
if (json_encode($newrights) != $cal->rights) {
$cal->update(array("rights" => json_encode($newrights)));
$update = 1;
}
if ($cal->colors) {
$stdColors = CalendarModel::$standardCalendarColors;
$colorsArray = json_decode($cal->colors, true);
$colors = $colorsArray;
foreach ($allCalendarUser as $key => $value) {
if ($colors[$key]) {
unset($colors[$key]);
} else {
$colorsArray[$key]['bgcolor'] = $stdColors[$key];
$colorsArray[$key]['txtcolor'] = "#000000";
}
}
if ($colors) {
foreach ($colors as $key => $value) {
if ($key != "998" && $key != "997") {
unset($colorsArray[$key]);
}
}
}
if (json_encode($colorsArray) != $cal->colors) {
$cal->update(array("colors" => json_encode($colorsArray)));
$update = 1;
}
}
if ($cal->groups) {
$groupArray = json_decode($cal->groups, true);
$groups = $groupArray;
foreach ($groups as $key => $value) {
foreach ($value["calendars"] as $key2 => $value2) {
if ((!$allCalendarUser[$value2['calendar_id']] && $value2['calendar_id'] != 997 && $value2['calendar_id'] != 998)) {
unset($groupArray[$key]["calendars"][$key2]);
} else {
unset($allCalendarUser[$value2['calendar_id']]);
}
}
}
if ($allCalendarUser) {
foreach ($groups as $key => $value) {
if ($value['name'] == "Persönlich") {
foreach ($allCalendarUser as $key2 => $value2) {
$groupArray[$key]["calendars"][] = array("calendar_id" => "$key2", "checked" => 0, "origin" => 1);
}
}
}
}
if (json_encode($groupArray, JSON_UNESCAPED_UNICODE) != $cal->groups) {
echo "groups";
$cal->update(array("groups" => json_encode($groupArray, JSON_UNESCAPED_UNICODE)));
$update = 1;
}
}
if ($update == 1) {
echo "save" . $cal->id . "\n";
$cal->save();
}
}