Skip to content

Commit

Permalink
Merge 756557f into 6f7cce5
Browse files Browse the repository at this point in the history
  • Loading branch information
guewen committed Oct 4, 2019
2 parents 6f7cce5 + 756557f commit 9c39768
Show file tree
Hide file tree
Showing 51 changed files with 1,634 additions and 1,498 deletions.
15 changes: 15 additions & 0 deletions .flake8
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[flake8]
max-line-length = 80
max-complexity = 16
# B = bugbear
# B9 = bugbear opinionated (incl line length)
select = C,E,F,W,B,B9
# E203: whitespace before ':' (black behaviour)
# E501: flake8 line length (covered by bugbear B950)
# W503: line break before binary operator (black behaviour)
ignore = E203,E501,W503
exclude =
./.git
./src
./venv*
.eggs/
9 changes: 9 additions & 0 deletions .isort.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[settings]
; see https://github.com/psf/black
multi_line_output=3
include_trailing_comma=True
force_grid_wrap=0
combine_as_imports=True
use_parentheses=True
line_length=88
known_third_party =dateutil,mock,odoo,psycopg2,requests,setuptools
45 changes: 45 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
exclude: "^(setup/)|.pot$|.po$|README.rst"
repos:
- repo: https://github.com/ambv/black
rev: 19.3b0
hooks:
- id: black
language_version: python3
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v2.3.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: debug-statements
- id: flake8
name: flake8 except __init__.py
args: [--exclude=__init__.py]
additional_dependencies: ["flake8-bugbear == 18.8.0"]
language_version: python3
- id: flake8
name: flake8 only __init__.py
args: [--ignore=E501 F401] # ignore imported unused in __init__.py
files: __init__.py
language_version: python3
- repo: https://github.com/pre-commit/mirrors-pylint
rev: v2.3.1
hooks:
- id: pylint
name: pylint odoo
additional_dependencies: [pylint-odoo==3.0.3]
language_version: python3
- repo: https://github.com/asottile/pyupgrade
rev: v1.24.0
hooks:
- id: pyupgrade
language_version: python3
- repo: https://github.com/asottile/seed-isort-config
rev: v1.3.0
hooks:
- id: seed-isort-config
language_version: python3
- repo: https://github.com/pre-commit/mirrors-isort
rev: v4.3.4
hooks:
- id: isort
language_version: python3
62 changes: 62 additions & 0 deletions .pylintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
[MASTER]
profile=no
ignore=CVS,.git,scenarios,.bzr
persistent=yes
cache-size=500
load-plugins=pylint_odoo

[ODOOLINT]
readme_template_url="https://github.com/OCA/maintainer-tools/blob/master/template/module/README.rst"
manifest_required_authors=Odoo Community Association (OCA)
manifest_required_keys=license
manifest_deprecated_keys=description,active
license_allowed=AGPL-3,GPL-2,GPL-2 or any later version,GPL-3,GPL-3 or any later version,LGPL-3
valid_odoo_versions=12.0

[MESSAGES CONTROL]
disable=all

enable=anomalous-backslash-in-string,
assignment-from-none,
dangerous-default-value,
duplicate-key,
eval-referenced,
eval-used,
license-allowed,
manifest-author-string,
manifest-required-author,
manifest-required-key,
manifest-version-format,
missing-import-error,
missing-manifest-dependency,
pointless-statement,
pointless-string-statement,
print-used,
redundant-keyword-arg,
reimported,
relative-import,
return-in-init,
rst-syntax-error,
too-few-format-args,
unreachable

[REPORTS]
msg-template={path}:{line}: [{msg_id}({symbol}), {obj}] {msg}
output-format=colorized
files-output=no
reports=no
evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
comment=no

[FORMAT]
indent-string=' '

[SIMILARITIES]
ignore-comments=yes
ignore-docstrings=yes

[MISCELLANEOUS]
notes=

[IMPORTS]
deprecated-modules=pdb,pudb,ipdb,openerp.osv
36 changes: 16 additions & 20 deletions base_export_async/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,23 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

