diff --git a/crypto_tax/__init__.py b/crypto_tax/__init__.py index 7f0790c..ed277ee 100644 --- a/crypto_tax/__init__.py +++ b/crypto_tax/__init__.py @@ -24,6 +24,7 @@ from decimal import Decimal from collections import deque from fin_depo.data import * import datetime +import dataclassabc import dataclasses import logging import fin_data @@ -42,9 +43,49 @@ logger = logging.getLogger(__name__) FIN_DB = fin_data.FinancialDatabase(enable_kucoin=True, enable_nationalbanken_dk=True) +@dataclassabc.dataclassabc(frozen=True) +class TransferDetails(fin_depo.data.DoubleRegister): + withdrawal: fin_depo.data.WithdrawalDetails + deposit: fin_depo.data.DepositDetails + + @property + def fee(self) -> AssetAmount | None: + return self.withdrawal.fee # TODO? + + @property + def executed_time(self) -> datetime.datetime: + return self.withdrawal.executed_time + + @property + def input(self) -> None: + return None + + @property + def output(self) -> None: + return None + + +def collate_interaccount_transfers(transfers: list[fin_depo.data.DoubleRegister]) -> list[fin_depo.data.DoubleRegister]: + new_transfers = [] + for t in transfers: + if isinstance(t, fin_depo.data.DepositDetails): + prev_transfer = new_transfers[-1] if len(new_transfers) > 0 else None + if isinstance(prev_transfer , fin_depo.data.WithdrawalDetails): + if prev_transfer.withdrawn == t.deposit: + del new_transfers[-1] + new_transfers.append(TransferDetails(prev_transfer, t)) + continue + del prev_transfer + + new_transfers.append(t) + del t + + return new_transfers + def compute_fifo(transfers: list) -> TaxReport: transfers.sort(key=lambda t:t.executed_time) + transfers = collate_interaccount_transfers(transfers) bought_and_sold_for: list[BoughtAndSold] = [] @@ -52,7 +93,7 @@ def compute_fifo(transfers: list) -> TaxReport: ledger_entries = [] prices_bought_for: dict[Asset, deque[BoughtAndNotYetSold]] = {} - if False: + if True: prices_bought_for[MPC] = deque() # TODO: prices_bought_for[MPC].append(BoughtAndNotYetSold(AssetAmount(MPC, Decimal(80)), datetime.datetime(2024, 4,1,1,1,1,1))) @@ -67,7 +108,8 @@ def compute_fifo(transfers: list) -> TaxReport: amount = amount_to_sell while amount.amount > 0: if len(prices_bought_for[amount.asset]) == 0: - raise Exception('Miscalculation: ' + str(amount)) + msg = f'Miscalculation: {amount} of {amount_to_sell}' + raise Exception(msg) partial = prices_bought_for[amount.asset].popleft() amount_covered_by_partial = min(partial.amount, amount) @@ -116,6 +158,7 @@ def compute_fifo(transfers: list) -> TaxReport: for transfer in transfers: + # Sell if _input := transfer.input: variant = 'WITHDRAW' if transfer.output is None else 'SELL' @@ -130,6 +173,8 @@ def compute_fifo(transfers: list) -> TaxReport: del variant del output + # TODO: Output line for transfer. + # Fee if fee := transfer.fee: spend(fee, transfer.executed_time) diff --git a/crypto_tax/output_excel.py b/crypto_tax/output_excel.py index 81a1724..7c14346 100644 --- a/crypto_tax/output_excel.py +++ b/crypto_tax/output_excel.py @@ -55,13 +55,13 @@ def add_headers(sheet, column_headers): cell.alignment = ALIGN_CENTER cell.border = BORDER_BOTTOM -def set_number_format(sheet, range): +def set_number_format(sheet, range, format="0.00"): for row in sheet[range]: for cell in row: - cell.number_format = "0.00" + cell.number_format = format def write_current_assets(sheet, tax_report: TaxReport): - column_headers = ['Værdipapir', 'Mængde', 'Kurs', 'Værdi (DKK)', + column_headers = ['Værdipapir', 'Mængde', 'Kurs', 'Sum (DKK)', 'Beskatningstype'] add_headers(sheet, column_headers) row_idx = 2 @@ -72,7 +72,7 @@ def write_current_assets(sheet, tax_report: TaxReport): row = [ asset.raw_short_name(), total_amount, - exchange_rate_asset_to_dkk, + exchange_rate_asset_to_dkk or 'Unknown', f'=B{row_idx}*C{row_idx}', TAX_TYPES[asset], ] @@ -97,7 +97,7 @@ def write_ledger_sheet(sheet, tax_report: TaxReport): 'Mængde', 'Kontoudbyder', '' - ] + [a.raw_short_name() for a in assets] + ] + [a.raw_short_name() for a in assets] + ['', 'Kommentarer'] add_headers(sheet, column_headers) row_idx = 2 @@ -156,9 +156,9 @@ def write_fifo_sheet(sheet, bought_and_sold_for: list, exchange_rate_at_time) -> 'Mængde', 'Anskaffelseskurs', 'Salgskurs', - 'Anskaffelsesværdi (DKK)', - 'Salgsværdi (DKK)', - 'Profit (DKK)', 'Tab (DKK)', + 'Købssum (DKK)', + 'Salgssum (DKK)', + 'Gevinst (DKK)', 'Tab (DKK)', ] add_headers(sheet, column_headers) row_idx = 2 @@ -175,12 +175,12 @@ def write_fifo_sheet(sheet, bought_and_sold_for: list, exchange_rate_at_time) -> fifo_entry.time_sold.replace(tzinfo=None), asset.raw_short_name(), fifo_entry.amount.amount, - exchange_rate_dkk_bought, - exchange_rate_dkk_sold, - f'=F{row_idx}*D{row_idx}', - f'=E{row_idx}*D{row_idx}', - f'=max(0, G{row_idx} - H{row_idx})', + exchange_rate_dkk_bought or 'Unknown', + exchange_rate_dkk_sold or 'Unknown', + f'=D{row_idx}*E{row_idx}', + f'=D{row_idx}*F{row_idx}', f'=max(0, H{row_idx} - G{row_idx})', + f'=max(0, G{row_idx} - H{row_idx})', ] sheet.append(row) row_idx+= 1 @@ -245,26 +245,33 @@ def write_overview(sheet, tax_report: TaxReport, sums): sheet['A9'] = 'Ledger' sheet['B9'] = 'Afdækker alle handler og overførsler.' sheet['A10'] = 'FIFO Stablecoin' - sheet['B10'] = 'Beregner profit og tab for stablecoins ved FIFO-pricippet.' + sheet['B10'] = 'Beregner gevinst og tab for stablecoins ved FIFO-pricippet.' sheet['A11'] = 'FIFO Kryptovaluta' - sheet['B11'] = 'Beregner profit og tab for kryptovaluta ved FIFO-pricippet.' + sheet['B11'] = 'Beregner gevinst og tab for kryptovaluta ved FIFO-pricippet.' sheet['A12'] = 'FIFO Fiat' - sheet['B12'] = 'Beregner profit og tab for udenlandsk valuta ved FIFO-pricippet.' + sheet['B12'] = 'Beregner gevinst og tab for udenlandsk valuta ved FIFO-pricippet.' # Beregnet kolonner - sheet['D6'] = 'Beregnet Skatte Kolonnner' # TODO + sheet['D6'] = 'Beregnet Skatte Rubrikker' # TODO sheet.merge_cells('D6:E6') sheet['A4'].alignment = ALIGN_CENTER - sheet['D7'] = 'Kolonne' # TODO + sheet['D7'] = 'Rubrik' # TODO sheet['E7'] = 'Værdi' - sheet['D8'] = 'Profit Krypto' + + sheet['D8'] = 'Rubrik 20' sheet['E8'] = '=$\'FIFO Kryptovaluta\'.'+sums['Kryptovaluta'][0] - sheet['D9'] = 'Tab Krypto' + sheet['F8'] = '(Gevinst ved kryptospekulation)' + sheet['G8'] = 'Kilde: https://skat.dk/borger/aktier-og-andre-vaerdipapirer/skat-paa-krypto-kend-reglerne-saa-du-undgaar-et-skattesmaek/beregn-og-oplys-gevinst-og-tab-paa-krypto' + + sheet['D9'] = 'Rubrik 58' sheet['E9'] = '=$\'FIFO Kryptovaluta\'.'+sums['Kryptovaluta'][1] - sheet['D10'] = 'Profit Stable Coin' - sheet['E10'] = '=$\'FIFO Stable Coin\'.'+sums['Stable Coin'][0] - sheet['D11'] = 'Profit Stable Coin' - sheet['E11'] = '=$\'FIFO Stable Coin\'.'+sums['Stable Coin'][1] + sheet['F9'] = '(Tab ved kryptospekulation)' + sheet['G10'] = 'Kilde: https://skat.dk/borger/aktier-og-andre-vaerdipapirer/skat-paa-krypto-kend-reglerne-saa-du-undgaar-et-skattesmaek/beregn-og-oplys-gevinst-og-tab-paa-krypto' + + sheet['D10'] = 'Rubrik 346' + sheet['E10'] = f"=$'FIFO Stable Coin'.{sums['Stable Coin'][0]}'-$'FIFO Stable Coin'.{sums['Stable Coin'][1]}'" + sheet['F10'] = '(Gevinst og Tab ved Stable Coin / Financiel Kontrakt)' + sheet['G10'] = 'Kilde: https://skat.dk/borger/aktier-og-andre-vaerdipapirer/skat-paa-krypto-kend-reglerne-saa-du-undgaar-et-skattesmaek/stablecoins-finansielle-kontrakter' # Disclaimer @@ -275,6 +282,11 @@ def write_overview(sheet, tax_report: TaxReport, sums): sheet.column_dimensions['B'].width = 70 sheet.row_dimensions[4].height = 60 + sheet.column_dimensions['D'].width = 20 + sheet.column_dimensions['E'].width = 20 + sheet.column_dimensions['F'].width = 50 + sheet.column_dimensions['G'].width = 80 + def produce_excel_report(report: TaxReport, output_path: Path): workbook = openpyxl.Workbook()