[IMP] followup
bzr revid: fp@openerp.com-20121130232837-mnp8cdlnsjpl6jeh
This commit is contained in:
commit
1165abefc4
|
@ -524,11 +524,11 @@ class account_invoice(osv.osv):
|
|||
return result
|
||||
|
||||
def onchange_payment_term_date_invoice(self, cr, uid, ids, payment_term_id, date_invoice):
|
||||
res = {}
|
||||
if not payment_term_id:
|
||||
return res
|
||||
res = {}
|
||||
if not date_invoice:
|
||||
date_invoice = time.strftime('%Y-%m-%d')
|
||||
if not payment_term_id:
|
||||
return {'value':{'date_due': date_invoice}} #To make sure the invoice has a due date when no payment term
|
||||
pterm_list = self.pool.get('account.payment.term').compute(cr, uid, payment_term_id, value=1, date_ref=date_invoice)
|
||||
if pterm_list:
|
||||
pterm_list = [line[0] for line in pterm_list]
|
||||
|
|
|
@ -475,7 +475,8 @@ class account_move_line(osv.osv):
|
|||
type='many2one', relation='account.invoice', fnct_search=_invoice_search),
|
||||
'account_tax_id':fields.many2one('account.tax', 'Tax'),
|
||||
'analytic_account_id': fields.many2one('account.analytic.account', 'Analytic Account'),
|
||||
'company_id': fields.related('account_id', 'company_id', type='many2one', relation='res.company', string='Company', store=True, readonly=True)
|
||||
'company_id': fields.related('account_id', 'company_id', type='many2one', relation='res.company',
|
||||
string='Company', store=True, readonly=True)
|
||||
}
|
||||
|
||||
def _get_date(self, cr, uid, context=None):
|
||||
|
|
|
@ -211,7 +211,7 @@
|
|||
<para style="terp_default_Right_9">[[ (line['account_id']['type'] == 'receivable' and formatLang(line['credit']) or 0) or (line['account_id']['type'] == 'payable' and formatLang(line['debit'] * -1) or 0) ]]</para>
|
||||
</td>
|
||||
<td>
|
||||
<para style="terp_default_Right_9">[[ time.strftime('%Y-%m-%d') > formatLang((line['date_maturity'])) and formatLang(line['debit'] - line['credit'], currency_obj = company.currency_id) ]]</para>
|
||||
<para style="terp_default_Right_9">[[ (time.strftime('%Y-%m-%d') > line['date_maturity']) and formatLang(line['debit'] - line['credit'], currency_obj = company.currency_id) ]]</para>
|
||||
</td>
|
||||
<td>
|
||||
<para style="terp_default_Centre_9">[[ line['blocked'] and 'X' or '' ]]</para>
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
##############################################################################
|
||||
|
||||
{
|
||||
'name': 'Follow-up Management',
|
||||
'name': 'Payment Follow-up Management',
|
||||
'version': '1.0',
|
||||
'category': 'Accounting & Finance',
|
||||
'description': """
|
||||
|
@ -29,19 +29,18 @@ Module to automate letters for unpaid invoices, with multi-level recalls.
|
|||
|
||||
You can define your multiple levels of recall through the menu:
|
||||
---------------------------------------------------------------
|
||||
**Invoicing** / **Configuration** / **Miscellaneous** / **Follow-ups**
|
||||
|
||||
Configuration / Follow-Up Levels
|
||||
|
||||
Once it is defined, you can automatically print recalls every day through simply clicking on the menu:
|
||||
------------------------------------------------------------------------------------------------------
|
||||
**Invoicing** / **Periodical Processing** / **Billing** / **Send follow-ups**
|
||||
Payment Follow-Up / Send Email and letters
|
||||
|
||||
It will generate a PDF with all the letters according to the the different levels
|
||||
of recall defined. You can define different policies for different companies. You
|
||||
can also send mail to the customer.
|
||||
It will generate a PDF / send emails / set manual actions according to the the different levels
|
||||
of recall defined. You can define different policies for different companies.
|
||||
|
||||
Note that if you want to check the follow-up level for a given partner/account entry, you can do from in the menu:
|
||||
------------------------------------------------------------------------------------------------------------------
|
||||
**Invoicing** / **Reporting** / **Generic Reporting** / **Partners** / **Follow-ups Sent**
|
||||
Reporting / Accounting / **Follow-ups Analysis
|
||||
|
||||
""",
|
||||
'author': 'OpenERP SA',
|
||||
|
@ -51,16 +50,16 @@ Note that if you want to check the follow-up level for a given partner/account e
|
|||
'data': [
|
||||
'security/account_followup_security.xml',
|
||||
'security/ir.model.access.csv',
|
||||
'wizard/account_followup_print_view.xml',
|
||||
'report/account_followup_report.xml',
|
||||
'account_followup_demo.xml', # Defined by default
|
||||
'account_followup_view.xml',
|
||||
'account_followup_data.xml',
|
||||
'account_followup_view.xml',
|
||||
'account_followup_customers.xml',
|
||||
'wizard/account_followup_print_view.xml',
|
||||
],
|
||||
'demo': [],
|
||||
'demo': ['account_followup_demo.xml'],
|
||||
'test': [
|
||||
'test/account_followup.yml',
|
||||
'test/account_followup_report.yml',
|
||||
#TODO 'test/account_followup_report.yml', --> Need to wait for second step in order to check report (expects after first)
|
||||
],
|
||||
'installable': True,
|
||||
'auto_install': False,
|
||||
|
|
|
@ -20,37 +20,66 @@
|
|||
##############################################################################
|
||||
|
||||
from osv import fields, osv
|
||||
from lxml import etree
|
||||
|
||||
from tools.translate import _
|
||||
|
||||
|
||||
class followup(osv.osv):
|
||||
_name = 'account_followup.followup'
|
||||
_description = 'Account Follow-up'
|
||||
_rec_name = 'name'
|
||||
_columns = {
|
||||
'name': fields.char('Name', size=64, required=True),
|
||||
'description': fields.text('Description'),
|
||||
'followup_line': fields.one2many('account_followup.followup.line', 'followup_id', 'Follow-up'),
|
||||
'company_id': fields.many2one('res.company', 'Company', required=True),
|
||||
'name': fields.related('company_id', 'name', string = "Name"),
|
||||
}
|
||||
_defaults = {
|
||||
'company_id': lambda s, cr, uid, c: s.pool.get('res.company')._company_default_get(cr, uid, 'account_followup.followup', context=c),
|
||||
}
|
||||
|
||||
followup()
|
||||
_sql_constraints = [('company_uniq', 'unique(company_id)', 'Only one follow-up per company is allowed')]
|
||||
|
||||
|
||||
class followup_line(osv.osv):
|
||||
|
||||
def _get_default_template(self, cr, uid, ids, context=None):
|
||||
dummy, templ = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'account_followup', 'email_template_account_followup_default')
|
||||
return templ
|
||||
|
||||
_name = 'account_followup.followup.line'
|
||||
_description = 'Follow-up Criteria'
|
||||
_columns = {
|
||||
'name': fields.char('Name', size=64, required=True),
|
||||
'name': fields.char('Follow-Up Action', size=64, required=True),
|
||||
'sequence': fields.integer('Sequence', help="Gives the sequence order when displaying a list of follow-up lines."),
|
||||
'delay': fields.integer('Days of delay'),
|
||||
'start': fields.selection([('days','Net Days'),('end_of_month','End of Month')], 'Type of Term', size=64, required=True),
|
||||
'delay': fields.integer('Due Days', help="The number of days after the due date of the invoice to wait before sending the reminder. Could be negative if you want to send a polite alert beforehand.", required=True),
|
||||
'followup_id': fields.many2one('account_followup.followup', 'Follow Ups', required=True, ondelete="cascade"),
|
||||
'description': fields.text('Printed Message', translate=True),
|
||||
'send_email':fields.boolean('Send an Email', help="When processing, it will send an email"),
|
||||
'send_letter':fields.boolean('Send a Letter', help="When processing, it will print a letter"),
|
||||
'manual_action':fields.boolean('Manual Action', help="When processing, it will set the manual action to be taken for that customer. "),
|
||||
'manual_action_note':fields.text('Action To Do', placeholder="e.g. Give a phone call, check with others , ..."),
|
||||
'manual_action_responsible_id':fields.many2one('res.users', 'Assign a Responsible', ondelete='set null'),
|
||||
'email_template_id':fields.many2one('email.template', 'Email Template', ondelete='set null'),
|
||||
}
|
||||
_order = 'delay'
|
||||
_sql_constraints = [('days_uniq', 'unique(followup_id, delay)', 'Days of the follow-up levels must be different')]
|
||||
_defaults = {
|
||||
'start': 'days',
|
||||
'send_email': True,
|
||||
'send_letter': True,
|
||||
'manual_action':False,
|
||||
'description': """
|
||||
Dear %(partner_name)s,
|
||||
|
||||
Exception made if there was a mistake of ours, it seems that the following amount stays unpaid. Please, take appropriate measures in order to carry out this payment in the next 8 days.
|
||||
|
||||
Would your payment have been carried out after this mail was sent, please ignore this message. Do not hesitate to contact our accounting department at (+32).10.68.94.39.
|
||||
|
||||
Best Regards,
|
||||
""",
|
||||
'email_template_id': _get_default_template,
|
||||
}
|
||||
|
||||
|
||||
def _check_description(self, cr, uid, ids, context=None):
|
||||
for line in self.browse(cr, uid, ids, context=context):
|
||||
if line.description:
|
||||
|
@ -64,40 +93,192 @@ class followup_line(osv.osv):
|
|||
(_check_description, 'Your description is invalid, use the right legend or %% if you want to use the percent character.', ['description']),
|
||||
]
|
||||
|
||||
followup_line()
|
||||
|
||||
class account_move_line(osv.osv):
|
||||
|
||||
def _get_result(self, cr, uid, ids, name, arg, context=None):
|
||||
res = {}
|
||||
for aml in self.browse(cr, uid, ids, context=context):
|
||||
res[aml.id] = aml.debit - aml.credit
|
||||
return res
|
||||
|
||||
_inherit = 'account.move.line'
|
||||
_columns = {
|
||||
'followup_line_id': fields.many2one('account_followup.followup.line', 'Follow-up Level'),
|
||||
'followup_line_id': fields.many2one('account_followup.followup.line', 'Follow-up Level',
|
||||
ondelete='restrict'), #restrict deletion of the followup line
|
||||
'followup_date': fields.date('Latest Follow-up', select=True),
|
||||
'result':fields.function(_get_result, type='float', method=True,
|
||||
string="Balance") #'balance' field is not the same
|
||||
}
|
||||
|
||||
account_move_line()
|
||||
|
||||
class res_company(osv.osv):
|
||||
_inherit = "res.company"
|
||||
|
||||
class email_template(osv.osv):
|
||||
_inherit = 'email.template'
|
||||
|
||||
# Adds current_date to the context. That way it can be used to put
|
||||
# the account move lines in bold that are overdue in the email
|
||||
def render_template(self, cr, uid, template, model, res_id, context=None):
|
||||
context['current_date'] = fields.date.context_today(cr, uid, context)
|
||||
return super(email_template, self).render_template(cr, uid, template, model, res_id, context=context)
|
||||
|
||||
|
||||
class res_partner(osv.osv):
|
||||
|
||||
def fields_view_get(self, cr, uid, view_id=None, view_type=None, context=None, toolbar=False, submenu=False):
|
||||
res = super(res_partner, self).fields_view_get(cr, uid, view_id=view_id, view_type=view_type, context=context,
|
||||
toolbar=toolbar, submenu=submenu)
|
||||
if view_type == 'form' and context and 'Followupfirst' in context.keys() and context['Followupfirst'] == True:
|
||||
doc = etree.XML(res['arch'], parser=None, base_url=None)
|
||||
first_node = doc.xpath("//page[@string='Payment Follow-up']")
|
||||
root = first_node[0].getparent()
|
||||
root.insert(0, first_node[0])
|
||||
res['arch'] = etree.tostring(doc)
|
||||
return res
|
||||
|
||||
def _get_latest(self, cr, uid, ids, names, arg, context=None, company_id=None):
|
||||
res={}
|
||||
if company_id == None:
|
||||
company = self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id
|
||||
else:
|
||||
company = self.pool.get('res.company').browse(cr, uid, company_id, context=context)
|
||||
for partner in self.browse(cr, uid, ids, context=context):
|
||||
amls = partner.unreconciled_aml_ids
|
||||
latest_date = False
|
||||
latest_level = False
|
||||
latest_days = False
|
||||
latest_level_without_lit = False
|
||||
latest_days_without_lit = False
|
||||
for aml in amls:
|
||||
if (aml.company_id == company) and (aml.followup_line_id != False) and (not latest_days or latest_days < aml.followup_line_id.delay):
|
||||
latest_days = aml.followup_line_id.delay
|
||||
latest_level = aml.followup_line_id.id
|
||||
if (aml.company_id == company) and (not latest_date or latest_date < aml.followup_date):
|
||||
latest_date = aml.followup_date
|
||||
if (aml.company_id == company) and (aml.blocked == False) and (aml.followup_line_id != False and
|
||||
(not latest_days_without_lit or latest_days_without_lit < aml.followup_line_id.delay)):
|
||||
latest_days_without_lit = aml.followup_line_id.delay
|
||||
latest_level_without_lit = aml.followup_line_id.id
|
||||
res[partner.id] = {'latest_followup_date': latest_date,
|
||||
'latest_followup_level_id': latest_level,
|
||||
'latest_followup_level_id_without_lit': latest_level_without_lit}
|
||||
return res
|
||||
|
||||
def do_partner_manual_action(self, cr, uid, partner_ids, context=None):
|
||||
#partner_ids -> res.partner
|
||||
for partner in self.browse(cr, uid, partner_ids, context=context):
|
||||
#Check action: check if the action was not empty, if not add
|
||||
action_text= ""
|
||||
if partner.payment_next_action:
|
||||
action_text = (partner.payment_next_action or '') + "\n" + (partner.latest_followup_level_id_without_lit.manual_action_note or '')
|
||||
else:
|
||||
action_text = partner.latest_followup_level_id_without_lit.manual_action_note or ''
|
||||
|
||||
#Check date: put the minimum date if it existed already
|
||||
action_date = (partner.payment_next_action_date and min(partner.payment_next_action_date, fields.date.context_today(cr, uid, context))
|
||||
) or fields.date.context_today(cr, uid, context)
|
||||
|
||||
# Check responsible: if partner has not got a responsible already, take from follow-up
|
||||
responsible_id = False
|
||||
if partner.payment_responsible_id:
|
||||
responsible_id = partner.payment_responsible_id.id
|
||||
else:
|
||||
p = partner.latest_followup_level_id_without_lit.manual_action_responsible_id
|
||||
responsible_id = p and p.id or False
|
||||
self.write(cr, uid, [partner.id], {'payment_next_action_date': action_date,
|
||||
'payment_next_action': action_text,
|
||||
'payment_responsible_id': responsible_id})
|
||||
|
||||
def do_partner_print(self, cr, uid, wizard_partner_ids, data, context=None):
|
||||
#wizard_partner_ids are ids from special view, not from res.partner
|
||||
if not wizard_partner_ids:
|
||||
return {}
|
||||
data['partner_ids'] = wizard_partner_ids
|
||||
datas = {
|
||||
'ids': [],
|
||||
'model': 'account_followup.followup',
|
||||
'form': data
|
||||
}
|
||||
return {
|
||||
'type': 'ir.actions.report.xml',
|
||||
'report_name': 'account_followup.followup.print',
|
||||
'datas': datas,
|
||||
}
|
||||
|
||||
def do_partner_mail(self, cr, uid, partner_ids, context=None):
|
||||
#partner_ids are res.partner ids
|
||||
# If not defined by latest follow-up level, it will be the default template if it can find it
|
||||
mtp = self.pool.get('email.template')
|
||||
unknown_mails = 0
|
||||
for partner in self.browse(cr, uid, partner_ids, context=context):
|
||||
if partner.email and partner.email.strip():
|
||||
level = partner.latest_followup_level_id_without_lit
|
||||
if level and level.send_email and level.email_template_id and level.email_template_id.id:
|
||||
mtp.send_mail(cr, uid, level.email_template_id.id, partner.id, context=context)
|
||||
else:
|
||||
mail_template_id = self.pool.get('ir.model.data').get_object_reference(cr, uid,
|
||||
'account_followup', 'email_template_account_followup_default')
|
||||
mtp.send_mail(cr, uid, mail_template_id[1], partner.id, context=context)
|
||||
else:
|
||||
unknown_mails = unknown_mails + 1
|
||||
action_text = _("Email not sent because of email address of partner not filled in")
|
||||
if partner.payment_next_action_date:
|
||||
payment_action_date = min(fields.date.context_today(cr, uid, context), partner.payment_next_action_date)
|
||||
else:
|
||||
payment_action_date = fields.date.context_today(cr, uid, context)
|
||||
if partner.payment_next_action:
|
||||
payment_next_action = partner.payment_next_action + " + " + action_text
|
||||
else:
|
||||
payment_next_action = action_text
|
||||
self.write(cr, uid, [partner.id], {'payment_next_action_date': payment_action_date,
|
||||
'payment_next_action': payment_next_action}, context=context)
|
||||
return unknown_mails
|
||||
|
||||
def action_done(self, cr, uid, ids, context=None):
|
||||
return self.write(cr, uid, ids, {'payment_next_action_date': False, 'payment_next_action':'', 'payment_responsible_id': False}, context=context)
|
||||
|
||||
def do_button_print(self, cr, uid, ids, context=None):
|
||||
assert(len(ids) == 1)
|
||||
self.message_post(cr, uid, [ids[0]], body=_('Printed overdue payments report'), context=context)
|
||||
datas = {
|
||||
'ids': ids,
|
||||
'model': 'res.partner',
|
||||
'form': self.read(cr, uid, ids[0], context=context)
|
||||
}
|
||||
return {
|
||||
'type': 'ir.actions.report.xml',
|
||||
'report_name': 'account.overdue',
|
||||
'datas': datas,
|
||||
'nodestroy' : True
|
||||
}
|
||||
|
||||
|
||||
_inherit = "res.partner"
|
||||
_columns = {
|
||||
'follow_up_msg': fields.text('Follow-up Message', translate=True),
|
||||
}
|
||||
|
||||
_defaults = {
|
||||
'follow_up_msg': '''
|
||||
Date: %(date)s
|
||||
|
||||
Dear %(partner_name)s,
|
||||
|
||||
Please find in attachment a reminder of all your unpaid invoices, for a total amount due of:
|
||||
|
||||
%(followup_amount).2f %(company_currency)s
|
||||
|
||||
Thanks,
|
||||
--
|
||||
%(user_signature)s
|
||||
%(company_name)s
|
||||
'''
|
||||
}
|
||||
|
||||
res_company()
|
||||
'payment_responsible_id':fields.many2one('res.users', ondelete='set null', string='Follow-up Responsible',
|
||||
help="Responsible for making sure the action happens."),
|
||||
'payment_note':fields.text('Customer Payment Promise', help="Payment Note"),
|
||||
'payment_next_action':fields.text('Next Action',
|
||||
help="This is the next action to be taken by the user. It will automatically be set when the action fields are empty and the partner gets a follow-up level that requires a manual action. "),
|
||||
'payment_next_action_date':fields.date('Next Action Date',
|
||||
help="This is when further follow-up is needed. The date will have been set to the current date if the action fields are empty and the partner gets a follow-up level that requires a manual action. "),
|
||||
'unreconciled_aml_ids':fields.one2many('account.move.line', 'partner_id', domain=['&', ('reconcile_id', '=', False), '&',
|
||||
('account_id.active','=', True), '&', ('account_id.type', '=', 'receivable'), ('state', '!=', 'draft')]),
|
||||
'latest_followup_date':fields.function(_get_latest, method=True, type='date', string="Latest Follow-up Date",
|
||||
help="Latest date that the follow-up level of the partner was changed",
|
||||
store=False,
|
||||
multi="latest"),
|
||||
'latest_followup_level_id':fields.function(_get_latest, method=True,
|
||||
type='many2one', relation='account_followup.followup.line', string="Latest Follow-up Level",
|
||||
help="The maximum follow-up level",
|
||||
store=False,
|
||||
multi="latest"),
|
||||
'latest_followup_level_id_without_lit':fields.function(_get_latest, method=True,
|
||||
type='many2one', relation='account_followup.followup.line', string="Latest Follow-up Level without litigation",
|
||||
help="The maximum follow-up level without taking into account the account move lines with litigation",
|
||||
store=False,
|
||||
multi="latest"),
|
||||
'payment_amount_due':fields.related('credit', type='float', string="Total amount due", readonly=True),
|
||||
}
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
|
@ -0,0 +1,159 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<!-- followup of customers views -->
|
||||
|
||||
<record id="customer_followup_tree" model="ir.ui.view">
|
||||
<field name="name">res.partner.followup.inherit.tree</field>
|
||||
<field name="model">res.partner</field>
|
||||
<field name="priority" eval="20"/>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Customer Followup">
|
||||
<field name="name"/>
|
||||
<field name="payment_next_action_date"/>
|
||||
<field name="payment_next_action"/>
|
||||
<field name="user_id" invisible="1"/>
|
||||
<field name="parent_id" invisible="1"/>
|
||||
<field name="payment_responsible_id"/>
|
||||
<field name="credit"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="customer_followup_search_view" model="ir.ui.view">
|
||||
<field name="name">Search</field>
|
||||
<field name="model">res.partner</field>
|
||||
<field name="inherit_id" ref="base.view_res_partner_filter"/>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Search Partner" position="inside">
|
||||
<group string="Follow-up">
|
||||
<filter string="Partners with Credits" domain="[('credit', '>', 0.0)]" name="credits"/>
|
||||
<separator/>
|
||||
<filter string="Follow-ups To Do" domain="[('payment_next_action_date', '<=', time.strftime('%%Y-%%m-%%d')), ('credit', '>', 0.0)]" name="todo"/>
|
||||
<filter string="Future Follow-ups" domain="[('payment_next_action_date', '>', time.strftime('%%Y-%%m-%%d')), ('credit', '>', 0.0)]"/>
|
||||
<separator/>
|
||||
<filter string="No Responsible" domain="[('payment_responsible_id', '=', False)]"/>
|
||||
<filter string="My Follow-ups" domain="[('payment_responsible_id','=', uid)]"/>
|
||||
</group>
|
||||
<group expand="1" string="Group By...">
|
||||
<filter string="Responsible" context="{'group_by':'payment_responsible_id'}"/>
|
||||
</group>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="customer_followup_search_view2" model="ir.ui.view">
|
||||
<field name="name">Search</field>
|
||||
<field name="model">res.partner</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Search view">
|
||||
<field name="name"/>
|
||||
<field name="payment_next_action"/>
|
||||
<!--<filter string="Actions to be taken with overdue amount" domain="['&', ('payment_amount_outstanding', '>', 0.0), ('payment_next_action_date', '<=', time.strftime('%%Y-%%m-%%d'))]"/>
|
||||
<separator/>-->
|
||||
<filter string="Overdue amount" domain="[('credit', '>', 0.0)]"/>
|
||||
<separator/>
|
||||
<filter string="Follow-ups to do" domain="[('payment_next_action_date', '<=', time.strftime('%%Y-%%m-%%d'))]"/>
|
||||
<separator/>
|
||||
<!--filter string="Future follow-ups" domain="['&', ('payment_next_action', '!=', ''), ('payment_next_action_date', '>', time.strftime('%%Y-%%m-%%d'))]"/>-->
|
||||
<separator/>
|
||||
<filter string="Without responsible" domain="[('payment_responsible_id', '=', False)]"/>
|
||||
<filter string="I am responsible" domain="[('payment_responsible_id','=', uid)]"/>
|
||||
<group expand="1" string="Group by">
|
||||
<filter string="Responsible" context="{'group_by':'payment_responsible_id'}"/>
|
||||
</group>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_customer_followup" model="ir.actions.act_window">
|
||||
<field name="name">Manual Follow-Ups</field>
|
||||
<field name="view_id" ref="customer_followup_tree"/>
|
||||
<field name="res_model">res.partner</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="context">{} </field>
|
||||
<field name="context">{'Followupfirst':True, 'search_default_todo': True} </field>
|
||||
<field name="search_view_id" ref="customer_followup_search_view"/>
|
||||
</record>
|
||||
|
||||
<!--Inherited view -->
|
||||
<record id="view_partner_inherit_followup_form" model="ir.ui.view">
|
||||
<field name="name">res.partner.followup.form.inherit</field>
|
||||
<field name="inherit_id" ref="base.view_partner_form"/>
|
||||
<field name="model">res.partner</field>
|
||||
<!--<field eval="[(4, ref('account.group_account_user'))]" name="groups_id"/>--><!-- or user? -->
|
||||
<field name="arch" type="xml" >
|
||||
<page string="Accounting" position="before" version="7.0">
|
||||
<page string="Payment Follow-up" position="inside" groups="account.group_account_invoice">
|
||||
<div class="oe_right oe_button_box" name="followup_button">
|
||||
<button name="do_button_print" type="object" string="Print Overdue Payments" groups="account.group_account_user"
|
||||
help="Print overdue payments report independent of follow-up line" attrs="{'invisible':[('credit', '<=', 0.0)]}" />
|
||||
<button name="do_partner_mail" type="object" string="Send Overdue Email" groups="account.group_account_user"
|
||||
help="If not specified by the latest follow-up level, it will send from the default follow-up of overdue invoices template" attrs="{'invisible':[('credit', '<=', 0.0)]}"/>
|
||||
</div>
|
||||
<p attrs="{'invisible':[('latest_followup_date','=', False)]}">
|
||||
The <field name="latest_followup_date" class = "oe_inline"/>, the latest payment follow-up
|
||||
was: <field name="latest_followup_level_id" class="oe_inline"/>
|
||||
</p>
|
||||
<group>
|
||||
<field name="payment_responsible_id" placeholder="Responsible of credit collection" class="oe_inline"/>
|
||||
|
||||
<label for="payment_next_action"/>
|
||||
<div>
|
||||
<field name="payment_next_action_date" class="oe_inline"/>
|
||||
<button name="action_done" type="object" string="⇾ Mark as Done"
|
||||
help="Click to mark the action as done." class="oe_link"
|
||||
attrs="{'invisible':[('payment_next_action_date','=', False)]}"
|
||||
groups="base.group_partner_manager"/>
|
||||
<field name="payment_next_action" placeholder="e.g. Give a phonecall, Check if it's paid, ..."/>
|
||||
</div>
|
||||
</group>
|
||||
<label for="payment_note" class="oe_edit_only"/>
|
||||
<field name="payment_note" placeholder="e.g. 50%% before 15th of May, balance before 1st of July."/>
|
||||
<p class="oe_grey"> <!--maybe only when accountmovelines empty-->
|
||||
Below is the history of the transactions of this
|
||||
customer. You can set an invoice in litigation in
|
||||
order to not include it in the next payment
|
||||
follow-ups.
|
||||
</p>
|
||||
<field name="unreconciled_aml_ids">
|
||||
<tree string="Account Move line" editable="bottom" create="false" delete="false" colors="red:(not date_maturity or date_maturity<=current_date) and result>0">
|
||||
<field name="date" readonly="True"/>
|
||||
<field name="move_id" readonly="True"/>
|
||||
<field name="blocked" string="Litigation"/>
|
||||
<field name="date_maturity" readonly="True"/>
|
||||
<field name="reconcile_partial_id" readonly="True"/>
|
||||
<field name="result" readonly="True"/>
|
||||
<field name="followup_line_id" invisible='1'/>
|
||||
</tree>
|
||||
</field>
|
||||
<group class="oe_subtotal_footer oe_right">
|
||||
<field name="payment_amount_due"/>
|
||||
</group>
|
||||
<div class="oe_clear"/>
|
||||
</page>
|
||||
</page>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_view_customer_followup_form" model="ir.actions.act_window.view">
|
||||
<field name="sequence" eval="2"/>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="view_id" ref="view_partner_inherit_followup_form"/>
|
||||
<field name="act_window_id" ref="action_customer_followup"/>
|
||||
</record>
|
||||
<record id="action_view_customer_followup_tree" model="ir.actions.act_window.view">
|
||||
<field name="sequence" eval="1"/>
|
||||
<field name="view_mode">tree</field>
|
||||
<field name="view_id" ref="customer_followup_tree"/>
|
||||
<field name="act_window_id" ref="action_customer_followup"/>
|
||||
</record>
|
||||
|
||||
<!-- Menus about followup of customers -->
|
||||
<menuitem id="account_followup_s" action="action_customer_followup"
|
||||
parent="menu_finance_followup" name="Do Manual Follow-Ups" sequence="3"/>
|
||||
|
||||
</data>
|
||||
</openerp>
|
|
@ -1,19 +1,378 @@
|
|||
<?xml version="1.0"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<record model="res.company" id="base.main_company">
|
||||
<field name="follow_up_msg">Date : %(date)s
|
||||
<!-- Mail template is done in a NOUPDATE block
|
||||
so users can freely customize/delete them -->
|
||||
<data noupdate="1">
|
||||
<!--Mail template level 0-->
|
||||
<record id="email_template_account_followup_level0" model="email.template">
|
||||
<field name="name">Follow-up of overdue invoices level 0</field>
|
||||
<field name="email_from">${user.email or ''}</field>
|
||||
<field name="subject">${user.company_id.name} Payment Follow-up</field>
|
||||
<field name="email_to">${object.email}</field>
|
||||
<field name="lang">${object.lang}</field>
|
||||
<field name="model_id" ref="base.model_res_partner"/>
|
||||
<field name="auto_delete" eval="True"/>
|
||||
<field name="body_html"><![CDATA[
|
||||
<div style="font-family: 'Lucica Grande', Ubuntu, Arial, Verdana, sans-serif; font-size: 12px; color: rgb(34, 34, 34); background-color: rgb(255, 255, 255); ">
|
||||
|
||||
<p>Dear ${object.name},</p>
|
||||
<p>
|
||||
Exception made if there was a mistake of ours, it seems that the following amount stays unpaid. Please, take
|
||||
appropriate measures in order to carry out this payment in the next 8 days.
|
||||
|
||||
Would your payment have been carried out after this mail was sent, please ignore this message. Do not hesitate to
|
||||
contact our accounting department at (+32).10.68.94.39.
|
||||
|
||||
</p>
|
||||
<br/>
|
||||
Best Regards,
|
||||
|
||||
<br/>
|
||||
${user.name}
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
<%
|
||||
from openerp.addons.account_followup.report import account_followup_print
|
||||
rml_parse = account_followup_print.report_rappel(object._cr, user.id, "followup_rml_parser")
|
||||
final_res = rml_parse._lines_get_with_partner(object, user.company_id.id)
|
||||
followup_table = ''
|
||||
for currency_dict in final_res:
|
||||
currency_symbol = currency_dict.get('line', [{'currency_id': user.company_id.currency_id}])[0]['currency_id'].symbol
|
||||
followup_table += '''
|
||||
<table border="2" width=100%%>
|
||||
<tr>
|
||||
<td>Invoice date</td>
|
||||
<td>Reference</td>
|
||||
<td>Due date</td>
|
||||
<td>Amount (%s)</td>
|
||||
<td>Lit.</td>
|
||||
</tr>
|
||||
''' % (currency_symbol)
|
||||
total = 0
|
||||
for aml in currency_dict['line']:
|
||||
block = aml['blocked'] and 'X' or ' '
|
||||
total += aml['balance']
|
||||
strbegin = "<TD> "
|
||||
strend = "</TD> "
|
||||
date = aml['date_maturity'] or aml['date']
|
||||
if date <= ctx['current_date'] and aml['balance'] > 0:
|
||||
strbegin = "<TD><B>"
|
||||
strend = "</B></TD>"
|
||||
followup_table +="<TR>" + strbegin + str(aml['date']) + strend + strbegin + aml['ref'] + strend + strbegin + str(date) + strend + strbegin + str(aml['balance']) + strend + strbegin + block + strend + "</TR>"
|
||||
total = rml_parse.formatLang(total, dp='Account', currency_obj=object.company_id.currency_id)
|
||||
followup_table += '''<tr> </tr>
|
||||
</table>
|
||||
<center>Amount due: %s </center>''' % (total)
|
||||
|
||||
%>
|
||||
|
||||
${followup_table}
|
||||
|
||||
<br/>
|
||||
|
||||
</div>
|
||||
]]></field>
|
||||
</record>
|
||||
|
||||
|
||||
|
||||
<!--Mail template level 1 -->
|
||||
<record id="email_template_account_followup_level1" model="email.template">
|
||||
<field name="name">Follow-up of overdue invoices level 1</field>
|
||||
<field name="email_from">${user.email or ''}</field>
|
||||
<field name="subject">${user.company_id.name} Payment Follow-up</field>
|
||||
<field name="email_to">${object.email}</field>
|
||||
<field name="lang">${object.lang}</field>
|
||||
<field name="model_id" ref="base.model_res_partner"/>
|
||||
<field name="auto_delete" eval="True"/>
|
||||
<field name="body_html"><![CDATA[
|
||||
<div style="font-family: 'Lucica Grande', Ubuntu, Arial, Verdana, sans-serif; font-size: 12px; color: rgb(34, 34, 34); background-color: rgb(255, 255, 255); ">
|
||||
|
||||
<p>Dear ${object.name},</p>
|
||||
<p>
|
||||
We are disappointed to see that despite sending a reminder, that your account is now seriously overdue.
|
||||
It is essential that immediate payment is made, otherwise we will have to consider placing a stop on your account
|
||||
which means that we will no longer be able to supply your company with (goods/services).
|
||||
Please, take appropriate measures in order to carry out this payment in the next 8 days.
|
||||
If there is a problem with paying invoice that we are not aware of, do not hesitate to contact our accounting
|
||||
department at (+32).10.68.94.39. so that we can resolve the matter quickly.
|
||||
Details of due payments is printed below.
|
||||
</p>
|
||||
<br/>
|
||||
Best Regards,
|
||||
|
||||
<br/>
|
||||
${user.name}
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
|
||||
<%
|
||||
from openerp.addons.account_followup.report import account_followup_print
|
||||
rml_parse = account_followup_print.report_rappel(object._cr, user.id, "followup_rml_parser")
|
||||
final_res = rml_parse._lines_get_with_partner(object, user.company_id.id)
|
||||
followup_table = ''
|
||||
for currency_dict in final_res:
|
||||
currency_symbol = currency_dict.get('line', [{'currency_id': user.company_id.currency_id}])[0]['currency_id'].symbol
|
||||
followup_table += '''
|
||||
<table border="2" width=100%%>
|
||||
<tr>
|
||||
<td>Invoice date</td>
|
||||
<td>Reference</td>
|
||||
<td>Due date</td>
|
||||
<td>Amount (%s)</td>
|
||||
<td>Lit.</td>
|
||||
</tr>
|
||||
''' % (currency_symbol)
|
||||
total = 0
|
||||
for aml in currency_dict['line']:
|
||||
block = aml['blocked'] and 'X' or ' '
|
||||
total += aml['balance']
|
||||
strbegin = "<TD> "
|
||||
strend = "</TD> "
|
||||
date = aml['date_maturity'] or aml['date']
|
||||
if date <= ctx['current_date'] and aml['balance'] > 0:
|
||||
strbegin = "<TD><B>"
|
||||
strend = "</B></TD>"
|
||||
followup_table +="<TR>" + strbegin + str(aml['date']) + strend + strbegin + aml['ref'] + strend + strbegin + str(date) + strend + strbegin + str(aml['balance']) + strend + strbegin + block + strend + "</TR>"
|
||||
total = rml_parse.formatLang(total, dp='Account', currency_obj=object.company_id.currency_id)
|
||||
followup_table += '''<tr> </tr>
|
||||
</table>
|
||||
<center>Amount due: %s </center>''' % (total)
|
||||
|
||||
%>
|
||||
|
||||
${followup_table}
|
||||
|
||||
<br/>
|
||||
|
||||
</div>
|
||||
]]></field>
|
||||
</record>
|
||||
<!--Email template -->
|
||||
<record id="email_template_account_followup_level2" model="email.template">
|
||||
<field name="name">Follow-up of overdue invoices level 2</field>
|
||||
<field name="email_from">${user.email or ''}</field>
|
||||
<field name="subject">${user.company_id.name} Payment Follow-up</field>
|
||||
<field name="email_to">${object.email}</field>
|
||||
<field name="lang">${object.lang}</field>
|
||||
<field name="model_id" ref="base.model_res_partner"/>
|
||||
<field name="auto_delete" eval="True"/>
|
||||
<field name="body_html"><![CDATA[
|
||||
<div style="font-family: 'Lucica Grande', Ubuntu, Arial, Verdana, sans-serif; font-size: 12px; color: rgb(34, 34, 34); background-color: rgb(255, 255, 255); ">
|
||||
|
||||
<p>Dear ${object.name},</p>
|
||||
<p>
|
||||
Despite several reminders, your account is still not settled.
|
||||
Unless full payment is made in next 8 days, legal action for the recovery of the debt will be taken without
|
||||
further notice.
|
||||
I trust that this action will prove unnecessary and details of due payments is printed below.
|
||||
In case of any queries concerning this matter, do not hesitate to contact our accounting department at (+32).10.68.94.39.
|
||||
</p>
|
||||
<br/>
|
||||
Best Regards,
|
||||
|
||||
<br/>
|
||||
${user.name}
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
|
||||
|
||||
<%
|
||||
from openerp.addons.account_followup.report import account_followup_print
|
||||
rml_parse = account_followup_print.report_rappel(object._cr, user.id, "followup_rml_parser")
|
||||
final_res = rml_parse._lines_get_with_partner(object, user.company_id.id)
|
||||
followup_table = ''
|
||||
for currency_dict in final_res:
|
||||
currency_symbol = currency_dict.get('line', [{'currency_id': user.company_id.currency_id}])[0]['currency_id'].symbol
|
||||
followup_table += '''
|
||||
<table border="2" width=100%%>
|
||||
<tr>
|
||||
<td>Invoice date</td>
|
||||
<td>Reference</td>
|
||||
<td>Due date</td>
|
||||
<td>Amount (%s)</td>
|
||||
<td>Lit.</td>
|
||||
</tr>
|
||||
''' % (currency_symbol)
|
||||
total = 0
|
||||
for aml in currency_dict['line']:
|
||||
block = aml['blocked'] and 'X' or ' '
|
||||
total += aml['balance']
|
||||
strbegin = "<TD> "
|
||||
strend = "</TD> "
|
||||
date = aml['date_maturity'] or aml['date']
|
||||
if date <= ctx['current_date'] and aml['balance'] > 0:
|
||||
strbegin = "<TD><B>"
|
||||
strend = "</B></TD>"
|
||||
followup_table +="<TR>" + strbegin + str(aml['date']) + strend + strbegin + aml['ref'] + strend + strbegin + str(date) + strend + strbegin + str(aml['balance']) + strend + strbegin + block + strend + "</TR>"
|
||||
total = rml_parse.formatLang(total, dp='Account', currency_obj=object.company_id.currency_id)
|
||||
followup_table += '''<tr> </tr>
|
||||
</table>
|
||||
<center>Amount due: %s </center>''' % (total)
|
||||
|
||||
%>
|
||||
|
||||
${followup_table}
|
||||
|
||||
<br/>
|
||||
|
||||
</div>
|
||||
]]></field>
|
||||
</record>
|
||||
|
||||
<!-- Default follow up message -->
|
||||
|
||||
<record id="email_template_account_followup_default" model="email.template">
|
||||
<field name="name">Default follow-up of overdue invoices</field>
|
||||
<field name="email_from">${user.email or ''}</field>
|
||||
<field name="subject">${user.company_id.name} Payment Follow-up</field>
|
||||
<field name="email_to">${object.email}</field>
|
||||
<field name="lang">${object.lang}</field>
|
||||
<field name="model_id" ref="base.model_res_partner"/>
|
||||
<field name="auto_delete" eval="True"/>
|
||||
<field name="body_html"><![CDATA[
|
||||
<div style="font-family: 'Lucica Grande', Ubuntu, Arial, Verdana, sans-serif; font-size: 12px; color: rgb(34, 34, 34); background-color: rgb(255, 255, 255); ">
|
||||
|
||||
<p>Dear ${object.name},</p>
|
||||
<p>
|
||||
Exception made if there was a mistake of ours, it seems that the following amount stays unpaid. Please, take
|
||||
appropriate measures in order to carry out this payment in the next 8 days.
|
||||
Would your payment have been carried out after this mail was sent, please ignore this message. Do not hesitate to
|
||||
contact our accounting department at (+32).10.68.94.39.
|
||||
</p>
|
||||
<br/>
|
||||
Best Regards,
|
||||
</br>
|
||||
</br>
|
||||
<br/>
|
||||
${user.name}
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
|
||||
|
||||
<%
|
||||
from openerp.addons.account_followup.report import account_followup_print
|
||||
rml_parse = account_followup_print.report_rappel(object._cr, user.id, "followup_rml_parser")
|
||||
final_res = rml_parse._lines_get_with_partner(object, user.company_id.id)
|
||||
followup_table = ''
|
||||
for currency_dict in final_res:
|
||||
currency_symbol = currency_dict.get('line', [{'currency_id': user.company_id.currency_id}])[0]['currency_id'].symbol
|
||||
followup_table += '''
|
||||
<table border="2" width=100%%>
|
||||
<tr>
|
||||
<td>Invoice date</td>
|
||||
<td>Reference</td>
|
||||
<td>Due date</td>
|
||||
<td>Amount (%s)</td>
|
||||
<td>Lit.</td>
|
||||
</tr>
|
||||
''' % (currency_symbol)
|
||||
total = 0
|
||||
for aml in currency_dict['line']:
|
||||
block = aml['blocked'] and 'X' or ' '
|
||||
total += aml['balance']
|
||||
strbegin = "<TD> "
|
||||
strend = "</TD> "
|
||||
date = aml['date_maturity'] or aml['date']
|
||||
if date <= ctx['current_date'] and aml['balance'] > 0:
|
||||
strbegin = "<TD><B>"
|
||||
strend = "</B></TD>"
|
||||
followup_table +="<TR>" + strbegin + str(aml['date']) + strend + strbegin + aml['ref'] + strend + strbegin + str(date) + strend + strbegin + str(aml['balance']) + strend + strbegin + block + strend + "</TR>"
|
||||
total = rml_parse.formatLang(total, dp='Account', currency_obj=object.company_id.currency_id)
|
||||
followup_table += '''<tr> </tr>
|
||||
</table>
|
||||
<center>Amount due: %s </center>''' % (total)
|
||||
|
||||
%>
|
||||
|
||||
${followup_table}
|
||||
|
||||
<br/>
|
||||
|
||||
</div>
|
||||
]]></field>
|
||||
</record>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<record id="demo_followup1" model="account_followup.followup">
|
||||
<field name="company_id" ref="base.main_company"/>
|
||||
</record>
|
||||
|
||||
<record id="demo_followup_line1" model="account_followup.followup.line">
|
||||
<field name="name">Send first reminder email</field>
|
||||
<field name="sequence">0</field>
|
||||
<field name="delay">15</field>
|
||||
<field name="followup_id" ref="demo_followup1"/>
|
||||
<field name="send-email">True</field>
|
||||
<field name="description">
|
||||
Dear %(partner_name)s,
|
||||
|
||||
Please find in attachment a reminder of all your unpaid invoices, for a total amount due of:
|
||||
Exception made if there was a mistake of ours, it seems that the following amount stays unpaid. Please, take appropriate measures in order to carry out this payment in the next 8 days.
|
||||
|
||||
%(followup_amount).2f %(company_currency)s
|
||||
Would your payment have been carried out after this mail was sent, please ignore this message. Do not hesitate to contact our accounting department at (+32).10.68.94.39.
|
||||
|
||||
Thanks,
|
||||
--
|
||||
%(user_signature)s
|
||||
%(company_name)s</field>
|
||||
Best Regards,
|
||||
</field>
|
||||
<field name="email_template_id" ref="email_template_account_followup_level0"/>
|
||||
</record>
|
||||
|
||||
<record id="demo_followup_line2" model="account_followup.followup.line">
|
||||
<field name="name">Send reminder letter and email</field>
|
||||
<field name="sequence">1</field>
|
||||
<field name="delay">30</field>
|
||||
<field name="followup_id" ref="demo_followup1"/>
|
||||
<field name="email_template_id" ref="email_template_account_followup_level1"/>
|
||||
<field name="send_email">True</field>
|
||||
<field name="send_letter">True</field>
|
||||
<field name="description">
|
||||
Dear %(partner_name)s,
|
||||
|
||||
We are disappointed to see that despite sending a reminder, that your account is now seriously overdue.
|
||||
|
||||
It is essential that immediate payment is made, otherwise we will have to consider placing a stop on your account which means that we will no longer be able to supply your company with (goods/services).
|
||||
Please, take appropriate measures in order to carry out this payment in the next 8 days.
|
||||
|
||||
If there is a problem with paying invoice that we are not aware of, do not hesitate to contact our accounting department at (+32).10.68.94.39. so that we can resolve the matter quickly.
|
||||
|
||||
Details of due payments is printed below.
|
||||
|
||||
Best Regards,
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
<record id="demo_followup_line3" model="account_followup.followup.line">
|
||||
<field name="name">Call the customer on the phone</field>
|
||||
<field name="sequence">3</field>
|
||||
<field name="delay">40</field>
|
||||
<field name="followup_id" ref="demo_followup1"/>
|
||||
<field name="email_template_id" ref="email_template_account_followup_level2"/>
|
||||
<field eval="False" name="send_email"/>
|
||||
<field name="manual_action">True</field>
|
||||
<field name="manual_action_note">Call the customer on the phone! </field>
|
||||
<field name="description">
|
||||
Dear %(partner_name)s,
|
||||
|
||||
Despite several reminders, your account is still not settled.
|
||||
|
||||
Unless full payment is made in next 8 days, then legal action for the recovery of the debt will be taken without further notice.
|
||||
|
||||
I trust that this action will prove unnecessary and details of due payments is printed below.
|
||||
|
||||
In case of any queries concerning this matter, do not hesitate to contact our accounting department at (+32).10.68.94.39.
|
||||
|
||||
Best Regards,
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
|
|
|
@ -1,58 +1,13 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data noupdate="1">
|
||||
|
||||
<record id="demo_followup1" model="account_followup.followup">
|
||||
<field name="name">Default Follow-up</field>
|
||||
<field name="company_id" ref="base.main_company"/>
|
||||
<field name="description">First letter after 15 net days, 30 net days and 45 days end of month levels.</field>
|
||||
</record>
|
||||
|
||||
<record id="demo_followup_line1" model="account_followup.followup.line">
|
||||
<field name="name">Level 0 : 15 net days</field>
|
||||
<field name="sequence">0</field>
|
||||
<field name="start">days</field>
|
||||
<field name="delay">15</field>
|
||||
<field name="followup_id" ref="demo_followup1"/>
|
||||
<field name="description">
|
||||
Dear %(partner_name)s,
|
||||
|
||||
Exception made if there was a mistake of ours, it seems that the following amount stays unpaid. Please, take appropriate measures in order to carry out this payment in the next 8 days.
|
||||
|
||||
Would your payment have been carried out after this mail was sent, please ignore this message. Do not hesitate to contact our accounting department at (+32).10.68.94.39.
|
||||
|
||||
Best Regards,
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="demo_followup_line2" model="account_followup.followup.line">
|
||||
<field name="name">Level 1 : 30 net days</field>
|
||||
<field name="sequence">1</field>
|
||||
<field name="start">days</field>
|
||||
<field name="delay">30</field>
|
||||
<field name="followup_id" ref="demo_followup1"/>
|
||||
<field name="description">
|
||||
Dear %(partner_name)s,
|
||||
|
||||
We are disappointed to see that despite sending a reminder, that your account is now seriously overdue.
|
||||
|
||||
It is essential that immediate payment is made, otherwise we will have to consider placing a stop on your account which means that we will no longer be able to supply your company with (goods/services).
|
||||
Please, take appropriate measures in order to carry out this payment in the next 8 days.
|
||||
|
||||
If there is a problem with paying invoice that we are not aware of, do not hesitate to contact our accounting department at (+32).10.68.94.39. so that we can resolve the matter quickly.
|
||||
|
||||
Details of due payments is printed below.
|
||||
|
||||
Best Regards,
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="demo_followup_line3" model="account_followup.followup.line">
|
||||
<field name="name">Level 2 : 45 days end of month</field>
|
||||
<field name="sequence">2</field>
|
||||
<field name="start">end_of_month</field>
|
||||
<field name="delay">45</field>
|
||||
<data noupdate="1">
|
||||
<record id="demo_followup_line4" model="account_followup.followup.line">
|
||||
<field name="name">Urging reminder email</field>
|
||||
<field name="sequence">4</field>
|
||||
<field name="delay">50</field>
|
||||
<field name="followup_id" ref="demo_followup1"/>
|
||||
<field name="send_email">True</field>
|
||||
<field name="email_template_id" ref="email_template_account_followup_level2"/>
|
||||
<field name="description">
|
||||
Dear %(partner_name)s,
|
||||
|
||||
|
@ -65,8 +20,29 @@ I trust that this action will prove unnecessary and details of due payments is p
|
|||
In case of any queries concerning this matter, do not hesitate to contact our accounting department at (+32).10.68.94.39.
|
||||
|
||||
Best Regards,
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
<record id="demo_followup_line5" model="account_followup.followup.line">
|
||||
<field name="name">Urging reminder letter</field>
|
||||
<field name="sequence">5</field>
|
||||
<field name="delay">60</field>
|
||||
<field name="followup_id" ref="demo_followup1"/>
|
||||
<field eval="False" name="send_email"/>
|
||||
<field name="send_letter">True</field>
|
||||
<field name="email_template_id" ref="email_template_account_followup_level2"/>
|
||||
<field name="description">
|
||||
Dear %(partner_name)s,
|
||||
|
||||
Despite several reminders, your account is still not settled.
|
||||
|
||||
Unless full payment is made in next 8 days, then legal action for the recovery of the debt will be taken without further notice.
|
||||
|
||||
I trust that this action will prove unnecessary and details of due payments is printed below.
|
||||
|
||||
In case of any queries concerning this matter, do not hesitate to contact our accounting department at (+32).10.68.94.39.
|
||||
|
||||
Best Regards,
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
<openerp>
|
||||
<data>
|
||||
|
||||
|
||||
<record id="view_account_followup_followup_line_tree" model="ir.ui.view">
|
||||
<field name="name">account_followup.followup.line.tree</field>
|
||||
<field name="model">account_followup.followup.line</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Follow-up Steps">
|
||||
<tree string="Follow-up Steps" >
|
||||
<field name="name"/>
|
||||
<field name="delay"/>
|
||||
<field name="start"/>
|
||||
<field name="send_email"/>
|
||||
<field name="send_letter"/>
|
||||
<field name="manual_action"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
@ -18,19 +20,47 @@
|
|||
<field name="model">account_followup.followup.line</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Follow-up Steps" version="7.0">
|
||||
<group col="4">
|
||||
<field name="name"/>
|
||||
<field name="delay"/>
|
||||
<field name="start"/>
|
||||
<label for="name" class="oe_edit_only"/>
|
||||
<h1><field name="name"/></h1>
|
||||
<div class="oe_inline">
|
||||
After <field name="delay" class="oe_inline"/> days overdue, do the following actions:
|
||||
</div>
|
||||
<div>
|
||||
<field name="manual_action" class="oe_inline"/>
|
||||
<label for="manual_action"/>
|
||||
</div><div>
|
||||
<field name="send_email" class="oe_inline"/>
|
||||
<label for="send_email"/>
|
||||
</div><div>
|
||||
<field name="send_letter" class="oe_inline"/>
|
||||
<label for="send_letter"/>
|
||||
</div>
|
||||
|
||||
<group string="Manual Action" attrs="{'invisible': [('manual_action', '=', False)]}">
|
||||
<field name="manual_action_responsible_id"/>
|
||||
<field name="manual_action_note" attrs="{'required': [('manual_action', '<>', False)]}"
|
||||
placeholder="e.g. Call the customer, check if it's paid, ..."/>
|
||||
</group>
|
||||
<separator string="Message"/>
|
||||
<field name="description"/>
|
||||
<separator string="Legend"/>
|
||||
<group>
|
||||
<label string="%%(partner_name)s: Partner Name"/>
|
||||
<label string="%%(date)s: Current Date"/>
|
||||
<label string="%%(user_signature)s: User Name"/>
|
||||
<label string="%%(company_name)s: User's Company Name"/>
|
||||
|
||||
<group string="Send an Email" attrs="{'invisible': [('send_email', '=', False)]}">
|
||||
<field name="email_template_id" attrs="{'required': [('send_email', '<>', False)]}"/>
|
||||
</group>
|
||||
|
||||
<group string="Send a Letter" attrs="{'invisible': [('send_letter', '=', False)]}">
|
||||
<p colspan="2" class="oe_grey">
|
||||
Write here the introduction in the letter,
|
||||
according to the level of the follow-up. You can
|
||||
use the following keywords in the text. Don't
|
||||
forget to translate in all languages you installed
|
||||
using to top right icon.
|
||||
<group class="oe_grey">
|
||||
<b>%%(partner_name)s</b>: Partner Name
|
||||
<b>%%(date)s</b>: Current Date
|
||||
<b>%%(user_signature)s</b>: User Name
|
||||
<b>%%(company_name)s</b>: User's Company Name
|
||||
</group>
|
||||
</p>
|
||||
<field name="description" nolabel="1" colspan="2"/>
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
|
@ -39,12 +69,18 @@
|
|||
<record id="view_account_followup_followup_form" model="ir.ui.view">
|
||||
<field name="name">account_followup.followup.form</field>
|
||||
<field name="model">account_followup.followup</field>
|
||||
<!-- <field name="group_ids" groups="base.group_multi_company"/>-->
|
||||
<field name="arch" type="xml">
|
||||
<form string="Follow-up" version="7.0">
|
||||
<group col="4">
|
||||
<field name="name"/>
|
||||
<field name="company_id" widget="selection" groups="base.group_multi_company"/>
|
||||
</group>
|
||||
<h1><field name="company_id" widget="selection" class="oe_inline"/></h1>
|
||||
<p class="oe_grey">
|
||||
To remind our customers of paying their invoices, we
|
||||
define different actions depending on how severely
|
||||
overdue the customer is. These actions are bundled
|
||||
into folow-up levels that are triggered when the due
|
||||
date of the most overdue invoice has passed a certain
|
||||
amount of days.
|
||||
</p>
|
||||
<field name="followup_line"/>
|
||||
</form>
|
||||
</field>
|
||||
|
@ -55,8 +91,7 @@
|
|||
<field name="model">account_followup.followup</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Follow-up">
|
||||
<field name="name"/>
|
||||
<field name="company_id" groups="base.group_multi_company"/>
|
||||
<field name="company_id" /> <!--groups="base.group_multi_company"-->
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
@ -66,31 +101,50 @@
|
|||
<field name="model">account_followup.followup</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Search Follow-up">
|
||||
<field name="name" string="Follow-up"/>
|
||||
<field name="company_id" groups="base.group_multi_company"/>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_account_followup_definition_form" model="ir.actions.act_window">
|
||||
<field name="name">Follow-ups</field>
|
||||
<field name="name">Payment Follow-ups</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">account_followup.followup</field>
|
||||
<field name="search_view_id" ref="view_account_followup_filter"/>
|
||||
<field name="view_type">form</field>
|
||||
<field name="help" type="html">
|
||||
<p class="oe_view_nocontent_create">
|
||||
Click to define follow-up levels and their related messages.
|
||||
Click to define follow-up levels and their related actions.
|
||||
</p><p>
|
||||
For each step, specify the message and the day of delay. Use
|
||||
the legend to know the using code to adapt the email content to
|
||||
the good context (good name, good date) and you can manage the
|
||||
multi language of messages.
|
||||
For each step, specify the actions to be taken and delay in days. It is
|
||||
possible to use print and e-mail templates to send specific messages to
|
||||
the customer.
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
<record id="action_account_manual_reconcile_receivable" model="ir.actions.act_window">
|
||||
<field name="name">Reconcile Invoices & Payments</field>
|
||||
<field name="search_view_id" ref="view_account_followup_filter"/>
|
||||
<field name="context">{'search_default_unreconciled': 1,'view_mode':True}</field>
|
||||
<field name="domain">[('account_id.type', '=', 'receivable')]</field>
|
||||
<field name="res_model">account.move.line</field>
|
||||
<field name="view_id" ref="account.view_move_line_tree_reconcile"/>
|
||||
<field name="view_mode">tree_account_reconciliation</field>
|
||||
<field name="help" type="html">
|
||||
<p>
|
||||
No journal items found.
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
<menuitem action="action_account_followup_definition_form" id="account_followup_menu" parent="account.menu_configuration_misc"/>
|
||||
|
||||
<menuitem
|
||||
name="Reconcile Invoices & Payments"
|
||||
action="action_account_manual_reconcile_receivable"
|
||||
parent="menu_finance_followup"
|
||||
sequence="0"
|
||||
id="menu_manual_reconcile_followup"/>
|
||||
|
||||
<menuitem action="action_account_followup_definition_form" id="account_followup_menu" parent="account.menu_finance_configuration" name="Follow-up Levels"/>
|
||||
<report auto="False" id="account_followup_followup_report" menu="False" model="account_followup.followup" name="account_followup.followup.print" rml="account_followup/report/account_followup_print.rml" string="Follow-up Report"/>
|
||||
|
||||
<record id="account_move_line_partner_tree" model="ir.ui.view">
|
||||
|
@ -139,25 +193,5 @@
|
|||
</field>
|
||||
</record> -->
|
||||
|
||||
<act_window domain="[('reconcile_id', '=', False),('account_id.type','=','receivable')]" id="act_account_partner_account_move_all" name="Receivable Items" res_model="account.move.line" src_model="" view_id="account_move_line_partner_tree"/>
|
||||
|
||||
<!--<menuitem action="act_account_partner_account_move_all" id="menu_account_move_open_unreconcile" parent="account_followup.menu_action_followup_stat"/> -->
|
||||
|
||||
<act_window domain="[('reconcile_id', '=', False), ('account_id.type','=','payable')]" id="act_account_partner_account_move_payable_all" name="Payable Items" res_model="account.move.line" src_model="" view_id="account_move_line_partner_tree"/>
|
||||
|
||||
<!-- <menuitem action="act_account_partner_account_move_payable_all" id="menu_account_move_open_unreconcile_payable" parent="account_followup.menu_action_followup_stat"/> -->
|
||||
|
||||
<record model="ir.ui.view" id="view_company_inherit_followup_form">
|
||||
<field name="name">res.company.followup.form.inherit</field>
|
||||
<field name="inherit_id" ref="account.view_company_inherit_form"/>
|
||||
<field name="model">res.company</field>
|
||||
<field name="arch" type="xml">
|
||||
<field name="overdue_msg" nolabel="1" colspan="4" position="after">
|
||||
<separator string="Follow-up Message" colspan="4"/>
|
||||
<field name="follow_up_msg" nolabel="1" colspan="4"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
|
|
|
@ -25,7 +25,7 @@ import pooler
|
|||
from report import report_sxw
|
||||
|
||||
class report_rappel(report_sxw.rml_parse):
|
||||
def __init__(self, cr, uid, name, context):
|
||||
def __init__(self, cr, uid, name, context=None):
|
||||
super(report_rappel, self).__init__(cr, uid, name, context=context)
|
||||
self.localcontext.update({
|
||||
'time': time,
|
||||
|
@ -43,14 +43,17 @@ class report_rappel(report_sxw.rml_parse):
|
|||
return all_lines
|
||||
|
||||
def _lines_get(self, stat_by_partner_line):
|
||||
return self._lines_get_with_partner(stat_by_partner_line.partner_id, stat_by_partner_line.company_id.id)
|
||||
|
||||
def _lines_get_with_partner(self, partner, company_id):
|
||||
pool = pooler.get_pool(self.cr.dbname)
|
||||
moveline_obj = pool.get('account.move.line')
|
||||
company_obj = pool.get('res.company')
|
||||
obj_currency = pool.get('res.currency')
|
||||
movelines = moveline_obj.search(self.cr, self.uid,
|
||||
[('partner_id', '=', stat_by_partner_line.partner_id.id),
|
||||
[('partner_id', '=', partner.id),
|
||||
('account_id.type', '=', 'receivable'),
|
||||
('reconcile_id', '=', False), ('state', '<>', 'draft'),('company_id','=', stat_by_partner_line.company_id.id)])
|
||||
('reconcile_id', '=', False), ('state', '<>', 'draft'),('company_id','=', company_id)])
|
||||
movelines = moveline_obj.browse(self.cr, self.uid, movelines)
|
||||
base_currency = movelines[0].company_id.currency_id
|
||||
final_res = []
|
||||
|
@ -67,7 +70,7 @@ class report_rappel(report_sxw.rml_parse):
|
|||
'date_maturity': line.date_maturity,
|
||||
'balance': currency.id <> line.company_id.currency_id.id and line.amount_currency or (line.debit - line.credit),
|
||||
'blocked': line.blocked,
|
||||
'currency_id': currency.symbol or currency.name,
|
||||
'currency_id': currency,
|
||||
}
|
||||
line_cur[currency.id]['line'].append(line_data)
|
||||
|
||||
|
@ -88,7 +91,7 @@ class report_rappel(report_sxw.rml_parse):
|
|||
li_delay.sort(reverse=True)
|
||||
text = ""
|
||||
a = {}
|
||||
partner_line_ids = pooler.get_pool(self.cr.dbname).get('account.move.line').search(self.cr, self.uid, [('partner_id','=',stat_line.partner_id.id),('reconcile_id','=',False),('company_id','=',stat_line.company_id.id)])
|
||||
partner_line_ids = pooler.get_pool(self.cr.dbname).get('account.move.line').search(self.cr, self.uid, [('partner_id','=',stat_line.partner_id.id),('reconcile_id','=',False),('company_id','=',stat_line.company_id.id),('blocked','=',False)])
|
||||
partner_delay = []
|
||||
context.update({'lang': stat_line.partner_id.lang})
|
||||
for i in pooler.get_pool(self.cr.dbname).get('account.move.line').browse(self.cr, self.uid, partner_line_ids, context):
|
||||
|
|
|
@ -194,7 +194,7 @@
|
|||
<para style="terp_default_Centre_9">[[ line['date_maturity'] and formatLang(line['date_maturity'], date=True) ]]</para>
|
||||
</td>
|
||||
<td>
|
||||
<para style="terp_default_Right_9">[[ formatLang(line['balance']) ]] [[ line['currency_id'] ]]</para>
|
||||
<para style="terp_default_Right_9">[[ formatLang(line['balance'], currency_obj=line['currency_id']) ]]</para>
|
||||
</td>
|
||||
<td>
|
||||
<para style="terp_default_Centre_9">[[ line['blocked'] and 'X' or '' ]]</para>
|
||||
|
@ -212,7 +212,7 @@
|
|||
<para style="terp_tblheader_Details_Centre">Total: </para>
|
||||
</td>
|
||||
<td>
|
||||
<para style="terp_default_Right_9">[[formatLang(reduce(lambda x,y: x+y['balance'], cur_lines['line'], 0.00)) ]] [[ line['currency_id'] ]] </para>
|
||||
<para style="terp_default_Right_9">[[formatLang(reduce(lambda x,y: x+y['balance'], cur_lines['line'], 0.00), currency_obj=line['currency_id']) ]] </para>
|
||||
</td>
|
||||
<td>
|
||||
<para style="terp_default_Right_9">
|
||||
|
|
|
@ -64,8 +64,8 @@
|
|||
<field name="context">{'search_default_followup_level':1}</field>
|
||||
<field name="search_view_id" ref="view_account_followup_stat_search"/>
|
||||
</record>
|
||||
|
||||
<menuitem action="action_followup_stat" id="menu_action_followup_stat_follow" parent="account.next_id_22" groups="account.group_account_user"/>
|
||||
<menuitem id="menu_finance_followup" parent="account.menu_finance" name="Payment Follow-up" groups="account.group_account_invoice"/>
|
||||
<menuitem action="action_followup_stat" id="menu_action_followup_stat_follow" parent="account.menu_finance_reporting" groups="account.group_account_invoice" name="Follow-Ups Analysis" sequence="10"/>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_account_followup_followup_line,account_followup.followup.line,model_account_followup_followup_line,account.group_account_user,1,0,0,0
|
||||
access_account_followup_followup_line_manager,account_followup.followup.line.manager,model_account_followup_followup_line,account.group_account_manager,1,1,1,1
|
||||
access_account_followup_followup_accountant,account_followup.followup user,model_account_followup_followup,account.group_account_user,1,0,0,0
|
||||
access_account_followup_followup_manager,account_followup.followup.manager,model_account_followup_followup,account.group_account_manager,1,1,1,1
|
||||
access_account_followup_stat_invoice,account_followup.stat.invoice,model_account_followup_stat,account.group_account_invoice,1,1,1,1
|
||||
access_account_followup_stat_by_partner_manager,account_followup.stat.by.partner,model_account_followup_stat_by_partner,account.group_account_manager,1,1,1,1
|
||||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_account_followup_followup_line,account_followup.followup.line,model_account_followup_followup_line,account.group_account_invoice,1,0,0,0
|
||||
access_account_followup_followup_line_manager,account_followup.followup.line.manager,model_account_followup_followup_line,account.group_account_manager,1,1,1,1
|
||||
access_account_followup_followup_accountant,account_followup.followup user,model_account_followup_followup,account.group_account_invoice,1,0,0,0
|
||||
access_account_followup_followup_manager,account_followup.followup.manager,model_account_followup_followup,account.group_account_manager,1,1,1,1
|
||||
access_account_followup_stat_invoice,account_followup.stat.invoice,model_account_followup_stat,account.group_account_invoice,1,1,1,1
|
||||
access_account_followup_stat_by_partner_manager,account_followup.stat.by.partner,model_account_followup_stat_by_partner,account.group_account_user,1,1,1,1
|
||||
|
|
|
|
@ -3,34 +3,23 @@
|
|||
-
|
||||
!record {model: account.invoice, id: account.demo_invoice_0}:
|
||||
check_total: 14.0
|
||||
-
|
||||
date_invoice: 2012-06-2
|
||||
invoice_line:
|
||||
- account_id : account.a_sale
|
||||
name: 'Test PC'
|
||||
quantity: 1.0
|
||||
journal_id: account.bank_journal
|
||||
partner_id: base.res_partner_12
|
||||
reference_type: none
|
||||
-
|
||||
!workflow {model: account.invoice, action: invoice_open, ref: account.demo_invoice_0}
|
||||
-
|
||||
I create a follow-up.
|
||||
-
|
||||
!record {model: account.followup.print, id: account_followup_print_0}:
|
||||
!record {model: account_followup.print, id: account_followup_print_0}:
|
||||
{}
|
||||
-
|
||||
I select the follow-up to send it to the partner.
|
||||
-
|
||||
!python {model: account.followup.print}: |
|
||||
self.do_continue(cr, uid, [ref("account_followup_print_0")], {"active_ids": [ref("account_followup.account_followup_print_menu")], "active_id": ref("account_followup.account_followup_print_menu"),
|
||||
})
|
||||
-
|
||||
I select partners whom I want to send follow-ups.
|
||||
-
|
||||
!record {model: account.followup.print.all, id: account_followup_print_all_0}:
|
||||
email_body: 'Date : %(date)s\n\nDear %(partner_name)s,\n\nPlease find in attachment
|
||||
a reminder of all your unpaid invoices, for a total amount due of:\n\n%(followup_amount).2f
|
||||
%(company_currency)s\n\nThanks,\n--\n%(user_signature)s\n%(company_name)s'
|
||||
email_subject: Invoices Reminder
|
||||
partner_ids:
|
||||
- base.res_partner_12
|
||||
partner_lang: 1
|
||||
-
|
||||
I send a follow-up mail to partner.
|
||||
-
|
||||
!python {model: account.followup.print.all}: |
|
||||
import time
|
||||
self.do_mail(cr, uid, [ref("account_followup_print_all_0")], {"active_ids": [ref("account_followup.account_followup_print_menu")], "date": time.strftime('%Y-%m-%d'), "followup_id": ref("account_followup.demo_followup1"), "active_id": ref("account_followup.account_followup_print_menu"),
|
||||
})
|
||||
-
|
||||
I will process follow-ups
|
||||
-
|
||||
!python {model: account_followup.print}: |
|
||||
self.do_process(cr, uid, [ref("account_followup_print_0")], {"active_ids": [ref("account_followup.account_followup_print_menu")], "active_id": ref("account_followup.account_followup_print_menu"),})
|
|
@ -1,10 +0,0 @@
|
|||
-
|
||||
In order to test the report I print follow-up report.
|
||||
-
|
||||
!python {model: account.followup.print.all}: |
|
||||
import time
|
||||
ctx = {'form_view_ref':'account_followup.view_account_followup_print_all', 'followup_id': ref('account_followup.demo_followup1'),'date': time.strftime('%Y-%m-%d'),'model': 'account_followup.followup','active_ids':[ref('account_followup_print_all_0')], 'company_id':ref('base.main_company')}
|
||||
data_dict = {'email_conf': 1}
|
||||
from tools import test_reports
|
||||
test_reports.try_report_action(cr, uid, 'action_account_followup_print_all', context=ctx, wiz_data=data_dict,wiz_buttons=["Print Follow-ups"], our_module='account_followup')
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Business Applications
|
||||
# Copyright (c) 2012-TODAY OpenERP S.A. <http://openerp.com>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
from . import test_account_followup
|
||||
|
||||
checks = [
|
||||
test_account_followup,
|
||||
]
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
|
@ -0,0 +1,159 @@
|
|||
|
||||
|
||||
import datetime
|
||||
|
||||
import tools
|
||||
from openerp.tests.common import TransactionCase
|
||||
|
||||
import netsvc
|
||||
|
||||
class TestAccountFollowup(TransactionCase):
|
||||
def setUp(self):
|
||||
""" setUp ***"""
|
||||
super(TestAccountFollowup, self).setUp()
|
||||
cr, uid = self.cr, self.uid
|
||||
|
||||
self.user = self.registry('res.users')
|
||||
self.user_id = self.user.browse(cr, uid, uid)
|
||||
self.partner = self.registry('res.partner')
|
||||
self.invoice = self.registry('account.invoice')
|
||||
self.invoice_line = self.registry('account.invoice.line')
|
||||
self.wizard = self.registry('account_followup.print')
|
||||
self.followup_id = self.registry('account_followup.followup')
|
||||
|
||||
self.partner_id = self.partner.create(cr, uid, {'name':'Test Company',
|
||||
'email':'test@localhost',
|
||||
'is_company': True,
|
||||
},
|
||||
context=None)
|
||||
self.followup_id = self.registry("ir.model.data").get_object_reference(cr, uid, "account_followup", "demo_followup1")[1]
|
||||
self.account_id = self.registry("ir.model.data").get_object_reference(cr, uid, "account", "a_recv")[1]
|
||||
self.journal_id = self.registry("ir.model.data").get_object_reference(cr, uid, "account", "bank_journal")[1]
|
||||
self.pay_account_id = self.registry("ir.model.data").get_object_reference(cr, uid, "account", "cash")[1]
|
||||
self.period_id = self.registry("ir.model.data").get_object_reference(cr, uid, "account", "period_10")[1]
|
||||
|
||||
self.first_followup_line_id = self.registry("ir.model.data").get_object_reference(cr, uid, "account_followup", "demo_followup_line1")[1]
|
||||
self.last_followup_line_id = self.registry("ir.model.data").get_object_reference(cr, uid, "account_followup", "demo_followup_line3")[1]
|
||||
self.product_id = self.registry("ir.model.data").get_object_reference(cr, uid, "product", "product_product_6")[1]
|
||||
self.invoice_id = self.invoice.create(cr, uid, {'partner_id': self.partner_id,
|
||||
'account_id': self.account_id,
|
||||
'journal_id': self.journal_id,
|
||||
'invoice_line': [(0, 0, {
|
||||
'name': "LCD Screen",
|
||||
'product_id': self.product_id,
|
||||
'quantity': 5,
|
||||
'price_unit':200
|
||||
})]})
|
||||
wf_service = netsvc.LocalService("workflow")
|
||||
wf_service.trg_validate(uid, 'account.invoice', self.invoice_id, 'invoice_open', cr)
|
||||
|
||||
self.voucher = self.registry("account.voucher")
|
||||
|
||||
|
||||
def test_00_send_followup_after_3_days(self):
|
||||
""" Send follow up after 3 days and check nothing is done (as first follow-up level is only after 15 days)"""
|
||||
cr, uid = self.cr, self.uid
|
||||
current_date = datetime.datetime.now()
|
||||
delta = datetime.timedelta(days=3)
|
||||
result = current_date + delta
|
||||
self.wizard_id = self.wizard.create(cr, uid, {'date':result.strftime("%Y-%m-%d"),
|
||||
'followup_id': self.followup_id
|
||||
}, context={"followup_id": self.followup_id})
|
||||
self.wizard.do_process(cr, uid, [self.wizard_id], context={"followup_id": self.followup_id})
|
||||
self.assertFalse(self.partner.browse(cr, uid, self.partner_id).latest_followup_level_id)
|
||||
|
||||
|
||||
def run_wizard_three_times(self):
|
||||
cr, uid = self.cr, self.uid
|
||||
current_date = datetime.datetime.now()
|
||||
delta = datetime.timedelta(days=40)
|
||||
result = current_date + delta
|
||||
self.wizard_id = self.wizard.create(cr, uid, {'date':result.strftime("%Y-%m-%d"),
|
||||
'followup_id': self.followup_id
|
||||
}, context={"followup_id": self.followup_id})
|
||||
self.wizard.do_process(cr, uid, [self.wizard_id], context={"followup_id": self.followup_id})
|
||||
self.wizard_id = self.wizard.create(cr, uid, {'date':result.strftime("%Y-%m-%d"),
|
||||
'followup_id': self.followup_id
|
||||
}, context={"followup_id": self.followup_id})
|
||||
self.wizard.do_process(cr, uid, [self.wizard_id], context={"followup_id": self.followup_id})
|
||||
self.wizard_id = self.wizard.create(cr, uid, {'date':result.strftime("%Y-%m-%d"),
|
||||
'followup_id': self.followup_id
|
||||
}, context={"followup_id": self.followup_id})
|
||||
self.wizard.do_process(cr, uid, [self.wizard_id], context={"followup_id": self.followup_id})
|
||||
|
||||
|
||||
def test_01_send_followup_later_for_upgrade(self):
|
||||
""" Send one follow-up after 15 days to check it upgrades to level 1"""
|
||||
cr, uid = self.cr, self.uid
|
||||
current_date = datetime.datetime.now()
|
||||
delta = datetime.timedelta(days=15)
|
||||
result = current_date + delta
|
||||
self.wizard_id = self.wizard.create(cr, uid, {
|
||||
'date':result.strftime("%Y-%m-%d"),
|
||||
'followup_id': self.followup_id
|
||||
}, context={"followup_id": self.followup_id})
|
||||
self.wizard.do_process(cr, uid, [self.wizard_id], context={"followup_id": self.followup_id})
|
||||
self.assertEqual(self.partner.browse(cr, uid, self.partner_id).latest_followup_level_id.id, self.first_followup_line_id,
|
||||
"Not updated to the correct follow-up level")
|
||||
|
||||
def test_02_check_manual_action(self):
|
||||
""" Check that when running the wizard three times that the manual action is set"""
|
||||
cr, uid = self.cr, self.uid
|
||||
self.run_wizard_three_times()
|
||||
self.assertEqual(self.partner.browse(cr, uid, self.partner_id).payment_next_action,
|
||||
"Call the customer on the phone! ", "Manual action not set")
|
||||
self.assertEqual(self.partner.browse(cr, uid, self.partner_id).payment_next_action_date,
|
||||
datetime.datetime.now().strftime("%Y-%m-%d"))
|
||||
|
||||
def test_03_filter_on_credit(self):
|
||||
""" Check the partners can be filtered on having credits """
|
||||
cr, uid = self.cr, self.uid
|
||||
ids = self.partner.search(cr, uid, [('credit', '>=', 0.0)])
|
||||
self.assertIn(self.partner_id, ids)
|
||||
|
||||
def test_04_action_done(self):
|
||||
""" Run the wizard 3 times, mark it as done, check the action fields are empty"""
|
||||
cr, uid = self.cr, self.uid
|
||||
partner_rec = self.partner.browse(cr, uid, self.partner_id)
|
||||
self.run_wizard_three_times()
|
||||
self.partner.action_done(cr, uid, self.partner_id)
|
||||
self.assertEqual(partner_rec.payment_next_action,
|
||||
"", "Manual action not emptied")
|
||||
self.assertFalse(partner_rec.payment_responsible_id)
|
||||
self.assertFalse(partner_rec.payment_next_action_date)
|
||||
|
||||
def test_05_litigation(self):
|
||||
""" Set the account move line as litigation, run the wizard 3 times and check nothing happened.
|
||||
Turn litigation off. Run the wizard 3 times and check it is in the right follow-up level.
|
||||
"""
|
||||
cr, uid = self.cr, self.uid
|
||||
aml_id = self.partner.browse(cr, uid, self.partner_id).unreconciled_aml_ids[0].id
|
||||
self.registry('account.move.line').write(cr, uid, aml_id, {'blocked': True})
|
||||
self.run_wizard_three_times()
|
||||
self.assertFalse(self.partner.browse(cr, uid, self.partner_id).latest_followup_level_id, "Litigation does not work")
|
||||
self.registry('account.move.line').write(cr, uid, aml_id, {'blocked': False})
|
||||
self.run_wizard_three_times()
|
||||
self.assertEqual(self.partner.browse(cr, uid, self.partner_id).latest_followup_level_id.id,
|
||||
self.last_followup_line_id, "Lines are not equal")
|
||||
|
||||
def test_06_pay_the_invoice(self):
|
||||
"""Run wizard until manual action, pay the invoice and check that partner has no follow-up level anymore and after running the wizard the action is empty"""
|
||||
cr, uid = self.cr, self.uid
|
||||
self.test_02_check_manual_action()
|
||||
current_date = datetime.datetime.now()
|
||||
delta = datetime.timedelta(days=1)
|
||||
result = current_date + delta
|
||||
self.invoice.pay_and_reconcile(cr, uid, [self.invoice_id], 1000.0, self.pay_account_id,
|
||||
self.period_id, self.journal_id, self.pay_account_id,
|
||||
self.period_id, self.journal_id,
|
||||
name = "Payment for test customer invoice follow-up")
|
||||
self.assertFalse(self.partner.browse(cr, uid, self.partner_id).latest_followup_level_id, "Level not empty")
|
||||
self.wizard_id = self.wizard.create(cr, uid, {'date':result.strftime("%Y-%m-%d"),
|
||||
'followup_id': self.followup_id
|
||||
}, context={"followup_id": self.followup_id})
|
||||
self.wizard.do_process(cr, uid, [self.wizard_id], context={"followup_id": self.followup_id})
|
||||
partner_ref = self.partner.browse(cr, uid, self.partner_id)
|
||||
print partner_ref.credit, partner_ref.payment_next_action_date, partner_ref.payment_responsible_id
|
||||
self.assertEqual(0, self.partner.browse(cr, uid, self.partner_id).credit, "Credit != 0")
|
||||
self.assertFalse(self.partner.browse(cr, uid, self.partner_id).payment_next_action_date, "Next action date not cleared")
|
||||
|
|
@ -26,49 +26,6 @@ import tools
|
|||
from osv import fields, osv
|
||||
from tools.translate import _
|
||||
|
||||
class account_followup_print(osv.osv_memory):
|
||||
_name = 'account.followup.print'
|
||||
_description = 'Print Follow-up & Send Mail to Customers'
|
||||
_columns = {
|
||||
'date': fields.date('Follow-up Sending Date', required=True, help="This field allow you to select a forecast date to plan your follow-ups"),
|
||||
'followup_id': fields.many2one('account_followup.followup', 'Follow-Up', required=True),
|
||||
}
|
||||
|
||||
def _get_followup(self, cr, uid, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
if context.get('active_model', 'ir.ui.menu') == 'account_followup.followup':
|
||||
return context.get('active_id', False)
|
||||
company_id = self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id.id
|
||||
followp_id = self.pool.get('account_followup.followup').search(cr, uid, [('company_id', '=', company_id)], context=context)
|
||||
return followp_id and followp_id[0] or False
|
||||
|
||||
def do_continue(self, cr, uid, ids, context=None):
|
||||
mod_obj = self.pool.get('ir.model.data')
|
||||
|
||||
if context is None:
|
||||
context = {}
|
||||
data = self.browse(cr, uid, ids, context=context)[0]
|
||||
model_data_ids = mod_obj.search(cr, uid, [('model','=','ir.ui.view'),('name','=','view_account_followup_print_all')], context=context)
|
||||
resource_id = mod_obj.read(cr, uid, model_data_ids, fields=['res_id'], context=context)[0]['res_id']
|
||||
context.update({'followup_id': data.followup_id.id, 'date': data.date, 'company_id': data.followup_id.company_id.id})
|
||||
return {
|
||||
'name': _('Select Partners'),
|
||||
'view_type': 'form',
|
||||
'context': context,
|
||||
'view_mode': 'tree,form',
|
||||
'res_model': 'account.followup.print.all',
|
||||
'views': [(resource_id,'form')],
|
||||
'type': 'ir.actions.act_window',
|
||||
'target': 'new',
|
||||
}
|
||||
|
||||
_defaults = {
|
||||
'date': lambda *a: time.strftime('%Y-%m-%d'),
|
||||
'followup_id': _get_followup,
|
||||
}
|
||||
account_followup_print()
|
||||
|
||||
class account_followup_stat_by_partner(osv.osv):
|
||||
_name = "account_followup.stat.by.partner"
|
||||
_description = "Follow-up Statistics by Partner"
|
||||
|
@ -110,50 +67,201 @@ class account_followup_stat_by_partner(osv.osv):
|
|||
a.active AND
|
||||
a.type = 'receivable' AND
|
||||
l.reconcile_id is NULL AND
|
||||
l.partner_id IS NOT NULL
|
||||
l.partner_id IS NOT NULL AND
|
||||
(l.blocked = False)
|
||||
GROUP BY
|
||||
l.partner_id, l.company_id
|
||||
)""")
|
||||
)""") #Blocked is to take into account litigation
|
||||
account_followup_stat_by_partner()
|
||||
|
||||
class account_followup_print_all(osv.osv_memory):
|
||||
_name = 'account.followup.print.all'
|
||||
_description = 'Print Follow-up & Send Mail to Customers'
|
||||
_columns = {
|
||||
'partner_ids': fields.many2many('account_followup.stat.by.partner', 'partner_stat_rel', 'osv_memory_id', 'partner_id', 'Partners', required=True),
|
||||
'email_conf': fields.boolean('Send Email Confirmation'),
|
||||
'email_subject': fields.char('Email Subject', size=64),
|
||||
'partner_lang': fields.boolean('Send Email in Partner Language', help='Do not change message text, if you want to send email in partner language, or configure from company'),
|
||||
'email_body': fields.text('Email Body'),
|
||||
'summary': fields.text('Summary', required=True, readonly=True),
|
||||
'test_print': fields.boolean('Test Print', help='Check if you want to print follow-ups without changing follow-ups level.')
|
||||
}
|
||||
def _get_summary(self, cr, uid, context=None):
|
||||
|
||||
class account_followup_sending_results(osv.osv_memory):
|
||||
|
||||
def do_report(self, cr, uid, ids, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
return context.get('summary', '')
|
||||
return context.get('report_data')
|
||||
|
||||
def _get_partners(self, cr, uid, context=None):
|
||||
return self._get_partners_followp(cr, uid, [], context=context)['partner_ids']
|
||||
def do_done(self, cr, uid, ids, context=None):
|
||||
return {}
|
||||
|
||||
def _get_description(self, cr, uid, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
return context.get('description')
|
||||
|
||||
def _get_need_printing(self, cr, uid, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
return context.get('needprinting')
|
||||
|
||||
_name = 'account_followup.sending.results'
|
||||
_description = 'Results from the sending of the different letters and emails'
|
||||
_columns = {
|
||||
'description': fields.text("Description", readonly=True),
|
||||
'needprinting': fields.boolean("Needs Printing")
|
||||
}
|
||||
_defaults = {
|
||||
'needprinting':_get_need_printing,
|
||||
'description':_get_description,
|
||||
}
|
||||
|
||||
account_followup_sending_results()
|
||||
|
||||
|
||||
class account_followup_print(osv.osv_memory):
|
||||
_name = 'account_followup.print'
|
||||
_description = 'Print Follow-up & Send Mail to Customers'
|
||||
_columns = {
|
||||
'date': fields.date('Follow-up Sending Date', required=True,
|
||||
help="This field allow you to select a forecast date to plan your follow-ups"),
|
||||
'followup_id': fields.many2one('account_followup.followup', 'Follow-Up', required=True, readonly = True),
|
||||
'partner_ids': fields.many2many('account_followup.stat.by.partner', 'partner_stat_rel',
|
||||
'osv_memory_id', 'partner_id', 'Partners', required=True),
|
||||
'company_id':fields.related('followup_id', 'company_id', type='many2one',
|
||||
relation='res.company', store=True, readonly=True),
|
||||
'email_conf': fields.boolean('Send Email Confirmation'),
|
||||
'email_subject': fields.char('Email Subject', size=64),
|
||||
'partner_lang': fields.boolean('Send Email in Partner Language',
|
||||
help='Do not change message text, if you want to send email in partner language, or configure from company'),
|
||||
'email_body': fields.text('Email Body'),
|
||||
'summary': fields.text('Summary', readonly=True),
|
||||
'test_print': fields.boolean('Test Print',
|
||||
help='Check if you want to print follow-ups without changing follow-ups level.'),
|
||||
}
|
||||
|
||||
def _get_followup(self, cr, uid, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
if context.get('active_model', 'ir.ui.menu') == 'account_followup.followup':
|
||||
return context.get('active_id', False)
|
||||
company_id = self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id.id
|
||||
followp_id = self.pool.get('account_followup.followup').search(cr, uid, [('company_id', '=', company_id)], context=context)
|
||||
return followp_id and followp_id[0] or False
|
||||
|
||||
def process_partners(self, cr, uid, partner_ids, data, context=None):
|
||||
partner_obj = self.pool.get('res.partner')
|
||||
partner_ids_to_print = []
|
||||
nbmanuals = 0
|
||||
manuals = {}
|
||||
nbmails = 0
|
||||
nbunknownmails = 0
|
||||
nbprints = 0
|
||||
resulttext = " "
|
||||
for partner in self.pool.get('account_followup.stat.by.partner').browse(cr, uid, partner_ids, context=context):
|
||||
if partner.max_followup_id.manual_action:
|
||||
partner_obj.do_partner_manual_action(cr, uid, [partner.partner_id.id], context=context)
|
||||
nbmanuals = nbmanuals + 1
|
||||
key = partner.partner_id.payment_responsible_id.name or _("Nobody")
|
||||
if not key in manuals.keys():
|
||||
manuals[key]= 1
|
||||
else:
|
||||
manuals[key] = manuals[key] + 1
|
||||
if partner.max_followup_id.send_email:
|
||||
nbunknownmails += partner_obj.do_partner_mail(cr, uid, [partner.partner_id.id], context=context)
|
||||
nbmails += 1
|
||||
if partner.max_followup_id.send_letter:
|
||||
partner_ids_to_print.append(partner.id)
|
||||
nbprints += 1
|
||||
message = _("Follow-up letter of ") + "<I> " + partner.partner_id.latest_followup_level_id_without_lit.name + "</I>" + _(" will be sent")
|
||||
partner_obj.message_post(cr, uid, [partner.partner_id.id], body=message, context=context)
|
||||
if nbunknownmails == 0:
|
||||
resulttext += str(nbmails) + _(" email(s) sent")
|
||||
else:
|
||||
resulttext += str(nbmails) + _(" email(s) should have been sent, but ") + str(nbunknownmails) + _(" had unknown email address(es)") + "\n <BR/> "
|
||||
resulttext += "<BR/>" + str(nbprints) + _(" letter(s) in report") + " \n <BR/>" + str(nbmanuals) + _(" manual action(s) assigned:")
|
||||
needprinting = False
|
||||
if nbprints > 0:
|
||||
needprinting = True
|
||||
resulttext += "<p align=\"center\">"
|
||||
for item in manuals:
|
||||
resulttext = resulttext + "<li>" + item + ":" + str(manuals[item]) + "\n </li>"
|
||||
resulttext += "</p>"
|
||||
result = {}
|
||||
action = partner_obj.do_partner_print(cr, uid, partner_ids_to_print, data, context=context)
|
||||
result['needprinting'] = needprinting
|
||||
result['resulttext'] = resulttext
|
||||
result['action'] = action or {}
|
||||
return result
|
||||
|
||||
def do_update_followup_level(self, cr, uid, to_update, partner_list, date, context=None):
|
||||
#update the follow-up level on account.move.line
|
||||
for id in to_update.keys():
|
||||
if to_update[id]['partner_id'] in partner_list:
|
||||
self.pool.get('account.move.line').write(cr, uid, [int(id)], {'followup_line_id': to_update[id]['level'],
|
||||
'followup_date': date})
|
||||
|
||||
def clear_manual_actions(self, cr, uid, partner_list, context=None):
|
||||
# Partnerlist is list to exclude
|
||||
# Will clear the actions of partners that have no due payments anymore
|
||||
partner_list_ids = [partner.partner_id.id for partner in self.pool.get('account_followup.stat.by.partner').browse(cr, uid, partner_list, context=context)]
|
||||
ids = self.pool.get('res.partner').search(cr, uid, ['&', ('id', 'not in', partner_list_ids), '|',
|
||||
('payment_responsible_id', '!=', False),
|
||||
('payment_next_action_date', '!=', False)], context=context)
|
||||
partners = self.pool.get('res.partner').browse(cr, uid, ids, context=context)
|
||||
newids = []
|
||||
for part in partners:
|
||||
credit = 0
|
||||
for aml in part.unreconciled_aml_ids:
|
||||
credit +=aml.result
|
||||
if credit <= 0:
|
||||
newids.append(part.id)
|
||||
self.pool.get('res.partner').action_done(cr, uid, newids, context=context)
|
||||
return len(ids)
|
||||
|
||||
def do_process(self, cr, uid, ids, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
|
||||
#Get partners
|
||||
tmp = self._get_partners_followp(cr, uid, ids, context=context)
|
||||
partner_list = tmp['partner_ids']
|
||||
to_update = tmp['to_update']
|
||||
date = self.browse(cr, uid, ids, context=context)[0].date
|
||||
data = self.read(cr, uid, ids, [], context=context)[0]
|
||||
data['followup_id'] = data['followup_id'][0]
|
||||
|
||||
#Update partners
|
||||
self.do_update_followup_level(cr, uid, to_update, partner_list, date, context=context)
|
||||
#process the partners (send mails...)
|
||||
restot = self.process_partners(cr, uid, partner_list, data, context=context)
|
||||
#clear the manual actions if nothing is due anymore
|
||||
nbactionscleared = self.clear_manual_actions(cr, uid, partner_list, context=context)
|
||||
if nbactionscleared > 0:
|
||||
restot['resulttext'] = restot['resulttext'] + "<li>" + _("%s partners have no credits and as such the action is cleared") %(str(nbactionscleared)) + "</li>"
|
||||
res = restot['action']
|
||||
|
||||
#return the next action
|
||||
mod_obj = self.pool.get('ir.model.data')
|
||||
model_data_ids = mod_obj.search(cr, uid, [('model','=','ir.ui.view'),('name','=','view_account_followup_sending_results')], context=context)
|
||||
resource_id = mod_obj.read(cr, uid, model_data_ids, fields=['res_id'], context=context)[0]['res_id']
|
||||
context.update({'description': restot['resulttext'], 'needprinting': restot['needprinting'], 'report_data': res})
|
||||
return {
|
||||
'name': _('Send Letters and Emails: Actions Summary'),
|
||||
'view_type': 'form',
|
||||
'context': context,
|
||||
'view_mode': 'tree,form',
|
||||
'res_model': 'account_followup.sending.results',
|
||||
'views': [(resource_id,'form')],
|
||||
'type': 'ir.actions.act_window',
|
||||
'target': 'new',
|
||||
}
|
||||
|
||||
def _get_msg(self, cr, uid, context=None):
|
||||
return self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id.follow_up_msg
|
||||
|
||||
_defaults = {
|
||||
'email_body': _get_msg,
|
||||
'email_subject': _('Invoices Reminder'),
|
||||
'partner_lang': True,
|
||||
'partner_ids': _get_partners,
|
||||
'summary': _get_summary,
|
||||
'date': lambda *a: time.strftime('%Y-%m-%d'),
|
||||
'followup_id': _get_followup,
|
||||
'email_body': "",
|
||||
'email_subject': _('Invoices Reminder'),
|
||||
'partner_lang': True,
|
||||
}
|
||||
|
||||
def _get_partners_followp(self, cr, uid, ids, context=None):
|
||||
data = {}
|
||||
if context is None:
|
||||
context = {}
|
||||
if ids:
|
||||
data = self.browse(cr, uid, ids, context=context)[0]
|
||||
company_id = 'company_id' in context and context['company_id'] or data.company_id.id
|
||||
data = self.browse(cr, uid, ids, context=context)[0]
|
||||
company_id = data.company_id.id
|
||||
|
||||
cr.execute(
|
||||
"SELECT l.partner_id, l.followup_line_id,l.date_maturity, l.date, l.id "\
|
||||
|
@ -166,8 +274,9 @@ class account_followup_print_all(osv.osv_memory):
|
|||
"AND (l.partner_id is NOT NULL) "\
|
||||
"AND (a.active) "\
|
||||
"AND (l.debit > 0) "\
|
||||
"AND (l.company_id = %s) "\
|
||||
"ORDER BY l.date", (company_id,))
|
||||
"AND (l.company_id = %s) " \
|
||||
"AND (l.blocked = False)" \
|
||||
"ORDER BY l.date", (company_id,)) #l.blocked added to take litigation into account and it is not necessary to change follow-up level of account move lines without debit
|
||||
move_lines = cr.fetchall()
|
||||
old = None
|
||||
fups = {}
|
||||
|
@ -181,17 +290,17 @@ class account_followup_print_all(osv.osv_memory):
|
|||
"FROM account_followup_followup_line "\
|
||||
"WHERE followup_id=%s "\
|
||||
"ORDER BY delay", (fup_id,))
|
||||
|
||||
#Create dictionary of tuples where first element is the date to compare with the due date and second element is the id of the next level
|
||||
for result in cr.dictfetchall():
|
||||
delay = datetime.timedelta(days=result['delay'])
|
||||
fups[old] = (current_date - delay, result['id'])
|
||||
if result['start'] == 'end_of_month':
|
||||
fups[old][0].replace(day=1)
|
||||
old = result['id']
|
||||
|
||||
fups[old] = (datetime.date(datetime.MAXYEAR, 12, 31), old)
|
||||
|
||||
partner_list = []
|
||||
to_update = {}
|
||||
|
||||
#Fill dictionary of accountmovelines to_update with the partners that need to be updated
|
||||
for partner_id, followup_line_id, date_maturity,date, id in move_lines:
|
||||
if not partner_id:
|
||||
continue
|
||||
|
@ -209,134 +318,6 @@ class account_followup_print_all(osv.osv_memory):
|
|||
to_update[str(id)]= {'level': fups[followup_line_id][1], 'partner_id': stat_line_id}
|
||||
return {'partner_ids': partner_list, 'to_update': to_update}
|
||||
|
||||
def do_mail(self, cr, uid, ids, context=None):
|
||||
mod_obj = self.pool.get('ir.model.data')
|
||||
move_obj = self.pool.get('account.move.line')
|
||||
user_obj = self.pool.get('res.users')
|
||||
|
||||
if context is None:
|
||||
context = {}
|
||||
data = self.browse(cr, uid, ids, context=context)[0]
|
||||
stat_by_partner_line_ids = [partner_id.id for partner_id in data.partner_ids]
|
||||
partners = [stat_by_partner_line / 10000 for stat_by_partner_line in stat_by_partner_line_ids]
|
||||
model_data_ids = mod_obj.search(cr, uid, [('model','=','ir.ui.view'),('name','=','view_account_followup_print_all_msg')], context=context)
|
||||
resource_id = mod_obj.read(cr, uid, model_data_ids, fields=['res_id'], context=context)[0]['res_id']
|
||||
if data.email_conf:
|
||||
msg_sent = ''
|
||||
msg_unsent = ''
|
||||
data_user = user_obj.browse(cr, uid, uid, context=context)
|
||||
for partner in self.pool.get('res.partner').browse(cr, uid, partners, context=context):
|
||||
ids_lines = move_obj.search(cr,uid,[('partner_id','=',partner.id),('reconcile_id','=',False),('account_id.type','in',['receivable']),('company_id','=',context.get('company_id', False))])
|
||||
data_lines = move_obj.browse(cr, uid, ids_lines, context=context)
|
||||
total_amt = 0.0
|
||||
for line in data_lines:
|
||||
total_amt += line.debit - line.credit
|
||||
dest = False
|
||||
if partner:
|
||||
dest = [partner.email]
|
||||
if not data.partner_lang:
|
||||
body = data.email_body
|
||||
else:
|
||||
cxt = context.copy()
|
||||
cxt['lang'] = partner.lang
|
||||
body = user_obj.browse(cr, uid, uid, context=cxt).company_id.follow_up_msg
|
||||
move_line = ''
|
||||
subtotal_due = 0.0
|
||||
subtotal_paid = 0.0
|
||||
subtotal_maturity = 0.0
|
||||
balance = 0.0
|
||||
l = '--------------------------------------------------------------------------------------------------------------------------'
|
||||
head = l+ '\n' + 'Date'.rjust(10) + '\t' + 'Description'.rjust(10) + '\t' + 'Ref'.rjust(10) + '\t' + 'Due date'.rjust(10) + '\t' + 'Due'.rjust(10) + '\t' + 'Paid'.rjust(10) + '\t' + 'Maturity'.rjust(10) + '\t' + 'Litigation'.rjust(10) + '\n' + l
|
||||
for i in data_lines:
|
||||
maturity = 0.00
|
||||
if i.date_maturity < time.strftime('%Y-%m-%d') and (i.debit - i.credit):
|
||||
maturity = i.debit - i.credit
|
||||
subtotal_due = subtotal_due + i.debit
|
||||
subtotal_paid = subtotal_paid + i.credit
|
||||
subtotal_maturity = subtotal_maturity + int(maturity)
|
||||
balance = balance + (i.debit - i.credit)
|
||||
move_line = move_line + (i.date).rjust(10) + '\t'+ (i.name).rjust(10) + '\t'+ (i.ref or '').rjust(10) + '\t' + (i.date_maturity or '').rjust(10) + '\t' + str(i.debit).rjust(10) + '\t' + str(i.credit).rjust(10) + '\t' + str(maturity).rjust(10) + '\t' + str(i.blocked).rjust(10) + '\n'
|
||||
move_line = move_line + l + '\n'+ '\t\t\t' + 'Sub total'.rjust(35) + '\t' + (str(subtotal_due) or '').rjust(10) + '\t' + (str(subtotal_paid) or '').rjust(10) + '\t' + (str(subtotal_maturity) or '').rjust(10)+ '\n'
|
||||
move_line = move_line + '\t\t\t' + 'Balance'.rjust(33) + '\t' + str(balance).rjust(10) + '\n' + l
|
||||
val = {
|
||||
'partner_name':partner.name,
|
||||
'followup_amount':total_amt,
|
||||
'user_signature':data_user.name,
|
||||
'company_name':data_user.company_id.name,
|
||||
'company_currency':data_user.company_id.currency_id.name,
|
||||
'line':move_line,
|
||||
'heading': head,
|
||||
'date':time.strftime('%Y-%m-%d'),
|
||||
}
|
||||
body = body%val
|
||||
sub = tools.ustr(data.email_subject)
|
||||
msg = ''
|
||||
if dest:
|
||||
try:
|
||||
vals = {'state': 'outgoing',
|
||||
'subject': sub,
|
||||
'body_html': '<pre>%s</pre>' % body,
|
||||
'email_to': dest,
|
||||
'email_from': data_user.email or tools.config.options['email_from']}
|
||||
self.pool.get('mail.mail').create(cr, uid, vals, context=context)
|
||||
msg_sent += partner.name + '\n'
|
||||
except Exception, e:
|
||||
raise osv.except_osv('Error !', e )
|
||||
else:
|
||||
msg += partner.name + '\n'
|
||||
msg_unsent += msg
|
||||
if not msg_unsent:
|
||||
summary = _("All Emails have been successfully sent to Partners:.\n\n%s") % msg_sent
|
||||
else:
|
||||
msg_unsent = _("Email not sent to following Partners, Email not available !\n\n%s") % msg_unsent
|
||||
msg_sent = msg_sent and _("\n\nEmail sent to following Partners successfully. !\n\n%s") % msg_sent
|
||||
line = '=========================================================================='
|
||||
summary = msg_unsent + line + msg_sent
|
||||
context.update({'summary': summary})
|
||||
else:
|
||||
context.update({'summary': '\n\n\nEmail has not been sent to any partner. If you want to send it, please tick send email confirmation on wizard.'})
|
||||
|
||||
return {
|
||||
'name': _('Followup Summary'),
|
||||
'view_type': 'form',
|
||||
'context': context,
|
||||
'view_mode': 'tree,form',
|
||||
'res_model': 'account.followup.print.all',
|
||||
'views': [(resource_id,'form')],
|
||||
'type': 'ir.actions.act_window',
|
||||
'target': 'new',
|
||||
'nodestroy': True
|
||||
}
|
||||
|
||||
def do_print(self, cr, uid, ids, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
data = self.read(cr, uid, ids, [], context=context)[0]
|
||||
res = self._get_partners_followp(cr, uid, ids, context)['to_update']
|
||||
to_update = res
|
||||
data['followup_id'] = 'followup_id' in context and context['followup_id'] or False
|
||||
date = 'date' in context and context['date'] or data['date']
|
||||
if not data['test_print']:
|
||||
for id in to_update.keys():
|
||||
if to_update[id]['partner_id'] in data['partner_ids']:
|
||||
cr.execute(
|
||||
"UPDATE account_move_line "\
|
||||
"SET followup_line_id=%s, followup_date=%s "\
|
||||
"WHERE id=%s",
|
||||
(to_update[id]['level'],
|
||||
date, int(id),))
|
||||
data.update({'date': context['date']})
|
||||
datas = {
|
||||
'ids': [],
|
||||
'model': 'account_followup.followup',
|
||||
'form': data
|
||||
}
|
||||
return {
|
||||
'type': 'ir.actions.report.xml',
|
||||
'report_name': 'account_followup.followup.print',
|
||||
'datas': datas,
|
||||
}
|
||||
|
||||
account_followup_print_all()
|
||||
account_followup_print()
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
|
@ -4,25 +4,30 @@
|
|||
|
||||
<record id="view_account_followup_print" model="ir.ui.view">
|
||||
<field name="name">account.followup.print.form</field>
|
||||
<field name="model">account.followup.print</field>
|
||||
<field name="model">account_followup.print</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Send follow-ups" version="7.0">
|
||||
<group col="4">
|
||||
<field name="followup_id"/>
|
||||
<field name="date"/>
|
||||
<field name="followup_id" groups="base.group_multi_company"/>
|
||||
<field name="date" groups="base.group_no_one"/>
|
||||
</group>
|
||||
<footer>
|
||||
<button name="do_continue" string="Continue" type="object" class="oe_highlight"/>
|
||||
or
|
||||
<button string="Cancel" class="oe_link" special="cancel"/>
|
||||
</footer>
|
||||
<p class ="oe_grey">
|
||||
When you hit the button below, for every partner the most overdue invoice (without litigation) is checked.
|
||||
If the amount of days overdue is greater or equal than the amount of days specified by a next follow-up level,
|
||||
it will be updated to that next level and the actions of that level will be executed. (See Configuration > Follow-up Levels)
|
||||
</p>
|
||||
<footer>
|
||||
<button name="do_process" string="Send emails and generate letters" type="object" class="oe_highlight"/>
|
||||
or
|
||||
<button string="Cancel" class="oe_link" special="cancel"/>
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_account_followup_print" model="ir.actions.act_window">
|
||||
<field name="name">Send Follow-Ups</field>
|
||||
<field name="res_model">account.followup.print</field>
|
||||
<field name="res_model">account_followup.print</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="target">new</field>
|
||||
|
@ -30,8 +35,10 @@
|
|||
|
||||
<menuitem action="action_account_followup_print"
|
||||
id="account_followup_print_menu"
|
||||
parent="account.menu_finance_periodical_processing_billing"
|
||||
sequence="10"/>
|
||||
parent="menu_finance_followup"
|
||||
name = "Send Letters and Emails"
|
||||
groups = "account.group_account_user"
|
||||
sequence="2"/>
|
||||
|
||||
<record id="account_followup_stat_by_partner_search" model="ir.ui.view">
|
||||
<field name="name">account_followup.stat.by.partner.search</field>
|
||||
|
@ -47,7 +54,6 @@
|
|||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Screen2 -->
|
||||
<record id="account_followup_stat_by_partner_tree" model="ir.ui.view">
|
||||
<field name="name">account_followup.stat.by.partner.tree</field>
|
||||
<field name="model">account_followup.stat.by.partner</field>
|
||||
|
@ -63,63 +69,25 @@
|
|||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_account_followup_print_all" model="ir.ui.view">
|
||||
<field name="name">account.followup.print.all.form</field>
|
||||
<field name="model">account.followup.print.all</field>
|
||||
<record id="view_account_followup_sending_results" model="ir.ui.view">
|
||||
<field name="name">account_followup.sending.results.form</field>
|
||||
<field name="model">account_followup.sending.results</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Send Follow-Ups" version="7.0">
|
||||
<form string="Summary of actions" version="7.0">
|
||||
<header>
|
||||
<button name="do_mail" string="Send Mails" type="object" class="oe_highlight"/>
|
||||
<button name="do_print" string="Print Follow Ups" type="object" class="oe_highlight"/>
|
||||
or
|
||||
<button string="Cancel" class="oe_link" special="cancel"/>
|
||||
<field name="description" widget="html" class="oe_view_only"/>
|
||||
</header>
|
||||
<notebook>
|
||||
<page string="Partner Selection">
|
||||
<field name="partner_ids" context="{'search_default_balance_positive': 1}" domain="[('company_id','=',context.get('company_id',False))]"/>
|
||||
</page>
|
||||
<page string="Email Settings">
|
||||
<group col="4">
|
||||
<field name="email_conf" colspan="4"/>
|
||||
<field name="partner_lang" colspan="4"/>
|
||||
<field name="test_print" colspan="4"/>
|
||||
<field name="email_subject" colspan="4"/>
|
||||
<field name="email_body" colspan="4" nolabel="1"/>
|
||||
</group>
|
||||
<group string="Legend">
|
||||
<label string="%%(partner_name)s: Partner name"/>
|
||||
<label string="%%(user_signature)s: User name"/>
|
||||
<label string="%%(followup_amount)s: Total Amount Due"/>
|
||||
<label string="%%(date)s: Current Date"/>
|
||||
<label string="%%(company_name)s: User's Company name"/>
|
||||
<label string="%%(company_currency)s: User's Company Currency"/>
|
||||
<label string="%%(heading)s: Move line header"/>
|
||||
<label string="%%(line)s: Ledger Posting lines"/>
|
||||
</group>
|
||||
</page>
|
||||
</notebook>
|
||||
<footer>
|
||||
<field name="needprinting" invisible="1"/>
|
||||
<div attrs="{'invisible':[('needprinting','=', False)]}">
|
||||
<button name="do_report" string="Download Letters" type="object" class="oe_highlight"/>
|
||||
</div>
|
||||
<div attrs="{'invisible':[('needprinting','!=', False)]}">
|
||||
<button name="do_done" string="Close" type="object" class="oe_highlight"/>
|
||||
</div>
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_account_followup_print_all_msg" model="ir.ui.view">
|
||||
<field name="name">account.followup.print.all.msg.form</field>
|
||||
<field name="model">account.followup.print.all</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Summary" version="7.0">
|
||||
<separator string="Summary"/>
|
||||
<field name="summary"/>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_account_followup_print_all" model="ir.actions.act_window">
|
||||
<field name="name">Send Follow-Ups</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">account.followup.print.all</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
|
|
|
@ -295,7 +295,7 @@ class mail_message(osv.Model):
|
|||
|
||||
return {'id': message.id,
|
||||
'type': message.type,
|
||||
'body': html_email_clean(message.body),
|
||||
'body': html_email_clean(message.body or ''),
|
||||
'model': message.model,
|
||||
'res_id': message.res_id,
|
||||
'record_name': message.record_name,
|
||||
|
|
Loading…
Reference in New Issue