Stub implementation of Lua plugins
This commit is contained in:
parent
97644042a3
commit
1d3aa269b7
102
libdrcr/Cargo.lock
generated
102
libdrcr/Cargo.lock
generated
@ -109,6 +109,16 @@ dependencies = [
|
|||||||
"generic-array",
|
"generic-array",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bstr"
|
||||||
|
version = "1.12.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "234113d19d0d7d613b40e86fb654acf958910802bcceab913a4f9e7cda03b1a4"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bumpalo"
|
name = "bumpalo"
|
||||||
version = "3.17.0"
|
version = "3.17.0"
|
||||||
@ -293,6 +303,16 @@ version = "1.0.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "erased-serde"
|
||||||
|
version = "0.4.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e004d887f51fcb9fef17317a2f3525c887d8aa3f4f50fed920816a688284a5b7"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
"typeid",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "etcetera"
|
name = "etcetera"
|
||||||
version = "0.8.0"
|
version = "0.8.0"
|
||||||
@ -680,12 +700,23 @@ dependencies = [
|
|||||||
"downcast-rs",
|
"downcast-rs",
|
||||||
"dyn-clone",
|
"dyn-clone",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
|
"mlua",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"sqlx",
|
"sqlx",
|
||||||
"tokio",
|
"tokio",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libloading"
|
||||||
|
version = "0.8.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"windows-targets 0.52.6",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libm"
|
name = "libm"
|
||||||
version = "0.2.15"
|
version = "0.2.15"
|
||||||
@ -725,6 +756,15 @@ version = "0.4.27"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
|
checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "luau0-src"
|
||||||
|
version = "0.12.3+luau663"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "76ae337c644bbf86a8d8e9ce3ee023311833d41741baf5e51acc31b37843aba1"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "md-5"
|
name = "md-5"
|
||||||
version = "0.10.6"
|
version = "0.10.6"
|
||||||
@ -761,6 +801,37 @@ dependencies = [
|
|||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mlua"
|
||||||
|
version = "0.10.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c1f5f8fbebc7db5f671671134b9321c4b9aa9adeafccfd9a8c020ae45c6a35d0"
|
||||||
|
dependencies = [
|
||||||
|
"bstr",
|
||||||
|
"either",
|
||||||
|
"erased-serde",
|
||||||
|
"libloading",
|
||||||
|
"mlua-sys",
|
||||||
|
"num-traits",
|
||||||
|
"parking_lot",
|
||||||
|
"rustc-hash",
|
||||||
|
"rustversion",
|
||||||
|
"serde",
|
||||||
|
"serde-value",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mlua-sys"
|
||||||
|
version = "0.6.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "380c1f7e2099cafcf40e51d3a9f20a346977587aa4d012eae1f043149a728a93"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"cfg-if",
|
||||||
|
"luau0-src",
|
||||||
|
"pkg-config",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-bigint-dig"
|
name = "num-bigint-dig"
|
||||||
version = "0.8.4"
|
version = "0.8.4"
|
||||||
@ -823,6 +894,15 @@ version = "1.21.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ordered-float"
|
||||||
|
version = "2.10.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c"
|
||||||
|
dependencies = [
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "parking"
|
name = "parking"
|
||||||
version = "2.2.1"
|
version = "2.2.1"
|
||||||
@ -1007,6 +1087,12 @@ version = "0.1.24"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
|
checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustc-hash"
|
||||||
|
version = "2.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustversion"
|
name = "rustversion"
|
||||||
version = "1.0.20"
|
version = "1.0.20"
|
||||||
@ -1034,6 +1120,16 @@ dependencies = [
|
|||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde-value"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c"
|
||||||
|
dependencies = [
|
||||||
|
"ordered-float",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.219"
|
version = "1.0.219"
|
||||||
@ -1513,6 +1609,12 @@ dependencies = [
|
|||||||
"once_cell",
|
"once_cell",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "typeid"
|
||||||
|
version = "1.0.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "typenum"
|
name = "typenum"
|
||||||
version = "1.18.0"
|
version = "1.18.0"
|
||||||
|
@ -9,6 +9,7 @@ chrono = "0.4.41"
|
|||||||
downcast-rs = "2.0.1"
|
downcast-rs = "2.0.1"
|
||||||
dyn-clone = "1.0.19"
|
dyn-clone = "1.0.19"
|
||||||
indexmap = "2.9.0"
|
indexmap = "2.9.0"
|
||||||
|
mlua = { version = "0.10", features = ["luau", "serialize"] }
|
||||||
serde = "1.0.219"
|
serde = "1.0.219"
|
||||||
serde_json = "1.0.140"
|
serde_json = "1.0.140"
|
||||||
sqlx = { version = "0.8", features = [ "runtime-tokio", "sqlite" ] }
|
sqlx = { version = "0.8", features = [ "runtime-tokio", "sqlite" ] }
|
||||||
|
86
libdrcr/plugins/austax/austax.luau
Normal file
86
libdrcr/plugins/austax/austax.luau
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
--!strict
|
||||||
|
-- DrCr: Web-based double-entry bookkeeping framework
|
||||||
|
-- Copyright (C) 2022-2025 Lee Yingtong Li (RunasSudo)
|
||||||
|
--
|
||||||
|
-- This program is free software: you can redistribute it and/or modify
|
||||||
|
-- it under the terms of the GNU Affero General Public License as published by
|
||||||
|
-- the Free Software Foundation, either version 3 of the License, or
|
||||||
|
-- (at your option) any later version.
|
||||||
|
--
|
||||||
|
-- This program is distributed in the hope that it will be useful,
|
||||||
|
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
-- GNU Affero General Public License for more details.
|
||||||
|
--
|
||||||
|
-- You should have received a copy of the GNU Affero General Public License
|
||||||
|
-- along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
local libdrcr = require('../libdrcr')
|
||||||
|
|
||||||
|
function requires(args, context)
|
||||||
|
return {
|
||||||
|
{
|
||||||
|
name = 'CombineOrdinaryTransactions',
|
||||||
|
kind = 'BalancesBetween',
|
||||||
|
args = { DateStartDateEndArgs = { date_start = context.sofy_date, date_end = context.eofy_date } },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
function after_init_graph(args, steps, add_dependency, context)
|
||||||
|
for i = 1, #steps do
|
||||||
|
local other = steps[i]
|
||||||
|
if other.name == 'AllTransactionsExceptEarningsToEquity' then
|
||||||
|
-- AllTransactionsExceptEarningsToEquity depends on CalculateIncomeTax
|
||||||
|
-- TODO: Only in applicable years
|
||||||
|
|
||||||
|
local other_args: libdrcr.ReportingStepArgs
|
||||||
|
if other.product_kinds[1] == 'Transactions' then
|
||||||
|
other_args = 'VoidArgs'
|
||||||
|
else
|
||||||
|
other_args = other.args
|
||||||
|
end
|
||||||
|
|
||||||
|
add_dependency(other, {
|
||||||
|
name = 'CalculateIncomeTax',
|
||||||
|
kind = other.product_kinds[1],
|
||||||
|
args = other_args,
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function execute(args, context, get_product)
|
||||||
|
print('Stub: CombineOrdinaryTransactions.execute')
|
||||||
|
|
||||||
|
local product = get_product({
|
||||||
|
name = 'CombineOrdinaryTransactions',
|
||||||
|
kind = 'BalancesBetween',
|
||||||
|
args = { DateStartDateEndArgs = { date_start = context.sofy_date, date_end = context.eofy_date } }
|
||||||
|
})
|
||||||
|
|
||||||
|
print(libdrcr.repr(product))
|
||||||
|
|
||||||
|
return {
|
||||||
|
[{ name = 'CalculateIncomeTax', kind = 'Transactions', args = 'VoidArgs' }] = {
|
||||||
|
Transactions = {
|
||||||
|
transactions = {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
local plugin: libdrcr.Plugin = {
|
||||||
|
name = 'austax',
|
||||||
|
reporting_steps = {
|
||||||
|
{
|
||||||
|
name = 'CalculateIncomeTax',
|
||||||
|
product_kinds = {'DynamicReport', 'Transactions'},
|
||||||
|
requires = requires,
|
||||||
|
after_init_graph = after_init_graph,
|
||||||
|
execute = execute,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return plugin
|
141
libdrcr/plugins/libdrcr.luau
Normal file
141
libdrcr/plugins/libdrcr.luau
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
--!strict
|
||||||
|
-- DrCr: Web-based double-entry bookkeeping framework
|
||||||
|
-- Copyright (C) 2022-2025 Lee Yingtong Li (RunasSudo)
|
||||||
|
--
|
||||||
|
-- This program is free software: you can redistribute it and/or modify
|
||||||
|
-- it under the terms of the GNU Affero General Public License as published by
|
||||||
|
-- the Free Software Foundation, either version 3 of the License, or
|
||||||
|
-- (at your option) any later version.
|
||||||
|
--
|
||||||
|
-- This program is distributed in the hope that it will be useful,
|
||||||
|
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
-- GNU Affero General Public License for more details.
|
||||||
|
--
|
||||||
|
-- You should have received a copy of the GNU Affero General Public License
|
||||||
|
-- along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
------------------------
|
||||||
|
-- Plugin specific types
|
||||||
|
|
||||||
|
-- Represents a libdrcr plugin specification and implementation
|
||||||
|
export type Plugin = {
|
||||||
|
name: string,
|
||||||
|
reporting_steps: {ReportingStep},
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Specifies a ReportingStep provided by the plugin
|
||||||
|
export type ReportingStep = {
|
||||||
|
name: string,
|
||||||
|
product_kinds: {ReportingProductKind},
|
||||||
|
|
||||||
|
requires: (
|
||||||
|
ReportingStepArgs,
|
||||||
|
ReportingContext
|
||||||
|
) -> {ReportingProductId},
|
||||||
|
|
||||||
|
after_init_graph: (
|
||||||
|
ReportingStepArgs,
|
||||||
|
{ReportingStepId}, -- steps
|
||||||
|
(ReportingStepId, ReportingProductId) -> (), -- add_dependency
|
||||||
|
ReportingContext
|
||||||
|
) -> (),
|
||||||
|
|
||||||
|
execute: (
|
||||||
|
ReportingStepArgs,
|
||||||
|
ReportingContext,
|
||||||
|
(ReportingProductId) -> ReportingProduct -- get_product
|
||||||
|
) -> {[ReportingProductId]: ReportingProduct},
|
||||||
|
}
|
||||||
|
|
||||||
|
-------------------------
|
||||||
|
-- libdrcr internal types
|
||||||
|
|
||||||
|
export type ReportingContext = {
|
||||||
|
sofy_date: string,
|
||||||
|
eofy_date: string,
|
||||||
|
reporting_commodity: string,
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Accounting types
|
||||||
|
|
||||||
|
export type Transaction = {
|
||||||
|
id: number | nil,
|
||||||
|
dt: string,
|
||||||
|
description: string,
|
||||||
|
postings: {Posting},
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Posting = {
|
||||||
|
id: number | nil,
|
||||||
|
transaction_id: number | nil,
|
||||||
|
description: number | nil,
|
||||||
|
account: string,
|
||||||
|
quantity: number,
|
||||||
|
commodity: string,
|
||||||
|
quantity_ascost: number | nil,
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Reporting products
|
||||||
|
|
||||||
|
export type ReportingProduct = {
|
||||||
|
BalancesAt: BalancesAt?,
|
||||||
|
BalancesBetween: BalancesBetween?,
|
||||||
|
DynamicReport: DynamicReport?,
|
||||||
|
Transactions: Transactions?,
|
||||||
|
}
|
||||||
|
|
||||||
|
export type BalancesAt = any
|
||||||
|
export type BalancesBetween = any
|
||||||
|
export type DynamicReport = any
|
||||||
|
export type Transactions = { transactions: {Transaction} }
|
||||||
|
|
||||||
|
export type ReportingProductId = {
|
||||||
|
name: string,
|
||||||
|
kind: ReportingProductKind,
|
||||||
|
args: ReportingStepArgs,
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ReportingProductKind = 'BalancesAt' | 'BalancesBetween' | 'DynamicReport' | 'Transactions'
|
||||||
|
|
||||||
|
-- Reporting steps
|
||||||
|
|
||||||
|
export type ReportingStepId = {
|
||||||
|
name: string,
|
||||||
|
product_kinds: {ReportingProductKind},
|
||||||
|
args: ReportingStepArgs,
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Reporting step args
|
||||||
|
|
||||||
|
export type ReportingStepArgs = 'VoidArgs' | { DateArgs: DateArgs } | { DateStartDateEndArgs: DateStartDateEndArgs } | { MultipleDateArgs: MultipleDateArgs } | { MultipleDateStartDateEndArgs: MultipleDateStartDateEndArgs }
|
||||||
|
|
||||||
|
export type DateArgs = { date: string }
|
||||||
|
export type DateStartDateEndArgs = { date_start: string, date_end: string }
|
||||||
|
export type MultipleDateArgs = { dates: {DateArgs} }
|
||||||
|
export type MultipleDateStartDateEndArgs = { dates: {DateStartDateEndArgs} }
|
||||||
|
|
||||||
|
-----------------
|
||||||
|
-- Module exports
|
||||||
|
|
||||||
|
local libdrcr = {}
|
||||||
|
|
||||||
|
function libdrcr.repr(value: any): string
|
||||||
|
local result = ''
|
||||||
|
if type(value) == 'table' then
|
||||||
|
result = result .. '{'
|
||||||
|
for k, v in pairs(value) do
|
||||||
|
result = result .. k .. ' = ' .. libdrcr.repr(v) .. ', '
|
||||||
|
end
|
||||||
|
result = result .. '}'
|
||||||
|
elseif type(value) == 'string' then
|
||||||
|
result = result .. "'" .. value .. "'"
|
||||||
|
elseif type(value) == 'number' then
|
||||||
|
result = result .. value
|
||||||
|
else
|
||||||
|
result = result .. '??'
|
||||||
|
end
|
||||||
|
return result
|
||||||
|
end
|
||||||
|
|
||||||
|
return libdrcr
|
@ -1,7 +1,8 @@
|
|||||||
pub mod account_config;
|
pub mod account_config;
|
||||||
pub mod austax;
|
//pub mod austax;
|
||||||
pub mod db;
|
pub mod db;
|
||||||
pub mod model;
|
pub mod model;
|
||||||
|
pub mod plugin;
|
||||||
pub mod reporting;
|
pub mod reporting;
|
||||||
pub mod serde;
|
pub mod serde;
|
||||||
pub mod util;
|
pub mod util;
|
||||||
|
@ -38,12 +38,14 @@ async fn main() {
|
|||||||
// Initialise ReportingContext
|
// Initialise ReportingContext
|
||||||
let mut context = ReportingContext::new(
|
let mut context = ReportingContext::new(
|
||||||
db_connection,
|
db_connection,
|
||||||
|
"plugins".to_string(),
|
||||||
|
vec!["austax.austax".to_string()],
|
||||||
NaiveDate::from_ymd_opt(2025, 6, 30).unwrap(),
|
NaiveDate::from_ymd_opt(2025, 6, 30).unwrap(),
|
||||||
"$".to_string(),
|
"$".to_string(),
|
||||||
);
|
);
|
||||||
|
libdrcr::plugin::register_lookup_fns(&mut context);
|
||||||
libdrcr::reporting::steps::register_lookup_fns(&mut context);
|
libdrcr::reporting::steps::register_lookup_fns(&mut context);
|
||||||
libdrcr::reporting::builders::register_dynamic_builders(&mut context);
|
libdrcr::reporting::builders::register_dynamic_builders(&mut context);
|
||||||
libdrcr::austax::register_lookup_fns(&mut context);
|
|
||||||
|
|
||||||
let context = Arc::new(context);
|
let context = Arc::new(context);
|
||||||
|
|
||||||
@ -109,16 +111,16 @@ async fn main() {
|
|||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let result = products
|
// let result = products
|
||||||
.get_or_err(&ReportingProductId {
|
// .get_or_err(&ReportingProductId {
|
||||||
name: "CalculateIncomeTax".to_string(),
|
// name: "CalculateIncomeTax".to_string(),
|
||||||
kind: ReportingProductKind::DynamicReport,
|
// kind: ReportingProductKind::DynamicReport,
|
||||||
args: ReportingStepArgs::VoidArgs,
|
// args: ReportingStepArgs::VoidArgs,
|
||||||
})
|
// })
|
||||||
.unwrap();
|
// .unwrap();
|
||||||
|
|
||||||
println!("Tax summary:");
|
// println!("Tax summary:");
|
||||||
println!("{:?}", result);
|
// println!("{:?}", result);
|
||||||
|
|
||||||
let result = products
|
let result = products
|
||||||
.get_or_err(&ReportingProductId {
|
.get_or_err(&ReportingProductId {
|
||||||
|
389
libdrcr/src/plugin.rs
Normal file
389
libdrcr/src/plugin.rs
Normal file
@ -0,0 +1,389 @@
|
|||||||
|
/*
|
||||||
|
DrCr: Web-based double-entry bookkeeping framework
|
||||||
|
Copyright (C) 2022-2025 Lee Yingtong Li (RunasSudo)
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
use std::fmt::Display;
|
||||||
|
|
||||||
|
use async_trait::async_trait;
|
||||||
|
use chrono::NaiveDate;
|
||||||
|
use mlua::{FromLua, Function, Lua, LuaSerdeExt, Table, Value};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use tokio::sync::RwLock;
|
||||||
|
|
||||||
|
use crate::reporting::calculator::ReportingGraphDependencies;
|
||||||
|
use crate::reporting::dynamic_report::DynamicReport;
|
||||||
|
use crate::reporting::executor::ReportingExecutionError;
|
||||||
|
use crate::reporting::types::{
|
||||||
|
BalancesAt, BalancesBetween, ReportingContext, ReportingProduct, ReportingProductId,
|
||||||
|
ReportingProductKind, ReportingProducts, ReportingStep, ReportingStepArgs, ReportingStepId,
|
||||||
|
Transactions,
|
||||||
|
};
|
||||||
|
use crate::util::sofy_from_eofy;
|
||||||
|
|
||||||
|
fn load_plugin(plugin_dir: &str, plugin_name: &str) -> (Lua, Plugin) {
|
||||||
|
let lua = Lua::new();
|
||||||
|
|
||||||
|
// Init Lua environment
|
||||||
|
let package = lua.globals().get::<Table>("package").unwrap();
|
||||||
|
package
|
||||||
|
.set("path", format!("{}/?.luau", plugin_dir))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// Require and call the plugin
|
||||||
|
let require = lua.load("require").eval::<Function>().unwrap();
|
||||||
|
let plugin = require.call::<Plugin>(plugin_name).expect("Lua error");
|
||||||
|
|
||||||
|
(lua, plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Call [ReportingContext::register_lookup_fn] for all steps provided by this module
|
||||||
|
pub fn register_lookup_fns(context: &mut ReportingContext) {
|
||||||
|
for plugin_path in context.plugin_names.clone().iter() {
|
||||||
|
let (_, plugin) = load_plugin(&context.plugin_dir, plugin_path);
|
||||||
|
|
||||||
|
for reporting_step in plugin.reporting_steps.iter() {
|
||||||
|
context.register_lookup_fn(
|
||||||
|
reporting_step.spec.name.clone(),
|
||||||
|
reporting_step.spec.product_kinds.clone(),
|
||||||
|
PluginReportingStep::takes_args,
|
||||||
|
PluginReportingStep::from_args,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
context
|
||||||
|
.plugin_specs
|
||||||
|
.insert(plugin_path.clone(), plugin.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Represents a libdrcr plugin specification and implementation
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Plugin {
|
||||||
|
name: String,
|
||||||
|
reporting_steps: Vec<LuaReportingStep>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromLua for Plugin {
|
||||||
|
fn from_lua(value: Value, _lua: &Lua) -> mlua::Result<Self> {
|
||||||
|
let value = value.as_table().unwrap();
|
||||||
|
Ok(Self {
|
||||||
|
name: value.get("name")?,
|
||||||
|
reporting_steps: value.get("reporting_steps")?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Represents a libdrcr plugin specification
|
||||||
|
#[derive(Debug, Deserialize, Serialize)]
|
||||||
|
pub struct PluginSpec {
|
||||||
|
name: String,
|
||||||
|
reporting_steps: Vec<ReportingStepSpec>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Plugin> for PluginSpec {
|
||||||
|
fn from(value: Plugin) -> Self {
|
||||||
|
Self {
|
||||||
|
name: value.name,
|
||||||
|
reporting_steps: value.reporting_steps.into_iter().map(|s| s.spec).collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// [ReportingStep] provided by the plugin specification and implementation
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct LuaReportingStep {
|
||||||
|
spec: ReportingStepSpec,
|
||||||
|
requires: Function,
|
||||||
|
after_init_graph: Function,
|
||||||
|
execute: Function,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromLua for LuaReportingStep {
|
||||||
|
fn from_lua(value: Value, lua: &Lua) -> mlua::Result<Self> {
|
||||||
|
let value = value.as_table().unwrap();
|
||||||
|
Ok(Self {
|
||||||
|
spec: ReportingStepSpec {
|
||||||
|
name: value.get("name")?,
|
||||||
|
product_kinds: lua.from_value(value.get("product_kinds")?)?,
|
||||||
|
},
|
||||||
|
requires: value.get("requires")?,
|
||||||
|
after_init_graph: value.get("after_init_graph")?,
|
||||||
|
execute: value.get("execute")?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// [ReportingStep] provided by the plugin specification
|
||||||
|
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
|
||||||
|
pub struct ReportingStepSpec {
|
||||||
|
name: String,
|
||||||
|
product_kinds: Vec<ReportingProductKind>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Represents a [ReportingProduct] which can be represented in Lua
|
||||||
|
#[derive(Deserialize, Serialize)]
|
||||||
|
enum LuaReportingProduct {
|
||||||
|
BalancesAt(BalancesAt),
|
||||||
|
BalancesBetween(BalancesBetween),
|
||||||
|
Transactions(Transactions),
|
||||||
|
DynamicReport(DynamicReport),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<LuaReportingProduct> for Box<dyn ReportingProduct> {
|
||||||
|
fn into(self) -> LuaReportingProduct {
|
||||||
|
if self.is::<BalancesAt>() {
|
||||||
|
LuaReportingProduct::BalancesAt(*self.downcast().unwrap())
|
||||||
|
} else if self.is::<BalancesBetween>() {
|
||||||
|
LuaReportingProduct::BalancesBetween(*self.downcast().unwrap())
|
||||||
|
} else if self.is::<Transactions>() {
|
||||||
|
LuaReportingProduct::Transactions(*self.downcast().unwrap())
|
||||||
|
} else if self.is::<DynamicReport>() {
|
||||||
|
LuaReportingProduct::DynamicReport(*self.downcast().unwrap())
|
||||||
|
} else {
|
||||||
|
panic!("Attempt to convert unknown ReportingProduct type into LuaReportingProduct")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<Box<dyn ReportingProduct>> for LuaReportingProduct {
|
||||||
|
fn into(self) -> Box<dyn ReportingProduct> {
|
||||||
|
match self {
|
||||||
|
LuaReportingProduct::BalancesAt(product) => Box::new(product),
|
||||||
|
LuaReportingProduct::BalancesBetween(product) => Box::new(product),
|
||||||
|
LuaReportingProduct::Transactions(product) => Box::new(product),
|
||||||
|
LuaReportingProduct::DynamicReport(product) => Box::new(product),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Represents subset of [ReportingContext] which is passed to Lua\
|
||||||
|
#[derive(Deserialize, Serialize)]
|
||||||
|
struct LuaReportingContext {
|
||||||
|
#[serde(with = "crate::serde::naivedate_to_js")]
|
||||||
|
pub sofy_date: NaiveDate,
|
||||||
|
#[serde(with = "crate::serde::naivedate_to_js")]
|
||||||
|
pub eofy_date: NaiveDate,
|
||||||
|
pub reporting_commodity: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LuaReportingContext {
|
||||||
|
fn from(context: &ReportingContext) -> Self {
|
||||||
|
Self {
|
||||||
|
sofy_date: sofy_from_eofy(context.eofy_date),
|
||||||
|
eofy_date: context.eofy_date,
|
||||||
|
reporting_commodity: context.reporting_commodity.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generic reporting step which is implemented by a plugin
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct PluginReportingStep {
|
||||||
|
pub plugin_path: String,
|
||||||
|
pub spec: ReportingStepSpec,
|
||||||
|
pub args: ReportingStepArgs, // Currently only VoidArgs is supported
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PluginReportingStep {
|
||||||
|
fn takes_args(_name: &str, args: &ReportingStepArgs, _context: &ReportingContext) -> bool {
|
||||||
|
*args == ReportingStepArgs::VoidArgs
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_args(
|
||||||
|
name: &str,
|
||||||
|
args: ReportingStepArgs,
|
||||||
|
context: &ReportingContext,
|
||||||
|
) -> Box<dyn ReportingStep> {
|
||||||
|
// Look up plugin
|
||||||
|
for (plugin_path, plugin_spec) in context.plugin_specs.iter() {
|
||||||
|
if let Some(reporting_step_spec) =
|
||||||
|
plugin_spec.reporting_steps.iter().find(|s| s.name == name)
|
||||||
|
{
|
||||||
|
return Box::new(Self {
|
||||||
|
plugin_path: plugin_path.to_string(),
|
||||||
|
spec: reporting_step_spec.clone(),
|
||||||
|
args,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
panic!("No plugin provides step {}", name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for PluginReportingStep {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.write_fmt(format_args!("{} {{PluginReportingStep}}", self.id()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl ReportingStep for PluginReportingStep {
|
||||||
|
fn id(&self) -> ReportingStepId {
|
||||||
|
ReportingStepId {
|
||||||
|
name: self.spec.name.clone(),
|
||||||
|
product_kinds: self.spec.product_kinds.clone(),
|
||||||
|
args: self.args.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn requires(&self, context: &ReportingContext) -> Vec<ReportingProductId> {
|
||||||
|
// Call to plugin
|
||||||
|
let (lua, plugin) = load_plugin(&context.plugin_dir, &self.plugin_path);
|
||||||
|
let plugin_step = plugin
|
||||||
|
.reporting_steps
|
||||||
|
.iter()
|
||||||
|
.find(|s| s.spec == self.spec)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let result_table = plugin_step
|
||||||
|
.requires
|
||||||
|
.call::<Table>((
|
||||||
|
lua.to_value(&self.args).unwrap(),
|
||||||
|
lua.to_value(&LuaReportingContext::from(context)).unwrap(),
|
||||||
|
))
|
||||||
|
.expect("Lua error");
|
||||||
|
|
||||||
|
// Convert result to Rust
|
||||||
|
let result = result_table
|
||||||
|
.sequence_values()
|
||||||
|
.map(|s| s.expect("Lua error"))
|
||||||
|
.map(|v| lua.from_value(v).expect("Deserialise error"))
|
||||||
|
.collect::<Vec<ReportingProductId>>();
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
fn after_init_graph(
|
||||||
|
&self,
|
||||||
|
steps: &Vec<Box<dyn ReportingStep>>,
|
||||||
|
dependencies: &mut ReportingGraphDependencies,
|
||||||
|
context: &ReportingContext,
|
||||||
|
) {
|
||||||
|
// Load plugin
|
||||||
|
let (lua, plugin) = load_plugin(&context.plugin_dir, &self.plugin_path);
|
||||||
|
let plugin_step = plugin
|
||||||
|
.reporting_steps
|
||||||
|
.iter()
|
||||||
|
.find(|s| s.spec == self.spec)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// Create a new scope since `add_dependency` depends on `dependencies`
|
||||||
|
lua.scope(|scope| {
|
||||||
|
// Init Lua environment
|
||||||
|
let add_dependency = scope.create_function_mut(|_, (step, product)| {
|
||||||
|
let step_id = lua.from_value::<ReportingStepId>(step)?;
|
||||||
|
let product_id = lua.from_value::<ReportingProductId>(product)?;
|
||||||
|
dependencies.add_dependency(step_id, product_id);
|
||||||
|
Ok(())
|
||||||
|
})?;
|
||||||
|
|
||||||
|
// Call to plugin
|
||||||
|
plugin_step.after_init_graph.call::<Value>((
|
||||||
|
lua.to_value(&self.args).unwrap(),
|
||||||
|
lua.to_value(&steps.iter().map(|s| s.id()).collect::<Vec<_>>())
|
||||||
|
.unwrap(),
|
||||||
|
add_dependency,
|
||||||
|
lua.to_value(&LuaReportingContext::from(context)).unwrap(),
|
||||||
|
))?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
.expect("Lua error");
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn execute(
|
||||||
|
&self,
|
||||||
|
context: &ReportingContext,
|
||||||
|
_steps: &Vec<Box<dyn ReportingStep>>,
|
||||||
|
_dependencies: &ReportingGraphDependencies,
|
||||||
|
products: &RwLock<ReportingProducts>,
|
||||||
|
) -> Result<ReportingProducts, ReportingExecutionError> {
|
||||||
|
let products = products.read().await;
|
||||||
|
|
||||||
|
// Load plugin
|
||||||
|
let (lua, plugin) = load_plugin(&context.plugin_dir, &self.plugin_path);
|
||||||
|
let plugin_step = plugin
|
||||||
|
.reporting_steps
|
||||||
|
.iter()
|
||||||
|
.find(|s| s.spec == self.spec)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// Create a new scope since `get_product` depends on `products`
|
||||||
|
let result_table = lua
|
||||||
|
.scope(|scope| {
|
||||||
|
// Init Lua environment
|
||||||
|
let get_product = scope.create_function(|_, product| {
|
||||||
|
let product_id = lua.from_value::<ReportingProductId>(product)?;
|
||||||
|
let product = products.get_or_err(&product_id).unwrap();
|
||||||
|
let product_enum: LuaReportingProduct = product.clone().into();
|
||||||
|
Ok(lua.to_value(&product_enum))
|
||||||
|
})?;
|
||||||
|
|
||||||
|
// Call to plugin
|
||||||
|
let result_table = plugin_step.execute.call::<Table>((
|
||||||
|
lua.to_value(&self.args).unwrap(),
|
||||||
|
lua.to_value(&LuaReportingContext::from(context)).unwrap(),
|
||||||
|
get_product,
|
||||||
|
))?;
|
||||||
|
|
||||||
|
Ok(result_table)
|
||||||
|
})
|
||||||
|
.expect("Lua error");
|
||||||
|
|
||||||
|
// Convert to Rust
|
||||||
|
let mut products = ReportingProducts::new();
|
||||||
|
for pair in result_table.pairs::<Value, Value>() {
|
||||||
|
let pair = pair.expect("Lua error");
|
||||||
|
let product_id = lua
|
||||||
|
.from_value::<ReportingProductId>(pair.0)
|
||||||
|
.expect("Deserialise error");
|
||||||
|
let product = lua
|
||||||
|
.from_value::<LuaReportingProduct>(pair.1)
|
||||||
|
.expect("Deserialise error");
|
||||||
|
|
||||||
|
products.insert(product_id, product.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(products)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Format the [Table] as a string
|
||||||
|
fn _dbg_table(table: &Table) -> String {
|
||||||
|
format!(
|
||||||
|
"{{{}}}",
|
||||||
|
table
|
||||||
|
.pairs::<Value, Value>()
|
||||||
|
.map(|p| p.expect("Lua error"))
|
||||||
|
.map(|(k, v)| format!(
|
||||||
|
"{}: {}",
|
||||||
|
if k.is_table() {
|
||||||
|
_dbg_table(k.as_table().unwrap())
|
||||||
|
} else {
|
||||||
|
format!("{:?}", k)
|
||||||
|
},
|
||||||
|
if v.is_table() {
|
||||||
|
_dbg_table(v.as_table().unwrap())
|
||||||
|
} else {
|
||||||
|
format!("{:?}", v)
|
||||||
|
}
|
||||||
|
))
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(", ")
|
||||||
|
)
|
||||||
|
}
|
@ -30,6 +30,7 @@ use tokio::sync::RwLock;
|
|||||||
|
|
||||||
use crate::db::DbConnection;
|
use crate::db::DbConnection;
|
||||||
use crate::model::transaction::TransactionWithPostings;
|
use crate::model::transaction::TransactionWithPostings;
|
||||||
|
use crate::plugin::PluginSpec;
|
||||||
use crate::QuantityInt;
|
use crate::QuantityInt;
|
||||||
|
|
||||||
use super::calculator::ReportingGraphDependencies;
|
use super::calculator::ReportingGraphDependencies;
|
||||||
@ -42,6 +43,8 @@ use super::executor::ReportingExecutionError;
|
|||||||
pub struct ReportingContext {
|
pub struct ReportingContext {
|
||||||
// Configuration
|
// Configuration
|
||||||
pub db_connection: DbConnection,
|
pub db_connection: DbConnection,
|
||||||
|
pub plugin_dir: String,
|
||||||
|
pub plugin_names: Vec<String>,
|
||||||
pub eofy_date: NaiveDate,
|
pub eofy_date: NaiveDate,
|
||||||
pub reporting_commodity: String,
|
pub reporting_commodity: String,
|
||||||
|
|
||||||
@ -51,21 +54,27 @@ pub struct ReportingContext {
|
|||||||
(ReportingStepTakesArgsFn, ReportingStepFromArgsFn),
|
(ReportingStepTakesArgsFn, ReportingStepFromArgsFn),
|
||||||
>,
|
>,
|
||||||
pub(crate) step_dynamic_builders: Vec<ReportingStepDynamicBuilder>,
|
pub(crate) step_dynamic_builders: Vec<ReportingStepDynamicBuilder>,
|
||||||
|
pub(crate) plugin_specs: HashMap<String, PluginSpec>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ReportingContext {
|
impl ReportingContext {
|
||||||
/// Initialise a new [ReportingContext]
|
/// Initialise a new [ReportingContext]
|
||||||
pub fn new(
|
pub fn new(
|
||||||
db_connection: DbConnection,
|
db_connection: DbConnection,
|
||||||
|
plugin_dir: String,
|
||||||
|
plugin_names: Vec<String>,
|
||||||
eofy_date: NaiveDate,
|
eofy_date: NaiveDate,
|
||||||
reporting_commodity: String,
|
reporting_commodity: String,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
db_connection,
|
db_connection,
|
||||||
|
plugin_dir,
|
||||||
|
plugin_names,
|
||||||
eofy_date,
|
eofy_date,
|
||||||
reporting_commodity,
|
reporting_commodity,
|
||||||
step_lookup_fn: HashMap::new(),
|
step_lookup_fn: HashMap::new(),
|
||||||
step_dynamic_builders: Vec::new(),
|
step_dynamic_builders: Vec::new(),
|
||||||
|
plugin_specs: HashMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,7 +148,7 @@ pub struct ReportingStepDynamicBuilder {
|
|||||||
// REPORTING PRODUCTS
|
// REPORTING PRODUCTS
|
||||||
|
|
||||||
/// Identifies a [ReportingProduct]
|
/// Identifies a [ReportingProduct]
|
||||||
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
|
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
|
||||||
pub struct ReportingProductId {
|
pub struct ReportingProductId {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub kind: ReportingProductKind,
|
pub kind: ReportingProductKind,
|
||||||
@ -155,7 +164,7 @@ impl Display for ReportingProductId {
|
|||||||
/// Identifies a type of [Box]ed [ReportingProduct]
|
/// Identifies a type of [Box]ed [ReportingProduct]
|
||||||
///
|
///
|
||||||
/// See [Box::downcast].
|
/// See [Box::downcast].
|
||||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
|
||||||
pub enum ReportingProductKind {
|
pub enum ReportingProductKind {
|
||||||
/// The [Box]ed [ReportingProduct] is a [Transactions]
|
/// The [Box]ed [ReportingProduct] is a [Transactions]
|
||||||
Transactions,
|
Transactions,
|
||||||
@ -184,7 +193,7 @@ pub struct Transactions {
|
|||||||
impl ReportingProduct for Transactions {}
|
impl ReportingProduct for Transactions {}
|
||||||
|
|
||||||
/// Records cumulative account balances at a particular point in time
|
/// Records cumulative account balances at a particular point in time
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||||
pub struct BalancesAt {
|
pub struct BalancesAt {
|
||||||
pub balances: HashMap<String, QuantityInt>,
|
pub balances: HashMap<String, QuantityInt>,
|
||||||
}
|
}
|
||||||
@ -192,7 +201,7 @@ pub struct BalancesAt {
|
|||||||
impl ReportingProduct for BalancesAt {}
|
impl ReportingProduct for BalancesAt {}
|
||||||
|
|
||||||
/// Records the total value of transactions in each account between two points in time
|
/// Records the total value of transactions in each account between two points in time
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||||
pub struct BalancesBetween {
|
pub struct BalancesBetween {
|
||||||
pub balances: HashMap<String, QuantityInt>,
|
pub balances: HashMap<String, QuantityInt>,
|
||||||
}
|
}
|
||||||
@ -274,7 +283,7 @@ impl Display for ReportingProducts {
|
|||||||
// REPORTING STEPS
|
// REPORTING STEPS
|
||||||
|
|
||||||
/// Identifies a [ReportingStep]
|
/// Identifies a [ReportingStep]
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
|
||||||
pub struct ReportingStepId {
|
pub struct ReportingStepId {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub product_kinds: Vec<ReportingProductKind>,
|
pub product_kinds: Vec<ReportingProductKind>,
|
||||||
@ -345,7 +354,7 @@ downcast_rs::impl_downcast!(ReportingStep);
|
|||||||
// REPORTING STEP ARGUMENTS
|
// REPORTING STEP ARGUMENTS
|
||||||
|
|
||||||
/// Represents arguments to a [ReportingStep]
|
/// Represents arguments to a [ReportingStep]
|
||||||
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
|
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
|
||||||
pub enum ReportingStepArgs {
|
pub enum ReportingStepArgs {
|
||||||
// This is an enum not a trait, to simply conversion to and from Lua
|
// This is an enum not a trait, to simply conversion to and from Lua
|
||||||
/// [ReportingStepArgs] implementation which takes no arguments
|
/// [ReportingStepArgs] implementation which takes no arguments
|
||||||
@ -378,8 +387,9 @@ impl Display for ReportingStepArgs {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
|
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
|
||||||
pub struct DateArgs {
|
pub struct DateArgs {
|
||||||
|
#[serde(with = "crate::serde::naivedate_to_js")]
|
||||||
pub date: NaiveDate,
|
pub date: NaiveDate,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -399,9 +409,11 @@ impl Into<DateArgs> for ReportingStepArgs {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
|
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
|
||||||
pub struct DateStartDateEndArgs {
|
pub struct DateStartDateEndArgs {
|
||||||
|
#[serde(with = "crate::serde::naivedate_to_js")]
|
||||||
pub date_start: NaiveDate,
|
pub date_start: NaiveDate,
|
||||||
|
#[serde(with = "crate::serde::naivedate_to_js")]
|
||||||
pub date_end: NaiveDate,
|
pub date_end: NaiveDate,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -421,7 +433,7 @@ impl Into<DateStartDateEndArgs> for ReportingStepArgs {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
|
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
|
||||||
pub struct MultipleDateArgs {
|
pub struct MultipleDateArgs {
|
||||||
pub dates: Vec<DateArgs>,
|
pub dates: Vec<DateArgs>,
|
||||||
}
|
}
|
||||||
@ -449,7 +461,7 @@ impl Into<MultipleDateArgs> for ReportingStepArgs {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
|
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
|
||||||
pub struct MultipleDateStartDateEndArgs {
|
pub struct MultipleDateStartDateEndArgs {
|
||||||
pub dates: Vec<DateStartDateEndArgs>,
|
pub dates: Vec<DateStartDateEndArgs>,
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,51 @@
|
|||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/// Serialises [chrono::NaiveDate] in database format
|
||||||
|
///
|
||||||
|
/// Use as `#[serde(with = "crate::serde::naivedate_to_js")]`, etc.
|
||||||
|
pub mod naivedate_to_js {
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
use chrono::NaiveDate;
|
||||||
|
use serde::{
|
||||||
|
de::{self, Unexpected, Visitor},
|
||||||
|
Deserializer, Serializer,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub(crate) fn serialize<S: Serializer>(
|
||||||
|
dt: &NaiveDate,
|
||||||
|
serializer: S,
|
||||||
|
) -> Result<S::Ok, S::Error> {
|
||||||
|
serializer.serialize_str(&dt.format("%Y-%m-%d").to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
struct DateVisitor;
|
||||||
|
impl<'de> Visitor<'de> for DateVisitor {
|
||||||
|
type Value = NaiveDate;
|
||||||
|
|
||||||
|
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(formatter, "a date string")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: de::Error,
|
||||||
|
{
|
||||||
|
match NaiveDate::parse_from_str(s, "%Y-%m-%d") {
|
||||||
|
Ok(dt) => Ok(dt),
|
||||||
|
Err(_) => Err(de::Error::invalid_value(Unexpected::Str(s), &self)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn deserialize<'de, D: Deserializer<'de>>(
|
||||||
|
deserializer: D,
|
||||||
|
) -> Result<NaiveDate, D::Error> {
|
||||||
|
deserializer.deserialize_str(DateVisitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Serialises [chrono::NaiveDateTime] in database format
|
/// Serialises [chrono::NaiveDateTime] in database format
|
||||||
///
|
///
|
||||||
/// Use as `#[serde(with = "crate::serde::naivedatetime_to_js")]`, etc.
|
/// Use as `#[serde(with = "crate::serde::naivedatetime_to_js")]`, etc.
|
||||||
@ -40,7 +85,7 @@ pub mod naivedatetime_to_js {
|
|||||||
type Value = NaiveDateTime;
|
type Value = NaiveDateTime;
|
||||||
|
|
||||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(formatter, "a date string")
|
write!(formatter, "a datetime string")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
|
fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
|
||||||
|
110
src-tauri/Cargo.lock
generated
110
src-tauri/Cargo.lock
generated
@ -370,6 +370,16 @@ dependencies = [
|
|||||||
"alloc-stdlib",
|
"alloc-stdlib",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bstr"
|
||||||
|
version = "1.12.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "234113d19d0d7d613b40e86fb654acf958910802bcceab913a4f9e7cda03b1a4"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bumpalo"
|
name = "bumpalo"
|
||||||
version = "3.16.0"
|
version = "3.16.0"
|
||||||
@ -878,7 +888,7 @@ version = "0.5.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412"
|
checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libloading",
|
"libloading 0.8.8",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -977,18 +987,6 @@ version = "1.0.19"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1c7a8fb8a9fbf66c1f703fe16184d10ca0ee9d23be5b4436400408ba54a95005"
|
checksum = "1c7a8fb8a9fbf66c1f703fe16184d10ca0ee9d23be5b4436400408ba54a95005"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "dyn-eq"
|
|
||||||
version = "0.1.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5c2d035d21af5cde1a6f5c7b444a5bf963520a9f142e5d06931178433d7d5388"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "dyn-hash"
|
|
||||||
version = "0.2.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "15401da73a9ed8c80e3b2d4dc05fe10e7b72d7243b9f614e516a44fa99986e88"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "either"
|
name = "either"
|
||||||
version = "1.13.0"
|
version = "1.13.0"
|
||||||
@ -2165,7 +2163,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "6e9ec52138abedcc58dc17a7c6c0c00a2bdb4f3427c7f63fa97fd0d859155caf"
|
checksum = "6e9ec52138abedcc58dc17a7c6c0c00a2bdb4f3427c7f63fa97fd0d859155caf"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"gtk-sys",
|
"gtk-sys",
|
||||||
"libloading",
|
"libloading 0.7.4",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -2183,9 +2181,8 @@ dependencies = [
|
|||||||
"chrono",
|
"chrono",
|
||||||
"downcast-rs 2.0.1",
|
"downcast-rs 2.0.1",
|
||||||
"dyn-clone",
|
"dyn-clone",
|
||||||
"dyn-eq",
|
|
||||||
"dyn-hash",
|
|
||||||
"indexmap 2.9.0",
|
"indexmap 2.9.0",
|
||||||
|
"mlua",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"sqlx",
|
"sqlx",
|
||||||
@ -2202,6 +2199,16 @@ dependencies = [
|
|||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libloading"
|
||||||
|
version = "0.8.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"windows-targets 0.52.6",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libm"
|
name = "libm"
|
||||||
version = "0.2.11"
|
version = "0.2.11"
|
||||||
@ -2257,6 +2264,15 @@ version = "0.4.22"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "luau0-src"
|
||||||
|
version = "0.12.3+luau663"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "76ae337c644bbf86a8d8e9ce3ee023311833d41741baf5e51acc31b37843aba1"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mac"
|
name = "mac"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
@ -2351,6 +2367,37 @@ dependencies = [
|
|||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mlua"
|
||||||
|
version = "0.10.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c1f5f8fbebc7db5f671671134b9321c4b9aa9adeafccfd9a8c020ae45c6a35d0"
|
||||||
|
dependencies = [
|
||||||
|
"bstr",
|
||||||
|
"either",
|
||||||
|
"erased-serde",
|
||||||
|
"libloading 0.8.8",
|
||||||
|
"mlua-sys",
|
||||||
|
"num-traits",
|
||||||
|
"parking_lot",
|
||||||
|
"rustc-hash",
|
||||||
|
"rustversion",
|
||||||
|
"serde",
|
||||||
|
"serde-value",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mlua-sys"
|
||||||
|
version = "0.6.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "380c1f7e2099cafcf40e51d3a9f20a346977587aa4d012eae1f043149a728a93"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"cfg-if",
|
||||||
|
"luau0-src",
|
||||||
|
"pkg-config",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "muda"
|
name = "muda"
|
||||||
version = "0.15.3"
|
version = "0.15.3"
|
||||||
@ -2769,6 +2816,15 @@ version = "0.2.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
|
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ordered-float"
|
||||||
|
version = "2.10.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c"
|
||||||
|
dependencies = [
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ordered-stream"
|
name = "ordered-stream"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
@ -3424,6 +3480,12 @@ version = "0.1.24"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
|
checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustc-hash"
|
||||||
|
version = "2.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc_version"
|
name = "rustc_version"
|
||||||
version = "0.4.1"
|
version = "0.4.1"
|
||||||
@ -3446,6 +3508,12 @@ dependencies = [
|
|||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustversion"
|
||||||
|
version = "1.0.21"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ryu"
|
name = "ryu"
|
||||||
version = "1.0.18"
|
version = "1.0.18"
|
||||||
@ -3549,6 +3617,16 @@ dependencies = [
|
|||||||
"typeid",
|
"typeid",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde-value"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c"
|
||||||
|
dependencies = [
|
||||||
|
"ordered-float",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.219"
|
version = "1.0.219"
|
||||||
|
@ -18,15 +18,19 @@
|
|||||||
|
|
||||||
use libdrcr::reporting::dynamic_report::DynamicReport;
|
use libdrcr::reporting::dynamic_report::DynamicReport;
|
||||||
use libdrcr::reporting::types::{ReportingProductId, ReportingProductKind, ReportingStepArgs};
|
use libdrcr::reporting::types::{ReportingProductId, ReportingProductKind, ReportingStepArgs};
|
||||||
use tauri::State;
|
use tauri::{AppHandle, State};
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
use crate::libdrcr_bridge::get_report;
|
use crate::libdrcr_bridge::get_report;
|
||||||
use crate::AppState;
|
use crate::AppState;
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub(crate) async fn get_tax_summary(state: State<'_, Mutex<AppState>>) -> Result<String, ()> {
|
pub(crate) async fn get_tax_summary(
|
||||||
|
app: AppHandle,
|
||||||
|
state: State<'_, Mutex<AppState>>,
|
||||||
|
) -> Result<String, ()> {
|
||||||
Ok(get_report(
|
Ok(get_report(
|
||||||
|
app,
|
||||||
state,
|
state,
|
||||||
&ReportingProductId {
|
&ReportingProductId {
|
||||||
name: "CalculateIncomeTax".to_string(),
|
name: "CalculateIncomeTax".to_string(),
|
||||||
|
@ -30,18 +30,25 @@ use libdrcr::reporting::types::{
|
|||||||
ReportingStepArgs, Transactions,
|
ReportingStepArgs, Transactions,
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tauri::State;
|
use tauri::path::BaseDirectory;
|
||||||
|
use tauri::{AppHandle, Manager, State};
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
use crate::AppState;
|
use crate::AppState;
|
||||||
|
|
||||||
fn prepare_reporting_context(context: &mut ReportingContext) {
|
fn prepare_reporting_context(context: &mut ReportingContext) {
|
||||||
libdrcr::austax::register_lookup_fns(context);
|
|
||||||
libdrcr::reporting::steps::register_lookup_fns(context);
|
libdrcr::reporting::steps::register_lookup_fns(context);
|
||||||
libdrcr::reporting::builders::register_dynamic_builders(context);
|
libdrcr::reporting::builders::register_dynamic_builders(context);
|
||||||
|
libdrcr::plugin::register_lookup_fns(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_plugins() -> Vec<String> {
|
||||||
|
// FIXME: Dynamically get this
|
||||||
|
vec!["austax.austax".to_string()]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn get_report(
|
pub(crate) async fn get_report(
|
||||||
|
app: AppHandle,
|
||||||
state: State<'_, Mutex<AppState>>,
|
state: State<'_, Mutex<AppState>>,
|
||||||
target: &ReportingProductId,
|
target: &ReportingProductId,
|
||||||
) -> Box<dyn ReportingProduct> {
|
) -> Box<dyn ReportingProduct> {
|
||||||
@ -54,7 +61,18 @@ pub(crate) async fn get_report(
|
|||||||
|
|
||||||
// Initialise ReportingContext
|
// Initialise ReportingContext
|
||||||
let eofy_date = db_connection.metadata().eofy_date;
|
let eofy_date = db_connection.metadata().eofy_date;
|
||||||
let mut context = ReportingContext::new(db_connection, eofy_date, "$".to_string());
|
let mut context = ReportingContext::new(
|
||||||
|
db_connection,
|
||||||
|
app.path()
|
||||||
|
.resolve("plugins", BaseDirectory::Resource)
|
||||||
|
.unwrap()
|
||||||
|
.to_str()
|
||||||
|
.unwrap()
|
||||||
|
.to_string(),
|
||||||
|
get_plugins(),
|
||||||
|
eofy_date,
|
||||||
|
"$".to_string(),
|
||||||
|
);
|
||||||
prepare_reporting_context(&mut context);
|
prepare_reporting_context(&mut context);
|
||||||
|
|
||||||
// Get dynamic report
|
// Get dynamic report
|
||||||
@ -75,9 +93,11 @@ pub(crate) async fn get_report(
|
|||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub(crate) async fn get_all_transactions_except_earnings_to_equity(
|
pub(crate) async fn get_all_transactions_except_earnings_to_equity(
|
||||||
|
app: AppHandle,
|
||||||
state: State<'_, Mutex<AppState>>,
|
state: State<'_, Mutex<AppState>>,
|
||||||
) -> Result<String, ()> {
|
) -> Result<String, ()> {
|
||||||
let transactions = get_report(
|
let transactions = get_report(
|
||||||
|
app,
|
||||||
state,
|
state,
|
||||||
&ReportingProductId {
|
&ReportingProductId {
|
||||||
name: "AllTransactionsExceptEarningsToEquity".to_string(),
|
name: "AllTransactionsExceptEarningsToEquity".to_string(),
|
||||||
@ -97,10 +117,12 @@ pub(crate) async fn get_all_transactions_except_earnings_to_equity(
|
|||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub(crate) async fn get_all_transactions_except_earnings_to_equity_for_account(
|
pub(crate) async fn get_all_transactions_except_earnings_to_equity_for_account(
|
||||||
|
app: AppHandle,
|
||||||
state: State<'_, Mutex<AppState>>,
|
state: State<'_, Mutex<AppState>>,
|
||||||
account: String,
|
account: String,
|
||||||
) -> Result<String, ()> {
|
) -> Result<String, ()> {
|
||||||
let transactions = get_report(
|
let transactions = get_report(
|
||||||
|
app,
|
||||||
state,
|
state,
|
||||||
&ReportingProductId {
|
&ReportingProductId {
|
||||||
name: "AllTransactionsExceptEarningsToEquity".to_string(),
|
name: "AllTransactionsExceptEarningsToEquity".to_string(),
|
||||||
@ -126,6 +148,7 @@ pub(crate) async fn get_all_transactions_except_earnings_to_equity_for_account(
|
|||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub(crate) async fn get_balance_sheet(
|
pub(crate) async fn get_balance_sheet(
|
||||||
|
app: AppHandle,
|
||||||
state: State<'_, Mutex<AppState>>,
|
state: State<'_, Mutex<AppState>>,
|
||||||
dates: Vec<String>,
|
dates: Vec<String>,
|
||||||
) -> Result<String, ()> {
|
) -> Result<String, ()> {
|
||||||
@ -137,6 +160,7 @@ pub(crate) async fn get_balance_sheet(
|
|||||||
}
|
}
|
||||||
|
|
||||||
Ok(get_report(
|
Ok(get_report(
|
||||||
|
app,
|
||||||
state,
|
state,
|
||||||
&ReportingProductId {
|
&ReportingProductId {
|
||||||
name: "BalanceSheet".to_string(),
|
name: "BalanceSheet".to_string(),
|
||||||
@ -154,6 +178,7 @@ pub(crate) async fn get_balance_sheet(
|
|||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub(crate) async fn get_income_statement(
|
pub(crate) async fn get_income_statement(
|
||||||
|
app: AppHandle,
|
||||||
state: State<'_, Mutex<AppState>>,
|
state: State<'_, Mutex<AppState>>,
|
||||||
dates: Vec<(String, String)>,
|
dates: Vec<(String, String)>,
|
||||||
) -> Result<String, ()> {
|
) -> Result<String, ()> {
|
||||||
@ -166,6 +191,7 @@ pub(crate) async fn get_income_statement(
|
|||||||
}
|
}
|
||||||
|
|
||||||
Ok(get_report(
|
Ok(get_report(
|
||||||
|
app,
|
||||||
state,
|
state,
|
||||||
&ReportingProductId {
|
&ReportingProductId {
|
||||||
name: "IncomeStatement".to_string(),
|
name: "IncomeStatement".to_string(),
|
||||||
@ -183,12 +209,14 @@ pub(crate) async fn get_income_statement(
|
|||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub(crate) async fn get_trial_balance(
|
pub(crate) async fn get_trial_balance(
|
||||||
|
app: AppHandle,
|
||||||
state: State<'_, Mutex<AppState>>,
|
state: State<'_, Mutex<AppState>>,
|
||||||
date: String,
|
date: String,
|
||||||
) -> Result<String, ()> {
|
) -> Result<String, ()> {
|
||||||
let date = NaiveDate::parse_from_str(&date, "%Y-%m-%d").expect("Invalid date");
|
let date = NaiveDate::parse_from_str(&date, "%Y-%m-%d").expect("Invalid date");
|
||||||
|
|
||||||
Ok(get_report(
|
Ok(get_report(
|
||||||
|
app,
|
||||||
state,
|
state,
|
||||||
&ReportingProductId {
|
&ReportingProductId {
|
||||||
name: "TrialBalance".to_string(),
|
name: "TrialBalance".to_string(),
|
||||||
@ -211,6 +239,7 @@ struct ValidatedBalanceAssertion {
|
|||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub(crate) async fn get_validated_balance_assertions(
|
pub(crate) async fn get_validated_balance_assertions(
|
||||||
|
app: AppHandle,
|
||||||
state: State<'_, Mutex<AppState>>,
|
state: State<'_, Mutex<AppState>>,
|
||||||
) -> Result<String, ()> {
|
) -> Result<String, ()> {
|
||||||
let state = state.lock().await;
|
let state = state.lock().await;
|
||||||
@ -233,8 +262,18 @@ pub(crate) async fn get_validated_balance_assertions(
|
|||||||
|
|
||||||
// Initialise ReportingContext
|
// Initialise ReportingContext
|
||||||
let eofy_date = db_connection.metadata().eofy_date;
|
let eofy_date = db_connection.metadata().eofy_date;
|
||||||
let mut context =
|
let mut context = ReportingContext::new(
|
||||||
ReportingContext::new(db_connection, get_plugins(), eofy_date, "$".to_string());
|
db_connection,
|
||||||
|
app.path()
|
||||||
|
.resolve("plugins", BaseDirectory::Resource)
|
||||||
|
.unwrap()
|
||||||
|
.to_str()
|
||||||
|
.unwrap()
|
||||||
|
.to_string(),
|
||||||
|
get_plugins(),
|
||||||
|
eofy_date,
|
||||||
|
"$".to_string(),
|
||||||
|
);
|
||||||
prepare_reporting_context(&mut context);
|
prepare_reporting_context(&mut context);
|
||||||
|
|
||||||
// Get report targets
|
// Get report targets
|
||||||
|
@ -26,6 +26,9 @@
|
|||||||
"targets": "all",
|
"targets": "all",
|
||||||
"icon": [
|
"icon": [
|
||||||
"icons/icon.png"
|
"icons/icon.png"
|
||||||
]
|
],
|
||||||
|
"resources": {
|
||||||
|
"../libdrcr/plugins/": "plugins/"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user