# docker-finance | modern accounting for the power-user
#
# Copyright (C) 2021-2025 Aaron Fiore (Founder, Evergreen Crypto LLC)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.

# TODO: currently, only supports "Legacy Invoice" and "Wallets" format (w/ additional custom columns)
fields ReceivedDate,StoreId,OrderId,InvoiceId,InvoiceCreatedDate,InvoiceExpirationDate,InvoiceMonitoringDate,txid,index,Destination,PaymentType,CryptoCode,Paid,NetworkFee,ConversionRate,PaidCurrency,InvoiceCurrency,InvoiceDue,InvoicePrice,InvoiceTaxIncluded,InvoiceTip,InvoiceSubtotal,InvoiceItemCode,InvoiceItemDesc,InvoiceFullStatus,InvoiceStatus,InvoiceExceptionStatus,BuyerEmail,Accounted,direction,subaccount

# NOTE: BTCPayServer exports to localtime
date-format %Y-%m-%d %H:%M:%S %z
date %ReceivedDate

description %ReceivedDate

if %InvoiceItemDesc [a-z0-9]
  description %ReceivedDate | %InvoiceItemDesc

account1 assets:btcpayserver:%subaccount:%CryptoCode
amount %Paid %CryptoCode

# If invoice is expired or otherwise not accounted for, skip
if %Accounted ^[^a-z]*$
  skip

#
# Comment
#

# NOTE: all IN assumed to be INCOME

# Default comment
comment created:%InvoiceCreatedDate, expired:%InvoiceExpirationDate, store_id:%StoreId, order_id:%OrderId, invoice_id:%InvoiceId, invoice_tax:%InvoiceTaxIncluded, invoice_tip:%InvoiceTip, invoice_subtotal:%InvoiceSubtotal, type:%PaymentType, to_address:%Destination, txid:%txid, index:%index, status:%InvoiceStatus, direction:%direction, taxed_as:INCOME

# Comment w/ item code
if %InvoiceItemCode [a-z0-9]
  comment created:%InvoiceCreatedDate, expired:%InvoiceExpirationDate, store_id:%StoreId, order_id:%OrderId, invoice_id:%InvoiceId, invoice_tax:%InvoiceTaxIncluded, invoice_tip:%InvoiceTip, invoice_subtotal:%InvoiceSubtotal, item_code:%InvoiceItemCode, type:%PaymentType, to_address:%Destination, txid:%txid, index:%index, status:%InvoiceStatus, direction:%direction, taxed_as:INCOME

# Comment w/ buyer email
if %BuyerEmail [a-z0-9]
  comment created:%InvoiceCreatedDate, expired:%InvoiceExpirationDate, store_id:%StoreId, order_id:%OrderId, invoice_id:%InvoiceId, invoice_tax:%InvoiceTaxIncluded, invoice_tip:%InvoiceTip, invoice_subtotal:%InvoiceSubtotal, email:%BuyerEmail, type:%PaymentType, to_address:%Destination, txid:%txid, index:%index, status:%InvoiceStatus, direction:%direction, taxed_as:INCOME

# Comment w/ both item code + buyer email
if %InvoiceItemCode [a-z0-9]
& %BuyerEmail [a-z0-9]
  comment created:%InvoiceCreatedDate, expired:%InvoiceExpirationDate, store_id:%StoreId, order_id:%OrderId, invoice_id:%InvoiceId, invoice_tax:%InvoiceTaxIncluded, invoice_tip:%InvoiceTip, invoice_subtotal:%InvoiceSubtotal, item_code:%InvoiceItemCode, email:%BuyerEmail, type:%PaymentType, to_address:%Destination, txid:%txid, index:%index, status:%InvoiceStatus, direction:%direction, taxed_as:INCOME

#
# Direction
#

# NOTE/TODO:
#
#   InvoiceTaxIncluded, InvoiceTip and InvoiceSubtotal are not included
#   as new accounts because they are static across rows and treated more
#   like tags (i.e., if an invoice is not paid in full in a single tx,
#   then these entries will be repeated across rows).

# Default income
if %direction ^IN$
  account2 income:btcpayserver:%subaccount:%CryptoCode
  comment2 %ReceivedDate,INCOME,btcpayserver:%subaccount,%CryptoCode,%Paid,%InvoiceCurrency,%PaidCurrency,%InvoiceId

# Default refund
#
# NOTE:
#
#   - If the tx is not a refund, use custom rules for account2/comment2
#     * If the tx also not an expense, remove comment tag taxed_as:SPEND
#
#   - Since refunds may not be considered taxable events, and since the
#     "Wallets" export only includes the market price of the tx at the
#     time of sending (refunding), use custom rules to replace the
#     sending tx's price to the time of receiving (the income tx).
#
#     This way one can "negate" the original income event by "spending"
#     the original amount at the original rate (the rate at which the
#     invoice was paid):
#
#     Example in custom rules (replace "MANUAL_ADJUSTMENT_NEEDED"):
#
#       if %direction ^OUT$
#         comment txid:%txid, confirmed:%Accounted, direction:%direction, taxed_as:SPEND
#         comment2 %ReceivedDate,SPEND,btcpayserver:%subaccount:%CryptoCode,%CryptoCode,%Paid,USD,MANUAL_ADJUSTMENT_NEEDED,REFUND
#
#   - Use different custom rules if your refund type is not the default
#     provided option of 'price at the rate the invoice was paid'.
#
if %direction ^OUT$
  account2 expenses:btcpayserver:%subaccount:refunds:%CryptoCode
  amount -%Paid %CryptoCode
  comment txid:%txid, confirmed:%Accounted, direction:%direction, taxed_as:SPEND
  comment2 %ReceivedDate,SPEND,btcpayserver:%subaccount:%CryptoCode,%CryptoCode,%Paid,USD,,REFUND
# TODO: don't hardcode USD (upstream should make the "Rate (XXX)" currency column a separate column).

if %direction ^OUT$
& %NetworkFee [1-9]
  account3 assets:btcpayserver:%subaccount:%CryptoCode
  amount3 -%NetworkFee %CryptoCode
  account4 expenses:electrum:%subaccount:fees:%CryptoCode
  amount4 %NetworkFee %CryptoCode
  comment txid:%txid, confirmed:%Accounted, direction:%direction, taxed_as:SPEND
  comment3 %ReceivedDate,SPEND,btcpayserver:%subaccount:%CryptoCode,%CryptoCode,%NetworkFee,USD,%PaidCurrency,FEE
# Using comment3 so a comment2 SPEND isn't overwritten (when applicable)
# TODO: don't hardcode USD (upstream should make the "Rate (XXX)" currency column a separate column).

# vim: sw=2 sts=2 si ai et
