shopify_sdk/rest/resources/v2025_10/
inventory_item.rs1use chrono::{DateTime, Utc};
39use serde::{Deserialize, Serialize};
40
41use crate::rest::{ResourceOperation, ResourcePath, RestResource};
42use crate::HttpMethod;
43
44#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
49pub struct CountryHarmonizedSystemCode {
50 #[serde(skip_serializing_if = "Option::is_none")]
52 pub harmonized_system_code: Option<String>,
53
54 #[serde(skip_serializing_if = "Option::is_none")]
56 pub country_code: Option<String>,
57}
58
59#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
89pub struct InventoryItem {
90 #[serde(skip_serializing)]
93 pub id: Option<u64>,
94
95 #[serde(skip_serializing_if = "Option::is_none")]
97 pub sku: Option<String>,
98
99 #[serde(skip_serializing_if = "Option::is_none")]
102 pub cost: Option<String>,
103
104 #[serde(skip_serializing)]
107 pub created_at: Option<DateTime<Utc>>,
108
109 #[serde(skip_serializing)]
112 pub updated_at: Option<DateTime<Utc>>,
113
114 #[serde(skip_serializing)]
117 pub requires_shipping: Option<bool>,
118
119 #[serde(skip_serializing_if = "Option::is_none")]
121 pub tracked: Option<bool>,
122
123 #[serde(skip_serializing_if = "Option::is_none")]
125 pub country_code_of_origin: Option<String>,
126
127 #[serde(skip_serializing_if = "Option::is_none")]
129 pub province_code_of_origin: Option<String>,
130
131 #[serde(skip_serializing_if = "Option::is_none")]
133 pub harmonized_system_code: Option<String>,
134
135 #[serde(skip_serializing_if = "Option::is_none")]
137 pub country_harmonized_system_codes: Option<Vec<CountryHarmonizedSystemCode>>,
138
139 #[serde(skip_serializing)]
142 pub admin_graphql_api_id: Option<String>,
143}
144
145impl RestResource for InventoryItem {
146 type Id = u64;
147 type FindParams = InventoryItemFindParams;
148 type AllParams = InventoryItemListParams;
149 type CountParams = ();
150
151 const NAME: &'static str = "InventoryItem";
152 const PLURAL: &'static str = "inventory_items";
153
154 const PATHS: &'static [ResourcePath] = &[
164 ResourcePath::new(
165 HttpMethod::Get,
166 ResourceOperation::Find,
167 &["id"],
168 "inventory_items/{id}",
169 ),
170 ResourcePath::new(
171 HttpMethod::Get,
172 ResourceOperation::All,
173 &[],
174 "inventory_items",
175 ),
176 ResourcePath::new(
177 HttpMethod::Put,
178 ResourceOperation::Update,
179 &["id"],
180 "inventory_items/{id}",
181 ),
182 ];
183
184 fn get_id(&self) -> Option<Self::Id> {
185 self.id
186 }
187}
188
189#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
191pub struct InventoryItemFindParams {
192 }
194
195#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
213pub struct InventoryItemListParams {
214 #[serde(skip_serializing_if = "Option::is_none")]
217 pub ids: Option<Vec<u64>>,
218
219 #[serde(skip_serializing_if = "Option::is_none")]
221 pub limit: Option<u32>,
222
223 #[serde(skip_serializing_if = "Option::is_none")]
225 pub page_info: Option<String>,
226}
227
228#[cfg(test)]
229mod tests {
230 use super::*;
231 use crate::rest::{get_path, ResourceOperation};
232
233 #[test]
234 fn test_inventory_item_struct_serialization() {
235 let item = InventoryItem {
236 id: Some(12345), sku: Some("SKU-001".to_string()),
238 cost: Some("15.99".to_string()),
239 created_at: Some(
240 DateTime::parse_from_rfc3339("2024-01-15T10:30:00Z")
241 .unwrap()
242 .with_timezone(&Utc),
243 ), updated_at: Some(
245 DateTime::parse_from_rfc3339("2024-06-20T15:45:00Z")
246 .unwrap()
247 .with_timezone(&Utc),
248 ), requires_shipping: Some(true), tracked: Some(true),
251 country_code_of_origin: Some("US".to_string()),
252 province_code_of_origin: Some("CA".to_string()),
253 harmonized_system_code: Some("6109.10".to_string()),
254 country_harmonized_system_codes: Some(vec![CountryHarmonizedSystemCode {
255 harmonized_system_code: Some("6109.10.0000".to_string()),
256 country_code: Some("CA".to_string()),
257 }]),
258 admin_graphql_api_id: Some("gid://shopify/InventoryItem/12345".to_string()), };
260
261 let json = serde_json::to_string(&item).unwrap();
262 let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
263
264 assert_eq!(parsed["sku"], "SKU-001");
266 assert_eq!(parsed["cost"], "15.99");
267 assert_eq!(parsed["tracked"], true);
268 assert_eq!(parsed["country_code_of_origin"], "US");
269 assert_eq!(parsed["province_code_of_origin"], "CA");
270 assert_eq!(parsed["harmonized_system_code"], "6109.10");
271
272 assert!(parsed.get("id").is_none());
274 assert!(parsed.get("created_at").is_none());
275 assert!(parsed.get("updated_at").is_none());
276 assert!(parsed.get("requires_shipping").is_none());
277 assert!(parsed.get("admin_graphql_api_id").is_none());
278
279 let codes = parsed["country_harmonized_system_codes"]
281 .as_array()
282 .unwrap();
283 assert_eq!(codes.len(), 1);
284 assert_eq!(codes[0]["harmonized_system_code"], "6109.10.0000");
285 assert_eq!(codes[0]["country_code"], "CA");
286 }
287
288 #[test]
289 fn test_inventory_item_deserialization() {
290 let json = r#"{
291 "id": 808950810,
292 "sku": "IPOD-342-N",
293 "cost": "25.00",
294 "created_at": "2024-01-15T10:30:00Z",
295 "updated_at": "2024-06-20T15:45:00Z",
296 "requires_shipping": true,
297 "tracked": true,
298 "country_code_of_origin": "US",
299 "province_code_of_origin": "CA",
300 "harmonized_system_code": "8523.29.90",
301 "country_harmonized_system_codes": [
302 {
303 "harmonized_system_code": "8523.29.9000",
304 "country_code": "CA"
305 },
306 {
307 "harmonized_system_code": "8523.29.9090",
308 "country_code": "GB"
309 }
310 ],
311 "admin_graphql_api_id": "gid://shopify/InventoryItem/808950810"
312 }"#;
313
314 let item: InventoryItem = serde_json::from_str(json).unwrap();
315
316 assert_eq!(item.id, Some(808950810));
318 assert_eq!(item.sku, Some("IPOD-342-N".to_string()));
319 assert_eq!(item.cost, Some("25.00".to_string()));
320 assert!(item.created_at.is_some());
321 assert!(item.updated_at.is_some());
322 assert_eq!(item.requires_shipping, Some(true));
323 assert_eq!(item.tracked, Some(true));
324 assert_eq!(item.country_code_of_origin, Some("US".to_string()));
325 assert_eq!(item.province_code_of_origin, Some("CA".to_string()));
326 assert_eq!(item.harmonized_system_code, Some("8523.29.90".to_string()));
327 assert_eq!(
328 item.admin_graphql_api_id,
329 Some("gid://shopify/InventoryItem/808950810".to_string())
330 );
331
332 let codes = item.country_harmonized_system_codes.unwrap();
334 assert_eq!(codes.len(), 2);
335 assert_eq!(
336 codes[0].harmonized_system_code,
337 Some("8523.29.9000".to_string())
338 );
339 assert_eq!(codes[0].country_code, Some("CA".to_string()));
340 assert_eq!(
341 codes[1].harmonized_system_code,
342 Some("8523.29.9090".to_string())
343 );
344 assert_eq!(codes[1].country_code, Some("GB".to_string()));
345 }
346
347 #[test]
348 fn test_inventory_item_list_params_with_ids() {
349 let params = InventoryItemListParams {
350 ids: Some(vec![808950810, 808950811, 808950812]),
351 limit: Some(50),
352 page_info: None,
353 };
354
355 let json = serde_json::to_value(¶ms).unwrap();
356
357 assert_eq!(
359 json["ids"],
360 serde_json::json!([808950810, 808950811, 808950812])
361 );
362 assert_eq!(json["limit"], 50);
363
364 assert!(json.get("page_info").is_none());
366
367 let empty_params = InventoryItemListParams::default();
369 let empty_json = serde_json::to_value(&empty_params).unwrap();
370 assert_eq!(empty_json, serde_json::json!({}));
371 }
372
373 #[test]
374 fn test_inventory_item_get_id_returns_correct_value() {
375 let item_with_id = InventoryItem {
377 id: Some(808950810),
378 sku: Some("TEST-SKU".to_string()),
379 ..Default::default()
380 };
381 assert_eq!(item_with_id.get_id(), Some(808950810));
382
383 let item_without_id = InventoryItem {
385 id: None,
386 sku: Some("NEW-SKU".to_string()),
387 ..Default::default()
388 };
389 assert_eq!(item_without_id.get_id(), None);
390
391 assert_eq!(InventoryItem::NAME, "InventoryItem");
393 assert_eq!(InventoryItem::PLURAL, "inventory_items");
394 }
395
396 #[test]
397 fn test_inventory_item_path_constants_are_correct() {
398 let find_path = get_path(InventoryItem::PATHS, ResourceOperation::Find, &["id"]);
400 assert!(find_path.is_some());
401 assert_eq!(find_path.unwrap().template, "inventory_items/{id}");
402 assert_eq!(find_path.unwrap().http_method, HttpMethod::Get);
403
404 let all_path = get_path(InventoryItem::PATHS, ResourceOperation::All, &[]);
406 assert!(all_path.is_some());
407 assert_eq!(all_path.unwrap().template, "inventory_items");
408 assert_eq!(all_path.unwrap().http_method, HttpMethod::Get);
409
410 let update_path = get_path(InventoryItem::PATHS, ResourceOperation::Update, &["id"]);
412 assert!(update_path.is_some());
413 assert_eq!(update_path.unwrap().template, "inventory_items/{id}");
414 assert_eq!(update_path.unwrap().http_method, HttpMethod::Put);
415
416 let create_path = get_path(InventoryItem::PATHS, ResourceOperation::Create, &[]);
418 assert!(create_path.is_none());
419
420 let delete_path = get_path(InventoryItem::PATHS, ResourceOperation::Delete, &["id"]);
422 assert!(delete_path.is_none());
423
424 let count_path = get_path(InventoryItem::PATHS, ResourceOperation::Count, &[]);
426 assert!(count_path.is_none());
427 }
428
429 #[test]
430 fn test_country_harmonized_system_code_struct() {
431 let code = CountryHarmonizedSystemCode {
432 harmonized_system_code: Some("8523.29.9000".to_string()),
433 country_code: Some("CA".to_string()),
434 };
435
436 let json = serde_json::to_value(&code).unwrap();
438 assert_eq!(json["harmonized_system_code"], "8523.29.9000");
439 assert_eq!(json["country_code"], "CA");
440
441 let json_str = r#"{"harmonized_system_code": "1234.56.7890", "country_code": "US"}"#;
443 let parsed: CountryHarmonizedSystemCode = serde_json::from_str(json_str).unwrap();
444 assert_eq!(
445 parsed.harmonized_system_code,
446 Some("1234.56.7890".to_string())
447 );
448 assert_eq!(parsed.country_code, Some("US".to_string()));
449
450 let empty_code = CountryHarmonizedSystemCode::default();
452 let empty_json = serde_json::to_value(&empty_code).unwrap();
453 assert_eq!(empty_json, serde_json::json!({}));
454 }
455}