jenner / lstgen Goto Github PK
View Code? Open in Web Editor NEWCode-Generator für die Lohnsteuerberechnung aus PAP XML
License: MIT License
Code-Generator für die Lohnsteuerberechnung aus PAP XML
License: MIT License
Hey jenner!
Great tool, would it be possible for you to add support for 2022?
I think the PAP have been released:
Hi,
I tried to create the python class. Nothing changed in the library.
While grabbing the XML, Python raised the SSL error.
Is it possible to fix that?
Best,
Tino
Hi,
I'm try to generate the classes (2020, 2021) for php, but i always get the same issue:
lstgen -p 2021_1 -l php --class-name Lohnsteuer2021 --outfile Lohnsteuer2021.php
/usr/local/lib/python3.9/site-packages/urllib3/connectionpool.py:979: InsecureRequestWarning: Unverified HTTPS request is being made to host 'www.bmf-steuerrechner.de'. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings
warnings.warn(
Traceback (most recent call last):
File "/usr/local/bin/lstgen", line 33, in <module>
sys.exit(load_entry_point('LstGen==0.5.2', 'console_scripts', 'lstgen')())
File "/usr/local/lib/python3.9/site-packages/LstGen-0.5.2-py3.9.egg/lstgen/cli.py", line 175, in main
generator.generate()
File "/usr/local/lib/python3.9/site-packages/LstGen-0.5.2-py3.9.egg/lstgen/generators/php/__init__.py", line 112, in generate
self._write_method(method)
File "/usr/local/lib/python3.9/site-packages/LstGen-0.5.2-py3.9.egg/lstgen/generators/php/__init__.py", line 166, in _write_method
self._write_stmt_body(method)
File "/usr/local/lib/python3.9/site-packages/LstGen-0.5.2-py3.9.egg/lstgen/generators/php/__init__.py", line 185, in _write_stmt_body
self._write_if(part)
File "/usr/local/lib/python3.9/site-packages/LstGen-0.5.2-py3.9.egg/lstgen/generators/php/__init__.py", line 194, in _write_if
self._write_stmt_body(stmt)
File "/usr/local/lib/python3.9/site-packages/LstGen-0.5.2-py3.9.egg/lstgen/generators/php/__init__.py", line 187, in _write_stmt_body
self._write_else(part)
File "/usr/local/lib/python3.9/site-packages/LstGen-0.5.2-py3.9.egg/lstgen/generators/php/__init__.py", line 203, in _write_else
self._write_stmt_body(stmt)
File "/usr/local/lib/python3.9/site-packages/LstGen-0.5.2-py3.9.egg/lstgen/generators/php/__init__.py", line 185, in _write_stmt_body
self._write_if(part)
File "/usr/local/lib/python3.9/site-packages/LstGen-0.5.2-py3.9.egg/lstgen/generators/php/__init__.py", line 194, in _write_if
self._write_stmt_body(stmt)
File "/usr/local/lib/python3.9/site-packages/LstGen-0.5.2-py3.9.egg/lstgen/generators/php/__init__.py", line 189, in _write_stmt_body
self._write_stmt_body(part)
File "/usr/local/lib/python3.9/site-packages/LstGen-0.5.2-py3.9.egg/lstgen/generators/php/__init__.py", line 181, in _write_stmt_body
self.writer.writeln(self._convert_exec(part.expr))
File "/usr/local/lib/python3.9/site-packages/LstGen-0.5.2-py3.9.egg/lstgen/generators/php/__init__.py", line 209, in _convert_exec
ret += self.to_code(parsed_stmt)
File "/usr/local/lib/python3.9/site-packages/LstGen-0.5.2-py3.9.egg/lstgen/generators/ast2code.py", line 225, in to_code
return self._conv_call(node)
File "/usr/local/lib/python3.9/site-packages/LstGen-0.5.2-py3.9.egg/lstgen/generators/ast2code.py", line 143, in _conv_call
caller = self.to_code(node.func)
File "/usr/local/lib/python3.9/site-packages/LstGen-0.5.2-py3.9.egg/lstgen/generators/ast2code.py", line 204, in to_code
return self._conv_attribute(node)
File "/usr/local/lib/python3.9/site-packages/LstGen-0.5.2-py3.9.egg/lstgen/generators/php/__init__.py", line 229, in _conv_attribute
val = self.to_code(node.value)
File "/usr/local/lib/python3.9/site-packages/LstGen-0.5.2-py3.9.egg/lstgen/generators/ast2code.py", line 225, in to_code
return self._conv_call(node)
File "/usr/local/lib/python3.9/site-packages/LstGen-0.5.2-py3.9.egg/lstgen/generators/ast2code.py", line 143, in _conv_call
caller = self.to_code(node.func)
File "/usr/local/lib/python3.9/site-packages/LstGen-0.5.2-py3.9.egg/lstgen/generators/ast2code.py", line 204, in to_code
return self._conv_attribute(node)
File "/usr/local/lib/python3.9/site-packages/LstGen-0.5.2-py3.9.egg/lstgen/generators/php/__init__.py", line 229, in _conv_attribute
val = self.to_code(node.value)
File "/usr/local/lib/python3.9/site-packages/LstGen-0.5.2-py3.9.egg/lstgen/generators/ast2code.py", line 222, in to_code
return self._conv_list_subscript(node)
File "/usr/local/lib/python3.9/site-packages/LstGen-0.5.2-py3.9.egg/lstgen/generators/ast2code.py", line 137, in _conv_list_subscript
self.to_code(node.slice.value) +
AttributeError: 'Name' object has no attribute 'value'
When I try to execute the code examples as they are shown in the Readme, they throw an error
% lstgen 2014 python --class-name Lohnsteuer2014 --outfile lst2014.py
usage: lstgen [-h] [-V] [-l LANG] [-p PAP] [-x XML_PATH] [--pap-versions]
[--outfile OUTFILE] [--class-name CLASS_NAME] [--indent INDENT]
[--java-package-name JAVA_PACKAGE] [--php-ns PHP_NAMESPACE]
lstgen: error: unrecognized arguments: 2014 python
It does work with extra -p and -l arguments
lstgen -p 2014 -l python --class-name Lohnsteuer2014 --outfile lst2014.py
Perhaps the readme could be ammended to include that.
see topic: Possible to add Golang as output?
I tried both the python and the javascript generations. And the calculations are correct in comparison to the BMF online calculator. But, for example,
RE4 = 195000
KVZ = 1.1
LZZ = 2
PVZ = 1
STKL = 1
R = 0
KRV = 0
I get:
steuer = 161.83
soli = 8.90
in the online calculator:
Ergebnis der Berechnung der Lohnsteuer für 2020
Die Lohnsteuer beträgt: 161,75 Euro
Der Solidaritätszuschlag beträgt: 8,89 Euro
Any help to find the issue is greatly appreciated :)
Ich hab mittels
lstgen -x Lohnsteuer2017.xml -l python --class-name Lohnsteuer2017 --outfile lst2017.py
die Lohnsteuer-Datei geniert und teste sie, wie hier beschrieben, gegen die externe Programmierschnittstelle
https://www.bmf-steuerrechner.de/interface/schnittstelle.jsp
und bekomme leider nicht die selben Ergebnisse. Mein Code
from lst.lst2017 import Lohnsteuer2017
def print_lst(lst):
BK = lst.getBk()
BKS = lst.getBks()
LSTLZZ = lst.getLstlzz()
SOLZLZZ = lst.getSolzlzz()
WVFRB = lst.getWvfrb()
print(('BK: %i\n' +
'BKS: %i\n' +
'LSTLZZ: %i\n' +
'SOLZLZZ: %i\n' +
'WVFRB: %i') % (BK, BKS, LSTLZZ, SOLZLZZ, WVFRB))
def test_simple():
brutto = 2500000 # Brutto in ¢ent
lst2017 = Lohnsteuer2017(
RE4=brutto,
LZZ=1,
STKL=1
)
lst2017.MAIN()
print_lst(lst2017)
if __name__ == '__main__':
test_simple()
liefert zum Beispiel
LSTLZZ: -1782700
aber
https://www.bmf-steuerrechner.de/interface/LSt2017.jsp?LZZ=1&RE4=2500000&STKL=1
liefert
LSTLZZ: 260100
Irgendeine Idee, was ich falsch mache?
The 2010 generator is causing an exception:
lstgen -p 2010 -l python --class-name BmfTax --outfile app/bmf/tax2010.py
/usr/lib/python3/dist-packages/urllib3/connectionpool.py:999: InsecureRequestWarning: Unverified HTTPS request is being made to host 'www.bmf-st
euerrechner.de'. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warn
ings
warnings.warn(
Traceback (most recent call last):
File "/usr/local/bin/lstgen", line 8, in <module>
sys.exit(main())
File "/usr/local/lib/python3.8/dist-packages/lstgen/cli.py", line 161, in main
generator.generate()
File "/usr/local/lib/python3.8/dist-packages/lstgen/generators/python/__init__.py", line 67, in generate
self._write_constructor()
File "/usr/local/lib/python3.8/dist-packages/lstgen/generators/python/__init__.py", line 102, in _write_constructor
value=self.convert_to_python(var.default)
File "/usr/local/lib/python3.8/dist-packages/lstgen/generators/python/__init__.py", line 168, in convert_to_python
tree = ast.parse(prepare_expr(value))
File "/usr/local/lib/python3.8/dist-packages/lstgen/__init__.py", line 26, in prepare_expr
source = source.replace(key, repl)
AttributeError: 'NoneType' object has no attribute 'replace'
The resulting Python module is then incomplete.
Hi, javascript output use BigDecimal but not very much browsers support it. Is there any polifill?
Hi,
following the README I can't get the tool running with Python 3 for a Python generation.
Example Dockerfile:
FROM python:3.6
RUN pip3 install lstgen &&\
lstgen 2014 python --class-name Lohnsteuer2014 --outfile lst2014.py
Error:
usage: lstgen [-h] [-l LANG] [-p PAP] [-x XML_PATH] [--pap-versions]
[--outfile OUTFILE] [--class-name CLASS_NAME] [--indent INDENT]
[--java-package-name JAVA_PACKAGE] [--php-ns PHP_NAMESPACE]
lstgen: error: unrecognized arguments: 2014 python
Following the help, I have also tried:
FROM python:3.6
RUN pip3 install lstgen &&\
lstgen -p 2017 -l python
but then get the following error:
/usr/local/lib/python3.6/site-packages/urllib3/connectionpool.py:847: InsecureRequestWarning: Unverified HTTPS request is being made. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings
InsecureRequestWarning)
Traceback (most recent call last):
File "/usr/local/bin/lstgen", line 11, in <module>
sys.exit(main())
File "/usr/local/lib/python3.6/site-packages/lstgen/cli.py", line 113, in main
pap_parser = PapParser(etree.fromstring(xml_content))
File "/usr/local/lib/python3.6/site-packages/lstgen/__init__.py", line 253, in __init__
self.parse()
File "/usr/local/lib/python3.6/site-packages/lstgen/__init__.py", line 259, in parse
main_element = self.tree_root.xpath('/PAP/METHODS/MAIN')[0]
IndexError: list index out of range
Python3's revamped decimal module doesn't expose the _rescale method any more, which is used in BigDecimal proxy class
Es stellte sich als ein Fehler in der aufrufenden Klasse heraus.
While the source BMF site has XML files also for both 2018 and 2019, the tool does not list all of them:
> lstgen --pap-versions
Verfügbare PAP Versionen:
2006
2007
2008
2009
2010
2011bisNov
2011Dez
2012
2013
2014
2015bisNov
2015Dez
2016
2017
Hello, on the BMF site it seems that there are only the xml files for 2023 and 2024 available. Is there a repository where also the older files are stored which can be accessed by LstGen? Currently I get an error when trying to use the tool with other files than for 2023 and 2024
Hi Jenner, thank you for your great work on making this Software.
I have a problem with the implementation of the sample PHP-Code:
$brutto = 500000; // Brutto in ¢ent
$lst = new Lohnsteuer2023();
$lst->setRe4($brutto);
$lst->setPkv(1);
$lst->setAlter1(0);
$lst->setAf(0);
$lst->setF(1);
$lst->setPvs(0);
$lst->setR(0);
$lst->setLzzhinzu(0);
$lst->setPvz(0);
$lst->setStkl(1);
$lst->setLzz(2);
$lst->setKrv(2);
$lst->main();
$steuer = floor($lst->getLstlzz()->toFloat() + $lst->getStv()->toFloat() + $lst->getSts()->toFloat());
$soli = floor($lst->getSolzlzz()->toFloat() + $lst->getSolzs()->toFloat() + $lst->getSolzv()->toFloat()) / 100;
$stges = $steuer + $soli;
echo "steuer: $steuer\nsoli: $soli\nstges: $stges\n";`
I always get the error message: Fatal error: Uncaught Error: Call to undefined method BigDecimal::toFloat() in ... on line x, where x is the line where toFloat() is first used in the sample code.
I am convinced that i produce these error through something myself, but did you have an idea what i could change to get it up and running?
Thank you very much!
Hi, first of all thank you for a quick update!
My next steps are now to check the codes against other sources to get an idea whether there could be a match. So, my assumption is that if I take an example from my own loan sheet or a reference loan sheet, it should have "more or less" same numbers like LstGen, or?
So my first example is here: https://www.lohnexperte.de/files/root-pdfs/pdf/Muster.pdf
There is a Steuer-Brutto 4926.59, resulting in LSt 1000.75 and SoliZ 42.20 as test data.
Python code ( a unit test method):
def test_lohnexample1(self):
# source: https://www.lohnexperte.de/files/root-pdfs/pdf/Muster.pdf
brutto = 4926.59 * 100 # Brutto in ¢ent
l = Lohnsteuer2018()
l.setRe4(brutto) # cent
l.setPkv(1)
l.setAlter1(0)
l.setAf(0)
l.setF(1)
l.setPvs(0)
l.setR(0)
l.setLzzhinzu(0)
l.setPvz(0)
l.setStkl(1)
l.setLzz(2)
l.setKrv(2)
l.MAIN()
print("results lohnexample1:")
print_lst(l)
steuer = math.floor(float(l.getLstlzz()) + float(l.getStv()) + float(l.getSts())) / 100.0
soli = math.floor(float(l.getSolzlzz()) + float(l.getSolzs()) + float(l.getSolzv())) / 100
stges = steuer + soli
assert steuer == 1000.75
assert soli == 42.20
Asserts fail, as the output of LstGen class is:
results lohnexample1:
steuer: 1247.91
soli: 68.63
stges: 1316.54
Do you have an idea why is so?
Same Steuer-Brutto put into , here I get:
Solidaritätszuschlag: 55,18 €
Lohnsteuer: 1.003,41 €
Actually LstGen seems to be best source of truth as we have evidence that it uses algorithms our government provides us with. :-)
Finally, the formula given in wikipedia provides the following values:
soli 51.53
lohnsteuer 936.91
Hello Igor,
first of all, thanks for this library. It saves a lot of time...
We are having a problem with the go implementation. I'm pertty sure it's related to the roundings (see the FIXIT code parts), thus the missing ROUND_DOWN in the github.com/shopspring/decimal lib.
E.G. the calculation like:
https://www.bmf-steuerrechner.de/interface/2021Version1.xhtml?code=eP2021&PVZ=1&R=1&RE4=207753&LZZ=2&STKL=1&AF=0&AJAHR=0&ALTER1=0&ENTSCH=0&F=0&JFREIB=0&JHINZU=0&JRE4=0&JVBEZ=0&KRV=0&KVZ=0.9&LZZFREIB=0&LZZHINZU=0&PKPV=0&PKV=0&PVS=0&SONSTB=0&STERBE=0&VBEZ=0&VBEZM=0&VBEZS=0&VBS=0&VJAHR=0&VKAPA=0&VMT=0&ZKF=0&ZMVB=0&JRE4ENT=0&SONSTENT=0
returns a drifference of 22 cents compared to the www.bmf-steuerrechner.de output.
For now we overcome this by using the javascript output and running it in a v8 engine inside our app, with this BigDecimal class:
`
// http://mikemcl.github.io/big.js/#toN
let BigDecimal = class extends Number {
static ROUND_DOWN = 0
static ROUND_UP = 3
constructor(value) {
super(value)
}
static valueOf(value){
return new BigDecimal(value)
}
divide(other, scale, rounding){
if(scale==undefined || rounding==undefined){
return new BigDecimal(this/other)
}
return new BigDecimal(this / other).setScale(scale, rounding)
}
multiply(other){
return new BigDecimal(this*other)
}
setScale(scale, rounding){
let b = Big(this)
return new BigDecimal(b.round(scale, rounding).toNumber())
}
add(other){
return new BigDecimal(this+other)
}
subtract(other){
return new BigDecimal(this-other)
}
longValue(){
return this.abs().toNumber();
}
compareTo(other){
if(this>other){
return new BigDecimal(1)
}else if (this<other){
return new BigDecimal(-1)
}else{
return new BigDecimal(0)
}
}
static ZERO() {
return new BigDecimal(0);
}
static ONE() {
return new BigDecimal(1);
}
static TEN() {
return new BigDecimal(10);
}
}
`
This works ok, but requires e.g. "rogchap.com/v8go" which uses cgo, which i would like to avoid.
Is there any chance to get this rounding thing fixed, so we can use the pure go implementation?
I belive, that using something like the BigDecimal class in go as an abstraction should work. As far as i can see, we don't need that complicated function, just add/mul/div/sub and round and those 2 rounding functions should be easily implementable in go:
up: math.Ceil(value10^scale)/10^scale
down: math.Floor(value10^scale)/10^scale
right?
And one more question. Are you going to add the 2022 calculation also? The BFM allready released a pre version:
(https://www.bundesfinanzministerium.de/Content/DE/Downloads/Steuern/Steuerarten/Lohnsteuer/Programmablaufplan/2021-10-05-PAP-2022-entwuerfe.html)
Thank you
Hi, Jenner, so if I understand your tool correctly, you somehow parse BMF's APIs to create the classes?
Thank you for publishing this, by finding your tool now I have learned about BMF PAPs!
So far I have worked on my own tool but now I know how to better proceed further :-)
First of all, Thanks a lot for putting in the work and making it available for everyone, really awesome.
It would be very helpful if the PAP versions were named in a way that they can be selected automatically. Currently they look like this:
Verfügbare PAP Versionen:
2006
2007
2008
2009
2010
2011bisNov
2011Dez
2012
2013
2014
2015bisNov
2015Dez
2016
2017
2018
2019
2020
Better would be (IMO):
2006
2007
2008
2009
2010
2011-1
2011-12
2012
2013
2014
2015-1
2015-12
2016
2017
2018
2019
2020
So each version is named according to the time where the rules come into effect. This would also be future-proof in case rules are changed mid-month in the future, e.g.
2020-11-15
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.