diff --git a/filter_aged_partners/__init__.py b/filter_aged_partners/__init__.py new file mode 100644 index 000000000..0f7cb6b22 --- /dev/null +++ b/filter_aged_partners/__init__.py @@ -0,0 +1,2 @@ +# -*- coding: utf-8 -*- +import models \ No newline at end of file diff --git a/filter_aged_partners/__manifest__.py b/filter_aged_partners/__manifest__.py new file mode 100644 index 000000000..3489cd7f9 --- /dev/null +++ b/filter_aged_partners/__manifest__.py @@ -0,0 +1,17 @@ +# -*- coding: utf-8 -*- +{ + 'name': 'Aged partner filter', + 'summary': "Aged partners filtered pdf reports", + 'version': '10.0.1.0', + 'author': 'Cybrosys Technologies', + 'website': "http://www.cybrosys.com", + 'company': 'Cybrosys Techno Solutions', + "category": "Accounts", + 'depends': ['base', 'account', 'sale'], + 'data': ['views/filter_aged_partners.xml', + ], + 'license': 'LGPL-3', + 'images': ['static/description/banner.jpg'], + 'installable': True, + 'application': True, +} diff --git a/filter_aged_partners/models/__init__.py b/filter_aged_partners/models/__init__.py new file mode 100644 index 000000000..82037a7d6 --- /dev/null +++ b/filter_aged_partners/models/__init__.py @@ -0,0 +1 @@ +import filter_aged_partners \ No newline at end of file diff --git a/filter_aged_partners/models/filter_aged_partners.py b/filter_aged_partners/models/filter_aged_partners.py new file mode 100644 index 000000000..b1270ca74 --- /dev/null +++ b/filter_aged_partners/models/filter_aged_partners.py @@ -0,0 +1,270 @@ +# -*- coding: utf-8 -*- +import time +from odoo.tools import float_is_zero +from datetime import datetime +from dateutil.relativedelta import relativedelta +from odoo import fields, models, _ +from odoo.exceptions import UserError + + +class FilterAgedPartner(models.TransientModel): + _inherit ='account.aged.trial.balance' + + customer = fields.Many2many('res.partner', 'name', string='Customers') + + def _print_report(self, data): + # data['form']=super(FilterAgedPartner, self)._print_report(data) + res = {} + data = self.pre_print_report(data) + data['form'].update(self.read(['period_length'])[0]) + period_length = data['form']['period_length'] + if period_length <= 0: + raise UserError(_('You must set a period length greater than 0.')) + if not data['form']['date_from']: + raise UserError(_('You must set a start date.')) + + start = datetime.strptime(data['form']['date_from'], "%Y-%m-%d") + + for i in range(5)[::-1]: + stop = start - relativedelta(days=period_length - 1) + res[str(i)] = { + 'name': (i != 0 and (str((5 - (i + 1)) * period_length) + '-' + str((5 - i) * period_length)) or ( + '+' + str(4 * period_length))), + 'stop': start.strftime('%Y-%m-%d'), + 'start': (i != 0 and stop.strftime('%Y-%m-%d') or False), + } + start = stop - relativedelta(days=1) + data['form'].update(res) + data['form'].update({'customer': self.customer.ids}) + # data=super(FilterAgedPartner, self)._print_report(data) + return self.env['report'].with_context(landscape=True).get_action(self, 'account.report_agedpartnerbalance', + data=data) + + +class FilterAgedCustomer(models .AbstractModel): + _inherit = 'report.account.report_agedpartnerbalance' + + def _get_partner_move_lines(self, account_type, date_from, target_move, period_length,customer): + periods = {} + start = datetime.strptime(date_from, "%Y-%m-%d") + for i in range(5)[::-1]: + stop = start - relativedelta(days=period_length) + periods[str(i)] = { + 'name': (i != 0 and (str((5-(i+1)) * period_length) + '-' + str((5-i) * period_length)) or ('+'+str(4 * period_length))), + 'stop': start.strftime('%Y-%m-%d'), + 'start': (i != 0 and stop.strftime('%Y-%m-%d') or False), + } + start = stop - relativedelta(days=1) + + res = [] + total = [] + cr = self.env.cr + user_company = self.env.user.company_id.id + move_state = ['draft', 'posted'] + if target_move == 'posted': + move_state = ['posted'] + arg_list = (tuple(move_state), tuple(account_type)) + reconciliation_clause = '(l.reconciled IS FALSE)' + cr.execute('SELECT debit_move_id, credit_move_id FROM account_partial_reconcile where create_date > %s', (date_from,)) + reconciled_after_date = [] + for row in cr.fetchall(): + reconciled_after_date += [row[0], row[1]] + if reconciled_after_date: + reconciliation_clause = '(l.reconciled IS FALSE OR l.id IN %s)' + arg_list += (tuple(reconciled_after_date),) + arg_list += (date_from, user_company) + query = ''' + SELECT DISTINCT l.partner_id, UPPER(res_partner.name) + FROM account_move_line AS l left join res_partner on l.partner_id = res_partner.id, account_account, account_move am + WHERE (l.account_id = account_account.id) + AND (l.move_id = am.id) + AND (am.state IN %s) + AND (account_account.internal_type IN %s) + AND ''' + reconciliation_clause + ''' + AND (l.date <= %s) + AND l.company_id = %s + ORDER BY UPPER(res_partner.name)''' + cr.execute(query, arg_list) + partners = cr.dictfetchall() + print 'filtered', partners + #-------------filter--------------# + if customer: + for ptnr in partners[:]: + print customer + print 'm', ptnr['partner_id'] + if ptnr['partner_id'] not in customer: + partners.remove(ptnr) + #---------------------------------# + + for i in range(7): + total.append(0) + + # Build a string like (1,2,3) for easy use in SQL query + partner_ids = [partner['partner_id'] for partner in partners if partner['partner_id']] + lines = dict((partner['partner_id'] or False, []) for partner in partners) + if not partner_ids: + return [], [], [] + + # This dictionary will store the not due amount of all partners + undue_amounts = {} + query = '''SELECT l.id + FROM account_move_line AS l, account_account, account_move am + WHERE (l.account_id = account_account.id) AND (l.move_id = am.id) + AND (am.state IN %s) + AND (account_account.internal_type IN %s) + AND (COALESCE(l.date_maturity,l.date) > %s)\ + AND ((l.partner_id IN %s) OR (l.partner_id IS NULL)) + AND (l.date <= %s) + AND l.company_id = %s''' + cr.execute(query, (tuple(move_state), tuple(account_type), date_from, tuple(partner_ids), date_from, user_company)) + aml_ids = cr.fetchall() + aml_ids = aml_ids and [x[0] for x in aml_ids] or [] + for line in self.env['account.move.line'].browse(aml_ids): + partner_id = line.partner_id.id or False + if partner_id not in undue_amounts: + undue_amounts[partner_id] = 0.0 + line_amount = line.balance + if line.balance == 0: + continue + for partial_line in line.matched_debit_ids: + if partial_line.create_date[:10] <= date_from: + line_amount += partial_line.amount + for partial_line in line.matched_credit_ids: + if partial_line.create_date[:10] <= date_from: + line_amount -= partial_line.amount + if not self.env.user.company_id.currency_id.is_zero(line_amount): + undue_amounts[partner_id] += line_amount + lines[partner_id].append({ + 'line': line, + 'amount': line_amount, + 'period': 6, + }) + + # Use one query per period and store results in history (a list variable) + # Each history will contain: history[1] = {'': } + history = [] + for i in range(5): + args_list = (tuple(move_state), tuple(account_type), tuple(partner_ids),) + dates_query = '(COALESCE(l.date_maturity,l.date)' + + if periods[str(i)]['start'] and periods[str(i)]['stop']: + dates_query += ' BETWEEN %s AND %s)' + args_list += (periods[str(i)]['start'], periods[str(i)]['stop']) + elif periods[str(i)]['start']: + dates_query += ' >= %s)' + args_list += (periods[str(i)]['start'],) + else: + dates_query += ' <= %s)' + args_list += (periods[str(i)]['stop'],) + args_list += (date_from, user_company) + + query = '''SELECT l.id + FROM account_move_line AS l, account_account, account_move am + WHERE (l.account_id = account_account.id) AND (l.move_id = am.id) + AND (am.state IN %s) + AND (account_account.internal_type IN %s) + AND ((l.partner_id IN %s) OR (l.partner_id IS NULL)) + AND ''' + dates_query + ''' + AND (l.date <= %s) + AND l.company_id = %s''' + cr.execute(query, args_list) + partners_amount = {} + aml_ids = cr.fetchall() + aml_ids = aml_ids and [x[0] for x in aml_ids] or [] + for line in self.env['account.move.line'].browse(aml_ids): + partner_id = line.partner_id.id or False + if partner_id not in partners_amount: + partners_amount[partner_id] = 0.0 + line_amount = line.balance + if line.balance == 0: + continue + for partial_line in line.matched_debit_ids: + if partial_line.create_date[:10] <= date_from: + line_amount += partial_line.amount + for partial_line in line.matched_credit_ids: + if partial_line.create_date[:10] <= date_from: + line_amount -= partial_line.amount + + if not self.env.user.company_id.currency_id.is_zero(line_amount): + partners_amount[partner_id] += line_amount + lines[partner_id].append({ + 'line': line, + 'amount': line_amount, + 'period': i + 1, + }) + history.append(partners_amount) + + for partner in partners: + if partner['partner_id'] is None: + partner['partner_id'] = False + at_least_one_amount = False + values = {} + undue_amt = 0.0 + if partner['partner_id'] in undue_amounts: # Making sure this partner actually was found by the query + undue_amt = undue_amounts[partner['partner_id']] + + total[6] = total[6] + undue_amt + values['direction'] = undue_amt + if not float_is_zero(values['direction'], precision_rounding=self.env.user.company_id.currency_id.rounding): + at_least_one_amount = True + + for i in range(5): + during = False + if partner['partner_id'] in history[i]: + during = [history[i][partner['partner_id']]] + # Adding counter + total[(i)] = total[(i)] + (during and during[0] or 0) + values[str(i)] = during and during[0] or 0.0 + if not float_is_zero(values[str(i)], precision_rounding=self.env.user.company_id.currency_id.rounding): + at_least_one_amount = True + values['total'] = sum([values['direction']] + [values[str(i)] for i in range(5)]) + ## Add for total + total[(i + 1)] += values['total'] + values['partner_id'] = partner['partner_id'] + if partner['partner_id']: + browsed_partner = self.env['res.partner'].browse(partner['partner_id']) + values['name'] = browsed_partner.name and len(browsed_partner.name) >= 45 and browsed_partner.name[0:40] + '...' or browsed_partner.name + values['trust'] = browsed_partner.trust + else: + values['name'] = _('Unknown Partner') + values['trust'] = False + + if at_least_one_amount: + res.append(values) + + return res, total, lines + + def render_html(self, docids, data=None): + print 'mymodule' + if not data.get('form') or not self.env.context.get('active_model') or not self.env.context.get('active_id'): + raise UserError(_("Form content is missing, this report cannot be printed.")) + + total = [] + model = self.env.context.get('active_model') + docs = self.env[model].browse(self.env.context.get('active_id')) + + target_move = data['form'].get('target_move', 'all') + date_from = data['form'].get('date_from', time.strftime('%Y-%m-%d')) + + if data['form']['result_selection'] == 'customer': + account_type = ['receivable'] + elif data['form']['result_selection'] == 'supplier': + account_type = ['payable'] + else: + account_type = ['payable', 'receivable'] + + movelines, total, dummy = self._get_partner_move_lines(account_type, date_from, target_move, + data['form']['period_length'], data['form']['customer']) + + + + docargs = { + 'doc_ids': self.ids, + 'doc_model': model, + 'data': data['form'], + 'docs': docs, + 'time': time, + 'get_partner_lines': movelines, + 'get_direction': total, + } + return self.env['report'].render('account.report_agedpartnerbalance', docargs) diff --git a/filter_aged_partners/static/description/aged_partnerwizard.png b/filter_aged_partners/static/description/aged_partnerwizard.png new file mode 100644 index 000000000..1e29880c5 Binary files /dev/null and b/filter_aged_partners/static/description/aged_partnerwizard.png differ diff --git a/filter_aged_partners/static/description/banner.jpg b/filter_aged_partners/static/description/banner.jpg new file mode 100644 index 000000000..cad4d04ac Binary files /dev/null and b/filter_aged_partners/static/description/banner.jpg differ diff --git a/filter_aged_partners/static/description/cybro_logo.png b/filter_aged_partners/static/description/cybro_logo.png new file mode 100644 index 000000000..bb309114c Binary files /dev/null and b/filter_aged_partners/static/description/cybro_logo.png differ diff --git a/filter_aged_partners/static/description/icon.png b/filter_aged_partners/static/description/icon.png new file mode 100644 index 000000000..b1256ef4c Binary files /dev/null and b/filter_aged_partners/static/description/icon.png differ diff --git a/filter_aged_partners/static/description/index.html b/filter_aged_partners/static/description/index.html new file mode 100644 index 000000000..ed94ae00e --- /dev/null +++ b/filter_aged_partners/static/description/index.html @@ -0,0 +1,64 @@ +
+

