Updated Warehouse

This commit is contained in:
Luca Haid
2025-02-13 11:56:27 +01:00
parent cc58b32312
commit c8d11661d0
8 changed files with 239 additions and 92 deletions

View File

@@ -17,10 +17,8 @@
}
.customer-details {
vertical-align: bottom;
vertical-align: top;
font-size: 14px;
padding-left: 30pt;
width: 35%;
}
.invoice-details {
@@ -58,8 +56,8 @@
<table style="width: 100%; border-collapse: collapse;">
<tr>
<td class="customer-details" style="float: left">
<h3>Lieferant</h3>
<td class="customer-details">
<h3>{{ addressLine_header }}</h3>
<div>{{ addressLine_1 }}</div>
<div>{{ addressLine_2 }}</div>
<div>{{ addressLine_3 }}</div>
@@ -67,8 +65,15 @@
<div style="margin-bottom: 12pt"></div>
<div>{{ externalReference }}</div>
</td>
<td class="customer-details" align="top">
<h3>Rechnungsadresse</h3>
<td class="customer-details">
<h3>{{ shippingAddressLine_header }}</h3>
<div>{{ shippingAddressLine_1 }}</div>
<div>{{ shippingAddressLine_2 }}</div>
<div>{{ shippingAddressLine_3 }}</div>
<div>{{ shippingAddressLine_4 }}</div>
</td>
<td class="customer-details">
<h3>{{ billingAddressLine_header }}</h3>
<div>{{ billingAddressLine_1 }}</div>
<div>{{ billingAddressLine_2 }}</div>
<div>{{ billingAddressLine_3 }}</div>
@@ -76,12 +81,6 @@
<div>{{ billingAddressLine_5 }}</div>
<div>{{ billingAddressLine_6 }}</div>
</td>
<td class="customer-details" style="float: right">
<div>{{ shippingAddressLine_1 }}</div>
<div>{{ shippingAddressLine_2 }}</div>
<div>{{ shippingAddressLine_3 }}</div>
<div>{{ shippingAddressLine_4 }}</div>
</td>
</tr>
</table>

View File

@@ -6,13 +6,51 @@
* @var Array $textElements
*/
$this->setReturnValue(['filename' => $order["id"] . ".pdf"]);
$texts = [
'EN' => [
'header' => 'XINON Supplier Order from ' . date("d.m.Y", $order["create"]),
'sum' => 'Sum',
'vat' => '20% VAT',
'total' => 'Total',
'taxFree' => 'Please provide tax-free delivery according to § 6a UStG (Austrian Sales tax law).<br>Our VAT ID number: ATU68711968. Delivery to Austria.',
'orderConfirmation' => 'Please send the order confirmation to office@xinon.at',
'table' => [
'pos' => 'POS',
'article' => 'Article',
'articleNumber' => 'Dist. art. nr.',
'amount' => 'Amount',
'unitPrice' => 'Unit price',
'totalPrice' => 'Total price'
]
],
'DE' => [
'header' => 'XINON Lieferantenbestellung vom ' . date("d.m.Y", $order["create"]),
'sum' => 'Summe',
'vat' => '20% MwSt',
'total' => 'Gesamt',
'taxFree' => 'Bitte um steuerfreie Lieferung gemäß § 6a UStG.<br> Unsere UID-Nr.: ATU68711968. Lieferung nach Österreich.',
'orderConfirmation' => 'Wir bitten um Zusendung der Auftragsbestätigung für die Bestellung an office@xinon.at.',
'table' => [
'pos' => 'POS',
'article' => 'Artikel',
'articleNumber' => 'Art.-Nr. Lieferant',
'amount' => 'Menge',
'unitPrice' => 'Einzelpreis',
'totalPrice' => 'Gesamtpreis'
]
]];
$text = $texts[in_array($distributorCountryText, ["Österreich", "Deutschland", "Schweiz"]) ? "DE" : "EN"];
?>
<!DOCTYPE html>
<html>
<head>
<title>Bestellung</title>
<meta charset="utf-8" />
<title><?= $text['header'] ?></title>
<meta charset="utf-8"/>
<style>
body {
margin-top: 0;
@@ -76,58 +114,78 @@ $this->setReturnValue(['filename' => $order["id"] . ".pdf"]);
</head>
<body>
<div>
<!--
TODO: enable option for showing prices
vertauschen
Die gelieferte Ware bleibt bis zur vollständigen Bezahlung in unserem Eigentum.
-->
<h2 style="text-align: center;color: #005384">XINON Lieferantenbestellung vom <?=date("d.m.Y", $order["create"])?></h2>
<h2 style="text-align: center;color: #005384"><?= $text['header'] ?></h2>
<table style="border-collapse: collapse; width: 100%;" id="invoiceTable">
<tr style="font-weight: bold; border-bottom: 1px solid black;" class="uneven">
<th style="text-align: center;padding-right: 6pt">Position</th>
<th style="text-align: center;padding-right: 6pt">Artikel</th>
<th style="text-align: center;padding-right: 6pt">Art.-Nr. Lieferant</th>
<th style="text-align: right">Menge</th>
<th style="text-align: right">Einzelpreis</th>
<th style="text-align: right;padding-right: 8pt">Gesamtpreis</th>
<th style="text-align: center;padding-right: 6pt"><?= $text['table']['pos'] ?></th>
<th style="text-align: center;padding-right: 6pt"><?= $text['table']['article'] ?></th>
<th style="text-align: center;padding-right: 6pt"><?= $text['table']['articleNumber'] ?></th>
<th style="text-align: right"><?= $text['table']['amount'] ?></th>
<th style="text-align: right"><?= $text['table']['unitPrice'] ?></th>
<th style="text-align: right;padding-right: 8pt"><?= $text['table']['totalPrice'] ?></th>
</tr>
<?php $i = 0; foreach($order['positions'] as $p):?>
<?php $i = 0;
foreach ($order['positions'] as $p): ?>
<tr class="position <?=($i%2 == 0) ? "even" : "uneven" ?>">
<td style="text-align: center;"><?= $i + 1 ?></td>
<td style="text-align: left;padding-right: 8pt"><?=$p["articleName"]?></td>
<td style="text-align: center;padding-right: 8pt"><?=$p["distributorArticleNumber"]?></td>
<td style="text-align: right"><?=$p["amount"]?></td>
<td style="text-align: right"><?=number_format($p["buyPrice"], 2, ",", ".")?> €</td>
<td style="text-align: right;padding-right: 8pt"><?=number_format($p["amount"] * $p["buyPrice"], 2, ",", ".")?> €</td>
</tr>
<?php $i++; endforeach;?>
<!-- display a grey like header sum with top border to differentiate 2nd last td = Summe , last td is the calculated value both bold-->
<tr class="position <?= ($i % 2 == 0) ? "even" : "uneven" ?>">
<td style="text-align: center;"><?= $i + 1 ?></td>
<td style="text-align: left;padding-right: 8pt"><?= $p["articleName"] ?></td>
<td style="text-align: center;padding-right: 8pt"><?= $p["distributorArticleNumber"] ?></td>
<td style="text-align: right"><?= $p["amount"] ?></td>
<td style="text-align: right"><?= number_format($p["buyPrice"], 2, ",", ".") ?> €</td>
<td style="text-align: right;padding-right: 8pt"><?= number_format($p["amount"] * $p["buyPrice"], 2, ",", ".") ?> €</td>
</tr>
<tr class="<?= ($i % 2 == 0) ? "even" : "uneven" ?>">
<td></td>
<td style="text-align: left;max-width: 200px"><?= $p["articleDescription"] ?></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<?php $i++; endforeach; ?>
<tr class="uneven">
<?php
$sum = 0;
foreach($order['positions'] as $p){
foreach ($order['positions'] as $p) {
$sum += $p["amount"] * $p["buyPrice"];
}
?>
<td colspan="5" style="text-align: right;border-top: 1px solid black;font-weight: bold
;border-bottom: 1px solid black;
">Summe</td>
"><?= $text['sum'] ?>
</td>
<td style="text-align: right;border-top: 1px solid black;font-weight: bold
;border-bottom: 1px solid black;
"><?=number_format($sum, 2, ",", ".")?> €</td>
"><?= number_format($sum, 2, ",", ".") ?> €
</td>
</tr>
<?php if ($distributorCountryText === "Österreich"): ?>
<tr style="font-weight: bold; border-bottom: 1px solid black; background-color: #ebebeb;">
<td colspan="5" style="text-align: right;font-weight: bold;">20% MwSt</td>
<td style="text-align: right;font-weight: bold;"><?= number_format($sum * 0.2, 2, ",", ".") ?> €</td>
</tr>
<tr class="uneven" style="font-weight: bold; border-bottom: 3px double black; background-color: #ebebeb;">
<td colspan="5" style="text-align: right;font-weight: bold;"><?= $text['total'] ?></td>
<td style="text-align: right;font-weight: bold;"><?= number_format($sum * 1.2, 2, ",", ".") ?> €</td>
</tr>
<?php endif; ?>
</table>
<div>
<h3>Anmerkungen</h3>
<p>
<?=$order["note"]?>
</p>
<?php if ($distributorCountryText !== "Österreich"): ?>
<?= $text['taxFree'] ?>
<?php endif; ?>
<?= $text['orderConfirmation'] ?>
</div>
</body>
</html>

View File

@@ -61,6 +61,8 @@
</head>
<body>
<script src="https://cdn.jsdelivr.net/npm/sortablejs@1.14.0/Sortable.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue-draggable-next@2.1.0"></script>
<script type="text/javascript">
baseurl = '<?=self::getResourcePath()?>';
</script>

View File

@@ -30,6 +30,10 @@ class WarehouseOfferController extends TTCrud {
['key' => 'sendOffer', 'title' => 'Angebot senden', 'class' => 'fas fa-paper-plane text-success']
];
protected array $additionalJS = ['
https://cdn.jsdelivr.net/npm/sortablejs@1.14.0/Sortable.min.js
https://cdn.jsdelivr.net/npm/vue-draggable-next@2.1.0'];
protected array $infoMessages = [
'create' => 'Angebot wurde erfolgreich erstellt.',
'update' => 'Angebot wurde aktualisiert.',

View File

@@ -9,18 +9,18 @@ class WarehouseOrderController extends TTCrud {
protected array $columns = [
['key' => 'id', 'text' => 'ID', 'modal' => false, 'table' => false],
['key' => 'orderNumber', 'text' => 'Bestellnummer', 'required' => true, 'modal' => false],
['key' => 'distributor', 'text' => 'Lieferant', 'required' => false, 'modal' => false, 'table' => ['filter' => false]],
['key' => 'distributorId', 'text' => 'Lieferant', 'required' => false, 'modal' => ['type' => 'select', 'items' => []], 'table' => ['filter' => 'select']],
['key' => 'delAddrCity', 'text' => 'Stadt', 'required' => true, 'modal' => false, 'table' => false],
['key' => 'delAddrEMail', 'text' => 'E-Mail', 'required' => true, 'modal' => false, 'table' => false],
['key' => 'delAddrLine', 'text' => 'Adresse', 'required' => true, 'modal' => false, 'table' => false],
['key' => 'delAddrName', 'text' => 'Name', 'required' => true, 'modal' => false, 'table' => false],
['key' => 'delAddrPLZ', 'text' => 'PLZ', 'required' => true, 'modal' => false, 'table' => false],
['key' => 'editor', 'text' => 'Bearbeiter', 'required' => true, 'modal' => ['type' => 'select'], 'table' => ['filter' => 'select']],
['key' => 'note', 'text' => 'Notiz', 'required' => true, 'modal' => false, 'table' => false],
['key' => 'note', 'text' => 'Notiz', 'required' => false, 'modal' => false, 'table' => false],
['key' => 'sum', 'text' => 'Summe', 'required' => false, 'modal' => false, 'table' => ['class' => 'text-right']],
['key' => 'status', 'text' => 'Status', 'required' => false, 'modal' => ['type' => 'select', 'items' => []], 'table' => ['filter' => 'select']],
['key' => 'positions', 'text' => 'Positionen', 'required' => true, 'modal' => false, 'table' => false],
['key' => 'extReference', 'text' => 'Externe Referenz', 'required' => true, 'modal' => false],
['key' => 'extReference', 'text' => 'Externe Referenz', 'required' => false, 'modal' => false],
['key' => 'createBy', 'text' => 'Erstellt von', 'required' => true, 'modal' => ['type' => 'select'], 'table' => ['filter' => 'select']],
['key' => 'create', 'text' => 'Erstellt', 'required' => true, 'modal' => false],
['key' => 'actions', 'text' => 'Aktionen', 'required' => false, 'modal' => false, 'table' => ['filter' => false, 'sortable' => false, 'class' => 'text-center']],
@@ -32,6 +32,8 @@ class WarehouseOrderController extends TTCrud {
'delete' => 'Bestellung wurde gelöscht',
'noChanges' => 'Keine Änderungen',];
protected array $additionalActions = [['key' => 'openpdf', 'title' => 'PDF öffnen', 'class' => 'fas fa-file-pdf', 'color' => 'primary']];
protected function prepareCrudConfig(): void {
$editorColumnIndex = array_search('editor', array_column($this->columns, 'key'));
$this->columns[$editorColumnIndex]['modal']['items'] = array_map(function ($user) {
@@ -48,6 +50,11 @@ class WarehouseOrderController extends TTCrud {
['value' => 'fullyDelivered', 'text' => 'Geliefert'],
['value' => 'cancelled', 'text' => 'Storniert'],
];
$distributorIndex = array_search('distributorId', array_column($this->columns, 'key'));
$this->columns[$distributorIndex]['modal']['items'] = array_map(function ($distributor) {
return ['value' => intval($distributor->id), 'text' => $distributor->name];
}, WarehouseDistributorModel::getAll());
}
protected function beforeCreate(): bool {
@@ -91,40 +98,43 @@ class WarehouseOrderController extends TTCrud {
// we need to get the article name and distributor name for the pdf
$position['distributorName'] = WarehouseDistributorModel::get($position['distributorId'])->name;
$position['articleName'] = WarehouseArticleModel::get($position['article'])->title;
$position['articleDescription'] = WarehouseArticleModel::get($position['article'])->description;
$order['positions'][$key] = $position;
}
$pdf_vars = ['order' => $order,
'distributor' => WarehouseDistributorModel::get($distributorId),
'distributorCountryText' => (new Country(WarehouseDistributorModel::get($distributorId)->countryId))->name,
"bank_iban" => TT_INVOICE_BANK_IBAN,
"bank_bic" => TT_INVOICE_BANK_BIC,
"bank_bank" => TT_INVOICE_BANK_BANK,
"bank_owner" => TT_INVOICE_BANK_OWNER];
$countryText = CountryModel::search(['id' => WarehouseDistributorModel::get($distributorId)->countryId])[0]->name;
$countryText = (new Country(WarehouseDistributorModel::get($distributorId)->countryId))->name;
$shouldGenerateEnglisch = !in_array($countryText, ['Österreich', 'Deutschland', 'Schweiz']);
$headerHtml = file_get_contents(BASEDIR . "/Layout/default/WarehouseOrder/PDF_HEADER.html");
$headerHtml = str_replace("{{ basedir }}", BASEDIR, $headerHtml);
$headerHtml = str_replace("{{ externalReference }}","<strong>Ihre Referenz:</strong> ". $order['extReference'], $headerHtml);
$headerHtml = str_replace("{{ externalReference }}", count($order['extReference']) > 0 ? "<strong>Ext. Ref.:</strong> ". $order['extReference'] : "", $headerHtml);
$headerHtml = str_replace("{{ addressLine_header }}", $shouldGenerateEnglisch ? "Supplier" : "Lieferant", $headerHtml);
$headerHtml = str_replace("{{ addressLine_1 }}", WarehouseDistributorModel::get($distributorId)->name, $headerHtml);
$headerHtml = str_replace("{{ addressLine_2 }}", WarehouseDistributorModel::get($distributorId)->address, $headerHtml);
$headerHtml = str_replace("{{ addressLine_3 }}", WarehouseDistributorModel::get($distributorId)->plz . " " . WarehouseDistributorModel::get($distributorId)->city, $headerHtml);
$headerHtml = str_replace("{{ addressLine_4 }}", $countryText, $headerHtml);
$headerHtml = str_replace("{{ billingAddressLine_header }}", $shouldGenerateEnglisch ? "Billing Address" : "Rechnungsadresse", $headerHtml);
$headerHtml = str_replace("{{ billingAddressLine_1 }}", "Xinon GmbH", $headerHtml);
$headerHtml = str_replace("{{ billingAddressLine_2 }}", "Fladnitz im Raabtal 150", $headerHtml);
$headerHtml = str_replace("{{ billingAddressLine_3 }}", "8322 Studenzen", $headerHtml);
$headerHtml = str_replace("{{ billingAddressLine_4 }}", "Österreich", $headerHtml);
$headerHtml = str_replace("{{ billingAddressLine_5 }}", "einkauf@xinon.at", $headerHtml);
$headerHtml = str_replace("{{ billingAddressLine_3 }}", "A-8322 Studenzen", $headerHtml);
$headerHtml = str_replace("{{ billingAddressLine_4 }}", "UID: ATU68711968", $headerHtml);
$headerHtml = str_replace("{{ billingAddressLine_5 }}", "EORI-Nr.: ATEOS1000085074", $headerHtml);
$headerHtml = str_replace("{{ billingAddressLine_6 }}", "<strong>Referenz: ". $order["orderNumber"] . "</strong>", $headerHtml);
// if order dellAddrLine is Fladnitz im Raabtal 150 we need to set all template strings to empty
$chk = $order['delAddrLine'] == "Fladnitz im Raabtal 150";
$headerHtml = str_replace("{{ shippingAddressLine_header }}", $chk ? "" : ($shouldGenerateEnglisch ? "Shipping Address" : "Lieferadresse"), $headerHtml);
$headerHtml = str_replace("{{ shippingAddressLine_1 }}", $chk ? "" : $order['delAddrName'], $headerHtml);
$headerHtml = str_replace("{{ shippingAddressLine_2 }}", $chk ? "" : $order['delAddrLine'], $headerHtml);
$headerHtml = str_replace("{{ shippingAddressLine_3 }}", $chk ? "" : $order['delAddrPLZ'] . " " . $order['delAddrCity'], $headerHtml);

View File

@@ -15,24 +15,22 @@ Vue.component('warehouse-offer-modal', {
sm
row
v-model="offer.editor"/>
<tt-input label="Kundennummer" v-model="offer.customerNumber" sm row/>
<tt-autocomplete label="Kunde" v-model="offer.customerNumber" sm row :api-url="billAddrAutoCompleteUrl"/>
<tt-input label="Kundenreferenz" v-model="offer.reference" sm row/>
<tt-textarea label="Angebotszweck" v-model="offer.purpose" sm row/>
<hr>
<h4 class="text-center">Kundenadresse</h4>
<div style="display: grid; grid-gap: 10px; grid-template-columns: 2fr 2fr 1fr 1fr 2fr;">
<div style="display: grid; grid-gap: 10px; grid-template-columns: 2fr 1fr 2fr 1fr 1fr;">
<tt-input label="Name" v-model="offer.customerName" sm/>
<tt-input label="Kontakt" v-model="offer.contactPerson" sm/>
<tt-input label="Straße" v-model="offer.customerStreet" sm/>
<tt-input label="PLZ" v-model="offer.customerZip" sm/>
<tt-input label="Ort" v-model="offer.customerCity" sm/>
<tt-input label="UID" v-model="offer.customerVAT" sm/>
</div>
<hr>
<h4 class="text-center">Positionen</h4>
<tt-positions-manager ref="positionsManager" v-model="offer.positions" :config="positionsConfig" @updateField-article="fetchArticleData"/>
<hr>
<h4 class="text-center">Alternative Artikel</h4>
<tt-positions-manager ref="alternativePositionsManager" v-model="offer.alternativePositions" :config="alternativePositionsConfig"/>
<tt-positions-manager group-mode ref="positionsManager" v-model="offer.positions" :config="positionsConfig" @updateField-article="fetchArticleData"/>
<hr>
<tt-input label="Gesamtrabatt (%)" v-model="offer.totalDiscount" sm row type="number"/>
<tt-select label="Zahlungskonditionen" :options="paymentTerms" sm row v-model="offer.paymentTerms"/>
@@ -45,6 +43,7 @@ Vue.component('warehouse-offer-modal', {
`,
data() {
return {
billAddrAutoCompleteUrl: window.TT_CONFIG['BASE_PATH'] + '/Address/Api?do=findAddress&fibu_primary_account=1',
window: window,
positionsConfig: {
fields: {
@@ -57,6 +56,7 @@ Vue.component('warehouse-offer-modal', {
amount: {type: 'input', label: 'Menge', inputType: 'number'},
unit: {type: 'input', label: 'Einheit'},
articleNumber: {type: 'input', label: 'Artikelnummer'},
isAlternative: {type: 'checkbox', label: 'Alternativposition'},
unitPrice: {type: 'input', label: 'Einzelpreis', inputType: 'number'},
discount: {type: 'input', label: 'Rabatt (%)', inputType: 'number'},
},
@@ -71,12 +71,6 @@ Vue.component('warehouse-offer-modal', {
return true;
},
},
alternativePositionsConfig: {
fields: {
article: {type: 'input', label: 'Artikel'},
description: {type: 'textarea', label: 'Beschreibung'},
},
},
paymentTerms: [
{value: 'net30', text: '30 Tage netto'},
{value: 'net60', text: '60 Tage netto'},

View File

@@ -218,19 +218,20 @@ Vue.component('warehouse-order', {
<tt-card>
<warehouse-order-modal v-if="orderModalId" :id="orderModalId" @close="closeOrderModal"/>
<button @click="orderModalId = 'create'" class="btn btn-primary">Bestellung erstellen</button>
<tt-table-crud emit-edit @edit="orderModalId = $event.id" ref="table">
<tt-table-crud emit-edit
@openpdf="window.open(window.TT_CONFIG['BASE_PATH'] + '/WarehouseOrder/createPDF?id=' + $event.id)"
@edit="orderModalId = $event.id" ref="table">
<template v-slot:expandedRow="{ row }">
<warehouse-order-detail :id="row['id']"/>
</template>
<template v-slot:sum="{ row }">{{ calculateSum(JSON.parse(row["positions"])).toFixed(2)}} €</template>
<!-- TODO: think of a way here prob we add it to the database as field-->
<template v-slot:distributor="{ row }">{{ row.id % 2 == 0 ? 'Triotronik' : 'Discomp' }}</template>
</tt-table-crud>
</tt-card>
`,
data() {
return {
window: window,
orderModalId: null,
}
},

View File

@@ -1,13 +1,42 @@
Vue.component('tt-resolver', {
props: {
value: {type: Number, required: true},
reference: {type: String, required: true},
},
data() {
return {
window: window,
loading: true,
text: '',
}
},
template: `
<div v-if="loading" class="d-flex justify-content-center align-items-center">
<div class="spinner-border spinner-border-sm text-primary" role="status">
<span class="sr-only">Loading...</span>
</div>
</div>
<span v-else>{{ text }}</span>
`,
async created() {
const entry = await axios.get(window.TT_CONFIG['BASE_PATH'] + '/' + this.reference + '/getById?id=' + this.value);
this.text = entry.data.name ?? entry.data.title ?? entry.data.text ?? '[E] Key not found';
this.loading = false;
}
})
Vue.component('tt-positions-manager', {
props: {
value: {type: Array, required: false},
config: {type: Object, required: true},
value: {type: Array, required: false},
config: {type: Object, required: true},
groupMode: {type: Boolean, default: false},
},
data() {
return {
window: window,
positions: this.value,
formData: {},
groupName: '',
selectedIndex: null,
resolvingFields: {},
}
@@ -63,6 +92,12 @@ Vue.component('tt-positions-manager', {
</div>
</div>
<div class="form-container" v-if="groupMode">
<tt-input label="Gruppenname" v-model="groupName" sm/>
<tt-button @click="addGroup" sm text="Gruppe hinzufügen" additional-class="btn-primary"/>
</div>
<table class="table table-striped table-sm">
<thead>
<tr>
@@ -71,24 +106,50 @@ Vue.component('tt-positions-manager', {
</tr>
</thead>
<tbody>
<tr v-for="(position, index) in positions" :key="index">
<td v-for="(field, key) in config.fields">
<template v-if="resolvingFields[index + key] === true">
<div class="d-flex justify-content-center align-items-center">
<div class="spinner-border spinner-border-sm text-primary" role="status">
<span class="sr-only">Loading...</span>
<template v-if="groupMode">
<template v-for="(groupPositions, groupName) in groupedPositions">
<tr>
<td colspan="100%">
<h4 style="text-align: center;">{{ groupName }}</h4>
</td>
<tr v-for="(position, index) in groupPositions" :key="groupName + index">
<td v-for="(field, key) in config.fields">
<tt-resolver v-if="field.customFieldReference" :reference="field.customFieldReference" :value="position[key]"/>
<span v-else>{{ formatFieldValue(position[key], field) }}</span>
</td>
<td>
<select v-model="position._group" @change="$set(position, '_group', $event.target.value)">
<option v-for="group in allGroups" :value="group">{{ group }}</option>
</select>
<button @click="editEntry(index)" class="btn btn-sm btn-primary">Editieren</button>
<button @click="deleteEntry(index)" class="btn btn-sm btn-danger">Löschen</button>
</td>
</tr>
</template>
</template>
<template v-else>
<tr v-for="(position, index) in positions" :key="index">
<td v-for="(field, key) in config.fields">
<template v-if="resolvingFields[index + key] === true">
<div class="d-flex justify-content-center align-items-center">
<div class="spinner-border spinner-border-sm text-primary" role="status">
<span class="sr-only">Loading...</span>
</div>
</div>
</div>
</template>
</template>
<span v-else-if="resolvingFields[index + key]">{{ resolvingFields[index + key] }}</span>
<span v-else>{{ formatFieldValue(position[key], field) }}</span>
</td>
<td>
<button @click="editEntry(index)" class="btn btn-sm btn-primary">Editieren</button>
<button @click="deleteEntry(index)" class="btn btn-sm btn-danger">Löschen</button>
</td>
</tr>
<span v-else-if="resolvingFields[index + key]">{{ resolvingFields[index + key] }}</span>
<span v-else>{{ formatFieldValue(position[key], field) }}</span>
</td>
<td>
<select v-model="position._group" @change="position._group = $event">
<option v-for="group in allGroups" :value="group">{{ group }}</option>
</select>
<button @click="editEntry(index)" class="btn btn-sm btn-primary">Editieren</button>
<button @click="deleteEntry(index)" class="btn btn-sm btn-danger">Löschen</button>
</td>
</tr>
</template>
</tbody>
</table>
</div>
@@ -110,6 +171,10 @@ Vue.component('tt-positions-manager', {
this.$emit('input', this.positions);
this.resetForm();
},
addGroup() {
this.positions.push({_group: this.groupName});
this.groupName = '';
},
editEntry(index) {
this.selectedIndex = index;
this.formData = {...this.positions[index]};
@@ -133,7 +198,7 @@ Vue.component('tt-positions-manager', {
this.$set(this.resolvingFields, i + key, true);
const textValue = await this.config.fields[key].customFieldResolver(this.positions[i][key]);
this.$set(this.resolvingFields, i + key, textValue);
} else if (this.config.fields[key].customFieldReference) {
} else if (this.config.fields[key].customFieldReference && this.positions[i][key]) {
this.$set(this.resolvingFields, i + key, true);
if (this.config.fields[key].customFieldReference) {
const entry = await axios.get(window.TT_CONFIG['BASE_PATH'] +
@@ -153,7 +218,21 @@ Vue.component('tt-positions-manager', {
created() {
if (this.config.customMethods) Object.assign(this, this.config.customMethods);
},
watch: {
computed: {
groupedPositions() {
const groups = {};
for (const position of this.positions) {
const group = position._group ?? 'Keine Gruppe';
if (!groups[group]) groups[group] = [];
if (Object.keys(position).length !== 1) groups[group].push(position);
}
return groups;
},
allGroups() {
return Object.keys(this.groupedPositions);
}
},
watch: {
positions: {
handler() {
this.resolveFields().then();