nodebb-plugin-calendar-onekite 11.1.39 → 11.1.40

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.
package/lib/admin.js CHANGED
@@ -93,29 +93,8 @@ admin.approveReservation = async function (req, res) {
93
93
  let paymentUrl = null;
94
94
  if (token) {
95
95
  const requester = await user.getUserFields(r.uid, ['username', 'email']);
96
- // Determine amount from HelloAsso items (pricing comes from HelloAsso)
97
- let totalAmount = 0;
98
- try {
99
- const items = await helloasso.listItems({
100
- env,
101
- token,
102
- organizationSlug: settings.helloassoOrganizationSlug,
103
- formType: settings.helloassoFormType,
104
- formSlug: settings.helloassoFormSlug,
105
- });
106
- const normalized = (items || []).map((it) => ({
107
- id: String(it.id || it.itemId || it.reference || it.name),
108
- price: it.price || it.amount || it.unitPrice || 0,
109
- })).filter(it => it.id);
110
- const match = normalized.find(it => it.id === String(r.itemId));
111
- totalAmount = match ? parseInt(match.price, 10) || 0 : 0;
112
- } catch (e) {
113
- totalAmount = 0;
114
- }
115
-
116
- if (!totalAmount) {
117
- return res.status(400).json({ error: 'item-price-not-found' });
118
- }
96
+ // r.total is stored as an estimated total in euros; HelloAsso expects cents.
97
+ const totalAmount = Math.max(0, Math.round((Number(r.total) || 0) * 100));
119
98
  paymentUrl = await helloasso.createCheckoutIntent({
120
99
  env,
121
100
  token,
@@ -124,6 +103,7 @@ admin.approveReservation = async function (req, res) {
124
103
  formSlug: settings.helloassoFormSlug,
125
104
  totalAmount,
126
105
  payerEmail: requester && requester.email,
106
+ callbackUrl: 'https://api.onekite.com/helloasso',
127
107
  });
128
108
  }
129
109
 
package/lib/api.js CHANGED
@@ -103,7 +103,7 @@ function eventsFor(resv) {
103
103
  start: startIsoDate,
104
104
  end: endIsoDate,
105
105
  extendedProps: {
106
- rid: resv.
106
+ rid: resv.rid,
107
107
  status,
108
108
  uid: resv.uid,
109
109
  itemIds: itemIds.filter(Boolean),
@@ -308,7 +308,8 @@ api.approveReservation = async function (req, res) {
308
308
  organizationSlug: settings2.helloassoOrganizationSlug,
309
309
  formType: settings2.helloassoFormType,
310
310
  formSlug: settings2.helloassoFormSlug,
311
- totalAmount: parseInt(r.total || 0, 10),
311
+ // r.total is stored as an estimated total in euros; HelloAsso expects cents.
312
+ totalAmount: Math.max(0, Math.round((Number(r.total) || 0) * 100)),
312
313
  payerEmail: payer && payer.email ? payer.email : '',
313
314
  callbackUrl: 'https://api.onekite.com/helloasso',
314
315
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodebb-plugin-calendar-onekite",
3
- "version": "11.1.39",
3
+ "version": "11.1.40",
4
4
  "description": "FullCalendar-based equipment reservation workflow with admin approval & HelloAsso payment for NodeBB",
5
5
  "main": "library.js",
6
6
  "license": "MIT",
package/public/admin.js CHANGED
@@ -66,15 +66,15 @@ define('admin/plugins/calendar-onekite', ['alerts', 'bootbox'], function (alerts
66
66
  for (const r of list) {
67
67
  const created = r.createdAt ? fmtFR(r.createdAt) : '';
68
68
  const itemNames = Array.isArray(r.itemNames) && r.itemNames.length ? r.itemNames : [r.itemName || r.itemId].filter(Boolean);
69
- const itemsHtml = itemNames.map(n => `<div>• ${esc(String(n))}</div>`).join('');
69
+ const itemsHtml = itemNames.map(n => `<div>• ${escapeHtml(String(n))}</div>`).join('');
70
70
  const div = document.createElement('div');
71
71
  div.className = 'list-group-item';
72
72
  div.innerHTML = `
73
73
  <div class="d-flex justify-content-between align-items-start gap-2">
74
74
  <div style="min-width: 0;">
75
- <div><strong>${itemsHtml || esc(r.itemName || '')}</strong></div>
76
- <div class="text-muted" style="font-size: 12px;">Créée: ${esc(created)}</div>
77
- <div class="text-muted" style="font-size: 12px;">Période: ${esc(new Date(parseInt(r.start, 10)).toLocaleDateString('fr-FR'))} → ${esc(new Date(parseInt(r.end, 10)).toLocaleDateString('fr-FR'))}</div>
75
+ <div><strong>${itemsHtml || escapeHtml(r.itemName || '')}</strong></div>
76
+ <div class="text-muted" style="font-size: 12px;">Créée: ${escapeHtml(created)}</div>
77
+ <div class="text-muted" style="font-size: 12px;">Période: ${escapeHtml(new Date(parseInt(r.start, 10)).toLocaleDateString('fr-FR'))} → ${escapeHtml(new Date(parseInt(r.end, 10)).toLocaleDateString('fr-FR'))}</div>
78
78
  </div>
79
79
  <div class="d-flex gap-2">
80
80
  <button class="btn btn-outline-danger btn-sm">Rejeter</button>
@@ -86,7 +86,8 @@ define('admin/plugins/calendar-onekite', ['alerts', 'bootbox'], function (alerts
86
86
  refuseBtn.addEventListener('click', async () => {
87
87
  if (!confirm('Rejeter cette demande ?')) return;
88
88
  try {
89
- await fetchJson(`/api/v3/admin/plugins/calendar-onekite/pending/${encodeURIComponent(r.rid)}/refuse`, { method: 'POST', body: JSON.stringify({}) });
89
+ // Server route: PUT /api/v3/admin/plugins/calendar-onekite/reservations/:rid/refuse
90
+ await fetchJson(`/api/v3/admin/plugins/calendar-onekite/reservations/${encodeURIComponent(r.rid)}/refuse`, { method: 'PUT' });
90
91
  showAlert('success', 'Demande rejetée.');
91
92
  await loadPending();
92
93
  } catch (e) {
@@ -128,7 +129,8 @@ define('admin/plugins/calendar-onekite', ['alerts', 'bootbox'], function (alerts
128
129
  try {
129
130
  const adminNote = (document.getElementById('onekite-admin-note')?.value || '').trim();
130
131
  const pickupTime = (document.getElementById('onekite-pickup-time')?.value || '').trim();
131
- await fetchJson(`/api/v3/admin/plugins/calendar-onekite/pending/${encodeURIComponent(r.rid)}/approve`, { method: 'POST', body: JSON.stringify({ adminNote, pickupTime }) });
132
+ // Server route: PUT /api/v3/admin/plugins/calendar-onekite/reservations/:rid/approve
133
+ await fetchJson(`/api/v3/admin/plugins/calendar-onekite/reservations/${encodeURIComponent(r.rid)}/approve`, { method: 'PUT', body: JSON.stringify({ adminNote, pickupTime }) });
132
134
  showAlert('success', 'Demande validée.');
133
135
  await loadPending();
134
136
  } catch (e) {
package/public/client.js CHANGED
@@ -245,7 +245,14 @@ define('forum/calendar-onekite', ['alerts', 'bootbox', 'hooks'], function (alert
245
245
  calendar.unselect();
246
246
  isDialogOpen = false;
247
247
  } catch (e) {
248
- showAlert('error', 'Impossible de créer la demande (droits/groupe ?).');
248
+ const code = String(e && e.message || '');
249
+ if (code === '403') {
250
+ showAlert('error', 'Impossible de créer la demande : droits insuffisants (groupe).');
251
+ } else if (code === '409') {
252
+ showAlert('error', 'Impossible : au moins un matériel est déjà réservé ou en attente sur cette période.');
253
+ } else {
254
+ showAlert('error', 'Erreur lors de la création de la demande.');
255
+ }
249
256
  calendar.unselect();
250
257
  isDialogOpen = false;
251
258
  }