Merge branch 'master-recurring-fatemi' into 'master'

[ADD]:Added recurring,recurring_sale,recurring_purchase,recurring_account

See merge request flectra-hq/flectra!125
This commit is contained in:
Parthiv Patel 2018-08-06 05:24:35 +00:00
commit 61bfc2a2d3
65 changed files with 1978 additions and 0 deletions

View File

@ -0,0 +1,5 @@
# -*- coding: utf-8 -*-
# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing
# details.
from . import models

View File

@ -0,0 +1,28 @@
# -*- coding: utf-8 -*-
# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing
# details.
{
'name': 'Recurring Documents',
'category': 'Extra Tools',
'description': """
Create recurring documents.
===========================
This module allows to create new documents and add recurring on that
document.
e.g. To have an invoice generated automatically periodically:
-------------------------------------------------------------
* Define a document type based on Invoice object
* Define a recurring whose source document is the document defined as
above. Specify the interval information and partner to be invoiced.
Module taken from odoov10 subscription.
""",
'depends': ['base'],
'data': [
'security/ir.model.access.csv',
'views/recurring_view.xml',
],
'demo': ['demo/recurring_demo.xml'],
}

View File

@ -0,0 +1,27 @@
<?xml version="1.0" ?>
<flectra noupdate="1">
<record id="recurring_document_partner0" model="recurring.document">
<field eval="1" name="active"/>
<field name="model" ref="base.model_res_partner"/>
<field name="name">Partner</field>
</record>
<record id="recurring_document_fields_2" model="recurring.document.fields">
<field name="field" ref="base.field_res_partner_name"/>
<field name="value">false</field>
<field model="recurring.document" name="document_id" search="[('name', '=', u'Partner')]"/>
</record>
<record id="recurring_document_fields_3" model="recurring.document.fields">
<field name="field" ref="base.field_res_partner_child_ids"/>
<field model="recurring.document" name="document_id" search="[('name', '=', u'Partner')]"/>
</record>
<record id="recurring_partner0" model="recurring">
<field name="name">Partner Recurring</field>
<field name="exec_init">5</field>
<field name="interval_type">minutes</field>
<field name="date_init" eval="datetime.now()"/>
<field name="doc_source" ref='base.res_partner_2'/>
</record>
</flectra>

View File

