versa_semval 0.8.0-alpha1

Cross-platform module for semantic validation of Versa data
Documentation
use crate::{helpers::object_key::is_null_or_undefined, model::ViolationDetails};

pub fn itemization_should_should_not_be_empty_if_totals_greater_than_zero(
  data: &serde_json::Value,
) -> Option<ViolationDetails> {
  let total = data
    .get("header")
    .and_then(|header| header.get("total"))
    .and_then(|total| total.as_i64())
    .unwrap_or(0);

  let subtotal = data
    .get("header")
    .and_then(|header| header.get("subtotal"))
    .and_then(|subtotal| subtotal.as_i64())
    .unwrap_or(0);

  if total + subtotal <= 0 {
    return None;
  }

  let Some(itemization) = data.get("itemization") else {
    return Some(ViolationDetails {
      details: Some("itemization is missing".to_string()),
    });
  };

  if itemization.is_null() {
    return Some(ViolationDetails {
      details: Some("itemization is null".to_string()),
    });
  }

  if itemization.is_object() {
    if is_null_or_undefined(itemization.get("general"))
      && is_null_or_undefined(itemization.get("lodging"))
      && is_null_or_undefined(itemization.get("ecommerce"))
      && is_null_or_undefined(itemization.get("car_rental"))
      && is_null_or_undefined(itemization.get("transit_route"))
      && is_null_or_undefined(itemization.get("subscription"))
      && is_null_or_undefined(itemization.get("flight"))
    {
      return Some(ViolationDetails {
        details: Some("itemization is empty".to_string()),
      });
    }
  }
  None
}

#[cfg(test)]
mod tests {
  use super::*;
  use pretty_assertions::assert_eq;

  #[test]
  fn test_itemization_should_should_not_be_null_if_totals_greater_than_zero() {
    let rule_invalid_serde_json_value = serde_json::json!({
      "header": { "total": 100, "subtotal": 100 },
      "itemization": null
    });

    let result = itemization_should_should_not_be_empty_if_totals_greater_than_zero(
      &rule_invalid_serde_json_value,
    )
    .unwrap();
    assert_eq!(result.details, Some("itemization is null".to_string()));
  }

  #[test]
  fn test_itemization_should_should_not_be_empty_if_totals_greater_than_zero() {
    let rule_invalid_serde_json_value1 = serde_json::json!({
      "header": { "total": 100, "subtotal": 100 },
      "itemization": {
        "general": null,
        "lodging": null,
        "ecommerce": null,
        "car_rental": null,
        "transit_route": null,
        "subscription": null,
        "flight": null
      }
    });

    let rule_invalid_serde_json_value2 = serde_json::json!({
      "header": { "total": 100, "subtotal": 100 },
      "itemization": {
        "general": {},
        "lodging": {},
        "ecommerce": {},
        "car_rental": {},
        "transit_route": {},
        "subscription": {},
        "flight": {}
      }
    });

    let result1 = itemization_should_should_not_be_empty_if_totals_greater_than_zero(
      &rule_invalid_serde_json_value1,
    )
    .unwrap();
    let result2 = itemization_should_should_not_be_empty_if_totals_greater_than_zero(
      &rule_invalid_serde_json_value2,
    )
    .unwrap();
    assert_eq!(result1.details, Some("itemization is empty".to_string()));
    assert_eq!(result2.details, Some("itemization is empty".to_string()));
  }

  #[test]
  fn allow_empty_itemization_if_totals_zero() {
    let rule_valid_serde_json_value = serde_json::json!({
      "header": { "total": 0, "subtotal": 0 },
      "itemization": {
        "general": null,
        "lodging": null,
        "ecommerce": null,
        "car_rental": null,
        "transit_route": null,
        "subscription": null,
        "flight": null
      }
    });

    let result = itemization_should_should_not_be_empty_if_totals_greater_than_zero(
      &rule_valid_serde_json_value,
    );
    assert!(result.is_none());

    let rule_valid_serde_json_value = serde_json::json!({
      "header": { "total": 0, "subtotal": 0 },
      "itemization": {}
    });

    let result = itemization_should_should_not_be_empty_if_totals_greater_than_zero(
      &rule_valid_serde_json_value,
    );
    assert!(result.is_none());
  }
}