[IMP] Search functions on amounts and dates in partner

bzr revid: jco@openerp.com-20121206110315-ddgp3qxwn3ezl06g
This commit is contained in:
Josse Colpaert 2012-12-06 12:03:15 +01:00
parent b838e677dd
commit cfd009394d
6 changed files with 64 additions and 46 deletions

View File

@ -456,7 +456,7 @@ class account_move_line(osv.osv):
store = {
'account.move': (_get_move_lines, ['period_id'], 20)
}),
'blocked': fields.boolean('Litigation', help="You can check this box to mark this journal item as a litigation with the associated partner"),
'blocked': fields.boolean('No Follow-up', help="You can check this box to mark this journal item as a litigation with the associated partner"),
'partner_id': fields.many2one('res.partner', 'Partner', select=1, ondelete='restrict'),
'date_maturity': fields.date('Due date', select=True ,help="This field is used for payable and receivable journal entries. You can put the limit date for the payment of this line."),
'date': fields.related('move_id','date', string='Effective date', type='date', required=True, select=True,

View File

@ -134,18 +134,23 @@ class res_partner(osv.osv):
return []
having_values = tuple(map(itemgetter(2), args))
where = ' AND '.join(
map(lambda x: '(SUM(debit-credit) %(operator)s %%s)' % {
map(lambda x: '(SUM(bal2) %(operator)s %%s)' % {
'operator':x[1]},args))
query = self.pool.get('account.move.line')._query_get(cr, uid, context=context)
cr.execute(('SELECT partner_id FROM account_move_line l '\
'WHERE account_id IN '\
'(SELECT id FROM account_account '\
'WHERE type=%s AND active) '\
'AND reconcile_id IS NULL '\
'AND '+query+' '\
'AND partner_id IS NOT NULL '\
'GROUP BY partner_id HAVING '+where),
(type,) + having_values)
cr.execute(('SELECT pid AS partner_id, SUM(bal2) FROM ' \
'(SELECT CASE WHEN bal IS NOT NULL THEN bal ' \
'ELSE 0.0 END AS bal2, p.id as pid FROM ' \
'(SELECT (debit-credit) AS bal, partner_id ' \
'FROM account_move_line l ' \
'WHERE account_id IN ' \
'(SELECT id FROM account_account '\
'WHERE type=%s AND active) ' \
'AND reconcile_id IS NULL ' \
'AND '+query+') AS l ' \
'RIGHT JOIN res_partner p ' \
'ON p.id = partner_id ) AS pl ' \
'GROUP BY pid HAVING ' + where),
(type,) + having_values)
res = cr.fetchall()
if not res:
return [('id','=','0')]

View File

@ -277,7 +277,7 @@ class res_partner(osv.osv):
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
payment_next_action = partner.payment_next_action + " \n " + action_text
else:
payment_next_action = action_text
self.write(cr, uid, [partner.id], {'payment_next_action_date': payment_action_date,
@ -363,6 +363,28 @@ class res_partner(osv.osv):
return [('id','=','0')]
return [('id','in',map(itemgetter(0), res))]
def _payment_earliest_date_search(self, cr, uid, obj, name, args, context=None):
if not args:
return []
having_values = tuple(map(itemgetter(2), args))
where = ' AND '.join(
map(lambda x: '(MIN(l.date_maturity) %(operator)s %%s)' % {
'operator':x[1]},args))
query = self.pool.get('account.move.line')._query_get(cr, uid, context=context)
cr.execute(('SELECT partner_id FROM account_move_line l '\
'WHERE account_id IN '\
'(SELECT id FROM account_account '\
'WHERE type=\'receivable\' AND active) '\
'AND reconcile_id IS NULL '\
'AND '+query+' '\
'AND partner_id IS NOT NULL '\
'GROUP BY partner_id HAVING '+where),
having_values)
res = cr.fetchall()
if not res:
return [('id','=','0')]
return [('id','in',map(itemgetter(0), res))]
def _payment_due_search(self, cr, uid, obj, name, args, context=None):
company = self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id.id
if not args:
@ -395,12 +417,13 @@ class res_partner(osv.osv):
_inherit = "res.partner"
_columns = {
'payment_responsible_id':fields.many2one('res.users', ondelete='set null', string='Follow-up Responsible',
help="Responsible for making sure the action happens."),
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':fields.text('Next Action',
help="This is the next action to be taken. It will automatically be set when 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. "),
help="This is when the manual follow-up is needed. " \
"The date will be set to the current date when the partner gets a follow-up level that requires a manual action. Can be practical to set manually e.g. to follow up his payment. "),
'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",
@ -418,18 +441,18 @@ class res_partner(osv.osv):
store=False,
multi="latest"),
'payment_amount_due':fields.function(_get_amounts_and_date, method = True,
type='float', string="Amount due",
type='float', string="Amount Due",
store = False, multi="amountsdate",
fnct_search=_payment_due_search),
'payment_amount_overdue':fields.function(_get_amounts_and_date, method = True,
type='float', string="Amount overdue",
type='float', string="Amount Overdue",
store = False, multi="amountsdate",
fnct_search = _payment_overdue_search),
'payment_earliest_due_date':fields.function(_get_amounts_and_date, method=True,
type='date',
string = "Most overdue date",
multi="amountsdate",
),
string = "Worst Due Date",
multi="amountsdate",
fnct_search=_payment_earliest_date_search),
}
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -18,7 +18,7 @@
<field name="payment_responsible_id"/>
<field name="payment_earliest_due_date"/>
<field name="payment_amount_overdue"/>
<field name="payment_amount_due"/>
<field name="payment_amount_due" />
</tree>
</field>
</record>
@ -53,7 +53,7 @@
<field name="res_model">res.partner</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="domain">[('credit', '>', 0.0)]</field>
<field name="domain">[('payment_amount_due', '>', 0.0)]</field>
<field name="context">{'Followupfirst':True, 'search_default_todo': True} </field>
<field name="search_view_id" ref="customer_followup_search_view"/>
</record>
@ -70,7 +70,7 @@
<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', '&lt;=', 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', '&lt;=', 0.0)]}"/>
help="If not specified by the latest follow-up level, it will send from the default email template" attrs="{'invisible':[('credit', '&lt;=', 0.0)]}"/>
</div>
<p attrs="{'invisible':[('latest_followup_date','=', False)]}">
The <field name="latest_followup_date" class = "oe_inline"/>, the latest payment follow-up
@ -89,24 +89,22 @@
</div>
</group>
<label for="payment_note" class="oe_edit_only"/>
<field name="payment_note" placeholder="Comments of the user: he promised to 50%% before 15th of May, balance before 1st of July."/>
<field name="payment_note" placeholder="He said the problem was temporary and promised to pay 50%% before 15th of May, balance before 1st of July."/>
<p class="oe_grey">
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.
customer. You can check "No Follow-up" in
order to exclude it from the next follow-up actions.
</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&lt;=current_date) and result&gt;0">
<field name="date" readonly="True"/>
<field name="company_id" groups="base.group_multi_company"/>
<field name="company_id" readonly="True" groups="base.group_multi_company" />
<field name="move_id" readonly="True"/>
<field name="blocked" string="Litigation"/>
<field name="blocked"/>
<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">

