From 07a4d583c7f4d10bf4c813d54dba8fc5f3aa81fc Mon Sep 17 00:00:00 2001 From: Ryan Ruckley Date: Thu, 15 Aug 2024 13:56:37 +1000 Subject: [PATCH 01/40] line not needed --- examples/create_customer.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/examples/create_customer.rs b/examples/create_customer.rs index 9c874ebf..e322d313 100644 --- a/examples/create_customer.rs +++ b/examples/create_customer.rs @@ -17,6 +17,4 @@ fn main() { customer.upgrade_to_code(None); dbg!(customer); - - // println!("Customer Code: {}",customer.get_characteristic("code").unwrap().value); } \ No newline at end of file From d0076530ccc30710473cdae33d0e846dc82e0503 Mon Sep 17 00:00:00 2001 From: Ryan Ruckley Date: Thu, 15 Aug 2024 14:00:11 +1000 Subject: [PATCH 02/40] removed --- examples/create_work_order.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/examples/create_work_order.rs b/examples/create_work_order.rs index b38f461b..6446b301 100644 --- a/examples/create_work_order.rs +++ b/examples/create_work_order.rs @@ -30,7 +30,5 @@ fn main() { wo.add_item(woi); - // dbg!(wo); - let json = serde_json::to_string(&wo).unwrap(); - println!("JSON>>\n{}\n< Date: Thu, 15 Aug 2024 14:01:33 +1000 Subject: [PATCH 03/40] Use trait functions --- examples/service_to_product.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/service_to_product.rs b/examples/service_to_product.rs index eac1d203..257e5770 100644 --- a/examples/service_to_product.rs +++ b/examples/service_to_product.rs @@ -14,6 +14,7 @@ use tmflib::tmf632::individual_v5::Individual; use tmflib::common::note::Note; use tmflib::common::related_party::RelatedParty; use tmflib::tmf641::service_order_item::{ServiceOrderItem,ServiceRefOrValue}; +use tmflib::HasNote; fn main() { let mut ss = ServiceSpecification::new("Access"); @@ -45,7 +46,7 @@ fn main() { // Create new ServiceOrder let mut so = ServiceOrder::new(); // Add a sample note - so.note.as_mut().unwrap().push(Note::new("This is a Note.")); + so.add_note(Note::new("This is a Note.")); // Create a related party let ind = Individual::new("John Q. Citizen"); // Add related party reference to ServiceOrder From c35d8da20c298cd7a6a90602bc87f75b1bfba5ba Mon Sep 17 00:00:00 2001 From: Ryan Ruckley Date: Thu, 15 Aug 2024 14:04:02 +1000 Subject: [PATCH 04/40] Add HasRelatedParty trait --- src/tmf641/service_order.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tmf641/service_order.rs b/src/tmf641/service_order.rs index d8760432..46d7ad42 100644 --- a/src/tmf641/service_order.rs +++ b/src/tmf641/service_order.rs @@ -3,8 +3,8 @@ use serde::{Deserialize, Serialize}; // URL Path components use crate::LIB_PATH; use super::MOD_PATH; -use crate::{HasId,HasNote,DateTime}; -use tmflib_derive::{HasId,HasNote}; +use crate::{HasId,HasNote,HasRelatedParty,DateTime}; +use tmflib_derive::{HasId,HasNote,HasRelatedParty}; use crate::common::note::Note; use super::service_order_item::ServiceOrderItem; use crate::common::related_party::RelatedParty; @@ -40,7 +40,7 @@ pub enum ServiceOrderStateType { } /// Service Order Object -#[derive(Clone, Debug, Default, Deserialize, HasId, HasNote, Serialize)] +#[derive(Clone, Debug, Default, Deserialize, HasId, HasNote, HasRelatedParty, Serialize)] #[serde(rename_all = "camelCase")] pub struct ServiceOrder { /// Cancellation Date From ec3f57f491703a328e5056d6d43d9fc08c0db410 Mon Sep 17 00:00:00 2001 From: Ryan Ruckley Date: Thu, 15 Aug 2024 14:07:22 +1000 Subject: [PATCH 05/40] Use trait functions --- examples/service_to_product.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/service_to_product.rs b/examples/service_to_product.rs index 257e5770..2fc5f8ea 100644 --- a/examples/service_to_product.rs +++ b/examples/service_to_product.rs @@ -14,7 +14,7 @@ use tmflib::tmf632::individual_v5::Individual; use tmflib::common::note::Note; use tmflib::common::related_party::RelatedParty; use tmflib::tmf641::service_order_item::{ServiceOrderItem,ServiceRefOrValue}; -use tmflib::HasNote; +use tmflib::{HasRelatedParty,HasNote}; fn main() { let mut ss = ServiceSpecification::new("Access"); @@ -50,7 +50,8 @@ fn main() { // Create a related party let ind = Individual::new("John Q. Citizen"); // Add related party reference to ServiceOrder - so.related_party.as_mut().unwrap().push(RelatedParty::from(&ind)); + // This should use trait functions to add a party. + so.add_party(RelatedParty::from(&ind)); // Set the Category so.category = Some("Fixed Product".to_string()); // Set the external Id From b6bb218a1b7b912faa27471719a1c0510f84441c Mon Sep 17 00:00:00 2001 From: Ryan Ruckley Date: Thu, 15 Aug 2024 14:14:56 +1000 Subject: [PATCH 06/40] new fn add_item() to safely add order items --- src/tmf641/service_order.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/tmf641/service_order.rs b/src/tmf641/service_order.rs index 46d7ad42..d21ff19f 100644 --- a/src/tmf641/service_order.rs +++ b/src/tmf641/service_order.rs @@ -94,7 +94,7 @@ pub struct ServiceOrder { pub note: Option>, /// Service Order Items #[serde(skip_serializing_if = "Option::is_none")] - pub servce_order_item: Option>, + pub service_order_item: Option>, /// Related Parties #[serde(skip_serializing_if = "Option::is_none")] pub related_party : Option>, @@ -106,9 +106,16 @@ impl ServiceOrder { let mut so = ServiceOrder::create(); so.note = Some(vec![]); so.related_party = Some(vec![]); - so.servce_order_item = Some(vec![]); so } + + /// Safely add a new [ServiceOrderItem] to this ServiceOrder + pub fn add_item(&mut self, item: ServiceOrderItem) { + match self.service_order_item.as_mut() { + Some(v) => v.push(item), + None => self.service_order_item = Some(vec![item]), + } + } } #[cfg(test)] From 021beee382d19950e71914662cfcecd0b3360ff2 Mon Sep 17 00:00:00 2001 From: Ryan Ruckley Date: Thu, 15 Aug 2024 14:15:10 +1000 Subject: [PATCH 07/40] use new add_item() fn --- examples/service_to_product.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/service_to_product.rs b/examples/service_to_product.rs index 2fc5f8ea..fd838f49 100644 --- a/examples/service_to_product.rs +++ b/examples/service_to_product.rs @@ -57,7 +57,8 @@ fn main() { // Set the external Id so.external_id = Some("PON1234983".to_string()); // Add sample Service Order Item - so.servce_order_item.as_mut().unwrap().push(soi); + // This should use an add_item() function + so.add_item(soi); // Now transform the Service Order into a Product Order for downstream parties let po = ProductOrder::from(so); From e568442f4b821f2db157dd3b6fcf50f9a0dfb929 Mon Sep 17 00:00:00 2001 From: Ryan Ruckley Date: Thu, 15 Aug 2024 14:15:23 +1000 Subject: [PATCH 08/40] Fix typo --- src/tmf622/product_order_v4.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tmf622/product_order_v4.rs b/src/tmf622/product_order_v4.rs index 91462246..6717b877 100644 --- a/src/tmf622/product_order_v4.rs +++ b/src/tmf622/product_order_v4.rs @@ -165,7 +165,7 @@ impl From for ProductOrder { po.expected_completion_date.clone_from(&value.expected_completion_date); // Iterate through service order items - let items = match value.servce_order_item { + let items = match value.service_order_item { Some(i) => { let mut out = vec![]; i.into_iter().for_each(|i| { From 1585d74b239641bb3a7288b7fe444cc4a4a8a6c5 Mon Sep 17 00:00:00 2001 From: Ryan Ruckley Date: Thu, 15 Aug 2024 16:04:33 +1000 Subject: [PATCH 09/40] safely unwrap --- examples/validate_customer_code.rs | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/examples/validate_customer_code.rs b/examples/validate_customer_code.rs index 9332470c..11f872f8 100644 --- a/examples/validate_customer_code.rs +++ b/examples/validate_customer_code.rs @@ -2,7 +2,7 @@ //! use tmflib::{tmf629::customer::Customer, HasName,HasId}; -fn main() { +fn main() -> Result<(),String> { let mut cust1 = Customer::default(); @@ -10,17 +10,19 @@ fn main() { cust1.id = Some(String::from("123456")); cust1.generate_code(None); - let code1 = cust1.get_characteristic("code"); - let hash = cust1.get_characteristic("hash"); + let code1 = cust1.get_characteristic("code").ok_or(String::from("No Value"))?; + let hash = cust1.get_characteristic("hash").ok_or(String::from("No Value"))?; - println!("Customer: {} + ID: {} Offset=0\t generates Code: {}",cust1.get_name(),cust1.get_id(),code1.unwrap().value); - println!("Customer: {},\tBase32: {}",cust1.get_name(),hash.unwrap().value); + println!("Customer: {} + ID: {} Offset=0\t generates Code: {}",cust1.get_name(),cust1.get_id(),code1.value); + println!("Customer: {},\tBase32: {}",cust1.get_name(),hash.value); cust1.generate_code(Some(1)); - let code1 = cust1.get_characteristic("code"); - let hash = cust1.get_characteristic("hash"); + let code1 = cust1.get_characteristic("code").ok_or(String::from("No Value"))?; + let hash = cust1.get_characteristic("hash").ok_or(String::from("No Value"))?; - println!("Customer: {} + ID: {} Offset=1\t generates Code: {}",cust1.get_name(),cust1.get_id(),code1.unwrap().value); - println!("Customer: {},\tBase32: {}",cust1.get_name(),hash.unwrap().value); + println!("Customer: {} + ID: {} Offset=1\t generates Code: {}",cust1.get_name(),cust1.get_id(),code1.value); + println!("Customer: {},\tBase32: {}",cust1.get_name(),hash.value); + + Ok(()) } \ No newline at end of file From cf485a30840f72821801dea2732c0803908b6526 Mon Sep 17 00:00:00 2001 From: Ryan Ruckley Date: Thu, 15 Aug 2024 16:05:50 +1000 Subject: [PATCH 10/40] Convert to expect --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index be90f47e..146fcd3c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -74,7 +74,7 @@ impl TimePeriod { /// Calculate period `days` into the future pub fn period_days(days : u64) -> TimePeriod { let now = Utc::now() + Days::new(days); - let time = chrono::DateTime::from_timestamp(now.timestamp(),0).unwrap(); + let time = chrono::DateTime::from_timestamp(now.timestamp(),0).expect("Invalid now() output"); TimePeriod { end_date_time: Some(time.to_rfc3339()), ..Default::default() From 6747aa8de8ac07547422255ceca27b7a8427d344 Mon Sep 17 00:00:00 2001 From: Ryan Ruckley Date: Thu, 15 Aug 2024 17:27:17 +1000 Subject: [PATCH 11/40] use Trait functions --- src/common/related_party.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/common/related_party.rs b/src/common/related_party.rs index 8793554b..0e264fbf 100644 --- a/src/common/related_party.rs +++ b/src/common/related_party.rs @@ -58,8 +58,8 @@ pub struct RelatedParty { impl From<&Customer> for RelatedParty { fn from(cust: &Customer) -> Self { RelatedParty { - id: cust.id.as_ref().unwrap().clone(), - href: cust.href.as_ref().unwrap().clone(), + id: cust.get_id(), + href: cust.get_href(), name: cust.name.clone(), role: Some(Customer::get_class()), base_type: Some(Customer::get_class()), From d161027448e7ff968ab86dbca646f4d040a3a2db Mon Sep 17 00:00:00 2001 From: Ryan Ruckley Date: Thu, 15 Aug 2024 17:27:35 +1000 Subject: [PATCH 12/40] use expect() --- src/tmf620/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/tmf620/mod.rs b/src/tmf620/mod.rs index 085b1e68..e1b9ed03 100644 --- a/src/tmf620/mod.rs +++ b/src/tmf620/mod.rs @@ -94,22 +94,22 @@ mod test { #[test] fn test_channelref_deserialize() { - let _channelref : ChannelRef = serde_json::from_str(EMPTY_JSON).unwrap(); + let _channelref : ChannelRef = serde_json::from_str(EMPTY_JSON).expect("Could not parse Empty JSON"); } #[test] fn test_marketsegmentref_deserialize() { - let _marketsegmentref : MarketSegmentRef = serde_json::from_str(EMPTY_JSON).unwrap(); + let _marketsegmentref : MarketSegmentRef = serde_json::from_str(EMPTY_JSON).expect("Could not parse Emoty JSON"); } #[test] fn test_placeref_deserialize() { - let _placeref : PlaceRef = serde_json::from_str(EMPTY_JSON).unwrap(); + let _placeref : PlaceRef = serde_json::from_str(EMPTY_JSON).expect("Could not parse Emoty JSON"); } #[test] fn test_slafef_deserialize() { - let _slaref : SLARef = serde_json::from_str(EMPTY_JSON).unwrap(); + let _slaref : SLARef = serde_json::from_str(EMPTY_JSON).expect("Could not parse Emoty JSON") } } From 2c494045dcfda204fd0d20d823b07c0396df3226 Mon Sep 17 00:00:00 2001 From: Ryan Ruckley Date: Thu, 15 Aug 2024 17:28:00 +1000 Subject: [PATCH 13/40] Use expect() --- src/common/attachment.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/common/attachment.rs b/src/common/attachment.rs index ad0fab4b..84fa041f 100644 --- a/src/common/attachment.rs +++ b/src/common/attachment.rs @@ -127,14 +127,14 @@ mod test { #[test] fn test_attachmenttype_deserialize() { - let attach_type : AttachmentType = serde_json::from_str(ATTACH_TYPE_JSON).unwrap(); + let attach_type : AttachmentType = serde_json::from_str(ATTACH_TYPE_JSON).expect("Could not parse test json"); assert_eq!(attach_type,AttachmentType::InLine); } #[test] fn test_attachmentsize_deserialize() { - let attach_size : AttachmentSize = serde_json::from_str(ATTACH_SIZE).unwrap(); + let attach_size : AttachmentSize = serde_json::from_str(ATTACH_SIZE).expect("Could not parse test json"); assert_eq!(attach_size.amount,123.4); assert_eq!(attach_size.units.as_str(),"bytes"); From bbabd9d0a28c262a38b051b4123d92e68969412d Mon Sep 17 00:00:00 2001 From: Ryan Ruckley Date: Thu, 15 Aug 2024 17:28:23 +1000 Subject: [PATCH 14/40] use expect() --- src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 146fcd3c..6d167a78 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -84,7 +84,7 @@ impl TimePeriod { pub fn started(&self) -> bool { let now = Utc::now(); - let start = chrono::DateTime::parse_from_rfc3339(&self.start_date_time).unwrap(); + let start = chrono::DateTime::parse_from_rfc3339(&self.start_date_time).expect("Could not start parse time from now()"); // Start is in the past, return true if start < now { return true @@ -96,7 +96,7 @@ impl TimePeriod { match &self.end_date_time { Some(f) => { let now = Utc::now(); - let finish = chrono::DateTime::parse_from_rfc3339(f).unwrap(); + let finish = chrono::DateTime::parse_from_rfc3339(f).expect("Could not parse finish time from now()"); if finish < now { return true } @@ -452,7 +452,7 @@ mod test { #[test] fn test_quantity_deserialize() { - let quantity : Quantity = serde_json::from_str(QUANTITY_JSON).unwrap(); + let quantity : Quantity = serde_json::from_str(QUANTITY_JSON).expect("Could not parse Quantity JSON"); assert_eq!(quantity.amount,12.34); assert_eq!(quantity.units.as_str(),"units"); @@ -460,7 +460,7 @@ mod test { #[test] fn test_timeperiod_deserialize() { - let period : TimePeriod = serde_json::from_str(PERIOD_JSON).unwrap(); + let period : TimePeriod = serde_json::from_str(PERIOD_JSON).expect("Could not parse Period JSON"); assert_eq!(period.start_date_time.as_str(),"2024-07-29T23:07:57Z"); assert_eq!(period.end_date_time.is_none(),true); From a128789c75ffa442b437435f4906a347bfac553d Mon Sep 17 00:00:00 2001 From: Ryan Ruckley Date: Thu, 15 Aug 2024 17:33:52 +1000 Subject: [PATCH 15/40] clean up logic. --- src/tmf620/category.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/tmf620/category.rs b/src/tmf620/category.rs index 9e1ddc75..50c7093b 100644 --- a/src/tmf620/category.rs +++ b/src/tmf620/category.rs @@ -133,11 +133,13 @@ impl Category { /// .is_root(true); /// ``` pub fn is_root(mut self, root: bool) -> Category { - self.is_root = Some(root); - if self.is_root.unwrap() { - // Remove parent + + // Two steps 1) delete parent if root= true + // update is_root + if root { self.parent_id = None; - } + }; + self.is_root = Some(root); self } } From d62efa091444514101d349aa702ca1fc68ae5bab Mon Sep 17 00:00:00 2001 From: Ryan Ruckley Date: Thu, 15 Aug 2024 17:34:03 +1000 Subject: [PATCH 16/40] use expect() --- src/tmf620/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tmf620/mod.rs b/src/tmf620/mod.rs index e1b9ed03..9ced7618 100644 --- a/src/tmf620/mod.rs +++ b/src/tmf620/mod.rs @@ -109,7 +109,7 @@ mod test { #[test] fn test_slafef_deserialize() { - let _slaref : SLARef = serde_json::from_str(EMPTY_JSON).expect("Could not parse Emoty JSON") + let _slaref : SLARef = serde_json::from_str(EMPTY_JSON).expect("Could not parse Emoty JSON"); } } From 4b79d15a8108d9b25c8a8f77cd95d80a1ea315ba Mon Sep 17 00:00:00 2001 From: Ryan Ruckley Date: Thu, 15 Aug 2024 17:44:24 +1000 Subject: [PATCH 17/40] Use Trait functions --- examples/cart_to_order.rs | 1 + examples/create_catalog.rs | 1 + examples/create_shopping_cart.rs | 1 + src/tmf620/catalog.rs | 19 +++++++++---------- src/tmf622/product_order_v4.rs | 2 +- src/tmf622/product_order_v5.rs | 20 +------------------- src/tmf632/individual_v4.rs | 13 ++++++------- src/tmf632/individual_v5.rs | 15 +++++++-------- src/tmf663/shopping_cart.rs | 10 +++------- src/tmf699/sales_opportunity_item_v5.rs | 8 +++++--- 10 files changed, 35 insertions(+), 55 deletions(-) diff --git a/examples/cart_to_order.rs b/examples/cart_to_order.rs index abb32d9a..d54b1250 100644 --- a/examples/cart_to_order.rs +++ b/examples/cart_to_order.rs @@ -1,4 +1,5 @@ //! Shopping Cart to Product Order +use tmflib::HasRelatedParty; use tmflib::common::related_party::RelatedParty; use tmflib::common::note::Note; #[cfg(feature = "tmf620-v4")] diff --git a/examples/create_catalog.rs b/examples/create_catalog.rs index d6ccaabd..5dbabde8 100644 --- a/examples/create_catalog.rs +++ b/examples/create_catalog.rs @@ -8,6 +8,7 @@ use tmflib::tmf632::organization_v4::Organization; #[cfg(feature = "tmf632-v5")] use tmflib::tmf632::organization_v5::Organization; use tmflib::tmf629::customer::Customer; +use tmflib::HasRelatedParty; fn main() { diff --git a/examples/create_shopping_cart.rs b/examples/create_shopping_cart.rs index 0bc926a6..82df6598 100644 --- a/examples/create_shopping_cart.rs +++ b/examples/create_shopping_cart.rs @@ -12,6 +12,7 @@ use tmflib::tmf632::individual_v4::Individual; use tmflib::tmf632::individual_v5::Individual; use tmflib::tmf663::shopping_cart::ShoppingCart; use tmflib::tmf663::cart_item::CartItem; +use tmflib::HasRelatedParty; fn main() { diff --git a/src/tmf620/catalog.rs b/src/tmf620/catalog.rs index 9e2ed24b..f31e6dea 100644 --- a/src/tmf620/catalog.rs +++ b/src/tmf620/catalog.rs @@ -5,7 +5,8 @@ use crate::{ HasId, HasName, HasLastUpdate, - HasValidity, + HasValidity, + HasRelatedParty, TimePeriod, DateTime, TMFEvent, @@ -15,7 +16,7 @@ use crate::{ use crate::tmf620::category::CategoryRef; use crate::common::related_party::RelatedParty; use crate::common::event::{Event,EventPayload}; -use tmflib_derive::{HasLastUpdate,HasId,HasName,HasValidity}; +use tmflib_derive::{HasLastUpdate,HasId,HasName,HasValidity,HasRelatedParty}; use chrono::Utc; use serde::{Deserialize, Serialize}; @@ -28,7 +29,7 @@ const CLASS_PATH: &str = "catalog"; const CAT_VERS: &str = "1.0"; /// Catalogue -#[derive(Clone, Default, Debug, Deserialize,HasLastUpdate, HasId, HasName, HasValidity, Serialize)] +#[derive(Clone, Default, Debug, Deserialize,HasLastUpdate, HasId, HasName, HasValidity, HasRelatedParty, Serialize)] #[serde(rename_all = "camelCase")] pub struct Catalog { /// Non-optional fields @@ -90,12 +91,10 @@ impl Catalog { /// Add a category to a catalog pub fn add_category(&mut self, category: CategoryRef) { - self.category.as_mut().unwrap().push(category); - } - - /// Add party to a catalog - pub fn add_party(&mut self, party : RelatedParty) { - self.related_party.as_mut().unwrap().push(party); + match self.category.as_mut() { + Some(v) => v.push(category), + None => self.category = Some(vec![category]), + } } } @@ -170,7 +169,7 @@ mod tests { use super::{Catalog, CatalogEvent, CatalogEventType}; use crate::tmf620::category::{Category, CategoryRef}; - use crate::{HasId,HasName, HasValidity,TimePeriod}; + use crate::{HasId,HasName, HasValidity,HasRelatedParty,TimePeriod}; const CAT_JSON : &str = "{ \"name\" : \"CatalogueName\", diff --git a/src/tmf622/product_order_v4.rs b/src/tmf622/product_order_v4.rs index 6717b877..6707627e 100644 --- a/src/tmf622/product_order_v4.rs +++ b/src/tmf622/product_order_v4.rs @@ -198,7 +198,7 @@ impl From for ProductOrder { // Bring across the related parties if value.related_party.is_some() { value.related_party.unwrap().into_iter().for_each(|rp| { - order.related_party.as_mut().unwrap().push(rp.clone()); + order.add_party(rp); }); } order diff --git a/src/tmf622/product_order_v5.rs b/src/tmf622/product_order_v5.rs index cf2ae621..58797543 100644 --- a/src/tmf622/product_order_v5.rs +++ b/src/tmf622/product_order_v5.rs @@ -133,24 +133,6 @@ impl ProductOrder { pub fn add_order_item(&mut self, order_item : ProductOrderItem) { self.product_order_item.as_mut().unwrap().push(order_item); } - - /// Add a RelatedParty into the ProductOrder - /// # Example - /// ``` - /// # use tmflib::tmf622::product_order_v5::ProductOrder; - /// use tmflib::common::related_party::RelatedParty; - /// use tmflib::tmf629::customer::Customer; - /// use tmflib::tmf632::organization_v5::Organization; - /// - /// let organization = Organization::new(String::from("My Customer")); - /// let customer = Customer::new(organization); - /// let mut order = ProductOrder::new(); - /// order.add_party(RelatedParty::from(&customer)); - /// dbg!(order); - /// ``` - pub fn add_party(&mut self, party: RelatedParty) { - self.related_party.as_mut().unwrap().push(party); - } } impl From for ProductOrder { @@ -204,7 +186,7 @@ impl From for ProductOrder { // Bring across the related parties if value.related_party.is_some() { value.related_party.unwrap().into_iter().for_each(|rp| { - order.related_party.as_mut().unwrap().push(rp.clone()); + order.add_party(rp); }); } order diff --git a/src/tmf632/individual_v4.rs b/src/tmf632/individual_v4.rs index 711fc980..bbad43ac 100644 --- a/src/tmf632/individual_v4.rs +++ b/src/tmf632/individual_v4.rs @@ -9,11 +9,15 @@ use serde::{Deserialize, Serialize}; use crate::{ HasId, HasName, + HasRelatedParty, DateTime, TMFEvent, gen_code, }; -use tmflib_derive::HasId; +use tmflib_derive::{ + HasId, + HasRelatedParty +}; use crate::LIB_PATH; use super::{ MOD_PATH, @@ -27,7 +31,7 @@ const CLASS_PATH : &str = "individual"; const CODE_PREFIX : &str = "I-"; /// An individual -#[derive(Clone, Debug, Default, Deserialize, HasId, Serialize)] +#[derive(Clone, Debug, Default, Deserialize, HasId, HasRelatedParty, Serialize)] #[serde(rename_all = "camelCase")] pub struct Individual { /// Unique id for this individual @@ -182,11 +186,6 @@ impl Individual { self } - /// Add a related party to the individual - pub fn add_party(&mut self, party : RelatedParty) { - self.related_party.as_mut().unwrap().push(party); - } - /// Add a contact medium to the individual pub fn add_contact(&mut self, medium : ContactMedium) { match self.contact_medium.as_mut() { diff --git a/src/tmf632/individual_v5.rs b/src/tmf632/individual_v5.rs index 0927e20c..3407a6de 100644 --- a/src/tmf632/individual_v5.rs +++ b/src/tmf632/individual_v5.rs @@ -8,14 +8,18 @@ use serde::{Deserialize, Serialize}; use crate::{ HasId, - HasName, + HasName, + HasRelatedParty, DateTime, TMFEvent, TimePeriod, LIB_PATH, gen_code }; -use tmflib_derive::HasId; +use tmflib_derive::{ + HasId, + HasRelatedParty +}; use super::{MOD_PATH,Characteristic}; use crate::common::related_party::RelatedParty; use crate::common::contact::ContactMedium; @@ -38,7 +42,7 @@ pub struct LanguageAbility { } /// An individual -#[derive(Clone, Debug, Default, Deserialize, HasId, Serialize)] +#[derive(Clone, Debug, Default, Deserialize, HasId, HasRelatedParty, Serialize)] #[serde(rename_all = "camelCase")] pub struct Individual { /// Unique id for this individual @@ -199,11 +203,6 @@ impl Individual { self } - /// Add a related party to the individual - pub fn add_party(&mut self, party : RelatedParty) { - self.related_party.as_mut().unwrap().push(party); - } - /// Add a contact medium to the individual pub fn add_contact(&mut self, medium : ContactMedium) { self.contact_medium.as_mut().unwrap().push(medium); diff --git a/src/tmf663/shopping_cart.rs b/src/tmf663/shopping_cart.rs index a1316d78..869c8a60 100644 --- a/src/tmf663/shopping_cart.rs +++ b/src/tmf663/shopping_cart.rs @@ -2,8 +2,8 @@ use serde::{Deserialize, Serialize}; -use crate::{HasId, LIB_PATH,HasValidity,TimePeriod}; -use tmflib_derive::{HasId,HasValidity}; +use crate::{HasId, LIB_PATH,HasValidity,HasRelatedParty,TimePeriod}; +use tmflib_derive::{HasId,HasValidity,HasRelatedParty}; use crate::common::contact::ContactMedium; use crate::common::related_party::RelatedParty; use crate::common::price::Price; @@ -27,7 +27,7 @@ pub struct CartPrice { } /// Shopping Cart -#[derive(Clone, Debug, Default, Deserialize, HasId,HasValidity, Serialize)] +#[derive(Clone, Debug, Default, Deserialize, HasId,HasValidity,HasRelatedParty, Serialize)] #[serde(rename_all = "camelCase")] pub struct ShoppingCart { /// Contact Medium @@ -68,10 +68,6 @@ impl ShoppingCart { pub fn add_item(&mut self, item : CartItem) { self.cart_item.as_mut().unwrap().push(item); } - /// Add Related Party - pub fn add_party(&mut self, party : RelatedParty) { - self.related_party.as_mut().unwrap().push(party); - } } #[cfg(test)] diff --git a/src/tmf699/sales_opportunity_item_v5.rs b/src/tmf699/sales_opportunity_item_v5.rs index 72573456..7d088d87 100644 --- a/src/tmf699/sales_opportunity_item_v5.rs +++ b/src/tmf699/sales_opportunity_item_v5.rs @@ -6,14 +6,16 @@ use crate::{common::{ money::Money, note::Note, related_party::RelatedParty -}, TimePeriod +}, TimePeriod, +HasRelatedParty, }; +use tmflib_derive::HasRelatedParty; use crate::tmf629::customer::Customer; use super::{sales_lead_v5::SalesLeadRef, sales_opportunity_v5::SalesOpportunityPriorityType}; /// Sales Opportunity Item -#[derive(Clone,Debug,Default,Deserialize,Serialize)] +#[derive(Clone,Debug,Default,Deserialize, HasRelatedParty, Serialize)] #[serde(rename_all = "camelCase")] pub struct SalesOpportunityItem { #[serde(skip_serializing_if = "Option::is_none")] @@ -42,7 +44,7 @@ impl SalesOpportunityItem { /// Add customer to opportunity item pub fn for_customer(mut self, cust : Customer) -> SalesOpportunityItem { - self.related_party.as_mut().unwrap().push(RelatedParty::from(&cust)); + self.add_party(RelatedParty::from(&cust)); self } } \ No newline at end of file From 3fe66d24da3f60daeccb325377cb906f3c6d0611 Mon Sep 17 00:00:00 2001 From: Ryan Ruckley Date: Fri, 16 Aug 2024 12:02:57 +1000 Subject: [PATCH 18/40] Use trait funcs. --- src/common/attachment.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/common/attachment.rs b/src/common/attachment.rs index 84fa041f..974a25e6 100644 --- a/src/common/attachment.rs +++ b/src/common/attachment.rs @@ -122,7 +122,7 @@ mod test { let attachment = AttachmentRefOrValue::from(&document); - assert_eq!(attachment.name.unwrap(),document.get_name()); + assert_eq!(attachment.get_name(),document.get_name()); } #[test] @@ -142,7 +142,7 @@ mod test { #[test] fn test_attach_deserialize() { - let _attach : AttachmentRefOrValue = serde_json::from_str(ATTACH_JSON).unwrap(); + let _attach : AttachmentRefOrValue = serde_json::from_str(ATTACH_JSON).expect("Could not parse attach JSON"); } From 8f6fa474ae747d4aa626c11cb84459f7f6ad817c Mon Sep 17 00:00:00 2001 From: Ryan Ruckley Date: Fri, 16 Aug 2024 12:04:14 +1000 Subject: [PATCH 19/40] use expect() --- src/common/contact.rs | 7 +++---- src/common/tax_item.rs | 3 ++- src/tmf632/mod.rs | 3 ++- src/tmf674/geographic_site_v4.rs | 3 ++- src/tmf679/product_qualification.rs | 3 ++- 5 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/common/contact.rs b/src/common/contact.rs index 72dc288d..7ba2c838 100644 --- a/src/common/contact.rs +++ b/src/common/contact.rs @@ -170,7 +170,6 @@ mod test { assert_eq!(email.medium_type.unwrap(),EMAIL_TYPE.to_string()); assert_eq!(email.characteristic.is_some(),true); assert_eq!(email.characteristic.unwrap().contact_type.unwrap(),EMAIL_TYPE.to_string()); - //assert_eq!(email.characteristic.unwrap().email_address.unwrap(),"test@example.com".to_string()); } #[test] @@ -195,10 +194,10 @@ mod test { let mediumchar: MediumCharacteristic = serde_json::from_str(MEDIUM_CHAR_JSON).unwrap(); assert_eq!(mediumchar.contact_type.is_some(),true); - assert_eq!(mediumchar.contact_type.unwrap().as_str(),"email"); + assert_eq!(mediumchar.contact_type.expect("Could not parse mediumchar JSON").as_str(),"email"); assert_eq!(mediumchar.email_address.is_some(),true); - assert_eq!(mediumchar.email_address.unwrap().as_str(),"john@example.com"); + assert_eq!(mediumchar.email_address.expect("Could not parse email_address JSON").as_str(),"john@example.com"); } #[test] @@ -223,6 +222,6 @@ mod test { let contact_char : ContactCharacteristic = serde_json::from_str(CONTACT_CHAR).unwrap(); assert_eq!(contact_char.email_address.is_some(),true); - assert_eq!(contact_char.email_address.unwrap().as_str(),"john@example.com"); + assert_eq!(contact_char.email_address.expect("Could not parse email_address JSON").as_str(),"john@example.com"); } } diff --git a/src/common/tax_item.rs b/src/common/tax_item.rs index 2feec2d5..55dd2491 100644 --- a/src/common/tax_item.rs +++ b/src/common/tax_item.rs @@ -24,7 +24,8 @@ mod test { #[test] fn test_taxitem_deserialise() { - let taxitem : TaxItem = serde_json::from_str(TAX_JSON).unwrap(); + let taxitem : TaxItem = serde_json::from_str(TAX_JSON) + .expect("Could not parase TAX_JSON"); assert_eq!(taxitem.tax_category.as_str(),"TaxCategory"); assert_eq!(taxitem.tax_rate,0.10); diff --git a/src/tmf632/mod.rs b/src/tmf632/mod.rs index 0a669d4b..5db2454a 100644 --- a/src/tmf632/mod.rs +++ b/src/tmf632/mod.rs @@ -59,7 +59,8 @@ mod test { #[test] fn test_characteristic_deserialise() { - let char : Characteristic = serde_json::from_str(CHAR_JSON).unwrap(); + let char : Characteristic = serde_json::from_str(CHAR_JSON) + .expect("Could not parse CHAR_JSON"); assert_eq!(char.name.as_str(),"name"); assert_eq!(char.name_type.as_str(),"NameType"); diff --git a/src/tmf674/geographic_site_v4.rs b/src/tmf674/geographic_site_v4.rs index c1e0fcb2..44d63479 100644 --- a/src/tmf674/geographic_site_v4.rs +++ b/src/tmf674/geographic_site_v4.rs @@ -307,7 +307,8 @@ mod test { #[test] fn test_placeref_deserialize() { - let placeref : PlaceRefOrValue = serde_json::from_str(PLACEREF_JSON).unwrap(); + let placeref : PlaceRefOrValue = serde_json::from_str(PLACEREF_JSON) + .expect("Cannot parse PLACEREF_JSON"); assert_eq!(placeref.id.as_str(),"P123"); assert_eq!(placeref.name.as_str(),"PlaceName"); diff --git a/src/tmf679/product_qualification.rs b/src/tmf679/product_qualification.rs index 48228127..df937349 100644 --- a/src/tmf679/product_qualification.rs +++ b/src/tmf679/product_qualification.rs @@ -73,7 +73,8 @@ mod test { #[test] fn test_poq_deserialize() { - let poq : ProductOfferingQualification = serde_json::from_str(POQ_JSON).unwrap(); + let poq : ProductOfferingQualification = serde_json::from_str(POQ_JSON) + .expect("Could not parse POQ JSON"); assert_eq!(poq.id.is_some(),true); assert_eq!(poq.get_id().as_str(),"POQ123"); From 4178b4f7c60711bbd2a10410605bbedbba7ab285 Mon Sep 17 00:00:00 2001 From: Ryan Ruckley Date: Fri, 16 Aug 2024 12:04:41 +1000 Subject: [PATCH 20/40] use trait funcs --- src/common/related_party.rs | 10 +++++----- src/tmf620/product_offering_price.rs | 2 +- src/tmf646/appointment.rs | 4 ++-- src/tmf666/billing_account.rs | 6 +++--- src/tmf687/product_stock.rs | 2 +- src/tmf699/sales_lead_v5.rs | 2 +- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/common/related_party.rs b/src/common/related_party.rs index 0e264fbf..e4b1fd26 100644 --- a/src/common/related_party.rs +++ b/src/common/related_party.rs @@ -118,9 +118,9 @@ impl From for RelatedParty { impl From<&Individual> for RelatedParty { fn from(value: &Individual) -> Self { RelatedParty { - id: value.id.as_ref().unwrap().clone(), - href: value.href.as_ref().unwrap().clone(), - name: value.full_name.clone(), + id: value.get_id(), + href: value.get_href(), + name: Some(value.get_name()), role: Some(Individual::get_class()), referred_type: Some(Individual::get_class()), base_type: Some(Individual::get_class()), @@ -135,8 +135,8 @@ impl From<&Individual> for RelatedParty { impl From<&PartyRole> for RelatedParty { fn from(value: &PartyRole) -> Self { RelatedParty { - id: value.id.as_ref().unwrap().clone(), - href: value.href.as_ref().unwrap().clone(), + id: value.get_id(), + href: value.get_href(), name: None, role: value.name.clone(), referred_type: Some(PartyRole::get_class()), diff --git a/src/tmf620/product_offering_price.rs b/src/tmf620/product_offering_price.rs index 2f8ad463..6d697408 100644 --- a/src/tmf620/product_offering_price.rs +++ b/src/tmf620/product_offering_price.rs @@ -47,7 +47,7 @@ impl From for ProductOfferingPriceRef { ProductOfferingPriceRef { id: pop.id.clone(), href: pop.href.clone(), - name: pop.name.as_ref().unwrap().clone(), + name: pop.get_name(), } } } diff --git a/src/tmf646/appointment.rs b/src/tmf646/appointment.rs index 21122793..4e6f3538 100644 --- a/src/tmf646/appointment.rs +++ b/src/tmf646/appointment.rs @@ -59,8 +59,8 @@ impl From for AppointmentRef { fn from(value: Appointment) -> Self { AppointmentRef { description: value.get_href(), - href: value.href.unwrap().clone(), - id: value.id.unwrap().clone(), + href: value.get_href(), + id: value.get_id(), } } } diff --git a/src/tmf666/billing_account.rs b/src/tmf666/billing_account.rs index 01852e2a..4e5a7541 100644 --- a/src/tmf666/billing_account.rs +++ b/src/tmf666/billing_account.rs @@ -100,9 +100,9 @@ pub struct BillingAccountRef { impl From for BillingAccountRef { fn from(value: BillingAccount) -> Self { BillingAccountRef { - id : value.id.unwrap_or_default(), - href : value.href.unwrap_or_default(), - name: value.name.unwrap_or_default(), + id : value.get_id(), + href : value.get_href(), + name: value.get_name(), } } } diff --git a/src/tmf687/product_stock.rs b/src/tmf687/product_stock.rs index ada77d24..7bd94bef 100644 --- a/src/tmf687/product_stock.rs +++ b/src/tmf687/product_stock.rs @@ -91,7 +91,7 @@ mod test { let stock = ProductStock::new(STOCK_NAME); assert_eq!(stock.name.is_some(),true); - assert_eq!(stock.name.unwrap().as_str(),STOCK_NAME); + assert_eq!(stock.get_name().as_str(),STOCK_NAME); } #[test] diff --git a/src/tmf699/sales_lead_v5.rs b/src/tmf699/sales_lead_v5.rs index addf7820..eb39e356 100644 --- a/src/tmf699/sales_lead_v5.rs +++ b/src/tmf699/sales_lead_v5.rs @@ -175,6 +175,6 @@ mod test { fn sales_lead_create_name() { let sl = SalesLead::new(SL_NAME); - assert_eq!(sl.name.unwrap(),SL_NAME.to_string()); + assert_eq!(sl.get_name(),SL_NAME.to_string()); } } \ No newline at end of file From bdd7480fddaa2af14c2a7f978d1a58cda863bca2 Mon Sep 17 00:00:00 2001 From: Ryan Ruckley Date: Fri, 16 Aug 2024 12:05:00 +1000 Subject: [PATCH 21/40] remove map() --- src/tmf666/financial_account.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/tmf666/financial_account.rs b/src/tmf666/financial_account.rs index 00b25680..96d4289d 100644 --- a/src/tmf666/financial_account.rs +++ b/src/tmf666/financial_account.rs @@ -36,7 +36,12 @@ pub struct FinancialAccountRef { impl From for FinancialAccountRef { fn from(value: FinancialAccount) -> Self { - let balance = value.account_balance.clone().map(|v| v.first().unwrap().clone()); + let balance = value + .account_balance + .clone() + .unwrap() + .first() + .cloned(); FinancialAccountRef { id: value.get_id(), From dcb91590814c29ee3bc68739a4ae7e7a6585b6fb Mon Sep 17 00:00:00 2001 From: Ryan Ruckley Date: Fri, 16 Aug 2024 16:02:35 +1000 Subject: [PATCH 22/40] Handle option --- src/tmf663/shopping_cart.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/tmf663/shopping_cart.rs b/src/tmf663/shopping_cart.rs index 869c8a60..a28102a0 100644 --- a/src/tmf663/shopping_cart.rs +++ b/src/tmf663/shopping_cart.rs @@ -66,7 +66,10 @@ impl ShoppingCart { /// Add item to shopping cart /// This function will calculate a total price and add it if not present pub fn add_item(&mut self, item : CartItem) { - self.cart_item.as_mut().unwrap().push(item); + match self.cart_item.as_mut() { + Some(v) => v.push(item), + None => self.cart_item = Some(vec![item]), + } } } From cda765b5ec79dd07865db502f6fae3c7ac590b4d Mon Sep 17 00:00:00 2001 From: Ryan Ruckley Date: Fri, 16 Aug 2024 16:03:27 +1000 Subject: [PATCH 23/40] Use expect() --- src/common/contact.rs | 3 ++- src/common/event.rs | 3 ++- src/common/external_identifier.rs | 3 ++- src/common/money.rs | 3 ++- src/lib.rs | 4 ++-- src/tmf620/bundled_product_offering.rs | 6 ++++-- src/tmf620/catalog.rs | 6 ++++-- src/tmf629/characteristic.rs | 3 ++- 8 files changed, 20 insertions(+), 11 deletions(-) diff --git a/src/common/contact.rs b/src/common/contact.rs index 7ba2c838..e0c079a0 100644 --- a/src/common/contact.rs +++ b/src/common/contact.rs @@ -191,7 +191,8 @@ mod test { #[test] fn test_mediumcharacteristic_deserialize() { - let mediumchar: MediumCharacteristic = serde_json::from_str(MEDIUM_CHAR_JSON).unwrap(); + let mediumchar: MediumCharacteristic = serde_json::from_str(MEDIUM_CHAR_JSON) + .expect("MEDIUM_CHAR_JSON"); assert_eq!(mediumchar.contact_type.is_some(),true); assert_eq!(mediumchar.contact_type.expect("Could not parse mediumchar JSON").as_str(),"email"); diff --git a/src/common/event.rs b/src/common/event.rs index e8c6e335..9f1e0765 100644 --- a/src/common/event.rs +++ b/src/common/event.rs @@ -92,7 +92,8 @@ mod test { #[test] fn test_event_deserialize() { - let event : Event = serde_json::from_str(EVENT_JSON).unwrap(); + let event : Event = serde_json::from_str(EVENT_JSON) + .expect("Could not parse EVENT_JSON"); assert_eq!(event.event_id.as_str(),"E123"); } diff --git a/src/common/external_identifier.rs b/src/common/external_identifier.rs index 789a118a..20ed413a 100644 --- a/src/common/external_identifier.rs +++ b/src/common/external_identifier.rs @@ -41,7 +41,8 @@ mod test { #[test] fn test_external_deserialize() { - let external : ExternalIdentifier = serde_json::from_str(EXTERNAL_JSON).unwrap(); + let external : ExternalIdentifier = serde_json::from_str(EXTERNAL_JSON) + .expect("Could not parse EXTERNAL_JSON"); assert_eq!(external.external_identifier_type.as_str(),"email"); assert_eq!(external.owner.as_str(),"customer"); diff --git a/src/common/money.rs b/src/common/money.rs index e0e59993..97c0ffef 100644 --- a/src/common/money.rs +++ b/src/common/money.rs @@ -75,7 +75,8 @@ mod test { #[test] fn test_money_deserialize() { - let money : Money = serde_json::from_str(MONEY_JSON).unwrap(); + let money : Money = serde_json::from_str(MONEY_JSON) + .expect("MONEY_JSON"); assert_eq!(money.unit.as_str(),"AUD"); assert_eq!(money.value,12.34); diff --git a/src/lib.rs b/src/lib.rs index 6d167a78..12e85eb5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -182,7 +182,7 @@ pub fn gen_code(name : String, id : String, offset : Option, prefix : Optio let hash_input = format!("{}:{}:{}",name,id,offset.unwrap_or_default()); let sha = digest(hash_input); let hex = decode(sha); - let base32 = encode(base32::Alphabet::Rfc4648 { padding: false }, hex.unwrap().as_ref()); + let base32 = encode(base32::Alphabet::Rfc4648 { padding: false }, hex.expect("Could not parse HEX string from digest()").as_ref()); let sha_slice = base32.as_str()[..length.unwrap_or(CODE_DEFAULT_LENGTH)].to_string().to_ascii_uppercase(); (format!("{}{}",prefix.unwrap_or_default(),sha_slice),base32) } @@ -471,7 +471,7 @@ mod test { let old_period = TimePeriod::period_30days(); let mut new_period = TimePeriod::default(); - new_period.start_date_time = old_period.end_date_time.unwrap().clone(); + new_period.start_date_time = old_period.end_date_time.expect("perdio_30days() did not set end date").clone(); assert_eq!(new_period.started(),false); } diff --git a/src/tmf620/bundled_product_offering.rs b/src/tmf620/bundled_product_offering.rs index 94843e5f..7045f039 100644 --- a/src/tmf620/bundled_product_offering.rs +++ b/src/tmf620/bundled_product_offering.rs @@ -149,7 +149,8 @@ mod test { #[test] fn test_bpo_deserialize() { - let bpo : BundledProductOffering = serde_json::from_str(BPO_JSON).unwrap(); + let bpo : BundledProductOffering = serde_json::from_str(BPO_JSON) + .expect("Could not parse BPO_JSON"); assert_eq!(bpo.id.is_some(),true); assert_eq!(bpo.get_id(),"BPO123"); @@ -159,7 +160,8 @@ mod test { #[test] fn test_bpo_option_deserialize() { - let bpo_option : BundledProductOfferingOption = serde_json::from_str(BPO_OPTION_JSON).unwrap(); + let bpo_option : BundledProductOfferingOption = serde_json::from_str(BPO_OPTION_JSON) + .expect("Could not parse BPO_OPTION_JSON"); assert_eq!(bpo_option.number_rel_offer_default,1); assert_eq!(bpo_option.number_rel_offer_lower_limit,2); diff --git a/src/tmf620/catalog.rs b/src/tmf620/catalog.rs index f31e6dea..ef31c7e7 100644 --- a/src/tmf620/catalog.rs +++ b/src/tmf620/catalog.rs @@ -260,14 +260,16 @@ mod tests { #[test] fn test_catalogeventtype_deserialize() { - let eventtype : CatalogEventType = serde_json::from_str(CAT_EVENT_TYPE_JSON).unwrap(); + let eventtype : CatalogEventType = serde_json::from_str(CAT_EVENT_TYPE_JSON) + .expect("Could not parse CAT_EVENT_TYPE_JSON"); assert_eq!(eventtype,CatalogEventType::CatalogCreateEvent); } #[test] fn test_catalogevent_deserialize() { - let _catalogevent : CatalogEvent = serde_json::from_str(CATALOGEVENT_JSON).unwrap(); + let _catalogevent : CatalogEvent = serde_json::from_str(CATALOGEVENT_JSON) + .expect("Could not parse CATALOGEVENT_JSON"); } #[test] diff --git a/src/tmf629/characteristic.rs b/src/tmf629/characteristic.rs index 2a3b033d..69aed731 100644 --- a/src/tmf629/characteristic.rs +++ b/src/tmf629/characteristic.rs @@ -44,7 +44,8 @@ mod test { #[test] fn test_characteristic_deserialize() { - let characteristic : Characteristic = serde_json::from_str(CHAR_JSON).unwrap(); + let characteristic : Characteristic = serde_json::from_str(CHAR_JSON) + .expect("Could not parse CHAR_JSON"); assert_eq!(characteristic.name.as_str(),"ABN"); assert_eq!(characteristic.value_type.as_str(),"string"); From fa2deec3e03f01cf2c2077cc38e27a62ba7a3c39 Mon Sep 17 00:00:00 2001 From: Ryan Ruckley Date: Fri, 16 Aug 2024 16:03:35 +1000 Subject: [PATCH 24/40] Use trait funcs --- src/tmf620/product_specification.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/tmf620/product_specification.rs b/src/tmf620/product_specification.rs index 8b10ed08..3e3a17a1 100644 --- a/src/tmf620/product_specification.rs +++ b/src/tmf620/product_specification.rs @@ -209,10 +209,10 @@ pub struct ProductSpecificationRef { impl From for ProductSpecificationRef { fn from(ps: ProductSpecification) -> ProductSpecificationRef { ProductSpecificationRef { - id: ps.id.unwrap(), - href: ps.href.unwrap(), - name: ps.name, - version: ps.version, + id: ps.get_id(), + href: ps.get_href(), + name: ps.name.clone(), + version: ps.version.clone(), } } } From 6e939ec035c9d6e1fcc3cd911b8f3f015a2864e3 Mon Sep 17 00:00:00 2001 From: Ryan Ruckley Date: Fri, 16 Aug 2024 16:03:43 +1000 Subject: [PATCH 25/40] Use trait funcs --- src/tmf620/product_offering_v5.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/tmf620/product_offering_v5.rs b/src/tmf620/product_offering_v5.rs index bdc680fa..6f834fc1 100644 --- a/src/tmf620/product_offering_v5.rs +++ b/src/tmf620/product_offering_v5.rs @@ -36,9 +36,10 @@ impl From for ProductOfferingRef { /// Convert from ProductOffering into ProductOfferingRef fn from(po : ProductOffering) -> ProductOfferingRef { ProductOfferingRef { - id: po.id.unwrap().clone(), - href: po.href.unwrap().clone(), - name: po.name.as_ref().unwrap().clone() } + id: po.get_id(), + href: po.get_href(), + name: po.get_name() + } } } From 2d86e704a33105dfa5b7fe3e830784323d4c6409 Mon Sep 17 00:00:00 2001 From: Ryan Ruckley Date: Fri, 16 Aug 2024 16:03:49 +1000 Subject: [PATCH 26/40] cleanup --- src/common/attachment.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/common/attachment.rs b/src/common/attachment.rs index 974a25e6..feb61e01 100644 --- a/src/common/attachment.rs +++ b/src/common/attachment.rs @@ -162,6 +162,5 @@ mod test { assert_eq!(attach.valid_for.is_some(),true); assert_eq!(attach.valid_for.unwrap().started(),true); - // assert_eq!(attach.valid_for.unwrap().finished(),false); } } From 896bb6f1290b436574ea7d9ea042eaeb2e7e0341 Mon Sep 17 00:00:00 2001 From: Ryan Ruckley Date: Tue, 20 Aug 2024 09:40:59 +1000 Subject: [PATCH 27/40] Use expect --- src/common/contact.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/common/contact.rs b/src/common/contact.rs index e0c079a0..865942da 100644 --- a/src/common/contact.rs +++ b/src/common/contact.rs @@ -203,7 +203,8 @@ mod test { #[test] fn test_contact_deserialize() { - let contact : Contact = serde_json::from_str(CONTACT_JSON).unwrap(); + let contact : Contact = serde_json::from_str(CONTACT_JSON) + .expect("CONTACT_JSON"); assert_eq!(contact.contact_name.as_str(),"John Quinton Citizen"); assert_eq!(contact.contact_type.as_str(),"primary"); From 5f43bb3937e6edbe75cbe6e7313a3a6e9f5e2b6c Mon Sep 17 00:00:00 2001 From: Ryan Ruckley Date: Tue, 20 Aug 2024 09:43:21 +1000 Subject: [PATCH 28/40] Use expect. --- src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 12e85eb5..4043619f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -110,7 +110,7 @@ impl TimePeriod { impl Default for TimePeriod { fn default() -> Self { let now = Utc::now(); - let time = chrono::DateTime::from_timestamp(now.timestamp(),0).unwrap(); + let time = chrono::DateTime::from_timestamp(now.timestamp(),0).expect("Invalid input timestamp"); TimePeriod { start_date_time : time.to_rfc3339(), end_date_time: None, @@ -233,7 +233,7 @@ pub trait HasLastUpdate : HasId { /// Geneate a timestamp for now(), useful for updating last_updated fields fn get_timestamp() -> String { let now = Utc::now(); - let time = chrono::DateTime::from_timestamp(now.timestamp(),0).unwrap(); + let time = chrono::DateTime::from_timestamp(now.timestamp(),0).expect("Invalid timestamp from now()"); time.to_string() } From d46d417edad080344f1aa7707e5d853e3f546d3a Mon Sep 17 00:00:00 2001 From: Ryan Ruckley Date: Tue, 20 Aug 2024 09:53:37 +1000 Subject: [PATCH 29/40] Use expect --- src/common/contact.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/contact.rs b/src/common/contact.rs index 865942da..f94eb1dc 100644 --- a/src/common/contact.rs +++ b/src/common/contact.rs @@ -214,7 +214,7 @@ mod test { #[test] fn test_contactmedium_deserialize() { - let contact_medium : ContactMedium = serde_json::from_str(CONTACT_MEDIUM).unwrap(); + let contact_medium : ContactMedium = serde_json::from_str(CONTACT_MEDIUM).expect("Could not parse CONTACT_MEDIUM"); assert_eq!(contact_medium.preferred,true); } From 1f704a3d545989f3df61a615b5af4ec13f44e2a9 Mon Sep 17 00:00:00 2001 From: Ryan Ruckley Date: Tue, 20 Aug 2024 09:53:43 +1000 Subject: [PATCH 30/40] Use expect --- src/common/price.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/common/price.rs b/src/common/price.rs index e474e8fd..56bc0516 100644 --- a/src/common/price.rs +++ b/src/common/price.rs @@ -90,7 +90,8 @@ mod test { #[test] fn test_price_deserialization() { - let price : Price = serde_json::from_str(PRICE_JSON).unwrap(); + let price : Price = serde_json::from_str(PRICE_JSON) + .expect("PRICE_JSON"); assert_eq!(price.percentage, 30.0); assert_eq!(price.tax_rate,10.0); From 3f05f12c45628db8ce30b59e9c0247ef9277ef0e Mon Sep 17 00:00:00 2001 From: Ryan Ruckley Date: Tue, 20 Aug 2024 09:54:00 +1000 Subject: [PATCH 31/40] Handle categories safely --- src/tmf620/product_offering_v5.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/tmf620/product_offering_v5.rs b/src/tmf620/product_offering_v5.rs index 6f834fc1..6e71e896 100644 --- a/src/tmf620/product_offering_v5.rs +++ b/src/tmf620/product_offering_v5.rs @@ -193,11 +193,12 @@ impl ProductOffering { /// let cat= Category::new(String::from("MyCategory")); /// let result = po.with_category(CategoryRef::from(&cat)); /// ``` - pub fn with_category(mut self, category: CategoryRef) -> ProductOffering { - if self.category.is_none() { - self.category = Some(vec![]); + pub fn with_category(mut self, category: Category) -> ProductOffering { + let cat_ref = CategoryRef::from(category); + match self.category.as_mut() { + Some(v) => v.push(cat_ref), + None => self.category = Some(vec![cat_ref]), } - self.category.as_mut().unwrap().push(category); self } From e7674232e37f32d14745388146558d86ce13f526 Mon Sep 17 00:00:00 2001 From: Ryan Ruckley Date: Tue, 20 Aug 2024 09:54:16 +1000 Subject: [PATCH 32/40] Use default if not set. --- src/tmf632/individual_v5.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/tmf632/individual_v5.rs b/src/tmf632/individual_v5.rs index 3407a6de..8e2d5dde 100644 --- a/src/tmf632/individual_v5.rs +++ b/src/tmf632/individual_v5.rs @@ -293,7 +293,8 @@ impl Individual { impl HasName for Individual { fn get_name(&self) -> String { - self.full_name.as_ref().unwrap().clone() + // This will panic if full_name is not set + self.full_name.as_ref().unwrap_or_default().clone() } fn set_name(&mut self, name : impl Into) { let name : String = name.into(); From 86c70fe6ded28e40efea25a0471871a97d165d54 Mon Sep 17 00:00:00 2001 From: Ryan Ruckley Date: Tue, 20 Aug 2024 13:59:06 +1000 Subject: [PATCH 33/40] doccomments --- src/tmf632/individual_v5.rs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/tmf632/individual_v5.rs b/src/tmf632/individual_v5.rs index 8e2d5dde..0222acc7 100644 --- a/src/tmf632/individual_v5.rs +++ b/src/tmf632/individual_v5.rs @@ -27,6 +27,7 @@ use crate::common::event::{Event, EventPayload}; const CLASS_PATH : &str = "individual"; const CODE_PREFIX : &str = "I-"; +const NAMENOTSET : &str = "NAMENOTSET"; /// Language ability of an individual #[derive(Clone, Debug, Default, Deserialize, Serialize)] @@ -260,6 +261,11 @@ impl Individual { } /// Replace a characteristic returning the old value if found + /// # Actions + /// Performs the following actions: + /// - Creates a characteristic array if one does not exist + /// - Creates a new characteristic entry if one is not found. + /// - Returns the old entry if one was found. pub fn replace_characteristic(&mut self, characteristic : Characteristic) -> Option { match self.party_characteristic.as_mut() { Some(c) => { @@ -271,11 +277,12 @@ impl Individual { let old = c[u].clone(); // Replace c[u] = characteristic; + // Return the previous value Some(old) }, None => { - // This means the characteristic could not be found, instead we insert it - // Additional we return None to indicate that no old value was found + // The characteristic could not be found, instead we insert it + // Additionally, we return None to indicate that no previous value was found c.push(characteristic); None }, @@ -294,7 +301,10 @@ impl Individual { impl HasName for Individual { fn get_name(&self) -> String { // This will panic if full_name is not set - self.full_name.as_ref().unwrap_or_default().clone() + match self.full_name.as_ref() { + Some(f) => f.clone(), + None => String::from(NAMENOTSET), + } } fn set_name(&mut self, name : impl Into) { let name : String = name.into(); From 7abe85bd9ac00a3758596239b9566f6505e6a7e0 Mon Sep 17 00:00:00 2001 From: Ryan Ruckley Date: Tue, 20 Aug 2024 13:59:15 +1000 Subject: [PATCH 34/40] handle missing name --- src/tmf632/individual_v4.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/tmf632/individual_v4.rs b/src/tmf632/individual_v4.rs index bbad43ac..8d039cd6 100644 --- a/src/tmf632/individual_v4.rs +++ b/src/tmf632/individual_v4.rs @@ -29,6 +29,7 @@ use crate::common::event::{Event, EventPayload}; const CLASS_PATH : &str = "individual"; const CODE_PREFIX : &str = "I-"; +const NAMENOTSET : &str = "NAMENOTSET"; /// An individual #[derive(Clone, Debug, Default, Deserialize, HasId, HasRelatedParty, Serialize)] @@ -194,7 +195,7 @@ impl Individual { } } - /// Find a particular contact medium matching ``medium`` + /// Find a particular contact medium matching [`medium`] fn find_medium(&self, medium : impl Into) -> Option> { match &self.contact_medium { None => None, @@ -279,7 +280,10 @@ impl Individual { impl HasName for Individual { fn get_name(&self) -> String { - self.full_name.as_ref().unwrap().clone() + match self.full_name.as_ref() { + Some(f) => f.clone(), + None => String::from(NAMENOTSET), + } } fn set_name(&mut self, name : impl Into) { let name : String = name.into(); From 207df56c7eb2f1e1a03928c21297983918276def Mon Sep 17 00:00:00 2001 From: Ryan Ruckley Date: Tue, 20 Aug 2024 15:38:37 +1000 Subject: [PATCH 35/40] add safe insert for optional vecs --- src/lib.rs | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 4043619f..2f786b61 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -187,6 +187,21 @@ pub fn gen_code(name : String, id : String, offset : Option, prefix : Optio (format!("{}{}",prefix.unwrap_or_default(),sha_slice),base32) } +/// Perform an safe insert operation on a optional vector of TMF objects +/// # Actions +/// - If Option is Some(v) then item is inserted into v +/// - If Option is None then a new Vec is created with item as single entry +pub fn vec_insert(ov : &mut Option>, item : T) { + match ov.as_mut() { + Some(v) => { + v.push(item); + }, + None => { + let _old_i = ov.replace(vec![item]); + } + } +} + /// Trait indicating a TMF struct has and id and corresponding href field pub trait HasId : Default { /// Get a new UUID in simple format (no seperators) @@ -374,7 +389,9 @@ mod test { use crate::{HasName, Quantity, TimePeriod}; use super::gen_code; + use super::vec_insert; use crate::tmf632::organization_v4::Organization; + use crate::common::related_party::RelatedParty; const CODE : &str = "T-DXQR65"; const HASH : &str = "DXQR656VE3FIKEZZWJX6C3WC27NSRTJVMYR7ILA5XNDLSJXQPDVQ"; @@ -475,4 +492,29 @@ mod test { assert_eq!(new_period.started(),false); } + + #[test] + fn test_vecinsert_none() { + let rp = RelatedParty::default(); + let mut ov : Option> = None; + + vec_insert(&mut ov,rp); + + assert_eq!(ov.is_some(),true); + assert_eq!(ov.unwrap().len(),1); + } + + #[test] + fn test_vecinsert_some() { + let mut rp = RelatedParty::default(); + let _prev = rp.name.insert(String::from("one")); + let mut ov : Option> = Some(vec![rp]); + + let rp2 = RelatedParty::default(); + + vec_insert(&mut ov,rp2); + + assert_eq!(ov.is_some(),true); + assert_eq!(ov.unwrap().len(),2); + } } \ No newline at end of file From 7d9fe6fa6b55e7e5f8a0d13ff7a499f343e7e978 Mon Sep 17 00:00:00 2001 From: Ryan Ruckley Date: Tue, 20 Aug 2024 15:38:45 +1000 Subject: [PATCH 36/40] Perform safe insert --- src/tmf620/product_offering_v5.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/tmf620/product_offering_v5.rs b/src/tmf620/product_offering_v5.rs index 6e71e896..03bbeaa7 100644 --- a/src/tmf620/product_offering_v5.rs +++ b/src/tmf620/product_offering_v5.rs @@ -195,6 +195,7 @@ impl ProductOffering { /// ``` pub fn with_category(mut self, category: Category) -> ProductOffering { let cat_ref = CategoryRef::from(category); + self.category = upsert(self.category,category); match self.category.as_mut() { Some(v) => v.push(cat_ref), None => self.category = Some(vec![cat_ref]), @@ -202,10 +203,11 @@ impl ProductOffering { self } - /// Add specification into this Product Offering - pub fn with_specification(mut self, specification: ProductSpecification) -> ProductOffering { - self.product_specification = Some(ProductSpecificationRef::from(specification)); - self + pub fn upsert( &i : Some(T), item : U) -> Option { + match i.as_mut() { + Some(v) => v.push(U), + None => Some(vec![item]), + } } /// Add characteristic value uses into this Product Offering From a6d967fda798bc20585930d13bbdfb7f1e2231c7 Mon Sep 17 00:00:00 2001 From: Ryan Ruckley Date: Tue, 20 Aug 2024 15:38:53 +1000 Subject: [PATCH 37/40] use safe insert --- src/tmf620/product_offering.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/tmf620/product_offering.rs b/src/tmf620/product_offering.rs index 5f521775..5ba3ec23 100644 --- a/src/tmf620/product_offering.rs +++ b/src/tmf620/product_offering.rs @@ -20,6 +20,7 @@ use crate::{ TimePeriod, DateTime, Uri, + vec_insert, LIB_PATH, }; @@ -34,7 +35,7 @@ use tmflib_derive::{ HasAttachment, HasLastUpdate, HasName, - HasValidity + HasValidity, }; use super::MOD_PATH; @@ -231,10 +232,8 @@ impl ProductOffering { /// let result = po.with_category(CategoryRef::from(&cat)); /// ``` pub fn with_category(mut self, category: CategoryRef) -> ProductOffering { - if self.category.is_none() { - self.category = Some(vec![]); - } - self.category.as_mut().unwrap().push(category); + vec_insert(&mut self.category,category); + // self.category.as_mut().unwrap().push(category); self } From 1b43d7b923c29254dff42f4ec79f241c95cf71b1 Mon Sep 17 00:00:00 2001 From: Ryan Ruckley Date: Tue, 20 Aug 2024 15:38:59 +1000 Subject: [PATCH 38/40] use safe insert --- src/tmf622/product_order_v4.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/tmf622/product_order_v4.rs b/src/tmf622/product_order_v4.rs index 6707627e..65fd8f6e 100644 --- a/src/tmf622/product_order_v4.rs +++ b/src/tmf622/product_order_v4.rs @@ -13,6 +13,7 @@ use crate::{ HasNote, HasRelatedParty, Uri, + vec_insert, LIB_PATH, }; use crate::tmf663::shopping_cart::ShoppingCart; @@ -142,7 +143,8 @@ impl ProductOrder { /// Add an ProductOrderItem into the ProductOrder pub fn add_order_item(&mut self, order_item : ProductOrderItem) { - self.product_order_item.as_mut().unwrap().push(order_item); + vec_insert(&mut self.product_order_item,order_item); + // self.product_order_item.as_mut().unwrap().push(order_item); } } From 9527375cd18ec29fd96789b4fe4003162d9edd78 Mon Sep 17 00:00:00 2001 From: Ryan Ruckley Date: Tue, 20 Aug 2024 15:39:10 +1000 Subject: [PATCH 39/40] define balance aggregation func --- src/tmf666/financial_account.rs | 37 ++++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/src/tmf666/financial_account.rs b/src/tmf666/financial_account.rs index 96d4289d..7a6876c3 100644 --- a/src/tmf666/financial_account.rs +++ b/src/tmf666/financial_account.rs @@ -36,18 +36,11 @@ pub struct FinancialAccountRef { impl From for FinancialAccountRef { fn from(value: FinancialAccount) -> Self { - let balance = value - .account_balance - .clone() - .unwrap() - .first() - .cloned(); - FinancialAccountRef { id: value.get_id(), href: value.get_href(), name: value.get_name(), - account_balance: balance, + account_balance: Some(value.get_balance()), } } } @@ -76,6 +69,34 @@ pub struct FinancialAccount { tax_exemption: Option>, } +impl FinancialAccount { + /// Get summed balance accross all AccountBalance records + pub fn get_balance(&self) -> AccountBalance { + let total = match self.account_balance.as_ref() { + Some(v) => { + let mut out = 0.0; + v.iter().for_each(|ab| { + out += match ab.amount.as_ref() { + Some(m) => m.value, + None => 0.0, + } + }); + out + }, + None => 0.0, + }; + let money = Money { + value : total, + unit : String::from("unknown"), + }; + AccountBalance { + amount : Some(money), + balance_type: String::from("total"), + valid_for: None, + } + } +} + #[cfg(test)] mod test { use super::*; From ce3e514b86b2484bdce4ca984c2eb77b1136cde2 Mon Sep 17 00:00:00 2001 From: Ryan Ruckley Date: Tue, 20 Aug 2024 15:39:24 +1000 Subject: [PATCH 40/40] include trait hasvalidity --- src/tmf666/mod.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/tmf666/mod.rs b/src/tmf666/mod.rs index c689e012..41ca45db 100644 --- a/src/tmf666/mod.rs +++ b/src/tmf666/mod.rs @@ -28,6 +28,9 @@ pub mod party_account; pub mod financial_account; pub mod settlement_account; +use crate::HasValidity; +use tmflib_derive::HasValidity; + const MOD_PATH : &str = "accountManagement/v4"; /// Account Reference @@ -52,7 +55,7 @@ pub struct AccountRelationship { } /// Account Balance -#[derive( Clone, Debug, Default, Deserialize, Serialize)] +#[derive( Clone, Debug, Default, Deserialize, HasValidity, Serialize)] #[serde(rename_all = "camelCase")] pub struct AccountBalance { #[serde(skip_serializing_if = "Option::is_none")]