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 from datetime import datetime,timedelta,date _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 asc" 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 q=0 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 email=p.email 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]) q=q+1 with open(csv_filename, 'r', encoding="utf-8") as f2: data = str.encode(f2.read(), 'utf-8') self.quantity=q self.csv_export=base64.encodestring(data) self.document_fname='operation'+str(self.id)+'.csv' self.exported_date=fields.Date.context_today(self) #generation des exports par lot for batch_export_id in self.batch_export_ids: batch_export_id.csv_export_batch() os.unlink(csv_filename) return True 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: if segexcl.mailing_domain: mailing_domain='["&","!",'+segexcl.mailing_domain[1:-1]+','+ sg.mailing_domain[1:-1]+']' else: mailing_domain='['+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 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='' if segexcl.mailing_domain: mailing_domain='["&","!",'+str_domain+ segexcl.mailing_domain[1:-1]+',' +sg.mailing_domain[1:-1]+']' else: mailing_domain='["&",'+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=datetime.now() 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