Aged Partner report with Partner Filter

+

Cybrosys Techno Solutions - www.cybrosys.com

+
+ +
+
+
You can generate aged partner report from wizard with partner filter
+
+
+ + +
+
+
+
+ + +
+
+
This will open partner ledger report wizard with the selected partner.
+
You can add or remove partner from wizard in case of fault selection
+ +
+ + +
+ +
+
+
+ + +
+
+ +
+ +
+

Need Any Help?

+ +
+ diff --git a/filter_aged_partners/static/description/partnerfilter.png b/filter_aged_partners/static/description/partnerfilter.png new file mode 100644 index 000000000..5810f417a Binary files /dev/null and b/filter_aged_partners/static/description/partnerfilter.png differ diff --git a/filter_aged_partners/static/description/pdfreport.png b/filter_aged_partners/static/description/pdfreport.png new file mode 100644 index 000000000..47e007809 Binary files /dev/null and b/filter_aged_partners/static/description/pdfreport.png differ diff --git a/filter_aged_partners/views/filter_aged_partners.xml b/filter_aged_partners/views/filter_aged_partners.xml new file mode 100644 index 000000000..c0336c9c5 --- /dev/null +++ b/filter_aged_partners/views/filter_aged_partners.xml @@ -0,0 +1,16 @@ + + + + + partner.filter.form + account.aged.trial.balance + + + + + + + + + + \ No newline at end of file