fix: dispensa.db auto-delete, zerowaste save, vacuum expiry, DB retention

- api/index.php: auto-delete legacy dispensa.db when evershelf.db exists
  and dispensa.db is empty (<1KB); vacuum-sealed items only show as
  expired after VACUUM_EXPIRY_EXTENSION_DAYS (default 30) past printed
  date; add dbCleanup() function; add recipe/tx/vacuum params to
  getServerSettings + saveSettings intMap; add 'db_cleanup' action
- api/cron_smart_shopping.php: run dbCleanup() each cron cycle
- app.js: add zerowaste_tips_enabled + screensaver_timeout + retention
  days to saveSettings POST payload (were missing, causing reset on sync);
  asset version bumped to v=20260518b
- .env: added ZEROWASTE_TIPS_ENABLED, RECIPE_RETENTION_DAYS=7,
  TRANSACTION_RETENTION_DAYS=7, VACUUM_EXPIRY_EXTENSION_DAYS=30
This commit is contained in:
dadaloop82
2026-05-18 07:16:26 +00:00
parent c9a859463c
commit bd5d4bcac6
4 changed files with 67 additions and 9 deletions
+13
View File
@@ -79,6 +79,19 @@ try {
echo '[' . date('Y-m-d H:i:s') . '] Shelf life pre-warm warning: ' . $pe->getMessage() . "\n";
}
// ── DB cleanup (retention policy) ────────────────────────────────────
// Delete old recipes and transactions based on .env retention settings.
try {
ob_start();
dbCleanup($db);
ob_end_clean();
echo '[' . date('Y-m-d H:i:s') . '] DB cleanup done'
. ' (recipes >' . env('RECIPE_RETENTION_DAYS','7') . 'd'
. ', tx >' . env('TRANSACTION_RETENTION_DAYS','7') . 'd' . ")\n";
} catch (Throwable $ce) {
echo '[' . date('Y-m-d H:i:s') . '] DB cleanup warning: ' . $ce->getMessage() . "\n";
}
} catch (Throwable $e) {
$msg = $e->getMessage();
echo '[' . date('Y-m-d H:i:s') . '] ERROR: ' . $msg . "\n";
+45 -5
View File
@@ -409,7 +409,13 @@ if (($_GET['action'] ?? '') === 'health_check') {
}
}
// Legacy DB still present alongside evershelf.db → warn
// Auto-delete legacy dispensa.db if evershelf.db already exists (it's just an empty leftover)
if ($hasLegacy && file_exists($dbPath) && filesize($legacyDb) < 1024) {
@unlink($legacyDb);
$hasLegacy = false;
}
// Legacy DB still present alongside evershelf.db → warn (should be rare now)
$checks['db_legacy'] = [
'ok' => !$hasLegacy,
'optional' => true,
@@ -898,6 +904,10 @@ try {
checkUpdate();
break;
case 'db_cleanup':
dbCleanup(getDB());
break;
case 'gemini_product_hint':
geminiProductHint();
break;
@@ -2492,14 +2502,19 @@ function getStats(PDO $db): void {
LIMIT 4
")->fetchAll();
// Expired
$expired = $db->query("
// Expired — vacuum-sealed items get extra days beyond printed expiry before being flagged
$vacExtDays = (int)env('VACUUM_EXPIRY_EXTENSION_DAYS', '30');
$expiredStmt = $db->prepare("
SELECT i.*, p.name, p.brand, p.category, p.unit, p.default_quantity, p.package_unit,
COALESCE(i.vacuum_sealed, 0) as vacuum_sealed
FROM inventory i JOIN products p ON i.product_id = p.id
WHERE i.expiry_date IS NOT NULL AND i.expiry_date < date('now') AND i.quantity > 0
WHERE i.expiry_date IS NOT NULL
AND julianday('now') - julianday(i.expiry_date) > CASE WHEN COALESCE(i.vacuum_sealed,0)=1 THEN ? ELSE 0 END
AND i.quantity > 0
ORDER BY i.expiry_date ASC
")->fetchAll();
");
$expiredStmt->execute([$vacExtDays]);
$expired = $expiredStmt->fetchAll();
// Opened (items with opened_at set by the app, OR fractional-qty items as legacy fallback)
// opened_at IS NOT NULL → already has recalculated expiry_date stored when first opened
@@ -2899,9 +2914,31 @@ function getServerSettings(): void {
'price_country' => env('PRICE_COUNTRY', 'Italia'),
'price_currency' => env('PRICE_CURRENCY', 'EUR'),
'price_update_months' => (int)env('PRICE_UPDATE_MONTHS', '3'),
'recipe_retention_days' => (int)env('RECIPE_RETENTION_DAYS', '7'),
'transaction_retention_days' => (int)env('TRANSACTION_RETENTION_DAYS', '7'),
'vacuum_expiry_extension_days' => (int)env('VACUUM_EXPIRY_EXTENSION_DAYS', '30'),
]);
}
function dbCleanup(?PDO $db = null): void {
$recipeDays = max(1, (int)env('RECIPE_RETENTION_DAYS', '7'));
$txDays = max(1, (int)env('TRANSACTION_RETENTION_DAYS', '7'));
$pdo = $db ?? getDB();
try {
// Delete old recipes (generated recipe plans)
$pdo->prepare("DELETE FROM recipes WHERE date < date('now', ? || ' days')")
->execute(["-$recipeDays"]);
// Delete old transactions (keep at least the last $txDays of history)
$pdo->prepare("DELETE FROM transactions WHERE created_at < datetime('now', ? || ' days') AND undone = 0")
->execute(["-$txDays"]);
// Compact the database
$pdo->exec('VACUUM');
echo json_encode(['success' => true, 'recipe_retention_days' => $recipeDays, 'transaction_retention_days' => $txDays]);
} catch (Throwable $e) {
echo json_encode(['success' => false, 'error' => $e->getMessage()]);
}
}
function saveSettings(): void {
// Require SETTINGS_TOKEN if configured
$requiredToken = env('SETTINGS_TOKEN');
@@ -2960,6 +2997,9 @@ function saveSettings(): void {
'default_persons' => 'DEFAULT_PERSONS',
'screensaver_timeout' => 'SCREENSAVER_TIMEOUT',
'price_update_months' => 'PRICE_UPDATE_MONTHS',
'recipe_retention_days' => 'RECIPE_RETENTION_DAYS',
'transaction_retention_days' => 'TRANSACTION_RETENTION_DAYS',
'vacuum_expiry_extension_days'=> 'VACUUM_EXPIRY_EXTENSION_DAYS',
];
// Float keys
$floatMap = [
+5
View File
@@ -3116,6 +3116,8 @@ async function saveSettings() {
scale_gateway_url: s.scale_gateway_url,
meal_plan_enabled: s.meal_plan_enabled,
screensaver_enabled: s.screensaver_enabled,
screensaver_timeout: s.screensaver_timeout || 5,
zerowaste_tips_enabled: s.zerowaste_tips_enabled,
tts_enabled: s.tts_enabled,
tts_url: s.tts_url,
tts_token: s.tts_token,
@@ -3133,6 +3135,9 @@ async function saveSettings() {
price_country: s.price_country,
price_currency: s.price_currency,
price_update_months: s.price_update_months,
recipe_retention_days: s.recipe_retention_days || 7,
transaction_retention_days: s.transaction_retention_days || 7,
vacuum_expiry_extension_days: s.vacuum_expiry_extension_days || 30,
}, tokenHeader);
const statusEl = document.getElementById('settings-status');
if (result.success) {
+1 -1
View File
@@ -1652,6 +1652,6 @@
</div>
</div>
<script src="assets/js/app.js?v=20260518a"></script>
<script src="assets/js/app.js?v=20260518b"></script>
</body>
</html>