From d8924a234adb72639b980af72a08d4e223b295b5 Mon Sep 17 00:00:00 2001 From: git_admin Date: Sat, 2 May 2026 07:02:14 +0000 Subject: [PATCH] Tower: upload om_account_followup 19.0.1.0.2 (was 1.0.2, via marketplace) --- .../wizard/followup_print.py | 224 ++++++++++++++++++ 1 file changed, 224 insertions(+) create mode 100644 addons/om_account_followup/wizard/followup_print.py diff --git a/addons/om_account_followup/wizard/followup_print.py b/addons/om_account_followup/wizard/followup_print.py new file mode 100644 index 0000000..bdc4af9 --- /dev/null +++ b/addons/om_account_followup/wizard/followup_print.py @@ -0,0 +1,224 @@ +import datetime +import time +from odoo import api, fields, models, _ +from markupsafe import Markup + + +class FollowupPrint(models.TransientModel): + _name = 'followup.print' + _description = 'Print Follow-up & Send Mail to Customers' + + def _get_followup(self): + if self.env.context.get('active_model', + 'ir.ui.menu') == 'followup.followup': + return self.env.context.get('active_id', False) + company_id = self.env.user.company_id.id + followp_id = self.env['followup.followup'].search( + [('company_id', '=', company_id)], limit=1) + return followp_id or False + + date = fields.Date('Follow-up Sending Date', required=True, + help="This field allow you to select a forecast date " + "to plan your follow-ups", + default=lambda *a: time.strftime('%Y-%m-%d')) + followup_id = fields.Many2one('followup.followup', 'Follow-Up', + required=True, readonly=True, + default=_get_followup) + partner_ids = fields.Many2many('followup.stat.by.partner', + 'partner_stat_rel', 'osv_memory_id', + 'partner_id', 'Partners', required=True) + company_id = fields.Many2one('res.company', readonly=True, + related='followup_id.company_id') + email_conf = fields.Boolean('Send Email Confirmation') + email_subject = fields.Char('Email Subject', size=64, + default=_('Invoices Reminder')) + partner_lang = fields.Boolean( + 'Send Email in Partner Language', default=True, + 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', default='') + summary = fields.Text('Summary', readonly=True) + test_print = fields.Boolean( + 'Test Print', help='Check if you want to print follow-ups without ' + 'changing follow-up level.') + + def process_partners(self, partner_ids, data): + partner_obj = self.env['res.partner'] + partner_ids_to_print = [] + nbmanuals = 0 + manuals = {} + nbmails = 0 + nbunknownmails = 0 + nbprints = 0 + resulttext = " " + for partner in self.env['followup.stat.by.partner'].browse( + partner_ids): + if partner.max_followup_id.manual_action: + partner_obj.do_partner_manual_action([partner.partner_id.id]) + nbmanuals = nbmanuals + 1 + key = partner.partner_id.payment_responsible_id.name or _( + "Anybody") + if key not in manuals.keys(): + manuals[key] = 1 + else: + manuals[key] = manuals[key] + 1 + if partner.max_followup_id.send_email: + nbunknownmails += partner.partner_id.do_partner_mail() + nbmails += 1 + if partner.max_followup_id.send_letter: + partner_ids_to_print.append(partner.id) + nbprints += 1 + followup_without_lit = \ + partner.partner_id.latest_followup_level_id_without_lit + message = "%s %s %s" % (_("Follow-up letter of "), + followup_without_lit.name, + _(" will be sent")) + partner.partner_id.message_post(body=message) + 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
" + resulttext += "
" + str(nbprints) + _( + " letter(s) in report") + " \n
" + str(nbmanuals) + _( + " manual action(s) assigned:") + needprinting = False + if nbprints > 0: + needprinting = True + resulttext += "

" + for item in manuals: + resulttext = resulttext + "

  • " + item + ":" + str( + manuals[item]) + "\n
  • " + resulttext += "

    " + result = {} + action = partner_obj.do_partner_print(partner_ids_to_print, data) + result['needprinting'] = needprinting + result['resulttext'] = Markup(resulttext) + result['action'] = action or {} + return result + + def do_update_followup_level(self, to_update, partner_list, date): + for id in to_update.keys(): + if to_update[id]['partner_id'] in partner_list: + self.env['account.move.line'].browse([int(id)]).write( + {'followup_line_id': to_update[id]['level'], + 'followup_date': date}) + + def clear_manual_actions(self, partner_list): + partner_list_ids = [partner.partner_id.id for partner in self.env[ + 'followup.stat.by.partner'].browse(partner_list)] + ids = self.env['res.partner'].search( + ['&', ('id', 'not in', partner_list_ids), '|', + ('payment_responsible_id', '!=', False), + ('payment_next_action_date', '!=', False)]) + + partners_to_clear = [] + for part in ids: + if not part.unreconciled_aml_ids: + partners_to_clear.append(part.id) + part.action_done() + return len(partners_to_clear) + + def do_process(self): + context = dict(self.env.context or {}) + + tmp = self._get_partners_followp() + partner_list = tmp['partner_ids'] + to_update = tmp['to_update'] + date = self.date + data = self.read()[0] + data['followup_id'] = data['followup_id'][0] + + self.do_update_followup_level(to_update, partner_list, date) + restot_context = context.copy() + restot = self.with_context(restot_context).process_partners( + partner_list, data) + context.update(restot_context) + nbactionscleared = self.clear_manual_actions(partner_list) + if nbactionscleared > 0: + restot['resulttext'] = restot['resulttext'] + "
  • " + _( + "%s partners have no credits and as such the " + "action is cleared") % (str(nbactionscleared)) + "
  • " + resource_id = self.env.ref( + 'om_account_followup.view_om_account_followup_sending_results') + context.update({'description': restot['resulttext'], + 'needprinting': restot['needprinting'], + 'report_data': restot['action']}) + return { + 'name': _('Send Letters and Emails: Actions Summary'), + 'view_type': 'form', + 'context': context, + 'view_mode': 'list,form', + 'res_model': 'followup.sending.results', + 'views': [(resource_id.id, 'form')], + 'type': 'ir.actions.act_window', + 'target': 'new', + } + + def _get_msg(self): + return self.env.user.company_id.follow_up_msg + + def _get_partners_followp(self): + data = self + company_id = data.company_id.id + context = self.env.context + self.env.cr.execute( + '''SELECT + l.partner_id, + l.followup_line_id, + l.date_maturity, + l.date, l.id + FROM account_move_line AS l + LEFT JOIN account_account AS a + ON (l.account_id=a.id) + WHERE (l.full_reconcile_id IS NULL) + AND a.account_type = 'asset_receivable' + AND (l.partner_id is NOT NULL) + AND (l.debit > 0) + AND (l.company_id = %s) + ORDER BY l.date''' % (company_id)) + move_lines = self.env.cr.fetchall() + old = None + fups = {} + fup_id = 'followup_id' in context and context[ + 'followup_id'] or data.followup_id.id + date = 'date' in context and context['date'] or data.date + date = fields.Date.to_string(date) + current_date = datetime.date(*time.strptime(date, '%Y-%m-%d')[:3]) + self.env.cr.execute( + '''SELECT * + FROM followup_line + WHERE followup_id=%s + ORDER BY delay''' % (fup_id,)) + + for result in self.env.cr.dictfetchall(): + delay = datetime.timedelta(days=result['delay']) + fups[old] = (current_date - delay, result['id']) + old = result['id'] + + partner_list = [] + to_update = {} + + for partner_id, followup_line_id, date_maturity, date, id in \ + move_lines: + if not partner_id: + continue + if followup_line_id not in fups: + continue + stat_line_id = partner_id * 10000 + company_id + if date_maturity: + date_maturity = fields.Date.to_string(date_maturity) + if date_maturity <= fups[followup_line_id][0].strftime( + '%Y-%m-%d'): + if stat_line_id not in partner_list: + partner_list.append(stat_line_id) + to_update[str(id)] = {'level': fups[followup_line_id][1], + 'partner_id': stat_line_id} + elif date and date <= fups[followup_line_id][0]: + if stat_line_id not in partner_list: + partner_list.append(stat_line_id) + to_update[str(id)] = {'level': fups[followup_line_id][1], + 'partner_id': stat_line_id} + return {'partner_ids': partner_list, 'to_update': to_update}