mirror of
https://github.com/rgrgogu/new_starr.git
synced 2026-09-27 00:12:54 +08:00
revise ads and alerts
This commit is contained in:
@@ -18,6 +18,7 @@
|
||||
* - expireUserTiers (cron/jobs/expire_user_tiers.cron.js)
|
||||
* - taskDueSoon (cron/jobs/task_due_soon.cron.js)
|
||||
* - expireAdvertisements (cron/jobs/expire_advertisements.cron.js) — plain
|
||||
* - failStalePayments (cron/jobs/fail_stale_payments.cron.js) — plain
|
||||
*
|
||||
* Author: Kenneth Obsequio (@lash0000)
|
||||
* Date Created: Jun. 17, 2026
|
||||
@@ -28,6 +29,7 @@ const issueCertificates = require('./jobs/issue_certificates.cron');
|
||||
const expireUserTiers = require('./jobs/expire_user_tiers.cron');
|
||||
const taskDueSoon = require('./jobs/task_due_soon.cron');
|
||||
const expireAdvertisements = require('./jobs/expire_advertisements.cron');
|
||||
const failStalePayments = require('./jobs/fail_stale_payments.cron');
|
||||
const { startSettingsBackedJobs } = require('./cronRegistry.util');
|
||||
|
||||
// ─── Registry — add future client-side cron jobs here ────────────────────────
|
||||
@@ -41,6 +43,7 @@ const settingsBackedJobs = [
|
||||
// Plain hardcoded-schedule jobs (not tied to any notification setting).
|
||||
const plainJobs = [
|
||||
expireAdvertisements,
|
||||
failStalePayments,
|
||||
];
|
||||
|
||||
// ─── Boot all registered client-side jobs ─────────────────────────────────────
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
/***********************************************************************************************************************************************************************
|
||||
* File Name : fail_stale_payments.cron.js
|
||||
* Type : Cron Job
|
||||
* Description : Marks abandoned checkout attempts as 'failed' instead of
|
||||
* leaving them stuck on 'pending' forever.
|
||||
*
|
||||
* A payment/purchase row is created as 'pending' the moment
|
||||
* PayPal's create-order call succeeds (createOrder / createCourseOrder),
|
||||
* before the buyer ever reaches PayPal's approval page. If PayPal's
|
||||
* own hosted checkout then fails to load ("Things don't appear to
|
||||
* be working at the moment") or the buyer just abandons the tab,
|
||||
* the browser never gets redirected back to our return_url/cancel_url —
|
||||
* so captureOrder/cancelOrder is never called, and the row sits as
|
||||
* 'pending' indefinitely even though no money ever moved.
|
||||
*
|
||||
* This job sweeps 'pending' rows older than STALE_MINUTES and
|
||||
* marks them 'failed', so payment history correctly reflects
|
||||
* that nothing was charged, instead of silently doing nothing.
|
||||
*
|
||||
* Schedule : Every 10 minutes ("*\/10 * * * *"). Registered by cron/client.cron.js.
|
||||
*
|
||||
* Author: Kenneth Obsequio (@lash0000)
|
||||
* Date Created: Aug. 3, 2026
|
||||
***********************************************************************************************************************************************************************/
|
||||
'use strict';
|
||||
|
||||
const { Op } = require('sequelize');
|
||||
const mdl_Payments = require('../../models/tiers/payments.mdl');
|
||||
const mdl_CoursePurchase = require('../../models/courses/course_purchases.mdl');
|
||||
|
||||
const STALE_MINUTES = 30;
|
||||
|
||||
async function run() {
|
||||
const cutoff = new Date(Date.now() - STALE_MINUTES * 60_000);
|
||||
|
||||
try {
|
||||
const stalePayments = await mdl_Payments.findAll({
|
||||
where: { status: 'pending', createdAt: { [Op.lt]: cutoff } },
|
||||
});
|
||||
|
||||
for (const payment of stalePayments) {
|
||||
await payment.update({
|
||||
status: 'failed',
|
||||
provider_payload: {
|
||||
...payment.provider_payload,
|
||||
failed_reason: 'abandoned_checkout',
|
||||
marked_failed_at: new Date().toISOString(),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if (stalePayments.length) {
|
||||
console.log(`[CRON][FAIL STALE PAYMENTS] Marked ${stalePayments.length} abandoned tier payment(s) as failed.`);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('[CRON][FAIL STALE PAYMENTS] Failed sweeping payments:', err);
|
||||
}
|
||||
|
||||
try {
|
||||
const stalePurchases = await mdl_CoursePurchase.findAll({
|
||||
where: { status: 'pending', createdAt: { [Op.lt]: cutoff } },
|
||||
});
|
||||
|
||||
for (const purchase of stalePurchases) {
|
||||
await purchase.update({
|
||||
status: 'failed',
|
||||
provider_payload: {
|
||||
...purchase.provider_payload,
|
||||
failed_reason: 'abandoned_checkout',
|
||||
marked_failed_at: new Date().toISOString(),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if (stalePurchases.length) {
|
||||
console.log(`[CRON][FAIL STALE PAYMENTS] Marked ${stalePurchases.length} abandoned course purchase(s) as failed.`);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('[CRON][FAIL STALE PAYMENTS] Failed sweeping course purchases:', err);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
name: 'failStalePayments',
|
||||
schedule: '*/10 * * * *',
|
||||
run,
|
||||
};
|
||||
Reference in New Issue
Block a user