from odoo import models, fields, api,_ from odoo.exceptions import UserError, ValidationError,Warning from psycopg2 import sql, DatabaseError from werkzeug import utils import json import logging import xlwt from io import BytesIO import base64 import csv import os,secrets _logger = logging.getLogger(__name__) class opendons_operation(models.Model): _name = 'opendons.operation' _description = 'opération marketing : mailing, emailing evenements' _inherit = ['mail.thread'] _check_company_auto = True #_order = "__last_update desc" code=fields.Char(string='Code',required=True, translate=True,track_visibility='always') name=fields.Char(string='Name',required=True, translate=True,copy=False,default='campagne',track_visibility='always') partner_count = fields.Integer(string="count",readonly=True) exported_date=fields.Date(string='Exported Date',track_visibility='always', readonly=True) partner_ids = fields.Many2many('res.partner', 'partner_operation_rel', 'partner_id', 'operation_id', string='partners') #contacts exclus de l'opération company_id = fields.Many2one( "res.company", string="Company", required=True, states={"exported": [("readonly", True)]}, default=lambda self: self.env.company ) partner_excl_ids=fields.Many2many('res.partner', 'partner_excl_operation_rel', 'partner_id', 'operation_id', string='excluded partners') chanel=fields.Selection([ ('mail', 'Mailing'), ('email', 'E-mailing'), ('event', 'Event'), ('face_to_face', 'Face to face')], 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') quantity = fields.Integer(string="quantity",readonly=True) @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 ) 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() batch_export_ids = fields.One2many( 'opendons.operation.batch_export', 'operation_id', string='batchs export', ) 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): tmstp=secrets.token_hex(16) csv_filename='/tmp/export_'+tmstp+'.csv' with open(csv_filename, mode='w') as file: writer = csv.writer(file, delimiter=',', quotechar='"', quoting=csv.QUOTE_MINIMAL) if self.chanel=='email': writer.writerow(['id','key','name','firstname','email','operation','segment']) if self.chanel=='mail': writer.writerow(['id','key','name','firstname','title','street','street2','city','cp','country_name','operation','segment']) #sélections des contacts res=self.select_partner_operation() segments=self.env['opendons.segment'].search(['&',('operation_id','=',self.id),('exclusion','=',False)]) #extraction des contacts sélectionnés sur chaque segment for seg in segments: if seg.partner_ids: for p in seg.partner_ids: #raise UserError(p) id=p.id key=p.key name=p.name firstname=p.firstname if p.firstname else '' street=p.street if p.street else '' street2=p.street2 if p.street2 else '' city=p.city if p.city else '' cp=p.zip if p.zip else '' country_name=p.country_id.name if p.country_id else '' title=p.title.name if p.title else '' operation=int(self.id) segment=int(seg.id) if self.chanel=='email': writer.writerow([id,key,name,firstname,email,operation,segment]) if self.chanel=='mail': writer.writerow([id,key,name,firstname,title,street,street2,city,cp,country_name,operation,segment]) with open(csv_filename, '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' self.exported_date=fields.Date.context_today(self) os.unlink(csv_filename) #raise Warning('Traitement terminé') return def select_partner_operation(self): # suppression selections précédemment calculées sur l'opération self.partner_ids=False self.partner_excl_ids=False #suppression des selections précédemment calculées sur sur les segments segments=self.env['opendons.segment'].search(['&',('operation_id','=',self.id),('exclusion','=',False)]) for seg in segments: seg.partner_ids=False segexcl=self.env['opendons.segment'].search(['&',('operation_id','=',self.id),('exclusion','=',True)]) segments=self.env['opendons.segment'].search(['&',('operation_id','=',self.id),('exclusion','=',False)],order='sequence asc') i=1 for sg in segments: if i==1: mailing_domain='["&","!",'+segexcl.mailing_domain[1:-1]+','+ sg.mailing_domain[1:-1]+']' #["&","!",["id","=",1],["id","=",2]] #["&","!",[["id","=",1]],[["id","=",1]]] #raise UserError(str(mailing_domain)) #try: partners=self.env['res.partner'].search(eval(mailing_domain)) #except: # raise UserError(mailing_domain) #ajouts des contact à l'opération self.partner_ids=partners #ajouts des contacts au segment sg.partner_ids=partners #sg_1=sg else: #on doit exclure tous les contacts qui pourraient être dans les segments précédent sg_up=self.env['opendons.segment'].search(['&',('operation_id','=',self.id),('sequence','<',int(sg.sequence))]) if len(sg_up)>1: str_domain='"&",' j=1 for s in sg_up: if j==1: str_domain=str_domain + s.mailing_domain[1:-1] else: str_domain= '"&",' + str_domain & s.mailing_domain[1:-1] j=j+1 str_domain=str_domain+',' else: str_domain='' mailing_domain='["&","!",'+str_domain+ segexcl.mailing_domain[1:-1]+',' +sg.mailing_domain[1:-1]+']' partners=self.env['res.partner'].search(eval(mailing_domain)) #ajouts des contact à l'opération self.partner_ids=partners #ajouts des contacts au segment sg.partner_ids=partners sg_1=sg i=i+1 self.exported_date=fields.Date.context_today(self, readonly=True) return True @api.model def create(self,vals): op=self.env['opendons.operation'].search(['&',('name','=',vals['name']),('company_id','=',int(self.env.user.company_id))]) if "company_id" in vals: self = self.with_company(vals["company_id"]) if op : raise Warning(_('name already exist')) 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 unlink(self): if self.state=='exported': raise UserError(_('it is impossible to delete the operation because his state is \'exported\'')) donation=self.env['donation.donation'].search([('operation_id','=',int(self.id))]) if donation:raise UserError(_('it is impossible to delete the operation because there are donations linked')) return super(opendons_operation,self).unlink() 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 def copy(self,default_values=None): vals={} vals['name']='copy of ' + self.name vals['chanel']=self.chanel vals['user_id']=self._uid vals['state']='draft' dup_operation=super(opendons_operation, self).create(vals) #on duplique les segment de l'opération for segment_id in self.segment_ids: #raise Warning(segment_id.id) seg=self.env['opendons.segment'].search([('id','=',int(segment_id.id))]) if seg: vals2={} vals2['operation_id']=dup_operation.id vals2['name']=seg.name vals2['mailing_domain']=seg.mailing_domain #dup_segment=super(opendons_segment,self).create(vals2) dup_segment=self.env['opendons.segment'].create(vals2) dup_operation.write({'segment_ids':[(4,dup_segment.id)]}) for ensemble_id in seg.ensemble_ids: ens=self.env['opendons.ensemble'].search([('id','=',int(ensemble_id.id))]) if ens: vals3={} vals3['segment_id']=dup_segment.id vals3['name']=ens.name vals3['mailing_domain']=ens.mailing_domain #dup_segment=super(opendons_segment,self).create(vals2) dup_ensemble=self.env['opendons.ensemble'].create(vals3) dup_segment.write({'ensemble_ids':[(4,dup_ensemble.id)]}) for request_id in ens.request_ids: req=self.env['opendons.request'].search([('id','=',int(request_id.id))]) if req: vals4={} vals4['ensemble_id']=dup_ensemble.id vals4['name']=req.name vals4['mailing_domain']=req.mailing_domain #dup_segment=super(opendons_segment,self).create(vals2) dup_request=self.env['opendons.request'].create(vals4) dup_ensemble.write({'request_ids':[(4,dup_request.id)]}) #rtn=super(opendons_operation,self).copy(default=default_values) return dup_operation class opendons_operation_batch_export(models.Model): _name = 'opendons.operation.batch_export' _description = 'lot export' name=fields.Char(string='Name',required=True,track_visibility='always') operation_id = fields.Many2one( 'opendons.operation', String='Operation', index=True, readonly=True, track_visibility='onchange', ondelete='cascade' )