AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Datenbanken Tücken bei der Mehrwertsteuerberechnung (mit Firebird)
Thema durchsuchen
Ansicht
Themen-Optionen

Tücken bei der Mehrwertsteuerberechnung (mit Firebird)

Ein Thema von BlueStarHH · begonnen am 2. Jul 2024 · letzter Beitrag vom 8. Jul 2024
Antwort Antwort
Delphi.Narium

Registriert seit: 27. Nov 2017
2.555 Beiträge
 
Delphi 7 Professional
 
#1

AW: MwSt. wird falsch berechnet. (Einige nutzen eine falsche Formel!)

  Alt 2. Jul 2024, 12:52
Das Problem liegt nicht in den Rechenverfahren sondern in der Datenbank bzw. in FireBird:
SQL-Code:
select
  RENR,
  MWSTSATZ,
  cast(round(BruttoSumme, 2) as NUMERIC(18,2)) as Brutto,
  (MwStSatz / (MwStSatz + 100)) as mwst_1,
  round((MwStSatz / (MwStSatz + 100)),2) as mwst_2,
  BruttoSumme * (MwStSatz / (MwStSatz + 100)) as mwst_3,
  BruttoSumme * MwStSatz / (MwStSatz + 100) as mwst_4,
  round(BruttoSumme * MwStSatz / (MwStSatz + 100),2) as mwst_5,
  cast(round(round(BruttoSumme, 2) * (MwStSatz / (MwStSatz + 100)), 2) as NUMERIC(18,2)) as Mwst,
  cast(round(round(BruttoSumme, 2) * MwStSatz / (MwStSatz + 100), 2) as NUMERIC(18,2)) as Mwst_Cast,
  cast(round(BruttoSumme, 2) - (round(round(BruttoSumme, 2) * (MwStSatz / (MwStSatz + 100)), 2)) as NUMERIC(18,2)) as Netto
from
(
  select
    RENR,
    MwStSatz,
    sum(BruttoSumme) as BruttoSumme
  from RePos
  group by RENR, MwStSatz
)
;
Habe mal eine der Views "erweitert" und dann die Ergebnisse verglichen.

Mathematisch sind

  cast(round(round(BruttoSumme, 2) * (MwStSatz / (MwStSatz + 100)), 2) as NUMERIC(18,2)) as Mwst,
und
  cast(round(round(BruttoSumme, 2) * MwStSatz / (MwStSatz + 100), 2) as NUMERIC(18,2)) as Mwst_Cast,
identisch.

Die Klammerung von (MwStSatz / (MwStSatz + 100)) ist nicht zwingend erforderlich, es würde auch MwStSatz / (MwStSatz + 100) ausreichen.

Das Problem dabei ist: FireBird liefert mit bzw. ohne diese Klammern unterschiedliche Ergebnisse.

Bei FireBird ist BruttoSumme * (MwStSatz / (MwStSatz + 100)) was anderes als BruttoSumme * MwStSatz / (MwStSatz + 100) .

Aus für mich nicht nachvollziehbaren Gründen ist der Ergebnis der Berechnung BruttoSumme * (MwStSatz / (MwStSatz + 100)) bei FireBird falsch.
  Mit Zitat antworten Zitat
Benutzerbild von gubbe
gubbe

Registriert seit: 8. Okt 2005
Ort: Schleswig-Holstein
150 Beiträge
 
Delphi 11 Alexandria
 
#2

AW: MwSt. wird falsch berechnet. (Einige nutzen eine falsche Formel!)

  Alt 2. Jul 2024, 18:25

Die Klammerung von (MwStSatz / (MwStSatz + 100)) ist nicht zwingend erforderlich, es würde auch MwStSatz / (MwStSatz + 100) ausreichen.

Das Problem dabei ist: FireBird liefert mit bzw. ohne diese Klammern unterschiedliche Ergebnisse.

Bei FireBird ist BruttoSumme * (MwStSatz / (MwStSatz + 100)) was anderes als BruttoSumme * MwStSatz / (MwStSatz + 100) .

Aus für mich nicht nachvollziehbaren Gründen ist der Ergebnis der Berechnung BruttoSumme * (MwStSatz / (MwStSatz + 100)) bei FireBird falsch.
Rein intuitiv hätte ich auch die Klammern weggelassen. Wenn ich erst dividiere rechne ich mit einem möglicherweise ungenauen Wert weiter, denn ich verliere Nachkommastellen je nach Datentyp. Die brauche ich aber bei den hohen Werten im Beispiel.
Multipliziere ich erst mit 19 und Teile dann durch 119, habe ich wenigstens im ersten Schritt einen genauen Werte und das zweite Ergebnis runde ich dann sowieso.

Also das ist letztlich genau das gleiche Problem wie in dem Beispiel des Steuerberaters, der mit einem gerundeten Faktor ungenau rechnet. Nur eben mit ein paar Nachkommastellen mehr.