@ -0,0 +1,392 @@
# Translation of Flectra Server.
# This file contains the translation of the following modules:
# * recurring
#
msgid ""
msgstr ""
"Project-Id-Version: Flectra Server 1.3\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-08-01 17:11+0000\n"
"PO-Revision-Date: 2018-08-01 17:11+0000\n"
"Last-Translator: <>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: recurring
#: model:ir.model.fields,field_description:recurring.field_recurring_active
#: model:ir.model.fields,field_description:recurring.field_recurring_document_active
msgid "Active"
msgstr ""
#. module: recurring
#: model:ir.ui.view,arch_db:recurring.view_recurring_wizard_form
msgid "Cancel"
msgstr ""
#. module: recurring
#: model:ir.model.fields,field_description:recurring.field_recurring_create_uid
#: model:ir.model.fields,field_description:recurring.field_recurring_document_create_uid
#: model:ir.model.fields,field_description:recurring.field_recurring_document_fields_create_uid
#: model:ir.model.fields,field_description:recurring.field_recurring_history_create_uid
msgid "Created by"
msgstr ""
#. module: recurring
#: model:ir.model.fields,field_description:recurring.field_recurring_create_date
#: model:ir.model.fields,field_description:recurring.field_recurring_document_create_date
#: model:ir.model.fields,field_description:recurring.field_recurring_document_fields_create_date
#: model:ir.model.fields,field_description:recurring.field_recurring_history_create_date
msgid "Created on"
msgstr ""
#. module: recurring
#: model:ir.model.fields,field_description:recurring.field_recurring_cron_id
msgid "Cron Job"
msgstr ""
#. module: recurring
#: code:addons/recurring/tests/test_recurring.py:21
#, python-format
msgid "Cron is not created"
msgstr ""
#. module: recurring
#: selection:recurring.document.fields,value:0
msgid "Current Date"
msgstr ""
#. module: recurring
#: model:ir.model.fields,field_description:recurring.field_recurring_history_date
msgid "Date"
msgstr ""
#. module: recurring
#: selection:recurring,interval_type:0
msgid "Days"
msgstr ""
#. module: recurring
#: model:ir.model.fields,field_description:recurring.field_recurring_document_fields_value
msgid "Default Value"
msgstr ""
#. module: recurring
#: model:ir.model.fields,help:recurring.field_recurring_document_fields_value
msgid "Default value is considered for field when new document is generated."
msgstr ""
#. module: recurring
#: model:ir.model.fields,help:recurring.field_recurring_note
msgid "Description or Summary of Recurring"
msgstr ""
#. module: recurring
#: model:ir.model.fields,field_description:recurring.field_recurring_display_name
#: model:ir.model.fields,field_description:recurring.field_recurring_document_display_name
#: model:ir.model.fields,field_description:recurring.field_recurring_document_fields_display_name
#: model:ir.model.fields,field_description:recurring.field_recurring_history_display_name
msgid "Display Name"
msgstr ""
#. module: recurring
#: model:ir.model.fields,field_description:recurring.field_recurring_doc_lines
#: model:ir.ui.view,arch_db:recurring.view_recurring_form
msgid "Documents created"
msgstr ""
#. module: recurring
#: selection:recurring,state:0
msgid "Done"
msgstr ""
#. module: recurring
#: selection:recurring,state:0
msgid "Draft"
msgstr ""
#. module: recurring
#: selection:recurring.document.fields,value:0
msgid "False"
msgstr ""
#. module: recurring
#: model:ir.model.fields,field_description:recurring.field_recurring_document_fields_field
msgid "Field"
msgstr ""
#. module: recurring
#: model:ir.model.fields,field_description:recurring.field_recurring_document_field_ids
msgid "Fields"
msgstr ""
#. module: recurring
#: model:ir.model.fields,field_description:recurring.field_recurring_date_init
msgid "First Date"
msgstr ""
#. module: recurring
#: model:ir.ui.view,arch_db:recurring.view_recurring_filter
msgid "Group By"
msgstr ""
#. module: recurring
#: selection:recurring,interval_type:0
msgid "Hours"
msgstr ""
#. module: recurring
#: model:ir.model.fields,field_description:recurring.field_recurring_document_fields_id
#: model:ir.model.fields,field_description:recurring.field_recurring_document_id
#: model:ir.model.fields,field_description:recurring.field_recurring_history_id
#: model:ir.model.fields,field_description:recurring.field_recurring_id
msgid "ID"
msgstr ""
#. module: recurring
#: model:ir.ui.view,arch_db:recurring.view_recurring_wizard_form
msgid "IR Recurring"
msgstr ""
#. module: recurring
#: model:ir.model.fields,help:recurring.field_recurring_document_active
msgid "If the active field is set to False, it will allow you to hide the recurring document without removing it."
msgstr ""
#. module: recurring
#: model:ir.model.fields,help:recurring.field_recurring_active
msgid "If the active field is set to False, it will allow you to hide the recurring without removing it."
msgstr ""
#. module: recurring
#: model:ir.model.fields,field_description:recurring.field_recurring_notes
#: model:ir.ui.view,arch_db:recurring.view_recurring_form
msgid "Internal Notes"
msgstr ""
#. module: recurring
#: model:ir.model.fields,field_description:recurring.field_recurring_interval_number
msgid "Internal Qty"
msgstr ""
#. module: recurring
#: model:ir.model.fields,field_description:recurring.field_recurring_interval_type
msgid "Interval Unit"
msgstr ""
#. module: recurring
#: model:ir.model.fields,field_description:recurring.field_recurring___last_update
#: model:ir.model.fields,field_description:recurring.field_recurring_document___last_update
#: model:ir.model.fields,field_description:recurring.field_recurring_document_fields___last_update
#: model:ir.model.fields,field_description:recurring.field_recurring_history___last_update
msgid "Last Modified on"
msgstr ""
#. module: recurring
#: model:ir.model.fields,field_description:recurring.field_recurring_document_fields_write_uid
#: model:ir.model.fields,field_description:recurring.field_recurring_document_write_uid
#: model:ir.model.fields,field_description:recurring.field_recurring_history_write_uid
#: model:ir.model.fields,field_description:recurring.field_recurring_write_uid
msgid "Last Updated by"
msgstr ""
#. module: recurring
#: model:ir.model.fields,field_description:recurring.field_recurring_document_fields_write_date
#: model:ir.model.fields,field_description:recurring.field_recurring_document_write_date
#: model:ir.model.fields,field_description:recurring.field_recurring_history_write_date
#: model:ir.model.fields,field_description:recurring.field_recurring_write_date
msgid "Last Updated on"
msgstr ""
#. module: recurring
#: selection:recurring,interval_type:0
msgid "Minutes"
msgstr ""
#. module: recurring
#: selection:recurring,interval_type:0
msgid "Months"
msgstr ""
#. module: recurring
#: model:ir.model.fields,field_description:recurring.field_recurring_document_name
#: model:ir.model.fields,field_description:recurring.field_recurring_name
msgid "Name"
msgstr ""
#. module: recurring
#: model:ir.model.fields,field_description:recurring.field_recurring_note
#: model:ir.ui.view,arch_db:recurring.view_recurring_form
msgid "Notes"
msgstr ""
#. module: recurring
#: model:ir.model.fields,field_description:recurring.field_recurring_exec_init
msgid "Number of Documents"
msgstr ""
#. module: recurring
#: model:ir.model.fields,field_description:recurring.field_recurring_document_model
msgid "Object"
msgstr ""
#. module: recurring
#: model:ir.model.fields,field_description:recurring.field_recurring_partner_id
#: model:ir.ui.view,arch_db:recurring.view_recurring_filter
msgid "Partner"
msgstr ""
#. module: recurring
#: code:addons/recurring/models/recurring.py:221
#, python-format
msgid "Please provide another source document.\n"
"This one does not exist!"
msgstr ""
#. module: recurring
#: model:ir.ui.view,arch_db:recurring.view_recurring_form
msgid "Process"
msgstr ""
#. module: recurring
#: model:ir.model,name:recurring.model_recurring
#: model:ir.model.fields,field_description:recurring.field_recurring_history_recurring_id
#: model:ir.ui.view,arch_db:recurring.view_recurring_filter
msgid "Recurring"
msgstr ""
#. module: recurring
#: model:ir.ui.view,arch_db:recurring.view_recurring_form
msgid "Recurring Data"
msgstr ""
#. module: recurring
#: model:ir.model,name:recurring.model_recurring_document
#: model:ir.model.fields,field_description:recurring.field_recurring_document_fields_document_id
#: model:ir.ui.view,arch_db:recurring.document_form
#: model:ir.ui.view,arch_db:recurring.document_tree
#: model:ir.ui.view,arch_db:recurring.view_recurring_document_filter
msgid "Recurring Document"
msgstr ""
#. module: recurring
#: model:ir.model,name:recurring.model_recurring_document_fields
#: model:ir.ui.view,arch_db:recurring.document_fields_form
#: model:ir.ui.view,arch_db:recurring.document_fields_tree
msgid "Recurring Document Fields"
msgstr ""
#. module: recurring
#: model:ir.actions.act_window,name:recurring.action_recurring_form
#: model:ir.actions.act_window,name:recurring.action_recurring_wizard
#: model:ir.ui.menu,name:recurring.menu_action_recurring_form
msgid "Recurring Documents"
msgstr ""
#. module: recurring
#: model:ir.ui.view,arch_db:recurring.recurring_history_form
#: model:ir.ui.view,arch_db:recurring.recurring_history_tree
msgid "Recurring History"
msgstr ""
#. module: recurring
#: model:ir.actions.act_window,name:recurring.action_document_form
#: model:ir.ui.menu,name:recurring.menu_action_document_form
msgid "Recurring Types"
msgstr ""
#. module: recurring
#: model:ir.model,name:recurring.model_recurring_history
msgid "Recurring history"
msgstr ""
#. module: recurring
#: code:addons/recurring/tests/test_recurring.py:31
#, python-format
msgid "Recurring is in running state"
msgstr ""
#. module: recurring
#: code:addons/recurring/tests/test_recurring.py:34
#, python-format
msgid "Recurring is not in draft state"
msgstr ""
#. module: recurring
#: model:ir.ui.view,arch_db:recurring.view_recurring_form
#: model:ir.ui.view,arch_db:recurring.view_recurring_tree
msgid "Recurrings"
msgstr ""
#. module: recurring
#: model:ir.ui.view,arch_db:recurring.view_recurring_filter
#: selection:recurring,state:0
msgid "Running"
msgstr ""
#. module: recurring
#: model:ir.ui.view,arch_db:recurring.view_recurring_wizard_form
msgid "Save"
msgstr ""
#. module: recurring
#: model:ir.model.fields,help:recurring.field_recurring_cron_id
msgid "Scheduler which runs on recurring"
msgstr ""
#. module: recurring
#: model:ir.ui.view,arch_db:recurring.view_recurring_filter
msgid "Search Recurring"
msgstr ""
#. module: recurring
#: model:ir.ui.view,arch_db:recurring.view_recurring_form
msgid "Set to Draft"
msgstr ""
#. module: recurring
#: model:ir.model.fields,field_description:recurring.field_recurring_doc_source
#: model:ir.model.fields,field_description:recurring.field_recurring_history_document_id
msgid "Source Document"
msgstr ""
#. module: recurring
#: model:ir.ui.view,arch_db:recurring.view_recurring_wizard_form
msgid "Start Recurring"
msgstr ""
#. module: recurring
#: model:ir.model.fields,field_description:recurring.field_recurring_state
#: model:ir.ui.view,arch_db:recurring.view_recurring_filter
msgid "Status"
msgstr ""
#. module: recurring
#: model:ir.ui.view,arch_db:recurring.view_recurring_form
msgid "Stop"
msgstr ""
#. module: recurring
#: model:ir.model.fields,field_description:recurring.field_recurring_user_id
#: model:ir.ui.view,arch_db:recurring.view_recurring_filter
msgid "User"
msgstr ""
#. module: recurring
#: model:ir.model.fields,help:recurring.field_recurring_doc_source
msgid "User can choose the source document on which he wants to create documents"
msgstr ""
#. module: recurring
#: selection:recurring,interval_type:0
msgid "Weeks"
msgstr ""
#. module: recurring
#: code:addons/recurring/models/recurring.py:247
#, python-format
msgid "You cannot delete an active recurring!"
msgstr ""

View File

@ -0,0 +1,5 @@
# -*- coding: utf-8 -*-
# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing
# details.
from . import recurring

View File

