implement payment dsl
This commit is contained in:
5
src/dsl/examples/payment/.env.example
Normal file
5
src/dsl/examples/payment/.env.example
Normal file
@@ -0,0 +1,5 @@
|
||||
# Copy this file to .env and replace with your actual Stripe API keys
|
||||
# Get your keys from: https://dashboard.stripe.com/apikeys
|
||||
|
||||
# Stripe Secret Key (starts with sk_test_ for test mode or sk_live_ for live mode)
|
||||
STRIPE_SECRET_KEY=sk_test_your_stripe_secret_key_here
|
58
src/dsl/examples/payment/README.md
Normal file
58
src/dsl/examples/payment/README.md
Normal file
@@ -0,0 +1,58 @@
|
||||
# Payment Example with Stripe Integration
|
||||
|
||||
This example demonstrates how to use the async HTTP API architecture to make real Stripe API calls from Rhai scripts.
|
||||
|
||||
## Setup
|
||||
|
||||
1. **Get Stripe API Keys**
|
||||
- Sign up at [Stripe Dashboard](https://dashboard.stripe.com)
|
||||
- Go to [API Keys](https://dashboard.stripe.com/apikeys)
|
||||
- Copy your **Secret key** (starts with `sk_test_` for test mode)
|
||||
|
||||
2. **Configure Environment**
|
||||
```bash
|
||||
# Copy the example file
|
||||
cp .env.example .env
|
||||
|
||||
# Edit .env and add your real Stripe secret key
|
||||
STRIPE_SECRET_KEY=sk_test_your_actual_key_here
|
||||
```
|
||||
|
||||
3. **Run the Example**
|
||||
```bash
|
||||
# From the rhailib root directory
|
||||
cd src/dsl && cargo run --example payment
|
||||
```
|
||||
|
||||
## What This Example Does
|
||||
|
||||
- **Loads environment variables** from `.env` file
|
||||
- **Configures async HTTP architecture** with real Stripe API credentials
|
||||
- **Creates Stripe objects** using the builder pattern:
|
||||
- Products
|
||||
- Prices (one-time and recurring)
|
||||
- Coupons (percentage and fixed amount)
|
||||
- Payment Intents
|
||||
- Subscriptions
|
||||
|
||||
## Architecture Features Demonstrated
|
||||
|
||||
- ✅ **Async HTTP calls** from synchronous Rhai scripts
|
||||
- ✅ **MPSC channel communication** between Rhai and async workers
|
||||
- ✅ **Environment variable loading** for secure API key management
|
||||
- ✅ **Error handling** with proper Stripe API error propagation
|
||||
- ✅ **Builder pattern** for creating complex Stripe objects
|
||||
- ✅ **Multi-threaded execution** with dedicated async worker threads
|
||||
|
||||
## Expected Output
|
||||
|
||||
With a valid Stripe API key, you'll see:
|
||||
```
|
||||
🔧 Configuring async HTTP client with timeouts...
|
||||
🚀 Async worker thread started
|
||||
🔄 Processing POST request to products
|
||||
📥 Stripe response: {"id":"prod_...","object":"product",...}
|
||||
✅ Product created successfully with ID: prod_...
|
||||
```
|
||||
|
||||
Without a valid key, you'll see the demo behavior with error handling.
|
46
src/dsl/examples/payment/main.rs
Normal file
46
src/dsl/examples/payment/main.rs
Normal file
@@ -0,0 +1,46 @@
|
||||
use rhailib_dsl::payment::register_payment_rhai_module;
|
||||
use rhai::{Engine, EvalAltResult, Scope};
|
||||
use std::fs;
|
||||
use std::env;
|
||||
|
||||
fn main() -> Result<(), Box<EvalAltResult>> {
|
||||
// Load environment variables from .env file
|
||||
dotenv::from_filename("examples/payment/.env").ok();
|
||||
|
||||
// Get Stripe API key from environment
|
||||
let stripe_secret_key = env::var("STRIPE_SECRET_KEY")
|
||||
.unwrap_or_else(|_| {
|
||||
println!("⚠️ STRIPE_SECRET_KEY not found in .env file, using demo key");
|
||||
println!(" Create examples/payment/.env with: STRIPE_SECRET_KEY=sk_test_your_key_here");
|
||||
"sk_test_demo_key_will_fail_gracefully".to_string()
|
||||
});
|
||||
|
||||
// Create a new Rhai engine
|
||||
let mut engine = Engine::new();
|
||||
|
||||
// Register the payment module
|
||||
register_payment_rhai_module(&mut engine);
|
||||
|
||||
// Create a scope and set the Stripe API key variable
|
||||
let mut scope = Scope::new();
|
||||
scope.push("STRIPE_API_KEY", stripe_secret_key.clone());
|
||||
|
||||
println!("=== Rhai Payment Module Example ===");
|
||||
println!("🔑 Using Stripe API key: {}***", &stripe_secret_key[..15.min(stripe_secret_key.len())]);
|
||||
println!("Reading and executing payment.rhai script...\n");
|
||||
|
||||
// Read the Rhai script
|
||||
let script = fs::read_to_string("examples/payment/payment.rhai")
|
||||
.expect("Failed to read payment.rhai file");
|
||||
|
||||
// Execute the script with the scope
|
||||
match engine.eval_with_scope::<()>(&mut scope, &script) {
|
||||
Ok(_) => println!("\n✅ Payment script executed successfully!"),
|
||||
Err(e) => {
|
||||
eprintln!("❌ Error executing script: {}", e);
|
||||
return Err(e);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
176
src/dsl/examples/payment/payment.rhai
Normal file
176
src/dsl/examples/payment/payment.rhai
Normal file
@@ -0,0 +1,176 @@
|
||||
// ===== Stripe Payment Integration Example =====
|
||||
// This script demonstrates the complete payment workflow using Stripe
|
||||
|
||||
print("🔧 Configuring Stripe...");
|
||||
// Configure Stripe with API key from environment variables
|
||||
// The STRIPE_API_KEY is loaded from .env file by main.rs
|
||||
let config_result = configure_stripe(STRIPE_API_KEY);
|
||||
print(`Configuration result: ${config_result}`);
|
||||
|
||||
print("\n📦 Creating a Product...");
|
||||
// Create a new product using builder pattern
|
||||
let product = new_product()
|
||||
.name("Premium Software License")
|
||||
.description("A comprehensive software solution for businesses")
|
||||
.metadata("category", "software")
|
||||
.metadata("tier", "premium");
|
||||
|
||||
print(`Product created: ${product.name}`);
|
||||
|
||||
// Create the product in Stripe
|
||||
print("🔄 Attempting to create product in Stripe...");
|
||||
try {
|
||||
let product_id = product.create();
|
||||
print(`✅ Product ID: ${product_id}`);
|
||||
} catch(error) {
|
||||
print(`❌ Failed to create product: ${error}`);
|
||||
print("This is expected with a demo API key. In production, use a valid Stripe secret key.");
|
||||
return; // Exit early since we can't continue without a valid product
|
||||
}
|
||||
|
||||
print("\n💰 Creating Prices...");
|
||||
|
||||
// Create upfront price (one-time payment)
|
||||
let upfront_price = new_price()
|
||||
.amount(19999) // $199.99 in cents
|
||||
.currency("usd")
|
||||
.product(product_id)
|
||||
.metadata("type", "upfront");
|
||||
|
||||
let upfront_price_id = upfront_price.create();
|
||||
print(`✅ Upfront Price ID: ${upfront_price_id}`);
|
||||
|
||||
// Create monthly subscription price
|
||||
let monthly_price = new_price()
|
||||
.amount(2999) // $29.99 in cents
|
||||
.currency("usd")
|
||||
.product(product_id)
|
||||
.recurring("month")
|
||||
.metadata("type", "monthly_subscription");
|
||||
|
||||
let monthly_price_id = monthly_price.create();
|
||||
print(`✅ Monthly Price ID: ${monthly_price_id}`);
|
||||
|
||||
// Create annual subscription price with discount
|
||||
let annual_price = new_price()
|
||||
.amount(29999) // $299.99 in cents (2 months free)
|
||||
.currency("usd")
|
||||
.product(product_id)
|
||||
.recurring("year")
|
||||
.metadata("type", "annual_subscription")
|
||||
.metadata("discount", "2_months_free");
|
||||
|
||||
let annual_price_id = annual_price.create();
|
||||
print(`✅ Annual Price ID: ${annual_price_id}`);
|
||||
|
||||
print("\n🎟️ Creating Discount Coupons...");
|
||||
|
||||
// Create a percentage-based coupon
|
||||
let percent_coupon = new_coupon()
|
||||
.duration("once")
|
||||
.percent_off(25)
|
||||
.metadata("campaign", "new_customer_discount")
|
||||
.metadata("code", "WELCOME25");
|
||||
|
||||
let percent_coupon_id = percent_coupon.create();
|
||||
print(`✅ 25% Off Coupon ID: ${percent_coupon_id}`);
|
||||
|
||||
// Create a fixed amount coupon
|
||||
let amount_coupon = new_coupon()
|
||||
.duration("repeating")
|
||||
.duration_in_months(3)
|
||||
.amount_off(500, "usd") // $5.00 off
|
||||
.metadata("campaign", "loyalty_program")
|
||||
.metadata("code", "LOYAL5");
|
||||
|
||||
let amount_coupon_id = amount_coupon.create();
|
||||
print(`✅ $5 Off Coupon ID: ${amount_coupon_id}`);
|
||||
|
||||
print("\n💳 Creating Payment Intent for Upfront Payment...");
|
||||
|
||||
// Create a payment intent for one-time payment
|
||||
let payment_intent = new_payment_intent()
|
||||
.amount(19999)
|
||||
.currency("usd")
|
||||
.customer("cus_example_customer_id")
|
||||
.description("Premium Software License - One-time Payment")
|
||||
.add_payment_method_type("card")
|
||||
.add_payment_method_type("us_bank_account")
|
||||
.metadata("product_id", product_id)
|
||||
.metadata("price_id", upfront_price_id)
|
||||
.metadata("payment_type", "upfront");
|
||||
|
||||
let payment_intent_id = payment_intent.create();
|
||||
print(`✅ Payment Intent ID: ${payment_intent_id}`);
|
||||
|
||||
print("\n🔄 Creating Subscription...");
|
||||
|
||||
// Create a subscription for monthly billing
|
||||
let subscription = new_subscription()
|
||||
.customer("cus_example_customer_id")
|
||||
.add_price(monthly_price_id)
|
||||
.trial_days(14) // 14-day free trial
|
||||
.coupon(percent_coupon_id) // Apply 25% discount
|
||||
.metadata("plan", "monthly")
|
||||
.metadata("trial", "14_days")
|
||||
.metadata("source", "website_signup");
|
||||
|
||||
let subscription_id = subscription.create();
|
||||
print(`✅ Subscription ID: ${subscription_id}`);
|
||||
|
||||
print("\n🎯 Creating Multi-Item Subscription...");
|
||||
|
||||
// Create a subscription with multiple items
|
||||
let multi_subscription = new_subscription()
|
||||
.customer("cus_example_enterprise_customer")
|
||||
.add_price_with_quantity(monthly_price_id, 5) // 5 licenses
|
||||
.add_price("price_addon_support_monthly") // Support addon
|
||||
.trial_days(30) // 30-day trial for enterprise
|
||||
.metadata("plan", "enterprise")
|
||||
.metadata("licenses", "5")
|
||||
.metadata("addons", "premium_support");
|
||||
|
||||
let multi_subscription_id = multi_subscription.create();
|
||||
print(`✅ Multi-Item Subscription ID: ${multi_subscription_id}`);
|
||||
|
||||
print("\n💰 Creating Payment Intent with Coupon...");
|
||||
|
||||
// Create another payment intent with discount applied
|
||||
let discounted_payment = new_payment_intent()
|
||||
.amount(14999) // Discounted amount after coupon
|
||||
.currency("usd")
|
||||
.customer("cus_example_customer_2")
|
||||
.description("Premium Software License - With 25% Discount")
|
||||
.metadata("original_amount", "19999")
|
||||
.metadata("coupon_applied", percent_coupon_id)
|
||||
.metadata("discount_percent", "25");
|
||||
|
||||
let discounted_payment_id = discounted_payment.create();
|
||||
print(`✅ Discounted Payment Intent ID: ${discounted_payment_id}`);
|
||||
|
||||
print("\n📊 Summary of Created Items:");
|
||||
print("================================");
|
||||
print(`Product ID: ${product_id}`);
|
||||
print(`Upfront Price ID: ${upfront_price_id}`);
|
||||
print(`Monthly Price ID: ${monthly_price_id}`);
|
||||
print(`Annual Price ID: ${annual_price_id}`);
|
||||
print(`25% Coupon ID: ${percent_coupon_id}`);
|
||||
print(`$5 Coupon ID: ${amount_coupon_id}`);
|
||||
print(`Payment Intent ID: ${payment_intent_id}`);
|
||||
print(`Subscription ID: ${subscription_id}`);
|
||||
print(`Multi-Subscription ID: ${multi_subscription_id}`);
|
||||
print(`Discounted Payment ID: ${discounted_payment_id}`);
|
||||
|
||||
print("\n🎉 Payment workflow demonstration completed!");
|
||||
print("All Stripe objects have been created successfully using the builder pattern.");
|
||||
|
||||
// Example of accessing object properties
|
||||
print("\n🔍 Accessing Object Properties:");
|
||||
print(`Product Name: ${product.name}`);
|
||||
print(`Product Description: ${product.description}`);
|
||||
print(`Upfront Price Amount: $${upfront_price.amount / 100}`);
|
||||
print(`Monthly Price Currency: ${monthly_price.currency}`);
|
||||
print(`Subscription Customer: ${subscription.customer}`);
|
||||
print(`Payment Intent Amount: $${payment_intent.amount / 100}`);
|
||||
print(`Percent Coupon Duration: ${percent_coupon.duration}`);
|
||||
print(`Percent Coupon Discount: ${percent_coupon.percent_off}%`);
|
Reference in New Issue
Block a user