Geändert von gubbe ( 2. Jul 2024 um 18:28 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von jaenicke
jaenicke

Registriert seit: 10. Jun 2003
Ort: Berlin
9.932 Beiträge
 
Delphi 12 Athens
 
#3

AW: MwSt. wird falsch berechnet. (Einige nutzen eine falsche Formel!)

  Alt 2. Jul 2024, 19:09
Wenn man die Berechnung in Delphi mit definierten Datentypen und Rundungen an den korrekten Stellen durchführt, hat man das Problem nicht. Dann ist es auch egal, wie die verwendete Datenbank rechnet. Und da kommt dann auch das gleiche raus, egal auf welchem Weg man die genannte Berechnung durchführt.
Sebastian Jänicke
AppCentral
  Mit Zitat antworten Zitat
Benutzerbild von gubbe
gubbe

Registriert seit: 8. Okt 2005
Ort: Schleswig-Holstein
150 Beiträge
 
Delphi 11 Alexandria
 
#4

AW: MwSt. wird falsch berechnet. (Einige nutzen eine falsche Formel!)

  Alt 3. Jul 2024, 10:26
Wenn man die Berechnung in Delphi mit definierten Datentypen und Rundungen an den korrekten Stellen durchführt, hat man das Problem nicht. Dann ist es auch egal, wie die verwendete Datenbank rechnet. Und da kommt dann auch das gleiche raus, egal auf welchem Weg man die genannte Berechnung durchführt.
Ja, wenn man in Delphi mit Datentyp Double rechnet, gibt es keinen Unterschied, egal welche Formel man verwendet oder wie man klammert. Bei anderen Datentypen wie Single würde es auch Abweichungen geben.
Nur verwenden Datenbanken für die Berechnung gemäß SQL-Standard Numeric bzw. Decimal und es gibt Regeln für die Zahl der signifikanten Nachkommastellen. Das heisst nicht, dass Firebird nicht rechnen kann, sondern man muss die Regeln beachten wie auch bei anderen Datenbanken.

Bei der Division unterscheiden sich Datenbanken in der Zahl der Nachkommastellen, aber man kann es auch in MySQL nachvollziehen:

Code:
select 150000000-150000000/1.19, 150000000 * 19 / 119, 150000000 * (19 / 119);
Ergibt (zum Vergleich untereinander geschrieben)

23949579.8319
23949579.8319
23949579.7500

Der dritte Wert ist ungenauer. Es kommt also auch hier nicht auf die Formel an, sondern auf die richtige Klammersetzung. Oder man fordert mehr Präzision und gibt Nachkommastellen vor (19.00 / 119.00)
  Mit Zitat antworten Zitat
raller09

Registriert seit: 7. Nov 2005
38 Beiträge
 
Delphi 10.1 Berlin Enterprise
 
#5

AW: MwSt. wird falsch berechnet. (Einige nutzen eine falsche Formel!)

  Alt 3. Jul 2024, 13:31
https://stackoverflow.com/questions/...-when-dividing
  Mit Zitat antworten Zitat
Benutzerbild von IBExpert
IBExpert

Registriert seit: 15. Mär 2005
695 Beiträge
 
FreePascal / Lazarus
 
#6

AW: MwSt. wird falsch berechnet. (Einige nutzen eine falsche Formel!)

  Alt 4. Jul 2024, 07:40
um zu verstehen, was firebird da macht, führ mal zB in ibexpert so was aus

insert into x
select
150000000.000 * 19.000 / 119.000 as A,
19.000 * 150000000.000 / 119.000 as B
from RDB$DATABASE;

auf basis von deinem select und den resultierenden Datentypen wird die tabelle
von ibexpert dynamisch erstellt

um 3 zahlen miteinander zu multiplizieren/dividiren, die jeweils 3 Nachkommastellen haben und
so wie im sql geschrieben wurde, werden zB als numeric(18,3) von firebird
interpretiert. Das resultierende Datenfeld wird also als numeric(18,9) erzeugt.

Gedankenexperiment:

wenn man nun ein mal
0.001*0.001*0.001
miteinander verlustfrei multiplizieren will, dann musst du im result
ein numeric(18,9) ermöglichen, sonst hast du ungeplant schon rundungsfehler.

Das vermeidet Firebird durch die gewählten Datentypen.

in der Tabelle x die da oben erstellt wird, sind die ergebnisfelder auch genau
dieser Datentyp, das wilde zwischendurch mal casten und rounden macht das Ergebnis
nicht besser, sondern führt ebenen ein, an denen die Abweichungen entstehen, die
hier bemängelt werden.

Und nun mal als Hinweis wo das Problem ist (bei dir an der Tastatur)

multipliziere folgende Zahlen

select
10000000000.00001*0.00001*0.00001
from RDB$DATABASE;

diese Rechnung erfordert damit nix weggerundet wird 15 nachkommastellen, ein insert
into wie oben würde dafür einen numeric(18,15) erzeugen, blöderweise sind dafür dann
aber von den 18 Stellen nur noch 3 vor dem Komma möglich, d.h. den Wert 1000 wirst
du darin schon nicht mehr speichern können.

hier ein Beispiel bei dem es knallt:

select
999900000.00111*0.11111*0.0111
from RDB$DATABASE;

Unsuccessful execution caused by system error that does not preclude successful execution of subsequent statements.
Integer overflow. The result of an integer operation caused the most significant bit of the result to carry.
-------------------------------------------------------------------------------------------------------------------
SQLCODE: -901
SQLSTATE: 22003
GDSCODE: 335544779

da ist keine zahl dabei, die die üblichen datentypen sprengt, aber das zwischenergebnis
kann nicht mit relevanter genauigkeit erstellt werden. Und vom dialekt 1 und dessen
gruseligkeiten reden wir da gar nicht erst, alle beispiele oben basieren auf dialekt 3.
Das Problem entsteht durch durch mehrfachoperation pro Zeile

Welche workarounds gibt es:

-Wenn das wirklich ein Problem ist, das du lösen musst, dann steig um auf fb>=4
dort gibt es numeric bis 34 statt 18, damit kommen aber nicht alle client libs
und komponenten klar

-wenn in deinem Zahlenraum >=zweistellige millionenbeträge gebraucht werden, sind für
Währungen meistens 2 Nachkommastellen ausreichend, also numeric(18,2). was dann für
Steuersätze erforderlich ist, ergibt sich durch das umfeld. Umrechnungsfaktoren
können aber auch noch ganz andere Ebenen sein, alte säcke wissen noch was mit der Zahl
1,95583 verbunden war.

-kombiniere im sql die werte immer mit nur einem operator oder nutze ab fb3 eigene
stored functions für eine sauberere berechnung, der du die werte übergibst
und die dann diese zeilenweise selber über geeignete Variablen mit ausreichender
Genauigkeit das ergebnis korrekt berechnet. SQL selber kann zwar auch direkt im
Befehl für Rechenoperationen benutzt werden, hat aber wie oben geschildert Grenzen,
die du berücksichtigen musst.

-Alternativ steht dir auch double precision in firebird als Datentyp zur verfügung, der
resultiert aber kaufmännisch betracht in anderen problemen. Eine torte für 10 € gesamtpreis
aufgeteilt in 3 stück zu je 10€/3 preislich festgelegt zeigt dann aufgrund der Endlichkeit
auf dem Preisschild 3,33€ als Stückpreis an, wenn jemand dann davon aber 3 stück kauft,
könnte es den Kunden wundern, warum deine Kasse 10€ auswirft und nicht wie im Kopf ausgrechnet
9,99€.Technisch kann nämlich im Double 3 1/3 stehen, auch wenn das im Front end nicht
komplett dargestellt wird, sind da auch unsichtbare teile in den Nachkommastellen
relevant).