@ -0,0 +1,291 @@
# -*- coding: utf-8 -*-
# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing
# details.
# TODO:
# Error treatment: exception, request, ... -> send request to user_id
from flectra import api, fields, models, _
from flectra.exceptions import UserError, ValidationError
def _get_document_types(self):
return [(doc.model.model, doc.name) for doc in self.env[
'recurring.document'].search([], order='name')]
class RecurringDocument(models.Model):
_name = "recurring.document"
_description = "Recurring Document"
name = fields.Char(string='Name')
active = fields.Boolean(
help="If the active field is set to False, it will allow you to hide "
"the recurring document without removing it.", default=True)
model = fields.Many2one('ir.model', string="Object")
field_ids = fields.One2many('recurring.document.fields',
'document_id', string='Fields', copy=True)
class RecurringDocumentFields(models.Model):
_name = "recurring.document.fields"
_description = "Recurring Document Fields"
_rec_name = 'field'
field = fields.Many2one('ir.model.fields', domain="[('model_id', '=', "
"parent.model)]")
value = fields.Selection(
[('false', 'False'), ('date', 'Current Date')], string='Default Value',
help="Default value is considered for field when new document is "
"generated.")
document_id = fields.Many2one('recurring.document',
string='Recurring Document',
ondelete='cascade')
class Recurring(models.Model):
_name = "recurring"
_description = "Recurring"
@api.model
def default_get(self, fields):
res = super(Recurring, self).default_get(fields)
active_model = self._context.get('active_model')
active_id = self._context.get('active_id')
if active_model and active_id:
record = self.env[active_model].browse(active_id)
if 'partner_id' in self.env[active_model]._fields:
res['partner_id'] = record.partner_id.id
else:
res['name'] = record.name
if not res['name']:
res['name'] = record.number
return res
@api.onchange('partner_id')
def _onchange_partner_id(self):
active_model = self._context.get('active_model')
active_id = self._context.get('active_id')
if self.partner_id and active_model and active_id:
record = self.env[active_model].browse(active_id)
name = record.name
if not name:
name = record.number
if name:
self.name = name + '-' + self.partner_id.name
else:
self.name = self.partner_id.name
@api.constrains('partner_id', 'doc_source')
def _check_partner_id_doc_source(self):
for record in self:
if record.partner_id and record.doc_source and 'partner_id' in \
self.env[record.doc_source._name]._fields and \
record.doc_source.partner_id != record.partner_id:
raise ValidationError(_(
'Error! Source Document should be related to partner %s' %
record.partner_id.name))
name = fields.Char(string='Name')
active = fields.Boolean(
help="If the active field is set to False, it will allow you to hide "
"the recurring without removing it.", default=True)
partner_id = fields.Many2one('res.partner', string='Partner')
notes = fields.Text(string='Internal Notes')
user_id = fields.Many2one('res.users', string='User',
default=lambda self: self.env.user)
interval_number = fields.Integer(string='Internal Qty', default=1)
interval_type = fields.Selection(
[('minutes', 'Minutes'), ('hours', 'Hours'), ('days', 'Days'),
('weeks', 'Weeks'), ('months', 'Months')], string='Interval Unit',
default='months')
exec_init = fields.Integer(string='Number of Documents')
date_init = fields.Datetime(string='First Date',
default=fields.Datetime.now)
state = fields.Selection(
[('draft', 'Draft'), ('running', 'Running'), ('done', 'Done')],
string='Status', copy=False, default='draft')
doc_source = fields.Reference(
selection=_get_document_types, string='Source Document',
help="User can choose the source document on which he wants to "
"create documents")
doc_lines = fields.One2many('recurring.history',
'recurring_id', string='Documents created')
cron_id = fields.Many2one('ir.cron', string='Cron Job',
help="Scheduler which runs on recurring",
states={'running': [('readonly', True)],
'done': [('readonly', True)]})
note = fields.Text(string='Notes',
help="Description or Summary of Recurring")
@api.model
def _auto_end(self):
super(Recurring, self)._auto_end()
# drop the FK from recurring to ir.cron, as it would cause deadlocks
# during cron job execution. When model_copy() tries to write() on
# the recurring,
# it has to wait for an ExclusiveLock on the cron job record,
# but the latter is locked by the cron system for the duration of
# the job!
# FIXME: the recurring module should be reviewed to simplify the
# scheduling process
# and to use a unique cron job for all recurrings, so that it
# never needs to be updated during its execution.
self.env.cr.execute("ALTER TABLE %s DROP CONSTRAINT %s" % (
self._table, '%s_cron_id_fkey' % self._table))
@api.multi
def create_recurring_type(self):
rec_doc_obj = self.env['recurring.document']
ir_model_id = self.env['ir.model'].search(
[('model', '=', self._context.get('active_model', False))])
rec_doc_id = rec_doc_obj.search([('model', '=', ir_model_id.id)])
if not rec_doc_id:
rec_doc_id = rec_doc_obj.create({
'name': ir_model_id.name,
'model': ir_model_id.id,
})
return rec_doc_id
@api.multi
def btn_recurring(self):
self.ensure_one()
rec_doc_id = self.create_recurring_type()
if rec_doc_id:
active_model = self._context.get('active_model')
active_id = self._context.get('active_id')
if active_id and active_model:
record = self.env[active_model].browse(active_id)
self.doc_source = record._name + "," + str(record.id)
record.recurring_id = self.id
record.rec_source_id = record.id
if self._context.get('process') == 'start':
self.set_process()
@api.multi
def set_process(self):
for recurring in self:
model = 'recurring'
cron_data = {
'name': recurring.name,
'interval_number': recurring.interval_number,
'interval_type': recurring.interval_type,
'numbercall': recurring.exec_init,
'nextcall': recurring.date_init,
'model_id': self.env['ir.model'].search([('model', '=',
model)]).id,
'priority': 6,
'user_id': recurring.user_id.id,
'state': 'code',
'code': 'model._cron_model_copy('+repr([recurring.id])+')',
}
cron = self.env['ir.cron'].sudo().create(cron_data)
recurring.write({'cron_id': cron.id, 'state': 'running'})
@api.multi
def set_recurring_id(self):
if self.doc_source and 'recurring_id' \
in self.env[self.doc_source._name]._fields:
rec_id = self.env[self.doc_source._name].browse(self.doc_source.id)
if not rec_id.recurring_id:
rec_id.recurring_id = self.id
else:
raise ValidationError(
_('Document is already recurring'))
@api.model
def create(self, vals):
if vals.get('doc_source', False) and self.search(
[('doc_source', '=', vals['doc_source'])]):
raise ValidationError(
_('Recurring of the selected Source Document already exist'))
res = super(Recurring, self).create(vals)
res.set_recurring_id()
return res
@api.multi
def write(self, values):
doc_source_id = False
if values.get('doc_source', False):
doc_source_id = self.doc_source
res = super(Recurring, self).write(values)
if doc_source_id:
rec_id = self.env[doc_source_id._name].browse(doc_source_id.id)
rec_id.recurring_id = False
self.set_recurring_id()
return res
@api.multi
def get_recurring(self, model, active_id):
result = self.env.ref('recurring.action_recurring_form').read()[0]
record = self.env[model].browse(active_id)
rec_ids = self.env['recurring'].search(
[('doc_source', '=', record._name + "," + str(record.id))])
result['domain'] = [('id', 'in', rec_ids.ids)]
return result
@api.multi
def get_recurring_documents(self, model, action, recurring_id):
result = self.env.ref(action).read()[0]
res_ids = self.env[model].search(
[('recurring_id', '=', recurring_id.id)])
result['domain'] = [('id', 'in', res_ids.ids)]
return result
@api.model
def _cron_model_copy(self, ids):
self.browse(ids).model_copy()
@api.multi
def model_copy(self):
for recurring in self.filtered(lambda sub: sub.cron_id):
if not recurring.doc_source.exists():
raise UserError(_('Please provide another source '
'document.\nThis one does not exist!'))
default = {}
documents = self.env['recurring.document'].search(
[('model.model', '=', recurring.doc_source._name)], limit=1)
fieldnames = dict((f.field.name, f.value == 'date' and
fields.Date.today() or False)
for f in documents.field_ids)
default.update(fieldnames)
# if there was only one remaining document to generate
# the recurring is over and we mark it as being done
if recurring.cron_id.numbercall == 1:
recurring.write({'state': 'done'})
else:
recurring.write({'state': 'running'})
copied_doc = recurring.doc_source.copy(default)
self.env['recurring.history'].create({
'recurring_id': recurring.id,
'date': fields.Datetime.now(),
'document_id': '%s,%s' % (recurring.doc_source._name,
copied_doc.id)})
@api.multi
def unlink(self):
if any(self.filtered(lambda s: s.state == "running")):
raise UserError(_('You cannot delete an active recurring!'))
return super(Recurring, self).unlink()
@api.multi
def set_done(self):
self.mapped('cron_id').write({'active': False})
self.write({'state': 'done'})
@api.multi
def set_draft(self):
self.write({'state': 'draft'})
class RecurringHistory(models.Model):
_name = "recurring.history"
_description = "Recurring history"
_rec_name = 'date'
date = fields.Datetime(string='Date')
recurring_id = fields.Many2one('recurring', string='Recurring',
ondelete='cascade')
document_id = fields.Reference(
selection=_get_document_types, string='Source Document')

