from odoo import models, fields, api from odoo.exceptions import UserError, ValidationError from psycopg2 import sql, DatabaseError from werkzeug import utils import json import logging import xlwt from io import BytesIO import base64 import csv _logger = logging.getLogger(__name__) MASS_MAILING_BUSINESS_MODELS = [ 'crm.lead', 'event.registration', 'hr.applicant', 'res.partner', 'event.track', 'sale.order', 'mailing.list', 'mailing.contact' ] class opendons_operation(models.Model): _name = 'opendons.operation' _description = 'opération marketing : mailing, emailing evenements' _inherit = ['mail.thread'] #code=fields.Char(string='Code',required=True, translate=True,track_visibility='always') name=fields.Char(string='Name',required=True, translate=True,track_visibility='always') partner_count = fields.Integer(string="count",readonly=True) #begin_date=fields.Date(string='Date begin',required=True, translate=True,track_visibility='always') #end_date=fields.Date(string='Date end',required=True, translate=True,track_visibility='always') chanel=fields.Selection([ ('mail', 'Mailing'), ('email', 'E-mailing'), ('event', 'Event')], string='Chanel',required=True, translate=True,track_visibility='always') user_id = fields.Many2one('res.users', string='Author', default=lambda self: self.env.uid) cost = fields.Monetary( string='Cost', currency_field='currency_id') @api.model def _default_currency(self): company = self.env['res.company']._company_default_get( 'opendons.operation') return company.currency_id currency_id = fields.Many2one( 'res.currency', string='Currency', required=True, track_visibility='onchange', ondelete='restrict', default=_default_currency ) _sql_constraints = [ ('name_uniq', 'unique (name)', "Name already exists !") ] number_of_sending = fields.Integer( compute='_compute_number_of_sending', string="# of sending", readonly=True ) segment_ids = fields.One2many( 'opendons.segment', 'operation_id', string='Segments', readonly=True ) segment_count = fields.Integer( string="# of segment", readonly=True ) state = fields.Selection([ ('draft', 'Draft'), ('validated', 'Validated'), ('exported', 'Exported')], string='State', readonly=True, copy=False, default='draft', index=True, track_visibility='onchange' ) csv_export = fields.Binary('csv export', filters='.csv', readonly=True) document_fname=fields.Char() # def _compute_segment_count(self): # # The current user may not have access rights for donations # for operation in self: # try: # operation.segment_count = len(operation.segment_ids) # except Exception: # operation.segment_count = 0 def validate(self): for operation in self: vals = {'state': 'validated'} operation.write(vals) return def validated2draft(self): '''from Done state to Cancel state''' for operation in self: operation.state = 'draft' def validated2exported(self): '''from Done state to Cancel state''' for operation in self: operation.state = 'exported' def exported2validated(self): '''from Done state to Cancel state''' for operation in self: operation.state = 'validated' def csv_export_operation(self): with open('export.csv', mode='w') as file: writer = csv.writer(file, delimiter=',', quotechar='"', quoting=csv.QUOTE_MINIMAL) # ggcreate a row containds heading of each column writer.writerow(['name', 'email']) # fetch products and write respective data. partners = self.select_partner_operation() for p in partners: name=p.name email=p.email writer.writerow([name,email]) with open('export.csv', 'r', encoding="utf-8") as f2: # file encode and store in a variable ‘data’ data = str.encode(f2.read(), 'utf-8') self.csv_export=base64.encodestring(data) self.document_fname='operation'+str(self.id)+'.csv' return #def select_partner_operation(self): #le principe est de selectionner les contacts associés aux segments avec les règles suivantes : #RG1: si un contact est présent dans un segment d'exclusion, alos on le retire de la sélection #RG2: la priorité des segments est l'ordre de présentation dans la liste des segmments #RG3: au final, un contact sélectionné est rattaché à l'opération avec le segment d'appartenance @api.model def create(self,vals): res=super(opendons_operation, self).create(vals) #création du segment d'exclusion vals2={} vals2['operation_id']=res.id vals2['sequence']=1 vals2['name']='Exclusion' vals2['exclusion']=True res2=self.env['opendons.segment'].create(vals2) return res def export_partners(self): partners = self.env['res.partner'].sudo().search([]) stream = BytesIO() book = xlwt.Workbook(encoding='utf-8') sheet = book.add_sheet(u'{}'.format(u'My Sheet')) row = 1 cell = 0 for p in partners: sheet.write(row, cell, p.name) row += 1 book.save(stream) self.excel_report = base64.encodestring(stream.getvalue()) self.document_fname='operation'+seld.id+'.csv' return class opendons_segment(models.Model): _name = 'opendons.segment' _description = 'operation marketing segment : a segment is a part of contacts selected for an operation ' _inherit = ['mail.thread'] sequence = fields.Integer(string="sequence", default=10) #code=fields.Char(string='Code',required=True, translate=True,track_visibility='always') name=fields.Char(string='Name',required=True, translate=True,track_visibility='always') exclusion=fields.Boolean(String='segment d\'exclusion',default=False,readonly=True) logical_operator = fields.Selection([('union','union'),('inter','intersection')],'Type',default='union') cost = fields.Monetary( string='Cost', currency_field='currency_id') partner_count = fields.Integer(string="partners count", compute='_count_partner_segment',readonly=True) mailing_domain = fields.Char(string='partners selection', readonly=True) @api.model def _default_currency(self): company = self.env['res.company']._company_default_get( 'opendons.segment') return company.currency_id currency_id = fields.Many2one( 'res.currency', string='Currency', required=True, track_visibility='onchange', ondelete='restrict', default=_default_currency ) operation_id = fields.Many2one( 'opendons.operation', String='Operation', index=True, readonly=True, track_visibility='onchange', ondelete='cascade' ) ensemble_ids = fields.One2many( 'opendons.ensemble', 'segment_id', string='Ensemble', required=True, track_visibility='onchange') ensemble_count = fields.Integer( compute='_compute_ensemble_count', string="# of ensemble", readonly=True ) @api.depends('mailing_domain') def _count_partner_segment(self): for rec in self: if rec.mailing_domain : rec.partner_count=self.env['res.partner'].search_count(eval(rec.mailing_domain)) else: rec.partner_count=0 def _compute_ensemble_count(self): # The current user may not have access rights for donations for segment in self: try: segment.ensemble_count = len(segment.ensemble_ids) except Exception: segment.ensemble_count = 0 @api.model def create(self,vals): res=super(opendons_segment, self).create(vals) #segment=self.env['opendons.segment'].search([('id','=',int(res.id))]) operation=self.env['opendons.operation'].search([('id','=',int(res.operation_id))]) #_logger.error('segment.id='+str(res.operation_id)) operation.write({'segment_count':len(operation.segment_ids)}) return res def write(self,vals): res=super(opendons_segment, self).write(vals) mailing_domain=False for val in vals: if val=='logical_operator': mailing_domain=self.env['opendons.ensemble'].update_segment_domain(self) if mailing_domain: vals['mailing_domain']=mailing_domain res=super(opendons_segment, self).write(vals) class opendons_ensemble(models.Model): _name = 'opendons.ensemble' _description = 'operation marketing ensemble : an ensemble is a part of contacts selected for an segment ' _inherit = ['mail.thread'] name=fields.Char(string='Name',required=True, translate=True,track_visibility='always') logical_operator = fields.Selection([('union','union'),('inter','intersection')],'Type',default='union') mailing_domain = fields.Char(string='partners selection', readonly=True) partner_count = fields.Integer(string="partners count",compute='_count_partner_ensemble',readonly=True) sequence = fields.Integer(string="sequence", default=10) segment_id = fields.Many2one( 'opendons.segment','Segment', index=True, readonly=True, track_visibility='onchange', ondelete='cascade') request_ids = fields.One2many( 'opendons.request', 'ensemble_id', string='Request', required=True, track_visibility='onchange') request_count = fields.Integer( compute='_compute_request_count', string="# of request", readonly=True ) csv_export = fields.Binary('csv export', filters='.csv', readonly=True) document_fname=fields.Char() @api.depends('mailing_domain') def _count_partner_ensemble(self): for rec in self: if rec.mailing_domain : rec.partner_count=self.env['res.partner'].search_count(eval(rec.mailing_domain)) else: rec.partner_count=0 def csv_export_ensemble(self): with open('export.csv', mode='w') as file: writer = csv.writer(file, delimiter=',', quotechar='"', quoting=csv.QUOTE_MINIMAL) # create a row contains heading of each column writer.writerow(['name', 'email']) # fetch products and write respective data. partners = self.env['res.partner'].sudo().search([]) for p in partners: name=p.name email=p.email writer.writerow([name,email]) with open('export.csv', 'r', encoding="utf-8") as f2: # file encode and store in a variable ‘data’ data = str.encode(f2.read(), 'utf-8') self.csv_export=base64.encodestring(data) self.document_fname='contacts.csv' return def _compute_request_count(self): # The current user may not have access rights for donations for ensemble in self: try: ensemble.request_count = len(ensemble.request_ids) except Exception: ensemble.request_count = 0 def update_segment_domain(self,segment): logical_operator=segment.logical_operator if logical_operator=='union': str_operator='"|",' if logical_operator=='inter': str_operator='"&",' mailing_domain='' if len(segment.ensemble_ids)>1: i=1 for ens in segment.ensemble_ids: if i==1: mailing_domain=ens.mailing_domain[1:-1] if i>1 : if ens.mailing_domain!=False: mailing_domain=str_operator +mailing_domain+","+ens.mailing_domain[1:-1] i+=1 mailing_domain="["+mailing_domain+"]" if len(segment.ensemble_ids)==1: for ens in segment.ensemble_ids: mailing_domain=ens.mailing_domain return mailing_domain @api.model def create(self,vals): res=super(opendons_ensemble, self).create(vals) segment=self.env['opendons.segment'].search([('id','=',int(res.segment_id))]) #_logger.error('segment.id='+str(res.operation_id)) segment_domain=self.update_segment_domain(segment) segment.write( { 'ensemble_count':len(segment.ensemble_ids), 'mailing_domain':segment_domain, }) return res def write(self,vals): res=super(opendons_ensemble, self).write(vals) mailing_domain=False for val in vals: if val=='logical_operator': mailing_domain=self.env['opendons.request'].update_ensemble_domain(self) if mailing_domain: vals['mailing_domain']=mailing_domain segment=self.env['opendons.segment'].search([('id','=',int(self.segment_id))]) segment_domain=self.update_segment_domain(segment) segment.write({ 'ensemble_count':len(segment.ensemble_ids), 'mailing_domain':segment_domain }) res=super(opendons_ensemble, self).write(vals) class opendons_request(models.Model): _name = 'opendons.request' _description = 'operation marketing request : a request is a part of contacts selected for an ensemble ' _inherit = ['mail.thread'] sequence = fields.Integer(string="sequence", default=10) name=fields.Char(string='Name',required=True, translate=True,track_visibility='always') partner_count = fields.Integer(string="partners count", compute='_count_partner_request', readonly=True) partner_ids = fields.Many2many('res.partner', 'partner_request_rel', 'partner_id', 'request_id', string='partners') ensemble_id = fields.Many2one( 'opendons.ensemble','Ensemble', index=True, readonly=True, track_visibility='onchange', ondelete='cascade') mailing_domain = fields.Char( string='Domain', readonly=False, store=True) @api.depends('mailing_domain') def _count_partner_request(self): for rec in self: if rec.mailing_domain : rec.partner_count=self.env['res.partner'].search_count(eval(rec.mailing_domain)) else: rec.partner_count=0 def count_partners_ensemble(self,ensemble): #on boucle sur toutes les requêtes de l'ensemble pour compter les contacts result=0 for req in ensemble.request_ids: result+=req.partner_count return result def update_ensemble_domain(self,ensemble): #on boucle sur toutes les requêtes de l'ensemble logical_operator=ensemble.logical_operator if logical_operator=='union': str_operator='"|",' if logical_operator=='inter': str_operator='"&",' mailing_domain='' if len(ensemble.request_ids)>1: i=1 for req in ensemble.request_ids: if i==1: mailing_domain=req.mailing_domain[1:-1] if i>1 : mailing_domain=str_operator +mailing_domain+","+req.mailing_domain[1:-1] i+=1 mailing_domain="["+mailing_domain+"]" #si une seule requête pour l'ensemble if len(ensemble.request_ids)==1: for req in ensemble.request_ids: mailing_domain=req.mailing_domain return mailing_domain def count_partners_segment(self,segment): #on boucle sur toutes les requêtes de l'ensemble pour compter les contacts result=0 for ensemble in segment.ensemble_ids: result+=ensemble.partner_count return result def count_partners_operation(self,operation): #on boucle sur toutes les requêtes de l'ensemble pour compter les contacts result=0 for segment in operation.segment_ids: result+=segment.partner_count return result def refresh_partners_count(self): for r in self: r.partner_count=self.env['res.partner'].search_count(eval(r.mailing_domain)) return True @api.model def create(self,vals): partners=self.count_partner_request(vals) if vals['mailing_domain']=="[]" : vals['mailing_domain']="[[\"id\",\"!=\",False]]" res=super(opendons_request, self).create(vals) #mise à jour du nombre de requête pour l'ensemble,le segment et l'opération liée ensemble=self.env['opendons.ensemble'].search([('id','=',int(res.ensemble_id))]) #partner_count=self.count_partners_ensemble(ensemble) #mise à jour du domaine pour l'ensemble ensemble_domain=self.update_ensemble_domain(ensemble) ensemble.write( {'request_count':len(ensemble.request_ids), 'mailing_domain':ensemble_domain }) segment=self.env['opendons.segment'].search([('id','=',int(ensemble.segment_id))]) segment_domain=ensemble.update_segment_domain(segment) segment.write({ 'mailing_domain':segment_domain }) return res def write(self,vals): mailing_domain_update=False for val in vals: if val=='mailing_domain': mailing_domain_update=True if mailing_domain_update==True : if vals['mailing_domain']=="[]" : vals['mailing_domain']="[[\"id\",\"!=\",False]]" res=super(opendons_request, self).write(vals) if mailing_domain_update==True: # #mise à jour du nombre de requête pour l'ensemble lié ensemble=self.env['opendons.ensemble'].search([('id','=',int(self.ensemble_id))]) ensemble_domain=self.update_ensemble_domain(ensemble) # partner_count=self.count_partners_ensemble(ensemble) ensemble.write({ 'request_count':len(ensemble.request_ids), 'mailing_domain':ensemble_domain }) segment=self.env['opendons.segment'].search([('id','=',int(ensemble.segment_id))]) segment_domain=ensemble.update_segment_domain(segment) segment.write({ 'mailing_domain':segment_domain }) # operation=self.env['opendons.operation'].search([('id','=',int(segment.operation_id))]) # partner_count=self.count_partners_operation(operation) # operation.write({ # 'partner_count':partner_count # }) return res