Updated
This commit is contained in:
parent
5ebd5d770b
commit
14e52eaa89
@ -5,7 +5,40 @@ import * as admin from "firebase-admin";
|
|||||||
const app = getAdmin();
|
const app = getAdmin();
|
||||||
const logger = getLogger();
|
const logger = getLogger();
|
||||||
const kTrainerRole = "Trainer";
|
const kTrainerRole = "Trainer";
|
||||||
const CACHE_FOLDER = "gym_member_cache";
|
|
||||||
|
async function updateCacheForMembership(
|
||||||
|
gymId: string,
|
||||||
|
membershipId: string
|
||||||
|
): Promise<void> {
|
||||||
|
try {
|
||||||
|
const response = await fetch(
|
||||||
|
`https://updatemembercache-2k7djjvd3q-el.a.run.app/updateMemberCache`,
|
||||||
|
{
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
gymId: gymId,
|
||||||
|
incrementalUpdate: true,
|
||||||
|
membershipIds: [membershipId],
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response.ok) {
|
||||||
|
logger.info(
|
||||||
|
`Cache updated successfully for membership ${membershipId} in gym ${gymId}`
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
logger.warn(
|
||||||
|
`Cache update failed for membership ${membershipId}: ${response.status}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
logger.error(`Error updating cache for membership ${membershipId}:`, error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
interface MembershipData {
|
interface MembershipData {
|
||||||
id?: string;
|
id?: string;
|
||||||
@ -45,183 +78,6 @@ interface PersonalTrainerAssign {
|
|||||||
gymId: string;
|
gymId: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface MinimalCacheEntry {
|
|
||||||
membershipId: string;
|
|
||||||
userId: string;
|
|
||||||
status: string;
|
|
||||||
displayName: string;
|
|
||||||
email?: string | null;
|
|
||||||
phoneNumber?: string | null;
|
|
||||||
alternateContact?: string | null;
|
|
||||||
renewalDate?: string | null;
|
|
||||||
expirationDate?: string | null;
|
|
||||||
createdAt?: string | null;
|
|
||||||
daysUntilExpiry?: number | null;
|
|
||||||
hasPersonalTraining: boolean;
|
|
||||||
hasPartialPayment: boolean;
|
|
||||||
remainingAmount: number;
|
|
||||||
subscriptionId?: string | null;
|
|
||||||
lastUpdated: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface MinimalJsonCacheData {
|
|
||||||
gymId: string;
|
|
||||||
members: MinimalCacheEntry[];
|
|
||||||
totalMembers: number;
|
|
||||||
lastUpdated: string;
|
|
||||||
cacheVersion: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function updateCacheForMembership(gymId: string, membershipId: string): Promise<void> {
|
|
||||||
try {
|
|
||||||
const fileName = `${CACHE_FOLDER}/${gymId}.json`;
|
|
||||||
const file = app.storage().bucket().file(fileName);
|
|
||||||
|
|
||||||
let existingData: MinimalJsonCacheData | null = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const [fileBuffer] = await file.download();
|
|
||||||
existingData = JSON.parse(fileBuffer.toString());
|
|
||||||
} catch (error) {
|
|
||||||
logger.warn(`Could not load existing cache for gym ${gymId}, skipping cache update: ${error}`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!existingData || !existingData.members) {
|
|
||||||
logger.warn(`Invalid cache data for gym ${gymId}, skipping cache update`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const membershipDoc = await app
|
|
||||||
.firestore()
|
|
||||||
.collection("memberships")
|
|
||||||
.doc(membershipId)
|
|
||||||
.get();
|
|
||||||
|
|
||||||
if (!membershipDoc.exists) {
|
|
||||||
logger.warn(`Membership ${membershipId} not found, skipping cache update`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const membershipData = membershipDoc.data();
|
|
||||||
const updatedEntry = await generateMinimalCacheEntry(
|
|
||||||
membershipData!.userId,
|
|
||||||
membershipId,
|
|
||||||
membershipData!,
|
|
||||||
gymId
|
|
||||||
);
|
|
||||||
|
|
||||||
const memberIndex = existingData.members.findIndex(
|
|
||||||
member => member.membershipId === membershipId
|
|
||||||
);
|
|
||||||
|
|
||||||
if (memberIndex >= 0) {
|
|
||||||
existingData.members[memberIndex] = updatedEntry;
|
|
||||||
} else {
|
|
||||||
existingData.members.push(updatedEntry);
|
|
||||||
}
|
|
||||||
|
|
||||||
existingData.lastUpdated = new Date().toISOString();
|
|
||||||
existingData.totalMembers = existingData.members.length;
|
|
||||||
|
|
||||||
await file.save(JSON.stringify(existingData, null, 2), {
|
|
||||||
metadata: {
|
|
||||||
contentType: "application/json",
|
|
||||||
metadata: {
|
|
||||||
gymId: gymId,
|
|
||||||
totalMembers: existingData.totalMembers.toString(),
|
|
||||||
generatedAt: existingData.lastUpdated,
|
|
||||||
cacheVersion: existingData.cacheVersion,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
logger.info(`Cache updated for membership ${membershipId} in gym ${gymId}`);
|
|
||||||
} catch (error) {
|
|
||||||
logger.error(`Error updating cache for membership ${membershipId}:`, error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function generateMinimalCacheEntry(
|
|
||||||
userId: string,
|
|
||||||
membershipId: string,
|
|
||||||
membershipData: any,
|
|
||||||
gymId: string
|
|
||||||
): Promise<MinimalCacheEntry> {
|
|
||||||
try {
|
|
||||||
let firstName = "";
|
|
||||||
let lastName = "";
|
|
||||||
let email = "";
|
|
||||||
let phoneNumber = "";
|
|
||||||
let alternateContact = "";
|
|
||||||
|
|
||||||
try {
|
|
||||||
const clientFieldsSnapshot = await app
|
|
||||||
.firestore()
|
|
||||||
.collection("client_profiles")
|
|
||||||
.where("uid", "==", userId)
|
|
||||||
.get();
|
|
||||||
|
|
||||||
if (!clientFieldsSnapshot.empty) {
|
|
||||||
const fieldDoc = clientFieldsSnapshot.docs[0];
|
|
||||||
const fieldData = fieldDoc.data();
|
|
||||||
|
|
||||||
const fields = fieldData.fields || {};
|
|
||||||
firstName = fields["first-name"] || fieldData["first-name"] || "";
|
|
||||||
lastName = fields["last-name"] || fieldData["last-name"] || "";
|
|
||||||
email = fields["email"] || fieldData["email"] || "";
|
|
||||||
phoneNumber = fields["phone-number"] || fieldData["phone-number"] || "";
|
|
||||||
alternateContact =
|
|
||||||
fields["alternate-contact"] || fieldData["alternate-contact"] || "";
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
logger.error(`Error getting fields for user ${userId}:`, error);
|
|
||||||
}
|
|
||||||
|
|
||||||
const daysUntilExpiry = membershipData.daysUntilExpiry || null;
|
|
||||||
|
|
||||||
const displayName =
|
|
||||||
firstName.length === 0
|
|
||||||
? "Unknown"
|
|
||||||
: lastName.length === 0
|
|
||||||
? firstName
|
|
||||||
: `${firstName} ${lastName}`;
|
|
||||||
|
|
||||||
const isPartial = membershipData.isPartialPayment === true;
|
|
||||||
const remaining = membershipData.remainingAmount || 0;
|
|
||||||
const hasPartialPayment = isPartial && remaining > 0;
|
|
||||||
|
|
||||||
const minimalEntry: MinimalCacheEntry = {
|
|
||||||
membershipId,
|
|
||||||
userId,
|
|
||||||
status: membershipData.status || "N/A",
|
|
||||||
displayName,
|
|
||||||
email: email || null,
|
|
||||||
phoneNumber: phoneNumber || null,
|
|
||||||
alternateContact: alternateContact || null,
|
|
||||||
renewalDate: null,
|
|
||||||
expirationDate: membershipData.expirationDate
|
|
||||||
? membershipData.expirationDate.toDate().toISOString()
|
|
||||||
: null,
|
|
||||||
createdAt: membershipData.createdAt
|
|
||||||
? membershipData.createdAt.toDate().toISOString()
|
|
||||||
: null,
|
|
||||||
daysUntilExpiry,
|
|
||||||
hasPersonalTraining:
|
|
||||||
membershipData.subscription?.hasPersonalTraining === true,
|
|
||||||
hasPartialPayment,
|
|
||||||
remainingAmount: remaining,
|
|
||||||
subscriptionId: membershipData.subscriptionId || null,
|
|
||||||
lastUpdated: new Date().toISOString(),
|
|
||||||
};
|
|
||||||
|
|
||||||
return minimalEntry;
|
|
||||||
} catch (error) {
|
|
||||||
logger.error("Error generating minimal cache entry:", error);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const checkExpiredMemberships = onSchedule(
|
export const checkExpiredMemberships = onSchedule(
|
||||||
{
|
{
|
||||||
schedule: "0 8,14,20 * * *",
|
schedule: "0 8,14,20 * * *",
|
||||||
@ -718,7 +574,6 @@ async function updateDaysUntilExpiryForAllMemberships(): Promise<void> {
|
|||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function calculateDaysUntilExpiry(
|
async function calculateDaysUntilExpiry(
|
||||||
membershipId: string,
|
membershipId: string,
|
||||||
data: MembershipData
|
data: MembershipData
|
||||||
@ -1254,4 +1109,4 @@ async function getGymName(gymId: string): Promise<string> {
|
|||||||
logger.error(`Error getting gym name for gym ${gymId}:`, error);
|
logger.error(`Error getting gym name for gym ${gymId}:`, error);
|
||||||
return "Unknown Gym";
|
return "Unknown Gym";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user