View File

@ -0,0 +1,7 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_recurring_document_fields,access_recurring_document_fields,model_recurring_document_fields,base.group_user,1,1,1,1
access_recurring_user,access_recurring_user,model_recurring,base.group_user,1,1,1,1
access_recurringhistory_user,access_recurring_history_user,model_recurring_history,base.group_user,1,1,1,1
access_recurring_document_user,access_recurring_document_user,model_recurring_document,base.group_user,1,1,1,1
access_res_partner_user,access_res_partner_user,base.model_res_partner,base.group_user,1,1,1,1
access_ir_cron_user,access_ir_cron_user,base.model_ir_cron,base.group_user,1,0,0,0
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_recurring_document_fields access_recurring_document_fields model_recurring_document_fields base.group_user 1 1 1 1
3 access_recurring_user access_recurring_user model_recurring base.group_user 1 1 1 1
4 access_recurringhistory_user access_recurring_history_user model_recurring_history base.group_user 1 1 1 1
5 access_recurring_document_user access_recurring_document_user model_recurring_document base.group_user 1 1 1 1
6 access_res_partner_user access_res_partner_user base.model_res_partner base.group_user 1 1 1 1
7 access_ir_cron_user access_ir_cron_user base.model_ir_cron base.group_user 1 0 0 0

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

View File

@ -0,0 +1,90 @@
<section class="container">
<div class="row">
<h2 class="oe_slogan">Recurring</h2>
<h3 class="oe_slogan">Create recurring of document of any module</h3>
</div>
</section>
<section class="container oe_dark">
<div class="row">
<h2 class="oe_slogan">Recurring Type</h2>
<div class="col-md-6 text-justify mt32">
<p class="mt32">
To generate recurring document of any module its Recurring type
is first created. Here recurring type of sale is created.
Recurring type is created from Settings > Technical >
Automation > Recurring Types
</p>
</div>
<div class="col-md-6">
<img class="oe_picture oe_screenshot" src="recurring_type.png">
</div>
</div>
</section>
<section class="container">
<div class="row">
<h2 class="oe_slogan">Recurring Document</h2>
<div class="col-md-6">
<img class="oe_picture oe_screenshot" src="recurring_document.png">
</div>
<div class="col-md-6">
<p class="mt32 mb32 text-justify">
Recurring Document is created of any document which is
needed to be generated everytime at a specific interval of
time.
Number of documents - The number of times the document
should be recurred.
Interval Unit - The interval when the recurring should occur.
Source Document - Choose the source document on which needs
to be generated at every specific interval.
Recurring Documents is created from Settings > Technical >
Automation > Recurring Documents
</p>
</div>
</div>
</section>
<section class="container oe_dark">
<div class="row oe_spaced">
<h2 class="oe_slogan">Recurring Document Started</h2>
<div class="col-md-6">
<p class="mt32">
Recurring of the selected document can be started any time
by clicking on the 'Process' Button
Cron job is automatically created and is linked here.
</p>
</div>
<div class="col-md-6">
<img class="oe_picture oe_screenshot"
src="recurring_document_started.png"/>
</div>
</div>
</section>
<section class="container">
<div class="row">
<h2 class="oe_slogan">Scheduled Actions</h2>
<div class="col-md-6">
<img class="oe_picture oe_screenshot" src="cron_job.png">
</div>
<div class="col-md-6">
<p class="oe_mt8 text-justify">The generated cron job from the
recurring document</p>
</div>
</div>
</section>
<section class="container">
<div class="row">
<h2 class="oe_slogan">Sale Orders</h2>
<div class="col-md-6">
<p class="mt32 text-justify">
Sale Orders that are generated through recurring.
</p>
</div>
<div class="col-md-6">
<img class="oe_picture oe_screenshot" src="sale_order.png"/>
</div>
</div>
</section>

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

View File

@ -0,0 +1,4 @@
# Part of Flectra. See LICENSE file for full copyright and licensing
# details.
from . import test_recurring

View File

@ -0,0 +1,36 @@
# Part of Flectra. See LICENSE file for full copyright and licensing details.
from flectra import _
from flectra.exceptions import UserError
from flectra.tests.common import TransactionCase
import logging
_logger = logging.getLogger(__name__)
class RecurringTransactionCase(TransactionCase):
def setUp(self):
super(RecurringTransactionCase, self).setUp()
self.recurring_id = self.env.ref("recurring.recurring_partner0")
def check_recurring(self):
self.recurring_id.set_process()
if not self.recurring_id.cron_id:
raise UserError(_("Cron is not created"))
else:
self.recurring_id.cron_id.method_direct_trigger()
try:
self.recurring_id.unlink()
except Exception as e:
_logger.info(
"You cannot delete an active recurring!")
self.recurring_id.set_done()
if not self.recurring_id.state == 'done':
raise UserError(_("Recurring is in running state"))
self.recurring_id.set_draft()
if not self.recurring_id.state == 'draft':
raise UserError(_("Recurring is not in draft state"))
def test_01_recurring(self):
self.check_recurring()

View File

