mcp-agendor 1.0.1 → 1.0.2

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.
@@ -26,7 +26,12 @@ export declare class AgendorClient {
26
26
  getDealsMovementsHistory(params?: {
27
27
  deal_id?: number;
28
28
  since?: string;
29
+ days_interval?: number;
30
+ page?: number;
31
+ per_page?: number;
29
32
  }): Promise<unknown[]>;
33
+ /** Busca movimentações em janelas de 30 dias (limite da API) com paginação */
34
+ getAllDealsMovementsHistory(since: string, daysTotal?: number): Promise<unknown[]>;
30
35
  getTasks(params?: {
31
36
  deal_id?: number;
32
37
  since?: string;
@@ -177,7 +177,11 @@ export class AgendorClient {
177
177
  q.set("deal_id", String(params.deal_id));
178
178
  if (params.since)
179
179
  q.set("since", params.since);
180
- const url = `${this.baseUrl}/deals/movements_history${q.toString() ? `?${q.toString()}` : ""}`;
180
+ if (params.days_interval != null)
181
+ q.set("days_interval", String(Math.min(30, params.days_interval)));
182
+ q.set("page", String(params.page ?? 1));
183
+ q.set("per_page", String(params.per_page ?? PER_PAGE));
184
+ const url = `${this.baseUrl}/deals/movements_history?${q.toString()}`;
181
185
  try {
182
186
  const data = await request(url, this.token);
183
187
  return Array.isArray(data) ? data : (data.data ?? []);
@@ -186,6 +190,34 @@ export class AgendorClient {
186
190
  return [];
187
191
  }
188
192
  }
193
+ /** Busca movimentações em janelas de 30 dias (limite da API) com paginação */
194
+ async getAllDealsMovementsHistory(since, daysTotal = 180) {
195
+ const all = [];
196
+ const windowDays = 30;
197
+ let sinceDate = new Date(since);
198
+ const endDate = new Date(sinceDate);
199
+ endDate.setDate(endDate.getDate() + daysTotal);
200
+ while (sinceDate < endDate) {
201
+ const windowEnd = new Date(sinceDate);
202
+ windowEnd.setDate(windowEnd.getDate() + windowDays);
203
+ const sinceStr = sinceDate.toISOString().slice(0, 19) + "Z";
204
+ let page = 1;
205
+ for (;;) {
206
+ const list = await this.getDealsMovementsHistory({
207
+ since: sinceStr,
208
+ days_interval: windowDays,
209
+ page,
210
+ per_page: PER_PAGE,
211
+ });
212
+ all.push(...list);
213
+ if (list.length < PER_PAGE)
214
+ break;
215
+ page += 1;
216
+ }
217
+ sinceDate = windowEnd;
218
+ }
219
+ return all;
220
+ }
189
221
  async getTasks(params = {}) {
190
222
  const q = new URLSearchParams();
191
223
  if (params.deal_id != null)
@@ -123,17 +123,20 @@ async function buildFunnelReport(funnel, deals, args, client) {
123
123
  since.setDate(since.getDate() - 180);
124
124
  const sinceStr = since.toISOString().slice(0, 19) + "Z";
125
125
  try {
126
- const raw = await client.getDealsMovementsHistory({ since: sinceStr });
126
+ const raw = await client.getAllDealsMovementsHistory(sinceStr, 180);
127
127
  const arr = Array.isArray(raw) ? raw : [];
128
128
  const stageDays = {};
129
129
  for (const s of stages)
130
130
  stageDays[s.id] = [];
131
131
  const byDeal = {};
132
132
  for (const m of arr) {
133
- const dealId = m.deal_id ?? m.dealId;
134
- const toId = m.to_stage_id ?? m.toStageId;
135
- const at = parseDate(m.created_at ?? m.createdAt ?? "").getTime();
136
- if (dealId == null)
133
+ if ((m.event_type ?? "").toLowerCase() !== "stage_changed")
134
+ continue;
135
+ const dealIdRaw = m.deal?.id ?? m.deal_id ?? m.dealId;
136
+ const dealId = typeof dealIdRaw === "string" ? parseInt(dealIdRaw, 10) : dealIdRaw;
137
+ const toId = m.deal_stage?.id ?? m.to_stage_id ?? m.toStageId;
138
+ const at = parseDate(m.updated_at ?? m.created_at ?? m.createdAt ?? "").getTime();
139
+ if (dealId == null || Number.isNaN(dealId))
137
140
  continue;
138
141
  if (!byDeal[dealId])
139
142
  byDeal[dealId] = [];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mcp-agendor",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "MCP server for Agendor CRM - pipeline metrics and commercial management",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -202,11 +202,20 @@ export class AgendorClient {
202
202
  return list as AgendorDeal[];
203
203
  }
204
204
 
205
- async getDealsMovementsHistory(params: { deal_id?: number; since?: string } = {}): Promise<unknown[]> {
205
+ async getDealsMovementsHistory(params: {
206
+ deal_id?: number;
207
+ since?: string;
208
+ days_interval?: number;
209
+ page?: number;
210
+ per_page?: number;
211
+ } = {}): Promise<unknown[]> {
206
212
  const q = new URLSearchParams();
207
213
  if (params.deal_id != null) q.set("deal_id", String(params.deal_id));
208
214
  if (params.since) q.set("since", params.since);
209
- const url = `${this.baseUrl}/deals/movements_history${q.toString() ? `?${q.toString()}` : ""}`;
215
+ if (params.days_interval != null) q.set("days_interval", String(Math.min(30, params.days_interval)));
216
+ q.set("page", String(params.page ?? 1));
217
+ q.set("per_page", String(params.per_page ?? PER_PAGE));
218
+ const url = `${this.baseUrl}/deals/movements_history?${q.toString()}`;
210
219
  try {
211
220
  const data = await request<unknown[] | { data?: unknown[] }>(url, this.token);
212
221
  return Array.isArray(data) ? data : (data.data ?? []);
@@ -215,6 +224,35 @@ export class AgendorClient {
215
224
  }
216
225
  }
217
226
 
227
+ /** Busca movimentações em janelas de 30 dias (limite da API) com paginação */
228
+ async getAllDealsMovementsHistory(since: string, daysTotal = 180): Promise<unknown[]> {
229
+ const all: unknown[] = [];
230
+ const windowDays = 30;
231
+ let sinceDate = new Date(since);
232
+ const endDate = new Date(sinceDate);
233
+ endDate.setDate(endDate.getDate() + daysTotal);
234
+
235
+ while (sinceDate < endDate) {
236
+ const windowEnd = new Date(sinceDate);
237
+ windowEnd.setDate(windowEnd.getDate() + windowDays);
238
+ const sinceStr = sinceDate.toISOString().slice(0, 19) + "Z";
239
+ let page = 1;
240
+ for (;;) {
241
+ const list = await this.getDealsMovementsHistory({
242
+ since: sinceStr,
243
+ days_interval: windowDays,
244
+ page,
245
+ per_page: PER_PAGE,
246
+ });
247
+ all.push(...list);
248
+ if (list.length < PER_PAGE) break;
249
+ page += 1;
250
+ }
251
+ sinceDate = windowEnd;
252
+ }
253
+ return all;
254
+ }
255
+
218
256
  async getTasks(params: { deal_id?: number; since?: string } = {}): Promise<AgendorTask[]> {
219
257
  const q = new URLSearchParams();
220
258
  if (params.deal_id != null) q.set("deal_id", String(params.deal_id));
@@ -148,17 +148,30 @@ async function buildFunnelReport(
148
148
  since.setDate(since.getDate() - 180);
149
149
  const sinceStr = since.toISOString().slice(0, 19) + "Z";
150
150
  try {
151
- const raw = await client.getDealsMovementsHistory({ since: sinceStr });
151
+ const raw = await client.getAllDealsMovementsHistory(sinceStr, 180);
152
152
  const arr = Array.isArray(raw) ? raw : [];
153
- type Mov = { deal_id?: number; to_stage_id?: number; created_at?: string; toStageId?: number; createdAt?: string };
153
+ type Mov = {
154
+ deal?: { id?: number | string };
155
+ deal_id?: number;
156
+ dealId?: number;
157
+ deal_stage?: { id?: number };
158
+ to_stage_id?: number;
159
+ toStageId?: number;
160
+ updated_at?: string;
161
+ created_at?: string;
162
+ createdAt?: string;
163
+ event_type?: string;
164
+ };
154
165
  const stageDays: Record<number, number[]> = {};
155
166
  for (const s of stages) stageDays[s.id] = [];
156
167
  const byDeal: Record<number, Array<{ stageId: number; enteredAt: number }>> = {};
157
168
  for (const m of arr as Mov[]) {
158
- const dealId = m.deal_id ?? (m as Record<string, unknown>).dealId as number | undefined;
159
- const toId = m.to_stage_id ?? m.toStageId;
160
- const at = parseDate(m.created_at ?? (m.createdAt as string) ?? "").getTime();
161
- if (dealId == null) continue;
169
+ if ((m.event_type ?? "").toLowerCase() !== "stage_changed") continue;
170
+ const dealIdRaw = (m.deal as { id?: number | string } | undefined)?.id ?? m.deal_id ?? m.dealId;
171
+ const dealId = typeof dealIdRaw === "string" ? parseInt(dealIdRaw, 10) : dealIdRaw;
172
+ const toId = (m.deal_stage as { id?: number } | undefined)?.id ?? m.to_stage_id ?? m.toStageId;
173
+ const at = parseDate(m.updated_at ?? m.created_at ?? (m.createdAt as string) ?? "").getTime();
174
+ if (dealId == null || Number.isNaN(dealId)) continue;
162
175
  if (!byDeal[dealId]) byDeal[dealId] = [];
163
176
  if (toId != null && stageIds.has(toId as number)) byDeal[dealId].push({ stageId: toId as number, enteredAt: at });
164
177
  }