Add address fields, e-invoice, stats and auto-backup
- Split address into street, postal code, city (sortable) - Add billing postal code/city fields - Add e-invoice address and operator fields - Add trivia stats (top postal code, top speed, avg price) - Improved layout with stat cards grid and max-width container - Sticky header, modal animations, search icon - Auto-backup on every save (keeps last 30 backups) - Footer added Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
24
api.php
24
api.php
@@ -31,6 +31,18 @@ function loadCustomers(): array {
|
||||
}
|
||||
|
||||
function saveCustomers(array $customers): void {
|
||||
// Automaattinen backup ennen tallennusta
|
||||
if (file_exists(DATA_FILE) && filesize(DATA_FILE) > 2) {
|
||||
$backupDir = __DIR__ . '/data/backups';
|
||||
if (!file_exists($backupDir)) mkdir($backupDir, 0755, true);
|
||||
copy(DATA_FILE, $backupDir . '/customers_' . date('Y-m-d_His') . '.json');
|
||||
// Säilytä vain 30 viimeisintä backuppia
|
||||
$backups = glob($backupDir . '/customers_*.json');
|
||||
if (count($backups) > 30) {
|
||||
sort($backups);
|
||||
array_map('unlink', array_slice($backups, 0, count($backups) - 30));
|
||||
}
|
||||
}
|
||||
file_put_contents(DATA_FILE, json_encode($customers, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
|
||||
}
|
||||
|
||||
@@ -78,13 +90,19 @@ switch ($action) {
|
||||
'id' => generateId(),
|
||||
'yritys' => trim($input['yritys'] ?? ''),
|
||||
'asennusosoite' => trim($input['asennusosoite'] ?? ''),
|
||||
'postinumero' => trim($input['postinumero'] ?? ''),
|
||||
'kaupunki' => trim($input['kaupunki'] ?? ''),
|
||||
'liittymanopeus' => trim($input['liittymanopeus'] ?? ''),
|
||||
'hinta' => floatval($input['hinta'] ?? 0),
|
||||
'yhteyshenkilö' => trim($input['yhteyshenkilö'] ?? ''),
|
||||
'puhelin' => trim($input['puhelin'] ?? ''),
|
||||
'sahkoposti' => trim($input['sahkoposti'] ?? ''),
|
||||
'laskutusosoite' => trim($input['laskutusosoite'] ?? ''),
|
||||
'laskutuspostinumero' => trim($input['laskutuspostinumero'] ?? ''),
|
||||
'laskutuskaupunki' => trim($input['laskutuskaupunki'] ?? ''),
|
||||
'laskutussahkoposti' => trim($input['laskutussahkoposti'] ?? ''),
|
||||
'elaskuosoite' => trim($input['elaskuosoite'] ?? ''),
|
||||
'elaskuvalittaja' => trim($input['elaskuvalittaja'] ?? ''),
|
||||
'ytunnus' => trim($input['ytunnus'] ?? ''),
|
||||
'lisatiedot' => trim($input['lisatiedot'] ?? ''),
|
||||
'luotu' => date('Y-m-d H:i:s'),
|
||||
@@ -111,13 +129,19 @@ switch ($action) {
|
||||
if ($c['id'] === $id) {
|
||||
$c['yritys'] = trim($input['yritys'] ?? $c['yritys']);
|
||||
$c['asennusosoite'] = trim($input['asennusosoite'] ?? $c['asennusosoite']);
|
||||
$c['postinumero'] = trim($input['postinumero'] ?? ($c['postinumero'] ?? ''));
|
||||
$c['kaupunki'] = trim($input['kaupunki'] ?? ($c['kaupunki'] ?? ''));
|
||||
$c['liittymanopeus'] = trim($input['liittymanopeus'] ?? $c['liittymanopeus']);
|
||||
$c['hinta'] = floatval($input['hinta'] ?? $c['hinta']);
|
||||
$c['yhteyshenkilö'] = trim($input['yhteyshenkilö'] ?? $c['yhteyshenkilö']);
|
||||
$c['puhelin'] = trim($input['puhelin'] ?? $c['puhelin']);
|
||||
$c['sahkoposti'] = trim($input['sahkoposti'] ?? $c['sahkoposti']);
|
||||
$c['laskutusosoite'] = trim($input['laskutusosoite'] ?? $c['laskutusosoite']);
|
||||
$c['laskutuspostinumero'] = trim($input['laskutuspostinumero'] ?? ($c['laskutuspostinumero'] ?? ''));
|
||||
$c['laskutuskaupunki'] = trim($input['laskutuskaupunki'] ?? ($c['laskutuskaupunki'] ?? ''));
|
||||
$c['laskutussahkoposti'] = trim($input['laskutussahkoposti'] ?? $c['laskutussahkoposti']);
|
||||
$c['elaskuosoite'] = trim($input['elaskuosoite'] ?? ($c['elaskuosoite'] ?? ''));
|
||||
$c['elaskuvalittaja'] = trim($input['elaskuvalittaja'] ?? ($c['elaskuvalittaja'] ?? ''));
|
||||
$c['ytunnus'] = trim($input['ytunnus'] ?? $c['ytunnus']);
|
||||
$c['lisatiedot'] = trim($input['lisatiedot'] ?? $c['lisatiedot']);
|
||||
$c['muokattu'] = date('Y-m-d H:i:s');
|
||||
|
||||
Reference in New Issue
Block a user