feat: Add new Rhai example demonstrating payment flow
- Add a new Rhai example showcasing complete payment flow for company registration. This includes company creation, payment record creation, successful payment processing, status updates, and handling failed and refunded payments. - Add new example demonstrating payment integration in Rhai scripting. This example showcases the usage of various payment status methods and verifies data from the database after processing payments. - Add new examples to Cargo.toml to facilitate building and running the examples. This makes it easier to integrate and test payment functionality using Rhai scripting.
This commit is contained in:
@@ -1,19 +1,21 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use heromodels_core::{BaseModelData, Model, IndexKey, IndexKeyBuilder, Index};
|
||||
use rhai::{CustomType, TypeBuilder}; // For #[derive(CustomType)]
|
||||
use heromodels_core::BaseModelData;
|
||||
use heromodels_derive::model;
|
||||
use rhai::{CustomType, TypeBuilder};
|
||||
use serde::{Deserialize, Serialize}; // For #[derive(CustomType)]
|
||||
|
||||
// --- Enums ---
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub enum CompanyStatus {
|
||||
Active,
|
||||
Inactive,
|
||||
Suspended,
|
||||
PendingPayment, // Company created but payment not completed
|
||||
Active, // Payment completed, company is active
|
||||
Suspended, // Company suspended (e.g., payment issues)
|
||||
Inactive, // Company deactivated
|
||||
}
|
||||
|
||||
impl Default for CompanyStatus {
|
||||
fn default() -> Self {
|
||||
CompanyStatus::Inactive
|
||||
CompanyStatus::PendingPayment
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +36,7 @@ impl Default for BusinessType {
|
||||
|
||||
// --- Company Struct ---
|
||||
|
||||
#[model]
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, CustomType)] // Added CustomType
|
||||
pub struct Company {
|
||||
pub base_data: BaseModelData,
|
||||
@@ -51,55 +54,11 @@ pub struct Company {
|
||||
pub status: CompanyStatus,
|
||||
}
|
||||
|
||||
// --- Model Trait Implementation ---
|
||||
|
||||
impl Model for Company {
|
||||
fn db_prefix() -> &'static str {
|
||||
"company"
|
||||
}
|
||||
|
||||
fn get_id(&self) -> u32 {
|
||||
self.base_data.id
|
||||
}
|
||||
|
||||
fn base_data_mut(&mut self) -> &mut BaseModelData {
|
||||
&mut self.base_data
|
||||
}
|
||||
|
||||
// Override db_keys to provide custom indexes if needed
|
||||
fn db_keys(&self) -> Vec<IndexKey> {
|
||||
vec![
|
||||
IndexKeyBuilder::new("name").value(self.name.clone()).build(),
|
||||
IndexKeyBuilder::new("registration_number").value(self.registration_number.clone()).build(),
|
||||
// Add other relevant keys, e.g., by status or type if frequently queried
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
// --- Index Implementations (Example) ---
|
||||
|
||||
pub struct CompanyNameIndex;
|
||||
impl Index for CompanyNameIndex {
|
||||
type Model = Company;
|
||||
type Key = str;
|
||||
fn key() -> &'static str {
|
||||
"name"
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CompanyRegistrationNumberIndex;
|
||||
impl Index for CompanyRegistrationNumberIndex {
|
||||
type Model = Company;
|
||||
type Key = str;
|
||||
fn key() -> &'static str {
|
||||
"registration_number"
|
||||
}
|
||||
}
|
||||
|
||||
// --- Builder Pattern ---
|
||||
|
||||
impl Company {
|
||||
pub fn new(name: String, registration_number: String, incorporation_date: i64) -> Self { // incorporation_date to i64
|
||||
pub fn new(name: String, registration_number: String, incorporation_date: i64) -> Self {
|
||||
// incorporation_date to i64
|
||||
Self {
|
||||
base_data: BaseModelData::new(),
|
||||
name,
|
||||
|
@@ -2,23 +2,24 @@
|
||||
// Sub-modules will be declared here
|
||||
|
||||
pub mod company;
|
||||
pub mod payment;
|
||||
pub mod product;
|
||||
// pub mod sale;
|
||||
// pub mod shareholder;
|
||||
// pub mod user;
|
||||
|
||||
// Re-export main types from sub-modules
|
||||
pub use company::{Company, CompanyStatus, BusinessType};
|
||||
pub use company::{BusinessType, Company, CompanyStatus};
|
||||
pub use payment::{Payment, PaymentStatus};
|
||||
pub mod shareholder;
|
||||
pub use product::{Product, ProductComponent, ProductStatus, ProductType};
|
||||
pub use shareholder::{Shareholder, ShareholderType};
|
||||
pub use product::{Product, ProductType, ProductStatus, ProductComponent};
|
||||
|
||||
pub mod sale;
|
||||
pub use sale::{Sale, SaleItem, SaleStatus};
|
||||
|
||||
// pub use user::{User}; // Assuming a simple User model for now
|
||||
|
||||
|
||||
#[cfg(feature = "rhai")]
|
||||
pub mod rhai;
|
||||
#[cfg(feature = "rhai")]
|
||||
|
216
heromodels/src/models/biz/payment.rs
Normal file
216
heromodels/src/models/biz/payment.rs
Normal file
@@ -0,0 +1,216 @@
|
||||
use heromodels_core::BaseModelData;
|
||||
use heromodels_derive::model;
|
||||
use rhai::{CustomType, TypeBuilder};
|
||||
use serde::{Deserialize, Serialize}; // For #[derive(CustomType)]
|
||||
|
||||
// --- Enums ---
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub enum PaymentStatus {
|
||||
Pending,
|
||||
Processing,
|
||||
Completed,
|
||||
Failed,
|
||||
Refunded,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for PaymentStatus {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
PaymentStatus::Pending => write!(f, "Pending"),
|
||||
PaymentStatus::Processing => write!(f, "Processing"),
|
||||
PaymentStatus::Completed => write!(f, "Completed"),
|
||||
PaymentStatus::Failed => write!(f, "Failed"),
|
||||
PaymentStatus::Refunded => write!(f, "Refunded"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for PaymentStatus {
|
||||
fn default() -> Self {
|
||||
PaymentStatus::Pending
|
||||
}
|
||||
}
|
||||
|
||||
// --- Payment Struct ---
|
||||
#[model]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, CustomType)]
|
||||
pub struct Payment {
|
||||
pub base_data: BaseModelData,
|
||||
|
||||
// Stripe payment intent ID for tracking
|
||||
#[index]
|
||||
pub payment_intent_id: String,
|
||||
|
||||
// Reference to the company this payment is for
|
||||
#[index]
|
||||
pub company_id: u32,
|
||||
|
||||
// Payment plan details
|
||||
pub payment_plan: String, // "monthly", "yearly", "two_year"
|
||||
pub setup_fee: f64,
|
||||
pub monthly_fee: f64,
|
||||
pub total_amount: f64,
|
||||
pub currency: String, // "usd"
|
||||
|
||||
pub status: PaymentStatus,
|
||||
pub stripe_customer_id: Option<String>,
|
||||
pub created_at: i64, // Timestamp
|
||||
pub completed_at: Option<i64>, // Completion timestamp
|
||||
}
|
||||
|
||||
// Model trait implementation is automatically generated by #[model] attribute
|
||||
|
||||
// --- Builder Pattern ---
|
||||
|
||||
impl Payment {
|
||||
pub fn new(
|
||||
payment_intent_id: String,
|
||||
company_id: u32,
|
||||
payment_plan: String,
|
||||
setup_fee: f64,
|
||||
monthly_fee: f64,
|
||||
total_amount: f64,
|
||||
) -> Self {
|
||||
let now = chrono::Utc::now().timestamp();
|
||||
Self {
|
||||
base_data: BaseModelData::new(),
|
||||
payment_intent_id,
|
||||
company_id,
|
||||
payment_plan,
|
||||
setup_fee,
|
||||
monthly_fee,
|
||||
total_amount,
|
||||
currency: "usd".to_string(), // Default to USD
|
||||
status: PaymentStatus::default(),
|
||||
stripe_customer_id: None,
|
||||
created_at: now,
|
||||
completed_at: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn payment_intent_id(mut self, payment_intent_id: String) -> Self {
|
||||
self.payment_intent_id = payment_intent_id;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn company_id(mut self, company_id: u32) -> Self {
|
||||
self.company_id = company_id;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn payment_plan(mut self, payment_plan: String) -> Self {
|
||||
self.payment_plan = payment_plan;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn setup_fee(mut self, setup_fee: f64) -> Self {
|
||||
self.setup_fee = setup_fee;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn monthly_fee(mut self, monthly_fee: f64) -> Self {
|
||||
self.monthly_fee = monthly_fee;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn total_amount(mut self, total_amount: f64) -> Self {
|
||||
self.total_amount = total_amount;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn status(mut self, status: PaymentStatus) -> Self {
|
||||
self.status = status;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn stripe_customer_id(mut self, stripe_customer_id: Option<String>) -> Self {
|
||||
self.stripe_customer_id = stripe_customer_id;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn currency(mut self, currency: String) -> Self {
|
||||
self.currency = currency;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn created_at(mut self, created_at: i64) -> Self {
|
||||
self.created_at = created_at;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn completed_at(mut self, completed_at: Option<i64>) -> Self {
|
||||
self.completed_at = completed_at;
|
||||
self
|
||||
}
|
||||
|
||||
// --- Business Logic Methods ---
|
||||
|
||||
/// Complete the payment with optional Stripe customer ID
|
||||
pub fn complete_payment(mut self, stripe_customer_id: Option<String>) -> Self {
|
||||
self.status = PaymentStatus::Completed;
|
||||
self.stripe_customer_id = stripe_customer_id;
|
||||
self.completed_at = Some(chrono::Utc::now().timestamp());
|
||||
self.base_data.update_modified();
|
||||
self
|
||||
}
|
||||
|
||||
/// Mark payment as processing
|
||||
pub fn process_payment(mut self) -> Self {
|
||||
self.status = PaymentStatus::Processing;
|
||||
self.base_data.update_modified();
|
||||
self
|
||||
}
|
||||
|
||||
/// Mark payment as failed
|
||||
pub fn fail_payment(mut self) -> Self {
|
||||
self.status = PaymentStatus::Failed;
|
||||
self.base_data.update_modified();
|
||||
self
|
||||
}
|
||||
|
||||
/// Refund the payment
|
||||
pub fn refund_payment(mut self) -> Self {
|
||||
self.status = PaymentStatus::Refunded;
|
||||
self.base_data.update_modified();
|
||||
self
|
||||
}
|
||||
|
||||
/// Check if payment is completed
|
||||
pub fn is_completed(&self) -> bool {
|
||||
self.status == PaymentStatus::Completed
|
||||
}
|
||||
|
||||
/// Check if payment is pending
|
||||
pub fn is_pending(&self) -> bool {
|
||||
self.status == PaymentStatus::Pending
|
||||
}
|
||||
|
||||
/// Check if payment is processing
|
||||
pub fn is_processing(&self) -> bool {
|
||||
self.status == PaymentStatus::Processing
|
||||
}
|
||||
|
||||
/// Check if payment has failed
|
||||
pub fn has_failed(&self) -> bool {
|
||||
self.status == PaymentStatus::Failed
|
||||
}
|
||||
|
||||
/// Check if payment is refunded
|
||||
pub fn is_refunded(&self) -> bool {
|
||||
self.status == PaymentStatus::Refunded
|
||||
}
|
||||
|
||||
// Setter for base_data fields if needed directly
|
||||
pub fn set_base_created_at(mut self, created_at: i64) -> Self {
|
||||
self.base_data.created_at = created_at;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_base_modified_at(mut self, modified_at: i64) -> Self {
|
||||
self.base_data.modified_at = modified_at;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
// Tests for Payment model are located in tests/payment.rs
|
File diff suppressed because it is too large
Load Diff
@@ -14,7 +14,7 @@ pub mod projects;
|
||||
pub use core::Comment;
|
||||
pub use userexample::User;
|
||||
// pub use productexample::Product; // Temporarily remove
|
||||
pub use biz::{Sale, SaleItem, SaleStatus};
|
||||
pub use biz::{Payment, PaymentStatus, Sale, SaleItem, SaleStatus};
|
||||
pub use calendar::{AttendanceStatus, Attendee, Calendar, Event};
|
||||
pub use finance::marketplace::{Bid, BidStatus, Listing, ListingStatus, ListingType};
|
||||
pub use finance::{Account, Asset, AssetType};
|
||||
|
Reference in New Issue
Block a user