0
# Fulfillment Service
1
2
Interface for fulfillment service implementations managing shipping options, fulfillment processing, returns, and document generation for logistics operations.
3
4
**Deprecation Notice**: Use `AbstractFulfillmentService` from @medusajs/medusa instead.
5
6
## Capabilities
7
8
### Static Methods
9
10
Type checking and identification methods for fulfillment services.
11
12
```javascript { .api }
13
/**
14
* Static property identifying this as a fulfillment service
15
*/
16
static _isFulfillmentService: boolean;
17
18
/**
19
* Checks if an object is a fulfillment service
20
* @param {object} obj - Object to check
21
* @returns {boolean} True if obj is a fulfillment service
22
*/
23
static isFulfillmentService(obj: object): boolean;
24
```
25
26
### Service Identification
27
28
Method to get the service identifier.
29
30
```javascript { .api }
31
/**
32
* Returns the service identifier from constructor
33
* @returns {string} Service identifier
34
*/
35
getIdentifier(): string;
36
```
37
38
### Fulfillment Options
39
40
Methods for managing available fulfillment options and validation.
41
42
```javascript { .api }
43
/**
44
* Returns all fulfillment options that the provider can be used with
45
* Called before a shipping option is created in Admin
46
* @returns {any} Available fulfillment options
47
* @throws {Error} If not overridden by child class
48
*/
49
getFulfillmentOptions(): any;
50
51
/**
52
* Validates fulfillment option exists before creating shipping option in Admin
53
* @param {object} data - Option data to validate
54
* @returns {any} Validation result
55
* @throws {Error} If not overridden by child class
56
*/
57
validateOption(data: object): any;
58
59
/**
60
* Validates data sent with shipping method before setting on cart
61
* @param {object} optionData - The option data to validate
62
* @param {object} data - The shipping method data to validate
63
* @param {object} cart - The cart the shipping method will be applied to
64
* @returns {object} Data to populate cart.shipping_methods.$.data
65
* @throws {Error} If not overridden by child class
66
*/
67
validateFulfillmentData(optionData: object, data: object, cart?: object): object;
68
```
69
70
### Price Calculation
71
72
Methods for determining if pricing can be calculated and calculating shipping costs.
73
74
```javascript { .api }
75
/**
76
* Determines if fulfillment service can calculate price for given data
77
* @param {object} data - Data to check for price calculation capability
78
* @returns {any} True if price can be calculated
79
* @throws {Error} If not overridden by child class
80
*/
81
canCalculate(data: object): any;
82
83
/**
84
* Calculates price for a given shipping option
85
* @param {object} optionData - Shipping option data
86
* @param {object} data - Additional calculation data
87
* @param {object} cart - Cart object for calculation context
88
* @returns {any} Calculated price
89
* @throws {Error} If not overridden by child class
90
*/
91
calculatePrice(optionData: object, data: object, cart: object): any;
92
```
93
94
### Fulfillment Operations
95
96
Methods for creating and canceling fulfillments.
97
98
```javascript { .api }
99
/**
100
* Creates a fulfillment for an order
101
* @param {object} data - Fulfillment data
102
* @param {array} items - Items to fulfill
103
* @param {object} order - Order object
104
* @param {object} fulfillment - Fulfillment object
105
* @returns {any} Created fulfillment result
106
* @throws {Error} If not overridden by child class
107
*/
108
createFulfillment(data: object, items: array, order: object, fulfillment: object): any;
109
110
/**
111
* Cancels an existing fulfillment
112
* @param {object} fulfillment - Fulfillment to cancel
113
* @returns {any} Cancellation result
114
* @throws {Error} If not overridden by child class
115
*/
116
cancelFulfillment(fulfillment: object): any;
117
```
118
119
### Return Operations
120
121
Methods for handling return orders.
122
123
```javascript { .api }
124
/**
125
* Creates a return order with necessary data for future operations
126
* @param {object} fromData - Data to create return from
127
* @returns {any} Return order data
128
* @throws {Error} If not overridden by child class
129
*/
130
createReturn(fromData: object): any;
131
```
132
133
### Document Operations
134
135
Methods for retrieving documents related to fulfillments, returns, and shipments.
136
137
```javascript { .api }
138
/**
139
* Retrieves documents associated with a fulfillment
140
* @param {object} data - Fulfillment data
141
* @returns {array} Array of fulfillment documents (empty by default)
142
*/
143
getFulfillmentDocuments(data: object): array;
144
145
/**
146
* Retrieves documents related to a return order
147
* @param {object} data - Return data
148
* @returns {array} Array of return documents (empty by default)
149
*/
150
getReturnDocuments(data: object): array;
151
152
/**
153
* Retrieves documents related to a shipment
154
* @param {object} data - Shipment data
155
* @returns {array} Array of shipment documents (empty by default)
156
*/
157
getShipmentDocuments(data: object): array;
158
159
/**
160
* Retrieves documents based on fulfillment data and document type
161
* @param {object} fulfillmentData - Fulfillment data
162
* @param {string} documentType - Type of document to retrieve
163
* @returns {any} Retrieved documents
164
* @throws {Error} If not overridden by child class
165
*/
166
retrieveDocuments(fulfillmentData: object, documentType: string): any;
167
```
168
169
## Implementation Example
170
171
```javascript
172
import { FulfillmentService } from "medusa-interfaces";
173
174
class CustomFulfillmentService extends FulfillmentService {
175
static identifier = "custom-fulfillment";
176
177
constructor(options) {
178
super();
179
this.options_ = options;
180
}
181
182
getFulfillmentOptions() {
183
return [
184
{
185
id: "standard",
186
name: "Standard Shipping",
187
description: "5-7 business days"
188
},
189
{
190
id: "express",
191
name: "Express Shipping",
192
description: "1-2 business days"
193
}
194
];
195
}
196
197
validateOption(data) {
198
const validOptions = ["standard", "express"];
199
if (!validOptions.includes(data.id)) {
200
throw new Error("Invalid fulfillment option");
201
}
202
return true;
203
}
204
205
validateFulfillmentData(optionData, data, cart) {
206
// Validate shipping method data
207
if (optionData.id === "express" && !data.express_service_type) {
208
throw new Error("Express service type required");
209
}
210
211
return {
212
service_type: optionData.id,
213
validated_data: data
214
};
215
}
216
217
canCalculate(data) {
218
// Check if we have necessary data for price calculation
219
return data.destination_address && data.items;
220
}
221
222
calculatePrice(optionData, data, cart) {
223
// Calculate shipping price based on option and cart data
224
const basePrice = optionData.id === "express" ? 15.00 : 5.00;
225
const weightMultiplier = cart.items.reduce((total, item) => total + item.quantity, 0) * 0.5;
226
227
return Math.round((basePrice + weightMultiplier) * 100); // Return in cents
228
}
229
230
async createFulfillment(data, items, order, fulfillment) {
231
// Create fulfillment with external provider
232
const shipment = await this.externalProvider.createShipment({
233
items: items,
234
address: order.shipping_address,
235
service_type: data.service_type
236
});
237
238
return {
239
tracking_number: shipment.tracking_number,
240
tracking_url: shipment.tracking_url,
241
data: shipment
242
};
243
}
244
245
async cancelFulfillment(fulfillment) {
246
// Cancel fulfillment with external provider
247
await this.externalProvider.cancelShipment(fulfillment.data.id);
248
249
return {
250
status: "cancelled"
251
};
252
}
253
254
async createReturn(fromData) {
255
// Create return order
256
const returnOrder = await this.externalProvider.createReturn({
257
original_fulfillment: fromData.fulfillment_id,
258
items: fromData.items,
259
reason: fromData.reason
260
});
261
262
return {
263
return_id: returnOrder.id,
264
return_label_url: returnOrder.label_url,
265
data: returnOrder
266
};
267
}
268
269
getFulfillmentDocuments(data) {
270
return [
271
{
272
type: "shipping_label",
273
url: data.label_url
274
},
275
{
276
type: "tracking_info",
277
url: data.tracking_url
278
}
279
];
280
}
281
282
getReturnDocuments(data) {
283
return [
284
{
285
type: "return_label",
286
url: data.return_label_url
287
}
288
];
289
}
290
291
retrieveDocuments(fulfillmentData, documentType) {
292
switch (documentType) {
293
case "shipping_label":
294
return this.getFulfillmentDocuments(fulfillmentData);
295
case "return_label":
296
return this.getReturnDocuments(fulfillmentData);
297
default:
298
return [];
299
}
300
}
301
}
302
```
303
304
## Error Handling
305
306
All abstract methods throw descriptive errors when not implemented:
307
308
- `"getFulfillmentOptions must be overridden by the child class"`
309
- `"validateFulfillmentData must be overridden by the child class"`
310
- `"validateOption must be overridden by the child class"`
311
- `"canCalculate must be overridden by the child class"`
312
- `"calculatePrice must be overridden by the child class"`
313
- `"createFulfillment must be overridden by the child class"`
314
- `"cancelFulfillment must be overridden by the child class"`
315
- `"createReturn must be overridden by the child class"`
316
- `"retrieveDocuments must be overridden by the child class"`