mcp-grocy 2.7.0 → 2.7.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.
- package/CHANGELOG.md +14 -0
- package/README.md +15 -1
- package/build/api/client.js +119 -0
- package/build/config/index.js +283 -0
- package/build/main.js +44 -0
- package/build/resources/CHANGELOG.md +15 -3
- package/build/resources/README.md +15 -1
- package/build/resources/api-reference.md +2 -1
- package/build/resources/response-format.md +1 -3
- package/build/server/http-server.js +398 -0
- package/build/server/mcp-server.js +230 -0
- package/build/server/resources.js +73 -0
- package/build/server/tool-input-zod.js +86 -0
- package/build/tools/base.js +157 -0
- package/build/tools/household/definitions.js +161 -0
- package/build/tools/household/handlers.js +109 -0
- package/build/tools/household/index.js +25 -0
- package/build/tools/index.js +2 -0
- package/build/tools/inventory/definitions.js +416 -0
- package/build/tools/inventory/handlers.js +443 -0
- package/build/tools/inventory/index.js +32 -0
- package/build/tools/module-loader.js +154 -0
- package/build/tools/recipes/definitions.js +278 -0
- package/build/tools/recipes/handlers.js +518 -0
- package/build/tools/recipes/index.js +33 -0
- package/build/tools/recipes/validations.js +29 -0
- package/build/tools/shopping/definitions.js +147 -0
- package/build/tools/shopping/handlers.js +198 -0
- package/build/tools/shopping/index.js +17 -0
- package/build/tools/system/definitions.js +89 -0
- package/build/tools/system/handlers.js +156 -0
- package/build/tools/system/index.js +16 -0
- package/build/tools/types.js +1 -0
- package/build/tools/validation-helpers.js +39 -0
- package/build/types/index.js +64 -0
- package/build/utils/errors.js +143 -0
- package/build/utils/logger.js +142 -0
- package/build/version.js +1 -1
- package/package.json +27 -25
|
@@ -0,0 +1,416 @@
|
|
|
1
|
+
export const inventoryToolDefinitions = [
|
|
2
|
+
// Product Management Tools
|
|
3
|
+
{
|
|
4
|
+
name: 'inventory_products_get',
|
|
5
|
+
description: '[INVENTORY/PRODUCTS] Get specific fields for all products from your Grocy instance. You must specify which fields to retrieve.',
|
|
6
|
+
annotations: { readOnlyHint: true },
|
|
7
|
+
inputSchema: {
|
|
8
|
+
type: 'object',
|
|
9
|
+
properties: {
|
|
10
|
+
fields: {
|
|
11
|
+
type: 'array',
|
|
12
|
+
items: {
|
|
13
|
+
type: 'string',
|
|
14
|
+
enum: [
|
|
15
|
+
'id',
|
|
16
|
+
'name',
|
|
17
|
+
'description',
|
|
18
|
+
'product_group_id',
|
|
19
|
+
'active',
|
|
20
|
+
'location_id',
|
|
21
|
+
'shopping_location_id',
|
|
22
|
+
'qu_id_purchase',
|
|
23
|
+
'qu_id_stock',
|
|
24
|
+
'qu_factor_purchase_to_stock',
|
|
25
|
+
'min_stock_amount',
|
|
26
|
+
'default_best_before_days',
|
|
27
|
+
'default_best_before_days_after_open',
|
|
28
|
+
'default_best_before_days_after_freezing',
|
|
29
|
+
'default_best_before_days_after_thawing',
|
|
30
|
+
'picture_file_name',
|
|
31
|
+
'allow_label_per_unit',
|
|
32
|
+
'energy_per_stock_unit',
|
|
33
|
+
'calories_per_stock_unit',
|
|
34
|
+
'default_stock_label_type',
|
|
35
|
+
'should_not_be_frozen',
|
|
36
|
+
'treat_opened_as_out_of_stock',
|
|
37
|
+
'no_own_stock',
|
|
38
|
+
'cumulate_min_stock_amount_of_sub_products',
|
|
39
|
+
'parent_product_id',
|
|
40
|
+
'calories_per_unit_factor',
|
|
41
|
+
'quick_consume_amount',
|
|
42
|
+
'hide_on_stock_overview',
|
|
43
|
+
],
|
|
44
|
+
},
|
|
45
|
+
description: 'Array of field names to retrieve. For basic lookup use ["id", "name"]. For detailed info include ["id", "name", "description", "active"]. Available fields: id, name, description, product_group_id, active, location_id, shopping_location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock, min_stock_amount, default_best_before_days, default_best_before_days_after_open, default_best_before_days_after_freezing, default_best_before_days_after_thawing, picture_file_name, allow_label_per_unit, energy_per_stock_unit, calories_per_stock_unit, default_stock_label_type, should_not_be_frozen, treat_opened_as_out_of_stock, no_own_stock, cumulate_min_stock_amount_of_sub_products, parent_product_id, calories_per_unit_factor, quick_consume_amount, hide_on_stock_overview',
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
required: ['fields'],
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
name: 'inventory_products_get_groups',
|
|
53
|
+
description: '[INVENTORY/PRODUCTS] **Categories only:** list product groups (taxonomy), not individual products. For product rows with fields use inventory_products_get.',
|
|
54
|
+
annotations: { readOnlyHint: true },
|
|
55
|
+
inputSchema: {
|
|
56
|
+
type: 'object',
|
|
57
|
+
properties: {},
|
|
58
|
+
required: [],
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
name: 'inventory_products_get_price_history',
|
|
63
|
+
description: '[INVENTORY/PRODUCTS] Get the price history of a product from your Grocy instance.',
|
|
64
|
+
annotations: { readOnlyHint: true },
|
|
65
|
+
inputSchema: {
|
|
66
|
+
type: 'object',
|
|
67
|
+
properties: {
|
|
68
|
+
productId: {
|
|
69
|
+
type: 'number',
|
|
70
|
+
description: 'ID of the product to get price history for. Use inventory_products_lookup to find the product ID by name (or inventory_products_get with fields if listing products).',
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
required: ['productId'],
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
// Stock Management Tools
|
|
77
|
+
{
|
|
78
|
+
name: 'inventory_stock_get_all',
|
|
79
|
+
description: '[INVENTORY/STOCK] **Full stock dump**—every stock entry in the home with stockIds. Prefer inventory_stock_get_by_product when the user names one product; prefer inventory_stock_get_by_location when they name one storage place.',
|
|
80
|
+
annotations: { readOnlyHint: true },
|
|
81
|
+
inputSchema: {
|
|
82
|
+
type: 'object',
|
|
83
|
+
properties: {},
|
|
84
|
+
required: [],
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
name: 'inventory_stock_get_by_product',
|
|
89
|
+
description: '[INVENTORY/STOCK] Stock rows for **one product** across locations (needs productId). Use when the user asks how much of a product is on hand or needs stockId for that product—not for everything in a cupboard (use inventory_stock_get_by_location).',
|
|
90
|
+
annotations: { readOnlyHint: true },
|
|
91
|
+
inputSchema: {
|
|
92
|
+
type: 'object',
|
|
93
|
+
properties: {
|
|
94
|
+
productId: {
|
|
95
|
+
type: 'number',
|
|
96
|
+
description: 'ID of the product to get stock entries for. Use inventory_products_lookup to find the product ID by name (or inventory_products_get with fields if listing products).',
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
required: ['productId'],
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
name: 'inventory_stock_get_volatile',
|
|
104
|
+
description: '[INVENTORY/STOCK] Get volatile stock information (due products, overdue products, expired products, missing products).',
|
|
105
|
+
annotations: { readOnlyHint: true },
|
|
106
|
+
inputSchema: {
|
|
107
|
+
type: 'object',
|
|
108
|
+
properties: {
|
|
109
|
+
includeDetails: {
|
|
110
|
+
type: 'boolean',
|
|
111
|
+
description: 'Whether to include additional details about each stock item',
|
|
112
|
+
},
|
|
113
|
+
},
|
|
114
|
+
required: [],
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
name: 'inventory_stock_get_by_location',
|
|
119
|
+
description: '[INVENTORY/STOCK] Everything stocked in **one storage location** (needs locationId from system_locations_get). Use when the user asks what is in the freezer/pantry—not for one named product across sites (use inventory_stock_get_by_product).',
|
|
120
|
+
annotations: { readOnlyHint: true },
|
|
121
|
+
inputSchema: {
|
|
122
|
+
type: 'object',
|
|
123
|
+
properties: {
|
|
124
|
+
locationId: {
|
|
125
|
+
type: 'number',
|
|
126
|
+
description: 'ID of the location to get stock for.',
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
required: ['locationId'],
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
// Stock Transaction Tools
|
|
133
|
+
{
|
|
134
|
+
name: 'inventory_transactions_purchase',
|
|
135
|
+
description: '[INVENTORY/TRANSACTIONS] **Product-level purchase:** add quantity by productId (creates/merges stock). No stockId. Use inventory_products_get and system_locations_get for IDs.',
|
|
136
|
+
inputSchema: {
|
|
137
|
+
type: 'object',
|
|
138
|
+
properties: {
|
|
139
|
+
productId: {
|
|
140
|
+
type: 'number',
|
|
141
|
+
description: 'ID of the product to purchase. Use inventory_products_lookup to find the product ID by name (or inventory_products_get with fields if listing products).',
|
|
142
|
+
},
|
|
143
|
+
amount: {
|
|
144
|
+
type: 'number',
|
|
145
|
+
description: "Amount to purchase in the product's stock unit (e.g., 2 pieces, 1.5 kg, 750 ml). Ensure you know the product's unit before specifying amount.",
|
|
146
|
+
},
|
|
147
|
+
bestBeforeDate: {
|
|
148
|
+
type: 'string',
|
|
149
|
+
description: "Best before date in YYYY-MM-DD format. If not provided, will use product's default best before days.",
|
|
150
|
+
},
|
|
151
|
+
price: {
|
|
152
|
+
type: 'number',
|
|
153
|
+
description: 'Price per stock unit (optional)',
|
|
154
|
+
},
|
|
155
|
+
locationId: {
|
|
156
|
+
type: 'number',
|
|
157
|
+
description: "Location ID where the product should be stored. Use system_locations_get to find the location ID. If not provided, uses product's default location.",
|
|
158
|
+
},
|
|
159
|
+
note: {
|
|
160
|
+
type: 'string',
|
|
161
|
+
description: 'Optional note for the stock entry',
|
|
162
|
+
},
|
|
163
|
+
},
|
|
164
|
+
required: ['productId', 'amount'],
|
|
165
|
+
},
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
name: 'inventory_transactions_consume',
|
|
169
|
+
description: '[INVENTORY/TRANSACTIONS] **Product-level consume:** reduce stock by productId+amount (Grocy picks lots). If the user refers to a specific package/stock row, use inventory_stock_entry_consume (stockId). Use inventory_products_get for productId.',
|
|
170
|
+
inputSchema: {
|
|
171
|
+
type: 'object',
|
|
172
|
+
properties: {
|
|
173
|
+
productId: {
|
|
174
|
+
type: 'number',
|
|
175
|
+
description: 'ID of the product to consume. Use inventory_products_lookup to find the product ID by name (or inventory_products_get with fields if listing products).',
|
|
176
|
+
},
|
|
177
|
+
amount: {
|
|
178
|
+
type: 'number',
|
|
179
|
+
description: "Amount to consume in the product's stock unit (e.g., 2 pieces, 1.5 kg, 750 ml). Ensure you know the product's unit before specifying amount.",
|
|
180
|
+
},
|
|
181
|
+
spoiled: {
|
|
182
|
+
type: 'boolean',
|
|
183
|
+
description: 'Whether the product was spoiled/wasted (default: false)',
|
|
184
|
+
default: false,
|
|
185
|
+
},
|
|
186
|
+
locationId: {
|
|
187
|
+
type: 'number',
|
|
188
|
+
description: 'Location ID to consume from (optional). Use system_locations_get to find the location ID.',
|
|
189
|
+
},
|
|
190
|
+
note: {
|
|
191
|
+
type: 'string',
|
|
192
|
+
description: 'Optional note for the consumption',
|
|
193
|
+
},
|
|
194
|
+
},
|
|
195
|
+
required: ['productId', 'amount'],
|
|
196
|
+
},
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
name: 'inventory_transactions_transfer',
|
|
200
|
+
description: '[INVENTORY/TRANSACTIONS] **Product-level transfer:** move amount of a product between locations without choosing a stock row. For one specific lot, use inventory_stock_entry_transfer (stockId). Use inventory_products_get and system_locations_get.',
|
|
201
|
+
inputSchema: {
|
|
202
|
+
type: 'object',
|
|
203
|
+
properties: {
|
|
204
|
+
productId: {
|
|
205
|
+
type: 'number',
|
|
206
|
+
description: 'ID of the product to transfer. Use inventory_products_lookup to find the product ID by name (or inventory_products_get with fields if listing products).',
|
|
207
|
+
},
|
|
208
|
+
amount: {
|
|
209
|
+
type: 'number',
|
|
210
|
+
description: "Amount to transfer in the product's stock unit (e.g., 2 pieces, 1.5 kg, 750 ml). Ensure you know the product's unit before specifying amount.",
|
|
211
|
+
},
|
|
212
|
+
fromLocationId: {
|
|
213
|
+
type: 'number',
|
|
214
|
+
description: 'Source location ID. Use system_locations_get to find the location ID.',
|
|
215
|
+
},
|
|
216
|
+
toLocationId: {
|
|
217
|
+
type: 'number',
|
|
218
|
+
description: 'Destination location ID. Use system_locations_get to find the location ID.',
|
|
219
|
+
},
|
|
220
|
+
note: {
|
|
221
|
+
type: 'string',
|
|
222
|
+
description: 'Optional note for the transfer',
|
|
223
|
+
},
|
|
224
|
+
},
|
|
225
|
+
required: ['productId', 'amount', 'fromLocationId', 'toLocationId'],
|
|
226
|
+
},
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
name: 'inventory_transactions_adjust',
|
|
230
|
+
description: '[INVENTORY/TRANSACTIONS] Track a product inventory (set current stock amount). Use inventory_products_get to find the product ID and system_locations_get to find location IDs.',
|
|
231
|
+
inputSchema: {
|
|
232
|
+
type: 'object',
|
|
233
|
+
properties: {
|
|
234
|
+
productId: {
|
|
235
|
+
type: 'number',
|
|
236
|
+
description: 'ID of the product to inventory. Use inventory_products_lookup to find the product ID by name (or inventory_products_get with fields if listing products).',
|
|
237
|
+
},
|
|
238
|
+
newAmount: {
|
|
239
|
+
type: 'number',
|
|
240
|
+
description: "The new/correct total amount of stock for this product in the product's stock unit.",
|
|
241
|
+
},
|
|
242
|
+
bestBeforeDate: {
|
|
243
|
+
type: 'string',
|
|
244
|
+
description: 'Best before date in YYYY-MM-DD format for the inventory correction.',
|
|
245
|
+
},
|
|
246
|
+
locationId: {
|
|
247
|
+
type: 'number',
|
|
248
|
+
description: 'Location ID for the inventory (optional). Use system_locations_get to find the location ID.',
|
|
249
|
+
},
|
|
250
|
+
note: {
|
|
251
|
+
type: 'string',
|
|
252
|
+
description: 'Optional note for the inventory correction',
|
|
253
|
+
},
|
|
254
|
+
},
|
|
255
|
+
required: ['productId', 'newAmount'],
|
|
256
|
+
},
|
|
257
|
+
},
|
|
258
|
+
{
|
|
259
|
+
name: 'inventory_transactions_open',
|
|
260
|
+
description: '[INVENTORY/TRANSACTIONS] **Product-level open:** mark opened/started without a stock row. For one specific package use inventory_stock_entry_open (stockId). Use inventory_products_get for productId.',
|
|
261
|
+
inputSchema: {
|
|
262
|
+
type: 'object',
|
|
263
|
+
properties: {
|
|
264
|
+
productId: {
|
|
265
|
+
type: 'number',
|
|
266
|
+
description: 'ID of the product to open. Use inventory_products_lookup to find the product ID by name (or inventory_products_get with fields if listing products).',
|
|
267
|
+
},
|
|
268
|
+
amount: {
|
|
269
|
+
type: 'number',
|
|
270
|
+
description: "Amount to mark as opened in the product's stock unit (e.g., 1 piece, 0.5 kg). Default: 1",
|
|
271
|
+
default: 1,
|
|
272
|
+
},
|
|
273
|
+
note: {
|
|
274
|
+
type: 'string',
|
|
275
|
+
description: 'Optional note for opening the product',
|
|
276
|
+
},
|
|
277
|
+
},
|
|
278
|
+
required: ['productId'],
|
|
279
|
+
},
|
|
280
|
+
},
|
|
281
|
+
{
|
|
282
|
+
name: 'inventory_products_lookup',
|
|
283
|
+
description: '[INVENTORY/PRODUCTS] Search for products by name using fuzzy matching. Returns up to 5 best matches with stock information and location details.',
|
|
284
|
+
annotations: { readOnlyHint: true },
|
|
285
|
+
inputSchema: {
|
|
286
|
+
type: 'object',
|
|
287
|
+
properties: {
|
|
288
|
+
productName: {
|
|
289
|
+
type: 'string',
|
|
290
|
+
description: 'Product name to search for. Uses fuzzy matching to find similar products.',
|
|
291
|
+
},
|
|
292
|
+
},
|
|
293
|
+
required: ['productName'],
|
|
294
|
+
},
|
|
295
|
+
},
|
|
296
|
+
{
|
|
297
|
+
name: 'inventory_products_print_label',
|
|
298
|
+
description: '[INVENTORY/PRODUCTS] Print a Grocycode label for a product. Use inventory_products_get to find valid productId values.',
|
|
299
|
+
inputSchema: {
|
|
300
|
+
type: 'object',
|
|
301
|
+
properties: {
|
|
302
|
+
productId: {
|
|
303
|
+
type: 'number',
|
|
304
|
+
description: 'ID of the product to print label for. Use inventory_products_get tool to find the correct product ID.',
|
|
305
|
+
},
|
|
306
|
+
},
|
|
307
|
+
required: ['productId'],
|
|
308
|
+
},
|
|
309
|
+
},
|
|
310
|
+
{
|
|
311
|
+
name: 'inventory_stock_entry_print_label',
|
|
312
|
+
description: '[INVENTORY/STOCK] Print a label for a specific stock entry. Use inventory_stock_get_by_product to find valid stockId values.',
|
|
313
|
+
inputSchema: {
|
|
314
|
+
type: 'object',
|
|
315
|
+
properties: {
|
|
316
|
+
stockId: {
|
|
317
|
+
type: 'number',
|
|
318
|
+
description: 'ID of the stock entry to print label for. Use inventory_stock_get_by_product to find stockId values.',
|
|
319
|
+
},
|
|
320
|
+
productId: {
|
|
321
|
+
type: 'number',
|
|
322
|
+
description: 'ID of the product that the stock entry belongs to. This is required for validation.',
|
|
323
|
+
},
|
|
324
|
+
},
|
|
325
|
+
required: ['stockId', 'productId'],
|
|
326
|
+
},
|
|
327
|
+
},
|
|
328
|
+
// ==================== GRANULAR STOCK ENTRY OPERATIONS ====================
|
|
329
|
+
{
|
|
330
|
+
name: 'inventory_stock_entry_consume',
|
|
331
|
+
description: '[INVENTORY/STOCK] **Specific stock row (stockId):** consume from one lot. If the user only names a product/amount without a particular package, use inventory_transactions_consume instead. Find stockId via inventory_stock_get_by_product.',
|
|
332
|
+
inputSchema: {
|
|
333
|
+
type: 'object',
|
|
334
|
+
properties: {
|
|
335
|
+
stockId: {
|
|
336
|
+
type: 'number',
|
|
337
|
+
description: 'ID of the specific stock entry to consume from.',
|
|
338
|
+
},
|
|
339
|
+
productId: {
|
|
340
|
+
type: 'number',
|
|
341
|
+
description: 'ID of the product being consumed. This is required for verification - if you know the stockId, you must know the productId.',
|
|
342
|
+
},
|
|
343
|
+
amount: {
|
|
344
|
+
type: 'number',
|
|
345
|
+
description: "Amount to consume in the product's stock unit (e.g., 1 piece, 0.5 kg, 250 ml). Ensure you know the product's stock unit before specifying amount.",
|
|
346
|
+
},
|
|
347
|
+
spoiled: {
|
|
348
|
+
type: 'boolean',
|
|
349
|
+
description: 'Whether the product is spoiled (default: false)',
|
|
350
|
+
default: false,
|
|
351
|
+
},
|
|
352
|
+
note: {
|
|
353
|
+
type: 'string',
|
|
354
|
+
description: 'Optional note',
|
|
355
|
+
},
|
|
356
|
+
},
|
|
357
|
+
required: ['stockId', 'productId', 'amount'],
|
|
358
|
+
},
|
|
359
|
+
},
|
|
360
|
+
{
|
|
361
|
+
name: 'inventory_stock_entry_transfer',
|
|
362
|
+
description: '[INVENTORY/STOCK] **Specific stock row (stockId):** move one lot to another location. For moving an amount of a product without picking a row, use inventory_transactions_transfer. Find stockId via inventory_stock_get_by_product.',
|
|
363
|
+
inputSchema: {
|
|
364
|
+
type: 'object',
|
|
365
|
+
properties: {
|
|
366
|
+
stockId: {
|
|
367
|
+
type: 'number',
|
|
368
|
+
description: 'ID of the specific stock entry to transfer.',
|
|
369
|
+
},
|
|
370
|
+
productId: {
|
|
371
|
+
type: 'number',
|
|
372
|
+
description: 'ID of the product being transferred. This is required for verification - if you know the stockId, you must know the productId.',
|
|
373
|
+
},
|
|
374
|
+
amount: {
|
|
375
|
+
type: 'number',
|
|
376
|
+
description: "Amount to transfer in the product's stock unit (e.g., 1 piece, 0.5 kg, 250 ml). Ensure you know the product's stock unit before specifying amount.",
|
|
377
|
+
},
|
|
378
|
+
locationIdTo: {
|
|
379
|
+
type: 'number',
|
|
380
|
+
description: 'ID of the destination location.',
|
|
381
|
+
},
|
|
382
|
+
note: {
|
|
383
|
+
type: 'string',
|
|
384
|
+
description: 'Optional note for this transfer',
|
|
385
|
+
},
|
|
386
|
+
},
|
|
387
|
+
required: ['stockId', 'productId', 'amount', 'locationIdTo'],
|
|
388
|
+
},
|
|
389
|
+
},
|
|
390
|
+
{
|
|
391
|
+
name: 'inventory_stock_entry_open',
|
|
392
|
+
description: '[INVENTORY/STOCK] **Specific stock row (stockId):** mark one opened package. For product-level open without a row, use inventory_transactions_open. Find stockId via inventory_stock_get_by_product.',
|
|
393
|
+
inputSchema: {
|
|
394
|
+
type: 'object',
|
|
395
|
+
properties: {
|
|
396
|
+
stockId: {
|
|
397
|
+
type: 'number',
|
|
398
|
+
description: 'ID of the specific stock entry to mark as opened.',
|
|
399
|
+
},
|
|
400
|
+
productId: {
|
|
401
|
+
type: 'number',
|
|
402
|
+
description: 'ID of the product being opened. This is required for verification - if you know the stockId, you must know the productId.',
|
|
403
|
+
},
|
|
404
|
+
amount: {
|
|
405
|
+
type: 'number',
|
|
406
|
+
description: "Amount to mark as opened in the product's stock unit (e.g., 1 piece, 0.5 kg, 200 ml). Ensure you know the product's stock unit before specifying amount.",
|
|
407
|
+
},
|
|
408
|
+
note: {
|
|
409
|
+
type: 'string',
|
|
410
|
+
description: 'Optional note',
|
|
411
|
+
},
|
|
412
|
+
},
|
|
413
|
+
required: ['stockId', 'productId', 'amount'],
|
|
414
|
+
},
|
|
415
|
+
},
|
|
416
|
+
];
|