Browse Source

[IMP] account_export_csv: black, isort, prettier

pull/756/head
Kévin Roche 3 years ago
parent
commit
4b769eef61
  1. 24
      account_export_csv/__manifest__.py
  2. 39
      account_export_csv/tests/test_account_export_csv.py
  3. 197
      account_export_csv/wizard/account_export_csv.py
  4. 46
      account_export_csv/wizard/account_export_csv_view.xml
  5. 1
      setup/account_export_csv/odoo/addons/account_export_csv
  6. 6
      setup/account_export_csv/setup.py

24
account_export_csv/__manifest__.py

@ -3,18 +3,18 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{ {
'name': 'Account Export CSV',
'summary': "Adds accounting CSV export",
'version': '12.0.1.2.0',
'depends': [
'account',
'date_range',
"name": "Account Export CSV",
"summary": "Adds accounting CSV export",
"version": "12.0.1.2.0",
"depends": [
"account",
"date_range",
], ],
'author': "Camptocamp,Odoo Community Association (OCA)",
'website': 'http://www.camptocamp.com',
'license': 'AGPL-3',
'data': [
'wizard/account_export_csv_view.xml',
"author": "Camptocamp,Odoo Community Association (OCA)",
"website": "https://github.com/OCA/account-financial-reporting",
"license": "AGPL-3",
"data": [
"wizard/account_export_csv_view.xml",
], ],
'installable': True,
"installable": True,
} }

39
account_export_csv/tests/test_account_export_csv.py

@ -1,50 +1,49 @@
# Copyright 2017 ACSONE SA/NV # Copyright 2017 ACSONE SA/NV
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
import base64
from datetime import date from datetime import date
from dateutil import relativedelta from dateutil import relativedelta
import base64
from odoo.tests.common import TransactionCase
from odoo import fields from odoo import fields
from odoo.tests.common import TransactionCase
class TestAccountExportCsv(TransactionCase): class TestAccountExportCsv(TransactionCase):
def setUp(self): def setUp(self):
super(TestAccountExportCsv, self).setUp() super(TestAccountExportCsv, self).setUp()
self.report_wizard = self.env['account.csv.export']
self.report_wizard = self.env["account.csv.export"]
today_dt = date.today() today_dt = date.today()
next_month_date = today_dt + relativedelta.relativedelta(months=1) next_month_date = today_dt + relativedelta.relativedelta(months=1)
self.report_date_start = fields.Date.to_string(today_dt) self.report_date_start = fields.Date.to_string(today_dt)
self.report_date_end = fields.Date.to_string(next_month_date) self.report_date_end = fields.Date.to_string(next_month_date)
def test_1(self): def test_1(self):
report_wizard = self.report_wizard.create({
'date_start': self.report_date_start,
'date_end': self.report_date_end
})
report_wizard = self.report_wizard.create(
{"date_start": self.report_date_start, "date_end": self.report_date_end}
)
report_wizard.action_manual_export_account() report_wizard.action_manual_export_account()
def test_2(self): def test_2(self):
report_wizard = self.report_wizard.create({
'date_start': self.report_date_start,
'date_end': self.report_date_end
})
report_wizard = self.report_wizard.create(
{"date_start": self.report_date_start, "date_end": self.report_date_end}
)
report_wizard.action_manual_export_analytic() report_wizard.action_manual_export_analytic()
def test_3(self): def test_3(self):
report_wizard = self.report_wizard.create({
'date_start': self.report_date_start,
'date_end': self.report_date_end
})
report_wizard = self.report_wizard.create(
{"date_start": self.report_date_start, "date_end": self.report_date_end}
)
report_wizard.action_manual_export_journal_entries() report_wizard.action_manual_export_journal_entries()
def test_file_content(self): def test_file_content(self):
report_wizard = self.report_wizard.create({
"date_start": "2000-01-01",
"date_end": "2200-01-01",
})
report_wizard = self.report_wizard.create(
{
"date_start": "2000-01-01",
"date_end": "2200-01-01",
}
)
report_wizard.action_manual_export_journal_entries() report_wizard.action_manual_export_journal_entries()
res = base64.decodestring(report_wizard.data) res = base64.decodestring(report_wizard.data)
line_number = self.env["account.move.line"].search_count([]) line_number = self.env["account.move.line"].search_count([])

