use chrono::Utc;
use serde::{Deserialize, Serialize};
#[cfg(all(feature = "tmf632", feature = "build-V4"))]
use crate::tmf632::organization_v4::Organization;
#[cfg(all(feature = "tmf632", feature = "build-V5"))]
use crate::tmf632::organization_v5::Organization;
use super::characteristic::Characteristic;
use crate::common::contact::ContactMedium;
use crate::common::event::{Event, EventPayload};
use crate::common::related_party::RelatedParty;
use crate::{gen_code, HasId, HasName, HasReference, HasValidity, TMFEvent, TimePeriod};
use tmflib_derive::{HasId, HasName, HasValidity};
use uuid::Uuid;
use super::MOD_PATH;
const CLASS_PATH: &str = "customer";
const CUST_ID_SIZE: usize = 5;
pub const CUST_STATUS: &str = "New";
const CUST_SEGMENT_CHAR: &str = "marketSegment";
#[derive(Clone, Default, Debug, Deserialize, HasId, HasName, HasValidity, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Customer {
pub href: Option<String>,
pub id: Option<String>,
pub name: Option<String>,
pub status: Option<String>,
pub status_reason: Option<String>,
pub valid_for: Option<TimePeriod>,
contact_medium: Option<Vec<ContactMedium>>,
characteristic: Option<Vec<Characteristic>>,
related_party: Vec<RelatedParty>,
engaged_party: Option<RelatedParty>,
}
impl Customer {
pub fn new(org: Organization) -> Customer {
let mut cust = Customer::create();
cust.name = Some(org.get_name());
cust.generate_code(None);
cust.engaged_party = Some(RelatedParty::from(org));
cust.status = Some(CUST_STATUS.to_string());
cust.contact_medium = Some(vec![]);
cust
}
pub fn generate_code(&mut self, offset: Option<u32>) {
if self.id.is_none() {
self.generate_id();
};
let (code, hash) = gen_code(
self.get_name(),
self.get_id(),
offset,
None,
Some(CUST_ID_SIZE),
);
let code = Characteristic {
name: String::from("code"),
value_type: String::from("string"),
value: code.into(),
};
let hash = Characteristic {
name: String::from("hash"),
value_type: String::from("string"),
value: hash.into(),
};
if self.characteristic.is_none() {
self.characteristic = Some(vec![]);
}
self.replace_characteristic(code);
self.replace_characteristic(hash);
}
pub fn get_characteristic(&self, characteristic: &str) -> Option<Characteristic> {
match &self.characteristic {
Some(c) => c.iter().find(|x| x.name == characteristic).cloned(),
None => None,
}
}
pub fn replace_characteristic(
&mut self,
characteristic: Characteristic,
) -> Option<Characteristic> {
match self.characteristic.as_mut() {
Some(c) => {
let pos = c.iter().position(|c| c.name == characteristic.name);
match pos {
Some(u) => {
let old = c[u].clone();
c[u] = characteristic;
Some(old)
}
None => {
c.push(characteristic);
None
}
}
}
None => {
self.characteristic = Some(vec![characteristic]);
None
}
}
}
pub fn name(&mut self, name: String) {
self.name = Some(name.clone());
}
pub fn set_market_segment(&mut self, segment: impl Into<String>) -> Option<Characteristic> {
let segment_char = Characteristic::new(CUST_SEGMENT_CHAR, segment);
self.replace_characteristic(segment_char)
}
pub fn get_market_segment(&self) -> Option<Characteristic> {
self.get_characteristic(CUST_SEGMENT_CHAR)
}
pub fn upgrade_to_code(&mut self, offset: Option<u32>) -> Option<Characteristic> {
let old_id = Characteristic {
name: String::from("Id"),
value_type: String::from("string"),
value: self.get_id().into(),
};
self.replace_characteristic(old_id);
self.generate_code(offset);
let code = self.get_characteristic("code")?;
let code_val = code.value.as_str()?;
self.set_id(code_val.to_string());
Some(code)
}
}
impl From<&Organization> for Customer {
fn from(value: &Organization) -> Self {
let mut customer = Customer::new(value.to_owned());
customer.generate_code(None);
customer
}
}
impl HasReference for Customer {
type RefType = RelatedParty;
fn as_ref(&self) -> Option<Self::RefType> {
Some(RelatedParty::from(self))
}
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub enum CustomerEventType {
CustomerCreateEvent,
CustomerAttributeValueChangeEvent,
CustomerStateChangeEvent,
CustomerDeleteEvent,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct CustomerEvent {
pub customer: Customer,
}
impl TMFEvent<CustomerEvent> for Customer {
fn event(&self) -> CustomerEvent {
CustomerEvent {
customer: self.clone(),
}
}
}
impl EventPayload<CustomerEvent> for Customer {
type Subject = Customer;
type EventType = CustomerEventType;
fn to_event(
&self,
event_type: Self::EventType,
) -> crate::common::event::Event<CustomerEvent, Self::EventType> {
let now = Utc::now();
let desc = format!(
"{:?} for {} [{}]",
event_type,
self.get_name(),
self.get_id()
);
let event_time = chrono::DateTime::from_timestamp(now.timestamp(), 0).unwrap();
let code = self.get_characteristic("code");
let code = code.map(|f| f.value);
Event {
correlation_id: Some(code.unwrap_or_default().to_string()),
description: Some(desc),
domain: Some(Customer::get_class()),
event_id: Uuid::new_v4().to_string(),
field_path: None,
href: Some(self.get_href()),
id: Some(self.get_id()),
title: Some(self.get_name()),
event_time: event_time.to_string(),
priority: None,
time_occurred: Some(event_time.to_string()),
event_type,
event: self.event(),
}
}
}
#[cfg(test)]
mod test {
use super::*;
const CUSTOMER: &str = "ACustomer";
const CUSTOMER_BAD: &str = " ACustomer ";
const CUSTOMER_UID: u16 = 174;
const CUSTOMER_SEGMENT: &str = "MarketSegment";
#[test]
fn test_customer_new_name() {
let org = Organization::new(CUSTOMER);
let customer = Customer::new(org);
assert_eq!(customer.name, Some(CUSTOMER.into()));
assert_eq!(customer.id.is_some(), true);
assert_eq!(customer.href.is_some(), true);
}
#[test]
fn test_customer_new_org() {
let org1 = Organization::new(CUSTOMER);
let org2 = org1.clone();
let customer = Customer::new(org1);
assert_eq!(customer.engaged_party, Some(RelatedParty::from(org2)));
}
#[test]
fn test_customer_new_code() {
let org1 = Organization::new(CUSTOMER);
let customer = Customer::new(org1);
assert!(customer.get_characteristic("code").is_some());
}
#[test]
fn test_customer_from_org() {
let org1 = Organization::new(CUSTOMER);
let customer = Customer::from(&org1);
assert_eq!(org1.name, customer.name);
}
#[test]
fn test_customer_characteristic_replace() {
let org1 = Organization::new(CUSTOMER);
let mut customer = Customer::from(&org1);
let code_new = Characteristic {
name: "code".into(),
value: "ABC".into(),
value_type: "String".into(),
};
let code_new_clone = code_new.clone();
let code_old = customer.get_characteristic("code");
let code_replace = customer.replace_characteristic(code_new);
let code_replaced = customer.get_characteristic("code");
assert_eq!(code_old.unwrap().value, code_replace.unwrap().value);
assert_eq!(code_new_clone.value, code_replaced.unwrap().value);
}
#[test]
fn test_customer_code_whitespace() {
let mut cust1 = Customer::default();
cust1.set_id(CUSTOMER_UID.to_string());
cust1.set_name(CUSTOMER);
let mut cust2 = Customer::default();
cust2.set_id(CUSTOMER_UID.to_string());
cust2.set_name(CUSTOMER_BAD);
cust1.generate_code(None);
cust2.generate_code(None);
let code1 = cust1.get_characteristic("code").unwrap();
let code2 = cust2.get_characteristic("code").unwrap();
assert_eq!(code1.value, code2.value);
}
#[test]
fn test_customer_characteristic_new_missing() {
let characteristic = Characteristic::from(("weather", "rainy"));
let org1 = Organization::new(CUSTOMER);
let mut customer = Customer::from(&org1);
customer.replace_characteristic(characteristic);
let test_char = customer.get_characteristic("weather");
assert!(test_char.is_some());
}
#[test]
fn test_customer_characteristic_default_missing() {
let characteristic = Characteristic::from(("weather", "rainy"));
let mut customer = Customer::default();
customer.replace_characteristic(characteristic);
let test_char = customer.get_characteristic("weather");
assert!(test_char.is_some());
}
#[test]
fn test_customer_upgrade_to_code() {
let mut customer = Customer::default();
customer.set_id("1");
let code = customer.upgrade_to_code(None).unwrap();
let char = customer.get_characteristic("code");
assert_eq!(code.value, char.unwrap().value);
assert_eq!(code.value, customer.get_id());
}
#[test]
fn test_customer_marketsegment() {
let mut customer = Customer::default();
let old_segment = customer.set_market_segment(CUSTOMER_SEGMENT.to_string());
assert_eq!(old_segment.is_none(), true);
let segment = customer.get_market_segment();
assert_eq!(segment.is_some(), true);
assert_eq!(segment.unwrap().value, CUSTOMER_SEGMENT);
}
#[test]
fn test_customer_noid() {
let customer = Customer::default();
assert_eq!(customer.get_id(), String::default());
assert_eq!(customer.get_href(), String::default());
}
#[test]
fn test_customer_asref() {
let org = Organization::new(CUSTOMER);
let customer = Customer::from(&org);
let ref_party = customer.as_ref().unwrap();
assert_eq!(ref_party.name.unwrap(), CUSTOMER.to_string());
assert_eq!(ref_party.id, customer.get_id());
assert_eq!(ref_party.href, customer.get_href());
}
}