use crate::db::Collection; // For db.set and db.get_by_id use crate::db::Db; use crate::db::hero::OurDB; use rhai::plugin::*; use rhai::{Dynamic, Engine, EvalAltResult, INT, Module, Position}; use std::mem; use std::sync::Arc; use super::company::{BusinessType, Company, CompanyStatus}; use crate::models::biz::product::{Product, ProductComponent, ProductStatus, ProductType}; use crate::models::biz::sale::{Sale, SaleItem, SaleStatus}; use crate::models::biz::shareholder::{Shareholder, ShareholderType}; use heromodels_core::Model; type RhaiCompany = Company; type RhaiShareholder = Shareholder; type RhaiProduct = Product; type RhaiProductComponent = ProductComponent; type RhaiSale = Sale; type RhaiSaleItem = SaleItem; // Helper to convert i64 from Rhai to u32 for IDs fn id_from_i64_to_u32(id_i64: i64) -> Result> { u32::try_from(id_i64).map_err(|_| { Box::new(EvalAltResult::ErrorArithmetic( format!("Failed to convert ID '{}' to u32", id_i64).into(), Position::NONE, )) }) } #[export_module] mod rhai_biz_module { // --- Company Functions --- #[rhai_fn(name = "new_company")] pub fn new_company() -> RhaiCompany { Company::new() } // Company builder methods #[rhai_fn(name = "name", return_raw, global, pure)] pub fn company_name( company: &mut RhaiCompany, name: String, ) -> Result> { let owned_company = mem::take(company); *company = owned_company.name(name); Ok(company.clone()) } #[rhai_fn(name = "fiscal_year_end", return_raw, global, pure)] pub fn company_fiscal_year_end( company: &mut RhaiCompany, fiscal_year_end: String, ) -> Result> { let owned_company = mem::take(company); *company = owned_company.fiscal_year_end(fiscal_year_end); Ok(company.clone()) } #[rhai_fn(name = "registration_number", return_raw, global, pure)] pub fn company_registration_number( company: &mut RhaiCompany, reg_num: String, ) -> Result> { let owned_company = mem::take(company); *company = owned_company.registration_number(reg_num); Ok(company.clone()) } #[rhai_fn(name = "incorporation_date", return_raw, global, pure)] pub fn company_incorporation_date( company: &mut RhaiCompany, date: i64, ) -> Result> { let owned_company = mem::take(company); *company = owned_company.incorporation_date(date); Ok(company.clone()) } #[rhai_fn(name = "status", return_raw, global, pure)] pub fn company_status( company: &mut RhaiCompany, status: CompanyStatus, ) -> Result> { let owned_company = mem::take(company); *company = owned_company.status(status); Ok(company.clone()) } #[rhai_fn(name = "business_type", return_raw, global, pure)] pub fn company_business_type( company: &mut RhaiCompany, business_type: BusinessType, ) -> Result> { let owned_company = mem::take(company); *company = owned_company.business_type(business_type); Ok(company.clone()) } // Company getters #[rhai_fn(name = "get_company_id")] pub fn get_company_id(company: &mut RhaiCompany) -> i64 { company.get_id() as i64 } #[rhai_fn(name = "get_company_name")] pub fn get_company_name(company: &mut RhaiCompany) -> String { company.name.clone() } #[rhai_fn(name = "get_company_created_at")] pub fn get_company_created_at(company: &mut RhaiCompany) -> i64 { company.base_data.created_at } #[rhai_fn(name = "get_company_modified_at")] pub fn get_company_modified_at(company: &mut RhaiCompany) -> i64 { company.base_data.modified_at } #[rhai_fn(name = "get_company_registration_number")] pub fn get_company_registration_number(company: &mut RhaiCompany) -> String { company.registration_number.clone() } #[rhai_fn(name = "get_company_fiscal_year_end")] pub fn get_company_fiscal_year_end(company: &mut RhaiCompany) -> String { company.fiscal_year_end.clone() } #[rhai_fn(name = "get_company_incorporation_date")] pub fn get_company_incorporation_date(company: &mut RhaiCompany) -> i64 { company.incorporation_date } #[rhai_fn(name = "get_company_status")] pub fn get_company_status(company: &mut RhaiCompany) -> CompanyStatus { company.status.clone() } #[rhai_fn(name = "get_company_business_type")] pub fn get_company_business_type(company: &mut RhaiCompany) -> BusinessType { company.business_type.clone() } // --- Shareholder Functions --- #[rhai_fn(name = "new_shareholder")] pub fn new_shareholder() -> RhaiShareholder { Shareholder::new() } // Shareholder builder methods #[rhai_fn(name = "name", return_raw, global, pure)] pub fn shareholder_name( shareholder: &mut RhaiShareholder, name: String, ) -> Result> { let owned_shareholder = mem::take(shareholder); *shareholder = owned_shareholder.name(name); Ok(shareholder.clone()) } #[rhai_fn(name = "company_id", return_raw, global, pure)] pub fn shareholder_company_id( shareholder: &mut RhaiShareholder, company_id: i64, ) -> Result> { let company_id_u32 = id_from_i64_to_u32(company_id)?; let owned_shareholder = mem::take(shareholder); *shareholder = owned_shareholder.company_id(company_id_u32); Ok(shareholder.clone()) } #[rhai_fn(name = "share_count", return_raw, global, pure)] pub fn shareholder_share_count( shareholder: &mut RhaiShareholder, share_count: f64, ) -> Result> { shareholder.shares = share_count; Ok(shareholder.clone()) } #[rhai_fn(name = "type_", return_raw, global, pure)] pub fn shareholder_type( shareholder: &mut RhaiShareholder, type_: ShareholderType, ) -> Result> { let owned_shareholder = mem::take(shareholder); *shareholder = owned_shareholder.type_(type_); Ok(shareholder.clone()) } // Shareholder getters #[rhai_fn(name = "get_shareholder_id")] pub fn get_shareholder_id(shareholder: &mut RhaiShareholder) -> i64 { shareholder.get_id() as i64 } #[rhai_fn(name = "get_shareholder_name")] pub fn get_shareholder_name(shareholder: &mut RhaiShareholder) -> String { shareholder.name.clone() } #[rhai_fn(name = "get_shareholder_company_id")] pub fn get_shareholder_company_id(shareholder: &mut RhaiShareholder) -> i64 { shareholder.company_id as i64 } #[rhai_fn(name = "get_shareholder_share_count")] pub fn get_shareholder_share_count(shareholder: &mut RhaiShareholder) -> i64 { shareholder.shares as i64 } #[rhai_fn(name = "get_shareholder_type")] pub fn get_shareholder_type(shareholder: &mut RhaiShareholder) -> ShareholderType { shareholder.type_.clone() } // --- ProductComponent Functions --- #[rhai_fn(name = "new_product_component")] pub fn new_product_component() -> RhaiProductComponent { ProductComponent::new() } // ProductComponent builder methods #[rhai_fn(name = "name", return_raw, global, pure)] pub fn product_component_name( component: &mut RhaiProductComponent, name: String, ) -> Result> { let owned_component = mem::take(component); *component = owned_component.name(name); Ok(component.clone()) } #[rhai_fn(name = "description", return_raw, global, pure)] pub fn product_component_description( component: &mut RhaiProductComponent, description: String, ) -> Result> { let owned_component = mem::take(component); *component = owned_component.description(description); Ok(component.clone()) } #[rhai_fn(name = "quantity", return_raw, global, pure)] pub fn product_component_quantity( component: &mut RhaiProductComponent, quantity: i64, ) -> Result> { let owned_component = mem::take(component); *component = owned_component.quantity(quantity as u32); Ok(component.clone()) } // ProductComponent getters #[rhai_fn(name = "get_product_component_name")] pub fn get_product_component_name(component: &mut RhaiProductComponent) -> String { component.name.clone() } #[rhai_fn(name = "get_product_component_description")] pub fn get_product_component_description(component: &mut RhaiProductComponent) -> String { component.description.clone() } #[rhai_fn(name = "get_product_component_quantity")] pub fn get_product_component_quantity(component: &mut RhaiProductComponent) -> i64 { component.quantity as i64 } // --- Product Functions --- #[rhai_fn(name = "new_product")] pub fn new_product() -> RhaiProduct { Product::new() } // Product builder methods #[rhai_fn(name = "name", return_raw, global, pure)] pub fn product_name( product: &mut RhaiProduct, name: String, ) -> Result> { let owned_product = mem::take(product); *product = owned_product.name(name); Ok(product.clone()) } #[rhai_fn(name = "description", return_raw, global, pure)] pub fn product_description( product: &mut RhaiProduct, description: String, ) -> Result> { let owned_product = mem::take(product); *product = owned_product.description(description); Ok(product.clone()) } #[rhai_fn(name = "price", return_raw, global, pure)] pub fn product_price( product: &mut RhaiProduct, price: f64, ) -> Result> { let owned_product = mem::take(product); *product = owned_product.price(price); Ok(product.clone()) } #[rhai_fn(name = "type_", return_raw, global, pure)] pub fn product_type( product: &mut RhaiProduct, type_: ProductType, ) -> Result> { let owned_product = mem::take(product); *product = owned_product.type_(type_); Ok(product.clone()) } #[rhai_fn(name = "category", return_raw, global, pure)] pub fn product_category( product: &mut RhaiProduct, category: String, ) -> Result> { let owned_product = mem::take(product); *product = owned_product.category(category); Ok(product.clone()) } #[rhai_fn(name = "status", return_raw, global, pure)] pub fn product_status( product: &mut RhaiProduct, status: ProductStatus, ) -> Result> { let owned_product = mem::take(product); *product = owned_product.status(status); Ok(product.clone()) } #[rhai_fn(name = "max_amount", return_raw, global, pure)] pub fn product_max_amount( product: &mut RhaiProduct, max_amount: i64, ) -> Result> { let owned_product = mem::take(product); *product = owned_product.max_amount(max_amount as u16); Ok(product.clone()) } #[rhai_fn(name = "purchase_till", return_raw, global, pure)] pub fn product_purchase_till( product: &mut RhaiProduct, purchase_till: i64, ) -> Result> { let owned_product = mem::take(product); *product = owned_product.purchase_till(purchase_till); Ok(product.clone()) } #[rhai_fn(name = "active_till", return_raw, global, pure)] pub fn product_active_till( product: &mut RhaiProduct, active_till: i64, ) -> Result> { let owned_product = mem::take(product); *product = owned_product.active_till(active_till); Ok(product.clone()) } #[rhai_fn(name = "add_component", return_raw, global, pure)] pub fn product_add_component( product: &mut RhaiProduct, component: RhaiProductComponent, ) -> Result> { let owned_product = mem::take(product); *product = owned_product.add_component(component); Ok(product.clone()) } #[rhai_fn(name = "components", return_raw, global, pure)] pub fn product_components( product: &mut RhaiProduct, components: Vec, ) -> Result> { let owned_product = mem::take(product); *product = owned_product.components(components); Ok(product.clone()) } // Product getters #[rhai_fn(name = "get_product_id")] pub fn get_product_id(product: &mut RhaiProduct) -> i64 { product.get_id() as i64 } #[rhai_fn(name = "get_product_name")] pub fn get_product_name(product: &mut RhaiProduct) -> String { product.name.clone() } #[rhai_fn(name = "get_product_description")] pub fn get_product_description(product: &mut RhaiProduct) -> String { product.description.clone() } #[rhai_fn(name = "get_product_price")] pub fn get_product_price(product: &mut RhaiProduct) -> f64 { product.price } #[rhai_fn(name = "get_product_type")] pub fn get_product_type(product: &mut RhaiProduct) -> ProductType { product.type_.clone() } #[rhai_fn(name = "get_product_category")] pub fn get_product_category(product: &mut RhaiProduct) -> String { product.category.clone() } #[rhai_fn(name = "get_product_status")] pub fn get_product_status(product: &mut RhaiProduct) -> ProductStatus { product.status.clone() } #[rhai_fn(name = "get_product_max_amount")] pub fn get_product_max_amount(product: &mut RhaiProduct) -> i64 { product.max_amount as i64 } #[rhai_fn(name = "get_product_purchase_till")] pub fn get_product_purchase_till(product: &mut RhaiProduct) -> i64 { product.purchase_till } #[rhai_fn(name = "get_product_active_till")] pub fn get_product_active_till(product: &mut RhaiProduct) -> i64 { product.active_till } #[rhai_fn(name = "get_product_components")] pub fn get_product_components(product: &mut RhaiProduct) -> Vec { product.components.clone() } #[rhai_fn(name = "get_product_created_at")] pub fn get_product_created_at(product: &mut RhaiProduct) -> i64 { product.base_data.created_at } #[rhai_fn(name = "get_product_modified_at")] pub fn get_product_modified_at(product: &mut RhaiProduct) -> i64 { product.base_data.modified_at } #[rhai_fn(name = "get_product_comments")] pub fn get_product_comments(product: &mut RhaiProduct) -> Vec { product .base_data .comments .iter() .map(|&id| id as i64) .collect() } // --- SaleItem Functions --- #[rhai_fn(name = "new_sale_item")] pub fn new_sale_item() -> RhaiSaleItem { SaleItem::new() } // SaleItem builder methods #[rhai_fn(name = "name", return_raw, global, pure)] pub fn sale_item_name( item: &mut RhaiSaleItem, name: String, ) -> Result> { let owned_item = mem::take(item); *item = owned_item.name(name); Ok(item.clone()) } #[rhai_fn(name = "price", return_raw, global, pure)] pub fn sale_item_price( item: &mut RhaiSaleItem, price: f64, ) -> Result> { item.unit_price = price; Ok(item.clone()) } #[rhai_fn(name = "quantity", return_raw, global, pure)] pub fn sale_item_quantity( item: &mut RhaiSaleItem, quantity: i64, ) -> Result> { let owned_item = mem::take(item); *item = owned_item.quantity(quantity.try_into().unwrap()); Ok(item.clone()) } #[rhai_fn(name = "product_id", return_raw, global, pure)] pub fn sale_item_product_id( item: &mut RhaiSaleItem, product_id: i64, ) -> Result> { let product_id_u32 = id_from_i64_to_u32(product_id)?; let owned_item = mem::take(item); *item = owned_item.product_id(product_id_u32); Ok(item.clone()) } // SaleItem getters #[rhai_fn(name = "get_sale_item_name")] pub fn get_sale_item_name(item: &mut RhaiSaleItem) -> String { item.name.clone() } #[rhai_fn(name = "get_sale_item_price")] pub fn get_sale_item_price(item: &mut RhaiSaleItem) -> f64 { item.unit_price } #[rhai_fn(name = "get_sale_item_quantity")] pub fn get_sale_item_quantity(item: &mut RhaiSaleItem) -> i64 { item.quantity as i64 } #[rhai_fn(name = "get_sale_item_product_id")] pub fn get_sale_item_product_id(item: &mut RhaiSaleItem) -> i64 { item.product_id as i64 } // --- Sale Functions --- #[rhai_fn(name = "new_sale")] pub fn new_sale() -> RhaiSale { Sale::new() } #[rhai_fn(name = "transaction_id", return_raw, global, pure)] pub fn sale_transaction_id( sale: &mut RhaiSale, transaction_id: u32, ) -> Result> { sale.transaction_id = transaction_id; Ok(sale.clone()) } #[rhai_fn(name = "status", return_raw, global, pure)] pub fn sale_status( sale: &mut RhaiSale, status: SaleStatus, ) -> Result> { let owned_sale = mem::take(sale); *sale = owned_sale.status(status); Ok(sale.clone()) } #[rhai_fn(name = "add_item", return_raw, global, pure)] pub fn sale_add_item( sale: &mut RhaiSale, item: RhaiSaleItem, ) -> Result> { let owned_sale = mem::take(sale); *sale = owned_sale.add_item(item); Ok(sale.clone()) } #[rhai_fn(name = "items", return_raw, global, pure)] pub fn sale_items( sale: &mut RhaiSale, items: Vec, ) -> Result> { let owned_sale = mem::take(sale); *sale = owned_sale.items(items); Ok(sale.clone()) } // Sale getters #[rhai_fn(name = "get_sale_id")] pub fn get_sale_id(sale: &mut RhaiSale) -> i64 { sale.get_id() as i64 } #[rhai_fn(name = "get_sale_transaction_id")] pub fn get_sale_transaction_id(sale: &mut RhaiSale) -> u32 { sale.transaction_id } #[rhai_fn(name = "get_sale_status")] pub fn get_sale_status(sale: &mut RhaiSale) -> SaleStatus { sale.status.clone() } #[rhai_fn(name = "get_sale_items")] pub fn get_sale_items(sale: &mut RhaiSale) -> Vec { sale.items.clone() } #[rhai_fn(name = "get_sale_created_at")] pub fn get_sale_created_at(sale: &mut RhaiSale) -> i64 { sale.base_data.created_at } #[rhai_fn(name = "get_sale_modified_at")] pub fn get_sale_modified_at(sale: &mut RhaiSale) -> i64 { sale.base_data.modified_at } #[rhai_fn(name = "get_sale_comments")] pub fn get_sale_comments(sale: &mut RhaiSale) -> Vec { sale.base_data .comments .iter() .map(|&id| id as i64) .collect() } } pub fn register_biz_rhai_module(engine: &mut Engine, db: Arc) { // Register the exported module globally let module = exported_module!(rhai_biz_module); engine.register_global_module(module.into()); // Create a new module for database operations let mut db_module = Module::new(); // Database operations will obtain fresh collection handles directly. // Add database functions for Company let db_for_set_company = Arc::clone(&db); db_module.set_native_fn( "set_company", move |company: Company| -> Result> { let company_collection_set = db_for_set_company .collection::() .expect("Failed to get company collection for set in closure"); company_collection_set .set(&company) .map(|(id_val, _)| id_val as INT) .map_err(|e| { Box::new(EvalAltResult::ErrorRuntime( format!("Failed to save company: {:?}", e).into(), Position::NONE, )) }) }, ); let db_for_get_company = Arc::clone(&db); db_module.set_native_fn( "get_company_by_id", move |id: INT| -> Result> { let company_collection_get = db_for_get_company .collection::() .expect("Failed to get company collection for get in closure"); let id_u32 = id_from_i64_to_u32(id)?; company_collection_get .get_by_id(id_u32) .map(Dynamic::from) .map_err(|e| { Box::new(EvalAltResult::ErrorRuntime( format!("Failed to get company with id {}: {:?}", id, e).into(), Position::NONE, )) }) }, ); // Add database functions for Shareholder let db_for_set_shareholder = Arc::clone(&db); db_module.set_native_fn( "set_shareholder", move |shareholder: Shareholder| -> Result> { let shareholder_collection_set = db_for_set_shareholder .collection::() .expect("Failed to get shareholder collection for set in closure"); shareholder_collection_set .set(&shareholder) .map(|(id_val, _)| id_val as INT) .map_err(|e| { Box::new(EvalAltResult::ErrorRuntime( format!("Failed to save shareholder: {:?}", e).into(), Position::NONE, )) }) }, ); let db_for_get_shareholder = Arc::clone(&db); db_module.set_native_fn( "get_shareholder_by_id", move |id: INT| -> Result> { let shareholder_collection_get = db_for_get_shareholder .collection::() .expect("Failed to get shareholder collection for get in closure"); let id_u32 = id_from_i64_to_u32(id)?; shareholder_collection_get .get_by_id(id_u32) .map(Dynamic::from) .map_err(|e| { Box::new(EvalAltResult::ErrorRuntime( format!("Failed to get shareholder with id {}: {:?}", id, e).into(), Position::NONE, )) }) }, ); // Add database functions for Product let db_for_set_product = Arc::clone(&db); db_module.set_native_fn( "set_product", move |product: Product| -> Result> { let product_collection_set = db_for_set_product .collection::() .expect("Failed to get product collection for set in closure"); product_collection_set .set(&product) .map(|(id_val, _)| id_val as INT) .map_err(|e| { Box::new(EvalAltResult::ErrorRuntime( format!("Failed to save product: {:?}", e).into(), Position::NONE, )) }) }, ); let db_for_get_product = Arc::clone(&db); db_module.set_native_fn( "get_product_by_id", move |id: INT| -> Result> { let product_collection_get = db_for_get_product .collection::() .expect("Failed to get product collection for get in closure"); let id_u32 = id_from_i64_to_u32(id)?; product_collection_get .get_by_id(id_u32) .map(Dynamic::from) .map_err(|e| { Box::new(EvalAltResult::ErrorRuntime( format!("Failed to get product with id {}: {:?}", id, e).into(), Position::NONE, )) }) }, ); // Add database functions for Sale let db_for_set_sale = Arc::clone(&db); db_module.set_native_fn( "set_sale", move |sale: Sale| -> Result> { let sale_collection_set = db_for_set_sale .collection::() .expect("Failed to get sale collection for set in closure"); sale_collection_set .set(&sale) .map(|(id_val, _)| id_val as INT) .map_err(|e| { Box::new(EvalAltResult::ErrorRuntime( format!("Failed to save sale: {:?}", e).into(), Position::NONE, )) }) }, ); let db_for_get_sale = Arc::clone(&db); db_module.set_native_fn( "get_sale_by_id", move |id: INT| -> Result> { let sale_collection_get = db_for_get_sale .collection::() .expect("Failed to get sale collection for get in closure"); let id_u32 = id_from_i64_to_u32(id)?; sale_collection_get .get_by_id(id_u32) .map(Dynamic::from) .map_err(|e| { Box::new(EvalAltResult::ErrorRuntime( format!("Failed to get sale with id {}: {:?}", id, e).into(), Position::NONE, )) }) }, ); // Register the database module globally engine.register_global_module(db_module.into()); println!("Successfully registered biz Rhai module using export_module approach."); }