197
account_export_csv/wizard/account_export_csv.py

@ -2,15 +2,14 @@
# Copyright 2017 ACSONE SA/NV # Copyright 2017 ACSONE SA/NV
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
import itertools
import tempfile
from io import StringIO, BytesIO
import base64 import base64
import csv
import codecs import codecs
import csv
import itertools
import tempfile
from io import BytesIO, StringIO
from odoo import api, fields, models, _
from odoo import _, api, fields, models
class AccountingWriter(object): class AccountingWriter(object):
@ -30,7 +29,7 @@ class AccountingWriter(object):
def writerow(self, row): def writerow(self, row):
# we ensure that we do not try to encode none or bool # we ensure that we do not try to encode none or bool
row = (x or '' for x in row)
row = (x or "" for x in row)
self.writer.writerow(row) self.writer.writerow(row)
# Fetch UTF-8 output from the queue ... # Fetch UTF-8 output from the queue ...
data = self.queue.getvalue() data = self.queue.getvalue()
@ -52,23 +51,28 @@ class AccountingWriter(object):
class AccountCSVExport(models.TransientModel): class AccountCSVExport(models.TransientModel):
_name = 'account.csv.export'
_description = 'Export Accounting'
_name = "account.csv.export"
_description = "Export Accounting"
data = fields.Binary('CSV', readonly=True)
data = fields.Binary("CSV", readonly=True)
company_id = fields.Many2one( company_id = fields.Many2one(
comodel_name='res.company', string='Company', invisible=True,
default=lambda self: self._get_company_default())
comodel_name="res.company",
string="Company",
invisible=True,
default=lambda self: self._get_company_default(),
)
date_start = fields.Date(required=True) date_start = fields.Date(required=True)
date_end = fields.Date(required=True) date_end = fields.Date(required=True)
date_range_id = fields.Many2one(
comodel_name='date.range', string='Date range')
date_range_id = fields.Many2one(comodel_name="date.range", string="Date range")
journal_ids = fields.Many2many( journal_ids = fields.Many2many(
comodel_name='account.journal', string='Journals',
comodel_name="account.journal",
string="Journals",
default=lambda s: s._get_journal_default(), default=lambda s: s._get_journal_default(),
help='If empty, use all journals, only used for journal entries')
help="If empty, use all journals, only used for journal entries",
)
export_filename = fields.Char( export_filename = fields.Char(
string='Export CSV Filename', size=128, default='account_export.csv')
string="Export CSV Filename", size=128, default="account_export.csv"
)
@api.model @api.model
def _get_journal_default(self): def _get_journal_default(self):
@ -79,17 +83,19 @@ class AccountCSVExport(models.TransientModel):
def _get_company_default(self): def _get_company_default(self):
return self.env.user.company_id return self.env.user.company_id
@api.onchange('date_range_id')
@api.onchange("date_range_id")
def _onchange_date_range(self): def _onchange_date_range(self):
if self.date_range_id: if self.date_range_id:
self.date_start = self.date_range_id.date_start self.date_start = self.date_range_id.date_start
self.date_end = self.date_range_id.date_end self.date_end = self.date_range_id.date_end
@api.onchange('date_start', 'date_end')
@api.onchange("date_start", "date_end")
def _onchange_dates(self): def _onchange_dates(self):
if self.date_range_id: if self.date_range_id:
if self.date_start != self.date_range_id.date_start or \
self.date_end != self.date_range_id.date_end:
if (
self.date_start != self.date_range_id.date_start
or self.date_end != self.date_range_id.date_end
):
self.date_range_id = False self.date_range_id = False
def action_manual_export_account(self): def action_manual_export_account(self):
@ -100,25 +106,25 @@ class AccountCSVExport(models.TransientModel):
writer = AccountingWriter(file_data) writer = AccountingWriter(file_data)
writer.writerows(rows) writer.writerows(rows)
file_value = file_data.getvalue() file_value = file_data.getvalue()
self.write({'data': base64.encodestring(file_value)})
self.write({"data": base64.encodestring(file_value)})
finally: finally:
file_data.close() file_data.close()
return { return {
'type': 'ir.actions.act_window',
'res_model': 'account.csv.export',
'view_mode': 'form',
'res_id': self.id,
'views': [(False, 'form')],
'target': 'new',
"type": "ir.actions.act_window",
"res_model": "account.csv.export",
"view_mode": "form",
"res_id": self.id,
"views": [(False, "form")],
"target": "new",
} }
def _get_header_account(self): def _get_header_account(self):
return [ return [
_('CODE'),
_('NAME'),
_('DEBIT'),
_('CREDIT'),
_('BALANCE'),
_("CODE"),
_("NAME"),
_("DEBIT"),
_("CREDIT"),
_("BALANCE"),
] ]
def _get_rows_account(self, journal_ids): def _get_rows_account(self, journal_ids):
@ -126,7 +132,8 @@ class AccountCSVExport(models.TransientModel):
Return list to generate rows of the CSV file Return list to generate rows of the CSV file
""" """
self.ensure_one() self.ensure_one()
self.env.cr.execute("""
self.env.cr.execute(
"""
select ac.code,ac.name, select ac.code,ac.name,
sum(debit) as sum_debit, sum(debit) as sum_debit,
sum(credit) as sum_credit, sum(credit) as sum_credit,
@ -137,8 +144,9 @@ class AccountCSVExport(models.TransientModel):
AND aml.date <= %(date_end)s AND aml.date <= %(date_end)s
group by ac.id,ac.code,ac.name group by ac.id,ac.code,ac.name
order by ac.code order by ac.code
""", {'date_start': self.date_start,
'date_end': self.date_end})
""",
{"date_start": self.date_start, "date_end": self.date_end},
)
res = self.env.cr.fetchall() res = self.env.cr.fetchall()
rows = [] rows = []
@ -154,28 +162,28 @@ class AccountCSVExport(models.TransientModel):
writer = AccountingWriter(file_data) writer = AccountingWriter(file_data)
writer.writerows(rows) writer.writerows(rows)
file_value = file_data.getvalue() file_value = file_data.getvalue()
self.write({'data': base64.encodestring(file_value)})
self.write({"data": base64.encodestring(file_value)})
finally: finally:
file_data.close() file_data.close()
return { return {
'type': 'ir.actions.act_window',
'res_model': 'account.csv.export',
'view_mode': 'form',
'view_type': 'form',
'res_id': self.id,
'views': [(False, 'form')],
'target': 'new',
"type": "ir.actions.act_window",
"res_model": "account.csv.export",
"view_mode": "form",
"view_type": "form",
"res_id": self.id,
"views": [(False, "form")],
"target": "new",
} }
def _get_header_analytic(self): def _get_header_analytic(self):
return [ return [
_('ANALYTIC CODE'),
_('ANALYTIC NAME'),
_('CODE'),
_('ACCOUNT NAME'),
_('DEBIT'),
_('CREDIT'),
_('BALANCE'),
_("ANALYTIC CODE"),
_("ANALYTIC NAME"),
_("CODE"),
_("ACCOUNT NAME"),
_("DEBIT"),
_("CREDIT"),
_("BALANCE"),
] ]
def _get_rows_analytic(self, journal_ids): def _get_rows_analytic(self, journal_ids):
@ -183,7 +191,8 @@ class AccountCSVExport(models.TransientModel):
Return list to generate rows of the CSV file Return list to generate rows of the CSV file
""" """
self.ensure_one() self.ensure_one()
self.env.cr.execute(""" select aac.code as analytic_code,
self.env.cr.execute(
""" select aac.code as analytic_code,
aac.name as analytic_name, aac.name as analytic_name,
ac.code,ac.name, ac.code,ac.name,
sum(debit) as sum_debit, sum(debit) as sum_debit,
@ -198,8 +207,9 @@ class AccountCSVExport(models.TransientModel):
AND account_move_line.date <= %(date_end)s AND account_move_line.date <= %(date_end)s
group by aac.id,aac.code,aac.name,ac.id,ac.code,ac.name group by aac.id,aac.code,aac.name,ac.id,ac.code,ac.name
order by aac.code order by aac.code
""", {'date_start': self.date_start,
'date_end': self.date_end})
""",
{"date_start": self.date_start, "date_end": self.date_end},
)
res = self.env.cr.fetchall() res = self.env.cr.fetchall()
rows = [] rows = []
@ -235,44 +245,46 @@ class AccountCSVExport(models.TransientModel):
file_data.seek(0) file_data.seek(0)
base64.encode(file_data, base64_data) base64.encode(file_data, base64_data)
base64_data.seek(0) base64_data.seek(0)
self.env.cr.execute("""
self.env.cr.execute(
"""
UPDATE account_csv_export UPDATE account_csv_export
SET data = %s SET data = %s
WHERE id = %s""", (base64_data.read(), self.id))
WHERE id = %s""",
(base64_data.read(), self.id),
)
return { return {
'type': 'ir.actions.act_window',
'res_model': 'account.csv.export',
'view_mode': 'form',
'res_id': self.id,
'views': [(False, 'form')],
'target': 'new',
"type": "ir.actions.act_window",
"res_model": "account.csv.export",
"view_mode": "form",
"res_id": self.id,
"views": [(False, "form")],
"target": "new",
} }
def _get_header_journal_entries(self): def _get_header_journal_entries(self):
return [ return [
# Standard Sage export fields # Standard Sage export fields
_('DATE'),
_('JOURNAL CODE'),
_('ACCOUNT CODE'),
_('PARTNER NAME'),
_('REF'),
_('DESCRIPTION'),
_('DEBIT'),
_('CREDIT'),
_('FULL RECONCILE'),
_('ANALYTIC ACCOUNT CODE'),
_("DATE"),
_("JOURNAL CODE"),
_("ACCOUNT CODE"),
_("PARTNER NAME"),
_("REF"),
_("DESCRIPTION"),
_("DEBIT"),
_("CREDIT"),
_("FULL RECONCILE"),
_("ANALYTIC ACCOUNT CODE"),
# Other fields # Other fields
_('ENTRY NUMBER'),
_('ACCOUNT NAME'),
_('BALANCE'),
_('AMOUNT CURRENCY'),
_('CURRENCY'),
_('ANALYTIC ACCOUNT NAME'),
_('JOURNAL'),
_('TAX CODE'),
_('TAX NAME'),
_('BANK STATEMENT'),
_("ENTRY NUMBER"),
_("ACCOUNT NAME"),
_("BALANCE"),
_("AMOUNT CURRENCY"),
_("CURRENCY"),
_("ANALYTIC ACCOUNT NAME"),
_("JOURNAL"),
_("TAX CODE"),
_("TAX NAME"),
_("BANK STATEMENT"),
] ]
def _get_rows_journal_entries(self, journal_ids): def _get_rows_journal_entries(self, journal_ids):
@ -280,7 +292,8 @@ class AccountCSVExport(models.TransientModel):
Create a generator of rows of the CSV file Create a generator of rows of the CSV file
""" """
self.ensure_one() self.ensure_one()
self.env.cr.execute("""
self.env.cr.execute(
"""
SELECT SELECT
account_move_line.date AS date, account_move_line.date AS date,
account_journal.name as journal, account_journal.name as journal,
@ -326,9 +339,13 @@ class AccountCSVExport(models.TransientModel):
AND account_move_line.date <= %(date_end)s AND account_move_line.date <= %(date_end)s
AND account_journal.id IN %(journal_ids)s AND account_journal.id IN %(journal_ids)s
ORDER BY account_move_line.date ORDER BY account_move_line.date
""", {'journal_ids': tuple(journal_ids),
'date_start': self.date_start,
'date_end': self.date_end})
""",
{
"journal_ids": tuple(journal_ids),
"date_start": self.date_start,
"date_end": self.date_end,
},
)
while 1: while 1:
# http://initd.org/psycopg/docs/cursor.html#cursor.fetchmany # http://initd.org/psycopg/docs/cursor.html#cursor.fetchmany
# Set cursor.arraysize to minimize network round trips # Set cursor.arraysize to minimize network round trips
@ -341,14 +358,12 @@ class AccountCSVExport(models.TransientModel):
def _get_data(self, result_type): def _get_data(self, result_type):
self.ensure_one() self.ensure_one()
get_header_func = getattr(
self, ("_get_header_%s" % (result_type)), None)
get_header_func = getattr(self, ("_get_header_%s" % (result_type)), None)
get_rows_func = getattr(self, ("_get_rows_%s" % (result_type)), None) get_rows_func = getattr(self, ("_get_rows_%s" % (result_type)), None)
if self.journal_ids: if self.journal_ids:
journal_ids = [x.id for x in self.journal_ids] journal_ids = [x.id for x in self.journal_ids]
else: else:
j_obj = self.env["account.journal"] j_obj = self.env["account.journal"]
journal_ids = j_obj.search([]).ids journal_ids = j_obj.search([]).ids
rows = itertools.chain((get_header_func(),),
get_rows_func(journal_ids))
rows = itertools.chain((get_header_func(),), get_rows_func(journal_ids))
return rows return rows

