Skip to content

Commit

Permalink
Merge branch 'master' into Customer_Characteristics
Browse files Browse the repository at this point in the history
  • Loading branch information
rruckley authored Dec 19, 2023
2 parents 001a5ce + c39023d commit cccbeaa
Show file tree
Hide file tree
Showing 9 changed files with 335 additions and 38 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "tmflib"
version = "0.1.4"
version = "0.1.5"
edition = "2021"
authors = ["Ryan Ruckley <[email protected]>"]
description = "Interface library for processing TMF payloads"
Expand Down
27 changes: 23 additions & 4 deletions examples/create_quote.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,31 @@
//! Create Quote Example
use tmflib::tmf648::{quote::Quote, quote_item::QuoteItem};
use tmflib::tmf648::{quote::Quote, quote_item::QuoteItem, quote_price::{Price,QuotePrice}};

fn main() {
// Create a quote
let item = QuoteItem::new();
// Create a quote using various components

// First create a quote item
let mut item = QuoteItem::new();
// Create a price for this item
let price = Price::new_ex(100.0);
// Add price to QuotePrice and set period
let quote_price = QuotePrice::new("Subscription").price(price).period("Monthly");
// add QuotePrice to item
item.price(quote_price);
// Create the new Quote
let mut quote = Quote::new();
// Add the item to the quote
let _result = quote.add_quote(item);
let _result = quote.with_external_id(String::from("ExternalId"));
// Set the external Id
let _result = quote.with_external_id(String::from("EXT123"));

// Create a total price for the quote
let total_price = Price::new_ex(3600.0);

// Create QuotePrice object for the total price and set period
let quote_total_price = QuotePrice::new("Total Contract").price(total_price).period("Contract");
// Add QuotePrice to quote
quote.price(quote_total_price);

dbg!(&quote);
}
4 changes: 3 additions & 1 deletion src/common/event.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
//! Asynchronous Events
//!
use serde::{Deserialize, Serialize};
use crate::HasId;
use std::fmt::Display;

/// Generic Event structure, will be linked into event specific payloads.
#[derive(Clone, Default, Debug, Deserialize, Serialize)]
Expand Down Expand Up @@ -44,7 +46,7 @@ pub struct Event<T,U> {
}

