Hi,

Thanks a lot for replying.

- As a workaround to the issue you mention, maybe a single file can be 
specified to populate a new price database for automatically applying these 
prices. That way if a user inserts a transaction with a particular price 
attached to a posting, the database won't pick it up as it is only using 
the one file to get the price points. But I understand your broader point.

- For my use case, what's happening is that Paypal charges me more money in 
the form of currency conversion by offering me an unfavourable rate (~5% 
lower than the market rate), than they charge in their "fees" (which is a 
percentage of sales). My country's central bank provides a reference 
conversion rate that I can compare against. The difference between how much 
I would have got with the reference rate for that day versus how much 
Paypal actually paid me gives me the actual fee that Paypal is charging me. 
The reference rate is also used for other stuff in a similar way, as being 
the official exchange rate, so it is useful to store it in a database and 
have Beancount refer to it automatically.

I decided to make a plugin for this. It seems to works perfectly. I was 
able to apply the price to the relevant postings and also adjust the 
automatic postings appropriately, but with this done, I needed Beancount to 
process the file and apply all the transformations, etc. However I could 
not find a way to call a plugin before the transformations, etc. are done, 
so I ended up using code from beancount.loader to process the entries again 
once I had applied the price. This works just fine, but for future use is 
there a more direct/appropriate way of doing this? To get the plugin to 
work after Beancount has parsed the files and made entries but before it 
actually starts working on the entries?

This is the plugin:

#autofetch_prices.py
#input: currencyList as "targetCurrency/baseCurrency", for example: plugin 
"autofetch_prices" "USD/CAD"
#finds all postings in targetCurrency where the price is not set, fetches 
the appropriate price for that date and sets it.
#example: for input "USD/CAD", every entry like "10 USD" gets a price and 
becomes something like "10 USD @ 1.22 CAD"


import beancount
from beancount.core.interpolate import AUTOMATIC_META
from beancount.core.number import MISSING
from beancount.core import data
from beancount.parser import booking
from beancount.ops import validation
from beancount.utils import misc_utils

__plugins__ = ['autofetch_prices']


def autofetch_prices(entries, options_map, currencyList):
targetCurrency, baseCurrency = currencyList.split('/')
priceMap = beancount.core.prices.build_price_map(entries)
for entry in entries:
if isinstance(entry, data.Transaction):
found = False
for k, posting in enumerate(entry.postings):
if posting.price==None and posting.units.currency==targetCurrency and 
posting.meta and not AUTOMATIC_META in posting.meta:
price = beancount.core.prices.get_price(priceMap, 
targetCurrency+"/"+baseCurrency, 
entry.date)[1]
#if there's no price from the priceDB for this posting, do nothing and move 
over to the next posting.
if price==None:
continue
found = True
priceAmount = beancount.core.amount.Amount(price, baseCurrency)
posting = posting._replace(price=priceAmount)
entry.postings[k] = posting
if found:
for z, posting in enumerate(entry.postings):
if posting.meta and AUTOMATIC_META in posting.meta and 
posting.meta[AUTOMATIC_META]:
if posting.units.currency==targetCurrency:
entry.postings.remove(posting)
if posting.units.currency==baseCurrency:
posting = posting._replace(units = MISSING)
del posting.meta[AUTOMATIC_META]
entry.postings[z] = posting
#remove this plugin now as it has done it's job and we don't want infinite 
recursion next
for plugin in options_map["plugin"]:
if plugin[0]==__plugins__[0]:
options_map["plugin"].remove(plugin)



#The following code is from the beancount.loader._load function
entries.sort(key=data.entry_sortkey)

# Run interpolation on incomplete entries.
entries, balance_errors = booking.book(entries, options_map)
parse_errors = []
parse_errors.extend(balance_errors)

# Transform the entries.
entries, errors = beancount.loader.run_transformations(entries, 
parse_errors, options_map, None)

# Validate the list of entries.
with misc_utils.log_time('beancount.ops.validate', None, indent=1):
valid_errors = validation.validate(entries, options_map, None)
errors.extend(valid_errors)

# Compute the input hash.
options_map['input_hash'] = beancount.loader.compute_input_hash(options_map[
'include'])

return entries, errors



Thanks!
Jitin