@ -0,0 +1,275 @@
<?xml version="1.0" encoding="utf-8"?>
<flectra>
<!-- Recurring Views -->
<record id="view_recurring_form" model="ir.ui.view">
<field name="name">recurring.form</field>
<field name="model">recurring</field>
<field name="arch" type="xml">
<form string="Recurrings">
<header>
<button name="set_process" states="draft" string="Process"
type="object" class="oe_highlight"/>
<button name="set_done" states="running" string="Stop"
type="object" class="oe_highlight"/>
<button name="set_draft" states="done"
string="Set to Draft" type="object"/>
<field name="state" widget="statusbar"
statusbar_visible="draft,running"/>
</header>
<sheet>
<group col="4">
<field name="name" required="1"/>
<field name="partner_id"/>
<field name="user_id" required="1"/>
<field name="active"/>
</group>
<notebook>
<page string="Recurring Data">
<group col="4">
<field name="interval_number"/>
<field name="interval_type"/>
<field name="exec_init"/>
<field name="date_init"/>
<field name="doc_source" required="1"/>
<field name="cron_id"/>
</group>
<separator string="Internal Notes"/>
<field name="notes"/>
</page>
<page string="Documents created">
<field name="doc_lines" widget="one2many_list"
readonly="1"/>
</page>
<page string="Notes">
<field name="note"/>
</page>
</notebook>
</sheet>
</form>
</field>
</record>
<record id="view_recurring_tree" model="ir.ui.view">
<field name="name">recurring.tree</field>
<field name="model">recurring</field>
<field name="arch" type="xml">
<tree string="Recurrings">
<field name="name"/>
<field name="partner_id"/>
<field name="active"/>
<field name="user_id"/>
<field name="state"/>
</tree>
</field>
</record>
<record id="view_recurring_filter" model="ir.ui.view">
<field name="name">recurring.filter</field>
<field name="model">recurring</field>
<field name="arch" type="xml">
<search string="Search Recurring">
<field name="name" string="Recurring"/>
<field name="date_init"/>
<filter string="Running"
domain="[('state','=','running')]"/>
<field name="user_id"/>
<field name="partner_id"/>
<group expand="0" string="Group By">
<filter string="User" name="User" domain="[]"
context="{'group_by':'user_id'}"/>
<filter string="Partner" name="Partner" domain="[]"
context="{'group_by':'partner_id'}"/>
<filter string="Status" domain="[]"
context="{'group_by':'state'}"/>
</group>
</search>
</field>
</record>
<record id="action_recurring_form" model="ir.actions.act_window">
<field name="name">Recurring Documents</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">recurring</field>
<field name="view_type">form</field>
<field name="view_id" ref="view_recurring_tree"/>
<field name="context">{'search_default_User':1,
'disable':False}
</field>
<field name="search_view_id" ref="view_recurring_filter"/>
</record>
<record model="ir.actions.act_window.view"
id="action_recurring_tree_view">
<field name="sequence" eval="2"/>
<field name="view_mode">tree</field>
<field name="view_id" ref="view_recurring_tree"/>
<field name="act_window_id" ref="action_recurring_form"/>
</record>
<record model="ir.actions.act_window.view"
id="action_recurring_form_view">
<field name="sequence" eval="2"/>
<field name="view_mode">form</field>
<field name="view_id" ref="view_recurring_form"/>
<field name="act_window_id" ref="action_recurring_form"/>
</record>
<menuitem action="action_recurring_form" id="menu_action_recurring_form"
parent="base.menu_automation"/>
<record id="recurring_history_tree" model="ir.ui.view">
<field name="name">recurring.history.tree</field>
<field name="model">recurring.history</field>
<field name="arch" type="xml">
<tree string="Recurring History">
<field name="date"/>
<field name="document_id"/>
</tree>
</field>
</record>
<record id="recurring_history_form" model="ir.ui.view">
<field name="name">recurring.history.form</field>
<field name="model">recurring.history</field>
<field name="arch" type="xml">
<form string="Recurring History">
<group col="4">
<field name="date"/>
<field name="document_id" required="1"/>
</group>
</form>
</field>
</record>
<record id="document_form" model="ir.ui.view">
<field name="name">recurring.document.form</field>
<field name="model">recurring.document</field>
<field name="arch" type="xml">
<form string="Recurring Document">
<group col="4">
<field name="name" required="1"/>
<field name="model" required="1"/>
<field name="active"/>
</group>
<field name="field_ids"/>
</form>
</field>
</record>
<record id="document_tree" model="ir.ui.view">
<field name="name">recurring.document.tree</field>
<field name="model">recurring.document</field>
<field name="arch" type="xml">
<tree string="Recurring Document">
<field name="name"/>
<field name="active"/>
<field name="model"/>
</tree>
</field>
</record>
<record id="view_recurring_document_filter" model="ir.ui.view">
<field name="name">recurring.document.filter</field>
<field name="model">recurring.document</field>
<field name="arch" type="xml">
<search string="Recurring Document">
<field name="name" string="Recurring Document"/>
<field name="model"/>
</search>
</field>
</record>
<record id="document_fields_form" model="ir.ui.view">
<field name="name">recurring.document.fields.form</field>
<field name="model">recurring.document.fields</field>
<field name="arch" type="xml">
<form string="Recurring Document Fields">
<group>
<field name="field" required="1"/>
<field name="value"/>
</group>
</form>
</field>
</record>
<record id="document_fields_tree" model="ir.ui.view">
<field name="name">recurring.document.fields.tree</field>
<field name="model">recurring.document.fields</field>
<field name="arch" type="xml">
<tree string="Recurring Document Fields">
<field name="field"/>
<field name="value"/>
</tree>
</field>
</record>
<record id="action_document_form" model="ir.actions.act_window">
<field name="name">Recurring Types</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">recurring.document</field>
<field name="view_type">form</field>
<field name="view_id" ref="document_tree"/>
<field name="search_view_id" ref="view_recurring_document_filter"/>
</record>
<menuitem id="menu_action_document_form" action="action_document_form"
parent="base.menu_automation"/>
<record id="view_recurring_wizard_form" model="ir.ui.view">
<field name="name">recurring</field>
<field name="model">recurring</field>
<field name="type">form</field>
<field name="priority" eval="8"/>
<field name="arch" type="xml">
<form string="IR Recurring">
<div class="oe_title">
<h1>
<field name="name" readonly="1" force_save="1"/>
</h1>
</div>
<group>
<group>
<field name="partner_id"/>
<field name="user_id" required="1"/>
<field name="active"/>
<field name="exec_init"/>
</group>
<group>
<field name="interval_number"/>
<field name="interval_type"/>
<field name="date_init"/>
<field name="doc_source" invisible="1"/>
</group>
</group>
<footer>
<button name="btn_recurring" type="object"
string="Start Recurring" class="oe_highlight"
context="{'process':'start'}"/>
<button name="btn_recurring" type="object"
string="Save"/>
<button string="Cancel" special="cancel"/>
</footer>
</form>
</field>
</record>
<record id="action_recurring_wizard" model="ir.actions.act_window">
<field name="name">Recurring Documents</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">recurring</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="view_id" ref="view_recurring_wizard_form"/>
<field name="target">new</field>
</record>
<record model="ir.actions.act_window.view"
id="action_recurring_wizard_form_view">
<field name="sequence" eval="2"/>
<field name="view_mode">form</field>
<field name="view_id" ref="view_recurring_wizard_form"/>
<field name="act_window_id" ref="action_recurring_wizard"/>
</record>
</flectra>

View File

@ -0,0 +1,3 @@
# Part of Flectra. See LICENSE file for full copyright and licensing details.
from . import models

View File

@ -0,0 +1,20 @@
# Part of Flectra. See LICENSE file for full copyright and licensing details.
{
'name': 'Account Invoice Recurrings',
'version': '1.0',
'category': 'Extra Tools',
'summary': 'Create recurring of invoices',
'description': """
Account Invoice Recurring allows to automatically create
recurring of any particular invoice
""",
'author': 'FlectraHQ',
'website': 'https://www.flectrahq.com/',
'depends': ['account_invoicing', 'recurring'],
'data': [
'views/account_invoice_view.xml',
],
'installable': True,
'auto_install': False,
}

View File

@ -0,0 +1,45 @@
# Translation of Flectra Server.
# This file contains the translation of the following modules:
# * recurring_account
#
msgid ""
msgstr ""
"Project-Id-Version: Flectra Server 1.3\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-08-01 17:10+0000\n"
"PO-Revision-Date: 2018-08-01 17:10+0000\n"
"Last-Translator: <>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: recurring_account
#: model:ir.ui.view,arch_db:recurring_account.invoice_form_inherit
#: model:ir.ui.view,arch_db:recurring_account.invoice_supplier_form_inherit
msgid "Document"
msgstr ""
#. module: recurring_account
#: model:ir.ui.view,arch_db:recurring_account.invoice_form_inherit
#: model:ir.ui.view,arch_db:recurring_account.invoice_supplier_form_inherit
msgid "Generate Recurring"
msgstr ""
#. module: recurring_account
#: model:ir.model,name:recurring_account.model_account_invoice
msgid "Invoice"
msgstr ""
#. module: recurring_account
#: model:ir.ui.view,arch_db:recurring_account.invoice_form_inherit
#: model:ir.ui.view,arch_db:recurring_account.invoice_supplier_form_inherit
msgid "Recurring"
msgstr ""
#. module: recurring_account
#: model:ir.model.fields,field_description:recurring_account.field_account_invoice_recurring_id
msgid "Recurring Reference"
msgstr ""

