nodebb-plugin-calendar-onekite 11.1.86 → 11.1.87

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/lib/scheduler.js +83 -22
  2. package/package.json +1 -1
package/lib/scheduler.js CHANGED
@@ -56,31 +56,92 @@ async function processAwaitingPayment() {
56
56
  const user = require.main.require('./src/user');
57
57
 
58
58
  async function sendEmail(template, toEmail, subject, data) {
59
- if (!toEmail) return;
60
- try {
61
- // NodeBB core signature (historically):
62
- // Emailer.sendToEmail(template, email, language, params[, callback])
63
- // Subject is not a positional arg; it must be injected (either by NodeBB itself
64
- // or via filter:email.modify). We always pass it in params.subject.
65
- const language = (meta && meta.config && (meta.config.defaultLang || meta.config.defaultLanguage)) || 'fr';
66
- const params = Object.assign({}, data || {}, subject ? { subject } : {});
67
- if (typeof emailer.sendToEmail === 'function') {
68
- await emailer.sendToEmail(template, toEmail, language, params);
69
- return;
70
- }
71
- // Fallback for older/unusual builds (rare)
72
- if (typeof emailer.send === 'function') {
73
- // Some builds accept (template, email, language, params)
74
- if (emailer.send.length >= 4) {
75
- await emailer.send(template, toEmail, language, params);
59
+ if (!toEmail) return;
60
+ try {
61
+ // NodeBB core signature:
62
+ // Emailer.sendToEmail(template, email, language, params[, callback])
63
+ // Subject is NOT a positional argument; it must be provided in params.subject
64
+ // and optionally copied into the final email by filter:email.modify.
65
+ const language = (meta && meta.config && (meta.config.defaultLang || meta.config.defaultLanguage)) || 'fr';
66
+ const params = Object.assign({}, data || {}, subject ? { subject } : {});
67
+
68
+ if (typeof emailer.sendToEmail === 'function') {
69
+ await emailer.sendToEmail(template, toEmail, language, params);
76
70
  return;
77
71
  }
78
- // Some builds accept (template, email, params)
79
- await emailer.send(template, toEmail, params);
72
+
73
+ // Fallbacks for older/unusual builds
74
+ if (typeof emailer.send === 'function') {
75
+ // Some builds accept (template, email, language, params)
76
+ if (emailer.send.length >= 4) {
77
+ await emailer.send(template, toEmail, language, params);
78
+ return;
79
+ }
80
+ // Some builds accept (template, email, params)
81
+ await emailer.send(template, toEmail, params);
82
+ }
83
+ } catch (err) {
84
+ // eslint-disable-next-line no-console
85
+ console.warn('[calendar-onekite] Failed to send email (scheduler)', {
86
+ template,
87
+ toEmail,
88
+ err: String((err && err.message) || err),
89
+ });
90
+ }
91
+ }
92
+
93
+ function formatFR(ts) {
94
+ const d = new Date(ts);
95
+ const dd = String(d.getDate()).padStart(2, '0');
96
+ const mm = String(d.getMonth() + 1).padStart(2, '0');
97
+ const yyyy = d.getFullYear();
98
+ return `${dd}/${mm}/${yyyy}`;
99
+ }
100
+
101
+ for (const rid of ids) {
102
+ const r = await dbLayer.getReservation(rid);
103
+ if (!r || r.status !== 'awaiting_payment') continue;
104
+
105
+ const approvedAt = parseInt(r.approvedAt || r.validatedAt || 0, 10) || 0;
106
+ if (!approvedAt) continue;
107
+
108
+ const reminderAt = approvedAt + holdMins * 60 * 1000;
109
+ const expireAt = approvedAt + 2 * holdMins * 60 * 1000;
110
+
111
+ if (!r.reminderSent && now >= reminderAt && now < expireAt) {
112
+ // Send reminder once
113
+ const u = await user.getUserFields(r.uid, ['username', 'email']);
114
+ if (u && u.email) {
115
+ await sendEmail('calendar-onekite_reminder', u.email, 'Location matériel - Rappel', {
116
+ username: u.username,
117
+ itemName: (Array.isArray(r.itemNames) ? r.itemNames.join(', ') : (r.itemName || '')),
118
+ itemNames: (Array.isArray(r.itemNames) ? r.itemNames : (r.itemName ? [r.itemName] : [])),
119
+ dateRange: `Du ${formatFR(r.start)} au ${formatFR(r.end)}`,
120
+ paymentUrl: r.paymentUrl || '',
121
+ delayMinutes: holdMins,
122
+ pickupLine: r.pickupTime ? (r.adminNote ? `${r.pickupTime} à ${r.adminNote}` : r.pickupTime) : '',
123
+ });
124
+ }
125
+ r.reminderSent = true;
126
+ r.reminderAt = now;
127
+ await dbLayer.saveReservation(r);
128
+ continue;
129
+ }
130
+
131
+ if (now >= expireAt) {
132
+ // Expire: remove reservation so it disappears from calendar and frees items
133
+ const u = await user.getUserFields(r.uid, ['username', 'email']);
134
+ if (u && u.email) {
135
+ await sendEmail('calendar-onekite_expired', u.email, 'Location matériel - Rappel', {
136
+ username: u.username,
137
+ itemName: (Array.isArray(r.itemNames) ? r.itemNames.join(', ') : (r.itemName || '')),
138
+ itemNames: (Array.isArray(r.itemNames) ? r.itemNames : (r.itemName ? [r.itemName] : [])),
139
+ dateRange: `Du ${formatFR(r.start)} au ${formatFR(r.end)}`,
140
+ delayMinutes: holdMins,
141
+ });
142
+ }
143
+ await dbLayer.removeReservation(rid);
80
144
  }
81
- } catch (err) {
82
- // eslint-disable-next-line no-console
83
- console.warn('[calendar-onekite] Failed to send email', { template, toEmail, err: String(err) });
84
145
  }
85
146
  }
86
147
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodebb-plugin-calendar-onekite",
3
- "version": "11.1.86",
3
+ "version": "11.1.87",
4
4
  "description": "FullCalendar-based equipment reservation workflow with admin approval & HelloAsso payment for NodeBB",
5
5
  "main": "library.js",
6
6
  "license": "MIT",