Files
sendico/api/proto/ledger/v1/ledger.proto
2026-02-13 15:35:17 +01:00

247 lines
7.2 KiB
Protocol Buffer

syntax = "proto3";
package ledger.v1;
option go_package = "github.com/tech/sendico/pkg/proto/ledger/v1;ledgerv1";
import "google/protobuf/timestamp.proto";
import "google/protobuf/wrappers.proto";
import "api/proto/common/describable/v1/describable.proto";
import "api/proto/common/money/v1/money.proto";
// ===== Enums =====
enum EntryType {
ENTRY_TYPE_UNSPECIFIED = 0;
ENTRY_CREDIT = 1;
ENTRY_DEBIT = 2;
ENTRY_TRANSFER = 3;
ENTRY_FX = 4;
ENTRY_FEE = 5;
ENTRY_ADJUST = 6;
ENTRY_REVERSE = 7;
}
enum LineType {
LINE_TYPE_UNSPECIFIED = 0;
LINE_MAIN = 1;
LINE_FEE = 2;
LINE_SPREAD = 3;
LINE_REVERSAL = 4;
}
enum AccountType {
ACCOUNT_TYPE_UNSPECIFIED = 0;
ACCOUNT_TYPE_ASSET = 1;
ACCOUNT_TYPE_LIABILITY = 2;
ACCOUNT_TYPE_REVENUE = 3;
ACCOUNT_TYPE_EXPENSE = 4;
}
enum AccountStatus {
ACCOUNT_STATUS_UNSPECIFIED = 0;
ACCOUNT_STATUS_ACTIVE = 1;
ACCOUNT_STATUS_FROZEN = 2;
}
enum AccountRole {
ACCOUNT_ROLE_UNSPECIFIED = 0;
ACCOUNT_ROLE_OPERATING = 1;
ACCOUNT_ROLE_HOLD = 2;
ACCOUNT_ROLE_TRANSIT = 3;
ACCOUNT_ROLE_SETTLEMENT = 4;
ACCOUNT_ROLE_CLEARING = 5;
ACCOUNT_ROLE_PENDING = 6;
ACCOUNT_ROLE_RESERVE = 7;
ACCOUNT_ROLE_LIQUIDITY = 8;
ACCOUNT_ROLE_FEE = 9;
ACCOUNT_ROLE_CHARGEBACK = 10;
ACCOUNT_ROLE_ADJUSTMENT = 11;
}
// LedgerAccount captures the canonical representation of an account resource.
message LedgerAccount {
string ledger_account_ref = 1;
string organization_ref = 2;
string account_code = 3;
AccountType account_type = 4;
string currency = 5;
AccountStatus status = 6;
bool allow_negative = 7;
reserved 8;
reserved "is_settlement";
map<string, string> metadata = 9;
google.protobuf.Timestamp created_at = 10;
google.protobuf.Timestamp updated_at = 11;
common.describable.v1.Describable describable = 12;
string owner_ref = 13;
AccountRole role = 14;
}
// A single posting line (mirrors your PostingLine model)
message PostingLine {
string ledger_account_ref = 1;
common.money.v1.Money money = 2;
LineType line_type = 3; // MAIN, FEE, SPREAD, ...
}
// ===== Requests/Responses =====
message CreateAccountRequest {
string organization_ref = 1;
string owner_ref = 2;
reserved 3;
reserved "account_code";
AccountType account_type = 4;
string currency = 5;
AccountStatus status = 6;
bool allow_negative = 7;
reserved 8;
reserved "is_settlement";
map<string, string> metadata = 9;
common.describable.v1.Describable describable = 10;
AccountRole role = 11;
}
message CreateAccountResponse {
LedgerAccount account = 1;
}
// Common: optional event_time lets caller set business time; server may default to now.
message PostCreditRequest {
string idempotency_key = 1;
string organization_ref = 2; // aligns with PermissionBound
string ledger_account_ref = 3;
common.money.v1.Money money = 4;
string description = 5;
repeated PostingLine charges = 6; // FEE/SPREAD lines (no MAIN here)
map<string, string> metadata = 7;
google.protobuf.Timestamp event_time = 8;
string contra_ledger_account_ref = 9; // optional override for settlement/contra account
AccountRole role = 10; // optional: assert target account has this role
}
message PostDebitRequest {
string idempotency_key = 1;
string organization_ref = 2;
string ledger_account_ref = 3;
common.money.v1.Money money = 4;
string description = 5;
repeated PostingLine charges = 6; // FEE/SPREAD
map<string, string> metadata = 7;
google.protobuf.Timestamp event_time = 8;
string contra_ledger_account_ref = 9; // optional override for settlement/contra account
AccountRole role = 10; // optional: assert target account has this role
}
message TransferRequest {
string idempotency_key = 1;
string organization_ref = 2;
string from_ledger_account_ref = 3;
string to_ledger_account_ref = 4;
common.money.v1.Money money = 5; // transfer amount/currency
string description = 6;
repeated PostingLine charges = 7; // optional FEE/SPREAD lines
map<string, string> metadata = 8;
google.protobuf.Timestamp event_time = 9;
AccountRole from_role = 10;
AccountRole to_role = 11;
}
message FXRequest {
string idempotency_key = 1;
string organization_ref = 2;
string from_ledger_account_ref = 3;
string to_ledger_account_ref = 4;
common.money.v1.Money from_money = 5; // debited
common.money.v1.Money to_money = 6; // credited
string rate = 7; // quoted rate as string (snapshot for audit)
string description = 8;
repeated PostingLine charges = 9; // FEE/SPREAD lines
map<string, string> metadata = 10;
google.protobuf.Timestamp event_time = 11;
}
message PostResponse {
string journal_entry_ref = 1;
int64 version = 2; // ledger's entry version (monotonic per scope)
EntryType entry_type = 3;
}
// ---- Balances & Entries ----
message GetBalanceRequest {
string ledger_account_ref = 1;
}
message BalanceResponse {
string ledger_account_ref = 1;
common.money.v1.Money balance = 2;
int64 version = 3;
google.protobuf.Timestamp last_updated = 4;
}
message GetEntryRequest {
string entry_ref = 1;
}
message JournalEntryResponse {
string entry_ref = 1;
string idempotency_key = 2;
EntryType entry_type = 3;
string description = 4;
google.protobuf.Timestamp event_time = 5;
int64 version = 6;
repeated PostingLine lines = 7;
map<string, string> metadata = 8;
repeated string ledger_account_refs = 9; // denormalized set for client-side filtering
}
message GetStatementRequest {
string ledger_account_ref = 1;
string cursor = 2; // opaque
int32 limit = 3; // page size
}
message StatementResponse {
repeated JournalEntryResponse entries = 1;
string next_cursor = 2;
}
message ListAccountsRequest {
string organization_ref = 1;
// Optional owner filter with 3-state semantics:
// - not set: return all accounts within organization
// - set to empty string: return accounts where owner_ref is null/empty
// - set to a value: return accounts where owner_ref matches
google.protobuf.StringValue owner_ref_filter = 2;
}
message ListAccountsResponse {
repeated LedgerAccount accounts = 1;
}
// ---- Account status mutations ----
message BlockAccountRequest {
string ledger_account_ref = 1;
string organization_ref = 2;
AccountRole role = 3; // optional: assert account has this role before blocking
}
message BlockAccountResponse {
LedgerAccount account = 1;
}
message UnblockAccountRequest {
string ledger_account_ref = 1;
string organization_ref = 2;
AccountRole role = 3; // optional: assert account has this role before unblocking
}
message UnblockAccountResponse {
LedgerAccount account = 1;
}