View File

@ -0,0 +1,3 @@
# Part of Flectra. See LICENSE file for full copyright and licensing details.
from . import account_invoice

View File

@ -0,0 +1,32 @@
# Part of Flectra. See LICENSE file for full copyright and licensing
# details.
from flectra import api, models, fields
class AccountInvoice(models.Model):
_inherit = "account.invoice"
recurring_id = fields.Many2one('recurring', string='Recurring Reference')
rec_source_id = fields.Many2one('account.invoice',
string='Recurring Source')
@api.multi
def get_recurring(self):
result = self.env['recurring'].get_recurring(
'account.invoice', self.id)
return result
@api.multi
def get_recurring_documents(self):
result = self.env['recurring'].get_recurring_documents(
'account.invoice', 'account.action_invoice_tree1',
self.recurring_id)
return result
@api.multi
def action_invoice_cancel(self):
res = super(AccountInvoice, self).action_invoice_cancel()
if self.recurring_id:
self.recurring_id.set_done()
return res

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

View File

@ -0,0 +1,99 @@
<section class="container">
<div class="row">
<h2 class="oe_slogan">Recurring Invoices</h2>
<h3 class="oe_slogan">Create recurring invoices</h3>
</div>
</section>
<section class="container oe_dark">
<div class="row">
<h2 class="oe_slogan">Recurring Wizard</h2>
<div class="col-md-6 text-justify mt32">
<p class="mt32">
A 'Generate Recurring' button is displayed on the invoice.<br/>
Recurring Document, Recurring Type and Scheduled action of this
particular invoice is automatically created.<br/>
Number of documents - The number of times the document
should be recurred.<br/>
Interval Unit - The interval when the recurring should
occur.<br/>
Start Recurring - Activates the generated recurring.<br/>
Save - Creates the recurring but doesn't activates it.
</p>
</div>
<div class="col-md-6">
<img class="oe_picture oe_screenshot" src="recurring_document_wizard1.png">
</div>
</div>
</section>
<section class="container">
<div class="row">
<h2 class="oe_slogan">Invoice</h2>
<div class="col-md-6">
<img class="oe_picture oe_screenshot" src="invoice.png">
</div>
<div class="col-md-6">
<p class="mt32 mb32 text-justify">
Recurring - Shows the generated recurring.<br/>
Document - Links the invoices that are generated by the
recurring of that particular invoice.
</p>
</div>
</div>
</section>
<section class="container oe_dark">
<div class="row oe_spaced">
<h2 class="oe_slogan">Invoice Recurring Documents</h2>
<div class="col-md-6">
<p class="mt32">
Invoices that are generated through recurring are linked here.
</p>
</div>
<div class="col-md-6">
<img class="oe_picture oe_screenshot"
src="recurring_documents.png"/>
</div>
</div>
</section>
<section class="container">
<div class="row">
<h2 class="oe_slogan">Recurring Document</h2>
<div class="col-md-6">
<img class="oe_picture oe_screenshot" src="rec_doc.png"/>
</div>
<div class="col-md-6">
<p class="mt32 text-justify">
Recurring Document is automatically created.
</p>
</div>
</div>
</section>
<section class="container">
<div class="row">
<h2 class="oe_slogan">Recurring Type</h2>
<div class="col-md-6">
<p class="oe_mt8 text-justify">Recurring Type is automatically
created</p>
</div>
<div class="col-md-6">
<img class="oe_picture oe_screenshot" src="rec_type.png">
</div>
</div>
</section>
<section class="container">
<div class="row">
<h2 class="oe_slogan">Scheduled Actions</h2>
<div class="col-md-6">
<img class="oe_picture oe_screenshot" src="cron_job.png">
</div>
<div class="col-md-6">
<p class="oe_mt8 text-justify">Cron job is automatically
created</p>
</div>
</div>
</section>

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View File

@ -0,0 +1,64 @@
<?xml version="1.0" encoding="utf-8"?>
<flectra>
<record id="invoice_form_inherit" model="ir.ui.view">
<field name="name">account.invoice.form.inherit</field>
<field name="model">account.invoice</field>
<field name="inherit_id" ref="account.invoice_form"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='user_id']" position="after">
<field name="recurring_id" invisible="1"/>
<field name="rec_source_id" readonly="1"/>
</xpath>
<xpath expr="//button[@name='action_invoice_open']"
position="after">
<button name="%(recurring.action_recurring_wizard)d"
id="generate_recurring"
string="Generate Recurring" class="btn-primary"
type="action"
attrs="{'invisible': ['|', ('state', 'in', ['draft','cancel']), ('recurring_id', '!=', False)]}"/>
</xpath>
<xpath expr="//sheet/div[@name='button_box']" position="inside">
<button class="oe_stat_button" type="object"
string="Recurring" name="get_recurring"
icon="fa-tasks" attrs="{'invisible': [('recurring_id', '=', False)]}"/>
<button class="oe_stat_button" type="object"
string="Document" name="get_recurring_documents"
icon="fa-tasks" attrs="{'invisible': [('recurring_id', '=', False)]}"/>
</xpath>
</field>
</record>
<record id="invoice_supplier_form_inherit" model="ir.ui.view">
<field name="name">account.invoice.supplier.form.inherit</field>
<field name="model">account.invoice</field>
<field name="inherit_id" ref="account.invoice_supplier_form"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='date_due']" position="after">
<field name="recurring_id" invisible="1"/>
<field name="rec_source_id" readonly="1"/>
</xpath>
<xpath expr="//button[@name='action_invoice_open']"
position="after">
<button name="%(recurring.action_recurring_wizard)d"
id="generate_recurring"
string="Generate Recurring" class="btn-primary"
type="action"
attrs="{'invisible': ['|', ('state', 'in', ['draft','cancel']), ('recurring_id', '!=', False)]}"/>
</xpath>
<xpath expr="//field[@name='type']" position="before">
<div class="oe_button_box" name="button_box">
<button class="oe_stat_button" type="object"
string="Recurring" name="get_recurring"
icon="fa-tasks" attrs="{'invisible': [('recurring_id', '=', False)]}"/>
<button class="oe_stat_button" type="object"
string="Document" name="get_recurring_documents"
icon="fa-tasks" attrs="{'invisible': [('recurring_id', '=', False)]}"/>
</div>
</xpath>
</field>
</record>
</flectra>

View File

@ -0,0 +1,3 @@
# Part of Flectra. See LICENSE file for full copyright and licensing details.
from . import models

View File

@ -0,0 +1,21 @@
# Part of Flectra. See LICENSE file for full copyright and licensing details.
{
'name': 'Purchase Order Recurring',
'version': '1.0',
'category': 'Extra Tools',
'summary': 'Create recurring of purchase order',
'description': """
Purchase Order Recurring allows to automatically create recurring of
any particular purchase order
""",
'author': 'FlectraHQ',
'website': 'https://www.flectrahq.com/',
'depends': ['recurring', 'purchase'],
'data': [
'views/purchase_views.xml',
],
'demo': ['demo/purchase_recurring_demo.xml'],
'installable': True,
'auto_install': False,
}

View File