View File

@ -5,7 +5,7 @@
<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="name">First polite payment follow-up reminder email</field>
<field name="email_from">${user.email or '' | h}</field>
<field name="subject">${user.company_id.name | h} Payment Reminder</field>
<field name="email_to">${object.email | h}</field>
@ -51,7 +51,7 @@ ${followup_table | h}
<!--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="name">A bit urging second payment follow-up reminder email</field>
<field name="email_from">${user.email or '' | h}</field>
<field name="subject">${user.company_id.name | h} Payment Reminder</field>
<field name="email_to">${object.email | h}</field>
@ -95,7 +95,7 @@ ${followup_table | h}
</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="name">Urging payment follow-up reminder email</field>
<field name="email_from">${user.email or '' | h}</field>
<field name="subject">${user.company_id.name | h} Payment Reminder</field>
<field name="email_to">${object.email | h}</field>
@ -138,7 +138,7 @@ ${object.followup_table(object, user) | h}
<!-- 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="name">Default payment follow-up reminder e-mail</field>
<field name="email_from">${user.email or '' | h}</field>
<field name="subject">${user.company_id.name | h} Payment Reminder</field>
<field name="email_to">${object.email | h}</field>

View File

@ -152,7 +152,7 @@ class account_followup_print(osv.osv_memory):
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")
key = partner.partner_id.payment_responsible_id.name or _("Anybody")
if not key in manuals.keys():
manuals[key]= 1
else:
@ -195,18 +195,10 @@ class account_followup_print(osv.osv_memory):
# 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), '|',
ids = self.pool.get('res.partner').search(cr, uid, ['&', ('credit', '<=', 0.0), '&', ('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)
self.pool.get('res.partner').action_done(cr, uid, ids, context=context)
return len(ids)
def do_process(self, cr, uid, ids, context=None):