[REF] apply black on the code
parent
8d469681fd
commit
68bbb49fec
|
@ -2,27 +2,22 @@
|
||||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||||
|
|
||||||
{
|
{
|
||||||
'name': 'Attachment Queue',
|
"name": "Attachment Queue",
|
||||||
'version': '12.0.1.0.0',
|
"version": "12.0.1.0.0",
|
||||||
'author': 'Akretion,Odoo Community Association (OCA)',
|
"author": "Akretion,Odoo Community Association (OCA)",
|
||||||
'summary': "Base module that add the concept of queue for processing file",
|
"summary": "Base module adding the concept of queue for processing file",
|
||||||
'website': 'https://github.com/OCA/server-tools',
|
"website": "https://github.com/OCA/server-tools",
|
||||||
'maintainers': ['florian-dacosta', 'sebastienbeau'],
|
"maintainers": ["florian-dacosta", "sebastienbeau"],
|
||||||
'license': 'AGPL-3',
|
"license": "AGPL-3",
|
||||||
'category': 'Generic Modules',
|
"category": "Generic Modules",
|
||||||
'depends': [
|
"depends": ["base", "mail"],
|
||||||
'base',
|
"data": [
|
||||||
'mail',
|
"views/attachment_queue_view.xml",
|
||||||
|
"security/ir.model.access.csv",
|
||||||
|
"data/cron.xml",
|
||||||
|
"data/ir_config_parameter.xml",
|
||||||
|
"data/mail_template.xml",
|
||||||
],
|
],
|
||||||
'data': [
|
"demo": ["demo/attachment_queue_demo.xml"],
|
||||||
'views/attachment_queue_view.xml',
|
"installable": True,
|
||||||
'security/ir.model.access.csv',
|
|
||||||
'data/cron.xml',
|
|
||||||
'data/ir_config_parameter.xml',
|
|
||||||
'data/mail_template.xml',
|
|
||||||
],
|
|
||||||
'demo': [
|
|
||||||
'demo/attachment_queue_demo.xml'
|
|
||||||
],
|
|
||||||
'installable': True,
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,36 +1,42 @@
|
||||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
from odoo import api, fields, models, registry
|
|
||||||
|
|
||||||
|
from odoo import api, fields, models, registry
|
||||||
|
|
||||||
_logger = logging.getLogger(__name__)
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class AttachmentQueue(models.Model):
|
class AttachmentQueue(models.Model):
|
||||||
_name = 'attachment.queue'
|
_name = "attachment.queue"
|
||||||
_inherits = {'ir.attachment': 'attachment_id'}
|
_inherits = {"ir.attachment": "attachment_id"}
|
||||||
_inherit = ['mail.thread']
|
_inherit = ["mail.thread"]
|
||||||
|
|
||||||
attachment_id = fields.Many2one(
|
attachment_id = fields.Many2one(
|
||||||
'ir.attachment', required=True, ondelete='cascade',
|
"ir.attachment",
|
||||||
help="Link to ir.attachment model ")
|
required=True,
|
||||||
|
ondelete="cascade",
|
||||||
|
help="Link to ir.attachment model ",
|
||||||
|
)
|
||||||
file_type = fields.Selection(
|
file_type = fields.Selection(
|
||||||
selection=[],
|
selection=[],
|
||||||
help="The file type determines an import method to be used "
|
help="The file type determines an import method to be used "
|
||||||
"to parse and transform data before their import in ERP or an export")
|
"to parse and transform data before their import in ERP or an export",
|
||||||
|
)
|
||||||
date_done = fields.Datetime()
|
date_done = fields.Datetime()
|
||||||
state = fields.Selection([
|
state = fields.Selection(
|
||||||
('pending', 'Pending'),
|
[("pending", "Pending"), ("failed", "Failed"), ("done", "Done")],
|
||||||
('failed', 'Failed'),
|
readonly=False,
|
||||||
('done', 'Done'),
|
required=True,
|
||||||
], readonly=False, required=True, default='pending')
|
default="pending",
|
||||||
|
)
|
||||||
state_message = fields.Text()
|
state_message = fields.Text()
|
||||||
failure_emails = fields.Char(
|
failure_emails = fields.Char(
|
||||||
compute='_compute_failure_emails',
|
compute="_compute_failure_emails",
|
||||||
string="Failure Emails",
|
string="Failure Emails",
|
||||||
help="list of email (separated by comma) which should be notified in "
|
help="Comma-separated list of email addresses to be notified in case of"
|
||||||
"case of failure")
|
"failure",
|
||||||
|
)
|
||||||
|
|
||||||
def _compute_failure_emails(self):
|
def _compute_failure_emails(self):
|
||||||
for attach in self:
|
for attach in self:
|
||||||
|
@ -44,10 +50,10 @@ class AttachmentQueue(models.Model):
|
||||||
@api.model
|
@api.model
|
||||||
def run_attachment_queue_scheduler(self, domain=None):
|
def run_attachment_queue_scheduler(self, domain=None):
|
||||||
if domain is None:
|
if domain is None:
|
||||||
domain = [('state', '=', 'pending')]
|
domain = [("state", "=", "pending")]
|
||||||
batch_limit = self.env.ref(
|
batch_limit = self.env.ref(
|
||||||
'attachment_queue.attachment_queue_cron_batch_limit') \
|
"attachment_queue.attachment_queue_cron_batch_limit"
|
||||||
.value
|
).value
|
||||||
if batch_limit and batch_limit.isdigit():
|
if batch_limit and batch_limit.isdigit():
|
||||||
limit = int(batch_limit)
|
limit = int(batch_limit)
|
||||||
else:
|
else:
|
||||||
|
@ -62,12 +68,14 @@ class AttachmentQueue(models.Model):
|
||||||
Run the process for each attachment queue
|
Run the process for each attachment queue
|
||||||
"""
|
"""
|
||||||
failure_tmpl = self.env.ref(
|
failure_tmpl = self.env.ref(
|
||||||
'attachment_queue.attachment_failure_notification')
|
"attachment_queue.attachment_failure_notification"
|
||||||
|
)
|
||||||
for attachment in self:
|
for attachment in self:
|
||||||
with api.Environment.manage():
|
with api.Environment.manage():
|
||||||
with registry(self.env.cr.dbname).cursor() as new_cr:
|
with registry(self.env.cr.dbname).cursor() as new_cr:
|
||||||
new_env = api.Environment(
|
new_env = api.Environment(
|
||||||
new_cr, self.env.uid, self.env.context)
|
new_cr, self.env.uid, self.env.context
|
||||||
|
)
|
||||||
attach = attachment.with_env(new_env)
|
attach = attachment.with_env(new_env)
|
||||||
try:
|
try:
|
||||||
attach._run()
|
attach._run()
|
||||||
|
@ -75,32 +83,29 @@ class AttachmentQueue(models.Model):
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
attach.env.cr.rollback()
|
attach.env.cr.rollback()
|
||||||
_logger.exception(str(e))
|
_logger.exception(str(e))
|
||||||
attach.write({
|
attach.write(
|
||||||
'state': 'failed',
|
{"state": "failed", "state_message": str(e)}
|
||||||
'state_message': str(e),
|
)
|
||||||
})
|
|
||||||
emails = attach.failure_emails
|
emails = attach.failure_emails
|
||||||
if emails:
|
if emails:
|
||||||
failure_tmpl.send_mail(attach.id)
|
failure_tmpl.send_mail(attach.id)
|
||||||
attach.env.cr.commit()
|
attach.env.cr.commit()
|
||||||
else:
|
else:
|
||||||
vals = {
|
vals = {
|
||||||
'state': 'done',
|
"state": "done",
|
||||||
'date_done': fields.Datetime.now(),
|
"date_done": fields.Datetime.now(),
|
||||||
}
|
}
|
||||||
attach.write(vals)
|
attach.write(vals)
|
||||||
attach.env.cr.commit()
|
attach.env.cr.commit()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@api.multi
|
|
||||||
def _run(self):
|
def _run(self):
|
||||||
self.ensure_one()
|
self.ensure_one()
|
||||||
_logger.info('Start to process attachment queue id %d', self.id)
|
_logger.info("Starting processing of attachment queue id %d", self.id)
|
||||||
|
|
||||||
@api.multi
|
|
||||||
def set_done(self):
|
def set_done(self):
|
||||||
"""
|
"""
|
||||||
Manually set to done
|
Manually set to done
|
||||||
"""
|
"""
|
||||||
message = "Manually set to done by %s" % self.env.user.name
|
message = "Manually set to done by %s" % self.env.user.name
|
||||||
self.write({'state_message': message, 'state': 'done'})
|
self.write({"state_message": message, "state": "done"})
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
This module implement a queue for processing file.
|
This module adds async processing capabilities to attachments by implementing a new model attachment.queue that wraps attachments and stores additional information so that it can be processed in an asynchronous way.
|
||||||
File are stored in Odoo standard ir.attachment.
|
|
||||||
The attachments will be processed depending on their type.
|
|
||||||
|
|
||||||
An example of the use of this module, can be found in the module `attachment_synchronize`.
|
A use case of this module can be found in the attachment_synchronize module.
|
||||||
|
|
|
@ -6,3 +6,12 @@ Configure the batch limit for attachments that can be sync by the cron task at a
|
||||||
|
|
||||||
Settings > Technical > System parameters > attachment_queue_cron_batch_limit
|
Settings > Technical > System parameters > attachment_queue_cron_batch_limit
|
||||||
|
|
||||||
|
|
||||||
|
image:: ../static/description/tree.png
|
||||||
|
|
||||||
|
|
||||||
|
This module can be used in combination with attachment_synchronize to control file processing workflow
|
||||||
|
|
||||||
|
|
||||||
|
image:: ../static/description/form.png
|
||||||
|
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 75 KiB |
Binary file not shown.
After Width: | Height: | Size: 41 KiB |
|
@ -1,18 +1,20 @@
|
||||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
|
||||||
from odoo.tests.common import TransactionCase
|
|
||||||
import odoo
|
import odoo
|
||||||
from odoo import api
|
from odoo import api
|
||||||
|
from odoo.tests.common import TransactionCase
|
||||||
|
|
||||||
|
|
||||||
class TestAttachmentBaseQueue(TransactionCase):
|
class TestAttachmentBaseQueue(TransactionCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super().setUp()
|
super().setUp()
|
||||||
self.registry.enter_test_mode(self.env.cr)
|
self.registry.enter_test_mode(self.env.cr)
|
||||||
self.env = api.Environment(self.registry.test_cr, self.env.uid,
|
self.env = api.Environment(
|
||||||
self.env.context)
|
self.registry.test_cr, self.env.uid, self.env.context
|
||||||
self.attachment = self.env.ref('attachment_queue.attachment_queue_demo')
|
)
|
||||||
|
self.attachment = self.env.ref(
|
||||||
|
"attachment_queue.attachment_queue_demo"
|
||||||
|
)
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
self.registry.leave_test_mode()
|
self.registry.leave_test_mode()
|
||||||
|
@ -21,30 +23,17 @@ class TestAttachmentBaseQueue(TransactionCase):
|
||||||
def test_attachment_queue(self):
|
def test_attachment_queue(self):
|
||||||
"""Test run_attachment_queue_scheduler to ensure set state to done
|
"""Test run_attachment_queue_scheduler to ensure set state to done
|
||||||
"""
|
"""
|
||||||
self.assertEqual(
|
self.assertEqual(self.attachment.state, "pending")
|
||||||
self.attachment.state,
|
self.env["attachment.queue"].run_attachment_queue_scheduler()
|
||||||
'pending'
|
|
||||||
)
|
|
||||||
self.env['attachment.queue'].run_attachment_queue_scheduler()
|
|
||||||
self.env.cache.invalidate()
|
self.env.cache.invalidate()
|
||||||
with odoo.registry(self.env.cr.dbname).cursor() as new_cr:
|
with odoo.registry(self.env.cr.dbname).cursor() as new_cr:
|
||||||
new_env = api.Environment(
|
new_env = api.Environment(new_cr, self.env.uid, self.env.context)
|
||||||
new_cr, self.env.uid, self.env.context)
|
|
||||||
attach = self.attachment.with_env(new_env)
|
attach = self.attachment.with_env(new_env)
|
||||||
self.assertEqual(
|
self.assertEqual(attach.state, "done")
|
||||||
attach.state,
|
|
||||||
'done'
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_set_done(self):
|
def test_set_done(self):
|
||||||
"""Test set_done manually
|
"""Test set_done manually
|
||||||
"""
|
"""
|
||||||
self.assertEqual(
|
self.assertEqual(self.attachment.state, "pending")
|
||||||
self.attachment.state,
|
|
||||||
'pending'
|
|
||||||
)
|
|
||||||
self.attachment.set_done()
|
self.attachment.set_done()
|
||||||
self.assertEqual(
|
self.assertEqual(self.attachment.state, "done")
|
||||||
self.attachment.state,
|
|
||||||
'done'
|
|
||||||
)
|
|
||||||
|
|
|
@ -63,10 +63,10 @@
|
||||||
<filter string="Failed" name="failed" domain="[('state', '=', 'failed')]"/>
|
<filter string="Failed" name="failed" domain="[('state', '=', 'failed')]"/>
|
||||||
<filter string="Done" name="done" domain="[('state', '=', 'done')]"/>
|
<filter string="Done" name="done" domain="[('state', '=', 'done')]"/>
|
||||||
<group expand="0" string="Group By">
|
<group expand="0" string="Group By">
|
||||||
<filter string="Owner" name="owner" icon="terp-personal" domain="[]" context="{'group_by':'create_uid'}"/>
|
<filter string="Owner" name="owner" domain="[]" context="{'group_by':'create_uid'}"/>
|
||||||
<filter string="Type" name="type" icon="terp-stock_symbol-selection" domain="[]" context="{'group_by':'type'}" groups="base.group_no_one"/>
|
<filter string="Type" name="type" domain="[]" context="{'group_by':'type'}" groups="base.group_no_one"/>
|
||||||
<filter string="Company" name="company" icon="terp-gtk-home" domain="[]" context="{'group_by':'company_id'}" groups="base.group_multi_company"/>
|
<filter string="Company" name="company" domain="[]" context="{'group_by':'company_id'}" groups="base.group_multi_company"/>
|
||||||
<filter string="Creation Month" name="creation_month" icon="terp-go-month" domain="[]" context="{'group_by':'create_date'}"/>
|
<filter string="Creation Month" name="creation_month" domain="[]" context="{'group_by':'create_date'}"/>
|
||||||
<filter string="State" name="state" domain="[]" context="{'group_by': 'state'}"/>
|
<filter string="State" name="state" domain="[]" context="{'group_by': 'state'}"/>
|
||||||
<filter string="File type" name="file_type" domain="[]" context="{'group_by': 'file_type'}"/>
|
<filter string="File type" name="file_type" domain="[]" context="{'group_by': 'file_type'}"/>
|
||||||
</group>
|
</group>
|
||||||
|
|
Loading…
Reference in New Issue