On Tuesday, 12 May 2020 07:12:15 UTC+5:30, Martin Blais wrote:
>
> On Mon, May 11, 2020 at 3:29 PM jitin <[email protected]> wrote:
>
>> Hi,
>>
>> I have postings which are something like:
>>
>> 2017-04-03 * "someone"
>> Income:Sales:International -42.5 USD
>> Equity:Drawings 2524.68 INR
>> Expenses:Banking:PaypalCharges
>>
>> However Benacount reports them as 4 transactions in a non-intuitive way:
>>
>> Income:Sales:International     -42.5 USD -42.5 USD 
>> Expenses:Banking:PaypalCharges 42.5 USD 42.5 USD 
>> Equity:Drawings 2524.68 INR 2524.68 INR 
>> Expenses:Banking:PaypalCharges -2524.68 INR -2524.68 INR
>>
>> If however I add a price information to the posting like this:
>>
>> 2017-04-03 * "someone"
>> Income:Sales:International -42.5 USD @65 INR
>> Equity:Drawings 2524.68 INR
>> Expenses:Banking:PaypalCharges
>>
>> Beancount reports it as 3 transactions in the way I want:
>>
>> Income:Sales:International     -42.5 USD 65 INR -2762.5 INR 
>> Equity:Drawings                 2524.68 INR 2524.68 INR 
>> Expenses:Banking:PaypalCharges 237.82 INR 237.82 INR 
>>
>>
>> I have already added price entries like this:
>> 2014-01-01 commodity USD
>>
>> 2015-08-30 price USD 66.15 INR
>> 2015-08-31 price USD 66.15 INR
>> 2015-09-01 price USD 66.35 INR
>> ...
>>
>> Is there any way for Beancount to pick up the price (the @65 INR part) 
>> automatically from this price list according to the transaction date, 
>> without me manually specifying the USD to INR price for each transaction?
>>
>
> Not at the moment. Two reasons for this:
> - Balancing Beancount transactions can be mildly tricky, so limiting the 
> effects to be local only to the data input to the transaction has been 
> driving the design.
> Non-local effects of changes to the price database could be tricky to 
> debug, e.g., you insert a transaction with a price attached to a posting, 
> that inserts a price point in the database, and then a bunch of unrelated 
> transactions break because the prices of their conversions is changed.
> (You could argue that reducing lots is a function of the inventory of the 
> account prior to applying the transaction and that this is not local, sure, 
> but notice that it's a bit tricky enough to resolve those at times.)
> - Generally speaking the rate at which a price conversion is made is an 
> explicit specific number that is subject to being input in your 
> transaction. I don't think it's common that one would want to use some 
> arbitrary rate (but I'm not 100% sure). In your example, the actual PayPal 
> charge is a precise number. Unless all you want is an approximation (I 
> doubt it), you still have to input it.
> That being said, I think in a future version that could be 
> considered, it's been requested frequently.
>
>  
>
>>
>> Thanks a lot.
>>
>> -- 
>> You received this message because you are subscribed to the Google Groups 
>> "Beancount" group.
>> To unsubscribe from this group and stop receiving emails from it, send an 
>> email to [email protected].
>> To view this discussion on the web visit 
>> https://groups.google.com/d/msgid/beancount/def09727-5aa1-4490-b8ed-428bde58b5f9%40googlegroups.com
>>  
>> <https://groups.google.com/d/msgid/beancount/def09727-5aa1-4490-b8ed-428bde58b5f9%40googlegroups.com?utm_medium=email&utm_source=footer>
>> .
>
>
On Tuesday, 12 May 2020 07:12:15 UTC+5:30, Martin Blais wrote:
>
> On Mon, May 11, 2020 at 3:29 PM jitin <[email protected] <javascript:>> 
> wrote:
>
>> Hi,
>>
>> I have postings which are something like:
>>
>> 2017-04-03 * "someone"
>> Income:Sales:International -42.5 USD
>> Equity:Drawings 2524.68 INR
>> Expenses:Banking:PaypalCharges
>>
>> However Benacount reports them as 4 transactions in a non-intuitive way:
>>
>> Income:Sales:International    -42.5 USD -42.5 USD 
>> Expenses:Banking:PaypalCharges 42.5 USD 42.5 USD 
>> Equity:Drawings 2524.68 INR 2524.68 INR 
>> Expenses:Banking:PaypalCharges -2524.68 INR -2524.68 INR
>>
>> If however I add a price information to the posting like this:
>>
>> 2017-04-03 * "someone"
>> Income:Sales:International -42.5 USD @65 INR
>> Equity:Drawings 2524.68 INR
>> Expenses:Banking:PaypalCharges
>>
>> Beancount reports it as 3 transactions in the way I want:
>>
>> Income:Sales:International    -42.5 USD 65 INR -2762.5 INR 
>> Equity:Drawings                2524.68 INR 2524.68 INR 
>> Expenses:Banking:PaypalCharges 237.82 INR 237.82 INR 
>>
>>
>> I have already added price entries like this:
>> 2014-01-01 commodity USD
>>
>> 2015-08-30 price USD 66.15 INR
>> 2015-08-31 price USD 66.15 INR
>> 2015-09-01 price USD 66.35 INR
>> ...
>>
>> Is there any way for Beancount to pick up the price (the @65 INR part) 
>> automatically from this price list according to the transaction date, 
>> without me manually specifying the USD to INR price for each transaction?
>>
>
> Not at the moment. Two reasons for this:
> - Balancing Beancount transactions can be mildly tricky, so limiting the 
> effects to be local only to the data input to the transaction has been 
> driving the design.
> Non-local effects of changes to the price database could be tricky to 
> debug, e.g., you insert a transaction with a price attached to a posting, 
> that inserts a price point in the database, and then a bunch of unrelated 
> transactions break because the prices of their conversions is changed.
> (You could argue that reducing lots is a function of the inventory of the 
> account prior to applying the transaction and that this is not local, sure, 
> but notice that it's a bit tricky enough to resolve those at times.)
> - Generally speaking the rate at which a price conversion is made is an 
> explicit specific number that is subject to being input in your 
> transaction. I don't think it's common that one would want to use some 
> arbitrary rate (but I'm not 100% sure). In your example, the actual PayPal 
> charge is a precise number. Unless all you want is an approximation (I 
> doubt it), you still have to input it.
> That being said, I think in a future version that could be 
> considered, it's been requested frequently.
>
>  
>
>>
>> Thanks a lot.
>>
>> -- 
>> You received this message because you are subscribed to the Google Groups 
>> "Beancount" group.
>> To unsubscribe from this group and stop receiving emails from it, send an 
>> email to [email protected] <javascript:>.
>> To view this discussion on the web visit 
>> https://groups.google.com/d/msgid/beancount/def09727-5aa1-4490-b8ed-428bde58b5f9%40googlegroups.com
>>  
>> <https://groups.google.com/d/msgid/beancount/def09727-5aa1-4490-b8ed-428bde58b5f9%40googlegroups.com?utm_medium=email&utm_source=footer>
>> .
>>
>

-- 
You received this message because you are subscribed to the Google Groups 
"Beancount" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/beancount/b699ccf5-9177-42e2-a1bd-fc56d9deeaaf%40googlegroups.com.

Reply via email to