From 97b407b3457f97ef1f5250465809e1c96adec203 Mon Sep 17 00:00:00 2001 From: Anantha Kumaran Date: Sun, 21 Aug 2022 16:29:09 +0530 Subject: [PATCH] rename Checking to Assets:Checking --- cmd/init.go | 10 +++---- docs/src/commodities.md | 6 ++-- docs/src/tutorial.md | 30 ++++++++++---------- internal/server/gain.go | 2 +- internal/server/investment.go | 2 +- internal/server/ledger.go | 8 ++++-- internal/service/xirr.go | 1 + web/src/ledger.ts | 20 ++++++++++---- web/src/overview.ts | 52 +++++++++++++---------------------- web/static/index.html | 8 +----- 10 files changed, 66 insertions(+), 73 deletions(-) diff --git a/cmd/init.go b/cmd/init.go index e147884..3e5248a 100644 --- a/cmd/init.go +++ b/cmd/init.go @@ -103,8 +103,8 @@ func emitSalary(file *os.File, start time.Time) { %s Salary Income:Salary:%s Assets:Debt:EPF %s INR - Tax %s INR - Checking %s INR + Expenses:Tax %s INR + Assets:Checking %s INR `, start.Format("2006/01/02"), company, formatFloat(salary*0.12), formatFloat(salary*0.20), formatFloat(salary*0.68))) if err != nil { log.Fatal(err) @@ -134,7 +134,7 @@ func emitEquityMutualFund(file *os.File, start time.Time, pricesTree map[string] _, err := file.WriteString(fmt.Sprintf(` %s Mutual Fund Nifty Assets:Equity:NIFTY %s NIFTY @ %s INR - Checking + Assets:Checking `, start.Format("2006/01/02"), formatFloat(10000/pc.Value*multiplier), formatFloat(pc.Value))) if err != nil { log.Fatal(err) @@ -144,7 +144,7 @@ func emitEquityMutualFund(file *os.File, start time.Time, pricesTree map[string] _, err = file.WriteString(fmt.Sprintf(` %s Mutual Fund Nifty Next 50 Assets:Equity:NIFTY_JR %s NIFTY_JR @ %s INR - Checking + Assets:Checking `, start.Format("2006/01/02"), formatFloat(10000/pc.Value*multiplier), formatFloat(pc.Value))) if err != nil { log.Fatal(err) @@ -161,7 +161,7 @@ func emitDebtMutualFund(file *os.File, start time.Time, pricesTree map[string]*b _, err := file.WriteString(fmt.Sprintf(` %s Mutual Fund Birla Corporate Fund Assets:Debt:ABCBF %s ABCBF @ %s INR - Checking + Assets:Checking `, start.Format("2006/01/02"), formatFloat(10000/pc.Value*multiplier), formatFloat(pc.Value))) if err != nil { log.Fatal(err) diff --git a/docs/src/commodities.md b/docs/src/commodities.md index cb92baf..11b01be 100644 --- a/docs/src/commodities.md +++ b/docs/src/commodities.md @@ -9,15 +9,15 @@ tracked as a commodity. Few example transactions can be found below. Assets:Equity:NPS:SBI:E 15.9378 NPS_SBI_E @ 23.5289 INR ;// account name units commodity purchase price ;// name per unit - Checking + Assets:Checking 2019/02/21 NPS Assets:Equity:NPS:SBI:E 1557.2175 NPS_SBI_E @ 23.8406 INR - Checking + Assets:Checking 2020/06/25 Gold Assets:Gold 40 GOLD @ 4650 INR - Checking + Assets:Checking ``` **paisa** comes with inbuilt support for fetching the latest price of diff --git a/docs/src/tutorial.md b/docs/src/tutorial.md index 998b949..6234dc8 100644 --- a/docs/src/tutorial.md +++ b/docs/src/tutorial.md @@ -14,13 +14,13 @@ content ```go 2022/01/01 Salary Income:Salary:Acme -100,000 INR - Checking 100,000 INR + Assets:Checking 100,000 INR ``` **ledger** follows the double-entry accounting system. In simple terms, it tracks the movement of money from debit account to credit account. Here `Income:Salary:Acme` is the debit account and -`Checking` is the credit account. The date at which the +`Assets:Checking` is the credit account. The date at which the transaction took place and a description of the transaction is written in the first line followed by the list of credit or debit entry. Account [naming conventions](./accounts.md) are explained later. The `:` in the account name @@ -31,23 +31,23 @@ accounts must be zero. ```go 2022/01/01 Salary Income:Salary:Acme -100,000 INR - Checking 100,000 INR + Assets:Checking 100,000 INR 2022/02/01 Salary Income:Salary:Acme -100,000 INR - Checking 100,000 INR + Assets:Checking 100,000 INR 2022/03/01 Salary Income:Salary:Acme -100,000 INR - Checking 100,000 INR + Assets:Checking 100,000 INR ``` let's add few more entries. The total balance in your savings account could be found by ```go -❯ ledger -f personal.ledger balance Checking -300,000 INR Checking +❯ ledger -f personal.ledger balance Assets:Checking +300,000 INR Assets:Checking ``` Let's say your company deducts 12,000 INR and contributes it to EPF, @@ -56,25 +56,25 @@ we could represent it as follows ```go 2022/01/01 Salary Income:Salary:Acme -100,000 INR - Checking 88,000 INR + Assets:Checking 88,000 INR Assets:Debt:EPF 12,000 INR 2022/02/01 Salary Income:Salary:Acme -100,000 INR - Checking 88,000 INR + Assets:Checking 88,000 INR Assets:Debt:EPF 12,000 INR 2022/03/01 Salary Income:Salary:Acme -100,000 INR - Checking 88,000 INR + Assets:Checking 88,000 INR Assets:Debt:EPF 12,000 INR ``` ```shell -❯ ledger -f personal.ledger balance Assets Checking +❯ ledger -f personal.ledger balance Assets 36,000 INR Assets:Debt:EPF - 264,000 INR Checking + 264,000 INR Assets:Checking -------------------- 300,000 INR ``` @@ -88,17 +88,17 @@ month. ```go 2018/01/01 Investment - Checking -20,000 INR + Assets:Checking -20,000 INR Assets:Equity:NIFTY 148.0865 NIFTY @ 67.5281 INR Assets:Equity:NIFTY_JR 358.6659 NIFTY_JR @ 27.8811 INR 2018/02/01 Investment - Checking -20,000 INR + Assets:Checking -20,000 INR Assets:Equity:NIFTY 140.2870 NIFTY @ 71.2824 INR Assets:Equity:NIFTY_JR 363.2242 NIFTY_JR @ 27.5312 INR 2018/03/01 Investment - Checking -20,000 INR + Assets:Checking -20,000 INR Assets:Equity:NIFTY 147.5908 NIFTY @ 67.7549 INR Assets:Equity:NIFTY_JR 378.4323 NIFTY_JR @ 26.4248 INR ``` diff --git a/internal/server/gain.go b/internal/server/gain.go index ea97371..b996336 100644 --- a/internal/server/gain.go +++ b/internal/server/gain.go @@ -18,7 +18,7 @@ type Gain struct { func GetGain(db *gorm.DB) gin.H { var postings []posting.Posting - result := db.Where("account like ?", "Assets:%").Order("date ASC").Find(&postings) + result := db.Where("account like ? and account != ?", "Assets:%", "Assets:Checking").Order("date ASC").Find(&postings) if result.Error != nil { log.Fatal(result.Error) } diff --git a/internal/server/investment.go b/internal/server/investment.go index 3a5944a..b5f9eeb 100644 --- a/internal/server/investment.go +++ b/internal/server/investment.go @@ -28,7 +28,7 @@ func GetInvestment(db *gorm.DB) gin.H { var assets []posting.Posting var incomes []posting.Posting var expenses []posting.Posting - result := db.Where("account like ? order by date asc", "Assets:%").Find(&assets) + result := db.Where("account like ? and account != ? order by date asc", "Assets:%", "Assets:Checking").Find(&assets) if result.Error != nil { log.Fatal(result.Error) } diff --git a/internal/server/ledger.go b/internal/server/ledger.go index 7ae07be..548b032 100644 --- a/internal/server/ledger.go +++ b/internal/server/ledger.go @@ -30,7 +30,9 @@ func GetLedger(db *gorm.DB) gin.H { } postings = service.PopulateMarketPrice(db, postings) - breakdowns := computeBreakdown(db, lo.Filter(postings, func(p posting.Posting, _ int) bool { return strings.HasPrefix(p.Account, "Assets:") })) + breakdowns := computeBreakdown(db, lo.Filter(postings, func(p posting.Posting, _ int) bool { + return strings.HasPrefix(p.Account, "Assets:") + })) return gin.H{"postings": postings, "breakdowns": breakdowns} } @@ -51,14 +53,14 @@ func computeBreakdown(db *gorm.DB, postings []posting.Posting) map[string]Breakd for group, leaf := range accounts { ps := lo.Filter(postings, func(p posting.Posting, _ int) bool { return strings.HasPrefix(p.Account, group) }) investmentAmount := lo.Reduce(ps, func(acc float64, p posting.Posting, _ int) float64 { - if p.Amount < 0 || service.IsInterest(db, p) { + if p.Account == "Assets:Checking" || p.Amount < 0 || service.IsInterest(db, p) { return acc } else { return acc + p.Amount } }, 0.0) withdrawalAmount := lo.Reduce(ps, func(acc float64, p posting.Posting, _ int) float64 { - if p.Amount > 0 || service.IsInterest(db, p) { + if p.Account == "Assets:Checking" || p.Amount > 0 || service.IsInterest(db, p) { return acc } else { return acc + -p.Amount diff --git a/internal/service/xirr.go b/internal/service/xirr.go index 21f3290..b0f7729 100644 --- a/internal/service/xirr.go +++ b/internal/service/xirr.go @@ -9,6 +9,7 @@ import ( ) func XIRR(db *gorm.DB, ps []posting.Posting) float64 { + ps = lo.Filter(ps, func(p posting.Posting, _ int) bool { return p.Account != "Assets:Checking" }) today := time.Now() marketAmount := lo.Reduce(ps, func(acc float64, p posting.Posting, _ int) float64 { return acc + p.MarketAmount }, 0.0) payments := lo.Reverse(lo.Map(ps, func(p posting.Posting, _ int) xirr.Payment { diff --git a/web/src/ledger.ts b/web/src/ledger.ts index 076ee66..6505eb1 100644 --- a/web/src/ledger.ts +++ b/web/src/ledger.ts @@ -114,14 +114,24 @@ function renderBreakdowns(breakdowns: Breakdown[]) { ${indent}${lastName( b.group )} - ${formatCurrency(b.investment_amount)} - ${formatCurrency(b.withdrawal_amount)} + ${ + b.investment_amount != 0 ? formatCurrency(b.investment_amount) : "" + } + ${ + b.withdrawal_amount != 0 ? formatCurrency(b.withdrawal_amount) : "" + } ${ b.balance_units > 0 ? formatFloat(b.balance_units, 4) : "" } - ${formatCurrency(b.market_amount)} - ${formatCurrency(gain)} - ${formatFloat(b.xirr)} + ${ + b.market_amount != 0 ? formatCurrency(b.market_amount) : "" + } + ${ + b.investment_amount != 0 && gain != 0 ? formatCurrency(gain) : "" + } + ${ + b.xirr > 0.0001 ? formatFloat(b.xirr) : "" + } `; }); } diff --git a/web/src/overview.ts b/web/src/overview.ts index 66f67c1..ba5768f 100644 --- a/web/src/overview.ts +++ b/web/src/overview.ts @@ -24,8 +24,10 @@ export default async function () { current.withdrawal_amount ) ); - setHtml("investment", formatCurrency(current.investment_amount)); - setHtml("withdrawal", formatCurrency(current.withdrawal_amount)); + setHtml( + "investment", + formatCurrency(current.investment_amount - current.withdrawal_amount) + ); setHtml("gains", formatCurrency(current.gain_amount)); setHtml("xirr", formatFloat(xirr)); @@ -48,22 +50,20 @@ function renderOverview(points: Overview[], element: Element) { const colors = ["#b2df8a", "#fb9a99"]; const areaScale = d3.scaleOrdinal().domain(areaKeys).range(colors); - const lineKeys = ["networth", "investment", "withdrawal"]; + const lineKeys = ["networth", "investment"]; const lineScale = d3 .scaleOrdinal() .domain(lineKeys) .range(["#1f77b4", "#17becf", "#ff7f0e"]); + + const positions = _.flatMap(points, (p) => [ + p.gain_amount + p.investment_amount - p.withdrawal_amount, + p.investment_amount - p.withdrawal_amount + ]); + positions.push(0); + const x = d3.scaleTime().range([0, width]).domain([start, end]), - y = d3 - .scaleLinear() - .range([height, 0]) - .domain([ - 0, - d3.max( - points, - (d) => d.gain_amount + d.investment_amount - ) - ]), + y = d3.scaleLinear().range([height, 0]).domain(d3.extent(positions)), z = d3.scaleOrdinal(colors).domain(areaKeys); const area = (y0, y1) => @@ -103,7 +103,7 @@ function renderOverview(points: Overview[], element: Element) { .attr( "d", area(height, (d) => { - return y(d.gain_amount + d.investment_amount); + return y(d.gain_amount + d.investment_amount - d.withdrawal_amount); }) ); @@ -115,7 +115,7 @@ function renderOverview(points: Overview[], element: Element) { .attr( "d", area(0, (d) => { - return y(d.gain_amount + d.investment_amount); + return y(d.gain_amount + d.investment_amount - d.withdrawal_amount); }) ); @@ -130,7 +130,7 @@ function renderOverview(points: Overview[], element: Element) { .attr( "d", area(0, (d) => { - return y(d.investment_amount); + return y(d.investment_amount - d.withdrawal_amount); }) ); @@ -145,7 +145,7 @@ function renderOverview(points: Overview[], element: Element) { .attr( "d", area(height, (d) => { - return y(d.investment_amount); + return y(d.investment_amount - d.withdrawal_amount); }) ); @@ -159,21 +159,7 @@ function renderOverview(points: Overview[], element: Element) { .line() .curve(d3.curveBasis) .x((d) => x(d.timestamp)) - .y((d) => y(d.investment_amount)) - ); - - layer - .append("path") - .style("stroke", lineScale("withdrawal")) - .style("fill", "none") - .attr( - "d", - d3 - .line() - .curve(d3.curveBasis) - .defined((d) => d.withdrawal_amount > 0) - .x((d) => x(d.timestamp)) - .y((d) => y(d.withdrawal_amount)) + .y((d) => y(d.investment_amount - d.withdrawal_amount)) ); layer @@ -192,7 +178,7 @@ function renderOverview(points: Overview[], element: Element) { svg .append("g") .attr("class", "legendOrdinal") - .attr("transform", "translate(365,3)"); + .attr("transform", "translate(265,3)"); const legendOrdinal = legend .legendColor() diff --git a/web/static/index.html b/web/static/index.html index a628976..5f7a6ef 100644 --- a/web/static/index.html +++ b/web/static/index.html @@ -42,16 +42,10 @@
-

Investment

+

Net Investment

-
-
-

Withdrawal

-

-
-

Gain