-alternativ kannst du auch alle zahlen die währungsbeträge
darstellen, zB dann als int128 darstellen und damit zb jeden Betrag in ct
verwalten, auch da sollte wenig verloren gehen, ein 128 bit integer hat
ausreichend stellen (für seriennummern aller Atome in einem menschlichen
Körper würde in etwa ein int78 ausreichen, da ist also luft nach oben
selbst für so eine wenig hilfreiche seriennummernerfassung, soll aber
nur ein vorstellung geben, über welche datentypen man da redet).

numeric >=10 <=18 wird intern von fb dialekt 3 immer als int64 benutzt
numeric >=5 <=9 wird intern von fb dialekt 3 immer als int32 benutzt
numeric <=4 wird intern von fb dialekt 3 immer als int16 benutzt
das war auch schon in fb2.x so

Zusammenfassung: Firebird rechnet nichts falsch, sondern das was man dort als SQL
und basisdatentyp bzw Werte vorgibt. Und Ja, auch die reihenfolge ist wichtig, weil
auch firebird mit den verfügbaren Datentypen intern klar kommen muss, insbesondere
wenn selber noch zwischendurch castings und rundungen gemacht werden.

Wenn die Ergebnisse nicht das sind was du erwartest, musst du den Weg zum Ergebnis
anpassen. Ob dann execute block die werte mit passenden Variablen sauber zusammenstellt
oder sp oder trigger zwischenwerte ermitteln ist relativ egal, wild verschaltelte sum/cast/round
etc. sind dann aber selten eine gute strategie. Eigene Funktionen als Stored functions
bieten einen sehr zuverlässigen weg.

Für fast alle normalen Zahlenwerte ist die sql multiplikation aber einwandfrei implementiert.

Der Titel von dem Thread ist aus meiner sicht irreführend
Holger Klemt
www.ibexpert.com - IBExpert GmbH
Oldenburger Str 233 - 26203 Wardenburg - Germany
Firebird 5 Update und Know-how Workshop – 28.8.-29.08.2025 64546 Mörfelden - Walldorf
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 17:04 Uhr.
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz