| ... | ... |
@@ -61,6 +61,8 @@ $GLOBALS['NOTIFICATION_CENTER']['NOTIFICATION_TYPE']['weinanlieferung']['wa_book |
| 61 | 61 |
'slot_time', |
| 62 | 62 |
'slot_standort', |
| 63 | 63 |
'booking_ncsent', |
| 64 |
+ 'booking_approved', |
|
| 65 |
+ 'booking_approved_on', |
|
| 64 | 66 |
), |
| 65 | 67 |
'email_text' => array |
| 66 | 68 |
( |
| ... | ... |
@@ -80,6 +82,8 @@ $GLOBALS['NOTIFICATION_CENTER']['NOTIFICATION_TYPE']['weinanlieferung']['wa_book |
| 80 | 82 |
'booking_sorten', |
| 81 | 83 |
'booking_ernteart', |
| 82 | 84 |
'booking_lage', |
| 85 |
+ 'booking_approved', |
|
| 86 |
+ 'booking_approved_on', |
|
| 83 | 87 |
), |
| 84 | 88 |
'email_html' => array |
| 85 | 89 |
( |
| ... | ... |
@@ -99,6 +103,8 @@ $GLOBALS['NOTIFICATION_CENTER']['NOTIFICATION_TYPE']['weinanlieferung']['wa_book |
| 99 | 103 |
'booking_sorten', |
| 100 | 104 |
'booking_ernteart', |
| 101 | 105 |
'booking_lage', |
| 106 |
+ 'booking_approved', |
|
| 107 |
+ 'booking_approved_on', |
|
| 102 | 108 |
) |
| 103 | 109 |
); |
| 104 | 110 |
|
| ... | ... |
@@ -97,7 +97,7 @@ $GLOBALS['TL_DCA']['tl_vr_wa_reservation'] = array |
| 97 | 97 |
'palettes' => array |
| 98 | 98 |
( |
| 99 | 99 |
'__selector__' => array(), |
| 100 |
- 'default' => 'pid,uid,behaelter,sorten,lage,ernteart,upload,approved' |
|
| 100 |
+ 'default' => 'pid,uid,behaelter,sorten,lage,ernteart,upload;{approval_legend},approved'
|
|
| 101 | 101 |
), |
| 102 | 102 |
|
| 103 | 103 |
// Subpalettes |
| ... | ... |
@@ -22,7 +22,10 @@ $GLOBALS['TL_LANG']['tl_vr_wa_reservation']['uid'][0] = 'Winzer'; |
| 22 | 22 |
$GLOBALS['TL_LANG']['tl_vr_wa_reservation']['uid'][1] = 'Zuordnung des anliefernden Winzers.'; |
| 23 | 23 |
$GLOBALS['TL_LANG']['tl_vr_wa_reservation']['upload'][0] = 'Datei'; |
| 24 | 24 |
$GLOBALS['TL_LANG']['tl_vr_wa_reservation']['upload'][1] = 'Die hochgeladene Datei des Winzers.'; |
| 25 |
+$GLOBALS['TL_LANG']['tl_vr_wa_reservation']['approved'][0] = 'Freigabe'; |
|
| 26 |
+$GLOBALS['TL_LANG']['tl_vr_wa_reservation']['approved'][1] = 'Der Freigabe-Status der Buchung.'; |
|
| 25 | 27 |
|
| 26 | 28 |
$GLOBALS['TL_LANG']['tl_vr_wa_reservation']['title_legend'] = 'Leseart'; |
| 29 |
+$GLOBALS['TL_LANG']['tl_vr_wa_reservation']['approval_legend'] = 'Freigabe-Einstellungen'; |
|
| 27 | 30 |
|
| 28 | 31 |
$GLOBALS['TL_LANG']['tl_vr_wa_reservation']['back'] = 'Zurück'; |
| ... | ... |
@@ -47,6 +47,21 @@ |
| 47 | 47 |
<a href="/contao?do=weinanlieferung&table=tl_vr_wa_reservation&act=create&rt={{ request_token }}&ref={{ ref }}" class="header_new" title="" accesskey="n" onclick="Backend.getScrollOffset()">Neu</a>
|
| 48 | 48 |
</div> |
| 49 | 49 |
<div class="tl_listing_container"> |
| 50 |
+ <div class="u-flex u-items-center u-gap-2 px-1 text-sm"> |
|
| 51 |
+ <div><strong>Legende:</strong></div> |
|
| 52 |
+ <div class="u-flex u-items-center u-gap-1"> |
|
| 53 |
+ <i class="status-icon status--approved status--small"></i> |
|
| 54 |
+ angenommen |
|
| 55 |
+ </div> |
|
| 56 |
+ <div class="u-flex u-items-center u-gap-1"> |
|
| 57 |
+ <i class="status-icon status--pending status--small"></i> |
|
| 58 |
+ Freigabe ausstehend |
|
| 59 |
+ </div> |
|
| 60 |
+ <div class="u-flex u-items-center u-gap-1"> |
|
| 61 |
+ <i class="status-icon status--canceled status--small"></i> |
|
| 62 |
+ abgelehnt |
|
| 63 |
+ </div> |
|
| 64 |
+ </div> |
|
| 50 | 65 |
<div> |
| 51 | 66 |
|
| 52 | 67 |
{% block content %}
|
| ... | ... |
@@ -56,37 +71,47 @@ |
| 56 | 71 |
<h3 class="tl_folder_list px-1 text-lg text-primary mt-2">{{ day|date('d.m.Y') }}</h3>
|
| 57 | 72 |
{% for standort in standorte %}
|
| 58 | 73 |
{% for time,bookings in standort.times %}
|
| 59 |
- <h3 class="tl_folder_list px-1 row u-items-center"> |
|
| 60 |
- <div class="col-2 pl-0">{{ time|date('H:i') }}</div>
|
|
| 61 |
- <div class="col-3"> |
|
| 74 |
+ <h3 class="tl_folder_list row u-items-center"> |
|
| 75 |
+ <div class="col-2 offset-1">{{ time|date('H:i') }}</div>
|
|
| 76 |
+ <div class="col-2"> |
|
| 62 | 77 |
<div class="t-label">Standort</div> |
| 63 | 78 |
{{ standort.standort }}
|
| 64 | 79 |
</div> |
| 65 |
- <div class="col-3"> |
|
| 80 |
+ <div class="col-2"> |
|
| 66 | 81 |
<div class="t-label">Verfügbare Behälterkapazität</div> |
| 67 | 82 |
{{ bookings.behaelterAvailable }}
|
| 68 | 83 |
</div> |
| 69 |
- <div class="col"> |
|
| 84 |
+ <div class="col px-1"> |
|
| 70 | 85 |
<div class="t-label">Verarbeitete Sorten</div> |
| 71 | 86 |
{{ bookings.sorten|join(', ') }}
|
| 72 | 87 |
</div> |
| 73 | 88 |
</h3> |
| 74 | 89 |
<div class="bookings u-row-striped"> |
| 75 | 90 |
{% for booking in bookings.items %}
|
| 76 |
- <div class="row u-items-center"> |
|
| 77 |
- <div class="col-1 time icon-uhr-outline"> |
|
| 91 |
+ {% if booking.approved == '1' %}
|
|
| 92 |
+ {% set status = 'approved' %}
|
|
| 93 |
+ {% elseif booking.approved == '0' %}
|
|
| 94 |
+ {% set status = 'canceled' %}
|
|
| 95 |
+ {% else %}
|
|
| 96 |
+ {% set status = 'pending' %}
|
|
| 97 |
+ {% endif %}
|
|
| 98 |
+ <div class="row u-items-flex-start my-1 status status--{{ status }}">
|
|
| 99 |
+ <div class="col-1"> |
|
| 100 |
+ <i class="status-icon" title="{{ ('MSC.wa_approval_status.'~status)|trans([], 'contao_default') }}">{{ ('MSC.wa_approval_status.'~status)|trans([], 'contao_default') }}</i>
|
|
| 101 |
+ </div> |
|
| 102 |
+ <div class="col-2 time icon-uhr-outline"> |
|
| 78 | 103 |
<div class="t-label">Uhrzeit</div> |
| 79 | 104 |
{{ booking.slot.time|date('H:i') }}
|
| 80 | 105 |
<div class="t-label">Standort</div> |
| 81 | 106 |
{{ booking.standort }}
|
| 82 | 107 |
</div> |
| 83 |
- <div class="col-3 behaelter icon-behaelter-outline"> |
|
| 108 |
+ <div class="col-2 behaelter icon-behaelter-outline"> |
|
| 84 | 109 |
<div class="t-label">Gebuchte Behälterkapazität</div> |
| 85 | 110 |
{{ booking.behaelter }}
|
| 86 | 111 |
<div class="t-label">Ernteart</div> |
| 87 | 112 |
{{ booking.ernteart|join(', ') }}
|
| 88 | 113 |
</div> |
| 89 |
- <div class="col-3 behaelter icon-behaelter-outline"> |
|
| 114 |
+ <div class="col-2 behaelter icon-behaelter-outline"> |
|
| 90 | 115 |
<div class="t-label">Anliefernde Sorten</div> |
| 91 | 116 |
{{ booking.sorte|join(', ') }}
|
| 92 | 117 |
<div class="t-label">Lage</div> |
| ... | ... |
@@ -106,7 +131,7 @@ |
| 106 | 131 |
</div>{% endif %}
|
| 107 | 132 |
{% endif %}
|
| 108 | 133 |
</div> |
| 109 |
- <div class="col-1 u-text-right action"> |
|
| 134 |
+ <div class="col px-1 u-text-right action"> |
|
| 110 | 135 |
<a |
| 111 | 136 |
href="/contao?do=weinanlieferung&table=tl_vr_wa_reservation&act=edit&id={{ booking.id }}&rt={{ request_token }}&ref={{ ref }}"
|
| 112 | 137 |
{# onclick="Backend.openModalIframe({'title':'Quellelement ID {{ booking.id }} bearbeiten','url':this.href});return false" #}
|
| ... | ... |
@@ -6307,3 +6307,69 @@ |
| 6307 | 6307 |
.u-border-opacity-100 {
|
| 6308 | 6308 |
--border-opacity: 1; |
| 6309 | 6309 |
} |
| 6310 |
+ |
|
| 6311 |
+ |
|
| 6312 |
+/** Status icons */ |
|
| 6313 |
+.status .status-icon {
|
|
| 6314 |
+ visibility: hidden; |
|
| 6315 |
+ position: relative; |
|
| 6316 |
+ width: 24px; |
|
| 6317 |
+ height: 24px; |
|
| 6318 |
+} |
|
| 6319 |
+.status .status-icon:after {
|
|
| 6320 |
+ width: 24px; |
|
| 6321 |
+ height: 24px; |
|
| 6322 |
+ visibility: visible; |
|
| 6323 |
+ position: absolute; |
|
| 6324 |
+ top: 50%; |
|
| 6325 |
+ left: 50%; |
|
| 6326 |
+ margin: -12px 0 0 -12px; |
|
| 6327 |
+ content: ''; |
|
| 6328 |
+ background-position: 50% 50%; |
|
| 6329 |
+ background-repeat: no-repeat; |
|
| 6330 |
+} |
|
| 6331 |
+.status-icon {
|
|
| 6332 |
+ visibility: hidden; |
|
| 6333 |
+ position: relative; |
|
| 6334 |
+ display: inline-block; |
|
| 6335 |
+ width: 24px; |
|
| 6336 |
+ height: 24px; |
|
| 6337 |
+} |
|
| 6338 |
+.status-icon:after {
|
|
| 6339 |
+ width: 24px; |
|
| 6340 |
+ height: 24px; |
|
| 6341 |
+ visibility: visible; |
|
| 6342 |
+ position: absolute; |
|
| 6343 |
+ top: 50%; |
|
| 6344 |
+ left: 50%; |
|
| 6345 |
+ margin: -12px 0 0 -12px; |
|
| 6346 |
+ content: ''; |
|
| 6347 |
+ background-position: 50% 50%; |
|
| 6348 |
+ background-repeat: no-repeat; |
|
| 6349 |
+} |
|
| 6350 |
+.status-icon.status--small, .status.status--small .status-icon, .status-icon.status--small:after, .status.status--small .status-icon:after {
|
|
| 6351 |
+ width: 16px; |
|
| 6352 |
+ height: 16px; |
|
| 6353 |
+} |
|
| 6354 |
+.status-icon.status--small:after, .status.status--small .status-icon:after {
|
|
| 6355 |
+ margin: -8px 0 0 -8px; |
|
| 6356 |
+} |
|
| 6357 |
+.status.status--approved:not(.status-icon):not(.status-no-rowcolor), .status-icon.status--approved:not(.status-icon):not(.status-no-rowcolor) {
|
|
| 6358 |
+ background-color: #f3ffe2; |
|
| 6359 |
+} |
|
| 6360 |
+.status.status--approved:not(.status):after, .status-icon.status--approved:not(.status):after, .status.status--approved .status-icon:after, .status-icon.status--approved .status-icon:after {
|
|
| 6361 |
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' class='icon icon-tabler icon-tabler-thumb-up' width='100%25' height='100%25' viewBox='0 0 24 24' stroke-width='1.5' stroke='%2300b341' fill='none' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath stroke='none' d='M0 0h24v24H0z' fill='none'/%3E%3Cpath d='M7 11v8a1 1 0 0 1 -1 1h-2a1 1 0 0 1 -1 -1v-7a1 1 0 0 1 1 -1h3a4 4 0 0 0 4 -4v-1a2 2 0 0 1 4 0v5h3a2 2 0 0 1 2 2l-1 5a2 3 0 0 1 -2 2h-7a3 3 0 0 1 -3 -3' /%3E%3C/svg%3E");
|
|
| 6362 |
+} |
|
| 6363 |
+.status.status--pending:not(.status-icon):not(.status-no-rowcolor), .status-icon.status--pending:not(.status-icon):not(.status-no-rowcolor) {
|
|
| 6364 |
+ background-color: #fff6e4; |
|
| 6365 |
+} |
|
| 6366 |
+.status.status--pending:not(.status):after, .status-icon.status--pending:not(.status):after, .status.status--pending .status-icon:after, .status-icon.status--pending .status-icon:after {
|
|
| 6367 |
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' class='icon icon-tabler icon-tabler-hourglass-high' width='100%25' height='100%25' viewBox='0 0 24 24' stroke-width='1.5' stroke='%23ff9300' fill='none' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath stroke='none' d='M0 0h24v24H0z' fill='none'/%3E%3Cpath d='M6.5 7h11' /%3E%3Cpath d='M6 20v-2a6 6 0 1 1 12 0v2a1 1 0 0 1 -1 1h-10a1 1 0 0 1 -1 -1z' /%3E%3Cpath d='M6 4v2a6 6 0 1 0 12 0v-2a1 1 0 0 0 -1 -1h-10a1 1 0 0 0 -1 1z' /%3E%3C/svg%3E");
|
|
| 6368 |
+} |
|
| 6369 |
+.status.status--canceled:not(.status-icon):not(.status-no-rowcolor), .status-icon.status--canceled:not(.status-icon):not(.status-no-rowcolor) {
|
|
| 6370 |
+ background-color: #ffe7e7; |
|
| 6371 |
+} |
|
| 6372 |
+.status.status--canceled:not(.status):after, .status-icon.status--canceled:not(.status):after, .status.status--canceled .status-icon:after, .status-icon.status--canceled .status-icon:after {
|
|
| 6373 |
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' class='icon icon-tabler icon-tabler-thumb-down' width='100%25' height='100%25' viewBox='0 0 24 24' stroke-width='1.5' stroke='%23ff2825' fill='none' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath stroke='none' d='M0 0h24v24H0z' fill='none'/%3E%3Cpath d='M7 13v-8a1 1 0 0 0 -1 -1h-2a1 1 0 0 0 -1 1v7a1 1 0 0 0 1 1h3a4 4 0 0 1 4 4v1a2 2 0 0 0 4 0v-5h3a2 2 0 0 0 2 -2l-1 -5a2 3 0 0 0 -2 -2h-7a3 3 0 0 0 -3 3' /%3E%3C/svg%3E");
|
|
| 6374 |
+} |
|
| 6375 |
+ |
| ... | ... |
@@ -62,7 +62,7 @@ class SendBookingChangeNotificationJob |
| 62 | 62 |
$time = Date::floorToMinute(); |
| 63 | 63 |
|
| 64 | 64 |
// Do we have updateable items |
| 65 |
- $Bookings = $this->db->executeQuery("SELECT r.id, r.pid, r.uid, r.behaelter, r.sorten, r.lage, r.ernteart, r.upload, r.nc_sent, s.date as 'slot_date', s.time as 'slot_time', s.behaelter as 'slot_behaelter', s.sorten as 'slot_sorten', s.ernteart as 'slot_ernteart', s.lage as 'slot_lage', s.anmerkungen as 'slot_anmerkungen' FROM tl_vr_wa_reservation r INNER JOIN tl_vr_wa_slot s ON s.id = r.pid WHERE s.pid = ? AND r.nc_sent < r.tstamp AND s.published='1'",[$Location->id]);
|
|
| 65 |
+ $Bookings = $this->db->executeQuery("SELECT r.id, r.pid, r.uid, r.behaelter, r.sorten, r.lage, r.ernteart, r.upload, r.nc_sent, s.date as 'slot_date', s.time as 'slot_time', s.behaelter as 'slot_behaelter', s.sorten as 'slot_sorten', s.ernteart as 'slot_ernteart', s.lage as 'slot_lage', s.anmerkungen as 'slot_anmerkungen', r.approved, r.approved_on FROM tl_vr_wa_reservation r INNER JOIN tl_vr_wa_slot s ON s.id = r.pid WHERE s.pid = ? AND r.nc_sent < r.tstamp AND s.published='1'",[$Location->id]);
|
|
| 66 | 66 |
|
| 67 | 67 |
// Load groups and notification models if we have news to share |
| 68 | 68 |
if ($Bookings->rowCount() && ($Notification = Notification::findByPk($Location->nc_notification)) !== null) |
| ... | ... |
@@ -139,6 +139,8 @@ class SendBookingChangeNotificationJob |
| 139 | 139 |
'booking_sorten' => implode(', ',$arrSortenBooked),
|
| 140 | 140 |
'booking_ernteart' => implode(', ',$arrErnteartBooked),
|
| 141 | 141 |
'booking_lage' => implode(', ',$arrLageBooked),
|
| 142 |
+ 'booking_approved' => $Booking['approved'], |
|
| 143 |
+ 'booking_approved_on'=> $Booking['approved_on'], |
|
| 142 | 144 |
'admin_email' => $admin_email, |
| 143 | 145 |
), |
| 144 | 146 |
$GLOBALS['TL_LANGUAGE']); |
| ... | ... |
@@ -19,6 +19,7 @@ use Contao\StringUtil; |
| 19 | 19 |
use Doctrine\DBAL\Connection; |
| 20 | 20 |
use vonRotenberg\WeinanlieferungBundle\Model\WeinanlieferungLeseartModel; |
| 21 | 21 |
use vonRotenberg\WeinanlieferungBundle\Model\WeinanlieferungRebsorteModel; |
| 22 |
+use vonRotenberg\WeinanlieferungBundle\Model\WeinanlieferungReservationModel; |
|
| 22 | 23 |
use vonRotenberg\WeinanlieferungBundle\Model\WeinanlieferungSlotsModel; |
| 23 | 24 |
|
| 24 | 25 |
class WeinanlieferungReservationContainerListener |
| ... | ... |
@@ -145,4 +146,25 @@ class WeinanlieferungReservationContainerListener |
| 145 | 146 |
|
| 146 | 147 |
return $arrData; |
| 147 | 148 |
} |
| 149 |
+ |
|
| 150 |
+ /** |
|
| 151 |
+ * @Callback(table="tl_vr_wa_reservation", target="fields.approved.save") |
|
| 152 |
+ */ |
|
| 153 |
+ public function onApprovedSaveCallback($varValue, DataContainer $dc) |
|
| 154 |
+ {
|
|
| 155 |
+ if (($Current = WeinanlieferungReservationModel::findByPk($dc->activeRecord->id)) !== null) |
|
| 156 |
+ {
|
|
| 157 |
+ if ($Current->approved === '1' && $varValue !== '1') |
|
| 158 |
+ {
|
|
| 159 |
+ $Current->approved_on = 0; |
|
| 160 |
+ $Current->save(); |
|
| 161 |
+ } elseif ($Current->approved !== '1' && $varValue === '1') |
|
| 162 |
+ {
|
|
| 163 |
+ $Current->approved_on = time(); |
|
| 164 |
+ $Current->save(); |
|
| 165 |
+ } |
|
| 166 |
+ } |
|
| 167 |
+ |
|
| 168 |
+ return $varValue; |
|
| 169 |
+ } |
|
| 148 | 170 |
} |
| ... | ... |
@@ -29,6 +29,12 @@ class WeinanlieferungReservationModel extends Model |
| 29 | 29 |
$Date = new Date(); |
| 30 | 30 |
$time = $Date->dayBegin; |
| 31 | 31 |
|
| 32 |
- return static::findBy(array("pid IN (SELECT tl_vr_wa_slot.id FROM tl_vr_wa_slot WHERE tl_vr_wa_slot.id=tl_vr_wa_reservation.pid AND tl_vr_wa_slot.time >= ?)"), $time, $arrOptions);
|
|
| 32 |
+ $arrColumn = ["pid IN (SELECT tl_vr_wa_slot.id FROM tl_vr_wa_slot WHERE tl_vr_wa_slot.id=tl_vr_wa_reservation.pid AND tl_vr_wa_slot.time >= ?)"]; |
|
| 33 |
+ |
|
| 34 |
+ /*if (!isset($arrOptions['showCanceled']) || !$arrOptions['showCanceled']) {
|
|
| 35 |
+ $arrColumn[] = "approved != '0'"; |
|
| 36 |
+ }*/ |
|
| 37 |
+ |
|
| 38 |
+ return static::findBy($arrColumn, $time, $arrOptions); |
|
| 33 | 39 |
} |
| 34 | 40 |
} |