-
Talinn, Estonia
-
-
support@lnsolutions.ee
Das XRechnung-Addon von LNSolutions erweitert Alfresco um vollständige Unterstützung für deutsche XRechnung-E-Rechnungen. Es erkennt XRechnung-XML-Dokumente automatisch, reichert sie mit Metadaten an und erzeugt hochwertige HTML- und PDF-Renderings über eine dedizierte Transform Engine (T‑Engine).
Die Lösung besteht aus drei Hauptkomponenten:
xr:xrechnungMetadata und Integration mit der T‑Engine. WEB-INF/lib oder eigenes Docker-Image)Um eine Testlizenz anzufordern, verwenden Sie:
XRechnung-Testlizenz anfordern
lnsolutions-alfresco-license-1.0.0.jar kopieren nach:
<TOMCAT>/webapps/alfresco/WEB-INF/lib/ (ohne Docker)xrechnung-lnsolutions-platform-1.0-SNAPSHOT.jar kopieren nach:
<TOMCAT>/webapps/alfresco/WEB-INF/lib/ (ohne Docker)lnsolutions-alfresco-license).Fügen Sie in alfresco-global.properties (oder der entsprechenden Docker-Umgebung) die URL der XRechnung-T‑Engine hinzu:
# URL der XRechnung Transform Engine
localTransform.xrechnung.url=http://xrechnung-tengine:8091
Passen Sie Host/Port an Ihre Umgebung an (z. B. http://localhost:8091 für lokale Tests).
docker run -d -p 8091:8091 --name xrechnung-tengine xrechnung-tengine:latest
curl http://localhost:8091/ready
java -jar xrechnung-tengine-1.0-SNAPSHOT.jar
curl http://localhost:8091/ready
Konfigurieren Sie für die T‑Engine die folgenden Umgebungsvariablen (z. B. in einer .env-Datei oder der Service-Konfiguration):
XRECHNUNG_TRANSFORM_CONFIG=/opt/xrechnung-tengine/config/xrechnung-transform-config.json
CORE_AIO_TRANSFORM_URL=http://transform-core-aio:8090/transform
LICENSE_VALIDATION_URL=http://<alfresco-host>:8080/alfresco/service/lnsolutions/admin/license-status
Die T‑Engine ruft LICENSE_VALIDATION_URL vor jeder Transformation auf, um Ihre Lizenz über Alfresco zu prüfen.
xr:xrechnungMetadata) an.Digital Invoice Profile, Digital Invoice Profile Description (Short) und Is Digital Invoice.http://<alfresco-host>:8080/alfresco/service/lnsolutions/node/xrechnung-html?id={nodeId}

Das Addon unterstützt außerdem eine PDF-Pipeline: XRechnung XML → HTML (T‑Engine) → PDF (Alfresco pdfRenderer).

Das XRechnung-Addon verwendet den XRechnung-Metadatenaspekt (xr:xrechnungMetadata) als technischen Indikator dafür, dass ein Dokument eine gültige XRechnung ist.
xr:isDigitalInvoice): Boolescher Schalter, der gesetzt wird, wenn ein Dokument als XRechnung erkannt wurde.xr:digitalInvoiceProfile): Speichert den erkannten Digital-Invoice-Profilbezeichner.xr:digitalInvoiceProfileDescShort): Kurze, menschenlesbare Bezeichnung für das erkannte Profil (z. B. in Alfresco als „Digital Invoice Profile Description (Short)“ angezeigt).Das XRechnungDetectionBehavior lauscht auf das Anlegen und Aktualisieren von cm:content-Knoten. Wenn eine hochgeladene XML-Datei den XRechnung-Mustern entspricht (basierend auf Inhalt, Metadaten oder Dateinamen), fügt das Behavior automatisch den Aspekt xr:xrechnungMetadata hinzu und setzt xr:isDigitalInvoice = true.
Nur Dokumente, die diesen XRechnung-Indikator tragen (den Aspekt xr:xrechnungMetadata mit xr:isDigitalInvoice=true), werden von der HTML/PDF-Transformationspipeline als XRechnung behandelt. Allgemeine XML-Dateien bleiben unberührt, bis sie eindeutig als XRechnung identifiziert wurden.

Wenn Sie das XRechnung-Addon vor dem Erwerb einer Volllizenz evaluieren möchten, fordern Sie hier eine Testlizenz an:
XRechnung-Testlizenz anfordern
Oder kontaktieren Sie uns für eine dauerhafte Lizenz.

