npm package: @rashidazarang/servicefusion-adapter
Description: ServiceFusion REST API adapter for field service management integrations
Author: Rashid Azarang
Latest version: 1.0.0

# ServiceFusion Adapter

[![npm version](https://img.shields.io/npm/v/@rashidazarang/servicefusion-adapter)](https://www.npmjs.com/package/@rashidazarang/servicefusion-adapter)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![TypeScript](https://img.shields.io/badge/TypeScript-5.3-blue)](https://www.typescriptlang.org/)

A TypeScript/JavaScript adapter for integrating with ServiceFusion's REST API. This adapter provides a clean, promise-based interface for field service management operations.

## 🚀 Features

- **Full REST API Coverage** for customers, jobs, estimates, invoices, and more
- **Built-in Rate Limiting** (0.5 requests/second as per ServiceFusion limits)
- **OAuth 2.0 Authentication** with automatic token refresh
- **Batch Operations** for efficient data synchronization
- **TypeScript Support** with complete type definitions
- **Smart Retry Logic** with exponential backoff
- **Webhook Support** for real-time updates
- **Comprehensive Error Handling**

## 📦 Installation

```bash
npm install @rashidazarang/servicefusion-adapter
```

or

```bash
yarn add @rashidazarang/servicefusion-adapter
```

## 🔧 Configuration

```typescript
import { ServiceFusionAdapter } from '@rashidazarang/servicefusion-adapter';

const adapter = new ServiceFusionAdapter({
  clientId: 'your-client-id',
  clientSecret: 'your-client-secret',
  baseUrl: 'https://api.servicefusion.com/v1',
  options: {
    rateLimit: 0.5, // requests per second (default: 0.5)
    retryAttempts: 3, // number of retry attempts (default: 3)
    timeout: 30000, // request timeout in ms (default: 30000)
    autoRefreshToken: true // auto refresh OAuth token (default: true)
  }
});

// Initialize and authenticate
await adapter.connect();
```

## 📖 Usage Examples

### Basic Operations

#### Get All Customers
```typescript
const customers = await adapter.getCustomers({
  limit: 100,
  offset: 0
});
console.log(`Found ${customers.length} customers`);
```

#### Create a Job
```typescript
const job = await adapter.createJob({
  customerId: 'customer-123',
  jobType: 'Maintenance',
  priority: 'High',
  scheduledDate: new Date('2025-01-15'),
  description: 'HVAC maintenance',
  address: {
    street: '123 Main St',
    city: 'Austin',
    state: 'TX',
    zipCode: '78701'
  }
});
console.log(`Created job: ${job.id}`);
```

#### Update Job Status
```typescript
const updatedJob = await adapter.updateJob(job.id, {
  status: 'In Progress',
  assignedTo: 'tech-456',
  notes: 'Technician en route'
});
```

### Advanced Features

#### Batch Sync Jobs
```typescript
// Sync jobs from external system
const externalJobs = await getExternalJobs(); // Your external data

const syncResults = await adapter.batchSyncJobs(externalJobs, {
  matchBy: 'externalId', // or 'customerId'
  updateExisting: true,
  createNew: true
});

console.log(`Created: ${syncResults.created}`);
console.log(`Updated: ${syncResults.updated}`);
console.log(`Errors: ${syncResults.errors}`);
```

#### Search with Filters
```typescript
// Find all high-priority jobs for today
const urgentJobs = await adapter.searchJobs({
  priority: 'High',
  scheduledDate: new Date(),
  status: ['Open', 'In Progress']
});

// Find customers by location
const localCustomers = await adapter.searchCustomers({
  city: 'Austin',
  state: 'TX',
  type: 'Commercial'
});
```

#### Pagination Helper
```typescript
// Automatically handle pagination
const allJobs = await adapter.getAllJobs({
  status: 'Open',
  pageSize: 100
});
console.log(`Total open jobs: ${allJobs.length}`);
```

### Webhook Management

```typescript
// Register a webhook
const webhook = await adapter.createWebhook({
  url: 'https://your-app.com/webhooks/servicefusion',
  events: ['job.created', 'job.updated', 'job.completed'],
  secret: 'your-webhook-secret'
});

// List webhooks
const webhooks = await adapter.getWebhooks();

// Delete webhook
await adapter.deleteWebhook(webhook.id);
```

### Error Handling

```typescript
try {
  const job = await adapter.getJob('invalid-id');
} catch (error) {
  if (error.code === 'NOT_FOUND') {
    console.error('Job not found');
  } else if (error.code === 'RATE_LIMIT_EXCEEDED') {
    console.error('Rate limit hit, retry after:', error.retryAfter);
  } else if (error.code === 'UNAUTHORIZED') {
    console.error('Authentication failed');
  }
}
```

## 🏗️ API Reference

### Authentication
- `connect(): Promise<void>` - Authenticate and get access token
- `disconnect(): Promise<void>` - Revoke token and cleanup
- `refreshToken(): Promise<void>` - Manually refresh OAuth token

### Customer Operations
- `getCustomers(options?: PaginationOptions): Promise<Customer[]>`
- `getCustomer(id: string): Promise<Customer>`
- `createCustomer(data: CustomerInput): Promise<Customer>`
- `updateCustomer(id: string, data: Partial<CustomerInput>): Promise<Customer>`
- `deleteCustomer(id: string): Promise<void>`
- `searchCustomers(filters: CustomerFilters): Promise<Customer[]>`

### Job Operations
- `getJobs(options?: JobFilters): Promise<Job[]>`
- `getJob(id: string): Promise<Job>`
- `createJob(data: JobInput): Promise<Job>`
- `updateJob(id: string, data: Partial<JobInput>): Promise<Job>`
- `deleteJob(id: string): Promise<void>`
- `searchJobs(filters: JobSearchFilters): Promise<Job[]>`
- `batchSyncJobs(jobs: JobInput[], options: SyncOptions): Promise<SyncResult>`

### Estimate Operations
- `getEstimates(jobId?: string): Promise<Estimate[]>`
- `getEstimate(id: string): Promise<Estimate>`
- `createEstimate(data: EstimateInput): Promise<Estimate>`
- `updateEstimate(id: string, data: Partial<EstimateInput>): Promise<Estimate>`
- `convertEstimateToJob(id: string): Promise<Job>`

### Invoice Operations
- `getInvoices(filters?: InvoiceFilters): Promise<Invoice[]>`
- `getInvoice(id: string): Promise<Invoice>`
- `createInvoice(data: InvoiceInput): Promise<Invoice>`
- `updateInvoice(id: string, data: Partial<InvoiceInput>): Promise<Invoice>`
- `sendInvoice(id: string, email: string): Promise<void>`

### Technician Operations
- `getTechnicians(options?: PaginationOptions): Promise<Technician[]>`
- `getTechnician(id: string): Promise<Technician>`
- `getSchedule(technicianId: string, date: Date): Promise<Schedule>`
- `assignJob(jobId: string, technicianId: string): Promise<Job>`

## 🔒 Rate Limiting

ServiceFusion enforces a rate limit of 0.5 requests per second (30 requests per minute). This adapter automatically handles rate limiting with:

- Built-in request throttling using Bottleneck
- Automatic queuing of requests
- Configurable rate limits
- Retry logic with exponential backoff for rate limit errors

```typescript
// Configure custom rate limiting
const adapter = new ServiceFusionAdapter({
  // ... credentials
  options: {
    rateLimit: 0.3, // Even more conservative: 0.3 requests per second
    retryAttempts: 5,
    retryDelay: 2000, // Initial retry delay in ms
    maxConcurrent: 2 // Max concurrent requests
  }
});
```

## 🧪 Testing

```bash
# Run all tests
npm test

# Run tests in watch mode
npm run test:watch

# Run with coverage
npm run test:coverage
```

## 🤝 Contributing

We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.

## 📝 License

This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

## 🆘 Support

- **Documentation**: [Full API Documentation](https://github.com/rashidazarang/servicefusion-adapter/wiki)
- **Issues**: [GitHub Issues](https://github.com/rashidazarang/servicefusion-adapter/issues)
- **Discussions**: [GitHub Discussions](https://github.com/rashidazarang/servicefusion-adapter/discussions)

## 🔗 Related Projects

- [PMIP Core](https://github.com/rashidazarang/property-management-integration-platform) - The main integration platform
- [PropertyWare Adapter](https://github.com/rashidazarang/propertyware-adapter) - PropertyWare SOAP API adapter

## 📈 Roadmap

- [ ] GraphQL API support
- [ ] Bulk import/export utilities
- [ ] Advanced caching strategies
- [ ] Real-time event streaming
- [ ] CLI tools for testing
- [ ] Terraform provider for infrastructure

## ⚠️ Disclaimer

This adapter is not officially affiliated with or endorsed by ServiceFusion. ServiceFusion is a registered trademark of ServiceFusion, Inc.