diff --git a/CHANGELOG.md b/CHANGELOG.md index b1bcb69..cc548aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ All notable changes to the Sharpy smart contract are documented here. ## [Unreleased] +- feat: invoice templates — reusable invoice configs — Adds InvoiceTemplate struct and create/get_template function - feat: recurring pause — pause/resume recurring chain — Adds pause_recurring / resume_recurring and is_recurring_pau - feat: discount config — set/get_discount — feat/discount-config - feat: invoice metadata — set/get_invoice_metadata — Adds InvoiceMetadata (key-value map) via set/get with creato diff --git a/README.md b/README.md index 2abc2b1..20dea1e 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@   - +   [](https://www.loom.com/share/09aa4a78e0c944dcab866a7036fde24d) @@ -85,6 +85,7 @@ graph TD - **Freeze control** — `freeze_invoice()`/`unfreeze_invoice()` admin blocks/re-enables `pay` (frozen field) - **Invoice notes** — `set_invoice_notes()`/`get_invoice_notes()` free-text `InvoiceNotes { text, updated_at }` - **Invoice tags** +- **Invoice templates** — `create_template`/`get_template` reusable configs `InvoiceTemplate` - **Recurring pause** — `pause_recurring`/`resume_recurring`/`is_recurring_paused` - **Discount config** — `set/get_discount` `DiscountConfig { discount_bps, updated_at }` - **Invoice metadata** — `set/get_invoice_metadata` `InvoiceMetadata { entries, updated_at }` diff --git a/contracts/sharpy/src/events.rs b/contracts/sharpy/src/events.rs index 165e5c3..3377553 100644 --- a/contracts/sharpy/src/events.rs +++ b/contracts/sharpy/src/events.rs @@ -286,3 +286,10 @@ pub struct RecurringPausedEvent { pub invoice_id: u64, pub paused: bool } pub fn recurring_paused(env: &Env, invoice_id: u64, paused: bool) { env.events().publish((symbol_short!("rpause"),), RecurringPausedEvent { invoice_id, paused }); } + +#[contracttype] +#[derive(Clone)] +pub struct TemplateCreatedEvent { pub template_id: u64, pub creator: Address } +pub fn template_created(env: &Env, template_id: u64, creator: &Address) { + env.events().publish((symbol_short!("tmpl"),), TemplateCreatedEvent { template_id, creator: creator.clone() }); +} diff --git a/contracts/sharpy/src/lib.rs b/contracts/sharpy/src/lib.rs index bf0f1b3..baf08f5 100644 --- a/contracts/sharpy/src/lib.rs +++ b/contracts/sharpy/src/lib.rs @@ -22,7 +22,7 @@ mod test; use soroban_sdk::{contract, contractimpl, symbol_short, token, Address, Bytes, Env, Map, String, Symbol, Vec}; use types::{ AuditEntry, CreateInvoiceParams, DisputeState, Invoice, InvoiceNotes, InvoiceOptions, - InvoicePayment, InvoiceStats, InvoiceStatus, InvoiceTags, InvoiceExtraMemo, Payment, InvoiceMetadata, DiscountConfig, RecurringPauseState, SplitRule, + InvoicePayment, InvoiceStats, InvoiceStatus, InvoiceTags, InvoiceExtraMemo, Payment, InvoiceMetadata, DiscountConfig, RecurringPauseState, InvoiceTemplate, SplitRule, SubscriptionParams, }; @@ -42,6 +42,7 @@ fn account_balance_key(account: &Address, token: &Address) -> (Symbol, Address, } fn invoice_notes_key(id: u64) -> (Symbol, u64) { (symbol_short!("notes"), id) } fn invoice_tags_key(id: u64) -> (Symbol, u64) { (symbol_short!("itags"), id) } +fn template_key(id: u64) -> (Symbol, u64) { (symbol_short!("tmpl"), id) } fn template_counter_key() -> Symbol { symbol_short!("tmpl_ctr") } fn recurring_pause_key(id: u64) -> (Symbol, u64) { (symbol_short!("rpause"), id) } fn discount_key(id: u64) -> (Symbol, u64) { (symbol_short!("disc"), id) } fn invoice_metadata_key(id: u64) -> (Symbol, u64) { (symbol_short!("imeta"), id) } @@ -1107,6 +1108,21 @@ impl SharpyContract { pub fn is_recurring_paused(env: Env, invoice_id: u64) -> bool { env.storage().persistent().get::<(Symbol,u64), RecurringPauseState>(&recurring_pause_key(invoice_id)).map(|s| s.paused).unwrap_or(false) } + + pub fn create_template(env: Env, creator: Address, name: String, recipients: Vec
, amounts: Vec