nodebb-plugin-calendar-onekite 11.1.21 → 11.1.22
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 +32 -5
- package/lib/api.js +7 -6
- package/lib/helloasso.js +79 -5
- package/package.json +1 -1
package/lib/admin.js
CHANGED
|
@@ -176,7 +176,10 @@ admin.debugHelloAsso = async function (req, res) {
|
|
|
176
176
|
ok: true,
|
|
177
177
|
settings: safeSettings,
|
|
178
178
|
token: { ok: false },
|
|
179
|
-
|
|
179
|
+
// Catalog = what you actually want for a shop (available products/material)
|
|
180
|
+
catalog: { ok: false, count: 0, sample: [], keys: [] },
|
|
181
|
+
// Sold items = items present in orders (can be 0 if no sales yet)
|
|
182
|
+
soldItems: { ok: false, count: 0, sample: [] },
|
|
180
183
|
};
|
|
181
184
|
|
|
182
185
|
try {
|
|
@@ -191,6 +194,30 @@ admin.debugHelloAsso = async function (req, res) {
|
|
|
191
194
|
}
|
|
192
195
|
out.token = { ok: true };
|
|
193
196
|
|
|
197
|
+
// Catalog items (via /public)
|
|
198
|
+
try {
|
|
199
|
+
const { publicForm, items } = await helloasso.listCatalogItems({
|
|
200
|
+
env,
|
|
201
|
+
token,
|
|
202
|
+
organizationSlug: settings.helloassoOrganizationSlug,
|
|
203
|
+
formType: settings.helloassoFormType,
|
|
204
|
+
formSlug: settings.helloassoFormSlug,
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
const arr = Array.isArray(items) ? items : [];
|
|
208
|
+
out.catalog.ok = true;
|
|
209
|
+
out.catalog.count = arr.length;
|
|
210
|
+
out.catalog.keys = publicForm && typeof publicForm === 'object' ? Object.keys(publicForm) : [];
|
|
211
|
+
out.catalog.sample = arr.slice(0, 10).map((it) => ({
|
|
212
|
+
id: it.id,
|
|
213
|
+
name: it.name,
|
|
214
|
+
price: it.price ?? null,
|
|
215
|
+
}));
|
|
216
|
+
} catch (e) {
|
|
217
|
+
out.catalog = { ok: false, error: String(e && e.message ? e.message : e), count: 0, sample: [], keys: [] };
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// Sold items
|
|
194
221
|
try {
|
|
195
222
|
const items = await helloasso.listItems({
|
|
196
223
|
env,
|
|
@@ -200,15 +227,15 @@ admin.debugHelloAsso = async function (req, res) {
|
|
|
200
227
|
formSlug: settings.helloassoFormSlug,
|
|
201
228
|
});
|
|
202
229
|
const arr = Array.isArray(items) ? items : [];
|
|
203
|
-
out.
|
|
204
|
-
out.
|
|
205
|
-
out.
|
|
230
|
+
out.soldItems.ok = true;
|
|
231
|
+
out.soldItems.count = arr.length;
|
|
232
|
+
out.soldItems.sample = arr.slice(0, 10).map((it) => ({
|
|
206
233
|
id: it.id || it.itemId || it.reference || it.name,
|
|
207
234
|
name: it.name || it.label || it.itemName,
|
|
208
235
|
price: it.price || it.amount || it.unitPrice || null,
|
|
209
236
|
}));
|
|
210
237
|
} catch (e) {
|
|
211
|
-
out.
|
|
238
|
+
out.soldItems = { ok: false, error: String(e && e.message ? e.message : e), count: 0, sample: [] };
|
|
212
239
|
}
|
|
213
240
|
|
|
214
241
|
return res.json(out);
|
package/lib/api.js
CHANGED
|
@@ -72,7 +72,9 @@ api.getItems = async function (req, res) {
|
|
|
72
72
|
return res.json([]);
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
-
|
|
75
|
+
// Important: the /items endpoint on HelloAsso lists *sold items*.
|
|
76
|
+
// For a shop catalog, use the /public form endpoint and extract the catalog.
|
|
77
|
+
const { items: catalog } = await helloasso.listCatalogItems({
|
|
76
78
|
env,
|
|
77
79
|
token,
|
|
78
80
|
organizationSlug: settings.helloassoOrganizationSlug,
|
|
@@ -80,11 +82,10 @@ api.getItems = async function (req, res) {
|
|
|
80
82
|
formSlug: settings.helloassoFormSlug,
|
|
81
83
|
});
|
|
82
84
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
price: it.price || it.amount || it.unitPrice || 0,
|
|
85
|
+
const normalized = (catalog || []).map((it) => ({
|
|
86
|
+
id: it.id,
|
|
87
|
+
name: it.name,
|
|
88
|
+
price: typeof it.price === 'number' ? it.price : 0,
|
|
88
89
|
})).filter(it => it.id && it.name);
|
|
89
90
|
|
|
90
91
|
res.json(normalized);
|
package/lib/helloasso.js
CHANGED
|
@@ -95,18 +95,89 @@ async function getAccessToken({ env, clientId, clientSecret }) {
|
|
|
95
95
|
|
|
96
96
|
async function listItems({ env, token, organizationSlug, formType, formSlug }) {
|
|
97
97
|
if (!token || !organizationSlug || !formType || !formSlug) return [];
|
|
98
|
-
|
|
98
|
+
// This endpoint returns *sold items* (i.e., items present in orders). If your shop has
|
|
99
|
+
// no sales yet, it will legitimately return an empty list.
|
|
100
|
+
const url = `${baseUrl(env)}/v5/organizations/${encodeURIComponent(organizationSlug)}/forms/${encodeURIComponent(formType)}/${encodeURIComponent(formSlug)}/items?pageIndex=1&pageSize=200`;
|
|
99
101
|
const { status, json } = await requestJson('GET', url, { Authorization: `Bearer ${token}` });
|
|
100
102
|
if (status >= 200 && status < 300 && json) {
|
|
101
|
-
|
|
102
|
-
return json.data || json.items || json || [];
|
|
103
|
+
return json.data || json.items || [];
|
|
103
104
|
}
|
|
104
105
|
return [];
|
|
105
106
|
}
|
|
106
107
|
|
|
107
|
-
async function
|
|
108
|
+
async function getFormPublic({ env, token, organizationSlug, formType, formSlug }) {
|
|
108
109
|
if (!token || !organizationSlug || !formType || !formSlug) return null;
|
|
109
|
-
|
|
110
|
+
// Public form details contains extraOptions/customFields and (for Shop) usually the catalog structure.
|
|
111
|
+
const url = `${baseUrl(env)}/v5/organizations/${encodeURIComponent(organizationSlug)}/forms/${encodeURIComponent(formType)}/${encodeURIComponent(formSlug)}/public`;
|
|
112
|
+
const { status, json } = await requestJson('GET', url, { Authorization: `Bearer ${token}` });
|
|
113
|
+
if (status >= 200 && status < 300) {
|
|
114
|
+
return json || null;
|
|
115
|
+
}
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function extractCatalogItems(publicFormJson) {
|
|
120
|
+
if (!publicFormJson || typeof publicFormJson !== 'object') return [];
|
|
121
|
+
|
|
122
|
+
// Try a few common shapes used in HelloAsso "public" form responses.
|
|
123
|
+
const candidates = [];
|
|
124
|
+
const pushArr = (arr) => {
|
|
125
|
+
if (Array.isArray(arr)) candidates.push(...arr);
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
pushArr(publicFormJson.items);
|
|
129
|
+
pushArr(publicFormJson.tiers);
|
|
130
|
+
pushArr(publicFormJson.products);
|
|
131
|
+
pushArr(publicFormJson.data);
|
|
132
|
+
if (publicFormJson.form) {
|
|
133
|
+
pushArr(publicFormJson.form.items);
|
|
134
|
+
pushArr(publicFormJson.form.tiers);
|
|
135
|
+
pushArr(publicFormJson.form.products);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Some responses nest in "campaign" or "publicForm".
|
|
139
|
+
if (publicFormJson.publicForm) {
|
|
140
|
+
pushArr(publicFormJson.publicForm.items);
|
|
141
|
+
pushArr(publicFormJson.publicForm.tiers);
|
|
142
|
+
pushArr(publicFormJson.publicForm.products);
|
|
143
|
+
}
|
|
144
|
+
if (publicFormJson.campaign) {
|
|
145
|
+
pushArr(publicFormJson.campaign.items);
|
|
146
|
+
pushArr(publicFormJson.campaign.tiers);
|
|
147
|
+
pushArr(publicFormJson.campaign.products);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Normalize to { id, name, price }
|
|
151
|
+
return candidates
|
|
152
|
+
.map((it) => {
|
|
153
|
+
if (!it || typeof it !== 'object') return null;
|
|
154
|
+
const id = it.id ?? it.itemId ?? it.tierId;
|
|
155
|
+
const name = it.name ?? it.label ?? it.title;
|
|
156
|
+
const price =
|
|
157
|
+
(it.amount && (it.amount.total ?? it.amount.value)) ??
|
|
158
|
+
it.price ??
|
|
159
|
+
it.unitPrice ??
|
|
160
|
+
it.totalAmount ??
|
|
161
|
+
it.initialAmount;
|
|
162
|
+
if (!id || !name) return null;
|
|
163
|
+
return { id, name, price: typeof price === 'number' ? price : 0, raw: it };
|
|
164
|
+
})
|
|
165
|
+
.filter(Boolean);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
async function listCatalogItems({ env, token, organizationSlug, formType, formSlug }) {
|
|
169
|
+
const publicForm = await getFormPublic({ env, token, organizationSlug, formType, formSlug });
|
|
170
|
+
const extracted = extractCatalogItems(publicForm);
|
|
171
|
+
return {
|
|
172
|
+
publicForm,
|
|
173
|
+
items: extracted.map(({ id, name, price, raw }) => ({ id, name, price, raw })),
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
async function createCheckoutIntent({ env, token, organizationSlug, formType, formSlug, totalAmount, payerEmail }) {
|
|
178
|
+
if (!token || !organizationSlug) return null;
|
|
179
|
+
// Checkout intents are created at organization level.
|
|
180
|
+
const url = `${baseUrl(env)}/v5/organizations/${encodeURIComponent(organizationSlug)}/checkout-intents`;
|
|
110
181
|
const payload = {
|
|
111
182
|
totalAmount: totalAmount,
|
|
112
183
|
initialAmount: totalAmount,
|
|
@@ -125,5 +196,8 @@ async function createCheckoutIntent({ env, token, organizationSlug, formType, fo
|
|
|
125
196
|
module.exports = {
|
|
126
197
|
getAccessToken,
|
|
127
198
|
listItems,
|
|
199
|
+
getFormPublic,
|
|
200
|
+
extractCatalogItems,
|
|
201
|
+
listCatalogItems,
|
|
128
202
|
createCheckoutIntent,
|
|
129
203
|
};
|
package/package.json
CHANGED