{
'name': 'Base Export Async',
'summary': """
"name": "Base Export Async",
"summary": """
Asynchronous export with job queue
""",
'version': '12.0.1.0.0',
'license': 'AGPL-3',
'author': 'ACSONE SA/NV, Odoo Community Association (OCA)',
'website': 'https://github.com/OCA/queue',
'depends': [
'web',
'queue_job'
"version": "12.0.1.0.0",
"license": "AGPL-3",
"author": "ACSONE SA/NV, Odoo Community Association (OCA)",
"website": "https://github.com/OCA/queue",
"depends": ["web", "queue_job"],
"data": [
"views/assets.xml",
"security/ir.model.access.csv",
"security/ir_rule.xml",
"data/config_parameter.xml",
"data/cron.xml",
],
'data': [
'views/assets.xml',
'security/ir.model.access.csv',
'security/ir_rule.xml',
'data/config_parameter.xml',
'data/cron.xml',
],
'demo': [
],
'qweb': ['static/src/xml/base.xml'],
'installable': False,
"demo": [],
"qweb": ["static/src/xml/base.xml"],
"installable": False,
}
115 changes: 63 additions & 52 deletions base_export_async/models/delay_export.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
# Copyright 2019 ACSONE SA/NV
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

import logging
import base64
import json
import logging
import operator
import base64
from dateutil.relativedelta import relativedelta

from odoo import api, fields, models, _
from dateutil.relativedelta import relativedelta
from odoo import _, api, fields, models
from odoo.addons.queue_job.job import job
from odoo.addons.web.controllers.main import CSVExport, ExcelExport
from odoo.exceptions import UserError
Expand All @@ -17,49 +17,49 @@

class DelayExport(models.Model):

_name = 'delay.export'
_description = 'Allow to delay the export'
_name = "delay.export"
_description = "Allow to delay the export"

user_id = fields.Many2one('res.users', string='User', index=True)
user_id = fields.Many2one("res.users", string="User", index=True)

@api.model
def delay_export(self, data):
params = json.loads(data.get('data'))
params = json.loads(data.get("data"))
if not self.env.user.email:
raise UserError(_("You must set an email address to your user."))
self.with_delay().export(params)

@api.model
def _get_file_content(self, params):
export_format = params.get('format')
raw_data = export_format != 'csv'
export_format = params.get("format")
raw_data = export_format != "csv"

model_name, fields_name, ids, domain, import_compat, context = \
operator.itemgetter('model', 'fields', 'ids',
'domain', 'import_compat', 'context')(params)
user = self.env['res.users'].browse([context.get('uid')])
item_names = ("model", "fields", "ids", "domain", "import_compat", "context")
items = operator.itemgetter(item_names)(params)
model_name, fields_name, ids, domain, import_compat, context = items
user = self.env["res.users"].browse([context.get("uid")])
if not user or not user.email:
raise UserError(_("The user doesn't have an email address."))

model = self.env[model_name].with_context(
import_compat=import_compat, **context)
import_compat=import_compat, **context
)
records = model.browse(ids) or model.search(
domain, offset=0, limit=False, order=False)
domain, offset=0, limit=False, order=False
)

if not model._is_an_ordinary_table():
fields_name = [field for field in fields_name
if field['name'] != 'id']
fields_name = [field for field in fields_name if field["name"] != "id"]

field_names = [f['name'] for f in fields_name]
import_data = records.export_data(
field_names, raw_data).get('datas', [])
field_names = [f["name"] for f in fields_name]
import_data = records.export_data(field_names, raw_data).get("datas", [])

if import_compat:
columns_headers = field_names
else:
columns_headers = [val['label'].strip() for val in fields_name]
columns_headers = [val["label"].strip() for val in fields_name]

if export_format == 'csv':
if export_format == "csv":
csv = CSVExport()
return csv.from_data(columns_headers, import_data)
else:
Expand All @@ -71,59 +71,70 @@ def _get_file_content(self, params):
def export(self, params):
content = self._get_file_content(params)

model_name, context, export_format = \
operator.itemgetter('model', 'context', 'format')(params)
user = self.env['res.users'].browse([context.get('uid')])
model_name, context, export_format = operator.itemgetter(
"model", "context", "format"
)(params)
user = self.env["res.users"].browse([context.get("uid")])

export_record = self.sudo().create({'user_id': user.id})
export_record = self.sudo().create({"user_id": user.id})

name = "{}.{}".format(model_name, export_format)
attachment = self.env['ir.attachment'].create({
'name': name,
'datas': base64.b64encode(content),
'datas_fname': name,
'type': 'binary',
'res_model': self._name,
'res_id': export_record.id,
})
attachment = self.env["ir.attachment"].create(
{
"name": name,
"datas": base64.b64encode(content),
"datas_fname": name,
"type": "binary",
"res_model": self._name,
"res_id": export_record.id,
}
)

url = "{}/web/content/ir.attachment/{}/datas/{}?download=true".format(
self.env['ir.config_parameter'].sudo().get_param('web.base.url'),
self.env["ir.config_parameter"].sudo().get_param("web.base.url"),
attachment.id,
attachment.name,
)

time_to_live = self.env['ir.config_parameter'].sudo(). \
get_param('attachment.ttl', 7)
time_to_live = (
self.env["ir.config_parameter"].sudo().get_param("attachment.ttl", 7)
)
date_today = fields.Date.today()
expiration_date = fields.Date.to_string(
date_today + relativedelta(days=+int(time_to_live)))
date_today + relativedelta(days=+int(time_to_live))
)

# TODO : move to email template
odoo_bot = self.sudo().env.ref("base.partner_root")
email_from = odoo_bot.email
model_description = self.env[model_name]._description
self.env['mail.mail'].create({
'email_from': email_from,
'reply_to': email_from,
'email_to': user.email,
'subject': _("Export {} {}").format(
model_description, fields.Date.to_string(fields.Date.today())),
'body_html': _("""
self.env["mail.mail"].create(
{
"email_from": email_from,
"reply_to": email_from,
"email_to": user.email,
"subject": _("Export {} {}").format(
model_description, fields.Date.to_string(fields.Date.today())
),
"body_html": _(
"""
<p>Your export is available <a href="{}">here</a>.</p>
<p>It will be automatically deleted the {}.</p>
<p>&nbsp;</p>
<p><span style="color: #808080;">
This is an automated message please do not reply.
</span></p>
""").format(url, expiration_date),
'auto_delete': True,
})
"""
).format(url, expiration_date),
"auto_delete": True,
}
)

@api.model
def cron_delete(self):
time_to_live = self.env['ir.config_parameter'].sudo(). \
get_param('attachment.ttl', 7)
time_to_live = (
self.env["ir.config_parameter"].sudo().get_param("attachment.ttl", 7)
)
date_today = fields.Date.today()
date_to_delete = date_today + relativedelta(days=-int(time_to_live))
self.search([('create_date', '<=', date_to_delete)]).unlink()
self.search([("create_date", "<=", date_to_delete)]).unlink()
4 changes: 2 additions & 2 deletions base_export_async/readme/USAGE.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
The user is presented with a new checkbox "Asynchronous export"
in the export screen. When selected, the export is delayed in a
The user is presented with a new checkbox "Asynchronous export"
in the export screen. When selected, the export is delayed in a
background job.

The .csv or .xls file generated by the export will be sent by email
Expand Down
Loading

0 comments on commit 9c39768

Please sign in to comment.