import { StateSetClient } from 'stateset-node';
import { TemporalClient } from '@temporalio/client';
class ReturnsManagementService {
constructor(apiKey) {
this.client = new StateSetClient({ apiKey });
this.temporal = new TemporalClient();
}
/**
* Complete returns workflow with all steps automated
*/
async processReturnRequest(request) {
const workflow = {
steps: [],
errors: [],
returnId: null
};
try {
// Step 1: Validate return eligibility
const eligibility = await this.checkReturnEligibility(request.order_id);
if (!eligibility.eligible) {
throw new Error(`Return not eligible: ${eligibility.reason}`);
}
workflow.steps.push({ step: 'eligibility_check', status: 'completed' });
// Step 2: Create return record
const return = await this.createReturnWithValidation(request);
workflow.returnId = return.id;
workflow.steps.push({ step: 'return_created', status: 'completed', returnId: return.id });
// Step 3: Generate return label
const label = await this.generateAndSendLabel(return.id, request.shipping_address);
workflow.steps.push({ step: 'label_generated', status: 'completed', trackingNumber: label.tracking_number });
// Step 4: Start Temporal workflow for automation
const workflowHandle = await this.startReturnWorkflow(return.id);
workflow.steps.push({ step: 'workflow_started', status: 'completed', workflowId: workflowHandle.workflowId });
// Step 5: Update support systems
await this.updateSupportSystems(return.id, request.ticket_id);
workflow.steps.push({ step: 'support_updated', status: 'completed' });
// Step 6: Set up tracking
await this.setupReturnTracking(return.id, label.tracking_number);
workflow.steps.push({ step: 'tracking_setup', status: 'completed' });
return {
success: true,
returnId: return.id,
rma: return.rma,
trackingNumber: label.tracking_number,
workflow: workflow
};
} catch (error) {
workflow.errors.push({
step: workflow.steps.length,
error: error.message,
timestamp: new Date()
});
// Attempt to clean up partial return
if (workflow.returnId) {
await this.client.returns.update(workflow.returnId, {
status: 'ERROR',
error_message: error.message
});
}
throw error;
}
}
async checkReturnEligibility(orderId) {
const order = await this.client.orders.get(orderId);
const daysSincePurchase = Math.floor((Date.now() - new Date(order.created_at)) / (1000 * 60 * 60 * 24));
if (daysSincePurchase > 30) {
return { eligible: false, reason: 'Outside 30-day return window' };
}
if (order.status === 'RETURNED') {
return { eligible: false, reason: 'Order already returned' };
}
return { eligible: true };
}
async createReturnWithValidation(request) {
// Validate all items are from the same order
const order = await this.client.orders.get(request.order_id);
const validSkus = order.items.map(item => item.sku);
for (const item of request.items) {
if (!validSkus.includes(item.sku)) {
throw new Error(`SKU ${item.sku} not found in order ${request.order_id}`);
}
}
// Create return with enriched data
const returnData = {
order_id: request.order_id,
customer_email: order.customer_email,
items: request.items,
status: 'NEW',
type: request.return_type,
reason_code: request.reason_code,
customer_notes: request.notes,
metadata: {
ip_address: request.ip_address,
user_agent: request.user_agent,
created_via: 'api'
}
};
return await this.client.returns.create(returnData);
}
async generateAndSendLabel(returnId, customerAddress) {
const label = await this.client.shipping.createReturnLabel({
return_id: returnId,
from_address: customerAddress,
carrier: this.selectOptimalCarrier(customerAddress),
service: 'GROUND',
insurance: true,
reference_1: returnId
});
// Send label via multiple channels
await Promise.all([
this.client.notifications.email({
return_id: returnId,
template: 'return_label',
attachments: [label]
}),
this.client.notifications.sms({
return_id: returnId,
message: `Your return label is ready. Tracking: ${label.tracking_number}`
})
]);
return label;
}
async startReturnWorkflow(returnId) {
return await this.temporal.workflow.start('returnApprovedWorkflow', {
taskQueue: 'returns-automation',
workflowId: `return-${returnId}`,
args: [{ returnId }]
});
}
async updateSupportSystems(returnId, ticketId) {
if (ticketId) {
// Update Zendesk/Gorgias
await this.client.support.updateTicket(ticketId, {
status: 'pending',
tags: ['return_initiated'],
custom_fields: {
return_id: returnId
}
});
}
}
async setupReturnTracking(returnId, trackingNumber) {
// Set up webhook for tracking updates
await this.client.webhooks.create({
url: `${process.env.WEBHOOK_URL}/returns/${returnId}/tracking`,
events: ['tracking.updated'],
filters: {
tracking_number: trackingNumber
}
});
// Register with Aftership or similar
await this.client.tracking.create({
tracking_number: trackingNumber,
carrier: 'auto-detect',
reference: returnId,
notify_customer: true
});
}
selectOptimalCarrier(address) {
// Logic to select best carrier based on location
if (address.country === 'US') {
return address.state === 'HI' || address.state === 'AK' ? 'usps' : 'fedex';
}
return 'ups';
}
}
// Usage example
const returnsService = new ReturnsManagementService(process.env.STATESET_API_KEY);
// Express.js endpoint
app.post('/api/returns', async (req, res) => {
try {
const result = await returnsService.processReturnRequest(req.body);
res.json(result);
} catch (error) {
res.status(400).json({
error: error.message,
code: error.code || 'RETURN_FAILED'
});
}
});