In diesem Tutorial erfahren Sie, wie Sie mit Kotlin eine sichere Spring Boot-Anwendung erstellen, Spring Security für die Authentifizierung integrieren, Coroutines für die asynchrone Programmierung nutzen und mit AWS-Services wie Athena und Cognito integrieren. Wir werden auch die Datenbankmigration mit Flyway und das kontinuierliche Deployment mit Jenkins behandeln.
Lass uns zunächst das Spring Boot Projekt mit Kotlin unter Verwendung von Gradle einrichten:
Sie können Spring Initializr verwenden, um das Projekt mit den erforderlichen Konfigurationen zu generieren. Gehen Sie zu https://start.spring.io/ und geben Sie die folgenden Details ein:
Klicken Sie auf “Generate”, um die Projekt-Zip-Datei herunterzuladen.
Entpacken Sie das heruntergeladene Projekt, und im Root-Ordner finden Sie eine build.gradle-Datei. Ändern Sie diese so, dass sie die notwendigen Konfigurationen für die Elastic Beanstalk-Bundle-Generierung und die Jenkins-Integration enthält.
plugins {
id 'org.springframework.boot' version '2.5.4'
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
id 'org.jetbrains.kotlin.jvm' version '1.5.21'
id 'org.jetbrains.kotlin.plugin.spring' version '1.5.21'
id 'org.jetbrains.kotlin.plugin.jpa' version '1.5.21'
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
java.sourceCompatibility = JavaVersion.VERSION_11
kotlin {
experimental {
coroutines 'enable'
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'com.amazonaws:aws-java-sdk-athena'
implementation 'com.amazonaws:aws-java-sdk-cognitoidp'
implementation 'com.amazonaws:aws-java-sdk-core'
implementation 'com.amazonaws:aws-java-sdk-elasticbeanstalk'
implementation 'com.h2database:h2'
implementation 'org.flywaydb:flyway-core'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
runtimeOnly 'org.postgresql:postgresql'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
springBoot {
buildInfo {
properties {
additional = ['build.version': version]
}
}
}
tasks.named('test') {
useJUnitPlatform()
}
Erstellen Sie eine Konfigurationsklasse für Spring Security mit AWS Cognito-Integration:
@Configuration
@EnableWebSecurity
class SecurityConfig : WebSecurityConfigurerAdapter() {
override fun configure(http: HttpSecurity) {
http.authorizeRequests()
.antMatchers("/api/public/**").permitAll()
.antMatchers("/api/**").authenticated()
.and()
.oauth2Login()
}
}
Konfigurieren Sie einen benutzerdefinierten Authentifizierungsanbieter für die Integration mit AWS Cognito:
@Component
class CustomAuthenticationProvider : AuthenticationProvider {
override fun authenticate(authentication: Authentication): Authentication {
// Implement authentication logic with AWS Cognito
}
override fun supports(authentication: Class<*>): Boolean {
return UsernamePasswordAuthenticationToken::class.java.isAssignableFrom(authentication)
}
}
Implementieren Sie einen benutzerdefinierten UserDetailsService, um Benutzerdetails aus AWS Cognito zu laden:
@Service
class CustomUserDetailsService : UserDetailsService {
override fun loadUserByUsername(username: String): UserDetails {
// Load user details from AWS Cognito
}
}
Erstellen Sie eine Konfigurationsklasse für die verschiedenen Profile (local, dev, prod):
@Configuration
class DatabaseConfig {
@Bean
@Profile("local")
fun dataSource(): DataSource {
return EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2)
.build()
}
@Bean
@Profile("dev", "prod")
fun dataSourceDevProd(): DataSource {
val dataSource = DriverManagerDataSource()
dataSource.setDriverClassName("YOUR_DATABASE_DRIVER")
dataSource.url = "YOUR_DATABASE_URL"
dataSource.username = "YOUR_DATABASE_USERNAME"
dataSource.password = "YOUR_DATABASE_PASSWORD"
return dataSource
}
}
Erstellen Sie ein Migrationsskript unter src/main/resources/db/migration für Flyway, um Änderungen am Datenbankschema zu verwalten.
Erstellen Sie eine Kotlin-Klasse, die als Einstiegspunkt für Ihre Spring Boot-Anwendung dient:
@SpringBootApplication
class DemoApplication
fun main(args: Array<String>) {
runApplication<DemoApplication>(*args)
}
Sie können die Integration mit AWS Athena mithilfe des AWS SDK für Java und den entsprechenden Anmeldeinformationen vornehmen. Sie können den entsprechenden Code für AWS Athena-Abfragen in Ihrer Service-Schicht oder Ihrem Controller hinzufügen.
Um ein Elastic Beanstalk-Bundle zu erstellen, müssen Sie das CLI-Tool von AWS Elastic Beanstalk verwenden, das Sie über Gradle aufrufen können. Hier ist ein Beispiel dafür, wie Sie es tun können:
task createElasticBeanstalkBundle(type: Exec) {
workingDir projectDir
commandLine 'eb', 'create'
// Add necessary AWS Elastic Beanstalk configurations here
}
tasks.named('build').dependsOn createElasticBeanstalkBundle
Dadurch wird der Befehl eb create ausgeführt, wenn Sie die Gradle-Bauaufgabe ausführen.
Für die Jenkins-Integration müssen Sie Ihre Jenkins-Pipeline so konfigurieren, dass das Projekt unter Verwendung des generierten Gradle-Wrappers gebaut und bereitgestellt wird.
Mit diesen Schritten sollten Sie ein Spring Boot-Projekt mit Kotlin, Spring Security, AWS Cognito, AWS Athena-Integration und Flyway-Datenbankmigration haben. Darüber hinaus verfügen Sie über Konfigurationen für lokale, Dev- und Prod-Umgebungen und eine Gradle-Aufgabe für die Generierung von Elastic Beanstalk-Bundles, die zur Bereitstellung in Jenkins integriert werden können.
For English here
In der dynamischen Welt der Kryptowährungen, in der sich Volatilität und Innovation überschneiden, entwickelt sich die regulatorische Landschaft ständig weiter. Ein bemerkenswerter Aspekt dieser Entwicklung ist die Besteuerung von Kryptowährungsgewinnen. Während viele Länder verschiedene Steuerregelungen für Kryptowährungen eingeführt haben, bieten einige Länder eine günstige Politik, die langfristige Inhaber von bestimmten Steuerpflichten befreit. Eine solche Politik, die in mehreren Ländern an Zugkraft gewinnt, ist die Steuerbefreiung für Kryptobestände, die ein Jahr oder länger gehalten werden.
Die Politik des einjährigen Haltens, auch bekannt als Behandlung langfristiger Kapitalgewinne, ist ein steuerlicher Rahmen, der Steuerbefreiungen oder ermäßigte Steuersätze für Gewinne aus dem Verkauf oder Tausch von Kryptowährungen gewährt, die für eine Mindestdauer von einem Jahr gehalten werden. Diese Politik zielt darauf ab, Anreize für langfristige Investitionen in Kryptowährungen zu schaffen und gleichzeitig die Stabilität auf dem Markt zu fördern.
Mehrere Länder haben das Konzept der steuerfreien Kryptogewinne für langfristige Inhaber übernommen. Einige dieser Länder sind:
Das Paket ccGains (cryptocurrency gains) bietet eine Python-Bibliothek zur Berechnung von Kapitalgewinnen aus dem Handel mit Kryptowährungen oder Fremdwährungen. Es wurde von Jürgen Probst erstellt und wird in Github gehostet (Link hier). Einige ihrer Funktionen sind:
Sie benötigen Python (ccGains wurde unter Python 2.7 und Python 3.x getestet). Sie erhalten es hier: https://www.python.org/
ccGains kann dann einfach über den Python-Paketmanager pip installiert werden:
git clone https://github.com/probstj/ccgains.gitpip install . (beachten Sie das . am Ende)pip install --user .pip install -e .Bitte schauen Sie sich die Datei examples/example.pyan und folgen Sie den Kommentaren, um sie für Ihre Zwecke anzupassen.
Kopieren Sie es in eine neue Datei, zum Beispiel taxReport2023.py.
Stündliche Daten für viele Börsenplätze stehen zum Download bereit unter:
https://api.bitcoincharts.com/v1/csv/
Um zu verstehen, welche Datei heruntergeladen werden soll, konsultieren Sie diese Liste:
https://bitcoincharts.com/markets/list/
Für EUR-Kurse auf Kraken laden Sie bitte die folgende Datei herunter: https://api.bitcoincharts.com/v1/csv/krakenEUR.csv.gz und legen Sie sie in den Ordner ../data.
Für CHF-Preise, laden Sie herunter: https://api.bitcoincharts.com/v1/csv/anxhkCHF.csv.gz
Für SGD-Preise, laden Sie herunter: https://api.bitcoincharts.com/v1/csv/anxhkSGD.csv.gz
Die Datei besteht aus drei durch Komma getrennten Spalten: dem Unix-Zeitstempel, dem Preis und dem Volumen (gehandelter Betrag).
Erstellen Sie das HistoricData-Objekt, indem Sie die genannte Datei laden und die Preiseinheit, d.h. fiat/btc, angibt:
h1 = ccgains.HistoricDataCSV(
'../data/bitcoin_de_EUR_abridged_as_example.csv.gz', 'EUR/BTC')
Für alle Coins, die Sie irgendwann einmal besessen haben, muss ihr historischer Preis in Ihrer heimischen Fiat-Währung bekannt sein, der auch aus ihrem BTC-Preis und dem oben angegebenen BTC/Fiat-Preis abgeleitet werden kann (oder sogar aus ihrem Preis in einem anderen Altcoin, dessen Preis wiederum abgeleitet werden kann).
Diese Daten können von jeder Website zur Verfügung gestellt werden, die diese Daten über eine API bereitstellt, oder aus einer csv-Datei, wie oben. Beachten Sie, dass derzeit nur die API von Poloniex.com implementiert ist.
Erstellen Sie HistoricData-Objekte, um Kurse von Poloniex.com abzurufen: (es ist wichtig, hier zumindest alle gehandelten Coins zu erwähnen)
h2 = ccgains.HistoricDataAPI('data', 'btc/xmr')
h3 = ccgains.HistoricDataAPI('data', 'btc/eth')
h4 = ccgains.HistoricDataAPI('data', 'btc/usdt')
h5 = ccgains.HistoricDataAPI('data', 'btc/link')
h6 = ccgains.HistoricDataAPI('data', 'btc/bat')
h7 = ccgains.HistoricDataAPI('data', 'btc/zrx')
h8 = ccgains.HistoricDataAPI('data', 'btc/cvc')
h9 = ccgains.HistoricDataAPI('data', 'btc/dash')
h10 = ccgains.HistoricDataAPI('data', 'btc/knc')
h11 = ccgains.HistoricDataAPI('data', 'btc/mkr')
h12 = ccgains.HistoricDataAPI('data', 'btc/matic')
h13 = ccgains.HistoricDataAPI('data', 'btc/doge')
h14 = ccgains.HistoricDataAPI('data', 'btc/bch')
h15 = ccgains.HistoricDataAPI('data', 'btc/dot')
h16 = ccgains.HistoricDataAPI('data', 'btc/qtum')
h17 = ccgains.HistoricDataAPI('data', 'btc/ren')
h18 = ccgains.HistoricDataAPI('data', 'btc/str')
h19 = ccgains.HistoricDataAPI('data', 'btc/xtz')
h20 = ccgains.HistoricDataAPI('data', 'btc/trx')
h21 = ccgains.HistoricDataAPI('data', 'btc/zec')
h22 = ccgains.HistoricDataAPI('data', 'btc/ltc')
h23 = ccgains.HistoricDataAPI('data', 'btc/xrp')
h24 = ccgains.HistoricDataAPI('data', 'btc/omg')
h25 = ccgains.HistoricDataAPI('data', 'btc/etc')
h26 = ccgains.HistoricDataAPI('data', 'btc/dot')
h27 = ccgains.HistoricDataAPI('data', 'btc/dai')
h28 = ccgains.HistoricDataAPI('data', 'btc/usdc')
h29 = ccgains.HistoricDataAPICoinbase('data', 'cro/eur')
h30 = ccgains.HistoricDataAPIBinance('data', 'btc/uni')
h31 = ccgains.HistoricDataAPIBinance('data', 'avax/eur')
h32 = ccgains.HistoricDataAPIBinance('data', 'btc/dydx')
h33 = ccgains.HistoricDataAPIBinance('data', 'btc/iota')
h34 = ccgains.HistoricDataAPIBinance('data', 'btc/axs')
In h2 bis h28 habe ich die Klasse HistoricDataAPI verwendet, die die öffentliche Poloniex-API verwendet: https://poloniex.com/public?command=returnTradeHistory, da dies die Börse ist, an der diese Paare im Jahr 2023 in diesem Beispiel gehandelt werden.
In h29 habe ich die Klasse HistoricDataAPICoinbase verwendet, die die öffentliche Coinbase-API verwendet: “https://api.pro.coinbase.com/products/:SYMBOL:/candles".
In h30 bis h34 habe ich die Klasse HistoricDataAPIBinance verwendet, die transparent Daten auf Anfrage (get_price) von der öffentlichen Binance-API abruft: https://api.binance.com/api/v1/klines
Um die Ladezeiten bei künftigen Aufrufen zu verkürzen, wird aus den angeforderten Daten eine HDF5-Datei erstellt, die bei der nächsten Anfrage für denselben Tag und dasselbe Paar transparent verwendet wird. Diese HDF5-Dateien werden im Ordner cache_folder gespeichert. Die Einheit muss ein String in der Form “kryptowährung_eins/kryptowährung_zwei” sein, z. B. “NEO/BTC”. Die Daten werden neu abgetastet, indem der gewichtete Preis für die durch interval angegebenen Intervallschritte berechnet wird. Siehe: http://pandas.pydata.org/pandas-docs/stable/timeseries.html#offset-aliases für mögliche Werte.
prepare_request(dtime) Gibt einen Pandas DataFrame zurück, der die Daten für den angeforderten Zeitpunkt dtime enthält.
Erstellen Sie ein CurrencyRelation-Objekt, das alle angegebenen HistoricData-Währungen in Beziehung setzt, um Wechselkurse für ein beliebiges Paar dieser Währungen zu liefern:
rel = ccgains.CurrencyRelation(h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11, h12, h13, h14, h15, h16, h17, h18, h19, h20, h21, h22, h23, h24, h25, h26,h27, h28, h29, h30, h31, h32, h33, h34)
Erstellen Sie das BagQueue-Objekt, das den steuerpflichtigen Gewinn aus Geschäften nach der First-in/First-out-Methode berechnet:
(dieses Objekt muss Ihre native Fiat-Währung und die oben erstellte CurrencyRelation kennen)
bf = ccgains.BagQueue('EUR', rel)
Das TradeHistory-Objekt bietet Methoden zum Laden Ihrer Trades aus CSV-Dateien, die von verschiedenen Börsen oder Anwendungen exportiert wurden.
th = ccgains.TradeHistory()
Exportieren Sie Ihre Trades von Börsen oder Apps als kommagetrennte Dateien und fügen Sie sie an die Liste der Trades an, die vom TradeHistory-Objekt verwaltet werden. Alle Trades werden automatisch sortiert.
Um von einer unterstützten Börse zu laden, verwenden Sie die Methoden namens `append_<exchange_name>_csv` in TradeHistory (siehe trades.py).
th.append_poloniex_csv(
'./data/2020/poloniex_depositHistory_2023.csv',
'deposits')
th.append_poloniex_csv(
'./data/2020/poloniex_tradeHistory_2023.csv',
'trades',
condense_trades=True)
th.append_poloniex_csv(
'./data/2020/poloniex_withdrawalHistory_2023.csv',
'withdr')
th.append_binance_csv(
'./data/2020/binance_depositHistory_2023.csv',
'deposits')
th.append_binance_csv(
'./data/2020/binance_tradeHistory_2023.csv',
'deposits')
th.append_binance_csv(
'./data/2020/binance_withdrawalHistory_2023.csv',
'deposits')
th.append_wirex_csv(
'./data/2020/wirex_btc_tradeHistory_2023.csv',
'trades')
th.append_cro_csv(
'./data/2021/cro_tradeHistory_2023.csv',
'trades')
Wenn Ihre Börse noch nicht unterstützt wird, fügen Sie eine neue Methode in trades.py hinzu. In diesem Beispiel werden die Methoden append_wirex_csv und append_cro_csv im ursprünglichen GitHub-Projekt nicht unterstützt.
Als nächstes werde ich zeigen, wie ich es mit append_cro_csv (Crypto.com) gemacht habe. Importieren Sie zunächst TPLOC_CRO_TRADES, die Bibliothek, die weiß, wie man die CSV-Datei von der Crypto.com-Börse liest.
from .cro_util import (
TPLOC_CRO_TRADES)
def append_cro_csv(
self, file_name, which_data='trades', delimiter=',',
skiprows=1, default_timezone=tz.tzutc()):
wdata = which_data[:5].lower()
if wdata not in ['trade']:
raise ValueError(
'`which_data` must be one of "trades"')
plocs = TPLOC_CRO_TRADES
self.append_csv(
file_name=file_name,
param_locs=plocs,
delimiter=delimiter,
skiprows=skiprows,
default_timezone=default_timezone
)
Erzeugen Sie nun die Datei cro_util.py
from decimal import Decimal
def kind_for(csv_line):
if 'Withdraw' in (csv_line[1].strip('" \n\t')) or ('Transfer' in (csv_line[1].strip('" \n\t')) and 'App' in csv_line[1].strip('" \n\t').split("->")[0]):
return 'Withdrawal'
elif 'Deposit' in (csv_line[1].strip('" \n\t')) or 'Reward' in (csv_line[1].strip('" \n\t')) or ('Transfer' in (csv_line[1].strip('" \n\t')) and 'Exchange' in csv_line[1].strip('" \n\t').split("->")[0]):
return 'Deposit'
elif 'Buy' in (csv_line[1].strip('" \n\t')):
return 'Buy'
elif '->' in csv_line[1].strip('" \n\t'):
return 'Sell'
else:
return None
def get_buy_currency(csv_line):
if not '->' in csv_line[1].strip('" \n\t') and (kind_for(csv_line) == 'Buy' or kind_for(csv_line) == 'Deposit' or 'App' in csv_line[1].strip('" \n\t').split("->")[0]):
return csv_line[2].strip('" \n\t')
elif '->' in csv_line[1].strip('" \n\t') and (kind_for(csv_line) == 'Buy' or kind_for(csv_line) == 'Deposit' or 'App' in csv_line[1].strip('" \n\t').split("->")[0]):
return csv_line[2].strip('" \n\t')
else:
return csv_line[1].strip('" \n\t').split("->")[1]
def get_sell_currency(csv_line):
if not '->' in csv_line[1].strip('" \n\t') and (kind_for(csv_line) == 'Sell' or kind_for(csv_line) == 'Withdrawal' or 'Exchange' in csv_line[1].strip('" \n\t').split("->")[0]):
return csv_line[2].strip('" \n\t')
elif '->' in csv_line[1].strip('" \n\t') and (kind_for(csv_line) == 'Sell' or kind_for(csv_line) == 'Withdrawal' or 'Exchange' in csv_line[1].strip('" \n\t').split("->")[0]):
return csv_line[2].strip('" \n\t')
else:
return csv_line[1].strip('" \n\t').split("->")[0]
#Trade parameters in csv from Crypto.com
TPLOC_CRO_TRADES = {
'kind': lambda cols: kind_for(cols),
'dtime': 0,
'buy_currency': lambda cols: get_buy_currency(cols) if kind_for(cols) == 'Buy' or kind_for(cols) == 'Deposit' else cols[4] if cols[4].strip('" \n\t') != '' else '',
'buy_amount': lambda cols: abs(Decimal(cols[3])) if kind_for(cols) == 'Buy' or kind_for(cols) == 'Deposit' else abs(Decimal(cols[5])) if cols[5].strip('" \n\t') != '' else '',
'sell_currency': lambda cols: get_sell_currency(cols) if kind_for(cols) == 'Sell' or kind_for(cols) == 'Withdrawal' else 'EUR',
'sell_amount': lambda cols: abs(Decimal(cols[3])) if kind_for(cols) == 'Sell' or kind_for(cols) == 'Withdrawal' else cols[7],
'fee_currency': -1,
'fee_amount': -1,
'exchange': 'Crypto.com', 'mark': -1,
'comment': lambda cols: cols[1]
}
Einige Börsen, wie Poloniex, enthalten keine Abhebungsgebühren in ihren exportierten csv-Dateien. Es wird versucht, diese fehlenden Gebühren zu ergänzen, indem die abgehobenen Beträge mit den Beträgen verglichen werden, die kurz nach der Abhebung an anderen Börsen eingezahlt wurden. Rufen Sie dies erst auf, nachdem alle Transaktionen von allen beteiligten Börsen und Wallets importiert wurden.
Da dieser Algorithmus sehr einfach ist, kann nicht garantiert werden, dass er in jedem Fall funktioniert, vor allem, wenn Sie Abhebungen in kurzer Folge an verschiedenen Börsen vorgenommen haben; überprüfen Sie daher bitte die Ausgabe.
th.add_missing_transaction_fees(raise_on_error=False)
Einige Währungen haben seit ihrem ersten Auflistungsdatum ihr Tickersymbol geändert (z. B. AntShares (ANS) -> Neo (NEO)). Dies kann zu Situationen führen, in denen alle historischen Preisdaten das neue Tickersymbol auflisten, die Transaktionshistorie jedoch noch das alte Tickersymbol enthält.
Diese Methode ermöglicht die Umbenennung von Symbolen in der TradeHistory, wenn ein Vorkommen des alten Namens/Tickers gefunden wird.
th.update_ticker_names({'ANS': 'NEO'})
Sie können alle importierten Trades zur späteren Verwendung in eine einzige Datei exportieren, optional gefiltert nach Jahr.
…entweder als kommagetrennte Textdatei (kann in ccgains importiert werden):
th.export_to_csv('transactions2023.csv', year=2023)
…oder als html- oder pdf-Datei, mit der Möglichkeit, Spaltenüberschriften oder Inhalte zu filtern oder umzubenennen:
(Dies ist ein Beispiel für eine Übersetzung ins Deutsche)
my_column_names=[
'Art', 'Datum', 'Kaufmenge', 'Verkaufsmenge', u'Gebühren', u'Börse']
transdct = {'Buy': 'Anschaffung',
'BUY': 'Anschaffung',
'Sell': 'Tausch',
'SELL': 'Tausch',
'Purchase': 'Anschaffung',
'Exchange': 'Tausch', 'Disbursement': 'Abhebung',
'Deposit': 'Einzahlung',
'Withdrawal': 'Abhebung',
'Received funds': 'Einzahlung',
'Withdrawn from wallet': 'Abhebung',
'Create offer fee: a5ed7482': u'Börsengebühr',
'Buy BTC' : 'Anschaffung',
'MultiSig deposit: a5ed7482': 'Abhebung',
'MultiSig payout: a5ed7482' : 'Einzahlung'}
th.export_to_pdf('Transactions2021.pdf',
year=2021, drop_columns=['mark', 'comment'],
font_size=12,
caption=u"Handel mit digitalen Währungen %(year)s",
intro=u"<h4>Auflistung aller Transaktionen zwischen "
"%(fromdate)s und %(todate)s:</h4>",
locale="de_DE",
custom_column_names=my_column_names,
custom_formatters={
'Art': lambda x: transdct[x] if x in transdct else x})
Wenn die Berechnung bereits für frühere Jahre gelaufen ist, können wir hier den Stand der Taschen laden, ohne alles erneut berechnen zu müssen:
bf.load('./status2022.json')
Oder, wenn die aktuelle Berechnung abgestürzt ist (z.B. weil Sie vergessen haben, eine gehandelte Währung in #2 oben hinzuzufügen), wird die Datei ‘precrash.json’ automatisch erstellt. Laden Sie sie hier, um fortzufahren:
bf.load('./precrash.json')
Im Folgenden wird lediglich nachgeschaut, wo mit der Berechnung der Trades begonnen werden soll, falls Sie bereits einige berechnet und durch das Laden von ‘precrash.json’ neu gestartet haben:
last_trade = 0
while (last_trade < len(th.tlist)
and th[last_trade].dtime <= bf._last_date):
last_trade += 1
if last_trade > 0:
logger.info("continuing with trade #%i" % (last_trade + 1))
# Now, the calculation. This goes through your imported list of trades:
for i, trade in enumerate(th.tlist[last_trade:]):
# Most of this is just the log output to the console and to the
# file 'ccgains_<date-time>.log'
# (check out this file for all gory calculation details!):
logger.info('TRADE #%i', i + last_trade + 1)
logger.info(trade)
# This is the important part:
bf.process_trade(trade)
# more logging:
log_bags(bf)
logger.info("Totals: %s", str(bf.totals))
logger.info("Gains (in %s): %s\n" % (bf.currency, str(bf.profit)))
bf.save('status2023.json')
Die im Bericht verwendeten Standard-Spaltennamen sehen nicht sehr schön aus: [‘Art’, ‘bag_spent’, ‘Währung’, ‘bag_date’, ‘sell_date’, ‘exchange’, ‘short_term’, ‘spent_cost’, ‘proceeds’, ‘profit’], also benennen wir sie um:
my_column_names=[
'Type', 'Amount spent', u'Currency', 'Purchase date',
'Sell date', u'Exchange', u'Short term', 'Purchase cost',
'Proceeds', 'Profit']
Hier erstellen wir den pdf-Bericht für Kapitalgewinne im Jahr 2023.
Die Angabe date_precision=’D’ bedeutet, dass wir nur den Tag des Abschlusses erwähnen, nicht die genaue Uhrzeit. Außerdem stellen wir combine=True ein, so dass mehrere Trades, die am selben Tag und an derselben Börse getätigt wurden, im Bericht zu einem einzigen Trade zusammengefasst werden:
my_column_names=[
'Art', 'Verkaufsmenge', u'Währung', 'Erwerbsdatum',
'Verkaufsdatum', u'Börse', u'in\xa0Besitz',
'Anschaffungskosten', u'Verkaufserlös', 'Gewinn']
transdct = {'sale': u'Veräußerung',
'withdrawal fee': u'Börsengebühr',
'deposit fee': u'Börsengebühr',
'exchange fee': u'Börsengebühr'}
convert_short_term=[u'>\xa01\xa0Jahr', u'<\xa01\xa0Jahr']
bf.report.export_report_to_pdf(
'Report2021_de.pdf', year=2023,
date_precision='D', combine=True,
custom_column_names=my_column_names,
custom_formatters={
u'in\xa0Besitz': lambda b: convert_short_term[b],
'Art': lambda x: transdct[x]},
locale="de_DE",
template_file='shortreport_de.html'
)
# If you rather want your report in a spreadsheet, you can export
# to csv:
bf.report.export_short_report_to_csv(
'report_2023.csv', year=2023,
date_precision='D', combine=False,
convert_timezone=True, strip_timezone=True)
Der oben erstellte einfache Kapitalertragsbericht ist nur eine einfache Auflistung aller Trades und der erzielten Gewinne, die für den Steuerbericht ausreicht.
Eine detailliertere Auflistung, in der die Berechnung dargestellt wird, ist ebenfalls verfügbar:
bf.report.export_extended_report_to_pdf(
'Details_2023.pdf', year=2023,
date_precision='S', combine=False,
font_size=10, locale="en_US")
Und noch einmal, übersetzen wir diesen Bericht ins Deutsche: (Wiederum mit transdct von oben, um die Zahlungsart zu übersetzen)
bf.report.export_extended_report_to_pdf(
'Details_2023_de.pdf', year=2023,
date_precision='S', combine=False,
font_size=10, locale="de_DE",
template_file='fullreport_de.html',
payment_kind_translation=transdct)
Jetzt ausführen
python taxReport2023.py
Dies sollte die pdf-Dateien Details_2023.pdf und Details_2023_de.pdf erzeugen, die vom Finanzamt benötigt werden.
Für weitere Informationen zur Erstellung von Krypto-Steuerberichten oder zur Anpassung an Ihre Bedürfnisse kontaktieren Sie uns unter lnsolutions.ee
Für Englisch hier
Wenn Sie MySQL-Befehle in einem Terminal oder in Bash-Skripten verwenden, können Sie auf diese Warnmeldung stoßen:
Warnung: Die Verwendung eines Passworts auf der Befehlszeilenschnittstelle kann unsicher sein.
Diese Warnung weist auf potenzielle Sicherheitslücken hin, da auf diese Weise eingegebene Passwörter für andere Benutzer sichtbar sein können. MySQL bietet jedoch mit dem Tool mysql_config_editor eine sichere Lösung, mit der Benutzer ihre Authentifizierungsdaten sicher speichern können. In dieser Anleitung zeigen wir Ihnen, wie Sie die Warnmeldung unterdrücken und MySQL-Passwörter mit mysql_config_editor sicher verwalten können.
Schritt 1: Installieren Sie MySQL und mysql_config_editor: Stellen Sie sicher, dass MySQL auf Ihrem System zusammen mit dem mysql_config_editor Tool installiert ist. Wenn Sie MySQL noch nicht installiert haben, können Sie dies mit Hilfe der offiziellen Installationsanleitung von MySQL für Ihr Betriebssystem nachholen.
Schritt 2: Authentifizierungsdaten einrichten: Sobald MySQL installiert ist, können Sie die Authentifizierungsdaten mit dem mysql_config_editor Tool sicher einrichten. Öffnen Sie Ihr Terminal und führen Sie den folgenden Befehl aus:
mysql_config_editor set --login-path=client --host=localhost --user=username --port=your_db_port --password
Ersetzen Sie username durch Ihren MySQL-Benutzernamen. Nachdem Sie diesen Befehl ausgeführt haben, werden Sie aufgefordert, Ihr MySQL-Passwort einzugeben. Sobald Sie es eingegeben haben, wird das Passwort sicher gespeichert.
Schritt 3: Warnmeldung unterdrücken: Um die Warnmeldung über die Verwendung eines unsicheren Passworts zu unterdrücken, verwenden Sie einfach die Option — login-path zusammen mit Ihrem MySQL-Befehl. Zum Beispiel:
mysql --login-path=client -e "SELECT * FROM your_table;"
Ersetzen Sie your_table durch den Namen der Tabelle, die se abfragen möchten.Durch die Verwendung von --login-path=client holt MySQL die Authentifizierungsdaten sicher aus der von mysql_config_editor gespeicherten Konfiguration, und die Warnmeldung wird unterdrückt.
Schritt 4: Einbinden in Bash-Skripte: Sie können die sichere Authentifizierungsmethode in Ihre Bash-Skripte integrieren, indem Sie die Option --login-pathin MySQL-Befehlen verwenden. Hier ist ein Beispielskript:
#!/bin/bash# MySQL command with secure authentication
mysql --login-path=client -e "SELECT * FROM your_table;"
Ersetzen Sie your_table durch den entsprechenden Tabellennamen oder die Abfrage für Ihr Skript.
Um zu sehen, was mysql_config_editor in die Datei .mylogin.cnf schreibt, benutzen Sie den Befehl print:
$> mysql_config_editor print --all
[client]
user = localuser
password = *****
host = localhost
[remote]
user = remoteuser
password = *****
host = remote.example.com
Durch die Verwendung von mysql_config_editor und der Option --login-path können Sie die MySQL-Authentifizierungsdaten sicher verwalten und Warnmeldungen über unsichere Passwortverwendung sowohl in Terminalbefehlen als auch in Bash-Skripten unterdrücken. Dies gewährleistet den Schutz sensibler Informationen bei gleichzeitiger Beibehaltung von Komfort und Effizienz im MySQL-Betrieb.