Skip to content

Commit

Permalink
Merge branch 'rchain-finance'
Browse files Browse the repository at this point in the history
  • Loading branch information
dckc committed Mar 9, 2022
2 parents c7693c5 + 892c136 commit 10dfece
Show file tree
Hide file tree
Showing 12 changed files with 1,282 additions and 17 deletions.
4 changes: 4 additions & 0 deletions brcal/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@
"sync": "node -r esm src/main.js --sync",
"sync:etherscan": "node -r esm src/etherscan.js",
"sync:uniswap": "node -r esm src/unisync.js",
"sync:lunchmoney": "node -r esm src/lmSync.js",
"build:coinbase": "node -r esm src/coinbaseCard.js --csv $CB $>$CB-lm.csv",
"lint:types": "tsc -p jsconfig.json",
"build": "exit 0",
"test:grok-balance-sheet": "node src/grokBalanceSheet.js <test/balance-sheet.txt >test/balance-sheet.json",
"test": "exit 1",
"pretty-fix": "prettier --write '**/*.js'",
"pretty-check": "prettier --check '**/*.js'",
Expand All @@ -15,6 +18,7 @@
"lint:eslint": "eslint '**/*.js'"
},
"dependencies": {
"better-sqlite3": "^7.4.6",
"csv-parse": "^4.16.0",
"esm": "^3.2.25",
"fast-json-patch": "^3.0.0-1",
Expand Down
2 changes: 1 addition & 1 deletion brcal/src/WebApp.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export function WebApp(url, { https }, headers) {
return freeze({
url,
pathjoin(/** @type { string } */ ref) {
return WebApp(`${new URL(ref, url)}`, { https });
return WebApp(`${new URL(ref, url)}`, { https }, headers);
},
withHeaders(/** @type { Headers } */ h) {
return WebApp(url, { https }, { ...headers, ...h });
Expand Down
6 changes: 3 additions & 3 deletions brcal/src/book_ops.sql
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ where tx_guid = ? and account_guid = (select guid from accounts where name = 'Im


-- createSlotImport:
create temporary table slot_import as
create table slot_import as
select string_val id, name, string_val from slots where 1 = 0;

-- loadSlotImport:
Expand All @@ -37,7 +37,7 @@ where not exists (
update slots sl
join slot_import si on md5(si.id) = sl.obj_guid and si.name = sl.name
set sl.string_val = si.string_val
where sl.string_val != sl.string_val;
;

-- dropSlotImport:
drop table slot_import;
drop table if exists slot_import;
28 changes: 28 additions & 0 deletions brcal/src/gc_load_patch.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
update accounts_load
set commodity_guid = (select commodity_guid from accounts where name = 'Assets')
, commodity_scu = (select commodity_scu from accounts where name = 'Assets')
, non_std_scu = (select non_std_scu from accounts where name = 'Assets')
;

-- delete from accounts;
insert into accounts select * from accounts_load;

update transactions_load
set num = ''
, currency_guid = (select guid from commodities where mnemonic = 'USD');


-- delete from transactions;
insert into transactions select * from transactions_load;

update splits_load
set memo=''
, action=''
, reconcile_state='n'
, quantity_num = value_num
, quantity_denom = value_denom;


-- delete from splits;
insert into splits select * from splits_load;

232 changes: 232 additions & 0 deletions brcal/src/gc_sync.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,232 @@
-- Lunch Money

-- delete from slots where name like 'lunchmoney.app/transactions';
select * from slots where name = 'lunchmoney.app/categories';
select * from slots where name = 'lunchmoney.app/assets';
select * from slots where name = 'lunchmoney.app/plaid_accounts';
select * from slots where name = 'lunchmoney.app/transactions';

-- Home -> House
-- delete from slots where name = 'lunchmoney.app/categories' and string_val like '%"Home"%';
-- delete from slots where name = 'lunchmoney.app/categories' and string_val like '%"Education"%';


-- odd! views don't seem to work well.
drop table if exists lm_categories ;
create table lm_categories as
select
obj_guid guid
-- https://lunchmoney.dev/#categories
, data->>"$.id" id
, data->>"$.name" name
, data->>"$.description" description
, data->>"$.is_income" = 'true' as is_income
-- exclude_from_budget
-- exclude_from_totals
, timestamp(replace(replace(data->>"$.updated_at", 'T', ' '), 'Z', '')) updated_at
, timestamp(replace(replace(data->>"$.created_at", 'T', ' '), 'Z', '')) created_at
-- , json_type(data->>"$.is_group") ty
, data->>"$.is_group" = 'true' is_group
, data->>"$.group_id" group_id
, ax.name account_name
, ax.guid account_guid
, ax.account_type
, ax.code
, data
from (
select id, obj_guid, name
, case when JSON_VALID(string_val) = 1 then cast(string_val as json) end data
from slots
where name = 'lunchmoney.app/categories'
) detail
left join (
select a.guid, string_val, a.code, a.name, a.account_type
from slots s join accounts a on a.guid = s.obj_guid
where s.string_val like 'lm:%'
) ax
on concat('lm:', data->>"$.id") = ax.string_val
;
select * from lm_categories where account_guid is not null;


-- Lunch Money Transactions
drop table lm_tx;
create table lm_tx as
select
obj_guid guid
-- https://lunchmoney.dev/#categories
, data->>"$.id" id
, data->>"$.date" date
-- fees, tags, type
, data->>"$.payee" payee
-- price
, data->>"$.amount" + 0 amount
-- status, subtype
, data->>"$.notes" notes
, data->>"$.asset_id" asset_id
, data->>"$.group_id" group_id
, data->>"$.is_group" is_group
, data->>"$.parent_id" parent_id
, data->>"$.recurring_id" recurring_id
, data->>"$.category_id" category_id
, data->>"$.external_id" external_id
-- currency
-- quantity,
-- , original_name
, data->>"$.plaid_account_id" plaid_account_id
-- , data
from (
select id, obj_guid, name
, case when JSON_VALID(string_val) = 1 then cast(string_val as json) end data
from slots
where name = 'lunchmoney.app/transactions'
) detail
order by date
;

drop table if exists lm_assets;
create table lm_assets as
select
obj_guid guid
, data->>"$.id" id
, data->>"$.name" name
, data->>"$.balance" + 0 balance
-- currency, closed_on
, data->>"$.type_name" type_name
-- created_at
, timestamp(replace(replace(data->>"$.balance_as_of", 'T', ' '), 'Z', '')) balance_as_of
-- institution_name
, data
from (
select id, obj_guid, name
, case when JSON_VALID(string_val) = 1 then cast(string_val as json) end data
from slots
where name = 'lunchmoney.app/assets'
) detail
;

drop table if exists lm_plaid_accounts;
create table lm_plaid_accounts as
select
detail.obj_guid guid
, data->>"$.id" id
, data->>"$.name" name
, data->>"$.display_name" display_name
, data->>"$.balance" + 0 balance
, data->>"$.type" type
, data->>"$.subtype" subtype
, timestamp(replace(replace(data->>"$.balance_last_update", 'T', ' '), 'Z', '')) balance_last_update
-- mask, ...
, ax.guid account_guid
, ax.name account_name
, ax.account_type
, data
from (
select id, obj_guid, name
, case when JSON_VALID(string_val) = 1 then cast(string_val as json) end data
from slots
where name = 'lunchmoney.app/plaid_accounts'
) detail
left join (
select a.guid, string_val, a.name, a.account_type
from slots s join accounts a on a.guid = s.obj_guid
where s.string_val like 'lm:%'
) ax
on concat('lm:', data->>"$.id") = ax.string_val
;
select * from lm_plaid_accounts;

create or replace view lm_detail as
select tx.date, tx.payee, tx.amount, tx.notes
, tx.category_id, cat.name category_name, cat.code, cat.account_guid cat_guid
, coalesce(pa.id, a.id) account_id, coalesce(pa.display_name, pa.name, a.name) account_name
, pa.account_guid
, tx.id
, tx.is_group, tx.parent_id
from lm_tx tx
left join lm_assets a on a.id = tx.asset_id
left join lm_plaid_accounts pa on pa.id = tx.plaid_account_id
left join lm_categories cat on cat.id = tx.category_id
order by tx.date
;
select * from lm_detail
-- where account_id = 23125 -- coinbase
where account_id = 43212 -- Discover
and cat_guid is not null
;

select * from split_detail;

select account_id, account_name, count(*) qty, sum(amount) from lm_detail
group by account_id, account_name
;



select * from slots where name = 'lunchmoney.app/plaid_accounts';

-- Do all GNUCash top-level budget categories have a corresponding Lunch Money category group?
-- ISSUE: leave TX, MBill, AIE behind?
select gc.parent, gc.name, gc.code, gc.hidden, lm.* from (
select a.*, root.name parent
from accounts a
join (
select guid, name, parent_guid from accounts
where (parent_guid is null and name like 'Root%')
or (name in ('EB'))
) root on a.parent_guid = root.guid
where account_type in ('INCOME', 'EXPENSE')
) gc
left join (
select * from lm_categories
where is_group = 1
) lm
on lm.name = gc.name
order by gc.hidden, gc.code
;

select * from lm_detail where cat_guid is not null and account_guid is not null;

-- Sync Discover between Lunch Money and GnuCash
create or replace view tx_split as
select post_date, tx.guid tx_guid
, sa.guid split_guid, sa.account_guid, sa.value_num / sa.value_denom amount
from transactions tx
join splits sa on sa.tx_guid = tx.guid
where tx.post_date >= '2021-07-01'
;

-- createLunchMoneyGnuCashSync:
create table lm_gc_sync as
select ga.tx_guid
, lm.*
from lm_detail lm
join tx_split ga on ga.account_guid = lm.account_guid and date(ga.post_date) = lm.date and ga.amount = -lm.amount
join accounts gc on gc.guid = lm.cat_guid
where lm.date >= '2021-07-01'
order by lm.date desc
;
select * from lm_gc_sync;

create or replace view lm_gc_sync_match as
select sd.*
, x.id, x.payee, x.notes, x.category_name, x.cat_guid
from split_detail sd
join lm_gc_sync x on x.tx_guid = sd.tx_guid and sd.amount = x.amount
where sd.path = 'Imbalance-USD';

-- IDEA: feed online_id back to lunchmoney? hm. are transactions from plaid accounts editable?

-- previewUpdateUnCat
select *
from splits s
join lm_gc_sync_match x on s.guid = x.guid
;

-- TODO: sync pay, notes

-- updateUnCat:
update splits s
join lm_gc_sync_match x on s.guid = x.guid
set s.account_guid = x.cat_guid
;
14 changes: 7 additions & 7 deletions brcal/src/gcbook.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ function DB({ connect, process }) {
await exec('commit', {});
await exec('delete from gnclock', {});
},
rollback: rollback,
rollback,
});

const locks = await exec('select hostname, pid from gnclock', [
Expand Down Expand Up @@ -211,16 +211,16 @@ export function GCBook(connect, requireText) {
async importSlots(name, records) {
console.log('importing', records.length, name, 'slots');
if (!records.length) return;
await db.exec(sql.dropSlotImport);
await db.exec(sql.createSlotImport);
await db.exec(sql.loadSlotImport, [
records.map(({ id, data }) => [id, name, JSON.stringify(data)]),
]);
const affected = { affectedRows: 1 };
const inserted = await db.query(sql.insertSlotImport, affected);
console.log('inserted', inserted.affectedRows);
await db.query(sql.updateSlotImport, affected);
console.log('updated', inserted.affectedRows);
await db.exec(sql.dropSlotImport);
const changed = { changedRows: 1 };
const inserted = await db.query(sql.insertSlotImport, changed);
console.log('inserted', inserted.changedRows);
await db.query(sql.updateSlotImport, changed);
console.log('updated', inserted.changedRows);
},
exec: db.exec,
close: db.close,
Expand Down
Loading

0 comments on commit 10dfece

Please sign in to comment.