payday tests
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { todayInTz, resolveTz } from '@shared/timezone';
|
||||
import { todayInTz, resolveTz, wallClockToUtc } from '@shared/timezone';
|
||||
import { famMeta } from './fam';
|
||||
import { pbAdmin } from '$lib/server/pocketbase';
|
||||
|
||||
@@ -26,24 +26,35 @@ async function completeOnceConfig(famId: string, reward: any) {
|
||||
} catch {}
|
||||
}
|
||||
|
||||
export function assertPaydayUnlocked(reward: any, tz?: string) {
|
||||
// Payday-gated rewards (claimable 'payday', e.g. pocket money) unlock on the
|
||||
// settle DATE at the fam's configured payday TIME — not midnight. Anything
|
||||
// else (claimable 'immediate'/unset, e.g. manual triggers) is always claimable.
|
||||
export function assertPaydayUnlocked(reward: any, tz?: string, paydayTime?: string) {
|
||||
if (!reward || reward.claimable !== 'payday' || !reward.settleDate) return;
|
||||
const today = todayInTz(resolveServerTz(tz));
|
||||
if (today < reward.settleDate) {
|
||||
throw new Error(`This bonus pays out on payday (${reward.settleDate}) — hang tight!`);
|
||||
const resolvedTz = resolveServerTz(tz);
|
||||
const settle = (reward.settleDate as string).slice(0, 10);
|
||||
const today = todayInTz(resolvedTz);
|
||||
if (today < settle) {
|
||||
throw new Error(`This bonus pays out on payday (${settle}) — hang tight!`);
|
||||
}
|
||||
if (today === settle && paydayTime && /^\d{2}:\d{2}$/.test(paydayTime)) {
|
||||
const unlock = wallClockToUtc(settle, paydayTime, resolvedTz);
|
||||
if (Date.now() < unlock) {
|
||||
throw new Error(`This bonus unlocks at ${paydayTime} on payday — hang tight!`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Member claim → status 'requested' (pending parent approval).
|
||||
export async function claim(pb: any, famId: string, id: string) {
|
||||
const now = new Date().toISOString();
|
||||
const { tz } = await famMeta(pb, famId);
|
||||
const { tz, paydayTime } = await famMeta(pb, famId);
|
||||
const found = await pb
|
||||
.collection('rewards')
|
||||
.getFullList({ filter: `famId = '${famId}' && id = '${id}'` });
|
||||
const reward = found?.[0];
|
||||
if (!reward) throw new Error('Reward not found');
|
||||
assertPaydayUnlocked(reward, tz);
|
||||
assertPaydayUnlocked(reward, tz, paydayTime);
|
||||
return pb.collection('rewards').update(id, { status: 'requested', requestedAt: now });
|
||||
}
|
||||
|
||||
@@ -59,14 +70,14 @@ export async function approve(pb: any, famId: string, id: string) {
|
||||
|
||||
export async function requestAll(pb: any, famId: string, memberId: string) {
|
||||
const now = new Date().toISOString();
|
||||
const { tz } = await famMeta(pb, famId);
|
||||
const { tz, paydayTime } = await famMeta(pb, famId);
|
||||
const rewards = await pb.collection('rewards').getFullList({
|
||||
filter: `famId = '${famId}' && memberId = '${memberId}' && status = 'unclaimed'`
|
||||
});
|
||||
let count = 0;
|
||||
for (const r of rewards) {
|
||||
try {
|
||||
assertPaydayUnlocked(r, tz);
|
||||
assertPaydayUnlocked(r, tz, paydayTime);
|
||||
} catch {
|
||||
continue;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user