@ -0,0 +1,28 @@
<?xml version="1.0" ?>
<flectra noupdate="1">
<record id="purchase_order_demo" model="purchase.order">
<field name="name">PO001</field>
<field name="partner_id" ref="base.res_partner_2"/>
</record>
<record id="purchase_order_line_demo" model="purchase.order.line">
<field name="order_id"
ref="recurring_purchase.purchase_order_demo"/>
<field name="name">[RAM-SR5] RAM DDR SR5</field>
<field name="date_planned" eval="time.strftime('%Y/%m/10')"/>
<field name="product_id" ref="product.product_product_13"/>
<field name="product_uom" ref="product.product_uom_unit"/>
<field name="price_unit">60</field>
<field name="product_qty">5</field>
</record>
<record id="recurring_purchase1" model="recurring">
<field name="name">PO001</field>
<field name="exec_init">2</field>
<field name="interval_type">minutes</field>
<field name="date_init" eval="datetime.now()"/>
<field name="doc_source" ref='recurring_purchase.purchase_order_demo'/>
</record>
</flectra>

View File

@ -0,0 +1,42 @@
# Translation of Flectra Server.
# This file contains the translation of the following modules:
# * recurring_purchase
#
msgid ""
msgstr ""
"Project-Id-Version: Flectra Server 1.3\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-08-01 16:52+0000\n"
"PO-Revision-Date: 2018-08-01 16:52+0000\n"
"Last-Translator: <>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: recurring_purchase
#: model:ir.ui.view,arch_db:recurring_purchase.view_purchase_order_form_inherit
msgid "Document"
msgstr ""
#. module: recurring_purchase
#: model:ir.ui.view,arch_db:recurring_purchase.view_purchase_order_form_inherit
msgid "Generate Recurring"
msgstr ""
#. module: recurring_purchase
#: model:ir.model,name:recurring_purchase.model_purchase_order
msgid "Purchase Order"
msgstr ""
#. module: recurring_purchase
#: model:ir.ui.view,arch_db:recurring_purchase.view_purchase_order_form_inherit
msgid "Recurring"
msgstr ""
#. module: recurring_purchase
#: model:ir.model.fields,field_description:recurring_purchase.field_purchase_order_recurring_id
msgid "Recurring Reference"
msgstr ""

View File

@ -0,0 +1,3 @@
# Part of Flectra. See LICENSE file for full copyright and licensing details.
from . import purchase

View File

@ -0,0 +1,28 @@
# Part of Flectra. See LICENSE file for full copyright and licensing details.
from flectra import api, models, fields
class PurchaseOrder(models.Model):
_inherit = 'purchase.order'
recurring_id = fields.Many2one('recurring', string='Recurring Reference')
rec_source_id = fields.Many2one('purchase.order',
string='Recurring Source')
@api.multi
def get_recurring(self):
result = self.env['recurring'].get_recurring('purchase.order', self.id)
return result
@api.multi
def get_recurring_documents(self):
result = self.env['recurring'].get_recurring_documents(
'purchase.order', 'purchase.purchase_rfq', self.recurring_id)
return result
@api.multi
def button_cancel(self):
if self.recurring_id:
self.recurring_id.set_done()
return super(PurchaseOrder, self).button_cancel()

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

View File

@ -0,0 +1,103 @@
<section class="container">
<div class="row">
<h2 class="oe_slogan">Recurring Purchase</h2>
<h3 class="oe_slogan">Create recurring purchase order</h3>
</div>
</section>
<section class="container oe_dark">
<div class="row">
<h2 class="oe_slogan">Recurring Wizard</h2>
<div class="col-md-6">
<p class="mt32 mb32 text-justify">
A 'Generate Recurring' button is displayed on the purchase
order.<br/>
Recurring Document, Recurring Type and Scheduled action of this
particular purchase order is automatically created.<br/>
Number of documents - The number of times the document
should be recurred.<br/>
Interval Unit - The interval when the recurring should
occur.<br/>
Start Recurring - Activates the generated recurring.<br/>
Save - Creates the recurring but doesn't activates it.
</p>
</div>
<div class="col-md-6">
<img class="oe_picture oe_screenshot"
src="recurring_document_wizard1.png">
</div>
</div>
</section>
<section class="container">
<div class="row">
<h2 class="oe_slogan">Purchase Order</h2>
<div class="col-md-6">
<img class="oe_picture oe_screenshot" src="purchase_order.png">
</div>
<div class="col-md-6">
<p class="mt32 mb32 text-justify">
Recurring - Shows the generated recurring.<br/>
Document - Links the purchase order that are generated by the
recurring of that particular purchase order.
</p>
</div>
</div>
</section>
<section class="container oe_dark">
<div class="row oe_spaced">
<h2 class="oe_slogan">PO Recurring Documents</h2>
<div class="col-md-6">
<p class="mt32">
Purchase Orders that are generated through recurring.
</p>
</div>
<div class="col-md-6">
<img class="oe_picture oe_screenshot"
src="recurring_documents.png"/>
</div>
</div>
</section>
<section class="container">
<div class="row">
<h2 class="oe_slogan">Recurring Document</h2>
<div class="col-md-6">
<img class="oe_picture oe_screenshot" src="rec_doc.png">
</div>
<div class="col-md-6">
<p class="oe_mt8 text-justify">Recurring Document is
automatically created and is linked with the purchase order
</p>
</div>
</div>
</section>
<section class="container">
<div class="row">
<h2 class="oe_slogan">Recurring Type</h2>
<div class="col-md-6">
<p class="mt32 text-justify">
Recurring Type is automatically
created
</p>
</div>
<div class="col-md-6">
<img class="oe_picture oe_screenshot" src="rec_type.png"/>
</div>
</div>
</section>
<section class="container">
<div class="row">
<h2 class="oe_slogan">Scheduled Actions</h2>
<div class="col-md-6">
<img class="oe_picture oe_screenshot" src="cron_job.png">
</div>
<div class="col-md-6">
<p class="oe_mt8 text-justify">Cron job is automatically
created</p>
</div>
</div>
</section>

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View File

@ -0,0 +1,3 @@
# Part of Flectra. See LICENSE file for full copyright and licensing details.
from . import test_puchase_recurring

View File

@ -0,0 +1,21 @@
# Part of Flectra. See LICENSE file for full copyright and licensing details.
from flectra.tests.common import TransactionCase
class PurchaseRecurringTransactionCase(TransactionCase):
def setUp(self):
super(PurchaseRecurringTransactionCase, self).setUp()
self.purchase_order = self.env.ref(
"purchase.purchase_order_2")
def create_purchase_recurring(self):
recurring_id = self.env['recurring'].create({
'name': 'PO00002',
'exec_init': 5,
})
recurring_id.btn_recurring()
def test_01_recurring(self):
self.create_purchase_recurring()

View File

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<flectra>
<record id="view_purchase_order_form_inherit" model="ir.ui.view">
<field name="name">purchase.order.form.inherit</field>
<field name="model">purchase.order</field>
<field name="inherit_id" ref="purchase.purchase_order_form"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='partner_ref']" position="after">
<field name="recurring_id" invisible="1"/>
<field name="rec_source_id" readonly="1"/>
</xpath>
<xpath expr="//button[@name='button_confirm']" position="before">
<button name="%(recurring.action_recurring_wizard)d"
id="generate_recurring"
string="Generate Recurring" class="btn-primary"
type="action"
attrs="{'invisible': ['|', ('state', 'in', ['draft', 'cancel']), ('recurring_id', '!=', False)]}"/>
</xpath>
<xpath expr="//sheet/div[@name='button_box']" position="inside">
<button class="oe_stat_button" type="object"
string="Recurring"
name="get_recurring"
icon="fa-tasks" attrs="{'invisible': [('recurring_id', '=', False)]}"/>
<button class="oe_stat_button" type="object"
string="Document"
name="get_recurring_documents"
icon="fa-tasks" attrs="{'invisible': [('recurring_id', '=', False)]}"/>
</xpath>
</field>
</record>
</flectra>

View File

@ -0,0 +1,3 @@
# Part of Flectra. See LICENSE file for full copyright and licensing details.
from . import models

View File

