Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
542a673
datev_export_xml: Add module to export account.move as DATEV XML
fkantelberg Mar 3, 2023
d20aebe
Move out common configurations to base module
fkantelberg Mar 10, 2023
ff40b23
[MIG] datev_export_xml: Migration to 15.0
fkantelberg May 31, 2023
41fc9d1
[FIX] datev_export_xml: Fix call of sorted for pickings
fkantelberg Jun 28, 2023
5b82694
[FIX] datev_export_xml: Enforce some limits and use different field f…
fkantelberg Jun 29, 2023
e19ffec
[IMP] datev_export_xml: Check invoices before rendering to prevent ba…
fkantelberg Jul 11, 2023
7437c20
[FIX] datev_export_xml: Negate values for refunds (invoice corrections)
fkantelberg Aug 9, 2023
82b3da1
[FIX] Problem when tax_base_amount is 0 or line names fallback to False
fkantelberg Dec 12, 2023
48ef0d7
[FIX] datev_export_xml: Skip non-product lines
fkantelberg Dec 13, 2023
36ec1a2
[IMP] : pre-commit stuff
Mar 19, 2024
12483bb
[MIG] : Migration datev_export_xml to 16.0
Mar 19, 2024
e8d5a61
[IMP] datev_export_xml: Update template invoice_party account
Mar 23, 2024
7f3e0aa
[FIX] datev_export_xml: display smart buttons
May 9, 2024
d818476
[IMP] datev_export_xml: Allow previous validation to see all errors o…
fkantelberg Apr 4, 2024
2e6ce2d
[FIX] datev_export_xml: Add general check on invoice e.g. when multip…
fkantelberg Apr 10, 2024
5b82001
[FIX] datev_export_xml: Fix tests (create journals if they do not exist)
victoralmau Apr 22, 2025
58be409
[IMP] datev_export_xml: pre-commit auto fixes
victoralmau May 7, 2025
91adffd
[MIG] datev_export_xml: Migration to 17.0
victoralmau Feb 18, 2025
6b48045
[UPD] Update datev_export_xml.pot
May 20, 2025
e2f8d50
[BOT] post-merge updates
OCA-git-bot May 20, 2025
2384644
[IMP] datev_export_xml: Add some length constrains to fix possible er…
etobella Jul 17, 2025
bb12055
[BOT] post-merge updates
OCA-git-bot Sep 5, 2025
2a7328a
[IMP] datev_export_xml: pre-commit auto fixes
hbrunn Jan 26, 2026
60c2ff3
[MIG] datev_export_xml: Migration to 18.0
hbrunn Jan 26, 2026
f98be19
[IMP] datev_export_xml: add security group
jans23 Aug 27, 2025
867b76f
[FIX] datev_export_xml: Fix duplicate lines because of t-if instead o…
fkantelberg May 15, 2024
faf692e
[IMP] datev_export_xml: Add xml declaration
fkantelberg May 27, 2024
af62059
[IMP] datev_export_xml: Insert vat_id if available at the partner
fkantelberg Jul 3, 2024
c6465c3
[IMP] datev_export_xml: Improve handling and download of bigger files
fkantelberg May 13, 2024
1faceed
[IMP] datev_export_xml: Automatic packaging into smaller zip files
fkantelberg May 24, 2024
3485c73
[FIX] datev_export_xml: Move counter threshold to packaging
fkantelberg May 31, 2024
05cb053
[FIX] datev_export_xml: Prevent exception if non-admin user tries to …
fkantelberg May 31, 2024
d634789
[FIX] datev_export_xml: Count the number of files for the threshold i…
fkantelberg Jun 24, 2024
54e84d0
[IMP] migrate #160 to v18
hbrunn Jan 26, 2026
bec68a9
[IMP] increase test coverage
hbrunn Jan 26, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
403 changes: 403 additions & 0 deletions datev_export_xml/README.rst

Large diffs are not rendered by default.

10 changes: 10 additions & 0 deletions datev_export_xml/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Copyright (C) 2022-2023 initOS GmbH
# Copyright (C) 2019 sewisoft (sewisoft.de)
# Copyright (C) 2010-2023 big-consulting GmbH (www.openbig.de)
# Copyright (C) 2010 OpenGLOBE Grzegorz Grzelak (www.openglobe.pl)
# @author Guenter Selbert <guenter.selbert@sewisoft.de>
# @author Thorsten Vocks
# @author Grzegorz Grzelak
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

