Steuermodul erstellt

This commit is contained in:
Eduard Wisch 2026-02-03 14:47:27 +01:00
commit 0b545ea47e
31 changed files with 6649 additions and 0 deletions

621
COPYING Executable file
View file

@ -0,0 +1,621 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS

5
ChangeLog.md Executable file
View file

@ -0,0 +1,5 @@
# CHANGELOG MODULE STEUER FOR [DOLIBARR ERP CRM](https://www.dolibarr.org)
## 1.0
Initial version

96
README.md Executable file
View file

@ -0,0 +1,96 @@
# STEUER FOR [DOLIBARR ERP & CRM](https://www.dolibarr.org)
## Features
Description of the module...
<!--
![Screenshot steuer](img/screenshot_steuer.png?raw=true "Steuer"){imgmd}
-->
Other external modules are available on [Dolistore.com](https://www.dolistore.com).
## Translations
Translations can be completed manually by editing files in the module directories under `langs`.
<!--
This module contains also a sample configuration for Transifex, under the hidden directory [.tx](.tx), so it is possible to manage translation using this service.
For more information, see the [translator's documentation](https://wiki.dolibarr.org/index.php/Translator_documentation).
There is a [Transifex project](https://transifex.com/projects/p/dolibarr-module-template) for this module.
-->
## Installation
Prerequisites: You must have Dolibarr ERP & CRM software installed. You can download it from [Dolistore.org](https://www.dolibarr.org).
You can also get a ready-to-use instance in the cloud from https://saas.dolibarr.org
### From the ZIP file and GUI interface
If the module is a ready-to-deploy zip file, so with a name `module_xxx-version.zip` (e.g., when downloading it from a marketplace like [Dolistore](https://www.dolistore.com)),
go to menu `Home> Setup> Modules> Deploy external module` and upload the zip file.
<!--
Note: If this screen tells you that there is no "custom" directory, check that your setup is correct:
- In your Dolibarr installation directory, edit the `htdocs/conf/conf.php` file and check that following lines are not commented:
```php
//$dolibarr_main_url_root_alt ...
//$dolibarr_main_document_root_alt ...
```
- Uncomment them if necessary (delete the leading `//`) and assign the proper value according to your Dolibarr installation
For example :
- UNIX:
```php
$dolibarr_main_url_root_alt = '/custom';
$dolibarr_main_document_root_alt = '/var/www/Dolibarr/htdocs/custom';
```
- Windows:
```php
$dolibarr_main_url_root_alt = '/custom';
$dolibarr_main_document_root_alt = 'C:/My Web Sites/Dolibarr/htdocs/custom';
```
-->
<!--
### From a GIT repository
Clone the repository in `$dolibarr_main_document_root_alt/steuer`
```shell
cd ....../custom
git clone git@github.com:gitlogin/steuer.git steuer
```
-->
### Final steps
Using your browser:
- Log into Dolibarr as a super-administrator
- Go to "Setup"> "Modules"
- You should now be able to find and enable the module
## Licenses
### Main code
GPLv3 or (at your option) any later version. See file COPYING for more information.
### Documentation
All texts and readme's are licensed under [GFDL](https://www.gnu.org/licenses/fdl-1.3.en.html).

118
admin/about.php Executable file
View file

@ -0,0 +1,118 @@
<?php
/* Copyright (C) 2004-2017 Laurent Destailleur <eldy@users.sourceforge.net>
* Copyright (C) 2026 Eduard Wisch <data@data-it-solution.de>
* Copyright (C) 2024 Frédéric France <frederic.france@free.fr>
*
* 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/>.
*/
/**
* \file steuer/admin/about.php
* \ingroup steuer
* \brief About page of module Steuer.
*/
// Load Dolibarr environment
$res = 0;
// Try main.inc.php into web root known defined into CONTEXT_DOCUMENT_ROOT (not always defined)
if (!$res && !empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) {
$res = @include $_SERVER["CONTEXT_DOCUMENT_ROOT"]."/main.inc.php";
}
// Try main.inc.php into web root detected using web root calculated from SCRIPT_FILENAME
$tmp = empty($_SERVER['SCRIPT_FILENAME']) ? '' : $_SERVER['SCRIPT_FILENAME'];
$tmp2 = realpath(__FILE__);
$i = strlen($tmp) - 1;
$j = strlen($tmp2) - 1;
while ($i > 0 && $j > 0 && isset($tmp[$i]) && isset($tmp2[$j]) && $tmp[$i] == $tmp2[$j]) {
$i--;
$j--;
}
if (!$res && $i > 0 && file_exists(substr($tmp, 0, ($i + 1))."/main.inc.php")) {
$res = @include substr($tmp, 0, ($i + 1))."/main.inc.php";
}
if (!$res && $i > 0 && file_exists(dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php")) {
$res = @include dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php";
}
// Try main.inc.php using relative path
if (!$res && file_exists("../../main.inc.php")) {
$res = @include "../../main.inc.php";
}
if (!$res && file_exists("../../../main.inc.php")) {
$res = @include "../../../main.inc.php";
}
if (!$res) {
die("Include of main fails");
}
// Libraries
require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
require_once '../lib/steuer.lib.php';
/**
* @var Conf $conf
* @var DoliDB $db
* @var HookManager $hookmanager
* @var Translate $langs
* @var User $user
*/
// Translations
$langs->loadLangs(array("errors", "admin", "steuer@steuer"));
// Access control
if (!$user->admin) {
accessforbidden();
}
// Parameters
$action = GETPOST('action', 'aZ09');
$backtopage = GETPOST('backtopage', 'alpha');
/*
* Actions
*/
// None
/*
* View
*/
$form = new Form($db);
$help_url = '';
$title = "SteuerSetup";
llxHeader('', $langs->trans($title), $help_url, '', 0, 0, '', '', '', 'mod-steuer page-admin_about');
// Subheader
$linkback = '<a href="'.($backtopage ? $backtopage : DOL_URL_ROOT.'/admin/modules.php?restore_lastsearch_values=1').'">'.$langs->trans("BackToModuleList").'</a>';
print load_fiche_titre($langs->trans($title), $linkback, 'title_setup');
// Configuration header
$head = steuerAdminPrepareHead();
print dol_get_fiche_head($head, 'about', $langs->trans($title), 0, 'steuer@steuer');
dol_include_once('/steuer/core/modules/modSteuer.class.php');
$tmpmodule = new modSteuer($db);
print $tmpmodule->getDescLong();
// Page end
print dol_get_fiche_end();
llxFooter();
$db->close();

629
admin/setup.php Executable file
View file

@ -0,0 +1,629 @@
<?php
/* Copyright (C) 2004-2017 Laurent Destailleur <eldy@users.sourceforge.net>
* Copyright (C) 2024 Frédéric France <frederic.france@free.fr>
* Copyright (C) 2026 Eduard Wisch <data@data-it-solution.de>
*
* 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/>.
*/
/**
* \file steuer/admin/setup.php
* \ingroup steuer
* \brief Steuer setup page.
*/
// Load Dolibarr environment
$res = 0;
// Try main.inc.php into web root known defined into CONTEXT_DOCUMENT_ROOT (not always defined)
if (!$res && !empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) {
$res = @include $_SERVER["CONTEXT_DOCUMENT_ROOT"]."/main.inc.php";
}
// Try main.inc.php into web root detected using web root calculated from SCRIPT_FILENAME
$tmp = empty($_SERVER['SCRIPT_FILENAME']) ? '' : $_SERVER['SCRIPT_FILENAME'];
$tmp2 = realpath(__FILE__);
$i = strlen($tmp) - 1;
$j = strlen($tmp2) - 1;
while ($i > 0 && $j > 0 && isset($tmp[$i]) && isset($tmp2[$j]) && $tmp[$i] == $tmp2[$j]) {
$i--;
$j--;
}
if (!$res && $i > 0 && file_exists(substr($tmp, 0, ($i + 1))."/main.inc.php")) {
$res = @include substr($tmp, 0, ($i + 1))."/main.inc.php";
}
if (!$res && $i > 0 && file_exists(dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php")) {
$res = @include dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php";
}
// Try main.inc.php using relative path
if (!$res && file_exists("../../main.inc.php")) {
$res = @include "../../main.inc.php";
}
if (!$res && file_exists("../../../main.inc.php")) {
$res = @include "../../../main.inc.php";
}
if (!$res) {
die("Include of main fails");
}
// Libraries
require_once DOL_DOCUMENT_ROOT."/core/lib/admin.lib.php";
require_once '../lib/steuer.lib.php';
//require_once "../class/myclass.class.php";
/**
* @var Conf $conf
* @var DoliDB $db
* @var HookManager $hookmanager
* @var Translate $langs
* @var User $user
*/
// Translations
$langs->loadLangs(array("admin", "steuer@steuer"));
// Initialize a technical object to manage hooks of page. Note that conf->hooks_modules contains an array of hook context
/** @var HookManager $hookmanager */
$hookmanager->initHooks(array('steuersetup', 'globalsetup'));
// Parameters
$action = GETPOST('action', 'aZ09');
$backtopage = GETPOST('backtopage', 'alpha');
$modulepart = GETPOST('modulepart', 'aZ09'); // Used by actions_setmoduleoptions.inc.php
$value = GETPOST('value', 'alpha');
$label = GETPOST('label', 'alpha');
$scandir = GETPOST('scan_dir', 'alpha');
$type = 'myobject';
$error = 0;
$setupnotempty = 0;
// Access control
if (!$user->admin) {
accessforbidden();
}
// Set this to 1 to use the factory to manage constants. Warning, the generated module will be compatible with version v15+ only
$useFormSetup = 1;
if (!class_exists('FormSetup')) {
require_once DOL_DOCUMENT_ROOT.'/core/class/html.formsetup.class.php';
}
$formSetup = new FormSetup($db);
// Access control
if (!$user->admin) {
accessforbidden();
}
// Enter here all parameters in your setup page
// Setup conf for selection of an URL
$item = $formSetup->newItem('STEUER_MYPARAM1');
$item->fieldParams['isMandatory'] = 1;
$item->fieldAttr['placeholder'] = (empty($_SERVER['HTTPS']) ? 'http://' : 'https://') . $_SERVER['HTTP_HOST'];
$item->cssClass = 'minwidth500';
// Setup conf for selection of a simple string input
$item = $formSetup->newItem('STEUER_MYPARAM2');
$item->defaultFieldValue = 'default value';
$item->fieldAttr['placeholder'] = 'A placeholder here';
$item->helpText = 'Tooltip text';
// Setup conf for selection of a simple textarea input but we replace the text of field title
$item = $formSetup->newItem('STEUER_MYPARAM3');
$item->nameText = $item->getNameText().' more html text ';
// Setup conf for a selection of a Thirdparty
$item = $formSetup->newItem('STEUER_MYPARAM4');
$item->setAsThirdpartyType();
// Setup conf for a selection of a boolean
$formSetup->newItem('STEUER_MYPARAM5')->setAsYesNo();
// Setup conf for a selection of an Email template of type thirdparty
$formSetup->newItem('STEUER_MYPARAM6')->setAsEmailTemplate('thirdparty');
// Setup conf for a selection of a secured key
//$formSetup->newItem('STEUER_MYPARAM7')->setAsSecureKey();
// Setup conf for a selection of a Product
$formSetup->newItem('STEUER_MYPARAM8')->setAsProduct();
// Add a title for a new section
$formSetup->newItem('NewSection')->setAsTitle();
$TField = array(
'test01' => $langs->trans('test01'),
'test02' => $langs->trans('test02'),
'test03' => $langs->trans('test03'),
'test04' => $langs->trans('test04'),
'test05' => $langs->trans('test05'),
'test06' => $langs->trans('test06'),
);
// Setup conf for a simple combo list
$formSetup->newItem('STEUER_MYPARAM9')->setAsSelect($TField);
// Setup conf for a multiselect combo list
$item = $formSetup->newItem('STEUER_MYPARAM10');
$item->setAsMultiSelect($TField);
$item->helpText = $langs->transnoentities('STEUER_MYPARAM10');
// Setup conf for a category selection
$formSetup->newItem('STEUER_CATEGORY_ID_XXX')->setAsCategory('product');
// Setup conf STEUER_MYPARAM10
$item = $formSetup->newItem('STEUER_MYPARAM10');
$item->setAsColor();
$item->defaultFieldValue = '#FF0000';
//$item->fieldValue = '';
//$item->fieldAttr = array() ; // fields attribute only for compatible fields like input text
//$item->fieldOverride = false; // set this var to override field output will override $fieldInputOverride and $fieldOutputOverride too
//$item->fieldInputOverride = false; // set this var to override field input
//$item->fieldOutputOverride = false; // set this var to override field output
$item = $formSetup->newItem('STEUER_MYPARAM11')->setAsHtml();
$item->nameText = $item->getNameText().' more html text ';
$item->fieldInputOverride = '';
$item->helpText = $langs->transnoentities('HelpMessage');
$item->cssClass = 'minwidth500';
$item = $formSetup->newItem('STEUER_MYPARAM12');
$item->fieldOverride = "Value forced, can't be modified";
$item->cssClass = 'minwidth500';
//$item = $formSetup->newItem('STEUER_MYPARAM13')->setAsDate(); // Not yet implemented
// End of definition of parameters
$setupnotempty += count($formSetup->items);
$dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
$moduledir = 'steuer';
$myTmpObjects = array();
// TODO Scan list of objects to fill this array
$myTmpObjects['myobject'] = array('label' => 'MyObject', 'includerefgeneration' => 0, 'includedocgeneration' => 0, 'class' => 'MyObject');
$tmpobjectkey = GETPOST('object', 'aZ09');
if ($tmpobjectkey && !array_key_exists($tmpobjectkey, $myTmpObjects)) {
accessforbidden('Bad value for object. Hack attempt ?');
}
/*
* Actions
*/
// For retrocompatibility Dolibarr < 15.0
if (versioncompare(explode('.', DOL_VERSION), array(15)) < 0 && $action == 'update' && !empty($user->admin)) {
$formSetup->saveConfFromPost();
}
include DOL_DOCUMENT_ROOT.'/core/actions_setmoduleoptions.inc.php';
if ($action == 'updateMask') {
$maskconst = GETPOST('maskconst', 'aZ09');
$maskvalue = GETPOST('maskvalue', 'alpha');
if ($maskconst && preg_match('/_MASK$/', $maskconst)) {
$res = dolibarr_set_const($db, $maskconst, $maskvalue, 'chaine', 0, '', $conf->entity);
if (!($res > 0)) {
$error++;
}
}
if (!$error) {
setEventMessages($langs->trans("SetupSaved"), null, 'mesgs');
} else {
setEventMessages($langs->trans("Error"), null, 'errors');
}
} elseif ($action == 'specimen' && $tmpobjectkey) {
$modele = GETPOST('module', 'alpha');
$className = $myTmpObjects[$tmpobjectkey]['class'];
$tmpobject = new $className($db);
'@phan-var-force MyObject $tmpobject';
$tmpobject->initAsSpecimen();
// Search template files
$file = '';
$className = '';
$dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
foreach ($dirmodels as $reldir) {
$file = dol_buildpath($reldir."core/modules/steuer/doc/pdf_".$modele."_".strtolower($tmpobjectkey).".modules.php", 0);
if (file_exists($file)) {
$className = "pdf_".$modele."_".strtolower($tmpobjectkey);
break;
}
}
if ($className !== '') {
require_once $file;
$module = new $className($db);
'@phan-var-force ModelePDFMyObject $module';
'@phan-var-force ModelePDFMyObject $module';
if ($module->write_file($tmpobject, $langs) > 0) {
header("Location: ".DOL_URL_ROOT."/document.php?modulepart=steuer-".strtolower($tmpobjectkey)."&file=SPECIMEN.pdf");
return;
} else {
setEventMessages($module->error, null, 'errors');
dol_syslog($module->error, LOG_ERR);
}
} else {
setEventMessages($langs->trans("ErrorModuleNotFound"), null, 'errors');
dol_syslog($langs->trans("ErrorModuleNotFound"), LOG_ERR);
}
} elseif ($action == 'setmod') {
// TODO Check if numbering module chosen can be activated by calling method canBeActivated
if (!empty($tmpobjectkey)) {
$constforval = 'STEUER_'.strtoupper($tmpobjectkey)."_ADDON";
dolibarr_set_const($db, $constforval, $value, 'chaine', 0, '', $conf->entity);
}
} elseif ($action == 'set') {
// Activate a model
$ret = addDocumentModel($value, $type, $label, $scandir);
} elseif ($action == 'del') {
$ret = delDocumentModel($value, $type);
if ($ret > 0) {
if (!empty($tmpobjectkey)) {
$constforval = 'STEUER_'.strtoupper($tmpobjectkey).'_ADDON_PDF';
if (getDolGlobalString($constforval) == "$value") {
dolibarr_del_const($db, $constforval, $conf->entity);
}
}
}
} elseif ($action == 'setdoc') {
// Set or unset default model
if (!empty($tmpobjectkey)) {
$constforval = 'STEUER_'.strtoupper($tmpobjectkey).'_ADDON_PDF';
if (dolibarr_set_const($db, $constforval, $value, 'chaine', 0, '', $conf->entity)) {
// The constant that was read before the new set
// We therefore requires a variable to have a coherent view
$conf->global->{$constforval} = $value;
}
// We disable/enable the document template (into llx_document_model table)
$ret = delDocumentModel($value, $type);
if ($ret > 0) {
$ret = addDocumentModel($value, $type, $label, $scandir);
}
}
} elseif ($action == 'unsetdoc') {
if (!empty($tmpobjectkey)) {
$constforval = 'STEUER_'.strtoupper($tmpobjectkey).'_ADDON_PDF';
dolibarr_del_const($db, $constforval, $conf->entity);
}
}
$action = 'edit';
/*
* View
*/
$form = new Form($db);
$help_url = '';
$title = "SteuerSetup";
llxHeader('', $langs->trans($title), $help_url, '', 0, 0, '', '', '', 'mod-steuer page-admin');
// Subheader
$linkback = '<a href="'.($backtopage ? $backtopage : DOL_URL_ROOT.'/admin/modules.php?restore_lastsearch_values=1').'">'.$langs->trans("BackToModuleList").'</a>';
print load_fiche_titre($langs->trans($title), $linkback, 'title_setup');
// Configuration header
$head = steuerAdminPrepareHead();
print dol_get_fiche_head($head, 'settings', $langs->trans($title), -1, "steuer@steuer");
// Setup page goes here
echo '<span class="opacitymedium">'.$langs->trans("SteuerSetupPage").'</span><br><br>';
/*if ($action == 'edit') {
print $formSetup->generateOutput(true);
print '<br>';
} elseif (!empty($formSetup->items)) {
print $formSetup->generateOutput();
print '<div class="tabsAction">';
print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?action=edit&token='.newToken().'">'.$langs->trans("Modify").'</a>';
print '</div>';
}
*/
if (!empty($formSetup->items)) {
print $formSetup->generateOutput(true);
print '<br>';
}
foreach ($myTmpObjects as $myTmpObjectKey => $myTmpObjectArray) {
if (!empty($myTmpObjectArray['includerefgeneration'])) {
// Numbering models
$setupnotempty++;
print load_fiche_titre($langs->trans("NumberingModules", $myTmpObjectArray['label']), '', '');
print '<table class="noborder centpercent">';
print '<tr class="liste_titre">';
print '<td>'.$langs->trans("Name").'</td>';
print '<td>'.$langs->trans("Description").'</td>';
print '<td class="nowrap">'.$langs->trans("Example").'</td>';
print '<td class="center" width="60">'.$langs->trans("Status").'</td>';
print '<td class="center" width="16">'.$langs->trans("ShortInfo").'</td>';
print '</tr>'."\n";
clearstatcache();
foreach ($dirmodels as $reldir) {
$dir = dol_buildpath($reldir."core/modules/".$moduledir);
if (is_dir($dir)) {
$handle = opendir($dir);
if (is_resource($handle)) {
while (($file = readdir($handle)) !== false) {
if (strpos($file, 'mod_'.strtolower($myTmpObjectKey).'_') === 0 && substr($file, dol_strlen($file) - 3, 3) == 'php') {
$file = substr($file, 0, dol_strlen($file) - 4);
require_once $dir.'/'.$file.'.php';
$module = new $file($db);
'@phan-var-force ModeleNumRefMyObject $module';
// Show modules according to features level
if ($module->version == 'development' && getDolGlobalInt('MAIN_FEATURES_LEVEL') < 2) {
continue;
}
if ($module->version == 'experimental' && getDolGlobalInt('MAIN_FEATURES_LEVEL') < 1) {
continue;
}
if ($module->isEnabled()) {
dol_include_once('/'.$moduledir.'/class/'.strtolower($myTmpObjectKey).'.class.php');
print '<tr class="oddeven"><td>'.$module->getName($langs)."</td><td>\n";
print $module->info($langs);
print '</td>';
// Show example of numbering model
print '<td class="nowrap">';
$tmp = $module->getExample();
if (preg_match('/^Error/', $tmp)) {
$langs->load("errors");
print '<div class="error">'.$langs->trans($tmp).'</div>';
} elseif ($tmp == 'NotConfigured') {
print $langs->trans($tmp);
} else {
print $tmp;
}
print '</td>'."\n";
print '<td class="center">';
$constforvar = 'STEUER_'.strtoupper($myTmpObjectKey).'_ADDON';
$defaultifnotset = 'thevaluetousebydefault';
$activenumberingmodel = getDolGlobalString($constforvar, $defaultifnotset);
if ($activenumberingmodel == $file) {
print img_picto($langs->trans("Activated"), 'switch_on');
} else {
print '<a href="'.$_SERVER["PHP_SELF"].'?action=setmod&token='.newToken().'&object='.strtolower($myTmpObjectKey).'&value='.urlencode($file).'">';
print img_picto($langs->trans("Disabled"), 'switch_off');
print '</a>';
}
print '</td>';
$className = $myTmpObjectArray['class'];
$mytmpinstance = new $className($db);
'@phan-var-force MyObject $mytmpinstance';
$mytmpinstance->initAsSpecimen();
// Info
$htmltooltip = '';
$htmltooltip .= ''.$langs->trans("Version").': <b>'.$module->getVersion().'</b><br>';
$nextval = $module->getNextValue($mytmpinstance);
if ("$nextval" != $langs->trans("NotAvailable")) { // Keep " on nextval
$htmltooltip .= ''.$langs->trans("NextValue").': ';
if ($nextval) {
if (preg_match('/^Error/', $nextval) || $nextval == 'NotConfigured') {
$nextval = $langs->trans($nextval);
}
$htmltooltip .= $nextval.'<br>';
} else {
$htmltooltip .= $langs->trans($module->error).'<br>';
}
}
print '<td class="center">';
print $form->textwithpicto('', $htmltooltip, 1, 'info');
print '</td>';
print "</tr>\n";
}
}
}
closedir($handle);
}
}
}
print "</table><br>\n";
}
if (!empty($myTmpObjectArray['includedocgeneration'])) {
/*
* Document templates generators
*/
$setupnotempty++;
$type = strtolower($myTmpObjectKey);
print load_fiche_titre($langs->trans("DocumentModules", $myTmpObjectKey), '', '');
// Load array def with activated templates
$def = array();
$sql = "SELECT nom";
$sql .= " FROM ".$db->prefix()."document_model";
$sql .= " WHERE type = '".$db->escape($type)."'";
$sql .= " AND entity = ".$conf->entity;
$resql = $db->query($sql);
if ($resql) {
$i = 0;
$num_rows = $db->num_rows($resql);
while ($i < $num_rows) {
$array = $db->fetch_array($resql);
array_push($def, $array[0]);
$i++;
}
} else {
dol_print_error($db);
}
print '<table class="noborder centpercent">'."\n";
print '<tr class="liste_titre">'."\n";
print '<td>'.$langs->trans("Name").'</td>';
print '<td>'.$langs->trans("Description").'</td>';
print '<td class="center" width="60">'.$langs->trans("Status")."</td>\n";
print '<td class="center" width="60">'.$langs->trans("Default")."</td>\n";
print '<td class="center" width="38">'.$langs->trans("ShortInfo").'</td>';
print '<td class="center" width="38">'.$langs->trans("Preview").'</td>';
print "</tr>\n";
clearstatcache();
foreach ($dirmodels as $reldir) {
foreach (array('', '/doc') as $valdir) {
$realpath = $reldir."core/modules/".$moduledir.$valdir;
$dir = dol_buildpath($realpath);
if (is_dir($dir)) {
$handle = opendir($dir);
if (is_resource($handle)) {
$filelist = array();
while (($file = readdir($handle)) !== false) {
$filelist[] = $file;
}
closedir($handle);
arsort($filelist);
foreach ($filelist as $file) {
if (preg_match('/\.modules\.php$/i', $file) && preg_match('/^(pdf_|doc_)/', $file)) {
if (file_exists($dir.'/'.$file)) {
$name = substr($file, 4, dol_strlen($file) - 16);
$className = substr($file, 0, dol_strlen($file) - 12);
require_once $dir.'/'.$file;
$module = new $className($db);
'@phan-var-force ModelePDFMyObject $module';
$modulequalified = 1;
if ($module->version == 'development' && getDolGlobalInt('MAIN_FEATURES_LEVEL') < 2) {
$modulequalified = 0;
}
if ($module->version == 'experimental' && getDolGlobalInt('MAIN_FEATURES_LEVEL') < 1) {
$modulequalified = 0;
}
if ($modulequalified) {
print '<tr class="oddeven"><td width="100">';
print(empty($module->name) ? $name : $module->name);
print "</td><td>\n";
if (method_exists($module, 'info')) {
print $module->info($langs); // @phan-suppress-current-line PhanUndeclaredMethod
} else {
print $module->description;
}
print '</td>';
// Active
if (in_array($name, $def)) {
print '<td class="center">'."\n";
print '<a href="'.$_SERVER["PHP_SELF"].'?action=del&token='.newToken().'&value='.urlencode($name).'">';
print img_picto($langs->trans("Enabled"), 'switch_on');
print '</a>';
print '</td>';
} else {
print '<td class="center">'."\n";
print '<a href="'.$_SERVER["PHP_SELF"].'?action=set&token='.newToken().'&value='.urlencode($name).'&scan_dir='.urlencode($module->scandir).'&label='.urlencode($module->name).'">'.img_picto($langs->trans("Disabled"), 'switch_off').'</a>';
print "</td>";
}
// Default
print '<td class="center">';
$constforvar = 'STEUER_'.strtoupper($myTmpObjectKey).'_ADDON_PDF';
if (getDolGlobalString($constforvar) == $name) {
//print img_picto($langs->trans("Default"), 'on');
// Even if choice is the default value, we allow to disable it. Replace this with previous line if you need to disable unset
print '<a href="'.$_SERVER["PHP_SELF"].'?action=unsetdoc&token='.newToken().'&object='.urlencode(strtolower($myTmpObjectKey)).'&value='.urlencode($name).'&scan_dir='.urlencode($module->scandir).'&label='.urlencode($module->name).'&amp;type='.urlencode($type).'" alt="'.$langs->trans("Disable").'">'.img_picto($langs->trans("Enabled"), 'on').'</a>';
} else {
print '<a href="'.$_SERVER["PHP_SELF"].'?action=setdoc&token='.newToken().'&object='.urlencode(strtolower($myTmpObjectKey)).'&value='.urlencode($name).'&scan_dir='.urlencode($module->scandir).'&label='.urlencode($module->name).'" alt="'.$langs->trans("Default").'">'.img_picto($langs->trans("Disabled"), 'off').'</a>';
}
print '</td>';
// Info
$htmltooltip = ''.$langs->trans("Name").': '.$module->name;
$htmltooltip .= '<br>'.$langs->trans("Type").': '.($module->type ? $module->type : $langs->trans("Unknown"));
if ($module->type == 'pdf') {
$htmltooltip .= '<br>'.$langs->trans("Width").'/'.$langs->trans("Height").': '.$module->page_largeur.'/'.$module->page_hauteur;
}
$htmltooltip .= '<br>'.$langs->trans("Path").': '.preg_replace('/^\//', '', $realpath).'/'.$file;
$htmltooltip .= '<br><br><u>'.$langs->trans("FeaturesSupported").':</u>';
$htmltooltip .= '<br>'.$langs->trans("Logo").': '.yn($module->option_logo, 1, 1);
$htmltooltip .= '<br>'.$langs->trans("MultiLanguage").': '.yn($module->option_multilang, 1, 1);
print '<td class="center">';
print $form->textwithpicto('', $htmltooltip, 1, 'info');
print '</td>';
// Preview
print '<td class="center">';
if ($module->type == 'pdf') {
$newname = preg_replace('/_'.preg_quote(strtolower($myTmpObjectKey), '/').'/', '', $name);
print '<a href="'.$_SERVER["PHP_SELF"].'?action=specimen&module='.urlencode($newname).'&object='.urlencode($myTmpObjectKey).'">'.img_object($langs->trans("Preview"), 'pdf').'</a>';
} else {
print img_object($langs->transnoentitiesnoconv("PreviewNotAvailable"), 'generic');
}
print '</td>';
print "</tr>\n";
}
}
}
}
}
}
}
}
print '</table>';
}
}
if (empty($setupnotempty)) {
print '<br>'.$langs->trans("NothingToSetup");
}
// Page end
print dol_get_fiche_end();
llxFooter();
$db->close();

417
buchung_card.php Normal file
View file

@ -0,0 +1,417 @@
<?php
/**
* Buchung Eingabe/Bearbeitung
*
* @package steuer
*/
// Load Dolibarr environment
$res = 0;
if (!$res && !empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) {
$res = @include $_SERVER["CONTEXT_DOCUMENT_ROOT"]."/main.inc.php";
}
$tmp = empty($_SERVER['SCRIPT_FILENAME']) ? '' : $_SERVER['SCRIPT_FILENAME'];
$tmp2 = realpath(__FILE__);
$i = strlen($tmp) - 1;
$j = strlen($tmp2) - 1;
while ($i > 0 && $j > 0 && isset($tmp[$i]) && isset($tmp2[$j]) && $tmp[$i] == $tmp2[$j]) {
$i--;
$j--;
}
if (!$res && $i > 0 && file_exists(substr($tmp, 0, ($i + 1))."/main.inc.php")) {
$res = @include substr($tmp, 0, ($i + 1))."/main.inc.php";
}
if (!$res && $i > 0 && file_exists(dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php")) {
$res = @include dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php";
}
if (!$res && file_exists("../main.inc.php")) {
$res = @include "../main.inc.php";
}
if (!$res && file_exists("../../main.inc.php")) {
$res = @include "../../main.inc.php";
}
if (!$res && file_exists("../../../main.inc.php")) {
$res = @include "../../../main.inc.php";
}
if (!$res) {
die("Include of main fails");
}
require_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php';
require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php';
dol_include_once('/steuer/class/buchung.class.php');
$langs->loadLangs(array("steuer@steuer", "bills", "compta"));
$id = GETPOSTINT('id');
$ref = GETPOST('ref', 'alpha');
$action = GETPOST('action', 'aZ09');
$confirm = GETPOST('confirm', 'alpha');
$cancel = GETPOST('cancel', 'aZ09');
$backtopage = GETPOST('backtopage', 'alpha');
// Objekt initialisieren
$object = new SteuerBuchung($db);
// Laden, wenn ID oder Ref
if ($id > 0 || !empty($ref)) {
$object->fetch($id, $ref);
}
/*
* Actions
*/
if ($cancel) {
if (!empty($backtopage)) {
header("Location: ".$backtopage);
exit;
}
$action = '';
}
// Neue Buchung erstellen
if ($action == 'add' && !$cancel) {
$error = 0;
$object->datum = dol_mktime(0, 0, 0, GETPOSTINT('datummonth'), GETPOSTINT('datumday'), GETPOSTINT('datumyear'));
$object->belegnummer = GETPOST('belegnummer', 'alpha');
$object->beschreibung = GETPOST('beschreibung', 'alpha');
$object->fk_konto = GETPOSTINT('fk_konto');
$object->typ = GETPOST('typ', 'alpha');
$object->ust_satz = GETPOSTFLOAT('ust_satz');
$object->zahlungsart = GETPOST('zahlungsart', 'alpha');
$object->fk_soc = GETPOSTINT('fk_soc');
$object->note_private = GETPOST('note_private', 'restricthtml');
// Betrag berechnen
$betrag_eingabe = GETPOST('betrag_eingabe', 'alpha');
$betrag = price2num(GETPOST('betrag', 'alpha'));
if ($betrag_eingabe == 'brutto') {
$object->betrag_brutto = $betrag;
$object->betrag_netto = $betrag / (1 + $object->ust_satz / 100);
$object->betrag_ust = $object->betrag_brutto - $object->betrag_netto;
} else {
$object->betrag_netto = $betrag;
$object->betrag_ust = $betrag * $object->ust_satz / 100;
$object->betrag_brutto = $object->betrag_netto + $object->betrag_ust;
}
// Validierung
if (empty($object->datum)) {
setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesaliases("Date")), null, 'errors');
$error++;
}
if (empty($object->beschreibung)) {
setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesaliases("Description")), null, 'errors');
$error++;
}
if (empty($object->fk_konto)) {
setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesaliases("Account")), null, 'errors');
$error++;
}
if ($betrag <= 0) {
setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesaliases("Amount")), null, 'errors');
$error++;
}
if (!$error) {
$result = $object->create($user);
if ($result > 0) {
setEventMessages($langs->trans("BuchungCreated"), null, 'mesgs');
header("Location: ".dol_buildpath('/steuer/buchung_card.php', 1).'?id='.$result);
exit;
} else {
setEventMessages($object->error, $object->errors, 'errors');
$action = 'create';
}
} else {
$action = 'create';
}
}
// Buchung aktualisieren
if ($action == 'update' && !$cancel) {
$error = 0;
$object->datum = dol_mktime(0, 0, 0, GETPOSTINT('datummonth'), GETPOSTINT('datumday'), GETPOSTINT('datumyear'));
$object->belegnummer = GETPOST('belegnummer', 'alpha');
$object->beschreibung = GETPOST('beschreibung', 'alpha');
$object->fk_konto = GETPOSTINT('fk_konto');
$object->typ = GETPOST('typ', 'alpha');
$object->ust_satz = GETPOSTFLOAT('ust_satz');
$object->zahlungsart = GETPOST('zahlungsart', 'alpha');
$object->fk_soc = GETPOSTINT('fk_soc');
$object->note_private = GETPOST('note_private', 'restricthtml');
// Betrag berechnen
$betrag_eingabe = GETPOST('betrag_eingabe', 'alpha');
$betrag = price2num(GETPOST('betrag', 'alpha'));
if ($betrag_eingabe == 'brutto') {
$object->betrag_brutto = $betrag;
$object->betrag_netto = $betrag / (1 + $object->ust_satz / 100);
$object->betrag_ust = $object->betrag_brutto - $object->betrag_netto;
} else {
$object->betrag_netto = $betrag;
$object->betrag_ust = $betrag * $object->ust_satz / 100;
$object->betrag_brutto = $object->betrag_netto + $object->betrag_ust;
}
if (!$error) {
$result = $object->update($user);
if ($result > 0) {
setEventMessages($langs->trans("BuchungUpdated"), null, 'mesgs');
header("Location: ".dol_buildpath('/steuer/buchung_card.php', 1).'?id='.$object->id);
exit;
} else {
setEventMessages($object->error, $object->errors, 'errors');
$action = 'edit';
}
} else {
$action = 'edit';
}
}
// Löschen bestätigen
if ($action == 'confirm_delete' && $confirm == 'yes') {
$result = $object->delete($user);
if ($result > 0) {
setEventMessages($langs->trans("BuchungDeleted"), null, 'mesgs');
header("Location: ".dol_buildpath('/steuer/buchung_list.php', 1));
exit;
} else {
setEventMessages($object->error, $object->errors, 'errors');
}
}
/*
* View
*/
$form = new Form($db);
$title = $langs->trans("Buchung");
if ($action == 'create') {
$title = $langs->trans("NeueBuchung");
}
llxHeader('', $title, '', '', 0, 0, '', '', '', 'mod-steuer page-buchung-card');
// Konten laden
$konten_einnahmen = SteuerBuchung::getKonten($db, 'einnahme');
$konten_ausgaben = SteuerBuchung::getKonten($db, 'ausgabe');
$konten_alle = SteuerBuchung::getKonten($db);
// USt-Sätze
$ust_saetze = array(
0 => '0% (steuerfrei)',
7 => '7% (ermäßigt)',
19 => '19% (Regelsteuersatz)'
);
// Zahlungsarten
$zahlungsarten = array(
'bank' => $langs->trans("Bank"),
'bar' => $langs->trans("Cash"),
'paypal' => 'PayPal',
'kreditkarte' => $langs->trans("CreditCard"),
'lastschrift' => $langs->trans("DirectDebit"),
'sonstige' => $langs->trans("Other")
);
// Buchungstypen
$typen = array(
'einnahme' => $langs->trans("Einnahme"),
'ausgabe' => $langs->trans("Ausgabe")
);
// Formular: Neue Buchung oder Bearbeiten
if ($action == 'create' || $action == 'edit') {
print load_fiche_titre($action == 'create' ? $langs->trans("NeueBuchung") : $langs->trans("EditBuchung"), '', 'steuer.png@steuer');
print '<form method="POST" action="'.$_SERVER["PHP_SELF"].'">';
print '<input type="hidden" name="token" value="'.newToken().'">';
print '<input type="hidden" name="action" value="'.($action == 'create' ? 'add' : 'update').'">';
if ($action == 'edit') {
print '<input type="hidden" name="id" value="'.$object->id.'">';
}
if ($backtopage) {
print '<input type="hidden" name="backtopage" value="'.$backtopage.'">';
}
print dol_get_fiche_head(array(), '', '', 0, '');
print '<table class="border centpercent tableforfieldcreate">';
// Typ (Einnahme/Ausgabe)
print '<tr><td class="titlefieldcreate fieldrequired">'.$langs->trans("Typ").'</td><td>';
print $form->selectarray('typ', $typen, GETPOSTISSET('typ') ? GETPOST('typ') : $object->typ, 0, 0, 0, '', 0, 0, 0, '', 'minwidth200');
print '</td></tr>';
// Datum
print '<tr><td class="fieldrequired">'.$langs->trans("Date").'</td><td>';
print $form->selectDate(GETPOSTISSET('datumday') ? dol_mktime(0, 0, 0, GETPOSTINT('datummonth'), GETPOSTINT('datumday'), GETPOSTINT('datumyear')) : ($object->datum ? $object->datum : dol_now()), 'datum', 0, 0, 0, '', 1, 1);
print '</td></tr>';
// Belegnummer
print '<tr><td>'.$langs->trans("Belegnummer").'</td><td>';
print '<input type="text" name="belegnummer" class="minwidth200" value="'.dol_escape_htmltag(GETPOSTISSET('belegnummer') ? GETPOST('belegnummer') : $object->belegnummer).'">';
print '</td></tr>';
// Beschreibung
print '<tr><td class="fieldrequired">'.$langs->trans("Description").'</td><td>';
print '<input type="text" name="beschreibung" class="minwidth400" value="'.dol_escape_htmltag(GETPOSTISSET('beschreibung') ? GETPOST('beschreibung') : $object->beschreibung).'">';
print '</td></tr>';
// Konto
print '<tr><td class="fieldrequired">'.$langs->trans("Account").'</td><td>';
print $form->selectarray('fk_konto', $konten_alle, GETPOSTISSET('fk_konto') ? GETPOSTINT('fk_konto') : $object->fk_konto, 1, 0, 0, '', 0, 0, 0, '', 'minwidth300', 1);
print '</td></tr>';
// Betrag
print '<tr><td class="fieldrequired">'.$langs->trans("Amount").'</td><td>';
$betrag_wert = GETPOSTISSET('betrag') ? GETPOST('betrag') : ($object->betrag_brutto > 0 ? $object->betrag_brutto : '');
print '<input type="text" name="betrag" class="minwidth100" value="'.dol_escape_htmltag($betrag_wert).'"> EUR ';
print '<select name="betrag_eingabe" class="flat">';
print '<option value="brutto"'.((GETPOST('betrag_eingabe') == 'brutto' || !GETPOSTISSET('betrag_eingabe')) ? ' selected' : '').'>'.$langs->trans("TTC").' (Brutto)</option>';
print '<option value="netto"'.(GETPOST('betrag_eingabe') == 'netto' ? ' selected' : '').'>'.$langs->trans("HT").' (Netto)</option>';
print '</select>';
print '</td></tr>';
// USt-Satz
print '<tr><td>'.$langs->trans("VATRate").'</td><td>';
print $form->selectarray('ust_satz', $ust_saetze, GETPOSTISSET('ust_satz') ? GETPOST('ust_satz') : ($object->ust_satz !== null ? (int)$object->ust_satz : 19), 0, 0, 0, '', 0, 0, 0, '', 'minwidth200');
print '</td></tr>';
// Zahlungsart
print '<tr><td>'.$langs->trans("PaymentMode").'</td><td>';
print $form->selectarray('zahlungsart', $zahlungsarten, GETPOSTISSET('zahlungsart') ? GETPOST('zahlungsart') : $object->zahlungsart, 1, 0, 0, '', 0, 0, 0, '', 'minwidth200');
print '</td></tr>';
// Kunde/Lieferant
print '<tr><td>'.$langs->trans("ThirdParty").'</td><td>';
print $form->select_company(GETPOSTISSET('fk_soc') ? GETPOSTINT('fk_soc') : $object->fk_soc, 'fk_soc', '', 1, 0, 0, array(), 0, 'minwidth300');
print '</td></tr>';
// Notiz
print '<tr><td>'.$langs->trans("Note").'</td><td>';
print '<textarea name="note_private" class="minwidth400" rows="3">'.dol_escape_htmltag(GETPOSTISSET('note_private') ? GETPOST('note_private', 'restricthtml') : $object->note_private).'</textarea>';
print '</td></tr>';
print '</table>';
print dol_get_fiche_end();
print '<div class="center">';
print '<input type="submit" class="button button-save" name="save" value="'.$langs->trans("Save").'">';
print ' &nbsp; ';
print '<input type="submit" class="button button-cancel" name="cancel" value="'.$langs->trans("Cancel").'">';
print '</div>';
print '</form>';
} elseif ($object->id > 0) {
// Anzeige der Buchung
// Löschen bestätigen
if ($action == 'delete') {
print $form->formconfirm(
$_SERVER["PHP_SELF"].'?id='.$object->id,
$langs->trans("DeleteBuchung"),
$langs->trans("ConfirmDeleteBuchung"),
'confirm_delete',
'',
0,
1
);
}
print load_fiche_titre($langs->trans("Buchung").' '.$object->ref, '', 'steuer.png@steuer');
print dol_get_fiche_head(array(), '', '', 0, '');
print '<table class="border centpercent tableforfield">';
// Referenz
print '<tr><td class="titlefield">'.$langs->trans("Ref").'</td>';
print '<td>'.$object->ref.'</td></tr>';
// Typ
print '<tr><td>'.$langs->trans("Typ").'</td>';
print '<td>'.$typen[$object->typ].'</td></tr>';
// Datum
print '<tr><td>'.$langs->trans("Date").'</td>';
print '<td>'.dol_print_date($object->datum, 'day').'</td></tr>';
// Belegnummer
print '<tr><td>'.$langs->trans("Belegnummer").'</td>';
print '<td>'.$object->belegnummer.'</td></tr>';
// Beschreibung
print '<tr><td>'.$langs->trans("Description").'</td>';
print '<td>'.$object->beschreibung.'</td></tr>';
// Konto
print '<tr><td>'.$langs->trans("Account").'</td>';
print '<td>'.$object->konto_nummer.' - '.$object->konto_bezeichnung.'</td></tr>';
// Beträge
print '<tr><td>'.$langs->trans("AmountHT").' (Netto)</td>';
print '<td class="amount">'.price($object->betrag_netto, 0, $langs, 1, 2, 2, 'EUR').'</td></tr>';
print '<tr><td>'.$langs->trans("VAT").' ('.(int)$object->ust_satz.'%)</td>';
print '<td class="amount">'.price($object->betrag_ust, 0, $langs, 1, 2, 2, 'EUR').'</td></tr>';
print '<tr><td>'.$langs->trans("AmountTTC").' (Brutto)</td>';
print '<td class="amount"><strong>'.price($object->betrag_brutto, 0, $langs, 1, 2, 2, 'EUR').'</strong></td></tr>';
// Zahlungsart
if ($object->zahlungsart) {
print '<tr><td>'.$langs->trans("PaymentMode").'</td>';
print '<td>'.(isset($zahlungsarten[$object->zahlungsart]) ? $zahlungsarten[$object->zahlungsart] : $object->zahlungsart).'</td></tr>';
}
// Kunde/Lieferant
if ($object->fk_soc > 0) {
$soc = new Societe($db);
$soc->fetch($object->fk_soc);
print '<tr><td>'.$langs->trans("ThirdParty").'</td>';
print '<td>'.$soc->getNomUrl(1).'</td></tr>';
}
// Notiz
if ($object->note_private) {
print '<tr><td>'.$langs->trans("Note").'</td>';
print '<td>'.nl2br($object->note_private).'</td></tr>';
}
// Erstellt am/von
print '<tr><td>'.$langs->trans("DateCreation").'</td>';
print '<td>'.dol_print_date($object->date_creation, 'dayhour').'</td></tr>';
print '</table>';
print dol_get_fiche_end();
// Aktionen
print '<div class="tabsAction">';
print '<a class="butAction" href="'.dol_buildpath('/steuer/buchung_list.php', 1).'"><i class="fa fa-arrow-left paddingright"></i>'.$langs->trans("Back").'</a>';
print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=edit">'.$langs->trans("Modify").'</a>';
print '<a class="butActionDelete" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=delete&token='.newToken().'">'.$langs->trans("Delete").'</a>';
print '</div>';
} else {
// Keine Buchung gefunden
print $langs->trans("RecordNotFound");
print '<br><br>';
print '<div class="tabsAction">';
print '<a class="butAction" href="'.dol_buildpath('/steuer/buchung_list.php', 1).'"><i class="fa fa-arrow-left paddingright"></i>'.$langs->trans("Back").'</a>';
print '</div>';
}
llxFooter();
$db->close();

345
buchung_list.php Normal file
View file

@ -0,0 +1,345 @@
<?php
/**
* Buchungsliste
*
* @package steuer
*/
// Load Dolibarr environment
$res = 0;
if (!$res && !empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) {
$res = @include $_SERVER["CONTEXT_DOCUMENT_ROOT"]."/main.inc.php";
}
$tmp = empty($_SERVER['SCRIPT_FILENAME']) ? '' : $_SERVER['SCRIPT_FILENAME'];
$tmp2 = realpath(__FILE__);
$i = strlen($tmp) - 1;
$j = strlen($tmp2) - 1;
while ($i > 0 && $j > 0 && isset($tmp[$i]) && isset($tmp2[$j]) && $tmp[$i] == $tmp2[$j]) {
$i--;
$j--;
}
if (!$res && $i > 0 && file_exists(substr($tmp, 0, ($i + 1))."/main.inc.php")) {
$res = @include substr($tmp, 0, ($i + 1))."/main.inc.php";
}
if (!$res && $i > 0 && file_exists(dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php")) {
$res = @include dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php";
}
if (!$res && file_exists("../main.inc.php")) {
$res = @include "../main.inc.php";
}
if (!$res && file_exists("../../main.inc.php")) {
$res = @include "../../main.inc.php";
}
if (!$res && file_exists("../../../main.inc.php")) {
$res = @include "../../../main.inc.php";
}
if (!$res) {
die("Include of main fails");
}
require_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
dol_include_once('/steuer/class/buchung.class.php');
dol_include_once('/steuer/class/euer.class.php');
$langs->loadLangs(array("steuer@steuer", "bills", "compta"));
$action = GETPOST('action', 'aZ09');
$massaction = GETPOST('massaction', 'alpha');
$confirm = GETPOST('confirm', 'alpha');
$toselect = GETPOST('toselect', 'array');
// Filter
$jahr = GETPOSTINT('jahr');
if (empty($jahr)) {
$jahr = date('Y');
}
$monat = GETPOSTINT('monat');
$typ = GETPOST('search_typ', 'alpha');
$search_ref = GETPOST('search_ref', 'alpha');
$search_beschreibung = GETPOST('search_beschreibung', 'alpha');
// Sortierung
$sortfield = GETPOST('sortfield', 'aZ09comma');
$sortorder = GETPOST('sortorder', 'aZ09comma');
if (empty($sortfield)) {
$sortfield = 'datum';
}
if (empty($sortorder)) {
$sortorder = 'DESC';
}
// Pagination
$limit = GETPOSTINT('limit') ? GETPOSTINT('limit') : $conf->liste_limit;
$page = GETPOSTISSET('pageplusone') ? (GETPOSTINT('pageplusone') - 1) : GETPOSTINT('page');
if (empty($page) || $page < 0) {
$page = 0;
}
$offset = $limit * $page;
/*
* View
*/
$form = new Form($db);
$euer = new EUeR($db);
llxHeader('', $langs->trans("Buchungen"), '', '', 0, 0, '', '', '', 'mod-steuer page-buchung-list');
print load_fiche_titre($langs->trans("Buchungen"), '', 'steuer.png@steuer');
// Datumsgrenzen für SQL
if ($monat > 0) {
$datum_von = $jahr.'-'.sprintf('%02d', $monat).'-01';
$datum_bis = date('Y-m-t', strtotime($datum_von));
} else {
$datum_von = $jahr.'-01-01';
$datum_bis = $jahr.'-12-31';
}
// SQL für manuelle Buchungen
$sql = "SELECT b.rowid, b.ref, b.datum, b.belegnummer, b.beschreibung,";
$sql .= " b.betrag_netto, b.betrag_ust, b.betrag_brutto, b.typ,";
$sql .= " k.kontonummer, k.bezeichnung as konto_bezeichnung,";
$sql .= " 'manuell' as quelle";
$sql .= " FROM ".MAIN_DB_PREFIX."steuer_buchung as b";
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."steuer_konto as k ON b.fk_konto = k.rowid";
$sql .= " WHERE b.entity = ".((int) $conf->entity);
$sql .= " AND b.status = 1";
$sql .= " AND b.datum BETWEEN '".$db->escape($datum_von)."' AND '".$db->escape($datum_bis)."'";
if ($typ) {
$sql .= " AND b.typ = '".$db->escape($typ)."'";
}
if ($search_ref) {
$sql .= " AND b.ref LIKE '%".$db->escape($search_ref)."%'";
}
if ($search_beschreibung) {
$sql .= " AND b.beschreibung LIKE '%".$db->escape($search_beschreibung)."%'";
}
// UNION mit Rechnungen (Einnahmen)
$sql .= " UNION ALL ";
$sql .= "SELECT f.rowid, f.ref, COALESCE(pf.datep, f.datef) as datum, f.ref as belegnummer,";
$sql .= " CONCAT('Rechnung: ', s.nom) as beschreibung,";
$sql .= " f.total_ht as betrag_netto, f.total_tva as betrag_ust, f.total_ttc as betrag_brutto,";
$sql .= " 'einnahme' as typ, '' as kontonummer, '' as konto_bezeichnung,";
$sql .= " 'facture' as quelle";
$sql .= " FROM ".MAIN_DB_PREFIX."facture as f";
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON f.fk_soc = s.rowid";
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."paiement_facture as pf ON pf.fk_facture = f.rowid";
$sql .= " WHERE f.entity = ".((int) $conf->entity);
$sql .= " AND f.fk_statut IN (2, 3)";
$sql .= " AND COALESCE(pf.datep, f.datef) BETWEEN '".$db->escape($datum_von)."' AND '".$db->escape($datum_bis)."'";
if ($typ == 'ausgabe') {
$sql .= " AND 1=0"; // Keine Einnahmen bei Ausgaben-Filter
}
if ($search_beschreibung) {
$sql .= " AND s.nom LIKE '%".$db->escape($search_beschreibung)."%'";
}
$sql .= " GROUP BY f.rowid";
// UNION mit Lieferantenrechnungen (Ausgaben)
$sql .= " UNION ALL ";
$sql .= "SELECT f.rowid, f.ref, COALESCE(pf.datep, f.datef) as datum, COALESCE(f.ref_supplier, f.ref) as belegnummer,";
$sql .= " CONCAT('Lieferant: ', s.nom) as beschreibung,";
$sql .= " f.total_ht as betrag_netto, f.total_tva as betrag_ust, f.total_ttc as betrag_brutto,";
$sql .= " 'ausgabe' as typ, '' as kontonummer, '' as konto_bezeichnung,";
$sql .= " 'facture_fourn' as quelle";
$sql .= " FROM ".MAIN_DB_PREFIX."facture_fourn as f";
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON f.fk_soc = s.rowid";
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."paiementfourn_facturefourn as pf ON pf.fk_facturefourn = f.rowid";
$sql .= " WHERE f.entity = ".((int) $conf->entity);
$sql .= " AND f.fk_statut IN (2)";
$sql .= " AND COALESCE(pf.datep, f.datef) BETWEEN '".$db->escape($datum_von)."' AND '".$db->escape($datum_bis)."'";
if ($typ == 'einnahme') {
$sql .= " AND 1=0"; // Keine Ausgaben bei Einnahmen-Filter
}
if ($search_beschreibung) {
$sql .= " AND s.nom LIKE '%".$db->escape($search_beschreibung)."%'";
}
$sql .= " GROUP BY f.rowid";
// Sortierung und Limit
$sql_count = "SELECT COUNT(*) as total FROM (".$sql.") as combined";
$sql .= " ORDER BY ".$sortfield." ".$sortorder;
$sql .= " LIMIT ".$limit." OFFSET ".$offset;
// Gesamtzahl ermitteln
$resql_count = $db->query($sql_count);
$nbtotalofrecords = 0;
if ($resql_count) {
$obj = $db->fetch_object($resql_count);
$nbtotalofrecords = $obj->total;
}
// Filter-Formular
print '<form method="POST" action="'.$_SERVER["PHP_SELF"].'" name="searchform">';
print '<input type="hidden" name="token" value="'.newToken().'">';
print '<input type="hidden" name="sortfield" value="'.$sortfield.'">';
print '<input type="hidden" name="sortorder" value="'.$sortorder.'">';
print '<div class="div-table-responsive-no-min">';
print '<table class="noborder centpercent">';
print '<tr class="liste_titre">';
print '<td>'.$langs->trans("Year").'</td>';
print '<td>'.$langs->trans("Month").'</td>';
print '<td>'.$langs->trans("Typ").'</td>';
print '<td></td>';
print '</tr>';
print '<tr class="oddeven">';
print '<td>';
print '<select name="jahr" class="flat minwidth100">';
for ($y = date('Y'); $y >= date('Y') - 5; $y--) {
print '<option value="'.$y.'"'.($y == $jahr ? ' selected' : '').'>'.$y.'</option>';
}
print '</select>';
print '</td>';
print '<td>';
print '<select name="monat" class="flat minwidth100">';
print '<option value="0"'.($monat == 0 ? ' selected' : '').'>'.$langs->trans("WholeYear").'</option>';
for ($m = 1; $m <= 12; $m++) {
print '<option value="'.$m.'"'.($m == $monat ? ' selected' : '').'>'.dol_print_date(mktime(0, 0, 0, $m, 1, 2000), '%B').'</option>';
}
print '</select>';
print '</td>';
print '<td>';
print '<select name="search_typ" class="flat minwidth100">';
print '<option value="">'.$langs->trans("All").'</option>';
print '<option value="einnahme"'.($typ == 'einnahme' ? ' selected' : '').'>'.$langs->trans("Einnahmen").'</option>';
print '<option value="ausgabe"'.($typ == 'ausgabe' ? ' selected' : '').'>'.$langs->trans("Ausgaben").'</option>';
print '</select>';
print '</td>';
print '<td>';
print '<input type="submit" class="button" value="'.$langs->trans("Refresh").'">';
print ' <a href="'.dol_buildpath('/steuer/buchung_card.php', 1).'?action=create" class="butAction">'.$langs->trans("NeueBuchung").'</a>';
print '</td>';
print '</tr>';
print '</table>';
print '</div>';
print '<br>';
// Haupttabelle
print '<table class="noborder centpercent">';
print '<tr class="liste_titre">';
print_liste_field_titre("Ref", $_SERVER["PHP_SELF"], "ref", "", $param, "", $sortfield, $sortorder);
print_liste_field_titre("Date", $_SERVER["PHP_SELF"], "datum", "", $param, "", $sortfield, $sortorder);
print_liste_field_titre("Belegnummer", $_SERVER["PHP_SELF"], "belegnummer", "", $param, "", $sortfield, $sortorder);
print_liste_field_titre("Description", $_SERVER["PHP_SELF"], "beschreibung", "", $param, "", $sortfield, $sortorder);
print_liste_field_titre("Account", $_SERVER["PHP_SELF"], "kontonummer", "", $param, "", $sortfield, $sortorder);
print_liste_field_titre("Typ", $_SERVER["PHP_SELF"], "typ", "", $param, "", $sortfield, $sortorder);
print_liste_field_titre("AmountHT", $_SERVER["PHP_SELF"], "betrag_netto", "", $param, 'class="right"', $sortfield, $sortorder);
print_liste_field_titre("VAT", $_SERVER["PHP_SELF"], "betrag_ust", "", $param, 'class="right"', $sortfield, $sortorder);
print_liste_field_titre("AmountTTC", $_SERVER["PHP_SELF"], "betrag_brutto", "", $param, 'class="right"', $sortfield, $sortorder);
print '</tr>';
$resql = $db->query($sql);
if ($resql) {
$num = $db->num_rows($resql);
$total_einnahmen = 0;
$total_ausgaben = 0;
while ($obj = $db->fetch_object($resql)) {
print '<tr class="oddeven">';
// Ref mit Link
print '<td class="nowraponall">';
if ($obj->quelle == 'manuell') {
print '<a href="'.dol_buildpath('/steuer/buchung_card.php', 1).'?id='.$obj->rowid.'">'.$obj->ref.'</a>';
} elseif ($obj->quelle == 'facture') {
print '<a href="'.DOL_URL_ROOT.'/compta/facture/card.php?id='.$obj->rowid.'">'.$obj->ref.'</a>';
print ' <span class="badge badge-info">Rechnung</span>';
} elseif ($obj->quelle == 'facture_fourn') {
print '<a href="'.DOL_URL_ROOT.'/fourn/facture/card.php?id='.$obj->rowid.'">'.$obj->ref.'</a>';
print ' <span class="badge badge-warning">Lieferant</span>';
}
print '</td>';
// Datum
print '<td>'.dol_print_date($db->jdate($obj->datum), 'day').'</td>';
// Belegnummer
print '<td>'.$obj->belegnummer.'</td>';
// Beschreibung
print '<td>'.dol_trunc($obj->beschreibung, 50).'</td>';
// Konto
print '<td>'.$obj->kontonummer.($obj->kontonummer ? ' - ' : '').$obj->konto_bezeichnung.'</td>';
// Typ
print '<td>';
if ($obj->typ == 'einnahme') {
print '<span class="badge badge-status4">'.$langs->trans("Einnahme").'</span>';
} else {
print '<span class="badge badge-status1">'.$langs->trans("Ausgabe").'</span>';
}
print '</td>';
// Beträge
print '<td class="right nowraponall">'.price($obj->betrag_netto, 0, $langs, 1, 2, 2).'</td>';
print '<td class="right nowraponall">'.price($obj->betrag_ust, 0, $langs, 1, 2, 2).'</td>';
print '<td class="right nowraponall amount">'.price($obj->betrag_brutto, 0, $langs, 1, 2, 2).'</td>';
print '</tr>';
// Summen
if ($obj->typ == 'einnahme') {
$total_einnahmen += $obj->betrag_netto;
} else {
$total_ausgaben += $obj->betrag_netto;
}
}
// Summenzeile
print '<tr class="liste_total">';
print '<td colspan="6"><strong>'.$langs->trans("Total").'</strong></td>';
print '<td class="right nowraponall"><strong>'.price($total_einnahmen - $total_ausgaben, 0, $langs, 1, 2, 2).'</strong></td>';
print '<td></td>';
print '<td></td>';
print '</tr>';
print '</table>';
// Pagination
print_barre_liste('', $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, '', $num, $nbtotalofrecords, '', 0, '', '', $limit, 0, 0, 1);
} else {
dol_print_error($db);
}
print '</form>';
// Zusammenfassung
print '<br>';
print '<div class="div-table-responsive-no-min">';
print '<table class="noborder centpercent">';
print '<tr class="liste_titre">';
print '<th colspan="2">'.$langs->trans("Summary").' '.$jahr.'</th>';
print '</tr>';
print '<tr class="oddeven">';
print '<td>'.$langs->trans("TotalEinnahmen").'</td>';
print '<td class="right amount">'.price($total_einnahmen, 0, $langs, 1, 2, 2, 'EUR').'</td>';
print '</tr>';
print '<tr class="oddeven">';
print '<td>'.$langs->trans("TotalAusgaben").'</td>';
print '<td class="right amount">'.price($total_ausgaben, 0, $langs, 1, 2, 2, 'EUR').'</td>';
print '</tr>';
print '<tr class="liste_total">';
$gewinn = $total_einnahmen - $total_ausgaben;
$color = $gewinn >= 0 ? 'amountpaymentcomplete' : 'amountremaintopay';
print '<td><strong>'.($gewinn >= 0 ? $langs->trans("Gewinn") : $langs->trans("Verlust")).'</strong></td>';
print '<td class="right amount '.$color.'"><strong>'.price($gewinn, 0, $langs, 1, 2, 2, 'EUR').'</strong></td>';
print '</tr>';
print '</table>';
print '</div>';
// Zurück-Button
print '<br>';
print '<div class="tabsAction">';
print '<a class="butAction" href="'.dol_buildpath('/steuer/steuerindex.php', 1).'"><i class="fa fa-arrow-left paddingright"></i>'.$langs->trans("Back").'</a>';
print '</div>';
llxFooter();
$db->close();

316
build/buildzip.php Executable file
View file

@ -0,0 +1,316 @@
#!/usr/bin/env php -d memory_limit=256M
<?php
/**
* buildzip.php
*
* Copyright (c) 2023-2025 Eric Seigne <eric.seigne@cap-rel.fr>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
/*
The goal of that php CLI script is to make zip package of your module
as an alternative to web "build zip" or "perl script makepack"
*/
// ============================================= configuration
/**
* list of files & dirs of your module
*
* @var string[]
*/
$listOfModuleContent = [
'admin',
'ajax',
'backport',
'class',
'css',
'COPYING',
'core',
'img',
'js',
'langs',
'lib',
'sql',
'tpl',
'*.md',
'*.json',
'*.php',
'modulebuilder.txt',
];
/**
* if you want to exclude some files from your zip
*
* @var string[]
*/
$exclude_list = [
'/^.git$/',
'/.*js.map/',
'/DEV.md/'
];
// ============================================= end of configuration
/**
* auto detect module name and version from file name
*
* @return (string|string)[] module name and module version
*/
function detectModule()
{
$name = $version = "";
$tab = glob("core/modules/mod*.class.php");
if (count($tab) == 0) {
echo "[fail] Error on auto detect data : there is no mod*.class.php file into core/modules dir\n";
exit(-1);
}
if (count($tab) == 1) {
$file = $tab[0];
$pattern = "/.*mod(?<mod>.*)\.class\.php/";
if (preg_match_all($pattern, $file, $matches)) {
$name = strtolower(reset($matches['mod']));
}
echo "extract data from $file\n";
if (!file_exists($file) || $name == "") {
echo "[fail] Error on auto detect data\n";
exit(-2);
}
} else {
echo "[fail] Error there is more than one mod*.class.php file into core/modules dir\n";
exit(-3);
}
//extract version from file
$contents = file_get_contents($file);
$pattern = "/^.*this->version\s*=\s*'(?<version>.*)'\s*;.*\$/m";
// search, and store all matching occurrences in $matches
if (preg_match_all($pattern, $contents, $matches)) {
$version = reset($matches['version']);
}
if (version_compare($version, '0.0.1', '>=') != 1) {
echo "[fail] Error auto extract version fail\n";
exit(-4);
}
echo "module name = $name, version = $version\n";
return [(string) $name, (string) $version];
}
/**
* delete recursively a directory
*
* @param string $dir dir path to delete
*
* @return bool true on success or false on failure.
*/
function delTree($dir)
{
$files = array_diff(scandir($dir), array('.', '..'));
foreach ($files as $file) {
(is_dir("$dir/$file")) ? delTree("$dir/$file") : secureUnlink("$dir/$file");
}
return rmdir($dir);
}
/**
* do a secure delete file/dir with double check
* (don't trust unlink return)
*
* @param string $path full path to delete
*
* @return bool true on success ($path does not exists at the end of process), else exit
*/
function secureUnlink($path)
{
if (file_exists($path)) {
if (unlink($path)) {
//then check if really deleted
clearstatcache();
if (file_exists($path)) { // @phpstan-ignore-line
echo "[fail] unlink of $path fail !\n";
exit(-5);
}
} else {
echo "[fail] unlink of $path fail !\n";
exit(-6);
}
}
return true;
}
/**
* create a directory and check if dir exists
*
* @param string $path path to make
*
* @return bool true on success ($path exists at the end of process), else exit
*/
function mkdirAndCheck($path)
{
if (mkdir($path)) {
clearstatcache();
if (is_dir($path)) {
return true;
}
}
echo "[fail] Error on $path (mkdir)\n";
exit(7);
}
/**
* check if that filename is concerned by exclude filter
*
* @param string $filename file name to check
*
* @return bool true if file is in excluded list
*/
function is_excluded($filename)
{
global $exclude_list;
$count = 0;
$notused = preg_filter($exclude_list, '1', $filename, -1, $count);
if ($count > 0) {
echo " - exclude $filename\n";
return true;
}
return false;
}
/**
* recursive copy files & dirs
*
* @param string $src source dir
* @param string $dst target dir
*
* @return bool true on success or false on failure.
*/
function rcopy($src, $dst)
{
if (is_dir($src)) {
// Make the destination directory if not exist
mkdirAndCheck($dst);
// open the source directory
$dir = opendir($src);
// Loop through the files in source directory
while ($file = readdir($dir)) {
if (($file != '.') && ($file != '..')) {
if (is_dir($src . '/' . $file)) {
// Recursively calling custom copy function
// for sub directory
if (!rcopy($src . '/' . $file, $dst . '/' . $file)) {
return false;
}
} else {
if (!is_excluded($file)) {
if (!copy($src . '/' . $file, $dst . '/' . $file)) {
return false;
}
}
}
}
}
closedir($dir);
} elseif (is_file($src)) {
if (!is_excluded($src)) {
if (!copy($src, $dst)) {
return false;
}
}
}
return true;
}
/**
* build a zip file with only php code and no external depends
* on "zip" exec for example
*
* @param string $folder folder to use as zip root
* @param ZipArchive $zip zip object (ZipArchive)
* @param string $root relative root path into the zip
*
* @return bool true on success or false on failure.
*/
function zipDir($folder, &$zip, $root = "")
{
foreach (new \DirectoryIterator($folder) as $f) {
if ($f->isDot()) {
continue;
} //skip . ..
$src = $folder . '/' . $f;
$dst = substr($f->getPathname(), strlen($root));
if ($f->isDir()) {
if ($zip->addEmptyDir($dst)) {
if (zipDir($src, $zip, $root)) {
continue;
} else {
return false;
}
} else {
return false;
}
}
if ($f->isFile()) {
if (! $zip->addFile($src, $dst)) {
return false;
}
}
}
return true;
}
/**
* main part of script
*/
list($mod, $version) = detectModule();
$outzip = sys_get_temp_dir() . "/module_" . $mod . "-" . $version . ".zip";
if (file_exists($outzip)) {
secureUnlink($outzip);
}
//copy all sources into system temp directory
$tmpdir = tempnam(sys_get_temp_dir(), $mod . "-module");
secureUnlink($tmpdir);
mkdirAndCheck($tmpdir);
$dst = $tmpdir . "/" . $mod;
mkdirAndCheck($dst);
foreach ($listOfModuleContent as $moduleContent) {
foreach (glob($moduleContent) as $entry) {
if (!rcopy($entry, $dst . '/' . $entry)) {
echo "[fail] Error on copy " . $entry . " to " . $dst . "/" . $entry . "\n";
echo "Please take time to analyze the problem and fix the bug\n";
exit(-8);
}
}
}
$z = new ZipArchive();
$z->open($outzip, ZIPARCHIVE::CREATE);
zipDir($tmpdir, $z, $tmpdir . '/');
$z->close();
delTree($tmpdir);
if (file_exists($outzip)) {
echo "[success] module archive is ready : $outzip ...\n";
} else {
echo "[fail] build zip error\n";
exit(-9);
}

11
build/makepack-steuer.conf Executable file
View file

@ -0,0 +1,11 @@
# Your module name here
#
# Goal: Goal of module
# Version: <version>
# Author: Copyright <year> - <name of author>
# License: GPLv3
# Install: Just unpack content of module package in Dolibarr directory.
# Setup: Go on Dolibarr setup - modules to enable module.
#
# Files in module
mymodule/

355
class/buchung.class.php Normal file
View file

@ -0,0 +1,355 @@
<?php
/**
* Buchung Klasse für manuelle EÜR-Buchungen
*
* @package steuer
* @subpackage class
*/
require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
/**
* Klasse zur Verwaltung von manuellen EÜR-Buchungen
*/
class SteuerBuchung extends CommonObject
{
public $element = 'steuer_buchung';
public $table_element = 'steuer_buchung';
public $picto = 'bill';
public $id;
public $ref;
public $datum;
public $belegnummer;
public $beschreibung;
public $fk_konto;
public $betrag_netto;
public $betrag_ust;
public $betrag_brutto;
public $ust_satz;
public $typ; // 'einnahme' oder 'ausgabe'
public $zahlungsart;
public $fk_soc;
public $fk_facture;
public $fk_facture_fourn;
public $note_private;
public $date_creation;
public $tms;
public $fk_user_creat;
public $fk_user_modif;
public $status;
public $entity;
// Verknüpfte Objekte
public $konto_bezeichnung;
public $konto_nummer;
/**
* Constructor
*
* @param DoliDB $db Database handler
*/
public function __construct($db)
{
global $conf;
$this->db = $db;
$this->entity = $conf->entity;
}
/**
* Erstellt eine neue Buchung
*
* @param User $user Benutzer
* @param int $notrigger Keine Trigger ausführen
* @return int >0 bei Erfolg, <0 bei Fehler
*/
public function create($user, $notrigger = 0)
{
global $conf;
$error = 0;
$now = dol_now();
// Standardwerte
if (empty($this->status)) {
$this->status = 1;
}
$this->entity = $conf->entity;
// Referenz generieren
if (empty($this->ref)) {
$this->ref = $this->getNextRef();
}
// Brutto berechnen falls nicht gesetzt
if (empty($this->betrag_brutto)) {
$this->betrag_brutto = $this->betrag_netto + $this->betrag_ust;
}
$this->db->begin();
$sql = "INSERT INTO ".MAIN_DB_PREFIX."steuer_buchung (";
$sql .= "ref, datum, belegnummer, beschreibung, fk_konto,";
$sql .= " betrag_netto, betrag_ust, betrag_brutto, ust_satz,";
$sql .= " typ, zahlungsart, fk_soc, fk_facture, fk_facture_fourn,";
$sql .= " note_private, date_creation, fk_user_creat, status, entity";
$sql .= ") VALUES (";
$sql .= "'".$this->db->escape($this->ref)."',";
$sql .= "'".$this->db->escape($this->datum)."',";
$sql .= ($this->belegnummer ? "'".$this->db->escape($this->belegnummer)."'" : "NULL").",";
$sql .= "'".$this->db->escape($this->beschreibung)."',";
$sql .= ((int) $this->fk_konto).",";
$sql .= ((float) $this->betrag_netto).",";
$sql .= ((float) $this->betrag_ust).",";
$sql .= ((float) $this->betrag_brutto).",";
$sql .= ((float) $this->ust_satz).",";
$sql .= "'".$this->db->escape($this->typ)."',";
$sql .= ($this->zahlungsart ? "'".$this->db->escape($this->zahlungsart)."'" : "NULL").",";
$sql .= ($this->fk_soc > 0 ? ((int) $this->fk_soc) : "NULL").",";
$sql .= ($this->fk_facture > 0 ? ((int) $this->fk_facture) : "NULL").",";
$sql .= ($this->fk_facture_fourn > 0 ? ((int) $this->fk_facture_fourn) : "NULL").",";
$sql .= ($this->note_private ? "'".$this->db->escape($this->note_private)."'" : "NULL").",";
$sql .= "'".$this->db->idate($now)."',";
$sql .= ((int) $user->id).",";
$sql .= ((int) $this->status).",";
$sql .= ((int) $this->entity);
$sql .= ")";
$resql = $this->db->query($sql);
if (!$resql) {
$error++;
$this->errors[] = "Error ".$this->db->lasterror();
}
if (!$error) {
$this->id = $this->db->last_insert_id(MAIN_DB_PREFIX."steuer_buchung");
}
if (!$error) {
$this->db->commit();
return $this->id;
} else {
$this->db->rollback();
return -1;
}
}
/**
* Aktualisiert eine Buchung
*
* @param User $user Benutzer
* @param int $notrigger Keine Trigger ausführen
* @return int >0 bei Erfolg, <0 bei Fehler
*/
public function update($user, $notrigger = 0)
{
$error = 0;
// Brutto berechnen
$this->betrag_brutto = $this->betrag_netto + $this->betrag_ust;
$this->db->begin();
$sql = "UPDATE ".MAIN_DB_PREFIX."steuer_buchung SET";
$sql .= " datum = '".$this->db->escape($this->datum)."',";
$sql .= " belegnummer = ".($this->belegnummer ? "'".$this->db->escape($this->belegnummer)."'" : "NULL").",";
$sql .= " beschreibung = '".$this->db->escape($this->beschreibung)."',";
$sql .= " fk_konto = ".((int) $this->fk_konto).",";
$sql .= " betrag_netto = ".((float) $this->betrag_netto).",";
$sql .= " betrag_ust = ".((float) $this->betrag_ust).",";
$sql .= " betrag_brutto = ".((float) $this->betrag_brutto).",";
$sql .= " ust_satz = ".((float) $this->ust_satz).",";
$sql .= " typ = '".$this->db->escape($this->typ)."',";
$sql .= " zahlungsart = ".($this->zahlungsart ? "'".$this->db->escape($this->zahlungsart)."'" : "NULL").",";
$sql .= " fk_soc = ".($this->fk_soc > 0 ? ((int) $this->fk_soc) : "NULL").",";
$sql .= " note_private = ".($this->note_private ? "'".$this->db->escape($this->note_private)."'" : "NULL").",";
$sql .= " fk_user_modif = ".((int) $user->id);
$sql .= " WHERE rowid = ".((int) $this->id);
$resql = $this->db->query($sql);
if (!$resql) {
$error++;
$this->errors[] = "Error ".$this->db->lasterror();
}
if (!$error) {
$this->db->commit();
return 1;
} else {
$this->db->rollback();
return -1;
}
}
/**
* Lädt eine Buchung
*
* @param int $id ID der Buchung
* @param string $ref Referenz der Buchung
* @return int >0 bei Erfolg, <0 bei Fehler
*/
public function fetch($id, $ref = '')
{
global $conf;
$sql = "SELECT b.*, k.kontonummer, k.bezeichnung as konto_bezeichnung";
$sql .= " FROM ".MAIN_DB_PREFIX."steuer_buchung as b";
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."steuer_konto as k ON b.fk_konto = k.rowid";
$sql .= " WHERE b.entity = ".((int) $conf->entity);
if ($id > 0) {
$sql .= " AND b.rowid = ".((int) $id);
} elseif ($ref) {
$sql .= " AND b.ref = '".$this->db->escape($ref)."'";
}
$resql = $this->db->query($sql);
if ($resql) {
if ($this->db->num_rows($resql)) {
$obj = $this->db->fetch_object($resql);
$this->id = $obj->rowid;
$this->ref = $obj->ref;
$this->datum = $this->db->jdate($obj->datum);
$this->belegnummer = $obj->belegnummer;
$this->beschreibung = $obj->beschreibung;
$this->fk_konto = $obj->fk_konto;
$this->betrag_netto = $obj->betrag_netto;
$this->betrag_ust = $obj->betrag_ust;
$this->betrag_brutto = $obj->betrag_brutto;
$this->ust_satz = $obj->ust_satz;
$this->typ = $obj->typ;
$this->zahlungsart = $obj->zahlungsart;
$this->fk_soc = $obj->fk_soc;
$this->fk_facture = $obj->fk_facture;
$this->fk_facture_fourn = $obj->fk_facture_fourn;
$this->note_private = $obj->note_private;
$this->date_creation = $this->db->jdate($obj->date_creation);
$this->tms = $obj->tms;
$this->fk_user_creat = $obj->fk_user_creat;
$this->fk_user_modif = $obj->fk_user_modif;
$this->status = $obj->status;
$this->entity = $obj->entity;
$this->konto_bezeichnung = $obj->konto_bezeichnung;
$this->konto_nummer = $obj->kontonummer;
return 1;
}
return 0;
} else {
$this->error = $this->db->lasterror();
return -1;
}
}
/**
* Löscht eine Buchung
*
* @param User $user Benutzer
* @param int $notrigger Keine Trigger ausführen
* @return int >0 bei Erfolg, <0 bei Fehler
*/
public function delete($user, $notrigger = 0)
{
$error = 0;
$this->db->begin();
$sql = "DELETE FROM ".MAIN_DB_PREFIX."steuer_buchung";
$sql .= " WHERE rowid = ".((int) $this->id);
$resql = $this->db->query($sql);
if (!$resql) {
$error++;
$this->errors[] = "Error ".$this->db->lasterror();
}
if (!$error) {
$this->db->commit();
return 1;
} else {
$this->db->rollback();
return -1;
}
}
/**
* Generiert die nächste Referenznummer
*
* @return string Nächste Referenz
*/
private function getNextRef()
{
global $conf;
$sql = "SELECT MAX(CAST(SUBSTRING(ref, 5) AS UNSIGNED)) as maxref";
$sql .= " FROM ".MAIN_DB_PREFIX."steuer_buchung";
$sql .= " WHERE ref LIKE 'BUC-%'";
$sql .= " AND entity = ".((int) $conf->entity);
$resql = $this->db->query($sql);
if ($resql) {
$obj = $this->db->fetch_object($resql);
$num = isset($obj->maxref) ? $obj->maxref + 1 : 1;
return 'BUC-'.sprintf('%06d', $num);
}
return 'BUC-000001';
}
/**
* Gibt den Link zur Buchung zurück
*
* @param int $withpicto Mit Piktogramm
* @param string $option Option
* @return string HTML-Link
*/
public function getNomUrl($withpicto = 0, $option = '')
{
global $langs;
$result = '';
$url = dol_buildpath('/steuer/buchung_card.php', 1).'?id='.$this->id;
$label = '<u>'.$langs->trans("Buchung").'</u><br>';
$label .= '<b>'.$langs->trans("Ref").':</b> '.$this->ref;
$linkstart = '<a href="'.$url.'" title="'.dol_escape_htmltag($label, 1).'" class="classfortooltip">';
$linkend = '</a>';
if ($withpicto) {
$result .= img_object($label, $this->picto, 'class="classfortooltip"');
}
$result .= $linkstart.$this->ref.$linkend;
return $result;
}
/**
* Holt alle Konten für Dropdown
*
* @param string $typ Optional: 'einnahme' oder 'ausgabe'
* @return array Konten-Array
*/
public static function getKonten($db, $typ = '')
{
global $conf;
$konten = array();
$sql = "SELECT rowid, kontonummer, bezeichnung, kategorie";
$sql .= " FROM ".MAIN_DB_PREFIX."steuer_konto";
$sql .= " WHERE aktiv = 1";
$sql .= " AND entity = ".((int) $conf->entity);
if ($typ) {
$sql .= " AND kategorie = '".$db->escape($typ)."'";
}
$sql .= " ORDER BY kontonummer";
$resql = $db->query($sql);
if ($resql) {
while ($obj = $db->fetch_object($resql)) {
$konten[$obj->rowid] = $obj->kontonummer.' - '.$obj->bezeichnung;
}
}
return $konten;
}
}

459
class/euer.class.php Normal file
View file

@ -0,0 +1,459 @@
<?php
/**
* EÜR (Einnahmen-Überschuss-Rechnung) Klasse für Deutschland
* Steuerjahr 2025
*
* @package steuer
* @subpackage class
*/
require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
/**
* Klasse zur Verwaltung der EÜR
*/
class EUeR extends CommonObject
{
public $db;
public $error = '';
public $errors = array();
public $jahr;
public $entity;
// EÜR Daten
public $einnahmen = array();
public $ausgaben = array();
public $summe_einnahmen = 0;
public $summe_ausgaben = 0;
public $gewinn = 0;
// USt/VSt Daten
public $ust_summe = 0;
public $vst_summe = 0;
public $ust_zahllast = 0;
/**
* Constructor
*
* @param DoliDB $db Database handler
*/
public function __construct($db)
{
global $conf;
$this->db = $db;
$this->entity = $conf->entity;
}
/**
* Berechnet die EÜR aus den Dolibarr-Buchungen
*
* @param int $jahr Steuerjahr
* @param int $monat_von Monat von (1-12, 0=ganzes Jahr)
* @param int $monat_bis Monat bis (1-12, 0=ganzes Jahr)
* @return int 0 bei Erfolg, <0 bei Fehler
*/
public function berechneAusDolibarr($jahr, $monat_von = 0, $monat_bis = 0)
{
global $conf;
$this->jahr = $jahr;
// Datumsgrenzen
if ($monat_von > 0 && $monat_bis > 0) {
$datum_von = $jahr.'-'.sprintf('%02d', $monat_von).'-01';
$datum_bis = date('Y-m-t', strtotime($jahr.'-'.sprintf('%02d', $monat_bis).'-01'));
} else {
$datum_von = $jahr.'-01-01';
$datum_bis = $jahr.'-12-31';
}
// Reset
$this->einnahmen = array();
$this->ausgaben = array();
$this->summe_einnahmen = 0;
$this->summe_ausgaben = 0;
$this->ust_summe = 0;
$this->vst_summe = 0;
// EINNAHMEN aus Kundenrechnungen (bezahlt)
$this->berechneEinnahmenAusRechnungen($datum_von, $datum_bis);
// AUSGABEN aus Lieferantenrechnungen (bezahlt)
$this->berechneAusgabenAusLieferantenrechnungen($datum_von, $datum_bis);
// Manuelle Buchungen aus steuer_buchung Tabelle
$this->berechneManuelleBuchungen($datum_von, $datum_bis);
// Gewinn berechnen
$this->gewinn = $this->summe_einnahmen - $this->summe_ausgaben;
$this->ust_zahllast = $this->ust_summe - $this->vst_summe;
return 0;
}
/**
* Einnahmen aus bezahlten Kundenrechnungen
*/
private function berechneEinnahmenAusRechnungen($datum_von, $datum_bis)
{
global $conf;
// Bezahlte Rechnungen nach Zahlungsdatum (Zufluss-Prinzip!)
$sql = "SELECT f.rowid, f.ref, f.datef as rechnungsdatum,";
$sql .= " pf.datep as zahlungsdatum, pf.amount as zahlung,";
$sql .= " f.total_ht as netto, f.total_tva as ust, f.total_ttc as brutto,";
$sql .= " s.nom as kunde,";
$sql .= " fd.tva_tx as ust_satz, fd.total_ht as zeile_netto, fd.total_tva as zeile_ust";
$sql .= " FROM ".MAIN_DB_PREFIX."facture as f";
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON f.fk_soc = s.rowid";
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."paiement_facture as pf ON pf.fk_facture = f.rowid";
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."facturedet as fd ON fd.fk_facture = f.rowid";
$sql .= " WHERE f.entity = ".((int) $conf->entity);
$sql .= " AND f.fk_statut IN (2, 3)"; // Bezahlt oder teilbezahlt
$sql .= " AND pf.datep BETWEEN '".$this->db->escape($datum_von)."' AND '".$this->db->escape($datum_bis)."'";
$sql .= " ORDER BY pf.datep";
$resql = $this->db->query($sql);
if ($resql) {
$einnahmen_details = array();
while ($obj = $this->db->fetch_object($resql)) {
$key = 'ust_'.(int)$obj->ust_satz;
if (!isset($einnahmen_details[$key])) {
$einnahmen_details[$key] = array(
'bezeichnung' => 'Erlöse '.(int)$obj->ust_satz.'% USt',
'netto' => 0,
'ust' => 0,
'brutto' => 0,
'ust_satz' => (int)$obj->ust_satz,
'anzahl' => 0
);
}
$einnahmen_details[$key]['netto'] += $obj->zahlung / (1 + $obj->ust_satz/100);
$einnahmen_details[$key]['ust'] += $obj->zahlung - ($obj->zahlung / (1 + $obj->ust_satz/100));
$einnahmen_details[$key]['brutto'] += $obj->zahlung;
$einnahmen_details[$key]['anzahl']++;
}
foreach ($einnahmen_details as $key => $detail) {
$this->einnahmen[$key] = $detail;
$this->summe_einnahmen += $detail['netto'];
$this->ust_summe += $detail['ust'];
}
}
// Alternative: Wenn keine Zahlungen verknüpft, nimm Rechnungsdatum
$sql2 = "SELECT f.rowid, f.ref, f.datef as datum,";
$sql2 .= " f.total_ht as netto, f.total_tva as ust, f.total_ttc as brutto,";
$sql2 .= " s.nom as kunde";
$sql2 .= " FROM ".MAIN_DB_PREFIX."facture as f";
$sql2 .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON f.fk_soc = s.rowid";
$sql2 .= " LEFT JOIN ".MAIN_DB_PREFIX."paiement_facture as pf ON pf.fk_facture = f.rowid";
$sql2 .= " WHERE f.entity = ".((int) $conf->entity);
$sql2 .= " AND f.fk_statut IN (2, 3)";
$sql2 .= " AND f.datef BETWEEN '".$this->db->escape($datum_von)."' AND '".$this->db->escape($datum_bis)."'";
$sql2 .= " AND pf.rowid IS NULL"; // Keine Zahlungsverknüpfung
$sql2 .= " ORDER BY f.datef";
$resql2 = $this->db->query($sql2);
if ($resql2) {
while ($obj = $this->db->fetch_object($resql2)) {
$key = 'einnahmen_ohne_zahlung';
if (!isset($this->einnahmen[$key])) {
$this->einnahmen[$key] = array(
'bezeichnung' => 'Erlöse (Rechnungsdatum)',
'netto' => 0,
'ust' => 0,
'brutto' => 0,
'anzahl' => 0
);
}
$this->einnahmen[$key]['netto'] += $obj->netto;
$this->einnahmen[$key]['ust'] += $obj->ust;
$this->einnahmen[$key]['brutto'] += $obj->brutto;
$this->einnahmen[$key]['anzahl']++;
$this->summe_einnahmen += $obj->netto;
$this->ust_summe += $obj->ust;
}
}
}
/**
* Ausgaben aus bezahlten Lieferantenrechnungen
*/
private function berechneAusgabenAusLieferantenrechnungen($datum_von, $datum_bis)
{
global $conf;
// Bezahlte Lieferantenrechnungen nach Zahlungsdatum (Abfluss-Prinzip!)
$sql = "SELECT f.rowid, f.ref, f.ref_supplier, f.datef as rechnungsdatum,";
$sql .= " pf.datep as zahlungsdatum, pf.amount as zahlung,";
$sql .= " f.total_ht as netto, f.total_tva as vst, f.total_ttc as brutto,";
$sql .= " s.nom as lieferant,";
$sql .= " fd.tva_tx as vst_satz";
$sql .= " FROM ".MAIN_DB_PREFIX."facture_fourn as f";
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON f.fk_soc = s.rowid";
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."paiementfourn_facturefourn as pf ON pf.fk_facturefourn = f.rowid";
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."facture_fourn_det as fd ON fd.fk_facture_fourn = f.rowid";
$sql .= " WHERE f.entity = ".((int) $conf->entity);
$sql .= " AND f.fk_statut IN (2)"; // Bezahlt
$sql .= " AND pf.datep BETWEEN '".$this->db->escape($datum_von)."' AND '".$this->db->escape($datum_bis)."'";
$sql .= " ORDER BY pf.datep";
$resql = $this->db->query($sql);
if ($resql) {
$ausgaben_details = array();
while ($obj = $this->db->fetch_object($resql)) {
$vst_satz = isset($obj->vst_satz) ? (int)$obj->vst_satz : 19;
$key = 'vst_'.$vst_satz;
if (!isset($ausgaben_details[$key])) {
$ausgaben_details[$key] = array(
'bezeichnung' => 'Betriebsausgaben '.$vst_satz.'% VSt',
'netto' => 0,
'vst' => 0,
'brutto' => 0,
'vst_satz' => $vst_satz,
'anzahl' => 0
);
}
$ausgaben_details[$key]['brutto'] += $obj->zahlung;
$ausgaben_details[$key]['netto'] += $obj->zahlung / (1 + $vst_satz/100);
$ausgaben_details[$key]['vst'] += $obj->zahlung - ($obj->zahlung / (1 + $vst_satz/100));
$ausgaben_details[$key]['anzahl']++;
}
foreach ($ausgaben_details as $key => $detail) {
$this->ausgaben[$key] = $detail;
$this->summe_ausgaben += $detail['netto'];
$this->vst_summe += $detail['vst'];
}
}
// Alternative: Ohne Zahlungsverknüpfung
$sql2 = "SELECT f.rowid, f.ref, f.datef as datum,";
$sql2 .= " f.total_ht as netto, f.total_tva as vst, f.total_ttc as brutto,";
$sql2 .= " s.nom as lieferant";
$sql2 .= " FROM ".MAIN_DB_PREFIX."facture_fourn as f";
$sql2 .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON f.fk_soc = s.rowid";
$sql2 .= " LEFT JOIN ".MAIN_DB_PREFIX."paiementfourn_facturefourn as pf ON pf.fk_facturefourn = f.rowid";
$sql2 .= " WHERE f.entity = ".((int) $conf->entity);
$sql2 .= " AND f.fk_statut IN (2)";
$sql2 .= " AND f.datef BETWEEN '".$this->db->escape($datum_von)."' AND '".$this->db->escape($datum_bis)."'";
$sql2 .= " AND pf.rowid IS NULL";
$sql2 .= " ORDER BY f.datef";
$resql2 = $this->db->query($sql2);
if ($resql2) {
while ($obj = $this->db->fetch_object($resql2)) {
$key = 'ausgaben_ohne_zahlung';
if (!isset($this->ausgaben[$key])) {
$this->ausgaben[$key] = array(
'bezeichnung' => 'Betriebsausgaben (Rechnungsdatum)',
'netto' => 0,
'vst' => 0,
'brutto' => 0,
'anzahl' => 0
);
}
$this->ausgaben[$key]['netto'] += $obj->netto;
$this->ausgaben[$key]['vst'] += $obj->vst;
$this->ausgaben[$key]['brutto'] += $obj->brutto;
$this->ausgaben[$key]['anzahl']++;
$this->summe_ausgaben += $obj->netto;
$this->vst_summe += $obj->vst;
}
}
}
/**
* Manuelle Buchungen aus steuer_buchung Tabelle
*/
private function berechneManuelleBuchungen($datum_von, $datum_bis)
{
global $conf;
$sql = "SELECT b.*, k.kontonummer, k.bezeichnung as konto_bezeichnung, k.kategorie";
$sql .= " FROM ".MAIN_DB_PREFIX."steuer_buchung as b";
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."steuer_konto as k ON b.fk_konto = k.rowid";
$sql .= " WHERE b.entity = ".((int) $conf->entity);
$sql .= " AND b.status = 1";
$sql .= " AND b.datum BETWEEN '".$this->db->escape($datum_von)."' AND '".$this->db->escape($datum_bis)."'";
$sql .= " ORDER BY b.datum";
$resql = $this->db->query($sql);
if ($resql) {
while ($obj = $this->db->fetch_object($resql)) {
$key = 'manuell_'.$obj->kontonummer;
if ($obj->typ == 'einnahme') {
if (!isset($this->einnahmen[$key])) {
$this->einnahmen[$key] = array(
'bezeichnung' => $obj->konto_bezeichnung,
'kontonummer' => $obj->kontonummer,
'netto' => 0,
'ust' => 0,
'brutto' => 0,
'ust_satz' => (int)$obj->ust_satz,
'anzahl' => 0
);
}
$this->einnahmen[$key]['netto'] += $obj->betrag_netto;
$this->einnahmen[$key]['ust'] += $obj->betrag_ust;
$this->einnahmen[$key]['brutto'] += $obj->betrag_brutto;
$this->einnahmen[$key]['anzahl']++;
$this->summe_einnahmen += $obj->betrag_netto;
$this->ust_summe += $obj->betrag_ust;
} else {
if (!isset($this->ausgaben[$key])) {
$this->ausgaben[$key] = array(
'bezeichnung' => $obj->konto_bezeichnung,
'kontonummer' => $obj->kontonummer,
'netto' => 0,
'vst' => 0,
'brutto' => 0,
'vst_satz' => (int)$obj->ust_satz,
'anzahl' => 0
);
}
$this->ausgaben[$key]['netto'] += $obj->betrag_netto;
$this->ausgaben[$key]['vst'] += $obj->betrag_ust;
$this->ausgaben[$key]['brutto'] += $obj->betrag_brutto;
$this->ausgaben[$key]['anzahl']++;
$this->summe_ausgaben += $obj->betrag_netto;
$this->vst_summe += $obj->betrag_ust;
}
}
}
}
/**
* Holt detaillierte Buchungsliste für einen Zeitraum
*
* @param string $datum_von Von-Datum
* @param string $datum_bis Bis-Datum
* @param string $typ 'einnahme', 'ausgabe' oder 'alle'
* @return array Buchungsliste
*/
public function getBuchungsliste($datum_von, $datum_bis, $typ = 'alle')
{
global $conf;
$buchungen = array();
// Kundenrechnungen (Einnahmen)
if ($typ == 'alle' || $typ == 'einnahme') {
$sql = "SELECT 'einnahme' as buchungstyp, f.rowid, f.ref,";
$sql .= " COALESCE(pf.datep, f.datef) as datum,";
$sql .= " CONCAT('Rechnung ', f.ref, ' - ', s.nom) as beschreibung,";
$sql .= " f.total_ht as netto, f.total_tva as steuer, f.total_ttc as brutto,";
$sql .= " s.nom as partner, 'facture' as quelle";
$sql .= " FROM ".MAIN_DB_PREFIX."facture as f";
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON f.fk_soc = s.rowid";
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."paiement_facture as pf ON pf.fk_facture = f.rowid";
$sql .= " WHERE f.entity = ".((int) $conf->entity);
$sql .= " AND f.fk_statut IN (2, 3)";
$sql .= " AND COALESCE(pf.datep, f.datef) BETWEEN '".$this->db->escape($datum_von)."' AND '".$this->db->escape($datum_bis)."'";
$sql .= " GROUP BY f.rowid";
$sql .= " ORDER BY datum";
$resql = $this->db->query($sql);
if ($resql) {
while ($obj = $this->db->fetch_object($resql)) {
$buchungen[] = (array)$obj;
}
}
}
// Lieferantenrechnungen (Ausgaben)
if ($typ == 'alle' || $typ == 'ausgabe') {
$sql = "SELECT 'ausgabe' as buchungstyp, f.rowid, f.ref,";
$sql .= " COALESCE(pf.datep, f.datef) as datum,";
$sql .= " CONCAT('Lieferantenrechnung ', COALESCE(f.ref_supplier, f.ref), ' - ', s.nom) as beschreibung,";
$sql .= " f.total_ht as netto, f.total_tva as steuer, f.total_ttc as brutto,";
$sql .= " s.nom as partner, 'facture_fourn' as quelle";
$sql .= " FROM ".MAIN_DB_PREFIX."facture_fourn as f";
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON f.fk_soc = s.rowid";
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."paiementfourn_facturefourn as pf ON pf.fk_facturefourn = f.rowid";
$sql .= " WHERE f.entity = ".((int) $conf->entity);
$sql .= " AND f.fk_statut IN (2)";
$sql .= " AND COALESCE(pf.datep, f.datef) BETWEEN '".$this->db->escape($datum_von)."' AND '".$this->db->escape($datum_bis)."'";
$sql .= " GROUP BY f.rowid";
$sql .= " ORDER BY datum";
$resql = $this->db->query($sql);
if ($resql) {
while ($obj = $this->db->fetch_object($resql)) {
$buchungen[] = (array)$obj;
}
}
}
// Manuelle Buchungen
$sql = "SELECT b.typ as buchungstyp, b.rowid, b.ref,";
$sql .= " b.datum, b.beschreibung,";
$sql .= " b.betrag_netto as netto, b.betrag_ust as steuer, b.betrag_brutto as brutto,";
$sql .= " COALESCE(s.nom, '') as partner, 'manuell' as quelle";
$sql .= " FROM ".MAIN_DB_PREFIX."steuer_buchung as b";
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON b.fk_soc = s.rowid";
$sql .= " WHERE b.entity = ".((int) $conf->entity);
$sql .= " AND b.status = 1";
if ($typ != 'alle') {
$sql .= " AND b.typ = '".$this->db->escape($typ)."'";
}
$sql .= " AND b.datum BETWEEN '".$this->db->escape($datum_von)."' AND '".$this->db->escape($datum_bis)."'";
$sql .= " ORDER BY b.datum";
$resql = $this->db->query($sql);
if ($resql) {
while ($obj = $this->db->fetch_object($resql)) {
$buchungen[] = (array)$obj;
}
}
// Nach Datum sortieren
usort($buchungen, function($a, $b) {
return strcmp($a['datum'], $b['datum']);
});
return $buchungen;
}
/**
* Generiert das EÜR-Format für die Anlage EÜR
*
* @return array EÜR-Zeilen
*/
public function getAnlageEUeR()
{
$zeilen = array();
// EINNAHMEN
$zeilen[10] = array('zeile' => 10, 'bezeichnung' => 'Steuerfreie Betriebseinnahmen', 'betrag' => 0);
$zeilen[11] = array('zeile' => 11, 'bezeichnung' => 'Innergemeinschaftliche Lieferungen', 'betrag' => 0);
$zeilen[12] = array('zeile' => 12, 'bezeichnung' => 'Ausfuhrlieferungen', 'betrag' => 0);
$zeilen[14] = array('zeile' => 14, 'bezeichnung' => 'Umsatzsteuerpflichtige Betriebseinnahmen', 'betrag' => $this->summe_einnahmen);
$zeilen[16] = array('zeile' => 16, 'bezeichnung' => 'Sonstige Betriebseinnahmen', 'betrag' => 0);
$zeilen[19] = array('zeile' => 19, 'bezeichnung' => 'Private Kfz-/Telefonnutzung', 'betrag' => 0);
// Summe Einnahmen
$zeilen[22] = array('zeile' => 22, 'bezeichnung' => 'Summe Betriebseinnahmen', 'betrag' => $this->summe_einnahmen, 'summe' => true);
// AUSGABEN
$zeilen[26] = array('zeile' => 26, 'bezeichnung' => 'Waren, Roh- und Hilfsstoffe', 'betrag' => 0);
$zeilen[31] = array('zeile' => 31, 'bezeichnung' => 'Löhne und Gehälter', 'betrag' => 0);
$zeilen[32] = array('zeile' => 32, 'bezeichnung' => 'Gesetzliche Sozialaufwendungen', 'betrag' => 0);
$zeilen[34] = array('zeile' => 34, 'bezeichnung' => 'Raumkosten', 'betrag' => 0);
$zeilen[36] = array('zeile' => 36, 'bezeichnung' => 'AfA auf Sachanlagen', 'betrag' => 0);
$zeilen[38] = array('zeile' => 38, 'bezeichnung' => 'Leasing, GWG', 'betrag' => 0);
$zeilen[45] = array('zeile' => 45, 'bezeichnung' => 'Schuldzinsen', 'betrag' => 0);
$zeilen[49] = array('zeile' => 49, 'bezeichnung' => 'Übrige Betriebsausgaben', 'betrag' => $this->summe_ausgaben);
$zeilen[51] = array('zeile' => 51, 'bezeichnung' => 'Fahrzeugkosten', 'betrag' => 0);
// Summe Ausgaben
$zeilen[67] = array('zeile' => 67, 'bezeichnung' => 'Summe Betriebsausgaben', 'betrag' => $this->summe_ausgaben, 'summe' => true);
// GEWINN
$zeilen[87] = array('zeile' => 87, 'bezeichnung' => 'Gewinn/Verlust', 'betrag' => $this->gewinn, 'ergebnis' => true);
return $zeilen;
}
}

620
core/modules/modSteuer.class.php Executable file
View file

@ -0,0 +1,620 @@
<?php
/* Copyright (C) 2004-2018 Laurent Destailleur <eldy@users.sourceforge.net>
* Copyright (C) 2018-2019 Nicolas ZABOURI <info@inovea-conseil.com>
* Copyright (C) 2019-2024 Frédéric France <frederic.france@free.fr>
* Copyright (C) 2026 Eduard Wisch <data@data-it-solution.de>
*
* 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/>.
*/
/**
* \defgroup steuer Module Steuer
* \brief Steuer module descriptor.
*
* \file htdocs/steuer/core/modules/modSteuer.class.php
* \ingroup steuer
* \brief Description and activation file for module Steuer
*/
include_once DOL_DOCUMENT_ROOT.'/core/modules/DolibarrModules.class.php';
/**
* Description and activation class for module Steuer
*/
class modSteuer extends DolibarrModules
{
/**
* Constructor. Define names, constants, directories, boxes, permissions
*
* @param DoliDB $db Database handler
*/
public function __construct($db)
{
global $conf, $langs;
$this->db = $db;
// Id for module (must be unique).
// Use here a free id (See in Home -> System information -> Dolibarr for list of used modules id).
$this->numero = 500000; // TODO Go on page https://wiki.dolibarr.org/index.php/List_of_modules_id to reserve an id number for your module
// Key text used to identify module (for permissions, menus, etc...)
$this->rights_class = 'steuer';
// Family can be 'base' (core modules),'crm','financial','hr','projects','products','ecm','technic' (transverse modules),'interface' (link with external tools),'other','...'
// It is used to group modules by family in module setup page
$this->family = "financial";
// Module position in the family on 2 digits ('01', '10', '20', ...)
$this->module_position = '90';
// Gives the possibility for the module, to provide his own family info and position of this family (Overwrite $this->family and $this->module_position. Avoid this)
//$this->familyinfo = array('myownfamily' => array('position' => '01', 'label' => $langs->trans("MyOwnFamily")));
// Module label (no space allowed), used if translation string 'ModuleSteuerName' not found (Steuer is name of module).
$this->name = preg_replace('/^mod/i', '', get_class($this));
// DESCRIPTION_FLAG
// Module description, used if translation string 'ModuleSteuerDesc' not found (Steuer is name of module).
$this->description = "EÜR Modul für Deutschland - Einnahmen-Überschuss-Rechnung, USt-Voranmeldung, Gewerbesteuer";
// Used only if file README.md and README-LL.md not found.
$this->descriptionlong = "Komplettes EÜR-Modul für deutsche Unternehmen: Einnahmen-Überschuss-Rechnung (Anlage EÜR), Umsatzsteuer-Voranmeldung (UStVA), Gewerbesteuer-Berechnung, WISO Steuer Export. Unterstützt SKR03 Kontenrahmen und Steuerjahr 2025.";
// Author
$this->editor_name = 'Alles Watt läuft (Testsystem)';
$this->editor_url = ''; // Must be an external online web site
$this->editor_squarred_logo = ''; // Must be image filename into the module/img directory followed with @modulename. Example: 'myimage.png@steuer'
// Possible values for version are: 'development', 'experimental', 'dolibarr', 'dolibarr_deprecated', 'experimental_deprecated' or a version string like 'x.y.z'
$this->version = '1.0';
// Url to the file with your last numberversion of this module
//$this->url_last_version = 'http://www.example.com/versionmodule.txt';
// Key used in llx_const table to save module status enabled/disabled (where STEUER is value of property name of module in uppercase)
$this->const_name = 'MAIN_MODULE_'.strtoupper($this->name);
// Name of image file used for this module.
// If file is in theme/yourtheme/img directory under name object_pictovalue.png, use this->picto='pictovalue'
// If file is in module/img directory under name object_pictovalue.png, use this->picto='pictovalue@module'
// To use a supported fa-xxx css style of font awesome, use this->picto='xxx'
$this->picto = 'fa-calculator';
// Define some features supported by module (triggers, login, substitutions, menus, css, etc...)
$this->module_parts = array(
// Set this to 1 if module has its own trigger directory (core/triggers)
'triggers' => 0,
// Set this to 1 if module has its own login method file (core/login)
'login' => 0,
// Set this to 1 if module has its own substitution function file (core/substitutions)
'substitutions' => 0,
// Set this to 1 if module has its own menus handler directory (core/menus)
'menus' => 0,
// Set this to 1 if module overwrite template dir (core/tpl)
'tpl' => 0,
// Set this to 1 if module has its own barcode directory (core/modules/barcode)
'barcode' => 0,
// Set this to 1 if module has its own models directory (core/modules/xxx)
'models' => 0,
// Set this to 1 if module has its own printing directory (core/modules/printing)
'printing' => 0,
// Set this to 1 if module has its own theme directory (theme)
'theme' => 0,
// Set this to relative path of css file if module has its own css file
'css' => array(
// '/steuer/css/steuer.css.php',
),
// Set this to relative path of js file if module must load a js on all pages
'js' => array(
// '/steuer/js/steuer.js.php',
),
// Set here all hooks context managed by module. To find available hook context, make a "grep -r '>initHooks(' *" on source code. You can also set hook context to 'all'
/* BEGIN MODULEBUILDER HOOKSCONTEXTS */
'hooks' => array(
// 'data' => array(
// 'hookcontext1',
// 'hookcontext2',
// ),
// 'entity' => '0',
),
/* END MODULEBUILDER HOOKSCONTEXTS */
// Set this to 1 if features of module are opened to external users
'moduleforexternal' => 0,
// Set this to 1 if the module provides a website template into doctemplates/websites/website_template-mytemplate
'websitetemplates' => 0,
// Set this to 1 if the module provides a captcha driver
'captcha' => 0
);
// Data directories to create when module is enabled.
// Example: this->dirs = array("/steuer/temp","/steuer/subdir");
$this->dirs = array("/steuer/temp");
// Config pages. Put here list of php page, stored into steuer/admin directory, to use to setup module.
$this->config_page_url = array("setup.php@steuer");
// Dependencies
// A condition to hide module
$this->hidden = getDolGlobalInt('MODULE_STEUER_DISABLED'); // A condition to disable module;
// List of module class names that must be enabled if this module is enabled. Example: array('always'=>array('modModuleToEnable1','modModuleToEnable2'), 'FR'=>array('modModuleToEnableFR')...)
$this->depends = array();
// List of module class names to disable if this one is disabled. Example: array('modModuleToDisable1', ...)
$this->requiredby = array();
// List of module class names this module is in conflict with. Example: array('modModuleToDisable1', ...)
$this->conflictwith = array();
// The language file dedicated to your module
$this->langfiles = array("steuer@steuer");
// Prerequisites
$this->phpmin = array(7, 1); // Minimum version of PHP required by module
// $this->phpmax = array(8, 0); // Maximum version of PHP required by module
$this->need_dolibarr_version = array(19, -3); // Minimum version of Dolibarr required by module
// $this->max_dolibarr_version = array(19, -3); // Maximum version of Dolibarr required by module
$this->need_javascript_ajax = 0;
// Messages at activation
$this->warnings_activation = array(); // Warning to show when we activate module. array('always'='text') or array('FR'='textfr','MX'='textmx'...)
$this->warnings_activation_ext = array(); // Warning to show when we activate an external module. array('always'='text') or array('FR'='textfr','MX'='textmx'...)
//$this->automatic_activation = array('FR'=>'SteuerWasAutomaticallyActivatedBecauseOfYourCountryChoice');
//$this->always_enabled = true; // If true, can't be disabled
// Constants
// List of particular constants to add when module is enabled (key, 'chaine', value, desc, visible, 'current' or 'allentities', deleteonunactive)
// Example: $this->const=array(1 => array('STEUER_MYNEWCONST1', 'chaine', 'myvalue', 'This is a constant to add', 1),
// 2 => array('STEUER_MYNEWCONST2', 'chaine', 'myvalue', 'This is another constant to add', 0, 'current', 1)
// );
$this->const = array();
// Some keys to add into the overwriting translation tables
/*$this->overwrite_translation = array(
'en_US:ParentCompany'=>'Parent company or reseller',
'fr_FR:ParentCompany'=>'Maison mère ou revendeur'
)*/
if (!isModEnabled("steuer")) {
$conf->steuer = new stdClass();
$conf->steuer->enabled = 0;
}
// Array to add new pages in new tabs
/* BEGIN MODULEBUILDER TABS */
$this->tabs = array();
/* END MODULEBUILDER TABS */
// Example:
// To add a new tab identified by code tabname1
// $this->tabs[] = array('data' => 'objecttype:+tabname1:Title1:mylangfile@steuer:$user->hasRight(\'steuer\', \'read\'):/steuer/mynewtab1.php?id=__ID__');
// To add another new tab identified by code tabname2. Label will be result of calling all substitution functions on 'Title2' key.
// $this->tabs[] = array('data' => 'objecttype:+tabname2:SUBSTITUTION_Title2:mylangfile@steuer:$user->hasRight(\'othermodule\', \'read\'):/steuer/mynewtab2.php?id=__ID__',
// To remove an existing tab identified by code tabname
// $this->tabs[] = array('data' => 'objecttype:-tabname:NU:conditiontoremove');
//
// Where objecttype can be
// 'categories_x' to add a tab in category view (replace 'x' by type of category (0=product, 1=supplier, 2=customer, 3=member)
// 'contact' to add a tab in contact view
// 'contract' to add a tab in contract view
// 'delivery' to add a tab in delivery view
// 'group' to add a tab in group view
// 'intervention' to add a tab in intervention view
// 'invoice' to add a tab in customer invoice view
// 'supplier_invoice' to add a tab in supplier invoice view
// 'member' to add a tab in foundation member view
// 'opensurveypoll' to add a tab in opensurvey poll view
// 'order' to add a tab in sale order view
// 'supplier_order' to add a tab in supplier order view
// 'payment' to add a tab in payment view
// 'supplier_payment' to add a tab in supplier payment view
// 'product' to add a tab in product view
// 'propal' to add a tab in propal view
// 'project' to add a tab in project view
// 'stock' to add a tab in stock view
// 'thirdparty' to add a tab in third party view
// 'user' to add a tab in user view
// Dictionaries
/* Example:
$this->dictionaries=array(
'langs' => 'steuer@steuer',
// List of tables we want to see into dictionary editor
'tabname' => array("table1", "table2", "table3"),
// Label of tables
'tablib' => array("Table1", "Table2", "Table3"),
// Request to select fields
'tabsql' => array('SELECT f.rowid as rowid, f.code, f.label, f.active FROM '.$this->db->prefix().'table1 as f', 'SELECT f.rowid as rowid, f.code, f.label, f.active FROM '.$this->db->prefix().'table2 as f', 'SELECT f.rowid as rowid, f.code, f.label, f.active FROM '.$this->db->prefix().'table3 as f'),
// Sort order
'tabsqlsort' => array("label ASC", "label ASC", "label ASC"),
// List of fields (result of select to show dictionary)
'tabfield' => array("code,label", "code,label", "code,label"),
// List of fields (list of fields to edit a record)
'tabfieldvalue' => array("code,label", "code,label", "code,label"),
// List of fields (list of fields for insert)
'tabfieldinsert' => array("code,label", "code,label", "code,label"),
// Name of columns with primary key (try to always name it 'rowid')
'tabrowid' => array("rowid", "rowid", "rowid"),
// Condition to show each dictionary
'tabcond' => array(isModEnabled('steuer'), isModEnabled('steuer'), isModEnabled('steuer')),
// Tooltip for every fields of dictionaries: DO NOT PUT AN EMPTY ARRAY
'tabhelp' => array(array('code' => $langs->trans('CodeTooltipHelp'), 'field2' => 'field2tooltip'), array('code' => $langs->trans('CodeTooltipHelp'), 'field2' => 'field2tooltip'), ...),
);
*/
/* BEGIN MODULEBUILDER DICTIONARIES */
$this->dictionaries = array();
/* END MODULEBUILDER DICTIONARIES */
// Boxes/Widgets
// Add here list of php file(s) stored in steuer/core/boxes that contains a class to show a widget.
/* BEGIN MODULEBUILDER WIDGETS */
$this->boxes = array(
// 0 => array(
// 'file' => 'steuerwidget1.php@steuer',
// 'note' => 'Widget provided by Steuer',
// 'enabledbydefaulton' => 'Home',
// ),
// ...
);
/* END MODULEBUILDER WIDGETS */
// Cronjobs (List of cron jobs entries to add when module is enabled)
// unit_frequency must be 60 for minute, 3600 for hour, 86400 for day, 604800 for week
/* BEGIN MODULEBUILDER CRON */
$this->cronjobs = array(
// 0 => array(
// 'label' => 'MyJob label',
// 'jobtype' => 'method',
// 'class' => '/steuer/class/myobject.class.php',
// 'objectname' => 'MyObject',
// 'method' => 'doScheduledJob',
// 'parameters' => '',
// 'comment' => 'Comment',
// 'frequency' => 2,
// 'unitfrequency' => 3600,
// 'status' => 0,
// 'test' => 'isModEnabled("steuer")',
// 'priority' => 50,
// ),
);
/* END MODULEBUILDER CRON */
// Example: $this->cronjobs=array(
// 0=>array('label'=>'My label', 'jobtype'=>'method', 'class'=>'/dir/class/file.class.php', 'objectname'=>'MyClass', 'method'=>'myMethod', 'parameters'=>'param1, param2', 'comment'=>'Comment', 'frequency'=>2, 'unitfrequency'=>3600, 'status'=>0, 'test'=>'isModEnabled("steuer")', 'priority'=>50),
// 1=>array('label'=>'My label', 'jobtype'=>'command', 'command'=>'', 'parameters'=>'param1, param2', 'comment'=>'Comment', 'frequency'=>1, 'unitfrequency'=>3600*24, 'status'=>0, 'test'=>'isModEnabled("steuer")', 'priority'=>50)
// );
// Permissions provided by this module
$this->rights = array();
$r = 0;
// Add here entries to declare new permissions
/* BEGIN MODULEBUILDER PERMISSIONS */
/*
$o = 1;
$this->rights[$r][0] = $this->numero . sprintf("%02d", ($o * 10) + 1); // Permission id (must not be already used)
$this->rights[$r][1] = 'Read objects of Steuer'; // Permission label
$this->rights[$r][4] = 'myobject';
$this->rights[$r][5] = 'read'; // In php code, permission will be checked by test if ($user->hasRight('steuer', 'myobject', 'read'))
$r++;
$this->rights[$r][0] = $this->numero . sprintf("%02d", ($o * 10) + 2); // Permission id (must not be already used)
$this->rights[$r][1] = 'Create/Update objects of Steuer'; // Permission label
$this->rights[$r][4] = 'myobject';
$this->rights[$r][5] = 'write'; // In php code, permission will be checked by test if ($user->hasRight('steuer', 'myobject', 'write'))
$r++;
$this->rights[$r][0] = $this->numero . sprintf("%02d", ($o * 10) + 3); // Permission id (must not be already used)
$this->rights[$r][1] = 'Delete objects of Steuer'; // Permission label
$this->rights[$r][4] = 'myobject';
$this->rights[$r][5] = 'delete'; // In php code, permission will be checked by test if ($user->hasRight('steuer', 'myobject', 'delete'))
$r++;
*/
/* END MODULEBUILDER PERMISSIONS */
// Main menu entries to add
$this->menu = array();
$r = 0;
// Add here entries to declare new menus
/* BEGIN MODULEBUILDER TOPMENU */
$this->menu[$r++] = array(
'fk_menu' => '', // Will be stored into mainmenu + leftmenu. Use '' if this is a top menu. For left menu, use 'fk_mainmenu=xxx' or 'fk_mainmenu=xxx,fk_leftmenu=yyy' where xxx is mainmenucode and yyy is a leftmenucode
'type' => 'top', // This is a Top menu entry
'titre' => 'ModuleSteuerName',
'prefix' => img_picto('', $this->picto, 'class="pictofixedwidth valignmiddle"'),
'mainmenu' => 'steuer',
'leftmenu' => '',
'url' => '/steuer/steuerindex.php',
'langs' => 'steuer@steuer', // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory.
'position' => 1000 + $r,
'enabled' => 'isModEnabled("steuer")', // Define condition to show or hide menu entry. Use 'isModEnabled("steuer")' if entry must be visible if module is enabled.
'perms' => '1', // Use 'perms'=>'$user->hasRight("steuer", "myobject", "read")' if you want your menu with a permission rules
'target' => '',
'user' => 2, // 0=Menu for internal users, 1=external users, 2=both
);
/* END MODULEBUILDER TOPMENU */
/* BEGIN MODULEBUILDER LEFTMENU */
// EÜR Übersicht
$this->menu[$r++] = array(
'fk_menu' => 'fk_mainmenu=steuer',
'type' => 'left',
'titre' => 'EUeRUebersicht',
'prefix' => img_picto('', 'fa-chart-pie', 'class="pictofixedwidth"'),
'mainmenu' => 'steuer',
'leftmenu' => 'euer_uebersicht',
'url' => '/steuer/steuerindex.php',
'langs' => 'steuer@steuer',
'position' => 1000 + $r,
'enabled' => 'isModEnabled("steuer")',
'perms' => '1',
'target' => '',
'user' => 2,
);
// Buchungen
$this->menu[$r++] = array(
'fk_menu' => 'fk_mainmenu=steuer',
'type' => 'left',
'titre' => 'Buchungen',
'prefix' => img_picto('', 'fa-list', 'class="pictofixedwidth"'),
'mainmenu' => 'steuer',
'leftmenu' => 'buchungen',
'url' => '/steuer/buchung_list.php',
'langs' => 'steuer@steuer',
'position' => 1000 + $r,
'enabled' => 'isModEnabled("steuer")',
'perms' => '1',
'target' => '',
'user' => 2,
);
// Neue Buchung
$this->menu[$r++] = array(
'fk_menu' => 'fk_mainmenu=steuer,fk_leftmenu=buchungen',
'type' => 'left',
'titre' => 'NeueBuchung',
'mainmenu' => 'steuer',
'leftmenu' => 'neue_buchung',
'url' => '/steuer/buchung_card.php?action=create',
'langs' => 'steuer@steuer',
'position' => 1000 + $r,
'enabled' => 'isModEnabled("steuer")',
'perms' => '1',
'target' => '',
'user' => 2,
);
// Anlage EÜR
$this->menu[$r++] = array(
'fk_menu' => 'fk_mainmenu=steuer',
'type' => 'left',
'titre' => 'AnlageEUeR',
'prefix' => img_picto('', 'fa-file-alt', 'class="pictofixedwidth"'),
'mainmenu' => 'steuer',
'leftmenu' => 'anlage_euer',
'url' => '/steuer/euer_bericht.php',
'langs' => 'steuer@steuer',
'position' => 1000 + $r,
'enabled' => 'isModEnabled("steuer")',
'perms' => '1',
'target' => '',
'user' => 2,
);
// UStVA
$this->menu[$r++] = array(
'fk_menu' => 'fk_mainmenu=steuer',
'type' => 'left',
'titre' => 'UStVA',
'prefix' => img_picto('', 'fa-percent', 'class="pictofixedwidth"'),
'mainmenu' => 'steuer',
'leftmenu' => 'ustva',
'url' => '/steuer/ustva.php',
'langs' => 'steuer@steuer',
'position' => 1000 + $r,
'enabled' => 'isModEnabled("steuer")',
'perms' => '1',
'target' => '',
'user' => 2,
);
// Gewerbesteuer
$this->menu[$r++] = array(
'fk_menu' => 'fk_mainmenu=steuer',
'type' => 'left',
'titre' => 'Gewerbesteuer',
'prefix' => img_picto('', 'fa-building', 'class="pictofixedwidth"'),
'mainmenu' => 'steuer',
'leftmenu' => 'gewerbesteuer',
'url' => '/steuer/gewerbesteuer.php',
'langs' => 'steuer@steuer',
'position' => 1000 + $r,
'enabled' => 'isModEnabled("steuer")',
'perms' => '1',
'target' => '',
'user' => 2,
);
// WISO Export
$this->menu[$r++] = array(
'fk_menu' => 'fk_mainmenu=steuer',
'type' => 'left',
'titre' => 'WISOExport',
'prefix' => img_picto('', 'fa-download', 'class="pictofixedwidth"'),
'mainmenu' => 'steuer',
'leftmenu' => 'wiso_export',
'url' => '/steuer/export_wiso.php',
'langs' => 'steuer@steuer',
'position' => 1000 + $r,
'enabled' => 'isModEnabled("steuer")',
'perms' => '1',
'target' => '',
'user' => 2,
);
// Kontenplan
$this->menu[$r++] = array(
'fk_menu' => 'fk_mainmenu=steuer',
'type' => 'left',
'titre' => 'Kontenplan',
'prefix' => img_picto('', 'fa-sitemap', 'class="pictofixedwidth"'),
'mainmenu' => 'steuer',
'leftmenu' => 'kontenplan',
'url' => '/steuer/konten.php',
'langs' => 'steuer@steuer',
'position' => 1000 + $r,
'enabled' => 'isModEnabled("steuer")',
'perms' => '1',
'target' => '',
'user' => 2,
);
/* END MODULEBUILDER LEFTMENU */
// Exports profiles provided by this module
$r = 0;
/* BEGIN MODULEBUILDER EXPORT MYOBJECT */
/*
$langs->load("steuer@steuer");
$this->export_code[$r] = $this->rights_class.'_'.$r;
$this->export_label[$r] = 'MyObjectLines'; // Translation key (used only if key ExportDataset_xxx_z not found)
$this->export_icon[$r] = $this->picto;
// Define $this->export_fields_array, $this->export_TypeFields_array and $this->export_entities_array
$keyforclass = 'MyObject'; $keyforclassfile='/steuer/class/myobject.class.php'; $keyforelement='myobject@steuer';
include DOL_DOCUMENT_ROOT.'/core/commonfieldsinexport.inc.php';
//$this->export_fields_array[$r]['t.fieldtoadd']='FieldToAdd'; $this->export_TypeFields_array[$r]['t.fieldtoadd']='Text';
//unset($this->export_fields_array[$r]['t.fieldtoremove']);
//$keyforclass = 'MyObjectLine'; $keyforclassfile='/steuer/class/myobject.class.php'; $keyforelement='myobjectline@steuer'; $keyforalias='tl';
//include DOL_DOCUMENT_ROOT.'/core/commonfieldsinexport.inc.php';
$keyforselect='myobject'; $keyforaliasextra='extra'; $keyforelement='myobject@steuer';
include DOL_DOCUMENT_ROOT.'/core/extrafieldsinexport.inc.php';
//$keyforselect='myobjectline'; $keyforaliasextra='extraline'; $keyforelement='myobjectline@steuer';
//include DOL_DOCUMENT_ROOT.'/core/extrafieldsinexport.inc.php';
//$this->export_dependencies_array[$r] = array('myobjectline' => array('tl.rowid','tl.ref')); // To force to activate one or several fields if we select some fields that need same (like to select a unique key if we ask a field of a child to avoid the DISTINCT to discard them, or for computed field than need several other fields)
//$this->export_special_array[$r] = array('t.field' => '...');
//$this->export_examplevalues_array[$r] = array('t.field' => 'Example');
//$this->export_help_array[$r] = array('t.field' => 'FieldDescHelp');
$this->export_sql_start[$r]='SELECT DISTINCT ';
$this->export_sql_end[$r] =' FROM '.$this->db->prefix().'steuer_myobject as t';
//$this->export_sql_end[$r] .=' LEFT JOIN '.$this->db->prefix().'steuer_myobject_line as tl ON tl.fk_myobject = t.rowid';
$this->export_sql_end[$r] .=' WHERE 1 = 1';
$this->export_sql_end[$r] .=' AND t.entity IN ('.getEntity('myobject').')';
$r++; */
/* END MODULEBUILDER EXPORT MYOBJECT */
// Imports profiles provided by this module
$r = 0;
/* BEGIN MODULEBUILDER IMPORT MYOBJECT */
/*
$langs->load("steuer@steuer");
$this->import_code[$r] = $this->rights_class.'_'.$r;
$this->import_label[$r] = 'MyObjectLines'; // Translation key (used only if key ExportDataset_xxx_z not found)
$this->import_icon[$r] = $this->picto;
$this->import_tables_array[$r] = array('t' => $this->db->prefix().'steuer_myobject', 'extra' => $this->db->prefix().'steuer_myobject_extrafields');
$this->import_tables_creator_array[$r] = array('t' => 'fk_user_author'); // Fields to store import user id
$import_sample = array();
$keyforclass = 'MyObject'; $keyforclassfile='/steuer/class/myobject.class.php'; $keyforelement='myobject@steuer';
include DOL_DOCUMENT_ROOT.'/core/commonfieldsinimport.inc.php';
$import_extrafield_sample = array();
$keyforselect='myobject'; $keyforaliasextra='extra'; $keyforelement='myobject@steuer';
include DOL_DOCUMENT_ROOT.'/core/extrafieldsinimport.inc.php';
$this->import_fieldshidden_array[$r] = array('extra.fk_object' => 'lastrowid-'.$this->db->prefix().'steuer_myobject');
$this->import_regex_array[$r] = array();
$this->import_examplevalues_array[$r] = array_merge($import_sample, $import_extrafield_sample);
$this->import_updatekeys_array[$r] = array('t.ref' => 'Ref');
$this->import_convertvalue_array[$r] = array(
't.ref' => array(
'rule'=>'getrefifauto',
'class'=>(!getDolGlobalString('STEUER_MYOBJECT_ADDON') ? 'mod_myobject_standard' : getDolGlobalString('STEUER_MYOBJECT_ADDON')),
'path'=>"/core/modules/steuer/".(!getDolGlobalString('STEUER_MYOBJECT_ADDON') ? 'mod_myobject_standard' : getDolGlobalString('STEUER_MYOBJECT_ADDON')).'.php',
'classobject'=>'MyObject',
'pathobject'=>'/steuer/class/myobject.class.php',
),
't.fk_soc' => array('rule' => 'fetchidfromref', 'file' => '/societe/class/societe.class.php', 'class' => 'Societe', 'method' => 'fetch', 'element' => 'ThirdParty'),
't.fk_user_valid' => array('rule' => 'fetchidfromref', 'file' => '/user/class/user.class.php', 'class' => 'User', 'method' => 'fetch', 'element' => 'user'),
't.fk_mode_reglement' => array('rule' => 'fetchidfromcodeorlabel', 'file' => '/compta/paiement/class/cpaiement.class.php', 'class' => 'Cpaiement', 'method' => 'fetch', 'element' => 'cpayment'),
);
$this->import_run_sql_after_array[$r] = array();
$r++; */
/* END MODULEBUILDER IMPORT MYOBJECT */
}
/**
* Function called when module is enabled.
* The init function add constants, boxes, permissions and menus (defined in constructor) into Dolibarr database.
* It also creates data directories
*
* @param string $options Options when enabling module ('', 'noboxes')
* @return int<-1,1> 1 if OK, <=0 if KO
*/
public function init($options = '')
{
global $conf, $langs;
// Create tables of module at module activation
//$result = $this->_load_tables('/install/mysql/', 'steuer');
$result = $this->_load_tables('/steuer/sql/');
if ($result < 0) {
return -1; // Do not activate module if error 'not allowed' returned when loading module SQL queries (the _load_table run sql with run_sql with the error allowed parameter set to 'default')
}
// Create extrafields during init
//include_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
//$extrafields = new ExtraFields($this->db);
//$result0=$extrafields->addExtraField('steuer_separator1', "Separator 1", 'separator', 1, 0, 'thirdparty', 0, 0, '', array('options'=>array(1=>1)), 1, '', 1, 0, '', '', 'steuer@steuer', 'isModEnabled("steuer")');
//$result1=$extrafields->addExtraField('steuer_myattr1', "New Attr 1 label", 'boolean', 1, 3, 'thirdparty', 0, 0, '', '', 1, '', -1, 0, '', '', 'steuer@steuer', 'isModEnabled("steuer")');
//$result2=$extrafields->addExtraField('steuer_myattr2', "New Attr 2 label", 'varchar', 1, 10, 'project', 0, 0, '', '', 1, '', -1, 0, '', '', 'steuer@steuer', 'isModEnabled("steuer")');
//$result3=$extrafields->addExtraField('steuer_myattr3', "New Attr 3 label", 'varchar', 1, 10, 'bank_account', 0, 0, '', '', 1, '', -1, 0, '', '', 'steuer@steuer', 'isModEnabled("steuer")');
//$result4=$extrafields->addExtraField('steuer_myattr4', "New Attr 4 label", 'select', 1, 3, 'thirdparty', 0, 1, '', array('options'=>array('code1'=>'Val1','code2'=>'Val2','code3'=>'Val3')), 1,'', -1, 0, '', '', 'steuer@steuer', 'isModEnabled("steuer")');
//$result5=$extrafields->addExtraField('steuer_myattr5', "New Attr 5 label", 'text', 1, 10, 'user', 0, 0, '', '', 1, '', -1, 0, '', '', 'steuer@steuer', 'isModEnabled("steuer")');
// Permissions
$this->remove($options);
$sql = array();
// Document templates
$moduledir = dol_sanitizeFileName('steuer');
$myTmpObjects = array();
$myTmpObjects['MyObject'] = array('includerefgeneration' => 0, 'includedocgeneration' => 0);
foreach ($myTmpObjects as $myTmpObjectKey => $myTmpObjectArray) {
if ($myTmpObjectArray['includerefgeneration']) {
$src = DOL_DOCUMENT_ROOT.'/install/doctemplates/'.$moduledir.'/template_myobjects.odt';
$dirodt = DOL_DATA_ROOT.($conf->entity > 1 ? '/'.$conf->entity : '').'/doctemplates/'.$moduledir;
$dest = $dirodt.'/template_myobjects.odt';
if (file_exists($src) && !file_exists($dest)) {
require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
dol_mkdir($dirodt);
$result = dol_copy($src, $dest, '0', 0);
if ($result < 0) {
$langs->load("errors");
$this->error = $langs->trans('ErrorFailToCopyFile', $src, $dest);
return 0;
}
}
$sql = array_merge($sql, array(
"DELETE FROM ".$this->db->prefix()."document_model WHERE nom = 'standard_".strtolower($myTmpObjectKey)."' AND type = '".$this->db->escape(strtolower($myTmpObjectKey))."' AND entity = ".((int) $conf->entity),
"INSERT INTO ".$this->db->prefix()."document_model (nom, type, entity) VALUES('standard_".strtolower($myTmpObjectKey)."', '".$this->db->escape(strtolower($myTmpObjectKey))."', ".((int) $conf->entity).")",
"DELETE FROM ".$this->db->prefix()."document_model WHERE nom = 'generic_".strtolower($myTmpObjectKey)."_odt' AND type = '".$this->db->escape(strtolower($myTmpObjectKey))."' AND entity = ".((int) $conf->entity),
"INSERT INTO ".$this->db->prefix()."document_model (nom, type, entity) VALUES('generic_".strtolower($myTmpObjectKey)."_odt', '".$this->db->escape(strtolower($myTmpObjectKey))."', ".((int) $conf->entity).")"
));
}
}
return $this->_init($sql, $options);
}
/**
* Function called when module is disabled.
* Remove from database constants, boxes and permissions from Dolibarr database.
* Data directories are not deleted
*
* @param string $options Options when enabling module ('', 'noboxes')
* @return int<-1,1> 1 if OK, <=0 if KO
*/
public function remove($options = '')
{
$sql = array();
return $this->_remove($sql, $options);
}
}

333
euer_bericht.php Normal file
View file

@ -0,0 +1,333 @@
<?php
/**
* EÜR Bericht - Anlage EÜR Format
*
* @package steuer
*/
// Load Dolibarr environment
$res = 0;
if (!$res && !empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) {
$res = @include $_SERVER["CONTEXT_DOCUMENT_ROOT"]."/main.inc.php";
}
$tmp = empty($_SERVER['SCRIPT_FILENAME']) ? '' : $_SERVER['SCRIPT_FILENAME'];
$tmp2 = realpath(__FILE__);
$i = strlen($tmp) - 1;
$j = strlen($tmp2) - 1;
while ($i > 0 && $j > 0 && isset($tmp[$i]) && isset($tmp2[$j]) && $tmp[$i] == $tmp2[$j]) {
$i--;
$j--;
}
if (!$res && $i > 0 && file_exists(substr($tmp, 0, ($i + 1))."/main.inc.php")) {
$res = @include substr($tmp, 0, ($i + 1))."/main.inc.php";
}
if (!$res && $i > 0 && file_exists(dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php")) {
$res = @include dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php";
}
if (!$res && file_exists("../main.inc.php")) {
$res = @include "../main.inc.php";
}
if (!$res && file_exists("../../main.inc.php")) {
$res = @include "../../main.inc.php";
}
if (!$res && file_exists("../../../main.inc.php")) {
$res = @include "../../../main.inc.php";
}
if (!$res) {
die("Include of main fails");
}
require_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
dol_include_once('/steuer/class/euer.class.php');
$langs->loadLangs(array("steuer@steuer", "bills", "compta"));
$jahr = GETPOSTINT('jahr');
if (empty($jahr)) {
$jahr = date('Y');
}
/*
* View
*/
$form = new Form($db);
$euer = new EUeR($db);
$euer->berechneAusDolibarr($jahr);
llxHeader('', $langs->trans("AnlageEUeR"), '', '', 0, 0, '', '', '', 'mod-steuer page-euer-bericht');
print load_fiche_titre($langs->trans("AnlageEUeR")." ".$jahr, '', 'steuer.png@steuer');
// Jahr-Auswahl
print '<form method="POST" action="'.$_SERVER["PHP_SELF"].'">';
print '<input type="hidden" name="token" value="'.newToken().'">';
print '<div class="inline-block marginrightonly">';
print '<select name="jahr" class="flat">';
for ($y = date('Y'); $y >= date('Y') - 5; $y--) {
print '<option value="'.$y.'"'.($y == $jahr ? ' selected' : '').'>'.$y.'</option>';
}
print '</select>';
print ' <input type="submit" class="button" value="'.$langs->trans("Refresh").'">';
print ' <a href="'.$_SERVER["PHP_SELF"].'?jahr='.$jahr.'&action=export_csv" class="butAction">'.$langs->trans("ExportCSV").'</a>';
print '</div>';
print '</form>';
print '<br><br>';
// Anlage EÜR Format
print '<div class="div-table-responsive">';
print '<table class="noborder centpercent">';
// Header
print '<tr class="liste_titre">';
print '<th class="center" style="width: 60px;">'.$langs->trans("Zeile").'</th>';
print '<th>'.$langs->trans("Bezeichnung").'</th>';
print '<th class="right" style="width: 150px;">'.$langs->trans("Betrag").' EUR</th>';
print '</tr>';
// ============ BETRIEBSEINNAHMEN ============
print '<tr class="liste_titre">';
print '<td colspan="3"><strong>A. Betriebseinnahmen</strong></td>';
print '</tr>';
// Zeile 10-12: Steuerfreie Einnahmen
$zeile10 = 0; // Steuerfreie Betriebseinnahmen
$zeile11 = 0; // Innergemeinschaftliche Lieferungen
$zeile12 = 0; // Ausfuhrlieferungen
print '<tr class="oddeven">';
print '<td class="center">10</td>';
print '<td>Steuerfreie Betriebseinnahmen nach § 4 Nr. 8 bis 28 UStG</td>';
print '<td class="right amount">'.price($zeile10, 0, $langs, 1, 2, 2).'</td>';
print '</tr>';
print '<tr class="oddeven">';
print '<td class="center">11</td>';
print '<td>Innergemeinschaftliche Lieferungen (§ 4 Nr. 1 Buchst. b UStG)</td>';
print '<td class="right amount">'.price($zeile11, 0, $langs, 1, 2, 2).'</td>';
print '</tr>';
print '<tr class="oddeven">';
print '<td class="center">12</td>';
print '<td>Steuerfreie Ausfuhrlieferungen (§ 4 Nr. 1 Buchst. a UStG)</td>';
print '<td class="right amount">'.price($zeile12, 0, $langs, 1, 2, 2).'</td>';
print '</tr>';
// Zeile 14: Umsatzsteuerpflichtige Einnahmen
print '<tr class="oddeven">';
print '<td class="center">14</td>';
print '<td><strong>Umsatzsteuerpflichtige Betriebseinnahmen</strong></td>';
print '<td class="right amount"><strong>'.price($euer->summe_einnahmen, 0, $langs, 1, 2, 2).'</strong></td>';
print '</tr>';
// Zeile 16: Vom Finanzamt erstattete USt
print '<tr class="oddeven">';
print '<td class="center">16</td>';
print '<td>Vom Finanzamt erstattete und ggf. verrechnete Umsatzsteuer</td>';
print '<td class="right amount">'.price(0, 0, $langs, 1, 2, 2).'</td>';
print '</tr>';
// Zeile 18: Veräußerungsgewinne
print '<tr class="oddeven">';
print '<td class="center">18</td>';
print '<td>Veräußerung/Entnahme von Anlagevermögen</td>';
print '<td class="right amount">'.price(0, 0, $langs, 1, 2, 2).'</td>';
print '</tr>';
// Zeile 19: Private Nutzung
print '<tr class="oddeven">';
print '<td class="center">19</td>';
print '<td>Private Kfz-Nutzung, Sach-, Nutzungs- und Leistungsentnahmen</td>';
print '<td class="right amount">'.price(0, 0, $langs, 1, 2, 2).'</td>';
print '</tr>';
// Zeile 20: Auflösung Rücklagen
print '<tr class="oddeven">';
print '<td class="center">20</td>';
print '<td>Auflösung von Rücklagen und Ausgleichsposten (§ 6c EStG)</td>';
print '<td class="right amount">'.price(0, 0, $langs, 1, 2, 2).'</td>';
print '</tr>';
// Zwischensumme Einnahmen
$summe_einnahmen = $zeile10 + $zeile11 + $zeile12 + $euer->summe_einnahmen;
print '<tr class="liste_total">';
print '<td class="center">22</td>';
print '<td><strong>Summe Betriebseinnahmen</strong></td>';
print '<td class="right amount"><strong>'.price($summe_einnahmen, 0, $langs, 1, 2, 2).'</strong></td>';
print '</tr>';
// ============ BETRIEBSAUSGABEN ============
print '<tr class="liste_titre">';
print '<td colspan="3"><strong>B. Betriebsausgaben</strong></td>';
print '</tr>';
// Wareneinkauf
print '<tr class="oddeven">';
print '<td class="center">26</td>';
print '<td>Waren, Roh- und Hilfsstoffe einschl. der Nebenkosten</td>';
print '<td class="right amount">'.price(0, 0, $langs, 1, 2, 2).'</td>';
print '</tr>';
// Fremdleistungen
print '<tr class="oddeven">';
print '<td class="center">27</td>';
print '<td>Bezogene Fremdleistungen</td>';
print '<td class="right amount">'.price(0, 0, $langs, 1, 2, 2).'</td>';
print '</tr>';
// Personal
print '<tr class="oddeven">';
print '<td class="center">31</td>';
print '<td>Löhne und Gehälter</td>';
print '<td class="right amount">'.price(0, 0, $langs, 1, 2, 2).'</td>';
print '</tr>';
print '<tr class="oddeven">';
print '<td class="center">32</td>';
print '<td>Gesetzliche Sozialaufwendungen</td>';
print '<td class="right amount">'.price(0, 0, $langs, 1, 2, 2).'</td>';
print '</tr>';
// Raumkosten
print '<tr class="oddeven">';
print '<td class="center">34</td>';
print '<td>Raumkosten und sonstige Grundstücksaufwendungen</td>';
print '<td class="right amount">'.price(0, 0, $langs, 1, 2, 2).'</td>';
print '</tr>';
// AfA
print '<tr class="oddeven">';
print '<td class="center">36</td>';
print '<td>AfA auf unbewegliche Wirtschaftsgüter</td>';
print '<td class="right amount">'.price(0, 0, $langs, 1, 2, 2).'</td>';
print '</tr>';
print '<tr class="oddeven">';
print '<td class="center">37</td>';
print '<td>AfA auf bewegliche Wirtschaftsgüter</td>';
print '<td class="right amount">'.price(0, 0, $langs, 1, 2, 2).'</td>';
print '</tr>';
print '<tr class="oddeven">';
print '<td class="center">38</td>';
print '<td>AfA auf geringwertige Wirtschaftsgüter</td>';
print '<td class="right amount">'.price(0, 0, $langs, 1, 2, 2).'</td>';
print '</tr>';
// Sonstige Ausgaben
print '<tr class="oddeven">';
print '<td class="center">45</td>';
print '<td>Schuldzinsen zur Finanzierung von Anschaffungs-/Herstellungskosten</td>';
print '<td class="right amount">'.price(0, 0, $langs, 1, 2, 2).'</td>';
print '</tr>';
print '<tr class="oddeven">';
print '<td class="center">46</td>';
print '<td>Übrige Schuldzinsen</td>';
print '<td class="right amount">'.price(0, 0, $langs, 1, 2, 2).'</td>';
print '</tr>';
print '<tr class="oddeven">';
print '<td class="center">48</td>';
print '<td>Geschenke</td>';
print '<td class="right amount">'.price(0, 0, $langs, 1, 2, 2).'</td>';
print '</tr>';
// Übrige Betriebsausgaben (enthält alle Ausgaben aus Dolibarr)
print '<tr class="oddeven">';
print '<td class="center">49</td>';
print '<td><strong>Übrige unbeschränkt abziehbare Betriebsausgaben</strong></td>';
print '<td class="right amount"><strong>'.price($euer->summe_ausgaben, 0, $langs, 1, 2, 2).'</strong></td>';
print '</tr>';
// Fahrzeugkosten
print '<tr class="oddeven">';
print '<td class="center">51</td>';
print '<td>Aufwendungen für ein zum Betriebsvermögen gehörendes Kfz</td>';
print '<td class="right amount">'.price(0, 0, $langs, 1, 2, 2).'</td>';
print '</tr>';
// Bewirtung
print '<tr class="oddeven">';
print '<td class="center">53</td>';
print '<td>Beschränkt abziehbare Bewirtungsaufwendungen (70%)</td>';
print '<td class="right amount">'.price(0, 0, $langs, 1, 2, 2).'</td>';
print '</tr>';
// Verpflegungsmehraufwand
print '<tr class="oddeven">';
print '<td class="center">54</td>';
print '<td>Pauschbeträge für Verpflegungsmehraufwand</td>';
print '<td class="right amount">'.price(0, 0, $langs, 1, 2, 2).'</td>';
print '</tr>';
// Häusliches Arbeitszimmer
print '<tr class="oddeven">';
print '<td class="center">56</td>';
print '<td>Aufwendungen für ein häusliches Arbeitszimmer</td>';
print '<td class="right amount">'.price(0, 0, $langs, 1, 2, 2).'</td>';
print '</tr>';
// USt gezahlt
print '<tr class="oddeven">';
print '<td class="center">64</td>';
print '<td>An das Finanzamt gezahlte und ggf. verrechnete Umsatzsteuer</td>';
print '<td class="right amount">'.price($euer->ust_zahllast > 0 ? $euer->ust_zahllast : 0, 0, $langs, 1, 2, 2).'</td>';
print '</tr>';
// Summe Ausgaben
$summe_ausgaben = $euer->summe_ausgaben;
print '<tr class="liste_total">';
print '<td class="center">67</td>';
print '<td><strong>Summe Betriebsausgaben</strong></td>';
print '<td class="right amount"><strong>'.price($summe_ausgaben, 0, $langs, 1, 2, 2).'</strong></td>';
print '</tr>';
// ============ GEWINNERMITTLUNG ============
print '<tr class="liste_titre">';
print '<td colspan="3"><strong>C. Gewinnermittlung</strong></td>';
print '</tr>';
print '<tr class="oddeven">';
print '<td class="center">71</td>';
print '<td>Betriebseinnahmen (aus Zeile 22)</td>';
print '<td class="right amount">'.price($summe_einnahmen, 0, $langs, 1, 2, 2).'</td>';
print '</tr>';
print '<tr class="oddeven">';
print '<td class="center">72</td>';
print '<td>Betriebsausgaben (aus Zeile 67)</td>';
print '<td class="right amount">'.price($summe_ausgaben, 0, $langs, 1, 2, 2).'</td>';
print '</tr>';
// Gewinn/Verlust
$gewinn = $summe_einnahmen - $summe_ausgaben;
$color = $gewinn >= 0 ? 'amountpaymentcomplete' : 'amountremaintopay';
print '<tr class="liste_total">';
print '<td class="center">87</td>';
print '<td><strong>'.($gewinn >= 0 ? $langs->trans("Gewinn") : $langs->trans("Verlust")).'</strong></td>';
print '<td class="right amount '.$color.'"><strong>'.price($gewinn, 0, $langs, 1, 2, 2).'</strong></td>';
print '</tr>';
print '</table>';
print '</div>';
// Hinweise
print '<br>';
print '<div class="opacitymedium">';
print '<strong>'.$langs->trans("Hinweis").':</strong><br>';
print '- '.$langs->trans("EUeRHinweis1").'<br>';
print '- '.$langs->trans("EUeRHinweis2").'<br>';
print '- '.$langs->trans("EUeRHinweis3").'<br>';
print '</div>';
// Zurück-Button
print '<br>';
print '<div class="tabsAction">';
print '<a class="butAction" href="'.dol_buildpath('/steuer/steuerindex.php', 1).'"><i class="fa fa-arrow-left paddingright"></i>'.$langs->trans("Back").'</a>';
print '</div>';
llxFooter();
$db->close();

369
export_wiso.php Normal file
View file

@ -0,0 +1,369 @@
<?php
/**
* WISO Steuer Export
*
* Exportiert Buchungen im CSV-Format für WISO Steuer Software
*
* @package steuer
*/
// Load Dolibarr environment
$res = 0;
if (!$res && !empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) {
$res = @include $_SERVER["CONTEXT_DOCUMENT_ROOT"]."/main.inc.php";
}
$tmp = empty($_SERVER['SCRIPT_FILENAME']) ? '' : $_SERVER['SCRIPT_FILENAME'];
$tmp2 = realpath(__FILE__);
$i = strlen($tmp) - 1;
$j = strlen($tmp2) - 1;
while ($i > 0 && $j > 0 && isset($tmp[$i]) && isset($tmp2[$j]) && $tmp[$i] == $tmp2[$j]) {
$i--;
$j--;
}
if (!$res && $i > 0 && file_exists(substr($tmp, 0, ($i + 1))."/main.inc.php")) {
$res = @include substr($tmp, 0, ($i + 1))."/main.inc.php";
}
if (!$res && $i > 0 && file_exists(dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php")) {
$res = @include dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php";
}
if (!$res && file_exists("../main.inc.php")) {
$res = @include "../main.inc.php";
}
if (!$res && file_exists("../../main.inc.php")) {
$res = @include "../../main.inc.php";
}
if (!$res && file_exists("../../../main.inc.php")) {
$res = @include "../../../main.inc.php";
}
if (!$res) {
die("Include of main fails");
}
require_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
dol_include_once('/steuer/class/euer.class.php');
$langs->loadLangs(array("steuer@steuer", "bills", "compta", "exports"));
$jahr = GETPOSTINT('jahr');
if (empty($jahr)) {
$jahr = date('Y');
}
$action = GETPOST('action', 'aZ09');
$format = GETPOST('format', 'alpha');
if (empty($format)) {
$format = 'wiso_euer';
}
/*
* Actions
*/
// Export durchführen
if ($action == 'export') {
$euer = new EUeR($db);
$buchungen = $euer->getBuchungsliste($jahr.'-01-01', $jahr.'-12-31', 'alle');
if ($format == 'wiso_euer') {
// WISO EÜR Format (CSV)
$filename = 'euer_export_'.$jahr.'_'.date('Ymd').'.csv';
header('Content-Type: text/csv; charset=utf-8');
header('Content-Disposition: attachment; filename="'.$filename.'"');
header('Cache-Control: no-cache, no-store, must-revalidate');
$output = fopen('php://output', 'w');
// BOM für Excel UTF-8
fprintf($output, chr(0xEF).chr(0xBB).chr(0xBF));
// Header
fputcsv($output, array(
'Datum',
'Belegnummer',
'Beschreibung',
'Einnahme/Ausgabe',
'Netto',
'USt/VSt',
'Brutto',
'USt-Satz',
'Kontonummer',
'Partner'
), ';');
// Daten
foreach ($buchungen as $buchung) {
fputcsv($output, array(
date('d.m.Y', strtotime($buchung['datum'])),
$buchung['ref'],
$buchung['beschreibung'],
$buchung['buchungstyp'] == 'einnahme' ? 'Einnahme' : 'Ausgabe',
number_format($buchung['netto'], 2, ',', ''),
number_format($buchung['steuer'], 2, ',', ''),
number_format($buchung['brutto'], 2, ',', ''),
'19', // Standard, könnte erweitert werden
'', // Kontonummer
$buchung['partner']
), ';');
}
fclose($output);
exit;
} elseif ($format == 'datev') {
// DATEV-Format (vereinfacht)
$filename = 'datev_export_'.$jahr.'_'.date('Ymd').'.csv';
header('Content-Type: text/csv; charset=utf-8');
header('Content-Disposition: attachment; filename="'.$filename.'"');
header('Cache-Control: no-cache, no-store, must-revalidate');
$output = fopen('php://output', 'w');
// BOM für Excel UTF-8
fprintf($output, chr(0xEF).chr(0xBB).chr(0xBF));
// DATEV Header (vereinfacht)
fputcsv($output, array(
'Umsatz',
'Soll/Haben',
'Konto',
'Gegenkonto',
'BU-Schlüssel',
'Belegdatum',
'Belegfeld 1',
'Buchungstext'
), ';');
foreach ($buchungen as $buchung) {
$soll_haben = $buchung['buchungstyp'] == 'einnahme' ? 'H' : 'S';
$konto = $buchung['buchungstyp'] == 'einnahme' ? '8400' : '4900';
$gegenkonto = '1200'; // Bank
fputcsv($output, array(
number_format($buchung['brutto'], 2, ',', ''),
$soll_haben,
$konto,
$gegenkonto,
'', // BU-Schlüssel
date('dm', strtotime($buchung['datum'])),
$buchung['ref'],
$buchung['beschreibung']
), ';');
}
fclose($output);
exit;
} elseif ($format == 'ustva_csv') {
// UStVA Werte als CSV
$filename = 'ustva_'.$jahr.'_'.date('Ymd').'.csv';
header('Content-Type: text/csv; charset=utf-8');
header('Content-Disposition: attachment; filename="'.$filename.'"');
header('Cache-Control: no-cache, no-store, must-revalidate');
$output = fopen('php://output', 'w');
fprintf($output, chr(0xEF).chr(0xBB).chr(0xBF));
// Header
fputcsv($output, array(
'Monat',
'Kz81 (Umsätze 19%)',
'Kz86 (Umsätze 7%)',
'USt 19%',
'USt 7%',
'Kz66 (Vorsteuer)',
'Zahllast'
), ';');
// Monatliche Werte
for ($m = 1; $m <= 12; $m++) {
$euer->berechneAusDolibarr($jahr, $m, $m);
$kz81 = 0;
$kz86 = 0;
$ust19 = 0;
$ust7 = 0;
foreach ($euer->einnahmen as $einnahme) {
$ust_satz = isset($einnahme['ust_satz']) ? $einnahme['ust_satz'] : 19;
if ($ust_satz == 19) {
$kz81 += $einnahme['netto'];
$ust19 += isset($einnahme['ust']) ? $einnahme['ust'] : 0;
} elseif ($ust_satz == 7) {
$kz86 += $einnahme['netto'];
$ust7 += isset($einnahme['ust']) ? $einnahme['ust'] : 0;
}
}
$zahllast = ($ust19 + $ust7) - $euer->vst_summe;
fputcsv($output, array(
date('F', mktime(0, 0, 0, $m, 1, $jahr)),
number_format(round($kz81), 0, ',', ''),
number_format(round($kz86), 0, ',', ''),
number_format($ust19, 2, ',', ''),
number_format($ust7, 2, ',', ''),
number_format($euer->vst_summe, 2, ',', ''),
number_format($zahllast, 2, ',', '')
), ';');
}
fclose($output);
exit;
}
}
/*
* View
*/
$form = new Form($db);
llxHeader('', $langs->trans("WISOExport"), '', '', 0, 0, '', '', '', 'mod-steuer page-export-wiso');
print load_fiche_titre($langs->trans("WISOExport"), '', 'steuer.png@steuer');
// Export-Formular
print '<form method="POST" action="'.$_SERVER["PHP_SELF"].'">';
print '<input type="hidden" name="token" value="'.newToken().'">';
print '<input type="hidden" name="action" value="export">';
print '<div class="div-table-responsive-no-min">';
print '<table class="noborder centpercent">';
print '<tr class="liste_titre">';
print '<th colspan="2">'.$langs->trans("ExportSettings").'</th>';
print '</tr>';
print '<tr class="oddeven">';
print '<td style="width: 200px;">'.$langs->trans("Year").'</td>';
print '<td>';
print '<select name="jahr" class="flat minwidth100">';
for ($y = date('Y'); $y >= date('Y') - 5; $y--) {
print '<option value="'.$y.'"'.($y == $jahr ? ' selected' : '').'>'.$y.'</option>';
}
print '</select>';
print '</td>';
print '</tr>';
print '<tr class="oddeven">';
print '<td>'.$langs->trans("ExportFormat").'</td>';
print '<td>';
print '<select name="format" class="flat minwidth300">';
print '<option value="wiso_euer"'.($format == 'wiso_euer' ? ' selected' : '').'>'.$langs->trans("WISOEUeRFormat").'</option>';
print '<option value="datev"'.($format == 'datev' ? ' selected' : '').'>'.$langs->trans("DATEVFormat").'</option>';
print '<option value="ustva_csv"'.($format == 'ustva_csv' ? ' selected' : '').'>'.$langs->trans("UStVACSV").'</option>';
print '</select>';
print '</td>';
print '</tr>';
print '<tr class="oddeven">';
print '<td colspan="2">';
print '<input type="submit" class="button button-save" value="'.$langs->trans("Export").'">';
print '</td>';
print '</tr>';
print '</table>';
print '</div>';
print '</form>';
print '<br>';
// Format-Beschreibungen
print '<div class="div-table-responsive-no-min">';
print '<table class="noborder centpercent">';
print '<tr class="liste_titre">';
print '<th colspan="2">'.$langs->trans("ExportFormatInfo").'</th>';
print '</tr>';
print '<tr class="oddeven">';
print '<td style="width: 200px;"><strong>'.$langs->trans("WISOEUeRFormat").'</strong></td>';
print '<td>'.$langs->trans("WISOEUeRFormatDesc").'</td>';
print '</tr>';
print '<tr class="oddeven">';
print '<td><strong>'.$langs->trans("DATEVFormat").'</strong></td>';
print '<td>'.$langs->trans("DATEVFormatDesc").'</td>';
print '</tr>';
print '<tr class="oddeven">';
print '<td><strong>'.$langs->trans("UStVACSV").'</strong></td>';
print '<td>'.$langs->trans("UStVACSVDesc").'</td>';
print '</tr>';
print '</table>';
print '</div>';
// Vorschau
print '<br>';
print '<h3>'.$langs->trans("PreviewData").' '.$jahr.'</h3>';
$euer = new EUeR($db);
$buchungen = $euer->getBuchungsliste($jahr.'-01-01', $jahr.'-12-31', 'alle');
print '<div class="div-table-responsive">';
print '<table class="noborder centpercent">';
print '<tr class="liste_titre">';
print '<th>'.$langs->trans("Date").'</th>';
print '<th>'.$langs->trans("Ref").'</th>';
print '<th>'.$langs->trans("Description").'</th>';
print '<th>'.$langs->trans("Typ").'</th>';
print '<th class="right">'.$langs->trans("Netto").'</th>';
print '<th class="right">'.$langs->trans("VAT").'</th>';
print '<th class="right">'.$langs->trans("Brutto").'</th>';
print '</tr>';
$count = 0;
$max_preview = 20;
foreach ($buchungen as $buchung) {
if ($count >= $max_preview) {
print '<tr class="oddeven"><td colspan="7" class="center opacitymedium">... '.$langs->trans("AndMore", count($buchungen) - $max_preview).'</td></tr>';
break;
}
print '<tr class="oddeven">';
print '<td>'.dol_print_date(strtotime($buchung['datum']), 'day').'</td>';
print '<td>'.$buchung['ref'].'</td>';
print '<td>'.dol_trunc($buchung['beschreibung'], 40).'</td>';
print '<td>';
if ($buchung['buchungstyp'] == 'einnahme') {
print '<span class="badge badge-status4">'.$langs->trans("Einnahme").'</span>';
} else {
print '<span class="badge badge-status1">'.$langs->trans("Ausgabe").'</span>';
}
print '</td>';
print '<td class="right">'.price($buchung['netto'], 0, $langs, 1, 2, 2).'</td>';
print '<td class="right">'.price($buchung['steuer'], 0, $langs, 1, 2, 2).'</td>';
print '<td class="right amount">'.price($buchung['brutto'], 0, $langs, 1, 2, 2).'</td>';
print '</tr>';
$count++;
}
print '<tr class="liste_total">';
print '<td colspan="4"><strong>'.$langs->trans("Total").': '.count($buchungen).' '.$langs->trans("Buchungen").'</strong></td>';
print '<td colspan="3"></td>';
print '</tr>';
print '</table>';
print '</div>';
// Hinweise
print '<br>';
print '<div class="opacitymedium">';
print '<strong>'.$langs->trans("ExportHinweise").':</strong><br>';
print '- '.$langs->trans("ExportHinweis1").'<br>';
print '- '.$langs->trans("ExportHinweis2").'<br>';
print '- '.$langs->trans("ExportHinweis3").'<br>';
print '</div>';
// Zurück-Button
print '<br>';
print '<div class="tabsAction">';
print '<a class="butAction" href="'.dol_buildpath('/steuer/steuerindex.php', 1).'"><i class="fa fa-arrow-left paddingright"></i>'.$langs->trans("Back").'</a>';
print '</div>';
llxFooter();
$db->close();

285
gewerbesteuer.php Normal file
View file

@ -0,0 +1,285 @@
<?php
/**
* Gewerbesteuer-Berechnung
*
* @package steuer
*/
// Load Dolibarr environment
$res = 0;
if (!$res && !empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) {
$res = @include $_SERVER["CONTEXT_DOCUMENT_ROOT"]."/main.inc.php";
}
$tmp = empty($_SERVER['SCRIPT_FILENAME']) ? '' : $_SERVER['SCRIPT_FILENAME'];
$tmp2 = realpath(__FILE__);
$i = strlen($tmp) - 1;
$j = strlen($tmp2) - 1;
while ($i > 0 && $j > 0 && isset($tmp[$i]) && isset($tmp2[$j]) && $tmp[$i] == $tmp2[$j]) {
$i--;
$j--;
}
if (!$res && $i > 0 && file_exists(substr($tmp, 0, ($i + 1))."/main.inc.php")) {
$res = @include substr($tmp, 0, ($i + 1))."/main.inc.php";
}
if (!$res && $i > 0 && file_exists(dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php")) {
$res = @include dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php";
}
if (!$res && file_exists("../main.inc.php")) {
$res = @include "../main.inc.php";
}
if (!$res && file_exists("../../main.inc.php")) {
$res = @include "../../main.inc.php";
}
if (!$res && file_exists("../../../main.inc.php")) {
$res = @include "../../../main.inc.php";
}
if (!$res) {
die("Include of main fails");
}
require_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
dol_include_once('/steuer/class/euer.class.php');
$langs->loadLangs(array("steuer@steuer", "bills", "compta"));
$jahr = GETPOSTINT('jahr');
if (empty($jahr)) {
$jahr = date('Y');
}
$action = GETPOST('action', 'aZ09');
// Einstellbare Parameter
$hebesatz = GETPOSTFLOAT('hebesatz');
if (empty($hebesatz)) {
$hebesatz = getDolGlobalString('STEUER_GEWERBE_HEBESATZ', 400);
}
$hinzurechnungen = GETPOSTFLOAT('hinzurechnungen');
$kuerzungen = GETPOSTFLOAT('kuerzungen');
/*
* View
*/
$form = new Form($db);
$euer = new EUeR($db);
$euer->berechneAusDolibarr($jahr);
// Gewerbesteuer-Berechnung
$gewinn_euer = $euer->gewinn;
$freibetrag = 24500; // Freibetrag für Einzelunternehmen/Personengesellschaften
// Gewerbeertrag berechnen
$gewerbeertrag_vor_freibetrag = $gewinn_euer + $hinzurechnungen - $kuerzungen;
$gewerbeertrag = max(0, $gewerbeertrag_vor_freibetrag - $freibetrag);
// Steuermessbetrag (3,5% vom Gewerbeertrag)
$steuermesszahl = 3.5;
$steuermessbetrag = $gewerbeertrag * $steuermesszahl / 100;
// Gewerbesteuer
$gewerbesteuer = $steuermessbetrag * $hebesatz / 100;
// Anrechnung auf ESt (max. das 4-fache des Steuermessbetrags, § 35 EStG)
$anrechnung_est = min($gewerbesteuer, $steuermessbetrag * 4);
// Effektive Gewerbesteuer nach Anrechnung
$gewerbesteuer_effektiv = $gewerbesteuer - $anrechnung_est;
llxHeader('', $langs->trans("Gewerbesteuer"), '', '', 0, 0, '', '', '', 'mod-steuer page-gewerbesteuer');
print load_fiche_titre($langs->trans("Gewerbesteuer")." ".$jahr, '', 'steuer.png@steuer');
// Formular
print '<form method="POST" action="'.$_SERVER["PHP_SELF"].'">';
print '<input type="hidden" name="token" value="'.newToken().'">';
print '<input type="hidden" name="action" value="calculate">';
print '<div class="div-table-responsive-no-min">';
print '<table class="noborder centpercent">';
print '<tr class="liste_titre">';
print '<th colspan="2">'.$langs->trans("Parameter").'</th>';
print '</tr>';
print '<tr class="oddeven">';
print '<td style="width: 300px;">'.$langs->trans("Year").'</td>';
print '<td>';
print '<select name="jahr" class="flat minwidth100">';
for ($y = date('Y'); $y >= date('Y') - 5; $y--) {
print '<option value="'.$y.'"'.($y == $jahr ? ' selected' : '').'>'.$y.'</option>';
}
print '</select>';
print '</td>';
print '</tr>';
print '<tr class="oddeven">';
print '<td>'.$langs->trans("Hebesatz").' (%)</td>';
print '<td>';
print '<input type="text" name="hebesatz" class="minwidth100" value="'.dol_escape_htmltag($hebesatz).'">';
print ' <small class="opacitymedium">'.$langs->trans("HebesatzHinweis").'</small>';
print '</td>';
print '</tr>';
print '<tr class="oddeven">';
print '<td>'.$langs->trans("Hinzurechnungen").' (§ 8 GewStG)</td>';
print '<td>';
print '<input type="text" name="hinzurechnungen" class="minwidth100" value="'.dol_escape_htmltag($hinzurechnungen).'">';
print ' EUR <small class="opacitymedium">'.$langs->trans("HinzurechnungenHinweis").'</small>';
print '</td>';
print '</tr>';
print '<tr class="oddeven">';
print '<td>'.$langs->trans("Kuerzungen").' (§ 9 GewStG)</td>';
print '<td>';
print '<input type="text" name="kuerzungen" class="minwidth100" value="'.dol_escape_htmltag($kuerzungen).'">';
print ' EUR <small class="opacitymedium">'.$langs->trans("KuerzungenHinweis").'</small>';
print '</td>';
print '</tr>';
print '<tr class="oddeven">';
print '<td colspan="2">';
print '<input type="submit" class="button" value="'.$langs->trans("Calculate").'">';
print '</td>';
print '</tr>';
print '</table>';
print '</div>';
print '</form>';
print '<br>';
// Berechnungstabelle
print '<div class="div-table-responsive">';
print '<table class="noborder centpercent">';
print '<tr class="liste_titre">';
print '<th colspan="2">'.$langs->trans("GewerbesteuerBerechnung").' '.$jahr.'</th>';
print '<th class="right" style="width: 150px;">'.$langs->trans("Betrag").' EUR</th>';
print '</tr>';
// Gewinn aus EÜR
print '<tr class="oddeven">';
print '<td>1.</td>';
print '<td>'.$langs->trans("GewinnAusEUeR").'</td>';
$color = $gewinn_euer >= 0 ? '' : 'amountremaintopay';
print '<td class="right amount '.$color.'">'.price($gewinn_euer, 0, $langs, 1, 2, 2).'</td>';
print '</tr>';
// Hinzurechnungen
print '<tr class="oddeven">';
print '<td>2.</td>';
print '<td>'.$langs->trans("Hinzurechnungen").' (§ 8 GewStG)<br><small class="opacitymedium">z.B. Zinsen, Mieten, Pachten, Lizenzen (anteilig)</small></td>';
print '<td class="right amount">+ '.price($hinzurechnungen, 0, $langs, 1, 2, 2).'</td>';
print '</tr>';
// Kürzungen
print '<tr class="oddeven">';
print '<td>3.</td>';
print '<td>'.$langs->trans("Kuerzungen").' (§ 9 GewStG)<br><small class="opacitymedium">z.B. 1,2% des Einheitswerts bei Grundstücken</small></td>';
print '<td class="right amount">- '.price($kuerzungen, 0, $langs, 1, 2, 2).'</td>';
print '</tr>';
// Gewerbeertrag vor Freibetrag
print '<tr class="oddeven">';
print '<td>4.</td>';
print '<td><strong>'.$langs->trans("GewerbeertragVorFreibetrag").'</strong></td>';
print '<td class="right amount"><strong>'.price($gewerbeertrag_vor_freibetrag, 0, $langs, 1, 2, 2).'</strong></td>';
print '</tr>';
// Freibetrag
print '<tr class="oddeven">';
print '<td>5.</td>';
print '<td>'.$langs->trans("Freibetrag").'<br><small class="opacitymedium">'.$langs->trans("FreibetragHinweis").'</small></td>';
print '<td class="right amount">- '.price($freibetrag, 0, $langs, 1, 2, 2).'</td>';
print '</tr>';
// Gewerbeertrag
print '<tr class="liste_total">';
print '<td>6.</td>';
print '<td><strong>'.$langs->trans("Gewerbeertrag").'</strong></td>';
print '<td class="right amount"><strong>'.price($gewerbeertrag, 0, $langs, 1, 2, 2).'</strong></td>';
print '</tr>';
// Steuermessbetrag
print '<tr class="oddeven">';
print '<td>7.</td>';
print '<td>'.$langs->trans("Steuermessbetrag").' ('.$steuermesszahl.'%)</td>';
print '<td class="right amount">'.price($steuermessbetrag, 0, $langs, 1, 2, 2).'</td>';
print '</tr>';
// Hebesatz
print '<tr class="oddeven">';
print '<td>8.</td>';
print '<td>'.$langs->trans("Hebesatz").' der Gemeinde</td>';
print '<td class="right">'.$hebesatz.' %</td>';
print '</tr>';
// Gewerbesteuer
print '<tr class="liste_total">';
print '<td>9.</td>';
print '<td><strong>'.$langs->trans("Gewerbesteuer").'</strong> (Zeile 7 x Zeile 8 / 100)</td>';
print '<td class="right amount"><strong>'.price($gewerbesteuer, 0, $langs, 1, 2, 2).'</strong></td>';
print '</tr>';
print '</table>';
print '</div>';
print '<br>';
// Anrechnung auf Einkommensteuer
print '<div class="div-table-responsive-no-min">';
print '<table class="noborder centpercent">';
print '<tr class="liste_titre">';
print '<th colspan="2">'.$langs->trans("AnrechnungESt").' (§ 35 EStG)</th>';
print '</tr>';
print '<tr class="oddeven">';
print '<td>'.$langs->trans("Steuermessbetrag").' x 4 (maximale Anrechnung)</td>';
print '<td class="right amount">'.price($steuermessbetrag * 4, 0, $langs, 1, 2, 2).' EUR</td>';
print '</tr>';
print '<tr class="oddeven">';
print '<td>'.$langs->trans("TatsaechlicheGewerbesteuer").'</td>';
print '<td class="right amount">'.price($gewerbesteuer, 0, $langs, 1, 2, 2).' EUR</td>';
print '</tr>';
print '<tr class="liste_total">';
print '<td><strong>'.$langs->trans("AnrechenbareGewerbesteuer").'</strong><br><small class="opacitymedium">(der niedrigere Betrag)</small></td>';
print '<td class="right amount amountpaymentcomplete"><strong>'.price($anrechnung_est, 0, $langs, 1, 2, 2).' EUR</strong></td>';
print '</tr>';
print '<tr class="oddeven">';
print '<td><strong>'.$langs->trans("EffektiveGewerbesteuer").'</strong><br><small class="opacitymedium">(Gewerbesteuer - Anrechnung)</small></td>';
$effektiv_color = $gewerbesteuer_effektiv > 0 ? '' : 'amountpaymentcomplete';
print '<td class="right amount '.$effektiv_color.'"><strong>'.price($gewerbesteuer_effektiv, 0, $langs, 1, 2, 2).' EUR</strong></td>';
print '</tr>';
print '</table>';
print '</div>';
// Hinweise
print '<br>';
print '<div class="opacitymedium">';
print '<strong>'.$langs->trans("Hinweise").':</strong><br>';
print '- '.$langs->trans("GewerbesteuerHinweis1").'<br>';
print '- '.$langs->trans("GewerbesteuerHinweis2").'<br>';
print '- '.$langs->trans("GewerbesteuerHinweis3").'<br>';
print '- '.$langs->trans("GewerbesteuerHinweis4").'<br>';
print '</div>';
// Info-Box Hebesätze
print '<br>';
print '<div class="info">';
print '<strong>'.$langs->trans("HebesaetzeInfo").':</strong><br>';
print $langs->trans("HebesaetzeInfoText");
print '</div>';
// Zurück-Button
print '<br>';
print '<div class="tabsAction">';
print '<a class="butAction" href="'.dol_buildpath('/steuer/steuerindex.php', 1).'"><i class="fa fa-arrow-left paddingright"></i>'.$langs->trans("Back").'</a>';
print '</div>';
llxFooter();
$db->close();

14
img/README.md Executable file
View file

@ -0,0 +1,14 @@
Directory for module image files
--------------------------------
You can put here the .png files of your module:
If the picto of your module is an image (property $picto has been set to 'steuer.png@steuer', you can put into this
directory a .png file called *object_steuer.png* (16x16 or 32x32 pixels)
If the picto of an object is an image (property $picto of the object.class.php has been set to 'myobject.png@steuer', then you can put into this
directory a .png file called *object_myobject.png* (16x16 or 32x32 pixels)

164
konten.php Normal file
View file

@ -0,0 +1,164 @@
<?php
/**
* Kontenplan Verwaltung
*
* @package steuer
*/
// Load Dolibarr environment
$res = 0;
if (!$res && !empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) {
$res = @include $_SERVER["CONTEXT_DOCUMENT_ROOT"]."/main.inc.php";
}
$tmp = empty($_SERVER['SCRIPT_FILENAME']) ? '' : $_SERVER['SCRIPT_FILENAME'];
$tmp2 = realpath(__FILE__);
$i = strlen($tmp) - 1;
$j = strlen($tmp2) - 1;
while ($i > 0 && $j > 0 && isset($tmp[$i]) && isset($tmp2[$j]) && $tmp[$i] == $tmp2[$j]) {
$i--;
$j--;
}
if (!$res && $i > 0 && file_exists(substr($tmp, 0, ($i + 1))."/main.inc.php")) {
$res = @include substr($tmp, 0, ($i + 1))."/main.inc.php";
}
if (!$res && $i > 0 && file_exists(dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php")) {
$res = @include dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php";
}
if (!$res && file_exists("../main.inc.php")) {
$res = @include "../main.inc.php";
}
if (!$res && file_exists("../../main.inc.php")) {
$res = @include "../../main.inc.php";
}
if (!$res && file_exists("../../../main.inc.php")) {
$res = @include "../../../main.inc.php";
}
if (!$res) {
die("Include of main fails");
}
require_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php';
$langs->loadLangs(array("steuer@steuer", "bills", "compta"));
$action = GETPOST('action', 'aZ09');
$kategorie = GETPOST('kategorie', 'alpha');
/*
* View
*/
$form = new Form($db);
llxHeader('', $langs->trans("Kontenplan"), '', '', 0, 0, '', '', '', 'mod-steuer page-konten');
print load_fiche_titre($langs->trans("Kontenplan").' (SKR03)', '', 'steuer.png@steuer');
// Filter
print '<form method="POST" action="'.$_SERVER["PHP_SELF"].'">';
print '<input type="hidden" name="token" value="'.newToken().'">';
print '<div class="inline-block marginrightonly">';
print '<select name="kategorie" class="flat">';
print '<option value="">'.$langs->trans("All").'</option>';
print '<option value="einnahme"'.($kategorie == 'einnahme' ? ' selected' : '').'>'.$langs->trans("Einnahmen").'</option>';
print '<option value="ausgabe"'.($kategorie == 'ausgabe' ? ' selected' : '').'>'.$langs->trans("Ausgaben").'</option>';
print '</select>';
print ' <input type="submit" class="button" value="'.$langs->trans("Filter").'">';
print '</div>';
print '</form>';
print '<br>';
// Konten-Tabelle
print '<div class="div-table-responsive">';
print '<table class="noborder centpercent">';
print '<tr class="liste_titre">';
print '<th style="width: 100px;">'.$langs->trans("Kontonummer").'</th>';
print '<th>'.$langs->trans("Bezeichnung").'</th>';
print '<th style="width: 120px;">'.$langs->trans("Kategorie").'</th>';
print '<th style="width: 80px;">'.$langs->trans("EUeRZeile").'</th>';
print '<th style="width: 80px;">'.$langs->trans("UStKz").'</th>';
print '<th style="width: 80px;">'.$langs->trans("Status").'</th>';
print '</tr>';
$sql = "SELECT rowid, kontonummer, bezeichnung, kategorie, euer_zeile, ust_kennzeichen, aktiv";
$sql .= " FROM ".MAIN_DB_PREFIX."steuer_konto";
$sql .= " WHERE entity = ".((int) $conf->entity);
if ($kategorie) {
$sql .= " AND kategorie = '".$db->escape($kategorie)."'";
}
$sql .= " ORDER BY kontonummer";
$resql = $db->query($sql);
if ($resql) {
$num = $db->num_rows($resql);
if ($num > 0) {
$last_kategorie = '';
while ($obj = $db->fetch_object($resql)) {
// Zwischenüberschrift bei Kategoriewechsel
if ($obj->kategorie != $last_kategorie && empty($kategorie)) {
print '<tr class="liste_titre">';
print '<td colspan="6"><strong>'.($obj->kategorie == 'einnahme' ? $langs->trans("Einnahmekonten") : $langs->trans("Ausgabekonten")).'</strong></td>';
print '</tr>';
$last_kategorie = $obj->kategorie;
}
print '<tr class="oddeven">';
print '<td><strong>'.$obj->kontonummer.'</strong></td>';
print '<td>'.$obj->bezeichnung.'</td>';
print '<td>';
if ($obj->kategorie == 'einnahme') {
print '<span class="badge badge-status4">'.$langs->trans("Einnahme").'</span>';
} else {
print '<span class="badge badge-status1">'.$langs->trans("Ausgabe").'</span>';
}
print '</td>';
print '<td class="center">'.($obj->euer_zeile ? $obj->euer_zeile : '-').'</td>';
print '<td class="center">'.($obj->ust_kennzeichen ? 'Kz '.$obj->ust_kennzeichen : '-').'</td>';
print '<td class="center">';
if ($obj->aktiv) {
print '<span class="badge badge-status4">'.$langs->trans("Active").'</span>';
} else {
print '<span class="badge badge-status8">'.$langs->trans("Inactive").'</span>';
}
print '</td>';
print '</tr>';
}
} else {
print '<tr class="oddeven">';
print '<td colspan="6" class="center opacitymedium">'.$langs->trans("NoRecordFound").'</td>';
print '</tr>';
}
} else {
dol_print_error($db);
}
print '</table>';
print '</div>';
// Legende
print '<br>';
print '<div class="opacitymedium">';
print '<strong>'.$langs->trans("Legende").':</strong><br>';
print '<table class="nobordernopadding">';
print '<tr><td style="width:100px;"><strong>'.$langs->trans("EUeRZeile").':</strong></td><td>'.$langs->trans("EUeRZeileDesc").'</td></tr>';
print '<tr><td><strong>'.$langs->trans("UStKz").':</strong></td><td>'.$langs->trans("UStKzDesc").'</td></tr>';
print '</table>';
print '</div>';
// SKR03 Info
print '<br>';
print '<div class="info">';
print '<strong>'.$langs->trans("SKR03Info").':</strong><br>';
print $langs->trans("SKR03InfoText");
print '</div>';
// Zurück-Button
print '<br>';
print '<div class="tabsAction">';
print '<a class="butAction" href="'.dol_buildpath('/steuer/steuerindex.php', 1).'"><i class="fa fa-arrow-left paddingright"></i>'.$langs->trans("Back").'</a>';
print '</div>';
llxFooter();
$db->close();

170
langs/de_DE/steuer.lang Normal file
View file

@ -0,0 +1,170 @@
# Copyright (C) 2026 Eduard Wisch
#
# 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.
#
# Deutsche Sprachdatei für EÜR Modul
#
# Modul
#
ModuleSteuerName = EÜR Deutschland
ModuleSteuerDesc = Einnahmen-Überschuss-Rechnung für Deutschland - Steuerjahr 2025
#
# Admin/Setup
#
SteuerSetup = EÜR Einstellungen
SteuerAbout = Über EÜR Modul
Settings = Einstellungen
#
# Hauptnavigation
#
EUeRUebersicht = EÜR Übersicht
Buchungen = Buchungen
NeueBuchung = Neue Buchung
AnlageEUeR = Anlage EÜR
UStVA = USt-Voranmeldung
Gewerbesteuer = Gewerbesteuer
WISOExport = WISO Export
Kontenplan = Kontenplan
#
# Allgemein
#
Period = Zeitraum
SelectPeriod = Zeitraum wählen
WholeYear = Ganzes Jahr
QuickAccess = Schnellzugriff
Year = Jahr
Month = Monat
Summary = Zusammenfassung
Total = Summe
Amount = Betrag
Status = Status
Draft = Entwurf
Active = Aktiv
Inactive = Inaktiv
Calculate = Berechnen
Filter = Filtern
Export = Exportieren
PreviewData = Datenvorschau
#
# EÜR spezifisch
#
Einnahmen = Betriebseinnahmen
Ausgaben = Betriebsausgaben
Einnahme = Einnahme
Ausgabe = Ausgabe
TotalEinnahmen = Summe Einnahmen
TotalAusgaben = Summe Ausgaben
Gewinn = Gewinn
Verlust = Verlust
ErgebnisEUeR = EÜR Ergebnis
GewinnAusEUeR = Gewinn aus EÜR
#
# Buchungen
#
Buchung = Buchung
EditBuchung = Buchung bearbeiten
DeleteBuchung = Buchung löschen
ConfirmDeleteBuchung = Möchten Sie diese Buchung wirklich löschen?
BuchungCreated = Buchung wurde erstellt
BuchungUpdated = Buchung wurde aktualisiert
BuchungDeleted = Buchung wurde gelöscht
Belegnummer = Belegnummer
Typ = Art/Typ
Netto = Netto
Brutto = Brutto
#
# Umsatzsteuer
#
UmsatzsteuerVorsteuer = Umsatzsteuer / Vorsteuer
UmsatzsteuerGesamt = Umsatzsteuer gesamt
VorsteuerGesamt = Vorsteuer gesamt
Zahllast = USt-Zahllast
Erstattung = USt-Erstattung
Kz81 = Kz 81
Kz86 = Kz 86
Kz66 = Kz 66
USt19 = USt 19%
USt7 = USt 7%
UStVASummary = UStVA Zusammenfassung
KennzahlenErklaerung = Kennzahlen-Erklärung
#
# Gewerbesteuer
#
GewerbesteuerBerechnung = Gewerbesteuer-Berechnung
Hebesatz = Hebesatz
HebesatzHinweis = Gemeinde-Hebesatz (z.B. 400 für 400%)
Hinzurechnungen = Hinzurechnungen
HinzurechnungenHinweis = z.B. 25% der Zinsen, Mieten, Pachten, Lizenzen
Kuerzungen = Kürzungen
KuerzungenHinweis = z.B. 1,2% des Einheitswerts für Grundstücke
GewerbeertragVorFreibetrag = Gewerbeertrag vor Freibetrag
Freibetrag = Freibetrag
FreibetragHinweis = 24.500 EUR für Einzelunternehmen und Personengesellschaften
Gewerbeertrag = Gewerbeertrag
Steuermessbetrag = Steuermessbetrag
AnrechnungESt = Anrechnung auf Einkommensteuer
AnrechenbareGewerbesteuer = Anrechenbare Gewerbesteuer
TatsaechlicheGewerbesteuer = Tatsächliche Gewerbesteuer
EffektiveGewerbesteuer = Effektive Gewerbesteuer
Hinweise = Hinweise
GewerbesteuerHinweis1 = Der Freibetrag von 24.500 EUR gilt für Einzelunternehmen und Personengesellschaften
GewerbesteuerHinweis2 = Die Steuermesszahl beträgt einheitlich 3,5%
GewerbesteuerHinweis3 = Die Anrechnung auf die ESt ist auf das 4-fache des Steuermessbetrags begrenzt (§ 35 EStG)
GewerbesteuerHinweis4 = Der individuelle Hebesatz kann bei Ihrer Gemeinde erfragt werden
HebesaetzeInfo = Informationen zu Hebesätzen
HebesaetzeInfoText = Die Hebesätze variieren je nach Gemeinde. Typische Werte: Großstädte 400-500%, ländliche Gemeinden 300-400%. Den genauen Hebesatz Ihrer Gemeinde finden Sie im Grundsteuerbescheid oder direkt bei der Gemeinde.
#
# Anlage EÜR
#
Zeile = Zeile
Bezeichnung = Bezeichnung
Hinweis = Hinweis
EUeRHinweis1 = Die Beträge werden automatisch aus Ihren Dolibarr-Buchungen berechnet
EUeRHinweis2 = Für die offizielle Anlage EÜR prüfen Sie bitte alle Werte sorgfältig
EUeRHinweis3 = Exportieren Sie die Daten für WISO Steuer über den WISO Export
#
# WISO Export
#
ExportSettings = Export-Einstellungen
ExportFormat = Export-Format
ExportFormatInfo = Informationen zu den Export-Formaten
WISOEUeRFormat = WISO EÜR Format (CSV)
WISOEUeRFormatDesc = CSV-Datei mit allen Buchungen, kompatibel mit WISO Steuer für den Import der EÜR-Daten
DATEVFormat = DATEV Format (CSV)
DATEVFormatDesc = Vereinfachtes DATEV-Format für den Import in Buchhaltungssoftware
UStVACSV = UStVA Werte (CSV)
UStVACSVDesc = Monatliche UStVA-Kennzahlen als CSV für die manuelle Eingabe in ELSTER oder WISO
AndMore = und %s weitere
ExportHinweise = Export-Hinweise
ExportHinweis1 = Die exportierten Daten dienen als Grundlage für Ihre Steuersoftware
ExportHinweis2 = Prüfen Sie alle Werte vor der Übernahme in WISO Steuer
ExportHinweis3 = Bei Fragen wenden Sie sich an Ihren Steuerberater
WISOHinweis = ELSTER/WISO Hinweis
WISOExportHinweis = Für die elektronische Übermittlung der UStVA verwenden Sie bitte WISO Steuer oder Elster Online. Die hier angezeigten Werte können Sie in WISO Steuer übernehmen.
#
# Kontenplan
#
Kontonummer = Kontonummer
EUeRZeile = EÜR-Zeile
UStKz = USt-Kz
Einnahmekonten = Einnahmekonten
Ausgabekonten = Ausgabekonten
Legende = Legende
EUeRZeileDesc = Zeile in der offiziellen Anlage EÜR
UStKzDesc = Kennzahl für die Umsatzsteuer-Voranmeldung
SKR03Info = Über den Kontenrahmen
SKR03InfoText = Dieses Modul verwendet einen vereinfachten SKR03-Kontenrahmen, der für die EÜR optimiert ist. Die Konten sind den entsprechenden Zeilen der Anlage EÜR und den UStVA-Kennzahlen zugeordnet.

170
langs/en_US/steuer.lang Executable file
View file

@ -0,0 +1,170 @@
# Copyright (C) 2026 Eduard Wisch
#
# 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.
#
# English language file for EÜR Module (German Tax)
#
# Module
#
ModuleSteuerName = EÜR Germany
ModuleSteuerDesc = Income-Surplus Calculation for Germany - Tax Year 2025
#
# Admin/Setup
#
SteuerSetup = EÜR Settings
SteuerAbout = About EÜR Module
Settings = Settings
#
# Main Navigation
#
EUeRUebersicht = EÜR Overview
Buchungen = Transactions
NeueBuchung = New Transaction
AnlageEUeR = EÜR Report
UStVA = VAT Return
Gewerbesteuer = Trade Tax
WISOExport = WISO Export
Kontenplan = Chart of Accounts
#
# General
#
Period = Period
SelectPeriod = Select Period
WholeYear = Whole Year
QuickAccess = Quick Access
Year = Year
Month = Month
Summary = Summary
Total = Total
Amount = Amount
Status = Status
Draft = Draft
Active = Active
Inactive = Inactive
Calculate = Calculate
Filter = Filter
Export = Export
PreviewData = Data Preview
#
# EÜR specific
#
Einnahmen = Business Income
Ausgaben = Business Expenses
Einnahme = Income
Ausgabe = Expense
TotalEinnahmen = Total Income
TotalAusgaben = Total Expenses
Gewinn = Profit
Verlust = Loss
ErgebnisEUeR = EÜR Result
GewinnAusEUeR = Profit from EÜR
#
# Transactions
#
Buchung = Transaction
EditBuchung = Edit Transaction
DeleteBuchung = Delete Transaction
ConfirmDeleteBuchung = Do you really want to delete this transaction?
BuchungCreated = Transaction created
BuchungUpdated = Transaction updated
BuchungDeleted = Transaction deleted
Belegnummer = Receipt Number
Typ = Type
Netto = Net
Brutto = Gross
#
# VAT
#
UmsatzsteuerVorsteuer = VAT / Input Tax
UmsatzsteuerGesamt = Total VAT
VorsteuerGesamt = Total Input Tax
Zahllast = VAT Payable
Erstattung = VAT Refund
Kz81 = Kz 81
Kz86 = Kz 86
Kz66 = Kz 66
USt19 = VAT 19%
USt7 = VAT 7%
UStVASummary = VAT Return Summary
KennzahlenErklaerung = Key Figures Explanation
#
# Trade Tax
#
GewerbesteuerBerechnung = Trade Tax Calculation
Hebesatz = Assessment Rate
HebesatzHinweis = Municipal rate (e.g. 400 for 400%)
Hinzurechnungen = Add-backs
HinzurechnungenHinweis = e.g. 25% of interest, rent, royalties
Kuerzungen = Deductions
KuerzungenHinweis = e.g. 1.2% of property value
GewerbeertragVorFreibetrag = Trade Income before Allowance
Freibetrag = Allowance
FreibetragHinweis = EUR 24,500 for sole proprietors and partnerships
Gewerbeertrag = Trade Income
Steuermessbetrag = Tax Base Amount
AnrechnungESt = Credit against Income Tax
AnrechenbareGewerbesteuer = Creditable Trade Tax
TatsaechlicheGewerbesteuer = Actual Trade Tax
EffektiveGewerbesteuer = Effective Trade Tax
Hinweise = Notes
GewerbesteuerHinweis1 = The EUR 24,500 allowance applies to sole proprietors and partnerships
GewerbesteuerHinweis2 = The tax multiplier is uniformly 3.5%
GewerbesteuerHinweis3 = Income tax credit is limited to 4x the tax base amount (§ 35 EStG)
GewerbesteuerHinweis4 = The specific assessment rate can be obtained from your municipality
HebesaetzeInfo = Assessment Rate Information
HebesaetzeInfoText = Assessment rates vary by municipality. Typical values: major cities 400-500%, rural municipalities 300-400%. Find your exact rate in your property tax notice or contact your municipality.
#
# EÜR Report
#
Zeile = Line
Bezeichnung = Description
Hinweis = Note
EUeRHinweis1 = Amounts are automatically calculated from your Dolibarr transactions
EUeRHinweis2 = Please verify all values carefully for the official EÜR report
EUeRHinweis3 = Export data for WISO Steuer via the WISO Export
#
# WISO Export
#
ExportSettings = Export Settings
ExportFormat = Export Format
ExportFormatInfo = Export Format Information
WISOEUeRFormat = WISO EÜR Format (CSV)
WISOEUeRFormatDesc = CSV file with all transactions, compatible with WISO Steuer for EÜR data import
DATEVFormat = DATEV Format (CSV)
DATEVFormatDesc = Simplified DATEV format for import into accounting software
UStVACSV = VAT Return Values (CSV)
UStVACSVDesc = Monthly VAT return key figures as CSV for manual entry in ELSTER or WISO
AndMore = and %s more
ExportHinweise = Export Notes
ExportHinweis1 = The exported data serves as a basis for your tax software
ExportHinweis2 = Verify all values before importing into WISO Steuer
ExportHinweis3 = Consult your tax advisor for questions
WISOHinweis = ELSTER/WISO Note
WISOExportHinweis = For electronic VAT return submission, please use WISO Steuer or Elster Online. The values shown here can be imported into WISO Steuer.
#
# Chart of Accounts
#
Kontonummer = Account Number
EUeRZeile = EÜR Line
UStKz = VAT Code
Einnahmekonten = Income Accounts
Ausgabekonten = Expense Accounts
Legende = Legend
EUeRZeileDesc = Line in the official EÜR report
UStKzDesc = Key figure for VAT return
SKR03Info = About the Chart of Accounts
SKR03InfoText = This module uses a simplified SKR03 chart of accounts optimized for EÜR. Accounts are assigned to the corresponding EÜR report lines and VAT return key figures.

85
lib/steuer.lib.php Executable file
View file

@ -0,0 +1,85 @@
<?php
/* Copyright (C) 2026 Eduard Wisch <data@data-it-solution.de>
*
* 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/>.
*/
/**
* \file steuer/lib/steuer.lib.php
* \ingroup steuer
* \brief Library files with common functions for Steuer
*/
/**
* Prepare admin pages header
*
* @return array<array{string,string,string}>
*/
function steuerAdminPrepareHead()
{
global $langs, $conf;
// global $db;
// $extrafields = new ExtraFields($db);
// $extrafields->fetch_name_optionals_label('myobject');
$langs->load("steuer@steuer");
$h = 0;
$head = array();
$head[$h][0] = dol_buildpath("/steuer/admin/setup.php", 1);
$head[$h][1] = $langs->trans("Settings");
$head[$h][2] = 'settings';
$h++;
/*
$head[$h][0] = dol_buildpath("/steuer/admin/myobject_extrafields.php", 1);
$head[$h][1] = $langs->trans("ExtraFields");
$nbExtrafields = (isset($extrafields->attributes['myobject']['label']) && is_countable($extrafields->attributes['myobject']['label'])) ? count($extrafields->attributes['myobject']['label']) : 0;
if ($nbExtrafields > 0) {
$head[$h][1] .= '<span class="badge marginleftonlyshort">' . $nbExtrafields . '</span>';
}
$head[$h][2] = 'myobject_extrafields';
$h++;
$head[$h][0] = dol_buildpath("/steuer/admin/myobjectline_extrafields.php", 1);
$head[$h][1] = $langs->trans("ExtraFieldsLines");
$nbExtrafields = (isset($extrafields->attributes['myobjectline']['label']) && is_countable($extrafields->attributes['myobjectline']['label'])) ? count($extrafields->attributes['myobject']['label']) : 0;
if ($nbExtrafields > 0) {
$head[$h][1] .= '<span class="badge marginleftonlyshort">' . $nbExtrafields . '</span>';
}
$head[$h][2] = 'myobject_extrafieldsline';
$h++;
*/
$head[$h][0] = dol_buildpath("/steuer/admin/about.php", 1);
$head[$h][1] = $langs->trans("About");
$head[$h][2] = 'about';
$h++;
// Show more tabs from modules
// Entries must be declared in modules descriptor with line
//$this->tabs = array(
// 'entity:+tabname:Title:@steuer:/steuer/mypage.php?id=__ID__'
//); // to add new tab
//$this->tabs = array(
// 'entity:-tabname:Title:@steuer:/steuer/mypage.php?id=__ID__'
//); // to remove a tab
complete_head_from_modules($conf, $langs, null, $head, $h, 'steuer@steuer');
complete_head_from_modules($conf, $langs, null, $head, $h, 'steuer@steuer', 'remove');
return $head;
}

3
modulebuilder.txt Executable file
View file

@ -0,0 +1,3 @@
# DO NOT DELETE THIS FILE MANUALLY
# File to flag module built using official module template.
# When this file is present into a module directory, you can edit it with the module builder tool.

83
sql/data.sql Normal file
View file

@ -0,0 +1,83 @@
-- Copyright (C) 2026 Eduard Wisch
-- Standard EÜR-Konten nach SKR03
-- EINNAHMEN
INSERT IGNORE INTO llx_steuer_konto (kontonummer, bezeichnung, kategorie, euer_zeile, ust_kennzeichen, entity) VALUES
('8400', 'Erlöse 19% USt', 'einnahme', 14, '81', 1),
('8300', 'Erlöse 7% USt', 'einnahme', 14, '86', 1),
('8100', 'Steuerfreie Umsätze Inland', 'einnahme', 10, NULL, 1),
('8120', 'Steuerfreie igL', 'einnahme', 11, '41', 1),
('8150', 'Steuerfreie Ausfuhrlieferungen', 'einnahme', 12, '44', 1),
('8200', 'Erlöse ohne USt §19', 'einnahme', 14, NULL, 1),
('8500', 'Provisionserlöse', 'einnahme', 14, '81', 1),
('8600', 'Sonstige Erlöse', 'einnahme', 16, '81', 1),
('8700', 'Erlöse aus VuV', 'einnahme', 17, NULL, 1),
('8800', 'Zinserträge', 'einnahme', 18, NULL, 1),
('8900', 'Privatentnahmen Sachen', 'einnahme', 19, '81', 1),
('8910', 'Private Kfz-Nutzung', 'einnahme', 19, '81', 1),
('8920', 'Private Telefonnutzung', 'einnahme', 19, '81', 1);
-- AUSGABEN - Wareneinkauf
INSERT IGNORE INTO llx_steuer_konto (kontonummer, bezeichnung, kategorie, euer_zeile, ust_kennzeichen, entity) VALUES
('3400', 'Wareneingang 19% VSt', 'ausgabe', 26, '66', 1),
('3300', 'Wareneingang 7% VSt', 'ausgabe', 26, '66', 1),
('3100', 'Wareneingang steuerfrei', 'ausgabe', 26, NULL, 1);
-- AUSGABEN - Personal
INSERT IGNORE INTO llx_steuer_konto (kontonummer, bezeichnung, kategorie, euer_zeile, ust_kennzeichen, entity) VALUES
('4100', 'Löhne und Gehälter', 'ausgabe', 31, NULL, 1),
('4130', 'Gesetzliche Sozialaufwendungen', 'ausgabe', 32, NULL, 1),
('4140', 'Freiwillige Sozialaufwendungen', 'ausgabe', 33, NULL, 1);
-- AUSGABEN - Raumkosten
INSERT IGNORE INTO llx_steuer_konto (kontonummer, bezeichnung, kategorie, euer_zeile, ust_kennzeichen, entity) VALUES
('4200', 'Raumkosten/Miete', 'ausgabe', 34, '66', 1),
('4210', 'Miete Geschäftsräume', 'ausgabe', 34, '66', 1),
('4230', 'Heizung', 'ausgabe', 34, '66', 1),
('4240', 'Gas, Strom, Wasser', 'ausgabe', 34, '66', 1),
('4250', 'Reinigung', 'ausgabe', 34, '66', 1),
('4260', 'Instandhaltung Räume', 'ausgabe', 34, '66', 1);
-- AUSGABEN - Sonstige Betriebsausgaben
INSERT IGNORE INTO llx_steuer_konto (kontonummer, bezeichnung, kategorie, euer_zeile, ust_kennzeichen, entity) VALUES
('4500', 'Fahrzeugkosten', 'ausgabe', 51, '66', 1),
('4510', 'Kfz-Steuer', 'ausgabe', 51, NULL, 1),
('4520', 'Kfz-Versicherung', 'ausgabe', 51, NULL, 1),
('4530', 'Kraftstoff', 'ausgabe', 51, '66', 1),
('4540', 'Kfz-Reparaturen', 'ausgabe', 51, '66', 1),
('4580', 'Sonstige Kfz-Kosten', 'ausgabe', 51, '66', 1),
('4600', 'Werbekosten', 'ausgabe', 53, '66', 1),
('4610', 'Geschenke abzugsfähig', 'ausgabe', 54, '66', 1),
('4630', 'Geschenke nicht abzugsfähig', 'ausgabe', 55, '66', 1),
('4650', 'Bewirtungskosten 70%', 'ausgabe', 56, '66', 1),
('4660', 'Reisekosten Unternehmer', 'ausgabe', 57, NULL, 1),
('4670', 'Reisekosten Arbeitnehmer', 'ausgabe', 58, '66', 1),
('4700', 'Porto', 'ausgabe', 49, '66', 1),
('4710', 'Telefon', 'ausgabe', 49, '66', 1),
('4750', 'Bürobedarf', 'ausgabe', 49, '66', 1),
('4780', 'Fremdleistungen', 'ausgabe', 49, '66', 1),
('4790', 'Sonstige Betriebsausgaben', 'ausgabe', 49, '66', 1),
('4800', 'Reparatur/Instandhaltung', 'ausgabe', 39, '66', 1),
('4830', 'Versicherungen', 'ausgabe', 46, NULL, 1),
('4840', 'Beiträge IHK/Verbände', 'ausgabe', 47, NULL, 1),
('4850', 'Fortbildungskosten', 'ausgabe', 48, '66', 1),
('4900', 'Rechts- und Beratungskosten', 'ausgabe', 50, '66', 1),
('4910', 'Buchführungskosten', 'ausgabe', 50, '66', 1),
('4920', 'Jahresabschlusskosten', 'ausgabe', 50, '66', 1),
('4940', 'Bankgebühren', 'ausgabe', 48, NULL, 1),
('4950', 'Nebenkosten Geldverkehr', 'ausgabe', 48, NULL, 1),
('4960', 'Miete für Einrichtungen', 'ausgabe', 38, '66', 1),
('4970', 'Leasing', 'ausgabe', 38, '66', 1),
('4980', 'Software/Lizenzen', 'ausgabe', 39, '66', 1);
-- AUSGABEN - AfA
INSERT IGNORE INTO llx_steuer_konto (kontonummer, bezeichnung, kategorie, euer_zeile, ust_kennzeichen, entity) VALUES
('4820', 'AfA Sachanlagen', 'ausgabe', 36, NULL, 1),
('4822', 'AfA immaterielle WG', 'ausgabe', 37, NULL, 1),
('4824', 'AfA GWG', 'ausgabe', 38, NULL, 1),
('4826', 'Sonderabschreibungen', 'ausgabe', 38, NULL, 1);
-- AUSGABEN - Zinsen
INSERT IGNORE INTO llx_steuer_konto (kontonummer, bezeichnung, kategorie, euer_zeile, ust_kennzeichen, entity) VALUES
('2100', 'Zinsaufwendungen', 'ausgabe', 45, NULL, 1),
('2110', 'Zinsen langfristige Darlehen', 'ausgabe', 45, NULL, 1);

202
sql/dolibarr_allversions.sql Executable file
View file

@ -0,0 +1,202 @@
--
-- Script run when an upgrade of Dolibarr is done. Whatever is the Dolibarr version.
-- EÜR Modul für Deutschland 2025
--
-- ============================================================================
-- Kontenrahmen (SKR03 basiert für EÜR)
-- ============================================================================
CREATE TABLE IF NOT EXISTS llx_steuer_konto (
rowid INTEGER AUTO_INCREMENT PRIMARY KEY,
kontonummer VARCHAR(10) NOT NULL,
bezeichnung VARCHAR(255) NOT NULL,
kategorie VARCHAR(50) NOT NULL, -- 'einnahme', 'ausgabe', 'ust', 'vorsteuer'
euer_zeile INTEGER DEFAULT NULL, -- Zeile in Anlage EÜR
ust_kennzeichen VARCHAR(10) DEFAULT NULL, -- USt-Kennzeichen für UStVA
aktiv TINYINT(1) DEFAULT 1,
entity INTEGER DEFAULT 1,
UNIQUE KEY uk_konto_nummer (kontonummer, entity)
) ENGINE=InnoDB;
-- ============================================================================
-- EÜR Buchungen
-- ============================================================================
CREATE TABLE IF NOT EXISTS llx_steuer_buchung (
rowid INTEGER AUTO_INCREMENT PRIMARY KEY,
ref VARCHAR(30) NOT NULL, -- Buchungsnummer
datum DATE NOT NULL, -- Belegdatum
belegnummer VARCHAR(50) DEFAULT NULL, -- Externe Belegnummer
beschreibung VARCHAR(255) NOT NULL,
fk_konto INTEGER NOT NULL, -- Verweis auf llx_steuer_konto
betrag_netto DOUBLE(24,8) DEFAULT 0,
betrag_ust DOUBLE(24,8) DEFAULT 0, -- USt/VSt Betrag
betrag_brutto DOUBLE(24,8) DEFAULT 0,
ust_satz DOUBLE(5,2) DEFAULT 0, -- 0, 7, 19
typ VARCHAR(20) NOT NULL, -- 'einnahme', 'ausgabe'
zahlungsart VARCHAR(30) DEFAULT NULL, -- 'bar', 'bank', 'paypal', etc.
fk_soc INTEGER DEFAULT NULL, -- Verknüpfung zu Kunde/Lieferant
fk_facture INTEGER DEFAULT NULL, -- Verknüpfung zu Rechnung
fk_facture_fourn INTEGER DEFAULT NULL, -- Verknüpfung zu Lieferantenrechnung
note_private TEXT,
date_creation DATETIME,
tms TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
fk_user_creat INTEGER,
fk_user_modif INTEGER,
status TINYINT(4) DEFAULT 1, -- 0=Entwurf, 1=Gebucht
entity INTEGER DEFAULT 1,
INDEX idx_buchung_datum (datum),
INDEX idx_buchung_konto (fk_konto),
INDEX idx_buchung_typ (typ),
INDEX idx_buchung_ref (ref)
) ENGINE=InnoDB;
-- ============================================================================
-- USt-Voranmeldung Perioden
-- ============================================================================
CREATE TABLE IF NOT EXISTS llx_steuer_ustva (
rowid INTEGER AUTO_INCREMENT PRIMARY KEY,
jahr INTEGER NOT NULL,
periode VARCHAR(10) NOT NULL, -- '01'-'12' für Monat, 'Q1'-'Q4' für Quartal
periode_typ VARCHAR(10) NOT NULL, -- 'monat' oder 'quartal'
-- Lieferungen und Leistungen
kz81 DOUBLE(24,8) DEFAULT 0, -- Steuerpfl. Umsätze 19%
kz86 DOUBLE(24,8) DEFAULT 0, -- Steuerpfl. Umsätze 7%
kz35 DOUBLE(24,8) DEFAULT 0, -- Steuerpfl. Umsätze andere Sätze
kz36 DOUBLE(24,8) DEFAULT 0, -- USt auf Kz35
-- Steuerfreie Umsätze
kz41 DOUBLE(24,8) DEFAULT 0, -- Innergemeinschaftl. Lieferungen
kz44 DOUBLE(24,8) DEFAULT 0, -- Steuerfreie Ausfuhrlieferungen
-- Vorsteuer
kz66 DOUBLE(24,8) DEFAULT 0, -- Vorsteuer aus Rechnungen
kz61 DOUBLE(24,8) DEFAULT 0, -- Vorsteuer aus igE
kz67 DOUBLE(24,8) DEFAULT 0, -- Vorsteuer nach § 13b
-- Berechnung
ust_summe DOUBLE(24,8) DEFAULT 0, -- Summe USt
vst_summe DOUBLE(24,8) DEFAULT 0, -- Summe VSt
zahllast DOUBLE(24,8) DEFAULT 0, -- USt - VSt (positiv = Zahllast)
status TINYINT(4) DEFAULT 0, -- 0=Entwurf, 1=Berechnet, 2=Übermittelt
uebermittelt_am DATE DEFAULT NULL,
note_private TEXT,
date_creation DATETIME,
tms TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
fk_user_creat INTEGER,
entity INTEGER DEFAULT 1,
UNIQUE KEY uk_periode (jahr, periode, entity)
) ENGINE=InnoDB;
-- ============================================================================
-- Gewerbesteuer
-- ============================================================================
CREATE TABLE IF NOT EXISTS llx_steuer_gewerbe (
rowid INTEGER AUTO_INCREMENT PRIMARY KEY,
jahr INTEGER NOT NULL,
gewinn_euer DOUBLE(24,8) DEFAULT 0, -- Gewinn aus EÜR
hinzurechnungen DOUBLE(24,8) DEFAULT 0, -- § 8 GewStG
kuerzungen DOUBLE(24,8) DEFAULT 0, -- § 9 GewStG
gewerbeertrag DOUBLE(24,8) DEFAULT 0, -- Nach Freibetrag
freibetrag DOUBLE(24,8) DEFAULT 24500, -- Freibetrag Einzelunternehmen
hebesatz DOUBLE(5,2) DEFAULT 400, -- Gemeinde-Hebesatz in %
steuermessbetrag DOUBLE(24,8) DEFAULT 0,
gewerbesteuer DOUBLE(24,8) DEFAULT 0,
anrechnung_est DOUBLE(24,8) DEFAULT 0, -- Anrechnung auf ESt
status TINYINT(4) DEFAULT 0,
note_private TEXT,
date_creation DATETIME,
tms TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
fk_user_creat INTEGER,
entity INTEGER DEFAULT 1,
UNIQUE KEY uk_jahr (jahr, entity)
) ENGINE=InnoDB;
-- ============================================================================
-- Standard EÜR-Konten nach SKR03 einfügen
-- ============================================================================
-- EINNAHMEN
INSERT IGNORE INTO llx_steuer_konto (kontonummer, bezeichnung, kategorie, euer_zeile, ust_kennzeichen) VALUES
('8400', 'Erlöse 19% USt', 'einnahme', 14, '81'),
('8300', 'Erlöse 7% USt', 'einnahme', 14, '86'),
('8100', 'Steuerfreie Umsätze Inland', 'einnahme', 10, NULL),
('8120', 'Steuerfreie igL', 'einnahme', 11, '41'),
('8150', 'Steuerfreie Ausfuhrlieferungen', 'einnahme', 12, '44'),
('8200', 'Erlöse ohne USt §19', 'einnahme', 14, NULL),
('8500', 'Provisionserlöse', 'einnahme', 14, '81'),
('8600', 'Sonstige Erlöse', 'einnahme', 16, '81'),
('8700', 'Erlöse aus VuV', 'einnahme', 17, NULL),
('8800', 'Zinserträge', 'einnahme', 18, NULL),
('8900', 'Privatentnahmen Sachen', 'einnahme', 19, '81'),
('8910', 'Private Kfz-Nutzung', 'einnahme', 19, '81'),
('8920', 'Private Telefonnutzung', 'einnahme', 19, '81');
-- AUSGABEN - Wareneinkauf
INSERT IGNORE INTO llx_steuer_konto (kontonummer, bezeichnung, kategorie, euer_zeile, ust_kennzeichen) VALUES
('3400', 'Wareneingang 19% VSt', 'ausgabe', 26, '66'),
('3300', 'Wareneingang 7% VSt', 'ausgabe', 26, '66'),
('3100', 'Wareneingang steuerfrei', 'ausgabe', 26, NULL);
-- AUSGABEN - Personal
INSERT IGNORE INTO llx_steuer_konto (kontonummer, bezeichnung, kategorie, euer_zeile, ust_kennzeichen) VALUES
('4100', 'Löhne und Gehälter', 'ausgabe', 31, NULL),
('4130', 'Gesetzliche Sozialaufwendungen', 'ausgabe', 32, NULL),
('4140', 'Freiwillige Sozialaufwendungen', 'ausgabe', 33, NULL);
-- AUSGABEN - Raumkosten
INSERT IGNORE INTO llx_steuer_konto (kontonummer, bezeichnung, kategorie, euer_zeile, ust_kennzeichen) VALUES
('4200', 'Raumkosten/Miete', 'ausgabe', 34, '66'),
('4210', 'Miete Geschäftsräume', 'ausgabe', 34, '66'),
('4230', 'Heizung', 'ausgabe', 34, '66'),
('4240', 'Gas, Strom, Wasser', 'ausgabe', 34, '66'),
('4250', 'Reinigung', 'ausgabe', 34, '66'),
('4260', 'Instandhaltung Räume', 'ausgabe', 34, '66');
-- AUSGABEN - Sonstige Betriebsausgaben
INSERT IGNORE INTO llx_steuer_konto (kontonummer, bezeichnung, kategorie, euer_zeile, ust_kennzeichen) VALUES
('4500', 'Fahrzeugkosten', 'ausgabe', 51, '66'),
('4510', 'Kfz-Steuer', 'ausgabe', 51, NULL),
('4520', 'Kfz-Versicherung', 'ausgabe', 51, NULL),
('4530', 'Kraftstoff', 'ausgabe', 51, '66'),
('4540', 'Kfz-Reparaturen', 'ausgabe', 51, '66'),
('4580', 'Sonstige Kfz-Kosten', 'ausgabe', 51, '66'),
('4600', 'Werbekosten', 'ausgabe', 53, '66'),
('4610', 'Geschenke abzugsfähig', 'ausgabe', 54, '66'),
('4630', 'Geschenke nicht abzugsfähig', 'ausgabe', 55, '66'),
('4650', 'Bewirtungskosten 70%', 'ausgabe', 56, '66'),
('4660', 'Reisekosten Unternehmer', 'ausgabe', 57, NULL),
('4670', 'Reisekosten Arbeitnehmer', 'ausgabe', 58, '66'),
('4700', 'Porto', 'ausgabe', 49, '66'),
('4710', 'Telefon', 'ausgabe', 49, '66'),
('4750', 'Bürobedarf', 'ausgabe', 49, '66'),
('4780', 'Fremdleistungen', 'ausgabe', 49, '66'),
('4790', 'Sonstige Betriebsausgaben', 'ausgabe', 49, '66'),
('4800', 'Reparatur/Instandhaltung', 'ausgabe', 39, '66'),
('4830', 'Versicherungen', 'ausgabe', 46, NULL),
('4840', 'Beiträge IHK/Verbände', 'ausgabe', 47, NULL),
('4850', 'Fortbildungskosten', 'ausgabe', 48, '66'),
('4900', 'Rechts- und Beratungskosten', 'ausgabe', 50, '66'),
('4910', 'Buchführungskosten', 'ausgabe', 50, '66'),
('4920', 'Jahresabschlusskosten', 'ausgabe', 50, '66'),
('4940', 'Bankgebühren', 'ausgabe', 48, NULL),
('4950', 'Nebenkosten Geldverkehr', 'ausgabe', 48, NULL),
('4960', 'Miete für Einrichtungen', 'ausgabe', 38, '66'),
('4970', 'Leasing', 'ausgabe', 38, '66'),
('4980', 'Software/Lizenzen', 'ausgabe', 39, '66');
-- AUSGABEN - AfA
INSERT IGNORE INTO llx_steuer_konto (kontonummer, bezeichnung, kategorie, euer_zeile, ust_kennzeichen) VALUES
('4820', 'AfA Sachanlagen', 'ausgabe', 36, NULL),
('4822', 'AfA immaterielle WG', 'ausgabe', 37, NULL),
('4824', 'AfA GWG', 'ausgabe', 38, NULL),
('4826', 'Sonderabschreibungen', 'ausgabe', 38, NULL);
-- AUSGABEN - Zinsen
INSERT IGNORE INTO llx_steuer_konto (kontonummer, bezeichnung, kategorie, euer_zeile, ust_kennzeichen) VALUES
('2100', 'Zinsaufwendungen', 'ausgabe', 45, NULL),
('2110', 'Zinsen langfristige Darlehen', 'ausgabe', 45, NULL);

View file

@ -0,0 +1,7 @@
-- Copyright (C) 2026 Eduard Wisch
-- Keys/Indexes for llx_steuer_buchung
ALTER TABLE llx_steuer_buchung ADD INDEX idx_buchung_datum (datum);
ALTER TABLE llx_steuer_buchung ADD INDEX idx_buchung_konto (fk_konto);
ALTER TABLE llx_steuer_buchung ADD INDEX idx_buchung_typ (typ);
ALTER TABLE llx_steuer_buchung ADD INDEX idx_buchung_ref (ref);

View file

@ -0,0 +1,27 @@
-- Copyright (C) 2026 Eduard Wisch
-- Table for EÜR Buchungen
CREATE TABLE IF NOT EXISTS llx_steuer_buchung (
rowid INTEGER AUTO_INCREMENT PRIMARY KEY,
ref VARCHAR(30) NOT NULL,
datum DATE NOT NULL,
belegnummer VARCHAR(50) DEFAULT NULL,
beschreibung VARCHAR(255) NOT NULL,
fk_konto INTEGER NOT NULL,
betrag_netto DOUBLE(24,8) DEFAULT 0,
betrag_ust DOUBLE(24,8) DEFAULT 0,
betrag_brutto DOUBLE(24,8) DEFAULT 0,
ust_satz DOUBLE(5,2) DEFAULT 0,
typ VARCHAR(20) NOT NULL,
zahlungsart VARCHAR(30) DEFAULT NULL,
fk_soc INTEGER DEFAULT NULL,
fk_facture INTEGER DEFAULT NULL,
fk_facture_fourn INTEGER DEFAULT NULL,
note_private TEXT,
date_creation DATETIME,
tms TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
fk_user_creat INTEGER,
fk_user_modif INTEGER,
status TINYINT(4) DEFAULT 1,
entity INTEGER DEFAULT 1
) ENGINE=InnoDB;

View file

@ -0,0 +1,23 @@
-- Copyright (C) 2026 Eduard Wisch
-- Table for Gewerbesteuer
CREATE TABLE IF NOT EXISTS llx_steuer_gewerbe (
rowid INTEGER AUTO_INCREMENT PRIMARY KEY,
jahr INTEGER NOT NULL,
gewinn_euer DOUBLE(24,8) DEFAULT 0,
hinzurechnungen DOUBLE(24,8) DEFAULT 0,
kuerzungen DOUBLE(24,8) DEFAULT 0,
gewerbeertrag DOUBLE(24,8) DEFAULT 0,
freibetrag DOUBLE(24,8) DEFAULT 24500,
hebesatz DOUBLE(5,2) DEFAULT 400,
steuermessbetrag DOUBLE(24,8) DEFAULT 0,
gewerbesteuer DOUBLE(24,8) DEFAULT 0,
anrechnung_est DOUBLE(24,8) DEFAULT 0,
status TINYINT(4) DEFAULT 0,
note_private TEXT,
date_creation DATETIME,
tms TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
fk_user_creat INTEGER,
entity INTEGER DEFAULT 1,
UNIQUE KEY uk_jahr (jahr, entity)
) ENGINE=InnoDB;

View file

@ -0,0 +1,2 @@
-- Copyright (C) 2026 Eduard Wisch
-- Keys/Indexes for llx_steuer_konto (none additional needed)

14
sql/llx_steuer_konto.sql Normal file
View file

@ -0,0 +1,14 @@
-- Copyright (C) 2026 Eduard Wisch
-- Table for EÜR Kontenrahmen (SKR03)
CREATE TABLE IF NOT EXISTS llx_steuer_konto (
rowid INTEGER AUTO_INCREMENT PRIMARY KEY,
kontonummer VARCHAR(10) NOT NULL,
bezeichnung VARCHAR(255) NOT NULL,
kategorie VARCHAR(50) NOT NULL,
euer_zeile INTEGER DEFAULT NULL,
ust_kennzeichen VARCHAR(10) DEFAULT NULL,
aktiv TINYINT(1) DEFAULT 1,
entity INTEGER DEFAULT 1,
UNIQUE KEY uk_konto_nummer (kontonummer, entity)
) ENGINE=InnoDB;

29
sql/llx_steuer_ustva.sql Normal file
View file

@ -0,0 +1,29 @@
-- Copyright (C) 2026 Eduard Wisch
-- Table for USt-Voranmeldung Perioden
CREATE TABLE IF NOT EXISTS llx_steuer_ustva (
rowid INTEGER AUTO_INCREMENT PRIMARY KEY,
jahr INTEGER NOT NULL,
periode VARCHAR(10) NOT NULL,
periode_typ VARCHAR(10) NOT NULL,
kz81 DOUBLE(24,8) DEFAULT 0,
kz86 DOUBLE(24,8) DEFAULT 0,
kz35 DOUBLE(24,8) DEFAULT 0,
kz36 DOUBLE(24,8) DEFAULT 0,
kz41 DOUBLE(24,8) DEFAULT 0,
kz44 DOUBLE(24,8) DEFAULT 0,
kz66 DOUBLE(24,8) DEFAULT 0,
kz61 DOUBLE(24,8) DEFAULT 0,
kz67 DOUBLE(24,8) DEFAULT 0,
ust_summe DOUBLE(24,8) DEFAULT 0,
vst_summe DOUBLE(24,8) DEFAULT 0,
zahllast DOUBLE(24,8) DEFAULT 0,
status TINYINT(4) DEFAULT 0,
uebermittelt_am DATE DEFAULT NULL,
note_private TEXT,
date_creation DATETIME,
tms TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
fk_user_creat INTEGER,
entity INTEGER DEFAULT 1,
UNIQUE KEY uk_periode (jahr, periode, entity)
) ENGINE=InnoDB;

279
steuerindex.php Executable file
View file

@ -0,0 +1,279 @@
<?php
/* Copyright (C) 2001-2005 Rodolphe Quiedeville <rodolphe@quiedeville.org>
* Copyright (C) 2004-2015 Laurent Destailleur <eldy@users.sourceforge.net>
* Copyright (C) 2005-2012 Regis Houssin <regis.houssin@inodbox.com>
* Copyright (C) 2015 Jean-François Ferry <jfefe@aternatik.fr>
* Copyright (C) 2024 Frédéric France <frederic.france@free.fr>
* Copyright (C) 2026 Eduard Wisch <data@data-it-solution.de>
*
* 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/>.
*/
/**
* \file steuer/steuerindex.php
* \ingroup steuer
* \brief EÜR Übersicht - Einnahmen-Überschuss-Rechnung für Deutschland
*/
// Load Dolibarr environment
$res = 0;
if (!$res && !empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) {
$res = @include $_SERVER["CONTEXT_DOCUMENT_ROOT"]."/main.inc.php";
}
$tmp = empty($_SERVER['SCRIPT_FILENAME']) ? '' : $_SERVER['SCRIPT_FILENAME'];
$tmp2 = realpath(__FILE__);
$i = strlen($tmp) - 1;
$j = strlen($tmp2) - 1;
while ($i > 0 && $j > 0 && isset($tmp[$i]) && isset($tmp2[$j]) && $tmp[$i] == $tmp2[$j]) {
$i--;
$j--;
}
if (!$res && $i > 0 && file_exists(substr($tmp, 0, ($i + 1))."/main.inc.php")) {
$res = @include substr($tmp, 0, ($i + 1))."/main.inc.php";
}
if (!$res && $i > 0 && file_exists(dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php")) {
$res = @include dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php";
}
if (!$res && file_exists("../main.inc.php")) {
$res = @include "../main.inc.php";
}
if (!$res && file_exists("../../main.inc.php")) {
$res = @include "../../main.inc.php";
}
if (!$res && file_exists("../../../main.inc.php")) {
$res = @include "../../../main.inc.php";
}
if (!$res) {
die("Include of main fails");
}
require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
dol_include_once('/steuer/class/euer.class.php');
/**
* @var Conf $conf
* @var DoliDB $db
* @var HookManager $hookmanager
* @var Translate $langs
* @var User $user
*/
// Load translation files required by the page
$langs->loadLangs(array("steuer@steuer", "bills", "compta"));
$action = GETPOST('action', 'aZ09');
$jahr = GETPOSTINT('jahr');
if (empty($jahr)) {
$jahr = date('Y');
}
$monat = GETPOSTINT('monat');
$now = dol_now();
// Security check
$socid = GETPOSTINT('socid');
if (!empty($user->socid) && $user->socid > 0) {
$action = '';
$socid = $user->socid;
}
/*
* Actions
*/
// None
/*
* View
*/
$form = new Form($db);
$formfile = new FormFile($db);
$euer = new EUeR($db);
// Berechne EÜR
if ($monat > 0) {
$euer->berechneAusDolibarr($jahr, $monat, $monat);
$periode_text = $langs->trans("Month")." ".dol_print_date(mktime(0, 0, 0, $monat, 1, $jahr), '%B %Y');
} else {
$euer->berechneAusDolibarr($jahr);
$periode_text = $langs->trans("Year")." ".$jahr;
}
llxHeader("", $langs->trans("EUeRUebersicht"), '', '', 0, 0, '', '', '', 'mod-steuer page-index');
print load_fiche_titre($langs->trans("EUeRUebersicht")." - ".$periode_text, '', 'steuer.png@steuer');
// Filter-Formular
print '<form method="POST" action="'.$_SERVER["PHP_SELF"].'">';
print '<input type="hidden" name="token" value="'.newToken().'">';
print '<div class="div-table-responsive-no-min">';
print '<table class="noborder centpercent">';
print '<tr class="liste_titre">';
print '<td>'.$langs->trans("Period").'</td>';
print '<td>'.$langs->trans("Year").'</td>';
print '<td>'.$langs->trans("Month").'</td>';
print '<td></td>';
print '</tr>';
print '<tr class="oddeven">';
print '<td>'.$langs->trans("SelectPeriod").'</td>';
print '<td>';
print '<select name="jahr" class="flat minwidth100">';
for ($y = date('Y'); $y >= date('Y') - 5; $y--) {
print '<option value="'.$y.'"'.($y == $jahr ? ' selected' : '').'>'.$y.'</option>';
}
print '</select>';
print '</td>';
print '<td>';
print '<select name="monat" class="flat minwidth100">';
print '<option value="0"'.($monat == 0 ? ' selected' : '').'>'.$langs->trans("WholeYear").'</option>';
for ($m = 1; $m <= 12; $m++) {
print '<option value="'.$m.'"'.($m == $monat ? ' selected' : '').'>'.dol_print_date(mktime(0, 0, 0, $m, 1, 2000), '%B').'</option>';
}
print '</select>';
print '</td>';
print '<td>';
print '<input type="submit" class="button" value="'.$langs->trans("Refresh").'">';
print '</td>';
print '</tr>';
print '</table>';
print '</div>';
print '</form>';
print '<br>';
// Schnellzugriff-Links
print '<div class="div-table-responsive-no-min">';
print '<table class="noborder centpercent">';
print '<tr class="liste_titre">';
print '<th colspan="4">'.$langs->trans("QuickAccess").'</th>';
print '</tr>';
print '<tr class="oddeven">';
print '<td><a href="'.dol_buildpath('/steuer/buchung_list.php', 1).'?jahr='.$jahr.'" class="butAction">'.$langs->trans("Buchungen").'</a></td>';
print '<td><a href="'.dol_buildpath('/steuer/buchung_card.php', 1).'?action=create" class="butAction">'.$langs->trans("NeueBuchung").'</a></td>';
print '<td><a href="'.dol_buildpath('/steuer/euer_bericht.php', 1).'?jahr='.$jahr.'" class="butAction">'.$langs->trans("AnlageEUeR").'</a></td>';
print '<td><a href="'.dol_buildpath('/steuer/ustva.php', 1).'?jahr='.$jahr.'" class="butAction">'.$langs->trans("UStVA").'</a></td>';
print '</tr>';
print '<tr class="oddeven">';
print '<td><a href="'.dol_buildpath('/steuer/gewerbesteuer.php', 1).'?jahr='.$jahr.'" class="butAction">'.$langs->trans("Gewerbesteuer").'</a></td>';
print '<td><a href="'.dol_buildpath('/steuer/export_wiso.php', 1).'?jahr='.$jahr.'" class="butAction">'.$langs->trans("WISOExport").'</a></td>';
print '<td><a href="'.dol_buildpath('/steuer/konten.php', 1).'" class="butAction">'.$langs->trans("Kontenplan").'</a></td>';
print '<td></td>';
print '</tr>';
print '</table>';
print '</div>';
print '<br>';
print '<div class="fichecenter"><div class="fichethirdleft">';
// EÜR Übersicht - Einnahmen
print '<table class="noborder centpercent">';
print '<tr class="liste_titre">';
print '<th colspan="2">'.$langs->trans("Einnahmen").'</th>';
print '<th class="right">'.$langs->trans("Amount").'</th>';
print '</tr>';
if (!empty($euer->einnahmen)) {
foreach ($euer->einnahmen as $key => $einnahme) {
print '<tr class="oddeven">';
print '<td colspan="2">'.$einnahme['bezeichnung'].'</td>';
print '<td class="right nowraponall amount">'.price($einnahme['netto'], 0, $langs, 1, 2, 2, 'EUR').'</td>';
print '</tr>';
}
}
print '<tr class="liste_total">';
print '<td colspan="2"><strong>'.$langs->trans("TotalEinnahmen").'</strong></td>';
print '<td class="right nowraponall amount"><strong>'.price($euer->summe_einnahmen, 0, $langs, 1, 2, 2, 'EUR').'</strong></td>';
print '</tr>';
print '</table>';
print '<br>';
// USt/VSt Übersicht
print '<table class="noborder centpercent">';
print '<tr class="liste_titre">';
print '<th colspan="2">'.$langs->trans("UmsatzsteuerVorsteuer").'</th>';
print '</tr>';
print '<tr class="oddeven">';
print '<td>'.$langs->trans("UmsatzsteuerGesamt").'</td>';
print '<td class="right nowraponall amount">'.price($euer->ust_summe, 0, $langs, 1, 2, 2, 'EUR').'</td>';
print '</tr>';
print '<tr class="oddeven">';
print '<td>'.$langs->trans("VorsteuerGesamt").'</td>';
print '<td class="right nowraponall amount">'.price($euer->vst_summe, 0, $langs, 1, 2, 2, 'EUR').'</td>';
print '</tr>';
print '<tr class="liste_total">';
print '<td><strong>'.$langs->trans("Zahllast").'</strong></td>';
$zahllast = $euer->ust_summe - $euer->vst_summe;
$color = $zahllast >= 0 ? '' : 'amountremaintopay';
print '<td class="right nowraponall amount '.$color.'"><strong>'.price($zahllast, 0, $langs, 1, 2, 2, 'EUR').'</strong></td>';
print '</tr>';
print '</table>';
print '</div><div class="fichetwothirdright">';
// EÜR Übersicht - Ausgaben
print '<table class="noborder centpercent">';
print '<tr class="liste_titre">';
print '<th colspan="2">'.$langs->trans("Ausgaben").'</th>';
print '<th class="right">'.$langs->trans("Amount").'</th>';
print '</tr>';
if (!empty($euer->ausgaben)) {
foreach ($euer->ausgaben as $key => $ausgabe) {
print '<tr class="oddeven">';
print '<td colspan="2">'.$ausgabe['bezeichnung'].'</td>';
print '<td class="right nowraponall amount">'.price($ausgabe['netto'], 0, $langs, 1, 2, 2, 'EUR').'</td>';
print '</tr>';
}
}
print '<tr class="liste_total">';
print '<td colspan="2"><strong>'.$langs->trans("TotalAusgaben").'</strong></td>';
print '<td class="right nowraponall amount"><strong>'.price($euer->summe_ausgaben, 0, $langs, 1, 2, 2, 'EUR').'</strong></td>';
print '</tr>';
print '</table>';
print '<br>';
// Gewinn/Verlust Box
print '<table class="noborder centpercent">';
print '<tr class="liste_titre">';
print '<th colspan="2">'.$langs->trans("ErgebnisEUeR").'</th>';
print '</tr>';
print '<tr class="oddeven">';
print '<td>'.$langs->trans("Einnahmen").'</td>';
print '<td class="right nowraponall amount">'.price($euer->summe_einnahmen, 0, $langs, 1, 2, 2, 'EUR').'</td>';
print '</tr>';
print '<tr class="oddeven">';
print '<td>'.$langs->trans("Ausgaben").'</td>';
print '<td class="right nowraponall amount">- '.price($euer->summe_ausgaben, 0, $langs, 1, 2, 2, 'EUR').'</td>';
print '</tr>';
print '<tr class="liste_total">';
$color = $euer->gewinn >= 0 ? 'amountpaymentcomplete' : 'amountremaintopay';
print '<td><strong>'.($euer->gewinn >= 0 ? $langs->trans("Gewinn") : $langs->trans("Verlust")).'</strong></td>';
print '<td class="right nowraponall amount '.$color.'"><strong>'.price($euer->gewinn, 0, $langs, 1, 2, 2, 'EUR').'</strong></td>';
print '</tr>';
print '</table>';
print '</div></div>';
print '<div class="clearboth"></div>';
// End of page
llxFooter();
$db->close();

398
ustva.php Normal file
View file

@ -0,0 +1,398 @@
<?php
/**
* Umsatzsteuer-Voranmeldung (UStVA)
* Mit ELSTER/WISO Kennzahlen
*
* @package steuer
*/
// Load Dolibarr environment
$res = 0;
if (!$res && !empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) {
$res = @include $_SERVER["CONTEXT_DOCUMENT_ROOT"]."/main.inc.php";
}
$tmp = empty($_SERVER['SCRIPT_FILENAME']) ? '' : $_SERVER['SCRIPT_FILENAME'];
$tmp2 = realpath(__FILE__);
$i = strlen($tmp) - 1;
$j = strlen($tmp2) - 1;
while ($i > 0 && $j > 0 && isset($tmp[$i]) && isset($tmp2[$j]) && $tmp[$i] == $tmp2[$j]) {
$i--;
$j--;
}
if (!$res && $i > 0 && file_exists(substr($tmp, 0, ($i + 1))."/main.inc.php")) {
$res = @include substr($tmp, 0, ($i + 1))."/main.inc.php";
}
if (!$res && $i > 0 && file_exists(dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php")) {
$res = @include dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php";
}
if (!$res && file_exists("../main.inc.php")) {
$res = @include "../main.inc.php";
}
if (!$res && file_exists("../../main.inc.php")) {
$res = @include "../../main.inc.php";
}
if (!$res && file_exists("../../../main.inc.php")) {
$res = @include "../../../main.inc.php";
}
if (!$res) {
die("Include of main fails");
}
require_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
dol_include_once('/steuer/class/euer.class.php');
$langs->loadLangs(array("steuer@steuer", "bills", "compta"));
$jahr = GETPOSTINT('jahr');
if (empty($jahr)) {
$jahr = date('Y');
}
$ansicht = GETPOST('ansicht', 'alpha');
if (empty($ansicht)) {
$ansicht = 'monat';
}
$monat = GETPOSTINT('monat');
if (empty($monat)) {
$monat = date('n');
}
/*
* View
*/
$form = new Form($db);
$euer = new EUeR($db);
llxHeader('', $langs->trans("UStVA"), '', '', 0, 0, '', '', '', 'mod-steuer page-ustva');
print load_fiche_titre($langs->trans("UStVA")." ".$jahr, '', 'fa-percent');
// Filter
print '<form method="POST" action="'.$_SERVER["PHP_SELF"].'">';
print '<input type="hidden" name="token" value="'.newToken().'">';
print '<div class="inline-block marginrightonly">';
print '<select name="jahr" class="flat">';
for ($y = date('Y'); $y >= date('Y') - 5; $y--) {
print '<option value="'.$y.'"'.($y == $jahr ? ' selected' : '').'>'.$y.'</option>';
}
print '</select>';
print ' ';
print '<select name="ansicht" class="flat">';
print '<option value="monat"'.($ansicht == 'monat' ? ' selected' : '').'>'.$langs->trans("Monthly").'</option>';
print '<option value="quartal"'.($ansicht == 'quartal' ? ' selected' : '').'>'.$langs->trans("Quarterly").'</option>';
print '</select>';
print ' ';
print '<select name="monat" class="flat">';
for ($m = 1; $m <= 12; $m++) {
print '<option value="'.$m.'"'.($m == $monat ? ' selected' : '').'>'.dol_print_date(mktime(0, 0, 0, $m, 1, 2000), '%B').'</option>';
}
print '</select>';
print ' <input type="submit" class="button" value="'.$langs->trans("Refresh").'">';
print '</div>';
print '</form>';
print '<br>';
// ============================================================================
// ELSTER FORMULAR - Für manuellen Übertrag
// ============================================================================
print '<h2>ELSTER/WISO Formular - '.dol_print_date(mktime(0, 0, 0, $monat, 1, $jahr), '%B %Y').'</h2>';
// Daten für gewählten Monat berechnen
$euer->berechneAusDolibarr($jahr, $monat, $monat);
// Berechne Werte für UStVA
$kz81 = 0; // Bemessungsgrundlage 19%
$kz81_steuer = 0; // Steuer darauf
$kz86 = 0; // Bemessungsgrundlage 7%
$kz86_steuer = 0; // Steuer darauf
$kz66 = $euer->vst_summe; // Vorsteuer
// Einnahmen nach USt-Satz aufteilen
foreach ($euer->einnahmen as $einnahme) {
$ust_satz = isset($einnahme['ust_satz']) ? $einnahme['ust_satz'] : 19;
if ($ust_satz == 19) {
$kz81 += $einnahme['netto'];
$kz81_steuer += isset($einnahme['ust']) ? $einnahme['ust'] : ($einnahme['netto'] * 0.19);
} elseif ($ust_satz == 7) {
$kz86 += $einnahme['netto'];
$kz86_steuer += isset($einnahme['ust']) ? $einnahme['ust'] : ($einnahme['netto'] * 0.07);
}
}
// Zahllast berechnen
$ust_gesamt = $kz81_steuer + $kz86_steuer;
$zahllast = $ust_gesamt - $kz66;
print '<div class="div-table-responsive">';
print '<table class="noborder centpercent">';
// Header
print '<tr class="liste_titre">';
print '<th style="width:100px;">ELSTER Kz</th>';
print '<th style="width:100px;">WISO Feld</th>';
print '<th>Bezeichnung</th>';
print '<th class="right" style="width:150px;">Bemessungsgrundl.</th>';
print '<th class="right" style="width:150px;">Steuer</th>';
print '</tr>';
// Abschnitt: Lieferungen und sonstige Leistungen
print '<tr class="liste_titre"><td colspan="5"><strong>Lieferungen und sonstige Leistungen (steuerpflichtige Umsätze)</strong></td></tr>';
// Kz 81 - 19% Umsätze
print '<tr class="oddeven">';
print '<td><span class="badge badge-status4" style="font-size:14px;"><strong>Kz 81</strong></span></td>';
print '<td><span class="badge badge-status1">Zeile 28</span></td>';
print '<td>Steuerpflichtige Umsätze zum Steuersatz von <strong>19%</strong></td>';
print '<td class="right amount"><strong>'.price(round($kz81), 0, $langs, 1, 0, 0).'</strong> EUR</td>';
print '<td class="right amount">'.price($kz81_steuer, 0, $langs, 1, 2, 2).' EUR</td>';
print '</tr>';
// Kz 86 - 7% Umsätze
print '<tr class="oddeven">';
print '<td><span class="badge badge-status4" style="font-size:14px;"><strong>Kz 86</strong></span></td>';
print '<td><span class="badge badge-status1">Zeile 29</span></td>';
print '<td>Steuerpflichtige Umsätze zum Steuersatz von <strong>7%</strong></td>';
print '<td class="right amount"><strong>'.price(round($kz86), 0, $langs, 1, 0, 0).'</strong> EUR</td>';
print '<td class="right amount">'.price($kz86_steuer, 0, $langs, 1, 2, 2).' EUR</td>';
print '</tr>';
// Weitere wichtige Kennzahlen (leer, aber für Vollständigkeit)
print '<tr class="oddeven opacitymedium">';
print '<td><span class="badge badge-secondary">Kz 35</span></td>';
print '<td><span class="badge badge-secondary">Zeile 30</span></td>';
print '<td>Umsätze zu anderen Steuersätzen</td>';
print '<td class="right">0 EUR</td>';
print '<td class="right">-</td>';
print '</tr>';
// Steuerfreie Umsätze
print '<tr class="liste_titre"><td colspan="5"><strong>Steuerfreie Umsätze</strong></td></tr>';
print '<tr class="oddeven opacitymedium">';
print '<td><span class="badge badge-secondary">Kz 41</span></td>';
print '<td><span class="badge badge-secondary">Zeile 20</span></td>';
print '<td>Innergemeinschaftliche Lieferungen (§ 4 Nr. 1b UStG)</td>';
print '<td class="right">0 EUR</td>';
print '<td class="right">-</td>';
print '</tr>';
print '<tr class="oddeven opacitymedium">';
print '<td><span class="badge badge-secondary">Kz 44</span></td>';
print '<td><span class="badge badge-secondary">Zeile 21</span></td>';
print '<td>Steuerfreie Ausfuhrlieferungen (§ 4 Nr. 1a UStG)</td>';
print '<td class="right">0 EUR</td>';
print '<td class="right">-</td>';
print '</tr>';
// Abziehbare Vorsteuerbeträge
print '<tr class="liste_titre"><td colspan="5"><strong>Abziehbare Vorsteuerbeträge</strong></td></tr>';
// Kz 66 - Vorsteuer
print '<tr class="oddeven">';
print '<td><span class="badge badge-status4" style="font-size:14px;"><strong>Kz 66</strong></span></td>';
print '<td><span class="badge badge-status1">Zeile 55</span></td>';
print '<td>Vorsteuerbeträge aus Rechnungen von anderen Unternehmern</td>';
print '<td class="right">-</td>';
print '<td class="right amount"><strong>'.price($kz66, 0, $langs, 1, 2, 2).'</strong> EUR</td>';
print '</tr>';
print '<tr class="oddeven opacitymedium">';
print '<td><span class="badge badge-secondary">Kz 61</span></td>';
print '<td><span class="badge badge-secondary">Zeile 56</span></td>';
print '<td>Vorsteuerbeträge aus innergemeinschaftlichem Erwerb</td>';
print '<td class="right">-</td>';
print '<td class="right">0,00 EUR</td>';
print '</tr>';
print '<tr class="oddeven opacitymedium">';
print '<td><span class="badge badge-secondary">Kz 67</span></td>';
print '<td><span class="badge badge-secondary">Zeile 57</span></td>';
print '<td>Vorsteuerbeträge nach § 13b UStG (Reverse Charge)</td>';
print '<td class="right">-</td>';
print '<td class="right">0,00 EUR</td>';
print '</tr>';
// Berechnung
print '<tr class="liste_titre"><td colspan="5"><strong>Berechnung der Umsatzsteuer</strong></td></tr>';
print '<tr class="oddeven">';
print '<td colspan="2"></td>';
print '<td>Summe Umsatzsteuer (Kz 81 + Kz 86)</td>';
print '<td class="right">-</td>';
print '<td class="right amount">'.price($ust_gesamt, 0, $langs, 1, 2, 2).' EUR</td>';
print '</tr>';
print '<tr class="oddeven">';
print '<td colspan="2"></td>';
print '<td>./. Vorsteuer (Kz 66)</td>';
print '<td class="right">-</td>';
print '<td class="right amount">- '.price($kz66, 0, $langs, 1, 2, 2).' EUR</td>';
print '</tr>';
// Zahllast / Erstattung
print '<tr class="liste_total">';
print '<td><span class="badge badge-status'.($zahllast >= 0 ? '1' : '4').'" style="font-size:14px;"><strong>Kz 83</strong></span></td>';
print '<td><span class="badge badge-status1">Zeile 65</span></td>';
print '<td><strong>'.($zahllast >= 0 ? 'Verbleibende Umsatzsteuer-Vorauszahlung' : 'Verbleibender Überschuss (Erstattung)').'</strong></td>';
print '<td class="right">-</td>';
$color = $zahllast >= 0 ? '' : 'amountremaintopay';
print '<td class="right amount '.$color.'"><strong>'.price(abs($zahllast), 0, $langs, 1, 2, 2).' EUR</strong></td>';
print '</tr>';
print '</table>';
print '</div>';
// ============================================================================
// Jahresübersicht
// ============================================================================
print '<br><h2>Jahresübersicht '.$jahr.'</h2>';
print '<div class="div-table-responsive">';
print '<table class="noborder centpercent">';
// Header
print '<tr class="liste_titre">';
print '<th>'.$langs->trans("Period").'</th>';
print '<th class="center">Kz 81<br><small>Umsätze 19%</small></th>';
print '<th class="center">Kz 86<br><small>Umsätze 7%</small></th>';
print '<th class="center">USt<br><small>Steuer</small></th>';
print '<th class="center">Kz 66<br><small>Vorsteuer</small></th>';
print '<th class="center">Kz 83<br><small>Zahllast</small></th>';
print '</tr>';
$total_kz81 = 0;
$total_kz86 = 0;
$total_ust = 0;
$total_vst = 0;
$total_zahllast = 0;
if ($ansicht == 'quartal') {
$perioden = array(
'Q1' => array(1, 3),
'Q2' => array(4, 6),
'Q3' => array(7, 9),
'Q4' => array(10, 12)
);
} else {
$perioden = array();
for ($m = 1; $m <= 12; $m++) {
$perioden[sprintf('%02d', $m)] = array($m, $m);
}
}
foreach ($perioden as $key => $range) {
$euer->berechneAusDolibarr($jahr, $range[0], $range[1]);
$p_kz81 = 0;
$p_kz86 = 0;
$p_ust = 0;
$p_vst = $euer->vst_summe;
foreach ($euer->einnahmen as $einnahme) {
$ust_satz = isset($einnahme['ust_satz']) ? $einnahme['ust_satz'] : 19;
if ($ust_satz == 19) {
$p_kz81 += $einnahme['netto'];
$p_ust += isset($einnahme['ust']) ? $einnahme['ust'] : ($einnahme['netto'] * 0.19);
} elseif ($ust_satz == 7) {
$p_kz86 += $einnahme['netto'];
$p_ust += isset($einnahme['ust']) ? $einnahme['ust'] : ($einnahme['netto'] * 0.07);
}
}
$p_zahllast = $p_ust - $p_vst;
$total_kz81 += $p_kz81;
$total_kz86 += $p_kz86;
$total_ust += $p_ust;
$total_vst += $p_vst;
$total_zahllast += $p_zahllast;
if ($ansicht == 'quartal') {
$periode_name = $key.' '.$jahr;
} else {
$periode_name = dol_print_date(mktime(0, 0, 0, (int)$key, 1, $jahr), '%B');
}
$is_current = ($ansicht != 'quartal' && (int)$key == $monat);
$row_class = $is_current ? 'liste_titre' : 'oddeven';
print '<tr class="'.$row_class.'">';
print '<td>'.($is_current ? '<strong>' : '').$periode_name.($is_current ? ' (oben)</strong>' : '').'</td>';
print '<td class="right">'.price(round($p_kz81), 0, $langs, 1, 0, 0).'</td>';
print '<td class="right">'.price(round($p_kz86), 0, $langs, 1, 0, 0).'</td>';
print '<td class="right">'.price($p_ust, 0, $langs, 1, 2, 2).'</td>';
print '<td class="right">'.price($p_vst, 0, $langs, 1, 2, 2).'</td>';
$color = $p_zahllast >= 0 ? '' : 'amountremaintopay';
print '<td class="right amount '.$color.'"><strong>'.price($p_zahllast, 0, $langs, 1, 2, 2).'</strong></td>';
print '</tr>';
}
// Summenzeile
print '<tr class="liste_total">';
print '<td><strong>Gesamt '.$jahr.'</strong></td>';
print '<td class="right"><strong>'.price(round($total_kz81), 0, $langs, 1, 0, 0).'</strong></td>';
print '<td class="right"><strong>'.price(round($total_kz86), 0, $langs, 1, 0, 0).'</strong></td>';
print '<td class="right"><strong>'.price($total_ust, 0, $langs, 1, 2, 2).'</strong></td>';
print '<td class="right"><strong>'.price($total_vst, 0, $langs, 1, 2, 2).'</strong></td>';
$color = $total_zahllast >= 0 ? 'amountpaymentcomplete' : 'amountremaintopay';
print '<td class="right amount '.$color.'"><strong>'.price($total_zahllast, 0, $langs, 1, 2, 2).'</strong></td>';
print '</tr>';
print '</table>';
print '</div>';
// ============================================================================
// Legende
// ============================================================================
print '<br>';
print '<div class="fichecenter">';
print '<div class="fichethirdleft">';
print '<table class="noborder centpercent">';
print '<tr class="liste_titre"><th colspan="2">ELSTER Kennzahlen</th></tr>';
print '<tr class="oddeven"><td><span class="badge badge-status4">Kz 81</span></td><td>Bemessungsgrundlage für Umsätze zum Steuersatz von 19%</td></tr>';
print '<tr class="oddeven"><td><span class="badge badge-status4">Kz 86</span></td><td>Bemessungsgrundlage für Umsätze zum Steuersatz von 7%</td></tr>';
print '<tr class="oddeven"><td><span class="badge badge-status4">Kz 66</span></td><td>Vorsteuerbeträge aus Rechnungen von anderen Unternehmern</td></tr>';
print '<tr class="oddeven"><td><span class="badge badge-status4">Kz 83</span></td><td>Verbleibende Umsatzsteuer-Vorauszahlung / Überschuss</td></tr>';
print '<tr class="oddeven"><td><span class="badge badge-secondary">Kz 35</span></td><td>Umsätze zu anderen Steuersätzen (z.B. 16%, 5%)</td></tr>';
print '<tr class="oddeven"><td><span class="badge badge-secondary">Kz 41</span></td><td>Innergemeinschaftliche Lieferungen</td></tr>';
print '<tr class="oddeven"><td><span class="badge badge-secondary">Kz 44</span></td><td>Steuerfreie Ausfuhrlieferungen</td></tr>';
print '</table>';
print '</div>';
print '<div class="fichetwothirdright">';
print '<table class="noborder centpercent">';
print '<tr class="liste_titre"><th colspan="2">WISO Steuer Zuordnung</th></tr>';
print '<tr class="oddeven"><td><span class="badge badge-status1">Zeile 28</span></td><td>= ELSTER Kz 81 (19% Umsätze)</td></tr>';
print '<tr class="oddeven"><td><span class="badge badge-status1">Zeile 29</span></td><td>= ELSTER Kz 86 (7% Umsätze)</td></tr>';
print '<tr class="oddeven"><td><span class="badge badge-status1">Zeile 55</span></td><td>= ELSTER Kz 66 (Vorsteuer)</td></tr>';
print '<tr class="oddeven"><td><span class="badge badge-status1">Zeile 65</span></td><td>= ELSTER Kz 83 (Zahllast)</td></tr>';
print '<tr class="oddeven"><td colspan="2" class="opacitymedium"><small>Die WISO Zeilennummern können je nach Version abweichen. Orientieren Sie sich an den ELSTER-Kennzahlen.</small></td></tr>';
print '</table>';
print '</div>';
print '</div>';
print '<div class="clearboth"></div>';
// Hinweis
print '<br>';
print '<div class="warning">';
print '<strong>Hinweis zur Übertragung:</strong><br>';
print '1. In ELSTER/WISO tragen Sie die <strong>Bemessungsgrundlagen</strong> (Netto-Beträge) in die Felder Kz 81 und Kz 86 ein<br>';
print '2. Die Steuer wird automatisch berechnet<br>';
print '3. Die <strong>Vorsteuer</strong> (Kz 66) ist der Gesamtbetrag der abziehbaren Vorsteuer<br>';
print '4. Die Kennzahlen sind identisch für ELSTER und WISO Steuer<br>';
print '</div>';
// Zurück-Button
print '<br>';
print '<div class="tabsAction">';
print '<a class="butAction" href="'.dol_buildpath('/steuer/steuerindex.php', 1).'"><i class="fa fa-arrow-left paddingright"></i>'.$langs->trans("Back").'</a>';
print '</div>';
llxFooter();
$db->close();