disable expired desired booking slots
This commit is contained in:
@@ -112,6 +112,23 @@ async function sendStoreWatchNotification({ profileId, storeName, storeId, regio
|
||||
});
|
||||
}
|
||||
|
||||
async function sendDesiredWindowMissedNotification({ profileId, storeName, desiredWindowLabel }) {
|
||||
if (!profileId) {
|
||||
return;
|
||||
}
|
||||
const title = `Keine Slots gefunden: ${storeName}`;
|
||||
const messageBase = desiredWindowLabel
|
||||
? `Für den gewünschten Zeitraum ${desiredWindowLabel} konnte kein Slot gefunden werden.`
|
||||
: 'Für den gewünschten Zeitraum konnte kein Slot gefunden werden.';
|
||||
const message = `${messageBase} Der Eintrag wurde deaktiviert.`;
|
||||
await notifyChannels(profileId, {
|
||||
title,
|
||||
message,
|
||||
link: null,
|
||||
priority: 'default'
|
||||
});
|
||||
}
|
||||
|
||||
async function sendTestNotification(profileId, channel) {
|
||||
const title = 'Pickup Benachrichtigung (Test)';
|
||||
const message = 'Das ist eine Testnachricht. Bei Fragen wende dich bitte an den Admin.';
|
||||
@@ -148,5 +165,6 @@ async function sendTestNotification(profileId, channel) {
|
||||
module.exports = {
|
||||
sendSlotNotification,
|
||||
sendStoreWatchNotification,
|
||||
sendTestNotification
|
||||
sendTestNotification,
|
||||
sendDesiredWindowMissedNotification
|
||||
};
|
||||
|
||||
@@ -80,7 +80,7 @@ function deactivateEntryInMemory(entry) {
|
||||
}
|
||||
}
|
||||
|
||||
function persistEntryDeactivation(profileId, entryId) {
|
||||
function persistEntryDeactivation(profileId, entryId, options = {}) {
|
||||
if (!profileId || !entryId) {
|
||||
return;
|
||||
}
|
||||
@@ -88,9 +88,27 @@ function persistEntryDeactivation(profileId, entryId) {
|
||||
const config = readConfig(profileId);
|
||||
let changed = false;
|
||||
const updated = config.map((item) => {
|
||||
if (String(item?.id) === String(entryId) && item?.active !== false) {
|
||||
if (String(item?.id) === String(entryId)) {
|
||||
let mutated = false;
|
||||
const updatedEntry = { ...item };
|
||||
if (item?.active !== false) {
|
||||
updatedEntry.active = false;
|
||||
mutated = true;
|
||||
}
|
||||
if (options.resetDesiredWindow) {
|
||||
if (updatedEntry.desiredDate !== undefined) {
|
||||
delete updatedEntry.desiredDate;
|
||||
mutated = true;
|
||||
}
|
||||
if (updatedEntry.desiredDateRange !== undefined) {
|
||||
delete updatedEntry.desiredDateRange;
|
||||
mutated = true;
|
||||
}
|
||||
}
|
||||
if (mutated) {
|
||||
changed = true;
|
||||
return { ...item, active: false };
|
||||
return updatedEntry;
|
||||
}
|
||||
}
|
||||
return item;
|
||||
});
|
||||
@@ -150,6 +168,89 @@ function toDateValue(input) {
|
||||
return new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime();
|
||||
}
|
||||
|
||||
function formatDesiredWindowLabel(entry) {
|
||||
if (!entry) {
|
||||
return null;
|
||||
}
|
||||
const formatValue = (value) => {
|
||||
if (!value) {
|
||||
return null;
|
||||
}
|
||||
const date = new Date(value);
|
||||
if (Number.isNaN(date.getTime())) {
|
||||
return null;
|
||||
}
|
||||
return date.toLocaleDateString('de-DE', {
|
||||
day: '2-digit',
|
||||
month: '2-digit',
|
||||
year: 'numeric'
|
||||
});
|
||||
};
|
||||
if (entry.desiredDateRange) {
|
||||
const startLabel = formatValue(entry.desiredDateRange.start);
|
||||
const endLabel = formatValue(entry.desiredDateRange.end);
|
||||
if (startLabel && endLabel) {
|
||||
return startLabel === endLabel ? startLabel : `${startLabel} – ${endLabel}`;
|
||||
}
|
||||
return startLabel || endLabel;
|
||||
}
|
||||
return formatValue(entry.desiredDate);
|
||||
}
|
||||
|
||||
function desiredWindowExpired(entry) {
|
||||
if (!entry?.active) {
|
||||
return false;
|
||||
}
|
||||
const todayValue = toDateValue(new Date());
|
||||
if (todayValue === null) {
|
||||
return false;
|
||||
}
|
||||
if (entry.desiredDateRange?.start || entry.desiredDateRange?.end) {
|
||||
const endValue = toDateValue(entry.desiredDateRange.end) ?? toDateValue(entry.desiredDateRange.start);
|
||||
return endValue !== null && endValue < todayValue;
|
||||
}
|
||||
const desiredValue = toDateValue(entry.desiredDate);
|
||||
return desiredValue !== null && desiredValue < todayValue;
|
||||
}
|
||||
|
||||
function resetDesiredWindow(entry) {
|
||||
if (!entry) {
|
||||
return;
|
||||
}
|
||||
if (entry.desiredDate !== undefined) {
|
||||
delete entry.desiredDate;
|
||||
}
|
||||
if (entry.desiredDateRange !== undefined) {
|
||||
delete entry.desiredDateRange;
|
||||
}
|
||||
}
|
||||
|
||||
async function handleExpiredDesiredWindow(session, entry) {
|
||||
const profileId = session?.profile?.id;
|
||||
const storeName = entry.label || entry.id;
|
||||
const desiredLabel = formatDesiredWindowLabel(entry);
|
||||
console.log(
|
||||
`[INFO] Wunschzeitraum abgelaufen für ${storeName}${desiredLabel ? ` (${desiredLabel})` : ''}. Eintrag wird deaktiviert.`
|
||||
);
|
||||
deactivateEntryInMemory(entry);
|
||||
resetDesiredWindow(entry);
|
||||
persistEntryDeactivation(profileId, entry.id, { resetDesiredWindow: true });
|
||||
if (profileId) {
|
||||
try {
|
||||
await notificationService.sendDesiredWindowMissedNotification({
|
||||
profileId,
|
||||
storeName,
|
||||
desiredWindowLabel: desiredLabel
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(
|
||||
`[NOTIFY] Benachrichtigung zum verpassten Zeitraum für ${storeName} fehlgeschlagen:`,
|
||||
error.message
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function matchesDesiredDate(pickupDate, desiredDate, desiredDateRange) {
|
||||
const pickupValue = toDateValue(pickupDate);
|
||||
if (pickupValue === null) {
|
||||
@@ -254,6 +355,11 @@ async function checkEntry(sessionId, entry, settings) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (desiredWindowExpired(entry)) {
|
||||
await handleExpiredDesiredWindow(session, entry);
|
||||
return;
|
||||
}
|
||||
|
||||
const ready = await ensureSession(session);
|
||||
if (!ready) {
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user