from . import controllers, models
36 changes: 36 additions & 0 deletions datev_export_xml/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Copyright (C) 2024 Solvti sp. z o.o. (https://solvti.pl)
# Copyright (C) 2022-2023 initOS GmbH
# Copyright (C) 2019 sewisoft (sewisoft.de)
# Copyright (C) 2010-2023 big-consulting GmbH (www.openbig.de)
# Copyright (C) 2010 OpenGLOBE Grzegorz Grzelak (www.openglobe.pl)
# @author Guenter Selbert <guenter.selbert@sewisoft.de>
# @author Thorsten Vocks <thorsten.vocks@openbig.org>
# @author Grzegorz Grzelak
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

{
"name": "Datev Export XML",
"version": "18.0.1.0.0",
"category": "Accounting",
"license": "AGPL-3",
"author": "Guenter Selbert, Thorsten Vocks, Maciej Wichowski, Daniela Scarpa, "
"Maria Sparenberg, initOS GmbH, Jan Sierpina, Odoo Community Association (OCA)",
"summary": "Export invoices and refunds as xml and pdf files zipped in DATEV "
"format.",
"website": "https://github.com/OCA/l10n-germany",
"depends": ["datev_export"],
"data": [
"data/ir_cron_data.xml",
"security/groups.xml",
"security/ir.model.access.csv",
"security/security.xml",
"views/account_invoice_view.xml",
"views/datev_export_views.xml",
"views/res_config_settings_views.xml",
"views/templates.xml",
],
"demo": [
"demo/export_data.xml",
],
"installable": True,
}
4 changes: 4 additions & 0 deletions datev_export_xml/controllers/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Copyright (C) 2022-2024 initOS GmbH
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from . import main
39 changes: 39 additions & 0 deletions datev_export_xml/controllers/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Copyright (C) 2022-2024 initOS GmbH
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

import base64
import logging

from odoo import http
from odoo.http import _send_file, request

_logger = logging.getLogger(__name__)


class DatevHome(http.Controller):
@http.route("/datev/xml/download/<int:line_id>", type="http", auth="user")
def datev_xml_download_attachment(self, line_id):
export = request.env["datev.export.xml.line"].search([("id", "=", line_id)])

if not export.attachment_id:
return request.not_found()

att = export.attachment_id

if att.store_fname:
full_path = att._full_path(att.store_fname)
return _send_file(
full_path,
environ=request.httprequest.environ,
download_name=att.name,
mimetype=att.mimetype,
as_attachment=True,
)

return request.make_response(
base64.b64decode(att.datas),
[
("Content-Type", att.mimetype),
("Content-Disposition", f'attachment; filename="{att.name}"'),
],
)
12 changes: 12 additions & 0 deletions datev_export_xml/data/ir_cron_data.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo noupdate="1">
<record model="ir.cron" id="cron_create_datev_export">
<field name='name'>DATEV XML: Create Export File</field>
<field name='interval_number'>5</field>
<field name='interval_type'>minutes</field>
<field name="active" eval="True" />
<field name="state">code</field>
<field name="model_id" ref="model_datev_export_xml" />
<field name="code">model.cron_run_pending_export()</field>
</record>
</odoo>
275 changes: 275 additions & 0 deletions datev_export_xml/demo/export_data.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,275 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<record id="base.main_company" model="res.company">
<field name="datev_client_number">1234</field>
<field name="datev_consultant_number">12345</field>
</record>

<!-- Company Datev Accounts -->
<record id="account_datev_rec" model="account.account">
<field name="name">Company Account Receivable</field>
<field name="code">69999</field>
<field name="reconcile" eval="True" />
<field name="account_type">asset_receivable</field>
</record>
<record id="account_datev_pay" model="account.account">
<field name="name">Company Account Payable</field>
<field name="code">99999</field>
<field name="reconcile" eval="True" />
<field name="account_type">liability_payable</field>
</record>

<record id="base.main_partner" model="res.partner">
<field name="property_account_receivable_id" ref="account_datev_rec" />
<field name="property_account_payable_id" ref="account_datev_pay" />
</record>

<!-- German Accounts -->
<record id="account_datev_rec_DE" model="account.account">
<field name="name">A-Customer Account DE</field>
<field name="code">10001</field>
<field name="reconcile" eval="True" />
<field name="account_type">asset_receivable</field>
</record>
<record id="account_datev_pay_DE" model="account.account">
<field name="name">A-Vendor Account DE</field>
<field name="code">70001</field>
<field name="reconcile" eval="True" />
<field name="account_type">liability_payable</field>
</record>
<!-- EU Accounts -->
<record id="account_datev_rec_EU" model="account.account">
<field name="name">A-Customer Account EU</field>
<field name="code">10002</field>
<field name="reconcile" eval="True" />
<field name="account_type">asset_receivable</field>
</record>
<record id="account_datev_pay_EU" model="account.account">
<field name="name">A-Vendor Account EU</field>
<field name="code">70002</field>
<field name="reconcile" eval="True" />
<field name="account_type">liability_payable</field>
</record>
<!-- Non-EU Accounts -->
<record id="account_datev_rec_NonEU" model="account.account">
<field name="name">A-Customer Account Non-EU</field>
<field name="code">10003</field>
<field name="reconcile" eval="True" />
<field name="account_type">asset_receivable</field>
</record>
<record id="account_datev_pay_NonEU" model="account.account">
<field name="name">A-Vendor Account Non-EU</field>
<field name="code">70003</field>
<field name="reconcile" eval="True" />
<field name="account_type">liability_payable</field>
</record>
<!-- Accounts Income and Expense -->
<record id="account_datev_income" model="account.account">
<field name="name">A-Income</field>
<field name="code">8401</field>
<field name="reconcile" eval="False" />
<field name="account_type">income</field>
</record>
<record id="account_datev_expense" model="account.account">
<field name="name">A-Expense</field>
<field name="code">3401</field>
<field name="reconcile" eval="False" />
<field name="account_type">expense</field>
</record>

<!-- German Partners -->
<record id="customer_DE" model="res.partner">
<field name="name">A-Customer DE</field>
<field name="street">Straße 1</field>
<field name="zip">12345</field>
<field name="city">City</field>
<field name="country_id" ref="base.de" />
<field name="customer_rank" eval="1" />
<field name="supplier_rank" eval="0" />
<field name="property_account_receivable_id" ref="account_datev_rec_DE" />
<field name="property_account_payable_id" ref="account_datev_pay_DE" />
</record>
<record id="vendor_DE" model="res.partner">
<field name="name">A-Vendor DE</field>
<field name="street">Alle 9</field>
<field name="zip">54321</field>
<field name="city">Metropole</field>
<field name="country_id" ref="base.de" />
<field name="supplier_rank" eval="1" />
<field name="customer_rank" eval="0" />
<field name="property_account_receivable_id" ref="account_datev_rec_DE" />
<field name="property_account_payable_id" ref="account_datev_pay_DE" />
</record>

<!-- EU Partners -->
<record id="customer_EU" model="res.partner">
<field name="name">A-Customer EU</field>
<field name="street">Straße 1</field>
<field name="zip">12345</field>
<field name="city">City</field>
<field name="country_id" ref="base.fr" />
<field name="customer_rank" eval="1" />
<field name="supplier_rank" eval="0" />
<field name="property_account_receivable_id" ref="account_datev_rec_EU" />
<field name="property_account_payable_id" ref="account_datev_pay_EU" />
</record>
<record id="vendor_EU" model="res.partner">
<field name="name">A-Vendor EU</field>
<field name="street">Alle 9</field>
<field name="zip">54321</field>
<field name="city">Metropole</field>
<field name="country_id" ref="base.fr" />
<field name="supplier_rank" eval="1" />
<field name="customer_rank" eval="0" />
<field name="property_account_receivable_id" ref="account_datev_rec_EU" />
<field name="property_account_payable_id" ref="account_datev_pay_EU" />
</record>

<!-- Non-EU Partners -->
<record id="customer_NonEU" model="res.partner">
<field name="name">A-Customer Non-EU</field>
<field name="street">Straße 1</field>
<field name="zip">12345</field>
<field name="city">City</field>
<field name="country_id" ref="base.us" />
<field name="customer_rank" eval="1" />
<field name="supplier_rank" eval="0" />
<field name="property_account_receivable_id" ref="account_datev_rec_NonEU" />
<field name="property_account_payable_id" ref="account_datev_pay_NonEU" />
</record>
<record id="vendor_NonEU" model="res.partner">
<field name="name">A-Vendor Non-EU</field>
<field name="street">Alle 9</field>
<field name="zip">54321</field>
<field name="city">Metropole</field>
<field name="country_id" ref="base.us" />
<field name="supplier_rank" eval="1" />
<field name="customer_rank" eval="0" />
<field name="property_account_receivable_id" ref="account_datev_rec_NonEU" />
<field name="property_account_payable_id" ref="account_datev_pay_NonEU" />
</record>

<record id="analytic_account_datev_01" model="account.analytic.account">
<field name="name">A-IT</field>
<field name="code">990010</field>
<field name="plan_id" ref="analytic.analytic_plan_departments" />
</record>
<record id="analytic_account_datev_02" model="account.analytic.account">
<field name="name">A-Office</field>
<field name="code">990000</field>
<field name="plan_id" ref="analytic.analytic_plan_departments" />
</record>

<record id="product_datev_01" model="product.product">
<field name="name">A-IT-Consulting</field>
<field name="default_code">11-001</field>
<field name="type">service</field>
<field name="sale_ok" eval="True" />
<field name="categ_id" ref="product.product_category_all" />
<field name="list_price">120.00</field>
<field name="property_account_income_id" ref="account_datev_income" />
</record>
<record id="product_datev_02" model="product.product">
<field name="name">A-Office-Lease</field>
<field name="default_code">99-015</field>
<field name="type">service</field>
<field name="purchase_ok" eval="True" />
<field name="categ_id" ref="product.product_category_all" />
<field name="list_price">900.00</field>
<field name="property_account_income_id" ref="account_datev_expense" />
</record>

<!-- Demo Attachment pdf for IN Invoice -->
<record id="vendor_bill_attachment_DE" model="ir.attachment">
<field name="name">vendor_bill_attachment_DE.pdf</field>
<field name="type">binary</field>
<field
name="datas"
type="base64"
file="datev_export_xml/static/src/demo/vendor_bill_attachment.pdf"
/>
</record>
<record id="vendor_bill_attachment_EU" model="ir.attachment">
<field name="name">vendor_bill_attachment_EU.pdf</field>
<field name="type">binary</field>
<field
name="datas"
type="base64"
file="datev_export_xml/static/src/demo/vendor_bill_attachment.pdf"
/>
</record>
<record id="vendor_bill_attachment_NonEU" model="ir.attachment">
<field name="name">vendor_bill_attachment_NonEU.pdf</field>
<field name="type">binary</field>
<field
name="datas"
type="base64"
file="datev_export_xml/static/src/demo/vendor_bill_attachment.pdf"
/>
</record>
<!-- Demo Attachment pdf for IN Refund -->
<record id="bill_refund_attachment_DE" model="ir.attachment">
<field name="name">bill_refund_attachment_DE.pdf</field>
<field name="type">binary</field>
<field
name="datas"
type="base64"
file="datev_export_xml/static/src/demo/vendor_bill_attachment.pdf"
/>
</record>
<record id="bill_refund_attachment_EU" model="ir.attachment">
<field name="name">bill_refund_attachment_EU.pdf</field>
<field name="type">binary</field>
<field
name="datas"
type="base64"
file="datev_export_xml/static/src/demo/vendor_bill_attachment.pdf"
/>
</record>
<record id="bill_refund_attachment_NonEU" model="ir.attachment">
<field name="name">bill_refund_attachment_NonEU.pdf</field>
<field name="type">binary</field>
<field
name="datas"
type="base64"
file="datev_export_xml/static/src/demo/vendor_bill_attachment.pdf"
/>
</record>

<!-- Bank Data -->
<record id="customer_parent" model="res.partner">
<field name="name">A-Customer Parent</field>
<field name="street">Straße 1</field>
<field name="zip">12345</field>
<field name="city">Berlin</field>
<field name="country_id" ref="base.de" />
<field name="customer_rank" eval="1" />
<field name="supplier_rank" eval="0" />
<field name="property_account_receivable_id" ref="account_datev_rec_DE" />
<field name="property_account_payable_id" ref="account_datev_pay_DE" />
</record>

<record id="example_bank" model="res.bank">
<field name="name">Example Bank</field>
<field name="active" eval="True" />
<field name="bic">ALSWCH21XXX</field>
<field name="country" ref="base.ch" />
</record>

<record id="customer_child" model="res.partner">
<field name="name">A-Customer Child</field>
<field name="type">contact</field>
<field name="parent_id" ref="customer_parent" />
<field name="vat">BE0477472701</field>
<field name="country_id" ref="base.de" />
<field name="customer_rank" eval="1" />
<field name="supplier_rank" eval="0" />
</record>

<record id="datev_partner_bank_1" model="res.partner.bank">
<field name="acc_number">DE89370400440532013000</field>
<field name="partner_id" ref="customer_child" />
<field name="acc_type">bank</field>
<field name="bank_id" ref="example_bank" />
</record>
</odoo>
Loading