Merge branch 'ConstructionConsent/fix-addr-search' into 'master'
added construction consent owner import See merge request fronk/thetool!1238
This commit is contained in:
@@ -164,8 +164,11 @@ $pagination_entity_name = "Zustimmungserklärungen";
|
||||
<div class="col">
|
||||
<button type="submit" class="btn btn-primary"><i class="far fa-search fa-fw"></i> Filter anwenden</button>
|
||||
<a class="btn btn-secondary" href="<?=self::getUrl("ConstructionConsent", "", ["resetFilter" => 1, "filter" => ["project_id" => (is_array($filter) && array_key_exists("project_id", $filter) ? $filter["project_id"] : "")]])?>"><i class="far fa-xmark fa-fw"></i> Filter zurücksetzen</a>
|
||||
<input type="file" id="csvFileInput" accept=".csv" class="d-none">
|
||||
<?php if ($me->isAdmin() && is_array($filter) && array_key_exists("project_id", $filter) && !empty($filter["project_id"])): ?>
|
||||
<label style="margin-bottom: 0; cursor: pointer" for="csvFileInput" class="btn btn-info"><i class="fas fa-upload fa-fw"></i> Eigentümer-CSV Import</label>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<!-- create a div that is on the right side of the row-->
|
||||
<div class="col text-right">
|
||||
<a class="btn btn-success" href="<?=self::getUrl("ConstructionConsent", "downloadMultiple", ["filter" => $filter])?>"><i class="fas fa-download"></i> Zustimmungserklärungen herunterladen</a>
|
||||
</div>
|
||||
@@ -449,4 +452,60 @@ $pagination_entity_name = "Zustimmungserklärungen";
|
||||
background-color: #337ab7; /* Blue */
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const csvFileInput = document.getElementById('csvFileInput');
|
||||
const apiUrl = '<?=self::getUrl("ConstructionConsent", "importConstructionConsentOwners", ["project_id" => (is_array($filter) && array_key_exists("project_id", $filter) ? $filter["project_id"] : "")])?>';
|
||||
|
||||
const csvToJson = csv => {
|
||||
let [headerLine, ...lines] = csv.trim().split(/\r?\n/).filter(Boolean);
|
||||
if (!headerLine || lines.length === 0) return [];
|
||||
const headers = headerLine.split(';').map(h => h.trim());
|
||||
return lines.map(row => {
|
||||
const values = row.split(';').map(v => v.trim().replaceAll('"', ''));
|
||||
return headers.reduce((obj, key, i) => ({ ...obj, [key]: values[i] || '' }), {});
|
||||
});
|
||||
};
|
||||
|
||||
csvFileInput.addEventListener('change', async e => {
|
||||
const file = e.target.files[0];
|
||||
e.target.value = ''; // Clear input immediately
|
||||
|
||||
if (!file || !file.name.toLowerCase().endsWith('.csv')) {
|
||||
return window.notify('warning', "Bitte wählen Sie eine gültige CSV-Datei aus.");
|
||||
}
|
||||
|
||||
try {
|
||||
const fileContent = await file.text();
|
||||
const jsonData = csvToJson(fileContent);
|
||||
|
||||
if (jsonData.length === 0) {
|
||||
return window.notify('warning', "CSV-Datei ist leer oder ungültig.");
|
||||
}
|
||||
|
||||
if (!confirm("Sind Sie sicher, dass Sie die CSV-Daten importieren möchten?")) return;
|
||||
|
||||
const response = await fetch(apiUrl, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' },
|
||||
body: JSON.stringify(jsonData)
|
||||
});
|
||||
|
||||
if (!response.ok) throw new Error(`HTTP error ${response.status}`);
|
||||
|
||||
const result = await response.json(); // Expect { created: N, updated: M, skipped: K }
|
||||
window.notify('success', `Import erfolgreich: ${result.counts.created || 0} erstellt, ${result.counts.updated || 0} aktualisiert, ${result.counts.skipped || 0} übersprungen.`);
|
||||
console.log("Response:", result);
|
||||
|
||||
} catch (error) {
|
||||
console.error("Import Error:", error);
|
||||
window.notify('error', 'Fehler beim Verarbeiten oder Importieren der CSV-Daten.');
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
<?php include(realpath(dirname(__FILE__)."/../../$mfLayoutPackage")."/footer.php"); ?>
|
||||
|
||||
@@ -1042,4 +1042,53 @@ class ConstructionConsentController extends mfBaseController {
|
||||
$this->returnJson(["status" => "OK"]);
|
||||
|
||||
}
|
||||
|
||||
protected function importConstructionConsentOwnersAction() {
|
||||
$projectId = $this->request->project_id;
|
||||
$importData = json_decode(file_get_contents('php://input'), true);
|
||||
|
||||
if (empty($importData) || !is_array($importData)) { $this->layout()->setFlash("Keine Daten gefunden", "error"); return $this->redirect("ConstructionConsent"); }
|
||||
if (!is_numeric($projectId) || $projectId < 1) { $this->layout()->setFlash("Projekt nicht gefunden", "error"); return $this->redirect("ConstructionConsent"); }
|
||||
if (!($consentProject = new ConstructionConsentProject($projectId))->id) { $this->layout()->setFlash("Projekt nicht gefunden", "error"); return $this->redirect("ConstructionConsent"); }
|
||||
|
||||
$counts = ["created" => 0, "updated" => 0, "skipped" => 0];
|
||||
|
||||
foreach ($importData as $ownerData) {
|
||||
$consentFilter = ["constructionconsentproject_id" => $consentProject->id, "kg" => $ownerData["KG-EZ"] ?? null, "ez" => $ownerData["EZ"] ?? null, "lnr" => $ownerData["LNR"] ?? null];
|
||||
if (!($consentRecord = ConstructionConsent::getFirst(array_filter($consentFilter)))) {
|
||||
$counts["skipped"]++; continue;
|
||||
}
|
||||
|
||||
$birthdate = (isset($ownerData["GEB"]) && preg_match("/^\d{4}-\d{2}-\d{2}$/", $ownerData["GEB"])) ? $ownerData["GEB"] : null;
|
||||
$ownerFilter = ["constructionconsent_id" => $consentRecord->id, "firstname" => $ownerData["VN"] ?? null, "lastname" => $ownerData["NN"] ?? null];
|
||||
if ($birthdate) { $ownerFilter["birthdate"] = $birthdate; }
|
||||
|
||||
$isNew = !($ownerRecord = ConstructionConsentOwner::getFirst(array_filter($ownerFilter)));
|
||||
if ($isNew) $ownerRecord = new ConstructionConsentOwner(["constructionconsent_id" => $consentRecord->id]);
|
||||
|
||||
$addressKey = null; foreach(array_keys($ownerData) as $k) { if(strpos($k,"ADR") === 0) {$addressKey=$k; break;} }
|
||||
$street = $city = $postcode = $country = null;
|
||||
if ($addressKey && isset($ownerData[$addressKey])) {
|
||||
$addressParts = explode(", ", str_replace('"', '', $ownerData[$addressKey]));
|
||||
$street = $addressParts[0] ?? null;
|
||||
if (isset($addressParts[1])) { list($postcode, $city) = array_pad(explode(" ", trim($addressParts[1]), 2), 2, null); }
|
||||
$country = $addressParts[2] ?? null;
|
||||
}
|
||||
|
||||
$ownerRecord->firstname = $ownerData["VN"] ?? null;
|
||||
$ownerRecord->lastname = (($ownerData["JUR"] ?? 'nein') === "ja") ? ($ownerData['BEZ'] ?? $ownerData["NN"]) : ($ownerData["NN"] ?? null);
|
||||
$ownerRecord->birthdate = $birthdate;
|
||||
$ownerRecord->street = $street;
|
||||
$ownerRecord->city = $city;
|
||||
$ownerRecord->zip = $postcode;
|
||||
$ownerRecord->country = $country;
|
||||
$ownerRecord->save();
|
||||
|
||||
$counts[$isNew ? "created" : "updated"]++;
|
||||
}
|
||||
|
||||
self::returnJson(["status" => "OK", "counts" => $counts]);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -221,9 +221,21 @@ class ConstructionConsentOwner extends mfBaseModel {
|
||||
$constructionconsent_id = $filter['constructionconsent_id'];
|
||||
if(is_numeric($constructionconsent_id)) {
|
||||
$where .= " AND constructionconsent_id=$constructionconsent_id";
|
||||
} else if(is_array($constructionconsent_id)) {
|
||||
$where .= " AND constructionconsent_id IN (".implode(",", $constructionconsent_id).")";
|
||||
}
|
||||
}
|
||||
|
||||
foreach($filter as $field => $value)
|
||||
if(in_array($field, ["firstname", "lastname", "street", "zip", "city", "country", "phone", "phone2", "birthdate", "fax", "email"]))
|
||||
if(is_array($value)) {
|
||||
$where .= " AND $field IN ('".implode("','", $value)."')";
|
||||
} else {
|
||||
$where .= " AND $field LIKE '%$value%'";
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if(array_key_exists("add-where", $filter)) {
|
||||
|
||||
@@ -42,11 +42,11 @@ class WarehouseEShopController extends TTCrud {
|
||||
$warehouseArticleFilter['isEShop'] = 1;
|
||||
$warehouseArticleFilter['isEShopHide'] = 0;
|
||||
|
||||
$warehouseArticles = WarehouseArticleModel::getAll($warehouseArticleFilter, $perPage, ($page - 1) * $perPage, $order);
|
||||
$warehouseArticles = WarehouseArticleModel::getAll($warehouseArticleFilter, null, 0, $order);
|
||||
$warehouseArticlesTotal = WarehouseArticleModel::count(['isEShop' => 1, 'isEShopHide' => 0]);
|
||||
$warehouseArticlesAvailable = WarehouseArticleModel::count($warehouseArticleFilter);
|
||||
|
||||
$warehousePackets = WarehouseArticlePacketModel::getAll();
|
||||
$warehousePackets = WarehouseArticlePacketModel::getAll($filter, null, 0, $order);
|
||||
$warehousePacketsTotal = WarehouseArticlePacketModel::count();
|
||||
$warehousePacketsAvailable = WarehouseArticlePacketModel::count($filter);
|
||||
|
||||
@@ -54,6 +54,8 @@ class WarehouseEShopController extends TTCrud {
|
||||
$totalRows = $warehouseArticlesTotal + $warehousePacketsTotal;
|
||||
$rows = [...$warehouseArticles, ...$warehousePackets];
|
||||
|
||||
$rows = array_slice($rows, ($page - 1) * $perPage, $perPage);
|
||||
|
||||
self::returnJson(["rows" => $rows,
|
||||
"pagination" => ["page" => $page,
|
||||
"total_pages" => ceil($filteredAvailable / $perPage),
|
||||
|
||||
Reference in New Issue
Block a user