home, subscription and other fixes
This commit is contained in:
@@ -13,6 +13,33 @@ const { sendNotification } = require("./notifications");
|
||||
|
||||
const DISTRIBUTION_REVENUE_BASELINE = 1000;
|
||||
const DISTRIBUTION_RATIO = 0.3;
|
||||
const ACTIVE_SUBSCRIPTION_STATUSES = new Set(["active"]);
|
||||
|
||||
const hasActiveSubscription = (userData) => {
|
||||
if (!userData || typeof userData !== "object") {
|
||||
return false;
|
||||
}
|
||||
const isPremium = userData.isPremium === true;
|
||||
if (!isPremium) {
|
||||
return false;
|
||||
}
|
||||
const status =
|
||||
typeof userData.stripeSubscriptionStatus === "string"
|
||||
? userData.stripeSubscriptionStatus.trim().toLowerCase()
|
||||
: null;
|
||||
if (status && ACTIVE_SUBSCRIPTION_STATUSES.has(status)) {
|
||||
return true;
|
||||
}
|
||||
const billingPeriod =
|
||||
typeof userData.premiumBillingPeriod === "string"
|
||||
? userData.premiumBillingPeriod.trim().toLowerCase()
|
||||
: null;
|
||||
if (billingPeriod === "monthly" || billingPeriod === "annual") {
|
||||
// Fallback: billing period is set only for active subscribers.
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
exports.distributeMonthlyPayouts = onSchedule(
|
||||
{
|
||||
@@ -51,6 +78,51 @@ exports.distributeMonthlyPayouts = onSchedule(
|
||||
.orderBy(["streams"], ["desc"])
|
||||
.value();
|
||||
|
||||
const userEligibilityMap = {};
|
||||
const userIds = _.uniq(
|
||||
entries.map((entry) => entry.userId).filter((userId) => !!userId),
|
||||
);
|
||||
|
||||
if (userIds.length) {
|
||||
const chunkSize = 300;
|
||||
for (let index = 0; index < userIds.length; index += chunkSize) {
|
||||
const chunk = userIds.slice(index, index + chunkSize);
|
||||
const snapshots = await Promise.all(
|
||||
chunk.map(async (userId) => {
|
||||
try {
|
||||
return await refList.users.doc(userId).get();
|
||||
} catch (error) {
|
||||
console.warn(
|
||||
"[distributeMonthlyPayouts] Unable to load user profile",
|
||||
{
|
||||
userId,
|
||||
error: error?.message || String(error),
|
||||
},
|
||||
);
|
||||
return null;
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
snapshots.forEach((snapshot, snapshotIndex) => {
|
||||
const userId = chunk[snapshotIndex];
|
||||
if (snapshot?.exists) {
|
||||
userEligibilityMap[userId] = hasActiveSubscription(
|
||||
snapshot.data(),
|
||||
);
|
||||
} else {
|
||||
userEligibilityMap[userId] = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const eligibleEntries = entries.filter(
|
||||
(entry) =>
|
||||
!!entry.userId && userEligibilityMap[entry.userId] === true,
|
||||
);
|
||||
const eligibleTotalStreams = _.sumBy(eligibleEntries, "streams");
|
||||
|
||||
const payoutsTotalStreamsFromDocs = _.sumBy(entries, "streams");
|
||||
const totalsData = totalsSnapshot.exists ? totalsSnapshot.data() : null;
|
||||
let totalStreams = _.toFinite(_.get(totalsData, "totalStreams", 0));
|
||||
@@ -63,9 +135,9 @@ exports.distributeMonthlyPayouts = onSchedule(
|
||||
2,
|
||||
);
|
||||
|
||||
let allocations = _.map(entries, (entry) => {
|
||||
if (!totalStreams) return 0;
|
||||
const rawAmount = (payoutPool * entry.streams) / totalStreams;
|
||||
let allocations = _.map(eligibleEntries, (entry) => {
|
||||
if (!eligibleTotalStreams) return 0;
|
||||
const rawAmount = (payoutPool * entry.streams) / eligibleTotalStreams;
|
||||
return _.round(rawAmount, 2);
|
||||
});
|
||||
|
||||
@@ -77,12 +149,14 @@ exports.distributeMonthlyPayouts = onSchedule(
|
||||
}
|
||||
}
|
||||
|
||||
const payouts = entries.map((entry, idx) => ({
|
||||
const payouts = eligibleEntries.map((entry, idx) => ({
|
||||
rank: idx + 1,
|
||||
projectId: entry.projectId,
|
||||
userId: entry.userId,
|
||||
streams: entry.streams,
|
||||
share: totalStreams ? _.round(entry.streams / totalStreams, 6) : 0,
|
||||
share: eligibleTotalStreams
|
||||
? _.round(entry.streams / eligibleTotalStreams, 6)
|
||||
: 0,
|
||||
amount: allocations[idx],
|
||||
statsDocPath: entry.statsDocPath,
|
||||
}));
|
||||
@@ -192,7 +266,10 @@ exports.distributeMonthlyPayouts = onSchedule(
|
||||
payoutRatio: DISTRIBUTION_RATIO,
|
||||
payoutPool,
|
||||
totalStreams,
|
||||
eligibleTotalStreams,
|
||||
totalRecipients: payouts.length,
|
||||
totalEntries: entries.length,
|
||||
eligibleEntries: eligibleEntries.length,
|
||||
totalAllocated: _.round(_.sumBy(payouts, "amount"), 2),
|
||||
payouts,
|
||||
status: payouts.length ? "computed" : "no-data",
|
||||
|
||||
Reference in New Issue
Block a user