Skip to main content
Glama

mcp-google-sheets

updated-quote.ts5.85 kB
import { TriggerStrategy, createTrigger, PiecePropValueSchema, Property, } from '@activepieces/pieces-framework'; import { xeroAuth } from '../..'; import { DedupeStrategy, httpClient, HttpMethod, Polling, pollingHelper, } from '@activepieces/pieces-common'; import { props } from '../common/props'; function parseXeroDateToEpoch(dateVal: unknown): number { if (typeof dateVal === 'string') { if (dateVal.includes('/Date(')) { const match = /\/Date\((\d+)/.exec(dateVal); if (match && match[1]) return Number(match[1]); } const t = Date.parse(dateVal); if (!Number.isNaN(t)) return t; } if (typeof dateVal === 'number') return dateVal; return Date.now(); } const polling: Polling< PiecePropValueSchema<typeof xeroAuth>, Record<string, unknown> > = { strategy: DedupeStrategy.TIMEBASED, async items({ auth, lastFetchEpochMS, propsValue }) { const { access_token } = auth; const tenantId = propsValue?.['tenant_id'] as string; const pageSize = (propsValue?.['page_size'] as number) || 200; const statuses = (propsValue?.['statuses'] as string[]) || []; const contactId = propsValue?.['contact_id'] as string | undefined; const quoteNumber = propsValue?.['quote_number'] as string | undefined; const dateFrom = propsValue?.['date_from'] as string | undefined; const dateTo = propsValue?.['date_to'] as string | undefined; const expiryFrom = propsValue?.['expiry_date_from'] as string | undefined; const expiryTo = propsValue?.['expiry_date_to'] as string | undefined; const results: any[] = []; const maxPages = 5; for (let page = 1; page <= maxPages; page++) { const queryParams: Record<string, string> = { page: String(page), pageSize: String(pageSize), order: 'UpdatedDateUTC ASC', }; if (Array.isArray(statuses) && statuses.length === 1) { queryParams['status'] = statuses[0]; } if (contactId) queryParams['ContactID'] = contactId; if (quoteNumber) queryParams['QuoteNumber'] = quoteNumber; if (dateFrom) queryParams['DateFrom'] = dateFrom; if (dateTo) queryParams['DateTo'] = dateTo; if (expiryFrom) queryParams['ExpiryDateFrom'] = expiryFrom; if (expiryTo) queryParams['ExpiryDateTo'] = expiryTo; const headers: Record<string, string> = { Authorization: `Bearer ${access_token}`, Accept: 'application/json', 'Xero-Tenant-Id': tenantId, }; if (lastFetchEpochMS > 0) { const ifModified = new Date(lastFetchEpochMS).toISOString().slice(0, 19); headers['If-Modified-Since'] = ifModified; } const resp = await httpClient.sendRequest<Record<string, any>>({ method: HttpMethod.GET, url: 'https://api.xero.com/api.xro/2.0/Quotes', headers, queryParams, }); if (resp.status !== 200) break; const quotes: any[] = resp.body?.Quotes ?? []; for (const q of quotes) { const epoch = parseXeroDateToEpoch(q.UpdatedDateUTC || q.Date); results.push({ epochMilliSeconds: epoch, data: q }); } if (quotes.length < pageSize) break; } return results; }, }; export const xeroUpdatedQuote = createTrigger({ auth: xeroAuth, name: 'xero_updated_quote', displayName: 'Updated Quote', description: 'Fires when a quote is created or updated.', props: { tenant_id: props.tenant_id, statuses: Property.StaticMultiSelectDropdown({ displayName: 'Filter by Status (optional)', required: false, options: { options: [ { label: 'DRAFT', value: 'DRAFT' }, { label: 'SENT', value: 'SENT' }, { label: 'ACCEPTED', value: 'ACCEPTED' }, { label: 'DECLINED', value: 'DECLINED' }, { label: 'INVOICED', value: 'INVOICED' }, { label: 'DELETED', value: 'DELETED' }, ], }, }), contact_id: props.contact_dropdown(false), quote_number: Property.ShortText({ displayName: 'Quote Number (partial match)', required: false }), date_from: Property.ShortText({ displayName: 'Date From (YYYY-MM-DD)', required: false }), date_to: Property.ShortText({ displayName: 'Date To (YYYY-MM-DD)', required: false }), expiry_date_from: Property.ShortText({ displayName: 'Expiry Date From (YYYY-MM-DD)', required: false }), expiry_date_to: Property.ShortText({ displayName: 'Expiry Date To (YYYY-MM-DD)', required: false }), page_size: Property.Number({ displayName: 'Page Size (1-1000)', required: false }), }, type: TriggerStrategy.POLLING, async onEnable(context: any) { await pollingHelper.onEnable(polling, { auth: context.auth, store: context.store, propsValue: context.propsValue, }); }, async onDisable(context: any) { await pollingHelper.onDisable(polling, { auth: context.auth, store: context.store, propsValue: context.propsValue, }); }, async test(context: any) { return await pollingHelper.test(polling, context); }, async run(context: any) { const items = (await pollingHelper.poll(polling, context)) as any[]; const tenantId = context.propsValue['tenant_id']; const prevMapKey = `xero_quote_prev_updated_${tenantId}`; const prevMap: Record<string, number> = (await context.store.get(prevMapKey)) || {}; const results: any[] = []; for (const q of items) { const id = q?.QuoteID as string | undefined; if (!id) continue; const updatedEpoch = parseXeroDateToEpoch(q?.UpdatedDateUTC || q?.Date); const prevEpoch = prevMap[id] || 0; if (updatedEpoch > prevEpoch) { results.push(q); prevMap[id] = updatedEpoch; } } await context.store.put(prevMapKey, prevMap); return results; }, sampleData: undefined, });

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/activepieces/activepieces'

If you have feedback or need assistance with the MCP directory API, please join our Discord server