/// Trait for types that can generate an event
pub trait EventPayload<T,U> {
pub trait EventPayload<T : HasId,U : Display> {
/// Generate a new event payload
fn generate_event(&self,event_type : U) -> Event<T,U>;
}
3 changes: 3 additions & 0 deletions src/tmf622/product_order.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,11 @@ const PO_PATH: &str = "order";
#[derive(Debug, Default, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct ProductOrder {
#[serde(skip_serializing_if = "Option::is_none")]
id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
href: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
order_date: Option<String>,
product_order_item: Vec<ProductOrderItem>,
related_party: Vec<RelatedParty>,
Expand Down
1 change: 1 addition & 0 deletions src/tmf648/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ const MOD_PATH: &str = "tmf648/v4";

pub mod quote;
pub mod quote_item;
pub mod quote_price;
120 changes: 97 additions & 23 deletions src/tmf648/quote.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
//! Quote Module
use serde::{Deserialize, Serialize};
use uuid::Uuid;

use super::quote_item::QuoteItem;
use super::MOD_PATH;
use super::quote_price::QuotePrice;
use crate::common::note::Note;
use crate::LIB_PATH;
use crate::{LIB_PATH, HasId, CreateTMF};

const QUOTE_PATH: &str = "quote";
const QUOTE_VERS: &str = "1.0";
Expand Down Expand Up @@ -33,31 +33,50 @@ pub enum QuoteStateType {
#[derive(Clone, Default, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Quote {
id: String,
href: String,
description: Option<String>,
/// Unique Id
#[serde(skip_serializing_if = "Option::is_none")]
pub id: Option<String>,
/// HTML Reference to quote
#[serde(skip_serializing_if = "Option::is_none")]
pub href: Option<String>,
/// Quote description
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
/// External reference
#[serde(skip_serializing_if = "Option::is_none")]
external_id: Option<String>,
/// Notes for Quote
#[serde(skip_serializing_if = "Option::is_none")]
note: Option<Vec<Note>>,
state: QuoteStateType,
quote_item: Vec<QuoteItem>,
version: String,
/// Quote status
#[serde(skip_serializing_if = "Option::is_none")]
pub state: Option<QuoteStateType>,
/// Vector of quote items
#[serde(skip_serializing_if = "Option::is_none")]
pub quote_item: Option<Vec<QuoteItem>>,
/// Current quote version
#[serde(skip_serializing_if = "Option::is_none")]
pub version: Option<String>,
/// Order Submission Date
#[serde(skip_serializing_if = "Option::is_none")]
pub order_date: Option<String>,
/// Requested Start Date
#[serde(skip_serializing_if = "Option::is_none")]
pub start_date: Option<String>,
/// Total Quote Pricing
#[serde(skip_serializing_if = "Option::is_none")]
pub quote_total_price : Option<Vec<QuotePrice>>,
}

impl Quote {
/// Create a new Product Quote
pub fn new() -> Quote {
let id = Uuid::new_v4().to_string();
let href = format!("/{}/{}/{}/{}", LIB_PATH, MOD_PATH, QUOTE_PATH, id);
Quote {
id,
href,
description: None,
external_id: None,
note: None,
version: QUOTE_VERS.to_string(),
state: QuoteStateType::Accepted,
quote_item: vec![],
}
let mut quote = Quote::create();
quote.version = Some(QUOTE_VERS.to_string());
quote.state = Some(QuoteStateType::Accepted);
quote.quote_item = Some(vec![]);
quote.quote_total_price = Some(vec![]);
quote
}

/// Set external Id for this quote
Expand All @@ -67,28 +86,83 @@ impl Quote {

/// Add a quote item into a product quote
pub fn add_quote(&mut self, item: QuoteItem) -> Result<String, String> {
self.quote_item.push(item);
self.quote_item.as_mut().unwrap().push(item);
Ok(String::from("Quote Item Added"))
}

/// Add a price entry to this quote
pub fn price(&mut self, price : QuotePrice) {
self.quote_total_price.as_mut().unwrap().push(price);
}

/// Get a description for this quote
pub fn description(&self) -> String {
match &self.description {
Some(d) => d.clone(),
None => {
format!("Quote-{}",self.get_id())
}
}
}

}

impl HasId for Quote {
fn generate_href(&mut self) {
let href = format!("/{}/{}/{}/{}",LIB_PATH,MOD_PATH,QUOTE_PATH,self.get_id());
self.href = Some(href);
}
fn generate_id(&mut self) {
let id = Quote::get_uuid();
self.id = Some(id);
self.generate_href();
}
fn get_class() -> String {
QUOTE_PATH.to_owned()
}
fn get_href(&self) -> String {
self.href.as_ref().unwrap().clone()
}
fn get_id(&self) -> String {
self.id.as_ref().unwrap().clone()
}
}

impl CreateTMF<Quote> for Quote {}

#[cfg(test)]
mod test {
use super::QuoteStateType;
use crate::tmf648::quote::QUOTE_VERS;
use crate::HasId;

use super::Quote;
#[test]
fn quote_test_new_vers() {
let quote = Quote::new();

assert_eq!(quote.version, QUOTE_VERS.to_string());
assert_eq!(quote.version, Some(QUOTE_VERS.to_string()));
}

#[test]
fn quote_test_new_state() {
let quote = Quote::new();

assert_eq!(quote.state, QuoteStateType::Accepted);
assert_eq!(quote.state, Some(QuoteStateType::Accepted));
}

#[test]
fn quote_test_description() {
let mut quote = Quote::new();
quote.description = Some("description".to_string());

assert_eq!(quote.description(), "description".to_string())
}

#[test]
fn quote_test_no_description() {
let quote = Quote::new();

assert_eq!(quote.description(),format!("Quote-{}",quote.get_id()));
}
}
101 changes: 92 additions & 9 deletions src/tmf648/quote_item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,30 +4,113 @@ use serde::{Deserialize, Serialize};
use uuid::Uuid;

use crate::common::attachment::AttachmentRefOrValue;
use crate::common::note::Note;
use crate::common::related_party::RelatedParty;
use crate::tmf620::product_specification::ProductSpecificationRef;

use super::quote_price::QuotePrice;

/// Status of product for Quote Item
#[derive(Clone, Default, Debug, Deserialize, Serialize)]
pub enum ProductStatusType {
/// Created
#[default]
Created,
/// Wait for Active
PendingActive,
/// Cancelled
Cancelled,
/// Active
Active,
/// Wait for terminate
PendingTerminate,
/// Terminated
Terminated,
/// Suspended
Suspended,
/// Aborted
Aborted,
}

// Not sure if this should be housed in TMF620 but sample payload shows it being local to QuoteItem
/// Quote Item Product
#[derive(Clone, Default, Debug, Deserialize, Serialize)]
pub struct ProductRefOrValue {
/// Unique Id
#[serde(skip_serializing_if = "Option::is_none")]
pub id : Option<String>,
/// HTTP Reference
#[serde(skip_serializing_if = "Option::is_none")]
pub href : Option<String>,
/// Product Description (from TMF620)
#[serde(skip_serializing_if = "Option::is_none")]
pub description : Option<String>,
/// Is this a bundle (from TMF620)
#[serde(skip_serializing_if = "Option::is_none")]
pub is_bundle: Option<bool>,
/// Is this customer visible (from TMF620)
#[serde(skip_serializing_if = "Option::is_none")]
pub is_customer_visible : Option<bool>,
/// Product Name
pub name : String,
/// Product serial number (if known)
#[serde(skip_serializing_if = "Option::is_none")]
pub product_serial_number : Option<String>,
/// Status of product
#[serde(skip_serializing_if = "Option::is_none")]
pub status : Option<ProductStatusType>,
/// Product Specification (TMF620)
#[serde(skip_serializing_if = "Option::is_none")]
pub product_specification : Option<ProductSpecificationRef>,
}



/// Quote Item, line item for a product quote
#[derive(Clone, Default, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct QuoteItem {
id: String,
/// Unique Id
#[serde(skip_serializing_if = "Option::is_none")]
pub id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
action: Option<String>,
quantity: u16,
/// Quantity
pub quantity: u16,
/// Child Quote Items
#[serde(skip_serializing_if = "Option::is_none")]
quote_item: Option<Vec<QuoteItem>>,
pub quote_item: Option<Vec<QuoteItem>>,
/// Attachments
#[serde(skip_serializing_if = "Option::is_none")]
attachment: Option<Vec<AttachmentRefOrValue>>,
pub attachment: Option<Vec<AttachmentRefOrValue>>,
/// Notes
#[serde(skip_serializing_if = "Option::is_none")]
pub note : Option<Vec<Note>>,
/// Related Party
#[serde(skip_serializing_if = "Option::is_none")]
pub related_party : Option<Vec<RelatedParty>>,
/// Product
#[serde(skip_serializing_if = "Option::is_none")]
pub product : Option<ProductRefOrValue>,
/// Quote Item Pricing
#[serde(skip_serializing_if = "Option::is_none")]
quote_item_price : Option<Vec<QuotePrice>>,
}

impl QuoteItem {
/// Create a new quote item
pub fn new() -> QuoteItem {
let id = Uuid::new_v4().to_string();
QuoteItem {
id,
action: None,
quantity: 1,
quote_item: None,
attachment: None,
id : Some(id),
quantity : 1,
quote_item_price : Some(vec![]),
..Default::default()
}
}

/// Add QuotePrice to this QuoteItem
pub fn price(&mut self, price : QuotePrice) {
self.quote_item_price.as_mut().unwrap().push(price);
}
}
Loading

0 comments on commit cccbeaa

Please sign in to comment.