diff --git a/apps/ops/src/pages/EventsPage.vue b/apps/ops/src/pages/EventsPage.vue
index fdb1a26..82d1366 100644
--- a/apps/ops/src/pages/EventsPage.vue
+++ b/apps/ops/src/pages/EventsPage.vue
@@ -138,9 +138,15 @@
:options="[{ label: 'Liste clients', value: 'list' }, { label: 'Import CSV', value: 'csv' }]" />
-
+
+
+
+
-
Astuce : « Clients actifs » = ~7900 clients avec courriel. « Abonnement actif » restreint à ceux ayant un service en cours.
+
+
+
+
« Total mensuel » = somme des abonnements actifs du client (0 = aucun filtre). « Résidentiel/Commercial » = type de compte.
@@ -209,7 +215,7 @@ const sendMode = ref('test')
const template = ref('')
const templates = ref([{ value: '', label: 'Invitation Fête 20 ans (TARGO)' }])
const audienceSource = ref('list')
-const audFilters = ref({ statut: 'active', active_sub: false })
+const audFilters = ref({ statut: 'active', customer_type: '', active_sub: false, min_monthly: 0 })
const csvFile = ref(null)
const audCsvText = ref('')
const audPreview = ref(null)
diff --git a/services/targo-hub/lib/events.js b/services/targo-hub/lib/events.js
index fc322d4..491c0ca 100644
--- a/services/targo-hub/lib/events.js
+++ b/services/targo-hub/lib/events.js
@@ -273,24 +273,26 @@ async function resolveAudience ({ mode = 'filter', filters = {}, csv = '' } = {}
const f = []
if (filters.statut === 'active') f.push(['disabled', '=', 0])
else if (filters.statut === 'disabled') f.push(['disabled', '=', 1])
- if (filters.territory) f.push(['territory', '=', filters.territory])
- if (filters.group) f.push(['customer_group', '=', filters.group])
- const CFIELDS = ['name', 'customer_name', 'email_id', 'language', 'territory', 'customer_group']
+ if (filters.customer_type) f.push(['customer_type', '=', filters.customer_type]) // Individual = résidentiel · Company = commercial
+ const CFIELDS = ['name', 'customer_name', 'email_id', 'language', 'customer_type']
+ const minMonthly = Number(filters.min_monthly) || 0
let customers = []
- if (filters.active_sub) {
- // Clients ayant ≥1 Service Subscription « Actif ».
- const subs = []; let s = 0
- for (let p = 0; p < 30; p++) { const b = await erp.list('Service Subscription', { filters: [['status', '=', 'Actif']], fields: ['customer'], limit: 500, start: s }); subs.push(...b); if (b.length < 500) break; s += 500 }
- const ids = [...new Set(subs.map(x => x.customer).filter(Boolean))]
+ if (filters.active_sub || minMonthly > 0) {
+ // Agrège les abonnements ACTIFS par client (somme mensuelle) ; filtre par minimum si demandé.
+ const byCust = {}; let s = 0
+ for (let p = 0; p < 40; p++) { const b = await erp.list('Service Subscription', { filters: [['status', '=', 'Actif']], fields: ['customer', 'monthly_price'], limit: 500, start: s }); b.forEach(x => { if (x.customer) byCust[x.customer] = (byCust[x.customer] || 0) + (Number(x.monthly_price) || 0) }); if (b.length < 500) break; s += 500 }
+ let ids = Object.keys(byCust)
+ if (minMonthly > 0) ids = ids.filter(c => byCust[c] >= minMonthly)
for (let i = 0; i < ids.length; i += 100) {
const b = await erp.list('Customer', { filters: [...f, ['name', 'in', ids.slice(i, i + 100)]], fields: CFIELDS, limit: 500 })
customers.push(...b)
}
+ customers.forEach(c => { c._monthly = byCust[c.name] || 0 })
} else {
let s = 0
for (let p = 0; p < 60; p++) { const b = await erp.list('Customer', { filters: f, fields: CFIELDS, limit: 500, start: s }); customers.push(...b); if (b.length < 500) break; s += 500 }
}
- rows = customers.map(c => { const n = splitName(c.customer_name); return { email: firstEmail(c.email_id), firstname: n.firstname, lastname: n.lastname, language: normLang(c.language), customer_id: c.name } })
+ rows = customers.map(c => { const n = splitName(c.customer_name); return { email: firstEmail(c.email_id), firstname: n.firstname, lastname: n.lastname, language: normLang(c.language), customer_id: c.name, customer_type: c.customer_type || '', monthly: Math.round(c._monthly || 0) } })
}
const seen = new Set(); const recipients = []; let dropped = 0
for (const r of rows) {