add deep diff pd

This commit is contained in:
Pakin 2025-09-05 08:56:21 +07:00
parent 64a7dae017
commit 6ccc6cb779
5 changed files with 67 additions and 53 deletions

View file

@ -48,6 +48,7 @@ macro_rules! update_each_field {
/// about its structure.
/// * `MaterialCode`: MaterialCode is a vector (array) that contains instances of the MaterialCode
/// struct.
#[allow(non_snake_case)]
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Recipe {
pub Timestamp: String,
@ -91,6 +92,8 @@ impl Recipe {
}
}
/// Get undefined fields from the recipe. This may included newer fields.
///
pub fn get_additional_fields(&self) -> Option<Value> {
if self.extra.is_empty() {
return None;
@ -115,12 +118,14 @@ impl Recipe {
.find(|&r| r.productCode == product_code)
}
/// Similar to `search_pd` but ignoring exacted matching.
pub fn search_pd_by_no_country_code(&self, product_code: String) -> Option<&Recipe01> {
self.Recipe01
.iter()
.find(|&r| r.productCode.contains(&product_code))
}
/// Mulitple product code searching with parallel and no exact matching.
pub fn search_multi_in_parallel(&self, pds: Vec<String>) -> Vec<Option<Recipe01>> {
let mut found = Vec::new();
@ -136,6 +141,7 @@ impl Recipe {
found
}
/// Get position of product code in the recipe's `Recipe01`
pub fn get_pd_index(&self, product_code: String) -> usize {
self.Recipe01
.iter()
@ -143,26 +149,32 @@ impl Recipe {
.unwrap()
}
/// Search expected material setting if existed
pub fn search_material_settings(&self, material_code: String) -> Option<&MaterialSetting> {
self.MaterialSetting
.iter()
.find(|r| r.id.to_string() == material_code)
}
/// Search expected topping list if existed
pub fn search_topping_list(&self, id: String) -> Option<&ToppingList> {
self.Topping.ToppingList.iter().find(|&r| r.id == id)
}
/// Search expected topping group if existed
pub fn search_topping_group(&self, id: String) -> Option<&ToppingGroup> {
self.Topping.ToppingGroup.iter().find(|&r| r.groupID == id)
}
/// Search expected material code if existed
pub fn search_material_code(&self, material_code: String) -> Option<&MaterialCode> {
self.MaterialCode
.iter()
.find(|&r| r.materialID == material_code)
}
/// Check if expected product code is different in both recipes.
/// This may return `false` if either one did not have this product code.
pub fn diff_pd_between_recipes(&self, another_recipe: &Recipe, product_code: String) -> bool {
let menu1 = Self::search_pd(self, product_code.clone());
let menu2 = Self::search_pd(another_recipe, product_code.clone());
@ -177,6 +189,7 @@ impl Recipe {
menu1 == menu2
}
/// Similar to `diff_pd_between_recipes` but will not check exacted matching.
pub fn diff_pd_between_recipes_ignore_country(
&self,
another_recipe: &Recipe,
@ -195,6 +208,35 @@ impl Recipe {
menu1 == menu2
}
pub fn deep_diff_pd_between_recipes(
&self,
another_recipe: &Recipe,
product_code: String,
) -> Vec<(String, bool)> {
let mut result = Vec::new();
let self_recipe = Self::search_pd_by_no_country_code(self, product_code.clone());
let another_recipe =
Self::search_pd_by_no_country_code(another_recipe, product_code.clone());
if self_recipe.is_some() && another_recipe.is_some() {
let sr = self_recipe.unwrap();
let ar = another_recipe.unwrap();
let diff_field_list = sr.compare(ar);
for key in sr.to_map().keys() {
if diff_field_list.contains(key) {
result.push((key.to_string(), true));
} else {
result.push((key.to_string(), false));
}
}
}
result
}
pub fn diff_material_setting_between_recipes(
&self,
another_recipe: &Recipe,
@ -522,6 +564,7 @@ impl Recipe {
pub fn add_prefix_country_code(&mut self) {}
}
#[allow(non_snake_case)]
fn StrShowTextErrorDefault() -> Option<Vec<Value>> {
Some(vec![
Value::String("เต่าบินเกิดเหตุขัดข้อง".into()),
@ -569,6 +612,7 @@ impl PartialRecipe {
/// temperature setting for a machine.
/// * `temperatureMin`: The `temperatureMin` property is of type `Value`. It represents the minimum
/// temperature setting for the machine.
#[allow(non_snake_case)]
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)]
pub struct MachineSetting {
pub Comment: Option<Vec<String>>,
@ -659,26 +703,32 @@ impl CommonRecipeTrait for MachineSetting {
}
}
#[allow(non_snake_case)]
fn BlankString() -> Option<String> {
Some("".to_string())
}
#[allow(non_snake_case)]
fn BlankBool() -> Option<bool> {
Some(false)
}
#[allow(non_snake_case)]
fn BlankVecString() -> Option<Vec<String>> {
Some(vec![].into())
}
#[allow(non_snake_case)]
fn BlankVecRecipe() -> Option<Vec<Recipe01>> {
Some(vec![].into())
}
#[allow(non_snake_case)]
fn BlankVecMenuTopping() -> Option<Vec<MenuToppingList>> {
Some(vec![].into())
}
#[allow(non_snake_case)]
fn BlankOtherStrShowTextError() -> Option<Vec<String>> {
Some(vec![
"".to_string(),
@ -692,14 +742,17 @@ fn BlankOtherStrShowTextError() -> Option<Vec<String>> {
])
}
#[allow(non_snake_case)]
fn BlankValueString() -> Option<Value> {
Some(Value::String("".into()))
}
#[allow(non_snake_case, dead_code)]
fn BlankValueArray() -> Option<Value> {
Some(Value::Array(vec![].into()))
}
#[allow(non_snake_case, dead_code)]
fn BlankValueBool() -> Option<Value> {
Some(Value::Bool(false.into()))
}
@ -754,6 +807,7 @@ fn BlankValueBool() -> Option<Value> {
/// * `useGram`: A boolean value indicating whether the recipe uses grams for measurement or not.
/// * `weight_float`: The `weight_float` property is of type `Value` and represents the weight of the
/// recipe as a floating-point number.
#[allow(non_snake_case)]
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)]
pub struct Recipe01 {
#[serde(default = "BlankString")]
@ -1371,6 +1425,7 @@ impl Recipe01 {
/// water in the recipe.
/// * `waterYield`: The `waterYield` property represents the amount of water produced or obtained from
/// the recipe.
#[allow(non_snake_case)]
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)]
pub struct RecipeList {
pub MixOrder: Value,
@ -1465,6 +1520,7 @@ impl RecipeList {
/// maximum number of retries for a payment.
/// * `RawMaterialUnit`: The `RawMaterialUnit` property is an optional string that represents the unit
/// of measurement for the raw material.
#[allow(non_snake_case)]
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)]
pub struct MaterialSetting {
pub AlarmIDWhenOffline: Value,
@ -1576,6 +1632,7 @@ impl MachineSetting {
}
}
#[allow(non_snake_case)]
fn BlankListGroupID() -> Option<Vec<Value>> {
Some(vec![
Value::String("0".into()),
@ -1585,6 +1642,7 @@ fn BlankListGroupID() -> Option<Vec<Value>> {
])
}
#[allow(non_snake_case)]
fn BlankGroupID() -> Option<Value> {
Some(Value::String("0".into()))
}
@ -1600,6 +1658,7 @@ fn BlankGroupID() -> Option<Value> {
/// which the menu topping list belongs.
/// * `isUse`: The `isUse` property is a boolean value that indicates whether the menu topping list is
/// being used or not.
#[allow(non_snake_case)]
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)]
pub struct MenuToppingList {
#[serde(default = "BlankListGroupID")]
@ -1620,6 +1679,7 @@ pub struct MenuToppingList {
/// struct. Each ToppingGroup struct represents a group of toppings.
/// * `ToppingList`: The `ToppingList` property is a vector (dynamic array) that contains elements of
/// type `ToppingList`.
#[allow(non_snake_case)]
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)]
pub struct Topping {
pub ToppingGroup: Vec<ToppingGroup>,
@ -1643,6 +1703,7 @@ pub struct Topping {
/// * `name`: The `name` property is a string that represents the name of the topping group.
/// * `otherName`: The `otherName` property is a string that represents an alternative name for the
/// `ToppingGroup`. It can be used to provide additional information or a different name for the group.
#[allow(non_snake_case)]
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)]
pub struct ToppingGroup {
pub groupID: Value,
@ -1703,6 +1764,7 @@ impl ToppingGroup {
/// * `useGram`: A boolean value indicating whether the topping uses grams for measurement or not.
/// * `weight_float`: The `weight_float` property is of type `Value` and represents the weight of the
/// topping in float format.
#[allow(non_snake_case)]
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)]
pub struct ToppingList {
pub ExtendID: Value,
@ -1754,6 +1816,7 @@ impl ToppingList {
/// * `materialCode`: The `materialCode` property is an optional field that represents the code
/// associated with a material. It is of type `Option<String>`, which means it can either be
/// `Some(String)` if a value is present, or `None` if no value is provided.
#[allow(non_snake_case)]
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)]
pub struct MaterialCode {
#[serde(default = "BlankString")]

View file

@ -5,7 +5,7 @@ use std::collections::HashMap;
use crate::models::recipe::*;
use crate::recipe_functions::common::*;
/// Version 2 of `models::Recipe`
/// Version 2 of `models::Recipe`, WIP
///
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct VersionRecipe {