46
account_export_csv/wizard/account_export_csv_view.xml

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8" ?>
<odoo> <odoo>
<record id="account_csv_export_view" model="ir.ui.view"> <record id="account_csv_export_view" model="ir.ui.view">
@ -13,12 +13,15 @@
</group> </group>
<group> <group>
<group> <group>
<field name="date_range_id" domain="['|', ('company_id', '=', company_id), ('company_id', '=', False)]"/>
<label for="date_start" string="Date" class="oe_inline"/>
<field
name="date_range_id"
domain="['|', ('company_id', '=', company_id), ('company_id', '=', False)]"
/>
<label for="date_start" string="Date" class="oe_inline" />
<div> <div>
<field name="date_start" class="oe_inline"/>
<span string="-" class="oe_inline"/>
<field name="date_end" class="oe_inline"/>
<field name="date_start" class="oe_inline" />
<span string="-" class="oe_inline" />
<field name="date_end" class="oe_inline" />
</div> </div>
</group> </group>
<group> <group>
@ -26,16 +29,31 @@
</group> </group>
<div> <div>
<label for="journal_ids" /> <label for="journal_ids" />
<field name="journal_ids"/>
<field name="journal_ids" />
</div> </div>
<separator string ="Report" colspan="4"/>
<separator string="Report" colspan="4" />
<group colspan="4"> <group colspan="4">
<field name="data" filename="export_filename"/>
<field name="data" filename="export_filename" />
</group> </group>
<footer> <footer>
<button name="action_manual_export_account" string="Trial Balance" type="object" icon="fa-cog"/>
<button name="action_manual_export_analytic" string="Analytic Balance (with accounts)" type="object" icon="fa-cog"/>
<button name="action_manual_export_journal_entries" string="Journal Entries" type="object" icon="fa-cog"/>
<button
name="action_manual_export_account"
string="Trial Balance"
type="object"
icon="fa-cog"
/>
<button
name="action_manual_export_analytic"
string="Analytic Balance (with accounts)"
type="object"
icon="fa-cog"
/>
<button
name="action_manual_export_journal_entries"
string="Journal Entries"
type="object"
icon="fa-cog"
/>
or or
<button string="Close" class="oe_link" special="cancel" /> <button string="Close" class="oe_link" special="cancel" />
</footer> </footer>
@ -49,7 +67,7 @@
<field name="res_model">account.csv.export</field> <field name="res_model">account.csv.export</field>
<field name="type">ir.actions.act_window</field> <field name="type">ir.actions.act_window</field>
<field name="view_mode">form</field> <field name="view_mode">form</field>
<field name="view_id" ref="account_csv_export_view"/>
<field name="view_id" ref="account_csv_export_view" />
<field name="target">new</field> <field name="target">new</field>
</record> </record>
@ -59,6 +77,6 @@
id="menu_account_csv_export" id="menu_account_csv_export"
parent="account.menu_finance_reports" parent="account.menu_finance_reports"
sequence="110" sequence="110"
/>
/>
</odoo> </odoo>

1
setup/account_export_csv/odoo/addons/account_export_csv

@ -0,0 +1 @@
../../../../account_export_csv

6
setup/account_export_csv/setup.py

@ -0,0 +1,6 @@
import setuptools
setuptools.setup(
setup_requires=['setuptools-odoo'],
odoo_addon=True,
)
Loading…
Cancel
Save