@ -0,0 +1,21 @@
# Part of Flectra. See LICENSE file for full copyright and licensing details.
{
'name': 'Sale Order Recurring',
'version': '1.0',
'category': 'Extra Tools',
'summary': 'Create recurring of sale order',
'description': """
Sale Order Recurring allows to automatically create recurring of
any particular sale order
""",
'author': 'FlectraHQ',
'website': 'https://www.flectrahq.com/',
'depends': ['sale_management', 'recurring'],
'data': [
'views/sale_views.xml',
],
'demo': ['demo/sale_recurring_demo.xml'],
'installable': True,
'auto_install': False,
}

View File

@ -0,0 +1,12 @@
<?xml version="1.0" ?>
<flectra noupdate="1">
<record id="recurring_sale1" model="recurring">
<field name="name">SO001</field>
<field name="exec_init">2</field>
<field name="interval_type">minutes</field>
<field name="date_init" eval="datetime.now()"/>
<field name="doc_source" ref='sale.sale_order_2'/>
</record>
</flectra>

View File

@ -0,0 +1,42 @@
# Translation of Flectra Server.
# This file contains the translation of the following modules:
# * recurring_sale
#
msgid ""
msgstr ""
"Project-Id-Version: Flectra Server 1.3\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-08-01 16:38+0000\n"
"PO-Revision-Date: 2018-08-01 16:38+0000\n"
"Last-Translator: <>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: recurring_sale
#: model:ir.ui.view,arch_db:recurring_sale.view_order_form_inherit
msgid "Document"
msgstr ""
#. module: recurring_sale
#: model:ir.ui.view,arch_db:recurring_sale.view_order_form_inherit
msgid "Generate Recurring"
msgstr ""
#. module: recurring_sale
#: model:ir.model,name:recurring_sale.model_sale_order
msgid "Quotation"
msgstr ""
#. module: recurring_sale
#: model:ir.ui.view,arch_db:recurring_sale.view_order_form_inherit
msgid "Recurring"
msgstr ""
#. module: recurring_sale
#: model:ir.model.fields,field_description:recurring_sale.field_sale_order_recurring_id
msgid "Recurring Reference"
msgstr ""

View File

@ -0,0 +1,3 @@
# Part of Flectra. See LICENSE file for full copyright and licensing details.
from . import sale

View File

@ -0,0 +1,28 @@
# Part of Flectra. See LICENSE file for full copyright and licensing details.
from flectra import api, models, fields
class SaleOrder(models.Model):
_inherit = "sale.order"
recurring_id = fields.Many2one('recurring', string='Recurring Reference')
rec_source_id = fields.Many2one('sale.order', string='Recurring Source')
@api.multi
def get_recurring(self):
result = self.env['recurring'].get_recurring('sale.order', self.id)
return result
@api.multi
def get_recurring_documents(self):
result = self.env['recurring'].get_recurring_documents(
'sale.order', 'sale.action_quotations', self.recurring_id)
return result
@api.multi
def action_cancel(self):
res = super(SaleOrder, self).action_cancel()
if self.recurring_id:
self.recurring_id.set_done()
return res

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@ -0,0 +1,101 @@
<section class="container">
<div class="row">
<h2 class="oe_slogan">Recurring Sale</h2>
<h3 class="oe_slogan">Create recurring sale order</h3>
</div>
</section>
<section class="container oe_dark">
<div class="row">
<h2 class="oe_slogan">Recurring Wizard</h2>
<div class="col-md-6 text-justify mt32">
<p class="mt32">
A 'Generate Recurring' button is displayed on the sale
order.<br/>
Recurring Document, Recurring Type and Scheduled action of this
particular sale order is automatically created.<br/>
Number of documents - The number of times the document
should be recurred.<br/>
Interval Unit - The interval when the recurring should
occur.<br/>
Start Recurring - Activates the generated recurring.<br/>
Save - Creates the recurring but doesn't activates it.
</p>
</div>
<div class="col-md-6">
<img class="oe_picture oe_screenshot"
src="recurring_document_wizard1.png">
</div>
</div>
</section>
<section class="container">
<div class="row">
<h2 class="oe_slogan">Sale Order</h2>
<div class="col-md-6">
<img class="oe_picture oe_screenshot" src="sale_order.png">
</div>
<div class="col-md-6">
<p class="mt32 mb32 text-justify">
Recurring - Shows the generated recurring.<br/>
Document - Links the sale order that are generated by the
recurring of that particular sale order.
</p>
</div>
</div>
</section>
<section class="container oe_dark">
<div class="row oe_spaced">
<h2 class="oe_slogan">SO Recurring Documents</h2>
<div class="col-md-6">
<p class="mt32">
Sale Orders that are generated through recurring.
</p>
</div>
<div class="col-md-6">
<img class="oe_picture oe_screenshot"
src="recurring_documents.png"/>
</div>
</div>
</section>
<section class="container">
<div class="row">
<h2 class="oe_slogan">Recurring Document</h2>
<div class="col-md-6">
<img class="oe_picture oe_screenshot" src="rec_doc.png"/>
</div>
<div class="col-md-6">
<p class="mt32 text-justify">
Recurring Document is automatically created.
</p>
</div>
</div>
</section>
<section class="container">
<div class="row">
<h2 class="oe_slogan">Recurring Type</h2>
<div class="col-md-6">
<p class="oe_mt8 text-justify">Recurring Type is automatically
created</p>
</div>
<div class="col-md-6">
<img class="oe_picture oe_screenshot" src="rec_type.png">
</div>
</div>
</section>
<section class="container">
<div class="row">
<h2 class="oe_slogan">Scheduled Actions</h2>
<div class="col-md-6">
<img class="oe_picture oe_screenshot" src="cron_job.png">
</div>
<div class="col-md-6">
<p class="oe_mt8 text-justify">Cron job is automatically
created</p>
</div>
</div>
</section>

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

View File

@ -0,0 +1,3 @@
# Part of Flectra. See LICENSE file for full copyright and licensing details.
from . import test_sale_recurring

View File

@ -0,0 +1,20 @@
# Part of Flectra. See LICENSE file for full copyright and licensing details.
from flectra.tests.common import TransactionCase
class RecurringTransactionCase(TransactionCase):
def setUp(self):
super(RecurringTransactionCase, self).setUp()
self.sale_order = self.env.ref("sale.sale_order_2")
def create_sale_recurring(self):
recurring_id = self.env['recurring'].create({
'name': 'SO0002',
'exec_init': 5,
})
recurring_id.btn_recurring()
def test_01_recurring(self):
self.create_sale_recurring()

View File

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<flectra>
<record id="view_order_form_inherit" model="ir.ui.view">
<field name="name">sale.order.form.inherit</field>
<field name="model">sale.order</field>
<field name="inherit_id" ref="sale.view_order_form"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='payment_term_id']" position="after">
<field name="recurring_id" invisible="1"/>
<field name="rec_source_id" readonly="1"/>
</xpath>
<xpath expr="//button[@name='action_cancel']" position="before">
<button name="%(recurring.action_recurring_wizard)d"
id="generate_recurring"
string="Generate Recurring" class="btn-primary"
type="action"
attrs="{'invisible': ['|', ('state', 'in', ['draft','cancel']), ('recurring_id', '!=', False)]}"/>
</xpath>
<xpath expr="//sheet/div[@name='button_box']" position="inside">
<button class="oe_stat_button" type="object"
string="Recurring" name="get_recurring"
icon="fa-tasks" attrs="{'invisible': [('recurring_id', '=', False)]}"/>
<button class="oe_stat_button" type="object"
string="Document" name="get_recurring_documents"
icon="fa-tasks" attrs="{'invisible': [('recurring_id', '=', False)]}"/>
</xpath>
</field>
</record>
</flectra>