Skip to content

Commit

Permalink
handle european formatting convention
Browse files Browse the repository at this point in the history
  • Loading branch information
ananthakumaran committed Oct 7, 2023
1 parent 7787b8f commit ce5516f
Show file tree
Hide file tree
Showing 26 changed files with 1,888 additions and 21 deletions.
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,12 @@ lint:

regen:
go build
REGENERATE=true TZ=UTC bun test tests
unset PAISA_CONFIG && REGENERATE=true TZ=UTC bun test tests

jstest:
bun test --preload ./src/happydom.ts src
go build
TZ=UTC bun test tests
unset PAISA_CONFIG && TZ=UTC bun test tests

jsbuild:
npm run build
Expand Down
72 changes: 56 additions & 16 deletions internal/ledger/ledger.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,12 @@ func (LedgerCLI) ValidateFile(journalPath string) ([]LedgerFileError, string, er
var output, error bytes.Buffer
err = utils.Exec(ledgerPath, &output, &error, "--args-only", "-f", journalPath, "balance")
if err == nil {
return errors, output.String(), nil
return errors, utils.Dos2Unix(output.String()), nil
}

re := regexp.MustCompile(`(?m)While parsing file "[^"]+", line ([0-9]+):\s*[\r\n]+(?:(?:While|>).*[\r\n]+)*((?:.*[\r\n]+)*?Error: .*[\r\n]+)`)
re := regexp.MustCompile(`(?m)While parsing file "[^"]+", line ([0-9]+):\s*\n(?:(?:While|>).*\n)*((?:.*\n)*?Error: .*\n)`)

matches := re.FindAllStringSubmatch(error.String(), -1)
matches := re.FindAllStringSubmatch(utils.Dos2Unix(error.String()), -1)

for _, match := range matches {
line, _ := strconv.ParseUint(match[1], 10, 64)
Expand Down Expand Up @@ -105,12 +105,13 @@ func (LedgerCLI) Prices(journalPath string) ([]price.Price, error) {
}

var output, error bytes.Buffer
err = utils.Exec(ledgerPath, &output, &error, "--args-only", "-f", journalPath, "pricesdb")
err = utils.Exec(ledgerPath, &output, &error, "--args-only", "-f", journalPath, "pricesdb", "--pricedb-format", "P %(datetime) %(display_account) %(quantity(scrub(display_amount))) %(commodity(scrub(display_amount)))\n")
if err != nil {
log.Error(error.String())
return prices, err
}

return parseLedgerPrices(output.String(), config.DefaultCurrency())
return parseLedgerPrices(utils.Dos2Unix(output.String()), config.DefaultCurrency())
}

func (HLedgerCLI) ValidateFile(journalPath string) ([]LedgerFileError, string, error) {
Expand All @@ -123,11 +124,11 @@ func (HLedgerCLI) ValidateFile(journalPath string) ([]LedgerFileError, string, e
var output, error bytes.Buffer
err = utils.Exec(path, &output, &error, "-f", journalPath, "--auto", "balance")
if err == nil {
return errors, output.String(), nil
return errors, utils.Dos2Unix(output.String()), nil
}

re := regexp.MustCompile(`(?m)hledger: Error: [^:]*:([0-9:-]+)[\r\n]+((?:.*[\r\n]+)*)`)
matches := re.FindAllStringSubmatch(error.String(), -1)
re := regexp.MustCompile(`(?m)hledger: Error: [^:]*:([0-9:-]+)\n((?:.*\n)*)`)
matches := re.FindAllStringSubmatch(utils.Dos2Unix(error.String()), -1)

for _, match := range matches {
lineRange := match[1]
Expand Down Expand Up @@ -179,18 +180,55 @@ func (HLedgerCLI) Prices(journalPath string) ([]price.Price, error) {
return prices, err
}

commodities, err := parseHLedgerCommodities(journalPath)
if err != nil {
log.Error(err)
return prices, err
}

commoditiesStyles := lo.Map(commodities, func(c string, _ int) string {
return fmt.Sprintf(`--commodity-style="%s" 1,000.00`, c)
})

args := append([]string{"-f", journalPath, "--infer-market-prices", "--infer-costs", "prices"}, commoditiesStyles...)

var output, error bytes.Buffer
err = utils.Exec(path, &output, &error, "-f", journalPath, "--auto", "--infer-market-prices", "--infer-costs", "prices")
err = utils.Exec(path, &output, &error, args...)
if err != nil {
log.Error(error.String())
return prices, err
}

return parseHLedgerPrices(output.String(), config.DefaultCurrency())
return parseHLedgerPrices(utils.Dos2Unix(output.String()), config.DefaultCurrency())
}

func parseHLedgerCommodities(journalPath string) ([]string, error) {
var commodities []string

path, err := binary.LookPath("hledger")
if err != nil {
return commodities, err
}

var output, error bytes.Buffer
err = utils.Exec(path, &output, &error, "-f", journalPath, "commodities")
if err != nil {
log.Error(error.String())
return commodities, err
}

lines := strings.Split(utils.Dos2Unix(output.String()), "\n")

for _, line := range lines {
commodities = append(commodities, utils.UnQuote(strings.TrimSpace(line)))
}

return commodities, nil
}

func parseLedgerPrices(output string, defaultCurrency string) ([]price.Price, error) {
var prices []price.Price
re := regexp.MustCompile(`P (\d{4}\/\d{2}\/\d{2}) (?:\d{2}:\d{2}:\d{2}) ([^\s\d.-]+|"[^"]+") ([^\r\n]+)[\r\n]+`)
re := regexp.MustCompile(`P (\d{4}\/\d{2}\/\d{2}) (?:\d{2}:\d{2}:\d{2}) ([^\s\d.-]+|"[^"]+") ([^\n]+)\n`)
matches := re.FindAllStringSubmatch(output, -1)

for _, match := range matches {
Expand Down Expand Up @@ -218,7 +256,7 @@ func parseLedgerPrices(output string, defaultCurrency string) ([]price.Price, er

func parseHLedgerPrices(output string, defaultCurrency string) ([]price.Price, error) {
var prices []price.Price
re := regexp.MustCompile(`P (\d{4}-\d{2}-\d{2}) ([^\s\d.-]+|"[^"]+") ([^\r\n]+)[\r\n]+`)
re := regexp.MustCompile(`P (\d{4}-\d{2}-\d{2}) ([^\s\d.-]+|"[^"]+") ([^\n]+)\n`)
matches := re.FindAllStringSubmatch(output, -1)

for _, match := range matches {
Expand Down Expand Up @@ -282,10 +320,11 @@ func execLedgerCommand(journalPath string, flags []string) ([]*posting.Posting,
TransactionBeginLine
TransactionEndLine
LotPrice
LotCommodity
TagRecurring
TagPeriod
)
args := append(append([]string{"--args-only", "-f", journalPath}, flags...), "csv", "--csv-format", "%(quoted(date)),%(quoted(payee)),%(quoted(display_account)),%(quoted(commodity(scrub(display_amount)))),%(quoted(quantity(scrub(display_amount)))),%(quoted(scrub(market(amount,date,'"+config.DefaultCurrency()+"') * 100000000))),%(quoted(xact.filename)),%(quoted(xact.id)),%(quoted(cleared ? \"*\" : (pending ? \"!\" : \"\"))),%(quoted(xact.beg_line)),%(quoted(xact.end_line)),%(quoted(lot_price(amount))),%(quoted(tag('Recurring'))),%(quoted(tag('Period')))\n")
args := append(append([]string{"--args-only", "-f", journalPath}, flags...), "csv", "--csv-format", "%(quoted(date)),%(quoted(payee)),%(quoted(display_account)),%(quoted(commodity(scrub(display_amount)))),%(quoted(quantity(scrub(display_amount)))),%(quoted(quantity(scrub(market(amount,date,'"+config.DefaultCurrency()+"') * 100000000)))),%(quoted(xact.filename)),%(quoted(xact.id)),%(quoted(cleared ? \"*\" : (pending ? \"!\" : \"\"))),%(quoted(xact.beg_line)),%(quoted(xact.end_line)),%(quoted(quantity(lot_price(amount)))),%(quoted(commodity(lot_price(amount)))),%(quoted(tag('Recurring'))),%(quoted(tag('Period')))\n")

ledgerPath, err := binary.LedgerBinaryPath()
if err != nil {
Expand Down Expand Up @@ -324,20 +363,21 @@ func execLedgerCommand(journalPath string, flags []string) ([]*posting.Posting,
amountAvailable := false

lotString := record[LotPrice]
if lotString != "" {
lotCurrency, lotAmount, err := parseAmount(record[LotPrice])
if lotString != "" && lotString != "0" {
lotAmount, err := decimal.NewFromString(record[LotPrice])
if err != nil {
return nil, err
}

lotCurrency := utils.UnQuote(record[LotCommodity])
if lotCurrency == config.DefaultCurrency() {
amount = lotAmount.Mul(quantity)
amountAvailable = true
}
}

if !amountAvailable {
_, amount, err = parseAmount(record[Amount])
amount, err = decimal.NewFromString(record[Amount])
if err != nil {
return nil, err
}
Expand Down
4 changes: 4 additions & 0 deletions internal/utils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -221,3 +221,7 @@ func OpenDB() (*gorm.DB, error) {
db, err := gorm.Open(sqlite.Open(config.GetDBPath()), &gorm.Config{Logger: gorm_logrus.New()})
return db, err
}

func Dos2Unix(str string) string {
return strings.ReplaceAll(str, "\r\n", "\n")
}
17 changes: 14 additions & 3 deletions src/lib/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import dayjs, { Dayjs } from "dayjs";
import { sprintf } from "sprintf-js";
import _ from "lodash";
import * as d3 from "d3";
import { loading } from "../store";
Expand Down Expand Up @@ -670,7 +669,10 @@ export function formatFloat(value: number, precision = 2) {
if (obscure()) {
return "00";
}
return sprintf(`%.${precision}f`, value);
return value.toLocaleString(USER_CONFIG.locale, {
minimumFractionDigits: precision,
maximumFractionDigits: precision
});
}

export function formatPercentage(value: number, precision = 0) {
Expand All @@ -697,7 +699,16 @@ export function formatFixedWidthFloat(value: number, width: number, precision =
if (obscure()) {
value = 0;
}
return sprintf(`%${width}.${precision}f`, value);

const formatted = value.toLocaleString(USER_CONFIG.locale, {
minimumFractionDigits: precision,
maximumFractionDigits: precision
});

if (formatted.length < width) {
return formatted.padStart(width, " ");
}
return formatted;
}

export function forEachMonth(
Expand Down
Loading

0 comments on commit ce5516f

Please sign in to comment.