#ledger #accounting #cala #unit #server #double #built

bin+lib cala-ledger

基于PG/SQLx构建的可嵌入的双面会计账簿

52次发布

0.2.41 2024年8月26日
0.2.40 2024年8月19日
0.2.30 2024年7月23日
0.2.25 2024年6月28日
0.1.6 2024年5月28日

#7 in #cala

Download history 221/week @ 2024-05-13 419/week @ 2024-05-20 278/week @ 2024-05-27 1493/week @ 2024-06-03 1700/week @ 2024-06-10 521/week @ 2024-06-17 820/week @ 2024-06-24 555/week @ 2024-07-01 100/week @ 2024-07-08 48/week @ 2024-07-15 161/week @ 2024-07-22 13/week @ 2024-07-29 162/week @ 2024-08-05 1100/week @ 2024-08-12 230/week @ 2024-08-19

1,520 每月下载量
用于 cala-server

Apache-2.0

355KB
10K SLoC

cala

运行(单元)测试

make reset-deps next-watch

运行端到端测试

make e2e

运行服务器

make run-server

lib.rs:

cala-ledger

此crate提供了一套原语,用于实现一个兼容SQL的双式会计系统。该系统专门设计用于处理货币和构建金融产品。

访问Cala项目的网站以获取更多信息和学习教程。

快速入门

以下是初始化账簿、创建原语模板和发布交易的步骤。这是一个玩具示例,将所有组件从端到端整合在一起。不建议用于实际用途。

use cala_ledger::{account::*, journal::*, tx_template::*, *};
use rust_decimal::Decimal;
use uuid::uuid;

async fn init_cala(journal_id: JournalId) -> anyhow::Result<CalaLedger, anyhow::Error> {
    let cala_config = CalaLedgerConfig::builder()
        .pg_con("postgres://user:password@localhost:5432/pg")
        // .exec_migrations(true) # commented out for execution in CI
        .build()?;
    let cala = CalaLedger::init(cala_config).await?;

    // Initialize the journal - all entities are constructed via builders
    let new_journal = NewJournal::builder()
        .id(journal_id)
        .name("Ledger")
        .build()
        .expect("Couldn't build NewJournal");
    let _ = cala.journals().create(new_journal).await;

    // Initialize an income omnibus account
    let main_account_id = uuid!("00000000-0000-0000-0000-000000000001");
    let new_account = NewAccount::builder()
        .id(main_account_id)
        .name("Income")
        .code("Income")
        .build()?;
    cala.accounts().create(new_account).await?;

    // Create the trivial 'income' template
    let params = vec![
        NewParamDefinition::builder()
            .name("sender_account_id")
            .r#type(ParamDataType::Uuid)
            .build()?,
        NewParamDefinition::builder()
            .name("units")
            .r#type(ParamDataType::Decimal)
            .build()?,
    ];

    let entries = vec![
        NewTxTemplateEntry::builder()
            .entry_type("'INCOME_DR'")
            .account_id("params.sender_account_id")
            .layer("SETTLED")
            .direction("DEBIT")
            .units("params.units")
            .currency("'BTC'")
            .build()?,
        NewTxTemplateEntry::builder()
            .entry_type("'INCOME_CR'")
            .account_id(format!("uuid('{}')", main_account_id))
            .layer("SETTLED")
            .direction("CREDIT")
            .units("params.units")
            .currency("'BTC'")
            .build()?,
    ];

    let tx_code = "GENERAL_INCOME";
    let new_template = NewTxTemplate::builder()
        .id(uuid::Uuid::new_v4())
        .code(tx_code)
        .params(params)
        .transaction(
            NewTxTemplateTransaction::builder()
                .effective("date()")
                .journal_id(format!("uuid('{}')", journal_id))
                .build()?,
        )
        .entries(entries)
        .build()?;

    cala.tx_templates().create(new_template).await?;
    Ok(cala)
}

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let journal_id = JournalId::from(uuid!("00000000-0000-0000-0000-000000000001"));
    let cala = init_cala(journal_id).await?;
    // The account that is sending to the general income account
    let sender_account_id = AccountId::new();
    let sender_account = NewAccount::builder()
        .id(sender_account_id)
        .name(format!("Sender-{}", sender_account_id))
        .code(format!("Sender-{}", sender_account_id))
        .build()?;
    cala.accounts().create(sender_account).await?;
    // Prepare the input parameters that the template requires
    let mut params = Params::new();
    params.insert("sender_account_id", sender_account_id);
    params.insert("units", Decimal::ONE);
    // Create the transaction via the template
    cala.post_transaction(TransactionId::new(), "GENERAL_INCOME", params)
        .await?;

    let account_balance = cala
        .balances()
        .find(journal_id, sender_account_id, "BTC".parse()?)
        .await?;

    let expected_balance = Decimal::new(-1, 0); // Define the expected balance
    assert_eq!(account_balance.settled(), expected_balance);
    Ok(())
}

依赖项

~49–69MB
~1M SLoC