use crate::common::attachment::AttachmentRefOrValue;
use crate::tmf620::bundled_product_offering::BundledProductOffering;
use crate::tmf620::category::CategoryRef;
use crate::tmf620::product_specification::{
ProductSpecification, ProductSpecificationCharacteristicValueUse, ProductSpecificationRef,
};
use crate::tmf634::resource_candidate::ResourceCandidateRef;
use crate::tmf633::service_candidate::ServiceCandidateRef;
use crate::{
HasAttachment,
HasDescription,
HasLastUpdate,
HasId,
HasName,
HasValidity,
TimePeriod,
DateTime,
Uri,
vec_insert,
LIB_PATH,
};
use super::product_offering_price::ProductOfferingPriceRef;
use serde::{Deserialize, Serialize};
use super::{ChannelRef,MarketSegmentRef,PlaceRef,SLARef};
use crate::tmf651::agreement::AgreementRef;
use tmflib_derive::{
HasId,
HasDescription,
HasAttachment,
HasLastUpdate,
HasName,
HasValidity,
};
use super::MOD_PATH;
const PO_VERS_INIT: &str = "1.0";
const CLASS_PATH: &str = "productOffering";
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
pub struct ProductOfferingRef {
pub id: String,
pub href: String,
pub name : String,
}
impl From<ProductOffering> for ProductOfferingRef {
fn from(po : ProductOffering) -> ProductOfferingRef {
ProductOfferingRef {
id: po.id.unwrap_or("MISSING".to_string()).clone(),
href: po.href.unwrap_or("MISSING".to_string()).clone(),
name: po.name.unwrap_or("MISSING".to_string()).clone()
}
}
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct ProductOfferingTerm {}
#[derive(Clone, Debug, Deserialize, Serialize, HasValidity)]
#[serde(rename_all = "camelCase")]
pub struct ProductOfferingRelationship {
pub id: Option<String>,
pub href: Option<String>,
pub name: Option<String>,
pub relationship_type: Option<String>,
pub role: Option<String>,
pub valid_for: Option<TimePeriod>,
}
impl From<ProductOffering> for ProductOfferingRelationship {
fn from(po : ProductOffering) -> ProductOfferingRelationship {
ProductOfferingRelationship {
id: po.id.clone(),
href: po.href.clone(),
name: po.name.clone(),
relationship_type: None,
role : None,
valid_for: None,
}
}
}
#[derive(Clone, Default, Debug, Deserialize, HasId, HasDescription, HasAttachment, HasLastUpdate, HasName, HasValidity, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct ProductOffering {
#[serde(skip_serializing_if = "Option::is_none")]
pub id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub href: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub is_bundle: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub is_sellable: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub last_update: Option<DateTime>,
#[serde(skip_serializing_if = "Option::is_none")]
pub lifecycle_status: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub status_reason: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub version: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub valid_for: Option<TimePeriod>,
#[serde(skip_serializing_if = "Option::is_none")]
pub agreement: Option<Vec<AgreementRef>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub attachment: Option<Vec<AttachmentRefOrValue>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub bundled_product_offering: Option<Vec<BundledProductOffering>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub category: Option<Vec<CategoryRef>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub channel: Option<Vec<ChannelRef>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub market_segment: Option<Vec<MarketSegmentRef>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub place: Option<Vec<PlaceRef>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub product_offering_price: Option<Vec<ProductOfferingPriceRef>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub product_offering_relationship: Option<Vec<ProductOfferingRelationship>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub product_offering_term: Option<Vec<ProductOfferingTerm>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub prod_spec_char_value_use: Option<Vec<ProductSpecificationCharacteristicValueUse>>,
pub product_specification: Option<ProductSpecificationRef>,
#[serde(skip_serializing_if = "Option::is_none")]
pub resource_candidate: Option<ResourceCandidateRef>,
#[serde(skip_serializing_if = "Option::is_none")]
pub service_candidate: Option<ServiceCandidateRef>,
#[serde(skip_serializing_if = "Option::is_none")]
pub service_level_agreement: Option<SLARef>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(rename = "@baseType")]
base_type : Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(rename = "@schemaLocation")]
schema_location: Option<Uri>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(rename = "@type")]
r#type : Option<String>,
}
impl ProductOffering {
pub fn new(name: impl Into<String>) -> ProductOffering {
let mut offer = ProductOffering::create_with_time();
offer.name = Some(name.into());
offer.version = Some(PO_VERS_INIT.to_string());
offer.base_type = Some(ProductOffering::get_class());
offer.r#type = Some(ProductOffering::get_class());
offer
}
pub fn status(&mut self, status : &str) {
self.lifecycle_status = Some(status.to_owned());
}
pub fn with_category(mut self, category: CategoryRef) -> ProductOffering {
vec_insert(&mut self.category,category);
self
}
pub fn with_specification(mut self, specification: ProductSpecification) -> ProductOffering {
self.product_specification = Some(ProductSpecificationRef::from(specification));
self
}
pub fn with_char_value_use(mut self, char_value_use : ProductSpecificationCharacteristicValueUse) -> ProductOffering {
match self.prod_spec_char_value_use.as_mut() {
Some(v) => v.push(char_value_use),
None => self.prod_spec_char_value_use = Some(vec![char_value_use]),
}
self
}
pub fn link_po(&mut self, remote_po : ProductOffering, relationship_type : &str, role : &str) {
let mut offer_rel = ProductOfferingRelationship::from(remote_po);
offer_rel.relationship_type = Some(relationship_type.to_string());
offer_rel.role = Some(role.to_string());
match self.product_offering_relationship.as_mut() {
Some(v) => {
v.push(offer_rel);
},
None => self.product_offering_relationship = Some(vec![offer_rel]),
};
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::tmf620::category::{Category,CategoryRef};
use crate::{HasId,HasName};
const PO_NAME : &str = "ProductOffering";
const PO2_NAME: &str = "Offer Two";
const PO_STATUS: &str = "A Status";
const CAT_NAME : &str = "A Category";
const SPEC_NAME: &str = "A Specification";
const CHARVALUSE_NAME : &str = "CharValUse";
const PRODOFFERREF_JSON : &str = "{
\"id\" : \"PO123\",
\"href\" : \"http://example.com/tmf620/offering/PO123\",
\"name\" : \"ProductOffering\"
}";
const PRODOFFER_JSON : &str = "{
\"id\" : \"PO123\",
\"href\" : \"http://example.com/tmf620/offering/PO123\",
\"name\" : \"ProductOffering\"
}";
const PRODOFFERTERM_JSON : &str = "{}";
const PRODOFFERREL_JSON : &str = "{
\"id\" : \"POR123\",
\"name\" : \"ProductOfferRel\",
\"relationshipType\" : \"Parent/Child\",
\"role\" : \"child\"
}";
const PO_TERM_JSON : &str = "{}";
#[test]
fn test_po_new_name() {
let po = ProductOffering::new(PO_NAME);
assert_eq!(po.name, Some(String::from(PO_NAME)));
}
#[test]
fn test_po_new_version() {
let po = ProductOffering::new(PO_NAME);
assert_eq!(po.version, Some(PO_VERS_INIT.into()));
}
#[test]
fn test_poref_from_po() {
let po = ProductOffering::new(PO_NAME);
let po_ref = ProductOfferingRef::from(po.clone());
assert_eq!(po.get_id(),po_ref.id);
assert_eq!(po.get_href(),po_ref.href);
assert_eq!(po.get_name(),po_ref.name);
}
#[test]
fn test_por_from_po() {
let po = ProductOffering::new(PO_NAME);
let por = ProductOfferingRelationship::from(po.clone());
assert_eq!(po.id,por.id);
assert_eq!(po.href,por.href);
assert_eq!(po.name,por.name);
assert_eq!(por.relationship_type.is_none(),true);
assert_eq!(por.role.is_none(),true);
assert_eq!(por.valid_for.is_none(),true);
}
#[test]
fn test_po_status() {
let mut po = ProductOffering::new(PO_NAME);
po.status(PO_STATUS);
assert_eq!(po.lifecycle_status.unwrap(),PO_STATUS.to_string());
}
#[test]
fn test_po_with_cat() {
let cat = Category::new(CAT_NAME);
let po = ProductOffering::new(PO_NAME)
.with_category(CategoryRef::from(&cat));
assert_eq!(po.category.is_some(),true);
}
#[test]
fn test_po_with_spec() {
let spec = ProductSpecification::new(SPEC_NAME);
let po = ProductOffering::new(PO_NAME)
.with_specification(spec);
assert_eq!(po.product_specification.is_some(),true);
}
#[test]
fn test_poref_deserialize() {
let productofferref : ProductOfferingRef = serde_json::from_str(PRODOFFERREF_JSON).unwrap();
assert_eq!(productofferref.id.as_str(),"PO123");
assert_eq!(productofferref.name.as_str(),"ProductOffering");
}
#[test]
fn test_po_term_deserialize() {
let _offerterm : ProductOfferingTerm = serde_json::from_str(PRODOFFERTERM_JSON).unwrap();
}
#[test]
fn test_po_relationship_deserialize() {
let offer_rel : ProductOfferingRelationship = serde_json::from_str(PRODOFFERREL_JSON).unwrap();
assert_eq!(offer_rel.id.is_some(),true);
assert_eq!(offer_rel.name.is_some(),true);
assert_eq!(offer_rel.relationship_type.is_some(),true);
assert_eq!(offer_rel.role.is_some(),true);
}
#[test]
fn test_po_deserialize() {
let po : ProductOffering = serde_json::from_str(PRODOFFER_JSON).unwrap();
assert_eq!(po.name.is_some(),true);
assert_eq!(po.get_name().as_str(),PO_NAME);
}
#[test]
fn test_po_hasattachment() {}
#[test]
fn test_po_hasvalidity() {
let mut po = ProductOffering::new(PO_NAME);
po.set_validity(TimePeriod::period_30days());
assert_eq!(po.valid_for.is_some(),true);
assert_eq!(po.get_validity().unwrap().started(),true);
assert_eq!(po.get_validity().unwrap().finished(),false);
assert_eq!(po.get_validity_start().is_some(),true);
assert_eq!(po.get_validity_end().is_some(),true);
}
#[test]
fn test_po_charvaluse() {
let charvaluse = ProductSpecificationCharacteristicValueUse::new(CHARVALUSE_NAME);
let po = ProductOffering::new(PO_NAME)
.with_char_value_use(charvaluse);
assert_eq!(po.prod_spec_char_value_use.is_some(),true);
assert_eq!(po.prod_spec_char_value_use.unwrap().len(),1);
}
#[test]
fn test_po_link_po() {
let mut po1 = ProductOffering::new(PO_NAME);
let po2 = ProductOffering::new(PO2_NAME);
po1.link_po(po2, "Parent/Child", "Parent");
assert_eq!(po1.product_offering_relationship.is_some(),true);
}
#[test]
fn test_pot_deserialize() {
let _pot : ProductOfferingTerm = serde_json::from_str(PO_TERM_JSON).unwrap();
}
#[test]
fn test_por_hasvalidity() {}
}