class payment_file_acc_voucher(models.TransientModel): _name = 'payment.file.acc.voucher' bank_id = fields.Many2one('res.bank', 'Banco', required=True) txt_binary = fields.Binary() txt_filename = fields.Char() @api.multi def generate_file(self): for record in self: file_txt = StringIO.StringIO() items = self._get_data()[0] for item in items: string = self.set_string(item) file_txt.write(upper(string)) out = base64.encodestring(file_txt.getvalue()) file_txt.close() record.txt_binary = out record.txt_filename = 'Pago_Proveedor(%s).txt' % datetime.now( ).strftime('%Y%m%d%H%M%S') return { 'name': 'Archivo Generado', 'view_type': 'form', 'view_mode': 'form', 'res_model': 'payment.file.acc.voucher', 'res_id': record.id, 'view_id': False, 'type': 'ir.actions.act_window', 'domain': [], 'target': 'new', 'context': self._context, } def set_string(self, value): space = str() if self.bank_id.bic == '10': return value['column1'] + '\t' + value['column2'] + '\t' + value['column3'] + '\t' + value['column4'] + '\t' + \ value['column5'] + '\t' + value['column6'] + '\t' + value['column7'] + '\t' + value['column8'][0: 41] + '\t' + value['column9'] + '\t' + value['column10'] + '\t' + \ value['column11'] + '\t' + value['column12'] + chr(13) + chr(10) elif self.bank_id.bic == '32': return value['column1'] + '\t' + value['column2'] + '\t' + value['column3'] + '\t' + value['column4'] + '\t' + \ value['column5'] + '\t' + value['column6'] + '\t' + value['column7'] + '\t' + value['column8'][0: 41] + '\t' + value['column9'] + '\t' + value['column10'] + '\t' + \ value['column11'] + '\t' + value['column12'] + chr(13) + chr(10) @api.one def _get_data(self): context = dict(self._context) ids = context['active_ids'] company = self.env['res.users'].browse(self._uid).company_id values = list() for statement in self.env['account.bank.statement'].browse(ids): if statement.to_partner: vals = { 'column1': 'PA', 'column2': statement.partner_id.part_number if not statement.partner_id.use_another_id else statement.partner_id.second_identification, 'column3': company.currency_id.name, 'column4': self.round_complete(statement.balance_start), 'column5': self.get_bank_data(statement, statement.bank_account)[0], 'column6': self.get_bank_data(statement, statement.bank_account)[1], 'column7': self.get_bank_data(statement, statement.bank_account)[2], 'column8': self.get_description(statement.name), 'column9': self.get_identification(statement.partner_id)[0], 'column10': self.get_identification(statement.partner_id)[1], 'column11': statement.partner_id.name, 'column12': statement.bank_account.bank_bic } values.append(vals) else: for line in statement.line_ids: if line.amount > 0.00: vals = { 'column1': 'PA', 'column2': line.partner_id.part_number if not line.partner_id.use_another_id else line.partner_id.second_identification, 'column3': company.currency_id.name, 'column4': self.round_complete(line.amount), 'column5': self.get_bank_data(statement, line.bank_account_id)[0], 'column6': self.get_bank_data(statement, line.bank_account_id)[1], 'column7': self.get_bank_data(statement, line.bank_account_id)[2], 'column8': self.get_description(line.ref), 'column9': self.get_identification(line.partner_id)[0], 'column10': self.get_identification(line.partner_id)[1], 'column11': line.partner_id.name, 'column12': line.bank_account_id.bank_bic } values.append(vals) return values def get_identification(self, partner): part_type = str() if partner.part_type == 'c': part_type = 'C' elif partner.part_type == 'r': part_type = 'R' return part_type, partner.part_number def get_description(self, ref): return ref def round_complete(self, value): if value < 0.00: value *= -1 value = round(value, 2) value *= 100 if len(str(value)) < 13: string_value = str(int(value)) while len(string_value) < 13: string_value = '0' + string_value return string_value return str(int(value)) def get_bank_data(self, statement, bank_account): if not statement.bank_account and statement.to_partner: raise except_orm( 'Error!!', 'El pago %s no tiene selccionada la cuenta bancaria de proveedor' % statement.name) type = 'CTA' type_account = str() if bank_account.state == 'AHO': type_account = 'AHO' elif bank_account.state == 'CTE': type_account = 'CTE' number = bank_account.acc_number return type, type_account, number
class ResPartner(models.Model): _inherit = 'res.partner' dom = "['|', " \ " ('on_contact' ,'!=', is_company )," \ " '|', " \ " '&', " \ " ('on_company' , '=', is_company )," \ " ('on_company' , '=', state=='perjur' )," \ " '&', " \ " ('on_merchant', '=', state=='pernat' )," \ " ('on_merchant', '=', is_company )]" fiscal_id_type = fields.Many2one( 'res.partner.idtype', string=u'Document Type', domain=dom, ) fiscal_id = fields.Char(string=u'Document ID', # compute='validateformatcopy', ) fiscal_id_doc = fields.Binary(string=u'Document Scan', help="Upload the supporting Document " "preferably as size-optimized PDF. " "This might " "help save disk space and PDF allows " "you to concatenate multiple documents.") @api.one @api.onchange( 'fiscal_id_type', 'fiscal_id', 'is_company', ) def validateformatcopy(self): # CASE: Current ID Type is not applicable on Merchant if self.is_company and self.state == 'pernat': if not self.fiscal_id_type.on_merchant: # Get the first valid ID type (remember: ordered by sequence) self.fiscal_id_type = self.env['res.partner.idtype'].search( [('on_merchant', '=', True)], limit=1).id self.fiscal_id = None # Reset ID value # CASE: Current ID Type is not applicable on Company if self.is_company and self.state == 'perjur': if not self.fiscal_id_type.on_company: # Get the first valid ID type (remember: ordered by sequence) self.fiscal_id_type = self.env['res.partner.idtype'].search( [('on_company', '=', True)], limit=1).id self.fiscal_id = None # Reset ID value # CASE: Current ID Type is not applicable on contact if not self.is_company: if not self.fiscal_id_type.on_contact: # Get the first valid ID type (remember: ordered by sequence) self.fiscal_id_type = self.env['res.partner.idtype'].search( [('on_contact', '=', True)], limit=1).id self.fiscal_id = None # Reset ID value # If everything is fine, call subclasses if self.fiscal_id_type and self.fiscal_id: # Function for String Operations res = self._validateandformatid() if res['output_type'] and res['output_id']: self.fiscal_id_type = res['output_type'] self.fiscal_id = res['output_id'] # Procedure for Copying self._copyid() def _validateandformatid(self): """ Hook method to be inherited for custom validation methods. :param input_type: the value of the field fiscal_id_type (id); passed on by onchange decorator :param input_id: the value of the field fiscal_id (string); passed on by onchange decorator :return: must return a dict with validated and formatted values Hint: you might not alter the output_type unless you might want to build some kind of fiscal_id_type recognition based on the input pattern into your hook method. CO###.###.###-# CO-VAT (NIT) for example. Find below a suggested basic outline. """ return { 'output_type': self.fiscal_id_type, 'output_id': self.fiscal_id } """ f_type = self.fiscal_id_type f_id = self.fiscal_id is_company = self.is_company def default(): return {'output_type': f_type, 'output_id': f_id} return { # Define your cases # The index to match is self.fiscal_id_type.code # Note: You can change this index below. # Example assignation using two functions # {'output_type': func_type1(), 'output_id': funct_id1()} 'CODE1': { "put your assignation here" }, 'CODE2': { "put your assignation here" }, }.get(self.fiscal_id_type.code, default()) """ def _copyid(self): """ Hook Method to be inherited for custom copy methods based on the document type (id) Example Use Case: Copy some local VAT number into the VAT-Field in it's international format for compatibility. :return: It is a Procedure and therefore has no return value. Find below a suggested basic outline. """ """
class fds_key_import_wizard(models.TransientModel): ''' FDS Postfinance keys import wizard. The goal is to import existing key in the database. This wizard is called when we click on import FDS authentication keys for one FDS. This Class inherit from fds_key_generator_wizard. ''' _name = 'fds.key.import.wizard' _inherit = 'fds.key.generator.wizard' public_key_import_txt = fields.Text(string='Public key', help='copy/paste your public key') private_key_import_txt = fields.Text(string='Private key', help='copy/paste your private key') public_key_import_file = fields.Binary( string='Public key', help='select one file that contain your public key') private_key_import_file = fields.Binary( string='Private key', help='select one file that contain your private key') ################################## # Button action # ################################## @api.multi def import_keys_button(self): ''' Import public and private key then save in the database. Called by pressing import button. :returns action: configuration for the next wizard's view :raises Warning: if missing input information ''' self.ensure_one() # check if authentication keys already exist self.userkey_exist() if self.private_key_import_file and self.public_key_import_file: # found 2 import file key return self._import_key('file') elif self.private_key_import_txt and self.public_key_import_txt: # found 2 import text key return self._import_key('text') elif self.private_key_import_file or self.public_key_import_file: # miss 1 import file key raise exceptions.Warning('Import key file missing') elif self.private_key_import_txt or self.public_key_import_txt: # miss 1 import text key raise exceptions.Warning('Import key text missing') else: raise exceptions.Warning('Import key not found') ############################## # function # ############################## @api.multi def _import_key(self, type): ''' private function that convert the keys depending on type, crypte and save in the database using inherit function (_savekeys). :param str type: type of the import "file" or "text" :returns action: configuration for the next wizard's view ''' self.ensure_one() # convert keys auth_key_obj = self.env['fds.authentication.keys'] if type == 'file': pub = base64.b64decode(self.public_key_import_file) ppk = base64.b64decode(self.private_key_import_file) elif type == 'text': pub = self.public_key_import_txt ppk = self.private_key_import_txt else: _logger.error("Bad implementation in fds_key_import_wizard") raise exceptions.Warning('Error code. Contact your admin') keys = auth_key_obj.import_pairkey(pub, ppk) # save values self.savekeys(keys[0], keys[1]) # change view wizard self.write({'state': 'generate'}) return self._do_populate_tasks()
class ftz_pos_order_import(models.Model): _name = 'ftz_pos_order_import.ftz_pos_order_import' # _description = 'Description' name = fields.Char( string='name', size=64, ) upload_file = fields.Binary(string='Upload File', ) @api.one def do_process(self): _logger.info("Import Started %s:%s" % ("1", "2")) curr_obj = self if not curr_obj.upload_file: raise UserError(_('Please Choose The File!')) file_name = curr_obj.name print "curr_obj.name here", curr_obj.name print "file namr here", file_name fname = str(file_name.split('.')[1]) print fname # if fname not in ['xls','xlsx']: # raise UserError(_('Please Choose The File With .xls or .xlsx extension and proper format!')) # try: # file=base64.decodestring(curr_obj.upload_file) # # fp = StringIO() # fp = BytesIO() # fp.write(file) # wb = xlrd.open_workbook(file_contents=fp.getvalue()) # wb.sheet_names() # sheet_name=wb.sheet_names() # sh = wb.sheet_by_index(0) # print sh # sh = wb.sheet_by_name(sheet_name[0]) # print sh # n_rows = sh.nrows file_data = self.upload_file.decode('base64') wb = xlrd.open_workbook(file_contents=file_data) sheet_names = wb.sheet_names() for sheet_name in sheet_names: sh = wb.sheet_by_name(sheet_name) num_cols = sh.ncols counter = 0 for row in range(0, sh.nrows): if counter == 0: continue print('-' * 40) print('Row: %s' % row) # Print row number for col in range(0, num_cols): # Iterate through columns cell_obj = sh.cell(row, col) # Get cell object by row, col print('Column: [%s] cell_obj: [%s]' % (col, cell_obj)) counter += 1 if counter > 10: break error @api.one @api.constrains('name') def _check_filename(self): if self.upload_file: if not self.name: raise ValidationError(_("There is no file")) else: # Check the file's extension tmp = self.name.split('.') ext = tmp[len(tmp) - 1] print ext print ext != 'xls' print ext != 'xlsx' print type(ext) print ext in ['xls', 'xlsx'] if not ext in ['xls', 'xlsx']: raise ValidationError(_("The file must be a excel file"))
return self._logo_image finally: image_file.close() else: self._logo_image = base64.encodestring(im.read()) return self._logo_image @api.one def _get_image_fn(recs): image = recs._get_image() for rec in recs: rec.config_logo = image ### Fields link = fields.Char('Original developer', size=128, readonly=True) config_logo = fields.Binary(compute='_get_image_fn', string='Image') ### ends Fields _defaults = { 'config_logo': _get_image, 'link': 'http://www.alistek.com', } class docs_config_installer(models.TransientModel): _name = 'docs_config.installer' _inherit = 'res.config.installer' _rec_name = 'host' _logo_image = None @api.cr_uid_context
class home_page(models.Model): _name = "home.page" _rec_name = "action" sequence = fields.Integer(u'序列') action = fields.Many2one('ir.actions.act_window', string=u'快捷页面', required='1') view_id = fields.Many2one('ir.ui.view', string=u'对应的视图') image = fields.Binary(u"显示的图片") menu_type = fields.Selection([(u'main', u'主菜单'), (u'top', u'金额汇总'), (u'left', u'快速查看')], string=u'类型', required="1") domain = fields.Char(u'页面的过滤', default='[]') note_one = fields.Char(u'第一个显示名称') compute_field_one = fields.Many2one('ir.model.fields', string=u'需要计算的字段') note_two = fields.Char(u'显示名称') compute_field_two = fields.Many2one('ir.model.fields', string=u'需要计算的字段') compute_type = fields.Selection([(u'sum', u'sum'), (u'average', u'average')], default="sum", string=u"计算类型") context = fields.Char(u'动作的上下文') @api.onchange('action') def onchange_action(self): if self.action: return { 'domain': {'view_id': [('model', '=', self.action.res_model), ('type', '=', 'tree')], } } @api.model def get_action_url(self): action_url_lsit = {'main': [], 'top': [], 'right': []} action_list = self.env['home.page'].search([(1, '=', 1), ('sequence', '!=', 0)], order='sequence') for action in action_list: if action: if action.menu_type == 'main': action_url_lsit['main'].append([action.note_one, action.action.view_mode, action.action.res_model, action.action.domain, action.id, action.action.context, action.view_id.id, action.action.name]) elif action.menu_type == 'top': note = "" res_model_objs = self.env[action.action.res_model].search(eval(action.domain or '[]')) if action.compute_field_one and action.compute_field_two: note = "%s %s <br\> %s %s" % (action.note_one, sum([res_model_obj[action.compute_field_one.name] for res_model_obj in res_model_objs]), action.note_two, sum([res_model_obj[action.compute_field_two.name] for res_model_obj in res_model_objs])) elif action.compute_field_one or action.compute_field_two: field_compute, note = "", "" if action.compute_field_one: field_compute = action.compute_field_one.name note = action.note_one else: field_compute = action.compute_field_two.name note = action.note_two note = "%s %s" % (note, sum([res_model_obj[field_compute] for res_model_obj in res_model_objs])) else: note = "%s %s" % (action.note_one, sum([1 for res_model_obj in res_model_objs])) action_url_lsit['top'].append([note, action.action.view_mode, action.action.res_model, action.domain, action.context, action.view_id.id, action.action.name]) else: res_model_objs = self.env[action.action.res_model].search(eval(action.domain or '[]')) action_url_lsit['right'].append(["%s %s" % (action.note_one, sum([1 for res_model_obj in res_model_objs])), action.action.view_mode, action.action.res_model, action.domain, action.context, action.view_id.id, action.action.name]) return action_url_lsit
class HrOrientationChecklist(models.Model): _name = 'hr.orientation.checklist' _inherit = ['mail.thread', 'ir.needaction_mixin'] _order = 'id asc' _rec_name = 'name' _description = "Employee Course Modules" name = fields.Char(string='Name', required=True, readonly=True) responsible_user_id = fields.Many2one( 'res.users', string='Responsible User', required=True, ) checklist_state = fields.Selection( selection=[('new', 'Ungraded'), \ ('done', 'Completed'),\ ('pass', 'Passed'),\ ('fail', 'Failed'),\ ('cancel', 'Cancelled')], string='Status', copy=False, default='new', track_visibility='onchange' ) checklist_date = fields.Date(string='Date', readonly=True) expected_date = fields.Date( string='Expected Date', default=fields.Date.today(), required=True, ) orientation_id = fields.Many2one( 'hr.orientation', string='Training', readonly=True, ) company_id = fields.Many2one('res.company', default=lambda self: self.env.user.company_id, string='Company', readonly=True) note = fields.Text( string='Notes', #related='orientation_id.main_configuration_id.main_checklist_ids.note', readonly=True, store=True, ) attachment_ids1 = fields.Binary( string='First Attachment', #related='orientation_id.main_configuration_id.main_checklist_ids.attachment_ids1', readonly=True, store=True, ) attachment_ids2 = fields.Binary( string='Second Attachment', #related='orientation_id.main_configuration_id.main_checklist_ids.attachment_ids2', readonly=True, store=True, ) attachment_ids3 = fields.Binary( string='Third Attachment', #related='orientation_id.main_configuration_id.main_checklist_ids.attachment_ids3', readonly=True, store=True, ) employee_id = fields.Many2one( related='orientation_id.employee_id', string='Employee User', readonly=True, store=True, ) x_orientation_checklist_id = fields.Many2one( 'hr.orientation.checklist.config', string='Course Module ID', store=True, readyonly=True) web_url = fields.Char( string='Web URL', readonly=True, ) survey_id = fields.Many2one('survey.survey', String='Test/Exam', store=True, readonly=True) supervisor = fields.Many2one(related='orientation_id.user_id', String='Supervisor Name', store=True, readonly=True) response_id = fields.Many2one( 'survey.user_input', "Response", ondelete="set null", oldname="response", store=True, readonly=True, ) survey_score = fields.Float(related='response_id.quizz_score', String='Test Score', store=True, readonly=True) @api.one def process_survey_result(self): if self.survey_score == 0: self.write({ 'checklist_state': 'new', }) elif (self.survey_score > 0) and (self.survey_score < 8): self.write({ 'checklist_state': 'fail', }) elif self.survey_score >= 8: self.write({ 'checklist_state': 'pass', }) @api.multi def action_start_survey(self): self.ensure_one() # create a response and link it to this applicant if not self.response_id: response = self.env['survey.user_input'].create({ 'survey_id': self.survey_id.id, 'responsible_user_id': self.responsible_user_id.id }) self.response_id = response.id else: response = self.response_id # grab the token of the response and start surveying return self.survey_id.with_context( survey_token=response.token).action_start_survey() @api.multi def action_print_survey(self): """ If response is available then print this response otherwise print survey form (print template of the survey) """ self.ensure_one() if not self.response_id: return self.survey_id.action_print_survey() else: response = self.response_id return self.survey_id.with_context( survey_token=response.token).action_print_survey()
class Image(models.Model): _name = "base_multi_image.image" _order = "sequence, owner_model, owner_id, id" _sql_constraints = [ ('uniq_name_owner', 'UNIQUE(owner_id, owner_model, name)', _('A document can have only one image with the same name.')), ] owner_id = fields.Integer("Owner", required=True) owner_model = fields.Char(required=True) storage = fields.Selection([('url', 'URL'), ('file', 'OS file'), ('db', 'Database')], required=True) name = fields.Char('Image title', translate=True) filename = fields.Char() extension = fields.Char('File extension', readonly=True) file_db_store = fields.Binary('Image stored in database', filters='*.png,*.jpg,*.gif') path = fields.Char("Image path", help="Image path") url = fields.Char('Image remote URL') image_main = fields.Binary("Full-sized image", compute="_get_image") image_medium = fields.Binary( "Medium-sized image", compute="_get_image_sizes", help="Medium-sized image. It is automatically resized as a " "128 x 128 px image, with aspect ratio preserved, only when the " "image exceeds one of those sizes. Use this field in form views " "or kanban views.") image_small = fields.Binary( "Small-sized image", compute="_get_image_sizes", help="Small-sized image. It is automatically resized as a 64 x 64 px " "image, with aspect ratio preserved. Use this field anywhere a " "small image is required.") comments = fields.Text('Comments', translate=True) sequence = fields.Integer(default=10) show_technical = fields.Boolean(compute="_show_technical") @api.multi @api.depends('storage', 'path', 'file_db_store', 'url') def _get_image(self): """Get image data from the right storage type.""" for s in self: s.image_main = getattr(s, "_get_image_from_%s" % s.storage)() @api.multi @api.depends("owner_id", "owner_model") def _show_technical(self): """Know if you need to show the technical fields.""" self.show_technical = all("default_owner_%s" % f not in self.env.context for f in ("id", "model")) @api.multi def _get_image_from_db(self): return self.file_db_store @api.multi def _get_image_from_file(self): if self.path and os.path.exists(self.path): try: with open(self.path, 'rb') as f: return base64.b64encode(f.read()) except Exception as e: _logger.error("Can not open the image %s, error : %s", self.path, e, exc_info=True) else: _logger.error("The image %s doesn't exist ", self.path) return False @api.multi def _get_image_from_url(self): return self._get_image_from_url_cached(self.url) @api.model @tools.ormcache(skiparg=1) def _get_image_from_url_cached(self, url): """Allow to download an image and cache it by its URL.""" if url: try: (filename, header) = urllib.urlretrieve(url) with open(filename, 'rb') as f: return base64.b64encode(f.read()) except: _logger.error("URL %s cannot be fetched", url, exc_info=True) return False @api.multi @api.depends('image_main') def _get_image_sizes(self): for s in self: try: image = s.with_context(bin_size=False).image_main vals = dict() vals["image_medium"] = tools.image_resize_image_medium( image, size=(300, 300)) vals["image_small"] = tools.image_resize_image_small(image) except: vals = {"image_medium": False, "image_small": False} s.update(vals) @api.model def _make_name_pretty(self, name): return name.replace('_', ' ').capitalize() @api.onchange('url') def _onchange_url(self): if self.url: filename = self.url.split('/')[-1] self.name, self.extension = os.path.splitext(filename) self.name = self._make_name_pretty(self.name) @api.onchange('path') def _onchange_path(self): if self.path: self.name, self.extension = os.path.splitext( os.path.basename(self.path)) self.name = self._make_name_pretty(self.name) @api.onchange('filename') def _onchange_filename(self): if self.filename: self.name, self.extension = os.path.splitext(self.filename) self.name = self._make_name_pretty(self.name) @api.constrains('storage', 'url') def _check_url(self): if self.storage == 'url' and not self.url: raise exceptions.ValidationError( 'You must provide an URL for the image.') @api.constrains('storage', 'path') def _check_path(self): if self.storage == 'file' and not self.path: raise exceptions.ValidationError( 'You must provide a file path for the image.') @api.constrains('storage', 'file_db_store') def _check_store(self): if self.storage == 'db' and not self.file_db_store: raise exceptions.ValidationError( 'You must provide an attached file for the image.')
class ImportInventory(models.TransientModel): _name = 'import.inventory' _description = 'Import inventory' def _get_default_location(self): ctx = self._context if 'active_id' in ctx: inventory_obj = self.env['stock.inventory'] inventory = inventory_obj.browse(ctx['active_id']) return inventory.location_id data = fields.Binary('File', required=True) name = fields.Char('Filename') delimeter = fields.Char('Delimeter', default=',', help='Default delimeter is ","') location = fields.Many2one('stock.location', 'Default Location', default=_get_default_location, required=True) @api.one def action_import(self): """Load Inventory data from the CSV file.""" ctx = self._context stloc_obj = self.env['stock.location'] inventory_obj = self.env['stock.inventory'] inv_imporline_obj = self.env['stock.inventory.import.line'] product_obj = self.env['product.product'] if 'active_id' in ctx: inventory = inventory_obj.browse(ctx['active_id']) if not self.data: raise exceptions.Warning(_("You need to select a file!")) # Decode the file data data = base64.b64decode(self.data) file_input = cStringIO.StringIO(data) file_input.seek(0) location = self.location reader_info = [] if self.delimeter: delimeter = str(self.delimeter) else: delimeter = ',' reader = csv.reader(file_input, delimiter=delimeter, lineterminator='\r\n') try: reader_info.extend(reader) except Exception: raise exceptions.Warning(_("Not a valid file!")) keys = reader_info[0] # check if keys exist if not isinstance(keys, list) or ('code' not in keys or 'quantity' not in keys): raise exceptions.Warning(_("Not 'code' or 'quantity' keys found")) del reader_info[0] values = {} actual_date = fields.Date.today() inv_name = self.name + ' - ' + actual_date inventory.write({ 'name': inv_name, 'date': fields.Datetime.now(), 'imported': True, 'state': 'confirm' }) for i in range(len(reader_info)): val = {} field = reader_info[i] values = dict(zip(keys, field)) prod_location = location.id if 'location' in values and values['location']: locations = stloc_obj.search([('name', '=', values['location']) ]) prod_location = locations[:1].id prod_lst = product_obj.search([('default_code', '=', values['code'])]) if prod_lst: val['product'] = prod_lst[0].id if 'lot' in values and values['lot']: val['lot'] = values['lot'] val['code'] = values['code'] val['quantity'] = values['quantity'] val['location_id'] = prod_location val['inventory_id'] = inventory.id val['fail'] = True val['fail_reason'] = _('No processed') inv_imporline_obj.create(val)
class PostlogisticsConfigSettings(models.TransientModel): _name = 'postlogistics.config.settings' _inherit = 'res.config.settings' def _default_company(self): return self.env.user.company_id company_id = fields.Many2one(comodel_name='res.company', string='Company', required=True, default=_default_company) wsdl_url = fields.Char(related='company_id.postlogistics_wsdl_url') username = fields.Char(related='company_id.postlogistics_username') password = fields.Char(related='company_id.postlogistics_password') license_ids = fields.One2many( related='company_id.postlogistics_license_ids', ) logo = fields.Binary(related='company_id.postlogistics_logo') office = fields.Char(related='company_id.postlogistics_office') default_label_layout = fields.Many2one( related='company_id.postlogistics_default_label_layout', ) default_output_format = fields.Many2one( related='company_id.postlogistics_default_output_format', ) default_resolution = fields.Many2one( related='company_id.postlogistics_default_resolution', ) @api.onchange('company_id') def onchange_company_id(self): # update related fields if not self.company_id: return company = self.company_id licenses = company.postlogistics_license_ids label_layout = company.postlogistics_default_label_layout output_format = company.postlogistics_default_output_format resolution = company.postlogistics_default_resolution self.username = company.postlogistics_username self.password = company.postlogistics_password self.license_ids = licenses self.logo = company.postlogistics_logo self.office = company.postlogistics_office self.default_label_layout = label_layout self.default_output_format = output_format self.default_resolution = resolution @api.model def _get_delivery_instructions(self, web_service, company, service_code): lang = self.env.context.get('lang', 'en') service_code_list = service_code.split(',') res = web_service.read_delivery_instructions(company, service_code_list, lang) if 'errors' in res: errors = '\n'.join(res['errors']) error_message = (_('Could not retrieve Postlogistics delivery' 'instructions:\n%s') % errors) raise exceptions.Warning(error_message) if not res['value']: return {} if hasattr(res['value'], 'Errors') and res['value'].Errors: for error in res['value'].Errors.Error: message = '[%s] %s' % (error.Code, error.Message) raise exceptions.Warning(message) delivery_instructions = {} for service in res['value'].DeliveryInstructions: service_code = service.PRZL delivery_instructions[service_code] = {'name': service.Description} return delivery_instructions @api.model def _update_delivery_instructions(self, web_service, additional_services): carrier_option_obj = self.env['delivery.carrier.template.option'] xmlid = 'delivery_carrier_label_postlogistics.postlogistics' postlogistics_partner = self.env.ref(xmlid) for service_code, data in additional_services.iteritems(): options = carrier_option_obj.search([('code', '=', service_code), ('postlogistics_type', '=', 'delivery')]) if options: options.write(data) else: data.update(code=service_code, postlogistics_type='delivery', partner_id=postlogistics_partner.id) carrier_option_obj.create(data) lang = self.env.context.get('lang', 'en') _logger.info("Updated delivery instructions. [%s]", lang) @api.model def _get_additional_services(self, web_service, company, service_code): lang = self.env.context.get('lang', 'en') service_code_list = service_code.split(',') res = web_service.read_additional_services(company, service_code_list, lang) if 'errors' in res: errors = '\n'.join(res['errors']) error_message = (_('Could not retrieve Postlogistics base ' 'services:\n%s') % errors) raise exceptions.Warning(error_message) if not res['value']: return {} if hasattr(res['value'], 'Errors') and res['value'].Errors: for error in res['value'].Errors.Error: message = '[%s] %s' % (error.Code, error.Message) raise exceptions.Warning(message) additional_services = {} for service in res['value'].AdditionalService: service_code = service.PRZL additional_services[service_code] = {'name': service.Description} return additional_services @api.model def _update_additional_services(self, web_service, additional_services): carrier_option_obj = self.env['delivery.carrier.template.option'] xmlid = 'delivery_carrier_label_postlogistics.postlogistics' postlogistics_partner = self.env.ref(xmlid) for service_code, data in additional_services.iteritems(): options = carrier_option_obj.search([('code', '=', service_code), ('postlogistics_type', '=', 'additional')]) if options: options.write(data) else: data.update(code=service_code, postlogistics_type='additional', partner_id=postlogistics_partner.id) carrier_option_obj.create(data) lang = self.env.context.get('lang', 'en') _logger.info("Updated additional services [%s]", lang) @api.model def _update_basic_services(self, web_service, company, group): """ Update of basic services A basic service can be part only of one service group :return: {additional_services: {<service_code>: service_data} delivery_instructions: {<service_code>: service_data} } """ carrier_option_obj = self.env['delivery.carrier.template.option'] xmlid = 'delivery_carrier_label_postlogistics.postlogistics' postlogistics_partner = self.env.ref(xmlid) lang = self.env.context.get('lang', 'en') res = web_service.read_basic_services(company, group.group_extid, lang) if 'errors' in res: errors = '\n'.join(res['errors']) error_message = (_('Could not retrieve Postlogistics base ' 'services:\n%s') % errors) raise exceptions.Warning(error_message) additional_services = {} delivery_instructions = {} # Create or update basic service for service in res['value'].BasicService: service_code = ','.join(service.PRZL) options = carrier_option_obj.search([ ('code', '=', service_code), ('postlogistics_service_group_id', '=', group.id), ('postlogistics_type', '=', 'basic') ]) data = {'name': service.Description} if options: options.write(data) option = options[0] else: data.update(code=service_code, postlogistics_service_group_id=group.id, partner_id=postlogistics_partner.id, postlogistics_type='basic') option = carrier_option_obj.create(data) # Get related services allowed_services = self._get_additional_services( web_service, company, service_code) for key, value in additional_services.iteritems(): if key in allowed_services: field = 'postlogistics_basic_service_ids' additional_services[key][field][0][2].append(option.id) del allowed_services[key] for key, value in allowed_services.iteritems(): field = 'postlogistics_basic_service_ids' value[field] = [(6, 0, [option.id])] additional_services[key] = value allowed_services = self._get_delivery_instructions( web_service, company, service_code) for key, value in delivery_instructions.iteritems(): if key in allowed_services: field = 'postlogistics_basic_service_ids' delivery_instructions[key][field][0][2].append(option.id) del allowed_services[key] for key, value in allowed_services.iteritems(): field = 'postlogistics_basic_service_ids' value[field] = [(6, 0, [option.id])] delivery_instructions[key] = value _logger.info("Updated '%s' basic service [%s].", group.name, lang) return { 'additional_services': additional_services, 'delivery_instructions': delivery_instructions } @api.model def _update_service_groups(self, web_service, company): """ Also updates additional services and delivery instructions as they are shared between groups """ service_group_obj = self.env['postlogistics.service.group'] lang = self.env.context.get('lang', 'en') res = web_service.read_service_groups(company, lang) if 'errors' in res: errors = '\n'.join(res['errors']) error_message = (_('Could not retrieve Postlogistics group ' 'services:\n%s') % errors) raise exceptions.Warning(error_message) additional_services = {} delivery_instructions = {} # Create or update groups for group in res['value'].ServiceGroup: group_extid = group.ServiceGroupID groups = service_group_obj.search( [('group_extid', '=', group_extid)], ) data = {'name': group.Description} if groups: groups.write(data) group = groups[0] else: data['group_extid'] = group_extid group = service_group_obj.create(data) # Get related services for all basic services of this group res = self._update_basic_services(web_service, company, group) allowed_services = res.get('additional_services', {}) for key, value in additional_services.iteritems(): if key in allowed_services: field = 'postlogistics_basic_service_ids' option_ids = allowed_services[key][field][0][2] additional_services[key][field][0][2].extend(option_ids) del allowed_services[key] additional_services.update(allowed_services) allowed_services = res.get('delivery_instructions', {}) for key, value in delivery_instructions.iteritems(): if key in allowed_services: field = 'postlogistics_basic_service_ids' option_ids = allowed_services[key][field][0][2] delivery_instructions[key][field][0][2].extend(option_ids) del allowed_services[key] delivery_instructions.update(allowed_services) # Update related services self._update_additional_services(web_service, additional_services) self._update_delivery_instructions( web_service, delivery_instructions, ) @api.multi def update_postlogistics_options(self): """ This action will update all postlogistics option by importing services from PostLogistics WebService API The object we create are 'delivey.carrier.template.option' """ for config in self: company = config.company_id web_service = PostlogisticsWebService(company) # make sure we create source text in en_US ctx = self.env.context.copy() ctx['lang'] = 'en_US' self._update_service_groups(web_service, company) language_obj = self.env['res.lang'] languages = language_obj.search([]) # handle translations # we call the same method with a different language context for lang in languages: lang_code = lang.code postlogistics_lang = web_service._get_language(lang_code) # add translations only for languages that exists on # postlogistics, english source will be kept for other # languages if postlogistics_lang == 'en': continue self.with_context(lang=lang_code)._update_service_groups( web_service, company) return True @api.model def _get_allowed_service_group_codes(self, web_service, company, cp_license): """ Get a list of allowed service group codes""" lang = self.env.context.get('lang', 'en') res = web_service.read_allowed_services_by_franking_license( cp_license.number, company, lang) if 'errors' in res: errors = '\n'.join(res['errors']) error_message = (_('Could not retrieve allowed Postlogistics ' 'service groups for the %s licence:\n%s') % (cp_license.name, errors)) raise exceptions.Warning(error_message) if not res['value']: return [] if hasattr(res['value'], 'Errors') and res['value'].Errors: for error in res['value'].Errors.Error: message = '[%s] %s' % (error.Code, error.Message) raise exceptions.Warning(message) service_group_codes = [] for group in res['value'].ServiceGroups: service_group_codes.append(group.ServiceGroup.ServiceGroupID) return service_group_codes @api.multi def assign_licenses_to_service_groups(self): """ Check all licenses to assign it to PostLogistics service groups """ service_group_obj = self.env['postlogistics.service.group'] license_obj = self.env['postlogistics.license'] for config in self: company = config.company_id web_service = PostlogisticsWebService(company) relations = {} for cp_license in company.postlogistics_license_ids: service_groups = self._get_allowed_service_group_codes( web_service, company, cp_license) groups = service_group_obj.search( [('group_extid', 'in', service_groups)], ) for group in groups: relations.setdefault(group, license_obj.browse()) relations[group] |= cp_license for group, licenses in relations.iteritems(): vals = {'postlogistics_license_ids': [(6, 0, licenses.ids)]} group.write(vals) return True
class SriTaxForm(models.Model): _name = 'l10n_ec_sri.tax.form' _order = 'formulario' state = fields.Selection([ ('draft', 'Borrador'), ('done', 'Presentado'), ('replaced', 'Sustituido'), ], string='Estado', default='draft', ) formulario = fields.Selection([ ('101', '101'), ('103', '103'), ('104', '104'), ('ats', 'Anexo Transaccional'), ]) sri_tax_form_set_id = fields.Many2one( 'l10n_ec_sri.tax.form.set', ondelete='cascade', string="Tax Form Set", ) date_from = fields.Date( 'Desde', related='sri_tax_form_set_id.date_from', ) date_to = fields.Date( 'Hasta', related='sri_tax_form_set_id.date_to', ) sri_tax_form_line_ids = fields.One2many( 'l10n_ec_sri.tax.form.line', inverse_name='sri_tax_form_id', string='Tax declarations', ) payment_ids = fields.Many2many( 'account.payment', 'payment_tax_form_rel', 'payment_ids', 'tax_form_ids', string="Payments", ) move_ids = fields.Many2many( 'account.move', 'move_tax_form_rel', 'move_ids', 'tax_form_ids', string="Move", ) xml_file = fields.Binary('Archivo XML', attachment=True, readonly=True, ) xml_filename = fields.Char(string="Archivo XML") declarar_facturas_electronicas = fields.Boolean( string='Declarar facturas electronicas', default=False, ) @api.multi def prepare_ats(self): """ Método para ser heredado. :return: dict con valores del ATS """ for f in self: inv = self.env['account.invoice'] form_set = f.sri_tax_form_set_id # Para generar los datos de ventas ventas = form_set.out_invoice_ids tipoem = ['F'] if f.declarar_facturas_electronicas: tipoem = list(set(ventas.mapped('tipoem'))) if 'F' in tipoem: f.declarar_facturas_electronicas = False raise UserError(_( "No puede declarar las facturas electrónicas si" \ "tiene comprobantes de venta físicos emitidos." )) elif not f.declarar_facturas_electronicas: ventas = ventas.filtered(lambda x: x.tipoem == 'F') devoluciones = form_set.out_refund_ids if devoluciones and f.declarar_facturas_electronicas: tipoem = list(set(devoluciones.mapped('tipoem'))) if 'F' in tipoem: f.declarar_facturas_electronicas = False raise UserError(_( "No puede declarar las notas de crédito electrónicas" \ "si tiene notas de crédito físicas emitidas." )) elif not f.declarar_facturas_electronicas: devoluciones = devoluciones.filtered(lambda x: x.tipoem == 'F') tipoem = tipoem[0] detalleVentas = [] establecimientos = set( (ventas).mapped('establecimiento')) establecimientos = establecimientos - set(['999', False]) ventaEst = [] for e in establecimientos: if tipoem == 'E': e_ventas = 0.00 else: e_ventas = sum(ventas.filtered( lambda r: r.establecimiento == e).mapped('subtotal')) ventaEst.append(OrderedDict([ ('codEstab', e), ('ventasEstab', '{:.2f}'.format(e_ventas)), ('ivaComp', '{:.2f}'.format(0)), ])) totalVentas = sum(float(v['ventasEstab']) for v in ventaEst) numEstabRuc = str(len(ventaEst)).zfill(3) partners = (ventas + devoluciones).mapped('partner_id') # Necesitamos una segunda lista de partners para comparar los ya procesados. pending_partners = self.env['res.partner'] pending_partners += partners for p in partners: # Continuamos si el partner ya ha sido procesado. if p not in pending_partners: continue # Filtramos los partners por cédula y RUC vat = p.vat if vat and len(vat) == 13: id_fiscal = [vat, vat[:9]] elif vat and len(vat) == 10: id_fiscal = [vat, vat + '001'] else: id_fiscal = [vat] contribuyentes = self.env['res.partner'] contribuyentes = partners.filtered(lambda r: r.vat in id_fiscal) # Restamos los partners para evitar duplicar el cálculo. pending_partners -= contribuyentes fiscal = p.property_account_position_id identificacion = fiscal.identificacion_id tpidcliente = identificacion.tpidcliente vals = OrderedDict([ ('tpIdCliente', tpidcliente), ('idCliente', p.vat), ('parteRelVtas', p.parterel and 'SI' or 'NO') ]) if tpidcliente == '06': vals.update(OrderedDict([ ('tipoCliente', fiscal.persona_id.tpidprov), # Al declarar el ATS sale un error que indica que se debe # declarar DenoCli cuando el tipo es 06. # ('DenoCli', inv.normalize_text(p.name)) ])) # VENTAS p_ventas = ventas.filtered(lambda r: r.partner_id in contribuyentes) if p_ventas: t_ventas = p_ventas.mapped('sri_ats_line_ids') ventas -= p_ventas tipoEmision = tipoem fp_inv = p_ventas.filtered(lambda inv: inv.subtotal >= 1000) formaPago = [] if fp_inv: formaPago = list( set(fp_inv.mapped('payment_ids').mapped('formapago_id.code'))) if not formaPago: formaPago.append(p.formapago_id.code or '01') basenograiva = sum(t_ventas.mapped('basenograiva')) baseimponible = sum(t_ventas.mapped('baseimponible')) baseimpgrav = sum(t_ventas.mapped('baseimpgrav')) montoiva = sum(t_ventas.mapped('montoiva')) montoice = sum(t_ventas.mapped('montoice')) valorretiva = sum(t_ventas.mapped('valorretiva')) valorretrenta = sum(t_ventas.mapped('valorretrenta')) ventas_dict = OrderedDict() ventas_dict.update(vals) ventas_dict.update(OrderedDict([ ('tipoComprobante', '18'), ('tipoEmision', tipoEmision), ('numeroComprobantes', len(p_ventas)), ('baseNoGraIva', '{:.2f}'.format(abs(basenograiva))), ('baseImponible', '{:.2f}'.format(abs(baseimponible))), ('baseImpGrav', '{:.2f}'.format(abs(baseimpgrav))), ('montoIva', '{:.2f}'.format(abs(montoiva))), # TODO: Tipo y monto de compensaciones, por desarrollar. # ('tipoCompe', ''), # ('monto', '{:.2f}'.format(0)), ('montoIce', '{:.2f}'.format(abs(montoice))), ('valorRetIva', '{:.2f}'.format(abs(valorretiva))), ('valorRetRenta', '{:.2f}'.format(abs(valorretrenta))), ])) # Solo se declaran formasDePago en comprobantes de venta '18' if formaPago: ventas_dict.update([ ('formasDePago', {'formaPago': formaPago}) ]) detalleVentas.append(ventas_dict) # DEVOLUCIONES p_devoluciones = devoluciones.filtered( lambda r: r.partner_id in contribuyentes) if not p_devoluciones: continue t_devoluciones = p_devoluciones.mapped('sri_ats_line_ids') devoluciones -= p_devoluciones tipoEmision = tipoem basenograiva = sum(t_devoluciones.mapped('basenograiva')) baseimponible = sum(t_devoluciones.mapped('baseimponible')) baseimpgrav = sum(t_devoluciones.mapped('baseimpgrav')) montoiva = sum(t_devoluciones.mapped('montoiva')) montoice = sum(t_devoluciones.mapped('montoice')) valorretiva = sum(t_devoluciones.mapped('valorretiva')) valorretrenta = sum(t_devoluciones.mapped('valorretrenta')) devoluciones_dict = OrderedDict() devoluciones_dict.update(vals) devoluciones_dict.update(OrderedDict([ ('tipoComprobante', '04'), ('tipoEmision', tipoEmision), ('numeroComprobantes', len(p_devoluciones)), ('baseNoGraIva', '{:.2f}'.format(abs(basenograiva))), ('baseImponible', '{:.2f}'.format(abs(baseimponible))), ('baseImpGrav', '{:.2f}'.format(abs(baseimpgrav))), ('montoIva', '{:.2f}'.format(abs(montoiva))), ('montoIce', '{:.2f}'.format(abs(montoice))), ('valorRetIva', '{:.2f}'.format(abs(valorretiva))), ('valorRetRenta', '{:.2f}'.format(abs(valorretrenta))), ])) detalleVentas.append(devoluciones_dict) ventas = OrderedDict([ ('detalleVentas', detalleVentas), ]) ventasEstablecimiento = OrderedDict([ ('ventaEst', ventaEst), ]) # Para la información general del informante date = f.sri_tax_form_set_id.date_to company = self.env.user.company_id informante = company.partner_id fiscal = informante.property_account_position_id iva = OrderedDict([ ('TipoIDInformante', fiscal.identificacion_id.code), ('IdInformante', informante.vat), ('razonSocial', inv.normalize_text(informante.name)), ('Anio', datetime.strptime(date, '%Y-%m-%d').strftime('%Y')), ('Mes', datetime.strptime(date, '%Y-%m-%d').strftime('%m')) ]) if numEstabRuc != '000': iva.update(OrderedDict([ ('numEstabRuc', numEstabRuc) ])) iva.update(OrderedDict([ ('totalVentas', '{:.2f}'.format(totalVentas)) ])) iva.update(OrderedDict([ ('codigoOperativo', 'IVA') ])) # Diccionario de compras compras = form_set.in_invoice_ids + form_set.in_refund_ids detalleCompras = OrderedDict([('detalleCompras', [])]) for c in compras: detalleCompra = c.prepare_detallecompras_dict() for dc in detalleCompra: detalleCompras['detalleCompras'].append(dc) res = { 'iva': iva, 'ventas': ventas, 'ventasEstablecimiento': ventasEstablecimiento, 'compras': detalleCompras } return res @api.multi def get_ats_xml(self): decl = """<?xml version="1.0" encoding="UTF-8" standalone="no"?>""" for f in self: vals = f.prepare_ats() data = OrderedDict([ ('iva', vals['iva']), ]) data['iva'].update([ ('compras', vals['compras']) ]) if vals['ventas']['detalleVentas']: data['iva'].update([ ('ventas', vals['ventas']) ]) if vals['ventasEstablecimiento']['ventaEst']: data['iva'].update([ ('ventasEstablecimiento', vals['ventasEstablecimiento']) ]) xml_data = decl + \ xmltodict.unparse(data, pretty=True, full_document=False) f.write({'xml_filename': 'ATS.xml', 'xml_file': base64.encodestring(xml_data)}) @api.multi def get_tax_form_lines(self): for f in self: # Limpiamos las líneas de impuestos previamente creadas. f.sri_tax_form_line_ids.unlink() tax_form_lines = [] # Calculamos los impuestos en ventas. in_ref = f.sri_tax_form_set_id.mapped('in_refund_ids') in_inv = f.sri_tax_form_set_id.mapped('in_invoice_ids') purchases = in_inv + in_ref taxes = purchases.mapped('sri_tax_line_ids').filtered( lambda r: r.formulario == f.formulario) for t in set(taxes.mapped('campo')): facturas = in_inv.mapped('sri_tax_line_ids').filtered( lambda r: r.campo == t) devoluciones = in_ref.mapped( 'sri_tax_line_ids').filtered(lambda r: r.campo == t) bruto = sum(facturas.mapped('base')) neto = bruto - sum(devoluciones.mapped('base')) impuesto = sum(facturas.mapped('amount')) - \ sum(devoluciones.mapped('amount')) tax_form_lines.append({ 'sri_tax_form_id': f.id, 'campo': t, 'bruto': bruto, 'neto': neto, 'impuesto': impuesto, }) # Calculamos los impuestos en compras. out_inv = f.sri_tax_form_set_id.mapped('out_invoice_ids') out_ref = f.sri_tax_form_set_id.mapped('out_refund_ids') sale_inv = out_inv + out_ref taxes = sale_inv.mapped('sri_tax_line_ids').filtered( lambda r: r.formulario == f.formulario) for t in set(taxes.mapped('campo')): facturas = out_inv.mapped('sri_tax_line_ids').filtered( lambda r: r.campo == t) devoluciones = out_ref.mapped( 'sri_tax_line_ids').filtered(lambda r: r.campo == t) bruto = sum(facturas.mapped('base')) neto = bruto - sum(devoluciones.mapped('base')) impuesto = sum(facturas.mapped('amount')) - \ sum(devoluciones.mapped('amount')) tax_form_lines.append({ 'sri_tax_form_id': f.id, 'campo': t, 'bruto': bruto, 'neto': neto, 'impuesto': impuesto, }) for line in tax_form_lines: self.env['l10n_ec_sri.tax.form.line'].create(line)
class rbs_documento_mercantil_vehiculo(models.Model): _name = "rbs.documento.mercantil.vehiculo" _description = "Documento Mercantil Vehiculo" #name= field.Char('Nombre') anio_id = fields.Many2one('rbs.archivo.anio', string='Año', required=True) libro_id = fields.Many2one('rbs.archivo.libro', string='Libro', required=True) tomo_id = fields.Many2one("rbs.archivo.tomo", string='Tomo', required=True) persona_id = fields.Many2one('rbs.persona', string='Compareciente(n)') persona_nombres = fields.Char(string='Nombres del Compareciente') persona_apellidos = fields.Char(string='Apellidos del Compareciente') persona_cedula = fields.Char(string='Cedula del Compareciente') persona_representante = fields.Char( string='Representante del Compareciente') persona_razonSocial = fields.Char(string='Razon Social del Compareciente') foleo_desde = fields.Char(string='Desde', required=True) foleo_hasta = fields.Char(string='Hasta', required=True) tipo_compareciente_id = fields.Many2one('rbs.tipo.compareciente.v', string='Tipo de Compareciente') tipo_contrato_id = fields.Many2one('rbs.tipo.contrato', string='Tipo de Contrato', required=True) fecha_inscripcion = fields.Datetime(string='Fecha de Inscripcion', required=True) numero_inscripcion = fields.Char(string='Numero de Inscripcion', required=True) fecha_cancelacion = fields.Datetime(string='Fecha de Cancelacion') tipo_bien_id = fields.Many2one('rbs.tipo.bien', string='Tipo de Bien', required=True) chasis = fields.Char(string='Chasis') motor = fields.Char(string='Motor') marca = fields.Char(string='Marca') modelo = fields.Char(string='Modelo') anio_fabricacion = fields.Char(string='Año de Fabricacion') placa = fields.Char(string='Placa') ultima_modificacion = fields.Char(string='Ultima Modificacion') nombre_institucion = fields.Char(string='Nombre de la Institucion', required=True) canton_notaria = fields.Char(string='Canton de Notaria', required=True) fecha_escritura_contrato = fields.Datetime(string='Fecha de Escritura', required=True) estado = fields.Selection([ ('VIGENTE', 'VIGENTE'), ('NOVIGENTE', 'NO VIGENTE'), ], string='Estado', required=True) #filedata = fields.Binary('Archivo',filters='*.pdf') #filename = fields.Char('Nombre de archivo', default="Archivo.pdf") filedata_id = fields.Many2one('rbs.archivo.pdf') filedata = fields.Binary(related='filedata_id.filedata', filters='*.pdf') esPesado = fields.Boolean(related='filedata_id.esPesado', string='¿Es Pesado?') rutaFTP = fields.Char(related='filedata_id.rutaFTP', string='Escriba la ruta del Archivo') identificacion_unica = fields.Char( string='Identificador Unico Sistema Remoto', compute='_compute_upper', store=True) ubicacion_dato_id = fields.Many2one('rbs.ubicacion.dato', string='Ubicacion del Dato', required=True) factura_ids = fields.One2many('account.invoice', 'vehiculo_id', string='Factura') def _getUltimoAnio(self, cr, uid, context=None): acta_id = self.pool.get("rbs.documento.mercantil.vehiculo").search( cr, uid, [], limit=1, order='id desc') anio = self.pool.get("rbs.documento.mercantil.vehiculo").browse( cr, uid, acta_id, context=None).anio_id.id return anio def _getUltimoLibro(self, cr, uid, context=None): acta_id = self.pool.get("rbs.documento.mercantil.vehiculo").search( cr, uid, [], limit=1, order='id desc') libro = self.pool.get("rbs.documento.mercantil.vehiculo").browse( cr, uid, acta_id, context=None).libro_id.id return libro def _getUltimoTomo(self, cr, uid, context=None): acta_id = self.pool.get("rbs.documento.mercantil.vehiculo").search( cr, uid, [], limit=1, order='id desc') tomo = self.pool.get("rbs.documento.mercantil.vehiculo").browse( cr, uid, acta_id, context=None).tomo_id.id return tomo def _create_pdf(self, cr, uid, context=None): return self.pool.get("rbs.archivo.pdf").create(cr, uid, {}, context=None) _defaults = { 'anio_id': _getUltimoAnio, 'libro_id': _getUltimoLibro, 'tomo_id': _getUltimoTomo, 'filedata_id': _create_pdf, } def open_ui(self, cr, uid, ids, context=None): data = self.browse(cr, uid, ids[0], context=context) context = dict(context or {}) #context['active_id'] = data.ids[0] return { 'type': 'ir.actions.act_url', 'url': '/registro_mercantil/web/?binary=' + str(ids[0]) + '&tipo=vehiculo', 'target': 'current', } _rec_name = 'numero_inscripcion' @api.depends('ubicacion_dato_id', 'persona_cedula', 'numero_inscripcion') def _compute_upper(self): for rec in self: try: rec.identificacion_unica = '03' + rec.ubicacion_dato_id.name + rec.persona_cedula + rec.numero_inscripcion except: try: rec.identificacion_unica = '03' + rec.ubicacion_dato_id.name + rec.numero_inscripcion + rec.numero_inscripcion except: pass def on_change_anio_id(self, cr, uid, ids, anio_id, context=None): result = {} if (self._getUltimoAnio(cr, uid, context=None) != anio_id): result['libro_id'] = 0 return { 'value': result, } def on_change_libro_id(self, cr, uid, ids, libro_id, context=None): result = {} if (self._getUltimoLibro(cr, uid, context=None) != libro_id): result['tomo_id'] = 0 return { 'value': result, } def codigoascii(self, text): return unicode(text).encode('utf-8') def onchange_persona_id(self, cr, uid, ids, persona_id, context=None): persona_id = self.pool.get('rbs.persona').search( cr, uid, [ ('id', '=', persona_id), ]) persona = self.pool.get('rbs.persona').browse(cr, uid, persona_id, context=None) result = {} try: if persona: #raise osv.except_osv('Esto es un Mesaje!',establecimiento) try: if persona.persona_nombres: result['persona_nombres'] = self.codigoascii( persona.persona_nombres) except: pass try: if persona.persona_apellidos: result['persona_apellidos'] = self.codigoascii( persona.persona_apellidos) except: pass try: if persona.name: result['persona_cedula'] = str(persona.name) except: pass try: if persona.persona_representante: result['persona_representante'] = self.codigoascii( persona.persona_representante) except: pass try: if persona.persona_razonSocial: result['persona_razonSocial'] = self.codigoascii( persona.persona_razonSocial) except: pass except: pass return { 'value': result, } def onchange_inscripcion(self, cr, uid, ids, inscripcion_num, libro_id, context=None): vehiculo_id = self.pool.get('rbs.documento.mercantil.vehiculo').search( cr, uid, [('numero_inscripcion', '=', inscripcion_num), ('libro_id', '=', libro_id)]) vehiculo = self.pool.get('rbs.documento.mercantil.vehiculo').browse( cr, uid, vehiculo_id, context=None) result = {} try: if vehiculo: vehiculo = vehiculo[0] #raise osv.except_osv('Esto es un Mesaje!',establecimiento) try: if vehiculo.fecha_inscripcion: result['fecha_inscripcion'] = str( vehiculo.fecha_inscripcion) except: pass try: if vehiculo.anio_id: result['anio_id'] = vehiculo.anio_id.id except: pass try: if vehiculo.libro_id: result['libro_id'] = vehiculo.libro_id.id except: pass try: if vehiculo.tomo_id: result['tomo_id'] = vehiculo.tomo_id.id except: pass try: if vehiculo.tipo_contrato_id: result[ 'tipo_contrato_id'] = vehiculo.tipo_contrato_id.id except: pass try: if vehiculo.fecha_cancelacion: result['fecha_cancelacion'] = str( vehiculo.fecha_cancelacion) except: pass try: if vehiculo.tipo_bien_id: result['tipo_bien_id'] = vehiculo.tipo_bien_id except: pass try: if vehiculo.chasis: result['chasis'] = self.codigoascii(vehiculo.chasis) except: pass try: if vehiculo.motor: result['motor'] = self.codigoascii(vehiculo.motor) except: pass try: if vehiculo.marca: result['marca'] = self.codigoascii(vehiculo.marca) except: pass try: if vehiculo.modelo: result['modelo'] = self.codigoascii(vehiculo.modelo) except: pass try: if vehiculo.anio_fabricacion: result['anio_fabricacion'] = str( vehiculo.anio_fabricacion) except: pass try: if vehiculo.placa: result['placa'] = self.codigoascii(vehiculo.placa) except: pass try: if vehiculo.ultima_modificacion: result['ultima_modificacion'] = str( vehiculo.ultima_modificacion) except: pass try: if vehiculo.nombre_institucion: result['nombre_institucion'] = self.codigoascii( vehiculo.nombre_institucion) except: pass try: if vehiculo.canton_notaria: result['canton_notaria'] = self.codigoascii( vehiculo.canton_notaria) except: pass try: if vehiculo.fecha_escritura_contrato: result['fecha_escritura_contrato'] = str( vehiculo.fecha_escritura_contrato) except: pass try: if vehiculo.estado: result['estado'] = vehiculo.estado except: pass try: if vehiculo.filedata_id: result['filedata_id'] = vehiculo.filedata_id.id except: pass try: if vehiculo.ubicacion_dato_id: result[ 'ubicacion_dato_id'] = vehiculo.ubicacion_dato_id.id except: pass if not vehiculo: result['filedata_id'] = self._create_pdf(cr, uid, context=None) except: pass return { 'value': result, }
class DermanordImport(models.TransientModel): _name = 'sale.dermanord.import.wizard' order_file = fields.Binary(string='Order file') order_url = fields.Char(string='Url') mime = fields.Selection([ ('url', 'url'), ('text', 'text/plain'), ('pdf', 'application/pdf'), ('xlsx', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'), ('xls', 'application/vnd.ms-excel'), ('xlm', 'application/vnd.ms-office') ]) import_type = fields.Selection([('bangerhead', 'Bangerhead AB'), ('tailwide', 'Tailwide AB'), ('birka', u'BIRKA CRUISES AB'), ('nordicfeel', 'Nordic Web Trading AB'), ('isaksen', 'Isaksen & CO AS'), ('lyko', 'Lyko Online AB'), ('finamig', 'Fina mig i Hedemora AB'), ('skincity', 'Skincity Sweden'), ('skincity_xl', 'Skincity Sweden')]) info = fields.Text(string='Info') tmp_file = fields.Char(string='Tmp File') file_name = fields.Char(string='File Name') @api.one @api.onchange('order_file') def check_file(self): self.mime = None self.import_type = None self.info = None self.tmp_file = None if self.order_file: fd, self.tmp_file = tempfile.mkstemp() os.write(fd, base64.b64decode(self.order_file)) os.close(fd) try: pop = Popen(['file', '-b', '--mime', self.tmp_file], shell=False, stdout=PIPE) (result, _) = pop.communicate() read_mime = result.split(';')[0] except OSError, e: _logger.warning( "Failed attempt to execute file. This program is necessary to check MIME type of %s", fname) _logger.debug("Trace of the failed MIME file attempt.", exc_info=True) raise Warning(e) self.mime = self.get_selection_text('mime', read_mime) if self.mime == 'pdf': try: pop = Popen([ 'pdftotext', '-enc', 'UTF-8', '-nopgbrk', self.tmp_file, '-' ], shell=False, stdout=PIPE) (content, _) = pop.communicate() except OSError, e: _logger.warning( "Failed attempt to execute pdftotext. This program is necessary to index the file %s of MIME type %s. Detailed error available at DEBUG level.", self.tmp_file, self.mime) _logger.debug("Trace of the failed file indexing attempt.", exc_info=True) raise Warning(e) lines = content.splitlines() if len(lines) >= 19 and lines[19] == 'Fina mig i Hedemora AB': self.import_type = 'finamig' elif 'SKINCITY SWEDEN AB' in content: self.import_type = 'skincity' elif self.mime in ['xlsx', 'xls', 'xlm']: try: wb = open_workbook(file_contents=base64.b64decode( self.order_file)).sheet_by_index(0) except XLRDError, e: raise Warning(e)
class Importimage(models.Model): _name = 'image_recognizer.images' name = fields.Char(string="Title", required=True) imager = fields.Binary() datas = fields.Char() description = fields.Char() image_filename = fields.Char("DONDOLO") probability = fields.Float(string="Probability", compute='_probability') proba = fields.Float() @api.depends('probability') def _probability(self): for r in self: if not r.probability: r.probability = 0.0 else: r.proba = 100.0 * r.probability @api.onchange('imager') def _onchange_imager(self): datas = self.imager if datas: script_dir = os.path.dirname( __file__) # <-- absolute dir the script is in rel_path = "files/imagetorecognize.jpg" abs_file_path = os.path.join(script_dir, rel_path) imagesa = open(abs_file_path, "r+") imagesa.write(base64.b64decode(datas)) imagesa.close() class NodeLookup(object): def __init__(self, label_lookup_path=None, uid_lookup_path=None): if not label_lookup_path: label_lookup_path = os.path.join( FLAGS.model_dir, 'imagenet_2012_challenge_label_map_proto.pbtxt') if not uid_lookup_path: uid_lookup_path = os.path.join( FLAGS.model_dir, 'imagenet_synset_to_human_label_map.txt') self.node_lookup = self.load(label_lookup_path, uid_lookup_path) def load(self, label_lookup_path, uid_lookup_path): """Loads a human readable English name for each softmax node. Args: label_lookup_path: string UID to integer node ID. uid_lookup_path: string UID to human-readable string. Returns: dict from integer node ID to human-readable string. """ if not tf.gfile.Exists(uid_lookup_path): tf.logging.fatal('File does not exist %s', uid_lookup_path) if not tf.gfile.Exists(label_lookup_path): tf.logging.fatal('File does not exist %s', label_lookup_path) # Loads mapping from string UID to human-readable string proto_as_ascii_lines = tf.gfile.GFile( uid_lookup_path).readlines() uid_to_human = {} p = re.compile(r'[n\d]*[ \S,]*') for line in proto_as_ascii_lines: parsed_items = p.findall(line) uid = parsed_items[0] human_string = parsed_items[2] uid_to_human[uid] = human_string # Loads mapping from string UID to integer node ID. node_id_to_uid = {} proto_as_ascii = tf.gfile.GFile(label_lookup_path).readlines() for line in proto_as_ascii: if line.startswith(' target_class:'): target_class = int(line.split(': ')[1]) if line.startswith(' target_class_string:'): target_class_string = line.split(': ')[1] node_id_to_uid[target_class] = target_class_string[ 1:-2] # Loads the final mapping of integer node ID to human-readable string node_id_to_name = {} for key, val in node_id_to_uid.items(): if val not in uid_to_human: tf.logging.fatal('Failed to locate: %s', val) name = uid_to_human[val] node_id_to_name[key] = name return node_id_to_name def id_to_string(self, node_id): if node_id not in self.node_lookup: return '' return self.node_lookup[node_id] def create_graph(): """Creates a graph from saved GraphDef file and returns a saver.""" # Creates graph from saved graph_def.pb. with tf.gfile.FastGFile( os.path.join(FLAGS.model_dir, 'tensorflow_inception_graph.pb'), 'rb') as f: graph_def = tf.GraphDef() graph_def.ParseFromString(f.read()) _ = tf.import_graph_def(graph_def, name='') def run_inference_on_image(image): """Runs inference on an image. Args: image: Image file name. Returns: Nothing """ if not tf.gfile.Exists(image): tf.logging.fatal('File does not exist %s', image) image_data = tf.gfile.FastGFile(image, 'rb').read() # Creates graph from saved GraphDef. create_graph() with tf.Session() as sess: # Some useful tensors: # 'softmax:0': A tensor containing the normalized prediction across # 1000 labels. # 'pool_3:0': A tensor containing the next-to-last layer containing 2048 # float description of the image. # 'DecodeJpeg/contents:0': A tensor containing a string providing JPEG # encoding of the image. # Runs the softmax tensor by feeding the image_data as input to the graph. softmax_tensor = sess.graph.get_tensor_by_name('softmax:0') predictions = sess.run(softmax_tensor, {'DecodeJpeg/contents:0': image_data}) predictions = np.squeeze(predictions) # Creates node ID --> English string lookup. node_lookup = NodeLookup() top_k = predictions.argsort( )[-FLAGS.num_top_predictions:][::-1] for node_id in top_k: human_string = node_lookup.id_to_string(node_id) score = predictions[node_id] * 100 descript = human_string return descript, score parser = argparse.ArgumentParser() # classify_image_graph_def.pb: # Binary representation of the GraphDef protocol buffer. # imagenet_synset_to_human_label_map.txt: # Map from synset ID to a human readable string. # imagenet_2012_challenge_label_map_proto.pbtxt: # Text representation of a protocol buffer mapping a label to synset ID. parser.add_argument('--model_dir', type=str, default=os.path.join(os.path.dirname(__file__), 'files'), help="""\ Path to classify_image_graph_def.pb, imagenet_synset_to_human_label_map.txt, and imagenet_2012_challenge_label_map_proto.pbtxt.\ """) parser.add_argument('--image_file', type=str, default='', help='Absolute path to image file.') parser.add_argument('--num_top_predictions', type=int, default=1, help='Display this many predictions.') FLAGS, unparsed = parser.parse_known_args() image = (FLAGS.image_file if FLAGS.image_file else os.path.join( FLAGS.model_dir, "imagetorecognize.jpg")) if datas: self.name, self.probability = run_inference_on_image(image)
class PrintInvoiceSummary(models.TransientModel): _name = "print.invoice.summary" @api.model def _get_from_date(self): company = self.env.user.company_id current_date = datetime.date.today() from_date = company.compute_fiscalyear_dates(current_date)['date_from'] return from_date from_date = fields.Date(string='From Date', default=_get_from_date) to_date = fields.Date(string='To Date', default=datetime.date.today()) invoice_summary_file = fields.Binary('Invoice Summary Report') file_name = fields.Char('File Name') invoice_report_printed = fields.Boolean('Invoice Report Printed') invoice_status = fields.Selection([('all', 'All'), ('paid', 'Paid'), ('un_paid', 'Unpaid')], string='Invoice Status') @api.multi def action_print_invoice_summary(self): workbook = xlwt.Workbook() amount_tot = 0 column_heading_style = easyxf('font:height 200;font:bold True;') worksheet = workbook.add_sheet('Invoice Summary') worksheet.write( 2, 3, self.env.user.company_id.name, easyxf('font:height 200;font:bold True;align: horiz center;')) worksheet.write( 4, 2, self.from_date, easyxf('font:height 200;font:bold True;align: horiz center;')) worksheet.write( 4, 3, 'To', easyxf('font:height 200;font:bold True;align: horiz center;')) worksheet.write( 4, 4, self.to_date, easyxf('font:height 200;font:bold True;align: horiz center;')) worksheet.write(6, 0, _('Invoice Number'), column_heading_style) worksheet.write(6, 1, _('Customer'), column_heading_style) worksheet.write(6, 2, _('Invoice Date'), column_heading_style) worksheet.write(6, 3, _('Invoice Amount'), column_heading_style) worksheet.write(6, 4, _('Invoice Currency'), column_heading_style) worksheet.write( 6, 5, _('Amount in Company Currency (' + str(self.env.user.company_id.currency_id.name) + ')'), column_heading_style) worksheet.col(0).width = 5000 worksheet.col(1).width = 5000 worksheet.col(2).width = 5000 worksheet.col(3).width = 5000 worksheet.col(4).width = 5000 worksheet.col(5).width = 8000 worksheet2 = workbook.add_sheet('Customer wise Invoice Summary') worksheet2.write(1, 0, _('Customer'), column_heading_style) worksheet2.write(1, 1, _('Paid Amount'), column_heading_style) worksheet2.write( 1, 2, _('Invoice Currency'), easyxf('font:height 200;font:bold True;align: horiz left;')) worksheet2.write( 1, 3, _('Amount in Company Currency (' + str(self.env.user.company_id.currency_id.name) + ')'), easyxf('font:height 200;font:bold True;align: horiz left;')) worksheet2.col(0).width = 5000 worksheet2.col(1).width = 5000 worksheet2.col(2).width = 4000 worksheet2.col(3).width = 8000 row = 7 customer_row = 2 for wizard in self: customer_payment_data = {} heading = 'Invoice Summary Report' worksheet.write_merge( 0, 0, 0, 5, heading, easyxf( 'font:height 210; align: horiz center;pattern: pattern solid, fore_color black; font: color white; font:bold True;' "borders: top thin,bottom thin")) heading = 'Customer wise Invoice Summary' worksheet2.write_merge( 0, 0, 0, 3, heading, easyxf( 'font:height 200; align: horiz center;pattern: pattern solid, fore_color black; font: color white; font:bold True;' "borders: top thin,bottom thin")) if wizard.invoice_status == 'all': invoice_objs = self.env['account.invoice'].search([ ('date_invoice', '>=', wizard.from_date), ('date_invoice', '<=', wizard.to_date), ('type', '=', 'out_invoice'), ('state', 'not in', ['draft', 'cancel']) ]) elif wizard.invoice_status == 'paid': invoice_objs = self.env['account.invoice'].search([ ('date_invoice', '>=', wizard.from_date), ('date_invoice', '<=', wizard.to_date), ('state', '=', 'paid'), ('type', '=', 'out_invoice') ]) else: invoice_objs = self.env['account.invoice'].search([ ('date_invoice', '>=', wizard.from_date), ('date_invoice', '<=', wizard.to_date), ('state', '=', 'open'), ('type', '=', 'out_invoice') ]) for invoice in invoice_objs: amount = 0 for journal_item in invoice.move_id.line_id: amount += journal_item.debit worksheet.write(row, 0, invoice.number) worksheet.write(row, 1, invoice.partner_id.name) worksheet.write(row, 2, invoice.date_invoice) worksheet.write(row, 3, invoice.amount_total) worksheet.write(row, 4, invoice.currency_id.symbol) worksheet.write(row, 5, amount) amount_tot += amount row += 1 key = str(invoice.partner_id.name) + '_' + str( invoice.currency_id.name) if key not in customer_payment_data: customer_payment_data.update({ key: { 'amount_total': invoice.amount_total, 'amount_company_currency': amount } }) else: paid_amount_data = customer_payment_data[key][ 'amount_total'] + invoice.amount_total amount_currency = customer_payment_data[key][ 'amount_company_currency'] + amount customer_payment_data.update({ key: { 'amount_total': paid_amount_data, 'amount_company_currency': amount_currency } }) worksheet.write(row + 2, 5, amount_tot, column_heading_style) for customer in customer_payment_data: worksheet2.write(customer_row, 0, customer.split('_')[0]) worksheet2.write( customer_row, 1, customer_payment_data[customer]['amount_total']) worksheet2.write(customer_row, 2, customer.split('_')[1]) worksheet2.write( customer_row, 3, customer_payment_data[customer]['amount_company_currency']) customer_row += 1 fp = StringIO() workbook.save(fp) excel_file = base64.encodestring(fp.getvalue()) wizard.invoice_summary_file = excel_file wizard.file_name = 'Invoice Summary Report.xls' wizard.invoice_report_printed = True fp.close() return { 'view_mode': 'form', 'res_id': wizard.id, 'res_model': 'print.invoice.summary', 'view_type': 'form', 'type': 'ir.actions.act_window', 'context': self.env.context, 'target': 'new', }
class SaasPortalPlan(models.Model): _name = 'saas_portal.plan' name = fields.Char('Plan', required=True) summary = fields.Char('Summary') template_id = fields.Many2one('saas_portal.database', 'Template') demo = fields.Boolean('Install Demo Data') def _get_default_lang(self): return self.env.lang def _default_tz(self): return self.env.user.tz lang = fields.Selection(scan_languages(), 'Language', default=_get_default_lang) tz = fields.Selection(_tz_get, 'TimeZone', default=_default_tz) sequence = fields.Integer('Sequence') state = fields.Selection([('draft', 'Draft'), ('confirmed', 'Confirmed')], 'State', compute='_get_state', store=True) expiration = fields.Integer('Expiration (hours)', help='time to delete database. Use for demo') _order = 'sequence' dbname_template = fields.Char( 'DB Names', help= 'Template for db name. Use %i for numbering. Ignore if you use manually created db names', placeholder='crm-%i.odoo.com') server_id = fields.Many2one('saas_portal.server', string='SaaS Server', help='User this saas server or choose random') website_description = fields.Text('Website description') logo = fields.Binary('Logo') @api.one @api.depends('template_id.state') def _get_state(self): if self.template_id.state == 'template': self.state = 'confirmed' else: self.state = 'draft' @api.one def _new_database_vals(self, vals): if self.expiration: now = datetime.now() delta = timedelta(hours=self.expiration) vals['expiration_datetime'] = ( now + delta).strftime(DEFAULT_SERVER_DATETIME_FORMAT) return vals @api.multi def create_new_database(self, dbname=None, client_id=None, partner_id=None, user_id=None): self.ensure_one() server = self.server_id if not server: server = self.env['saas_portal.server'].get_saas_server() server.action_sync_server() vals = { 'name': dbname or self.generate_dbname()[0], 'server_id': server.id, 'plan_id': self.id, 'partner_id': partner_id, } client = None if client_id: vals['client_id'] = client_id client = self.env['saas_portal.client'].search([('client_id', '=', client_id)]) vals = self._new_database_vals(vals)[0] if client: client.write(vals) else: client = self.env['saas_portal.client'].create(vals) client_id = client.client_id scheme = server.request_scheme port = server.request_port if user_id: owner_user = self.env['res.users'].browse(user_id) else: owner_user = self.env.user owner_user_data = { 'user_id': owner_user.id, 'login': owner_user.login, 'name': owner_user.name, 'email': owner_user.email, } state = { 'd': client.name, 'e': client.expiration_datetime, 'r': '%s://%s:%s/web' % (scheme, client.name, port), 'owner_user': owner_user_data, } if self.template_id: state.update({'db_template': self.template_id.name}) scope = ['userinfo', 'force_login', 'trial', 'skiptheuse'] url = server._request_server( path='/saas_server/new_database', scheme=scheme, port=port, state=state, client_id=client_id, scope=scope, )[0] res = requests.get(url, verify=(self.server_id.request_scheme == 'https' and self.server_id.verify_ssl)) if res.status_code != 200: # TODO /saas_server/new_database show more details here raise exceptions.Warning('Error %s' % res.status_code) data = simplejson.loads(res.text) params = { 'state': data.get('state'), 'access_token': client.oauth_application_id._get_access_token(user_id, create=True), } url = '{url}?{params}'.format(url=data.get('url'), params=werkzeug.url_encode(params)) return {'url': url, 'id': client.id, 'client_id': client_id} @api.one def generate_dbname(self, raise_error=True): if not self.dbname_template: if raise_error: raise exceptions.Warning( _('Template for db name is not configured')) return '' sequence = self.env['ir.sequence'].get('saas_portal.plan') return self.dbname_template.replace('%i', sequence) @api.multi def create_template(self): assert len(self) == 1, 'This method is applied only for single record' # TODO use create_new_database function plan = self[0] state = { 'd': plan.template_id.name, 'demo': plan.demo and 1 or 0, 'addons': [], 'lang': plan.lang, 'tz': plan.tz, 'is_template_db': 1, } client_id = plan.template_id.client_id plan.template_id.server_id = plan.server_id params = plan.server_id._request_params( path='/saas_server/new_database', state=state, client_id=client_id)[0] access_token = plan.template_id.oauth_application_id._get_access_token( create=True) params.update({ 'token_type': 'Bearer', 'access_token': access_token, 'expires_in': 3600, }) url = '{scheme}://{saas_server}:{port}{path}?{params}'.format( scheme=plan.server_id.request_scheme, saas_server=plan.server_id.name, port=plan.server_id.request_port, path='/saas_server/new_database', params=werkzeug.url_encode(params)) res = requests.get(url, verify=(plan.server_id.request_scheme == 'https' and plan.server_id.verify_ssl)) if res.ok != True: msg = """Status Code - %s Reason - %s URL - %s """ % (res.status_code, res.reason, res.url) raise Warning(msg) return self.action_sync_server() @api.one def action_sync_server(self): self.server_id.action_sync_server() @api.multi def edit_template(self): return self[0].template_id.edit_database() @api.multi def upgrade_template(self): return self[0].template_id.upgrade_database() @api.multi def delete_template(self): res = self[0].template_id.delete_database() return res
class event_track(models.Model): _name = "event.track" _description = 'Event Track' _order = 'priority, date' _inherit = [ 'mail.thread', 'ir.needaction_mixin', 'website.seo.metadata', 'website.published.mixin' ] name = fields.Char('Title', required=True, translate=True) user_id = fields.Many2one('res.users', 'Responsible', track_visibility='onchange', default=lambda self: self.env.user) partner_id = fields.Many2one('res.partner', 'Proposed by') partner_name = fields.Char('Partner Name') partner_email = fields.Char('Partner Email') partner_phone = fields.Char('Partner Phone') partner_biography = fields.Html('Partner Biography') speaker_ids = fields.Many2many('res.partner', string='Speakers') tag_ids = fields.Many2many('event.track.tag', string='Tags') state = fields.Selection([('draft', 'Proposal'), ('confirmed', 'Confirmed'), ('announced', 'Announced'), ('published', 'Published'), ('refused', 'Refused'), ('cancel', 'Cancelled')], 'Status', default='draft', required=True, copy=False, track_visibility='onchange') description = fields.Html('Track Description', translate=True) date = fields.Datetime('Track Date') duration = fields.Float('Duration', digits=(16, 2), default=1.5) location_id = fields.Many2one('event.track.location', 'Room') event_id = fields.Many2one('event.event', 'Event', required=True) color = fields.Integer('Color Index') priority = fields.Selection([('0', 'Low'), ('1', 'Medium'), ('2', 'High'), ('3', 'Highest')], 'Priority', required=True, default='1') image = fields.Binary('Image', compute='_compute_image', store=True, attachment=True) @api.one @api.depends('speaker_ids.image') def _compute_image(self): if self.speaker_ids: self.image = self.speaker_ids[0].image else: self.image = False @api.model def create(self, vals): res = super(event_track, self).create(vals) res.message_subscribe(res.speaker_ids.ids) res.event_id.message_post(body="""<h3>%(header)s</h3> <ul> <li>%(proposed_by)s</li> <li>%(mail)s</li> <li>%(phone)s</li> <li>%(title)s</li> <li>%(speakers)s</li> <li>%(introduction)s</li> </ul>""" % { 'header': _('New Track Proposal'), 'proposed_by': '<b>%s</b>: %s' % (_('Proposed By'), (res.partner_id.name or res.partner_name or res.partner_email)), 'mail': '<b>%s</b>: %s' % (_('Mail'), '<a href="mailto:%s">%s</a>' % (res.partner_email, res.partner_email)), 'phone': '<b>%s</b>: %s' % (_('Phone'), res.partner_phone), 'title': '<b>%s</b>: %s' % (_('Title'), res.name), 'speakers': '<b>%s</b>: %s' % (_('Speakers Biography'), res.partner_biography), 'introduction': '<b>%s</b>: %s' % (_('Talk Introduction'), res.description), }, subtype='event.mt_event_track') return res @api.multi def write(self, vals): if vals.get('state') == 'published': vals.update({'website_published': True}) res = super(event_track, self).write(vals) if vals.get('speaker_ids'): self.message_subscribe([ speaker['id'] for speaker in self.resolve_2many_commands( 'speaker_ids', vals['speaker_ids'], ['id']) ]) return res @api.multi @api.depends('name') def _website_url(self, field_name, arg): res = super(event_track, self)._website_url(field_name, arg) res.update({ (track.id, '/event/%s/track/%s' % (slug(track.event_id), slug(track))) for track in self }) return res def read_group(self, cr, uid, domain, fields, groupby, offset=0, limit=None, context=None, orderby=False, lazy=True): """ Override read_group to always display all states. """ if groupby and groupby[0] == "state": # Default result structure # states = self._get_state_list(cr, uid, context=context) states = [('draft', 'Proposal'), ('confirmed', 'Confirmed'), ('announced', 'Announced'), ('published', 'Published'), ('cancel', 'Cancelled')] read_group_all_states = [{ '__context': { 'group_by': groupby[1:] }, '__domain': domain + [('state', '=', state_value)], 'state': state_value, 'state_count': 0, } for state_value, state_name in states] # Get standard results read_group_res = super(event_track, self).read_group(cr, uid, domain, fields, groupby, offset=offset, limit=limit, context=context, orderby=orderby) # Update standard results with default results result = [] for state_value, state_name in states: res = filter(lambda x: x['state'] == state_value, read_group_res) if not res: res = filter(lambda x: x['state'] == state_value, read_group_all_states) if state_value == 'cancel': res[0]['__fold'] = True res[0]['state'] = [state_value, state_name] result.append(res[0]) return result else: return super(event_track, self).read_group(cr, uid, domain, fields, groupby, offset=offset, limit=limit, context=context, orderby=orderby) def open_track_speakers_list(self, cr, uid, track_id, context=None): track_id = self.browse(cr, uid, track_id, context=context) return { 'name': _('Speakers'), 'domain': [('id', 'in', [partner.id for partner in track_id.speaker_ids])], 'view_type': 'form', 'view_mode': 'kanban,form', 'res_model': 'res.partner', 'view_id': False, 'type': 'ir.actions.act_window', }
class ImportReview(models.TransientModel): """ Browse through the import lines and allow the user to review and correct the results easily. """ _name = 'import.letters.review' ########################################################################## # FIELDS # ########################################################################## progress = fields.Float(compute='_get_current_line', store=True) current_line_index = fields.Integer(default=0) count = fields.Integer(compute='_get_current_line', store=True) nb_lines = fields.Integer(compute='_get_current_line', store=True) current_line_id = fields.Many2one( 'import.letter.line', 'Letter', compute='_get_current_line', store=True, readonly=True) postpone_import_id = fields.Many2one('import.letters.history') # Import line related fields state = fields.Selection(related='current_line_id.status', readonly=True) letter_image = fields.Binary(compute='_get_current_line') letter_file = fields.Binary( 'Letter file', readonly=True, compute='_get_current_line') fname = fields.Char(related='current_line_id.letter_image.name') partner_id = fields.Many2one(related='current_line_id.partner_id') sponsorship_id = fields.Many2one('recurring.contract', 'Sponsorship') child_id = fields.Many2one(related='current_line_id.child_id') template_id = fields.Many2one(related='current_line_id.template_id') language_id = fields.Many2one( related='current_line_id.letter_language_id', order='translatable desc, id asc') is_encourager = fields.Boolean(related='current_line_id.is_encourager') mandatory_review = fields.Boolean( related='current_line_id.mandatory_review') physical_attachments = fields.Selection( related='current_line_id.physical_attachments') attachments_description = fields.Char( related='current_line_id.attachments_description') edit = fields.Boolean('Edit mode') ########################################################################## # FIELDS METHODS # ########################################################################## @api.one @api.depends('current_line_index') def _get_current_line(self): line_ids = self.env.context.get('line_ids') if line_ids: self.current_line_id = line_ids[self.current_line_index] self.nb_lines = len(line_ids) self.count = self.current_line_index + 1 self.progress = (float(self.count) / self.nb_lines) * 100 self.letter_image = self.with_context( bin_size=False).current_line_id.letter_image_preview self.letter_file = self.with_context( bin_size=False).current_line_id.letter_image.datas @api.onchange('sponsorship_id') def _get_partner_child(self): for wizard in self: child = wizard.sponsorship_id.child_id if child: wizard.child_id = child @api.onchange('partner_id') def _get_default_sponsorship(self): self.ensure_one() if self.partner_id: sponsorships = self.env['recurring.contract'].search([ ('correspondant_id', '=', self.partner_id.id) ]) if len(sponsorships) == 1: self.sponsorship_id = sponsorships ########################################################################## # VIEW CALLBACKS # ########################################################################## @api.multi def next(self): """ Load the next import line in the view. """ self.ensure_one() if self.current_line_id.status not in ('ok', 'no_template'): raise Warning( _("Import is not valid"), _("Please review this import before going to the next.")) self.write({ 'current_line_index': self.current_line_index + 1, 'sponsorship_id': False, }) self.current_line_id.reviewed = True @api.multi def finish(self): """ Return to import view. """ self.ensure_one() import_history = self.current_line_id.import_id import_history.import_line_ids.check_status() return { 'type': 'ir.actions.act_window', 'view_type': 'form', 'view_mode': 'form,tree', 'res_model': import_history._name, 'res_id': import_history.id, 'context': self.env.context, 'target': 'current', } @api.multi def postpone(self): """ Move the line in another import. """ self.ensure_one() postpone_import = self.postpone_import_id current_import = self.current_line_id.import_id if not postpone_import: import_vals = current_import.get_correspondence_metadata() import_vals['import_completed'] = True postpone_import = self.env['import.letters.history'].create( import_vals) self.postpone_import_id = postpone_import self.current_line_id.import_id = postpone_import self.current_line_index += 1
class ImportLetterLine(models.Model): """ This class is used for the validation of an export. """ _name = 'import.letter.line' _inherit = 'import.letter.config' _order = 'reviewed,status' ########################################################################## # FIELDS # ########################################################################## sponsorship_id = fields.Many2one('recurring.contract', 'Sponsorship', compute='_set_sponsorship_id') partner_id = fields.Many2one('res.partner', 'Partner') name = fields.Char(compute='_set_name') child_id = fields.Many2one('compassion.child', 'Child') letter_language_id = fields.Many2one('res.lang.compassion', 'Language') letter_image = fields.Many2one('ir.attachment') letter_image_preview = fields.Binary() import_id = fields.Many2one('import.letters.history') reviewed = fields.Boolean() status = fields.Selection( [("no_lang", _("Language not Detected")), ("no_sponsorship", _("Sponsorship not Found")), ("no_child_partner", _("Partner or Child not Found")), ("no_template", _("Template not Detected")), ("ok", _("OK"))], compute="check_status", store=True, readonly=True) original_text = fields.Text() ########################################################################## # ORM METHODS # ########################################################################## @api.model def create(self, vals): # Fetch default values in import configuration. create_vals = dict() if vals.get('import_id'): config = self.env['import.letters.history'].browse( vals['import_id']) create_vals = config.get_correspondence_metadata() create_vals.update(vals) return super(ImportLetterLine, self).create(create_vals) ########################################################################## # FIELDS METHODS # ########################################################################## @api.multi @api.depends('partner_id', 'child_id', 'sponsorship_id', 'letter_language_id', 'import_id.template_id') def check_status(self): """ At each change, check if all the fields are OK """ default_template = self.env.ref('sbc_compassion.default_template') for line in self: valid_template = (line.template_id and not (line.template_id == default_template != line.import_id.template_id)) if not line.sponsorship_id: if not (line.child_id and line.partner_id): line.status = "no_child_partner" else: line.status = "no_sponsorship" elif not valid_template: line.status = "no_template" elif len(line.letter_language_id) != 1: line.status = "no_lang" else: line.status = "ok" @api.multi @api.depends('partner_id', 'child_id') def _set_sponsorship_id(self): """ From the partner codega and the child code, find the record linking them together. At the same time, check if the child, the partner and the sponsorship are found. """ for line in self: if line.partner_id and line.child_id: line.sponsorship_id = line.env['recurring.contract'].search( [('child_id', '=', line.child_id.id), ('correspondant_id', '=', line.partner_id.id)], order='is_active desc, end_date desc', limit=1) @api.multi @api.depends('partner_id', 'child_id') def _set_name(self): for line in self: if line.sponsorship_id: line.name = str( line.sponsorship_id.partner_codega) + " - " + str( line.child_id.local_id) @api.multi def get_letter_data(self): """ Create a list of dictionaries in order to create some lines inside import_letters_history. :returns: list to use in a write :rtype: list[dict{}] """ letter_data = [] for line in self: vals = line.get_correspondence_metadata() vals.update({ 'sponsorship_id': line.sponsorship_id.id, 'letter_image': line.letter_image.datas, 'original_language_id': line.letter_language_id.id, 'direction': 'Supporter To Beneficiary', 'original_text': line.original_text, 'source': line.source, }) if line.is_encourager: vals['relationship'] = 'Encourager' del vals['is_encourager'] letter_data.append((0, 0, vals)) return letter_data
class AccountPaymentBatchFile(models.TransientModel): _name = "account.payment.batch.file" partner_id = fields.Many2one('res.partner', string=_('Partner')) payment_method_id = fields.Many2one('account.payment.method', string='Payment Type') csv_file = fields.Binary(_('CSV File')) delimiter = fields.Char(_('Delimiter'), default=',') csv_name = fields.Char(_('CSV File name')) payment_slip_number = fields.Char(_('Payment Slip Number')) error = fields.Text(_('Error')) state = fields.Selection([('new', _('New')), ('error', _('Error'))], string='State', default='new') @api.multi def check_invoices(self): res = {} inv_obj = self.env['account.invoice'] for row in self: ctx = {} file_ext = row.csv_name.split('.') if len(file_ext) > 1 and file_ext[1] not in [u'csv', u'CSV']: raise UserError(_('The file to import is not CSV')) elif len(file_ext) == 1: raise UserError( _('The file to import does not have a valid extention')) data = base64.b64decode(row.csv_file) file_input = cStringIO.StringIO(data) file_input.seek(0) reader_info = [] if row.delimiter: delimiter = str(row.delimiter) else: delimiter = ',' reader = csv.reader(file_input, delimiter=delimiter, lineterminator='\r\n') try: reader_info.extend(reader) except Exception: raise Warning(_("Not a valid file!")) keys = reader_info[0] # check if keys exist not_found = [x for x in ['reference', 'amount'] if x not in keys] if not_found: raise Warning( _('The file to be imported does not present the following columns: {}' .format(', '.join(map(str, not_found))))) del reader_info[0] active_ids = [] invoices = {} no_doc = '' for i in reader_info: try: number = str(int(i[0].split('-')[2])) except ValueError: number = str(i[0].split('-')[2]) if not number.isdigit(): number = str(int(re.findall('\d+', number)[0])) inv_id = inv_obj.search([('secuencial', 'like', number), ('state', '=', 'open'), ('partner_id', '=', row.partner_id.id) ]) if inv_id: active_ids.append(inv_id.id) invoices.update({inv_id.id: abs(float(i[1]))}) else: no_doc += _( 'The invoice with the number: {} is not in the system or is in a different state open\n' .format(i[0])) ctx.update({ 'active_ids': active_ids, 'active_model': 'account.invoice', 'payment_slip_number': row.payment_slip_number, 'payment_method_id': row.payment_method_id.id, 'batch': True, 'invoices': invoices, 'errors': no_doc }) vals_ok = { 'name': _('Batch Payments from File'), 'context': ctx, 'view_type': 'form', 'view_mode': 'form', 'res_model': 'account.register.payments', 'view_id': False, 'res_id': False, 'target': 'new', 'type': 'ir.actions.act_window', } vals_err = { 'name': _('Batch Payments from File'), 'context': self.env.context, 'view_type': 'form', 'view_mode': 'form', 'res_model': 'account.payment.batch.file', 'view_id': False, 'res_id': row.id, 'target': 'new', 'type': 'ir.actions.act_window', } if no_doc: row.error = no_doc row.state = 'error' res = vals_err else: res = vals_ok return res
class HrOrientationChecklistConfig(models.Model): _name = 'hr.orientation.checklist.config' name = fields.Char(string='Name', required=True) web_url = fields.Char(string='Web URL', required=True) responsible_user_id = fields.Many2one( 'res.users', string='Responsible User', required=False, ) survey_id = fields.Many2one( 'survey.survey', string='Mini Test', required=False, store=True, ) note = fields.Text( string='Notes', store=True, ) attachment_ids1 = fields.Binary( string='First Attachment', store=True, ) attachment_ids2 = fields.Binary( string='Second Attachment', store=True, ) attachment_ids3 = fields.Binary( string='Third Attachment', store=True, ) @api.multi def action_start_survey(self): self.ensure_one() # create a response and link it to this applicant if not self.response_id: response = self.env['survey.user_input'].create({ 'survey_id': self.survey_id.id, 'partner_id': self.partner_id.id }) self.response_id = response.id else: response = self.response_id # grab the token of the response and start surveying return self.survey_id.with_context( survey_token=response.token).action_start_survey() @api.multi def action_print_survey(self): """ If response is available then print this response otherwise print survey form (print template of the survey) """ self.ensure_one() if not self.response_id: return self.survey_id.action_print_survey() else: response = self.response_id return self.survey_id.with_context( survey_token=response.token).action_print_survey()
class Slide(models.Model): """ This model represents actual presentations. Those must be one of four types: - Presentation - Document - Infographic - Video Slide has various statistics like view count, embed count, like, dislikes """ _name = 'slide.slide' _inherit = ['mail.thread', 'website.seo.metadata', 'website.published.mixin'] _description = 'Slides' _PROMOTIONAL_FIELDS = [ '__last_update', 'name', 'image_thumb', 'image_medium', 'slide_type', 'total_views', 'category_id', 'channel_id', 'description', 'tag_ids', 'write_date', 'create_date', 'website_published', 'website_url', 'website_meta_title', 'website_meta_description', 'website_meta_keywords'] _sql_constraints = [ ('name_uniq', 'UNIQUE(channel_id, name)', 'The slide name must be unique within a channel') ] # description name = fields.Char('Title', required=True, translate=True) description = fields.Text('Description', translate=True) channel_id = fields.Many2one('slide.channel', string="Channel", required=True) category_id = fields.Many2one('slide.category', string="Category", domain="[('channel_id', '=', channel_id)]") tag_ids = fields.Many2many('slide.tag', 'rel_slide_tag', 'slide_id', 'tag_id', string='Tags') download_security = fields.Selection( [('none', 'No One'), ('user', 'Authentified Users Only'), ('public', 'Everyone')], string='Download Security', required=True, default='user') image = fields.Binary('Image', attachment=True) image_medium = fields.Binary('Medium', compute="_get_image", store=True, attachment=True) image_thumb = fields.Binary('Thumbnail', compute="_get_image", store=True, attachment=True) @api.depends('image') def _get_image(self): for record in self: if record.image: record.image_medium = image.crop_image(record.image, type='top', ratio=(4, 3), thumbnail_ratio=4) record.image_thumb = image.crop_image(record.image, type='top', ratio=(4, 3), thumbnail_ratio=6) else: record.image_medium = False record.iamge_thumb = False # content slide_type = fields.Selection([ ('infographic', 'Infographic'), ('presentation', 'Presentation'), ('document', 'Document'), ('video', 'Video')], string='Type', required=True, default='document', help="Document type will be set automatically depending on file type, height and width.") index_content = fields.Text('Transcript') datas = fields.Binary('Content') url = fields.Char('Document URL', help="Youtube or Google Document URL") document_id = fields.Char('Document ID', help="Youtube or Google Document ID") mime_type = fields.Char('Mime-type') @api.onchange('url') def on_change_url(self): self.ensure_one() if self.url: res = self._parse_document_url(self.url) if res.get('error'): raise Warning(_('Could not fetch data from url. Document or access right not available:\n%s') % res['error']) values = res['values'] if not values.get('document_id'): raise Warning(_('Please enter valid Youtube or Google Doc URL')) for key, value in values.iteritems(): setattr(self, key, value) # website date_published = fields.Datetime('Publish Date') website_message_ids = fields.One2many( 'mail.message', 'res_id', domain=lambda self: [('model', '=', self._name), ('message_type', '=', 'comment')], string='Website Messages', help="Website communication history") likes = fields.Integer('Likes') dislikes = fields.Integer('Dislikes') # views embedcount_ids = fields.One2many('slide.embed', 'slide_id', string="Embed Count") slide_views = fields.Integer('# of Website Views') embed_views = fields.Integer('# of Embedded Views') total_views = fields.Integer("Total # Views", default="0", compute='_compute_total', store=True) @api.depends('slide_views', 'embed_views') def _compute_total(self): for record in self: record.total_views = record.slide_views + record.embed_views embed_code = fields.Text('Embed Code', readonly=True, compute='_get_embed_code') def _get_embed_code(self): base_url = self.env['ir.config_parameter'].get_param('web.base.url') for record in self: if record.datas and (not record.document_id or record.slide_type in ['document', 'presentation']): record.embed_code = '<iframe src="%s/slides/embed/%s?page=1" allowFullScreen="true" height="%s" width="%s" frameborder="0"></iframe>' % (base_url, record.id, 315, 420) elif record.slide_type == 'video' and record.document_id: if not record.mime_type: # embed youtube video record.embed_code = '<iframe src="//www.youtube.com/embed/%s?theme=light" allowFullScreen="true" frameborder="0"></iframe>' % (record.document_id) else: # embed google doc video record.embed_code = '<embed src="https://video.google.com/get_player?ps=docs&partnerid=30&docid=%s" type="application/x-shockwave-flash"></embed>' % (record.document_id) else: record.embed_code = False @api.multi @api.depends('name') def _website_url(self, name, arg): res = super(Slide, self)._website_url(name, arg) base_url = self.env['ir.config_parameter'].get_param('web.base.url') #link_tracker is not in dependencies, so use it to shorten url only if installed. if self.env.registry.get('link.tracker'): LinkTracker = self.env['link.tracker'] res.update({(slide.id, LinkTracker.sudo().create({'url': '%s/slides/slide/%s' % (base_url, slug(slide))}).short_url) for slide in self}) else: res.update({(slide.id, '%s/slides/slide/%s' % (base_url, slug(slide))) for slide in self}) return res @api.model def create(self, values): if not values.get('index_content'): values['index_content'] = values.get('description') if values.get('slide_type') == 'infographic' and not values.get('image'): values['image'] = values['datas'] if values.get('website_published') and not values.get('date_published'): values['date_published'] = datetime.datetime.now() if values.get('url'): doc_data = self._parse_document_url(values['url']).get('values', dict()) for key, value in doc_data.iteritems(): values.setdefault(key, value) # Do not publish slide if user has not publisher rights if not self.user_has_groups('base.group_website_publisher'): values['website_published'] = False slide = super(Slide, self).create(values) slide.channel_id.message_subscribe_users() slide._post_publication() return slide @api.multi def write(self, values): if values.get('url'): doc_data = self._parse_document_url(values['url']).get('values', dict()) for key, value in doc_data.iteritems(): values.setdefault(key, value) res = super(Slide, self).write(values) if values.get('website_published'): self.date_published = datetime.datetime.now() self._post_publication() return res @api.model def check_field_access_rights(self, operation, fields): """ As per channel access configuration (visibility) - public ==> no restriction on slides access - private ==> restrict all slides of channel based on access group defined on channel group_ids field - partial ==> show channel, but presentations based on groups means any user can see channel but not slide's content. For private: implement using record rule For partial: user can see channel, but channel gridview have slide detail so we have to implement partial field access mechanism for public user so he can have access of promotional field (name, view_count) of slides, but not all fields like data (actual pdf content) all fields should be accessible only for user group defined on channel group_ids """ if self.env.uid == SUPERUSER_ID: return fields or list(self._fields) fields = super(Slide, self).check_field_access_rights(operation, fields) # still read not perform so we can not access self.channel_id if self.ids: self.env.cr.execute('SELECT DISTINCT channel_id FROM ' + self._table + ' WHERE id IN %s', (tuple(self.ids),)) channel_ids = [x[0] for x in self.env.cr.fetchall()] channels = self.env['slide.channel'].sudo().browse(channel_ids) limited_access = all(channel.visibility == 'partial' and not len(channel.group_ids & self.env.user.groups_id) for channel in channels) if limited_access: fields = [field for field in fields if field in self._PROMOTIONAL_FIELDS] return fields def get_related_slides(self, limit=20): domain = [('website_published', '=', True), ('channel_id.visibility', '!=', 'private'), ('id', '!=', self.id)] if self.category_id: domain += [('category_id', '=', self.category_id.id)] for record in self.search(domain, limit=limit): yield record def get_most_viewed_slides(self, limit=20): for record in self.search([('website_published', '=', True), ('channel_id.visibility', '!=', 'private'), ('id', '!=', self.id)], limit=limit, order='total_views desc'): yield record def _post_publication(self): base_url = self.env['ir.config_parameter'].get_param('web.base.url') for slide in self.filtered(lambda slide: slide.website_published): publish_template = slide.channel_id.publish_template_id html_body = publish_template.with_context({'base_url': base_url}).render_template(publish_template.body_html, 'slide.slide', slide.id) slide.channel_id.message_post(body=html_body, subtype='website_slides.mt_channel_slide_published') return True @api.one def send_share_email(self, email): base_url = self.env['ir.config_parameter'].get_param('web.base.url') return self.channel_id.share_template_id.with_context({'email': email, 'base_url': base_url}).send_mail(self.id) # -------------------------------------------------- # Parsing methods # -------------------------------------------------- @api.model def _fetch_data(self, base_url, data, content_type=False): result = {'values': dict()} try: if data: base_url = base_url + '?%s' % urlencode(data) req = urllib2.Request(base_url) content = urllib2.urlopen(req).read() if content_type == 'json': result['values'] = json.loads(content) elif content_type in ('image', 'pdf'): result['values'] = content.encode('base64') else: result['values'] = content except urllib2.HTTPError as e: result['error'] = e.read() e.close() except urllib2.URLError as e: result['error'] = e.reason return result def _find_document_data_from_url(self, url): expr = re.compile(r'^.*((youtu.be/)|(v/)|(\/u\/\w\/)|(embed\/)|(watch\?))\??v?=?([^#\&\?]*).*') arg = expr.match(url) document_id = arg and arg.group(7) or False if document_id: return ('youtube', document_id) expr = re.compile(r'(^https:\/\/docs.google.com|^https:\/\/drive.google.com).*\/d\/([^\/]*)') arg = expr.match(url) document_id = arg and arg.group(2) or False if document_id: return ('google', document_id) return (None, False) def _parse_document_url(self, url, only_preview_fields=False): document_source, document_id = self._find_document_data_from_url(url) if document_source and hasattr(self, '_parse_%s_document' % document_source): return getattr(self, '_parse_%s_document' % document_source)(document_id, only_preview_fields) return {'error': _('Unknown document')} def _parse_youtube_document(self, document_id, only_preview_fields): key = self.env['ir.config_parameter'].sudo().get_param('website_slides.google_app_key') fetch_res = self._fetch_data('https://www.googleapis.com/youtube/v3/videos', {'id': document_id, 'key': key, 'part': 'snippet', 'fields': 'items(id,snippet)'}, 'json') if fetch_res.get('error'): return fetch_res values = {'slide_type': 'video', 'document_id': document_id} youtube_values = fetch_res['values'].get('items', list(dict()))[0] if youtube_values.get('snippet'): snippet = youtube_values['snippet'] if only_preview_fields: values.update({ 'url_src': snippet['thumbnails']['high']['url'], 'title': snippet['title'], 'description': snippet['description'] }) return values values.update({ 'name': snippet['title'], 'image': self._fetch_data(snippet['thumbnails']['high']['url'], {}, 'image')['values'], 'description': snippet['description'], }) return {'values': values} @api.model def _parse_google_document(self, document_id, only_preview_fields): def get_slide_type(vals): # TDE FIXME: WTF ?? image = Image.open(io.BytesIO(vals['image'].decode('base64'))) width, height = image.size if height > width: return 'document' else: return 'presentation' key = self.env['ir.config_parameter'].sudo().get_param('website_slides.google_app_key') fetch_res = self._fetch_data('https://www.googleapis.com/drive/v2/files/%s' % document_id, {'projection': 'BASIC', 'key': key}, "json") if fetch_res.get('error'): return fetch_res google_values = fetch_res['values'] if only_preview_fields: return { 'url_src': google_values['thumbnailLink'], 'title': google_values['title'], } values = { 'name': google_values['title'], 'image': self._fetch_data(google_values['thumbnailLink'].replace('=s220', ''), {}, 'image')['values'], 'mime_type': google_values['mimeType'], 'document_id': document_id, } if google_values['mimeType'].startswith('video/'): values['slide_type'] = 'video' elif google_values['mimeType'].startswith('image/'): values['datas'] = values['image'] values['slide_type'] = 'infographic' elif google_values['mimeType'].startswith('application/vnd.google-apps'): values['datas'] = self._fetch_data(google_values['exportLinks']['application/pdf'], {}, 'pdf')['values'] values['slide_type'] = get_slide_type(values) if google_values['exportLinks'].get('text/plain'): values['index_content'] = self._fetch_data(google_values['exportLinks']['text/plain'], {})['values'] if google_values['exportLinks'].get('text/csv'): values['index_content'] = self._fetch_data(google_values['exportLinks']['text/csv'], {})['values'] elif google_values['mimeType'] == 'application/pdf': # TODO: Google Drive PDF document doesn't provide plain text transcript values['datas'] = self._fetch_data(google_values['webContentLink'], {}, 'pdf')['values'] values['slide_type'] = get_slide_type(values) return {'values': values}
class IrActionBackground(models.Model): _name = "ir.action.background" name = fields.Char(string="Name") action_file = fields.Binary(string="Action File") progress_current = fields.Integer(string="Progress Current", readonly=True) progress_max = fields.Integer(string="Progress Max", readonly=True) track_progress = fields.Boolean( string="Track Progress", help="Tracks how far along a action is complete(decreases speed)") start_time = fields.Datetime(string="Start Time", readonly=True) auto_commit = fields.Boolean( string="Auto Commit", help= "Adds the records after every line is executed without waiting until the file finishes(decreases speed)" ) finish_time = fields.Datetime(string="Fnish Time", readonly=True) time_taken = fields.Char(string="Time Taken", compute="_compute_time_taken") rule_char_size = fields.Selection( [('do_not_import_record', 'Do not import record'), ('truncate', 'Truncate')], string="Exceed Max Size", default="do_not_import_record") log = fields.Text(string="Log", readonly=True) state = fields.Selection([('new', 'New'), ('running', 'Running'), ('finished', 'Finished')], default="new", string="State", readonly=True) @api.depends('start_time', 'finish_time') def _compute_time_taken(self): if self.start_time and self.finish_time: start_time = datetime.strptime(self.start_time, DEFAULT_SERVER_DATETIME_FORMAT) finish_time = datetime.strptime(self.finish_time, DEFAULT_SERVER_DATETIME_FORMAT) time_taken = finish_time - start_time m, s = divmod(time_taken.seconds, 60) h, m = divmod(m, 60) self.time_taken = str(h) + " hours, " + str( m) + " minutes, " + str(s) + " seconds" @api.one def reset_state(self): self.state = "new" @api.one def run_now(self): self.env['ir.action.background'].process_background_actions() @api.model def process_background_actions(self): for background_action in self.env['ir.action.background'].search([ ('state', '=', 'new') ]): background_action.state = "running" model = "res.partner" my_model = self.env['ir.model'].search([('model', '=', model)])[0] log_string = "" background_action.start_time = datetime.utcnow() rownum = 0 csv_data = base64.decodestring(background_action.action_file) progress_max = sum(1 for row in StringIO.StringIO(csv_data)) - 1 background_action.progress_max = progress_max reader = csv.reader(StringIO.StringIO(csv_data), delimiter=',') track = background_action.track_progress auto_commit = background_action.auto_commit cancel_import = False create_commit_data = [] header = [] header_field = {} for row in reader: row_dict = {} # Save header row. if rownum == 0: header = row colnum = 0 for col in row: map_column = self.env['ir.model.fields'].search([ ('model_id', '=', my_model.id), ('name', '=', col) ]) if len(map_column) == 1: header_field[colnum] = map_column[0] colnum += 1 elif len(map_column) > 1: log_string += "Column " + col + " maps to more then 1 field, import failed\n" cancel_import = True else: log_string += "Column " + col + " could not be found\n" cancel_import = True if cancel_import: break else: colnum = 0 for col in row: row_dict[header[colnum]] = col ttype = header_field[colnum].ttype size = header_field[colnum].size #Char size validation if ttype == "char" and size != 0: #Exceeds max size if len(col) > size: if background_action.rule_char_size == "do_not_import_record": log_string += "Row " + str( rownum ) + " was skipped because field " + str( header[colnum] ) + " exceeded the character limit\n" break elif background_action.rule_char_size == "truncate": #Truncates by default log_string += "Row " + str( rownum) + " field " + str( header[colnum] ) + " was truncated\n" colnum += 1 self.env[model].create(row_dict) if track: _logger.error(str(rownum) + "/" + str(progress_max)) background_action.progress_current = rownum if auto_commit: self._cr.commit() rownum += 1 background_action.state = "finished" background_action.finish_time = datetime.utcnow() background_action.log = log_string background_action.state = "finished"
class dev_product_movement_excel(models.TransientModel): _name= "dev.product.movement.excel" excel_file = fields.Binary('Excel Report') file_name = fields.Char('Excel File')
class rbs_documento_mercantil_acta(models.Model): _name = "rbs.documento.mercantil.acta" _description = "Documento Mercantil de Acta" #name= field.Char('Nombre') anio_id = fields.Many2one('rbs.archivo.anio', string='Año', required=True) libro_id = fields.Many2one('rbs.archivo.libro', string='Libro', required=True) tomo_id = fields.Many2one("rbs.archivo.tomo", string='Tomo', required=True) compania_id = fields.Many2one('rbs.compania', string='Compania') compania_nombres = fields.Char(string='Nombres de la Compañia') compania_identificacion = fields.Char( string='Indentificacion de la Compañia') compania_especie_id = fields.Many2one('rbs.compania.especie', string='Especie de Compañia') fecha_inscripcion = fields.Datetime(string='Fecha de Inscripcion', required=True) persona_id = fields.Many2one('rbs.persona', string='Compareciente(n)') persona_nombres = fields.Char(string='Nombres del Compareciente') persona_apellidos = fields.Char(string='Apellidos del Compareciente') persona_cedula = fields.Char(string='Cedula del Compareciente') cargo_id = fields.Many2one('rbs.cargo', string='Cargo') tipo_compareciente_id = fields.Many2one('rbs.tipo.compareciente.a', string='Tipo de Compareciente') numero_inscripcion = fields.Char(string='Numero de Inscripcion', required=True) autoridad_emisora = fields.Char(string='Autoridad que emitio el Acta') foleo_desde = fields.Char(string='Desde', required=True) foleo_hasta = fields.Char(string='Hasta', required=True) disposicion = fields.Char(string='Disposicion') fecha_disposicion = fields.Datetime(string='Fecha de Disposicion') numero_Disposicion = fields.Char(string='Numero de Disposicion') fecha_ecritura = fields.Datetime(string='Fecha de Escritura', required=True) nombre_instancia_publica = fields.Char( string='Nombre de Instancia Publica') canton_id = fields.Many2one('rbs.canton', string='Canton de Notaria', required=True) tipo_tramite_id = fields.Many2one('rbs.tipo.tramite', string='Tipo de Tramite', required=True) ubicacion_dato_id = fields.Many2one('rbs.ubicacion.dato', string='Ubicacion del Dato', required=True) fecha_ultima_modificacion = fields.Datetime( string='Ultima Modificacion de la Fuente') estado_inscripcion_id = fields.Many2one('rbs.estado.inscripcion', string='Estado de la Inscripcion', required=True) #filedata = fields.Binary('Archivo',filters='*.pdf') #filename = fields.Char( compute='_get_value', string = 'Nombre de archivo', default="Archivo.pdf") filedata_id = fields.Many2one('rbs.archivo.pdf') filedata = fields.Binary(related='filedata_id.filedata', filters='*.pdf') esPesado = fields.Boolean(related='filedata_id.esPesado', string='¿Es Pesado?') rutaFTP = fields.Char(related='filedata_id.rutaFTP', string='Escriba la ruta del Archivo') #libro_tipo = fields.Selection(string='Tipo de Libro', related='libro_id.libro_tipo',store = True) identificacion_unica = fields.Char( string='Identificador Unico Sistema Remoto', compute='_compute_upper', store=True) factura_ids = fields.One2many('account.invoice', 'acta_id', string='Factura') contenedor_id = fields.Many2one("rbs.contenedor", string="Contenedor") _defaults = {} def open_ui(self, cr, uid, ids, context=None): data = self.browse(cr, uid, ids[0], context=context) context = dict(context or {}) #context['active_id'] = data.ids[0] return { 'type': 'ir.actions.act_url', 'url': '/registro_mercantil/web/?binary=' + str(ids[0]) + '&tipo=acta', 'target': 'current', } def _getUltimoAnio(self, cr, uid, context=None): acta_id = self.pool.get("rbs.documento.mercantil.acta").search( cr, uid, [], limit=1, order='id desc') anio = self.pool.get("rbs.documento.mercantil.acta").browse( cr, uid, acta_id, context=None).anio_id.id return anio def _getUltimoLibro(self, cr, uid, context=None): acta_id = self.pool.get("rbs.documento.mercantil.acta").search( cr, uid, [], limit=1, order='id desc') libro = self.pool.get("rbs.documento.mercantil.acta").browse( cr, uid, acta_id, context=None).libro_id.id return libro def _getUltimoTomo(self, cr, uid, context=None): acta_id = self.pool.get("rbs.documento.mercantil.acta").search( cr, uid, [], limit=1, order='id desc') tomo = self.pool.get("rbs.documento.mercantil.acta").browse( cr, uid, acta_id, context=None).tomo_id.id return tomo def _getUltimoTomo(self, cr, uid, context=None): acta_id = self.pool.get("rbs.documento.mercantil.acta").search( cr, uid, [], limit=1, order='id desc') tomo = self.pool.get("rbs.documento.mercantil.acta").browse( cr, uid, acta_id, context=None).tomo_id.id return tomo def _create_pdf(self, cr, uid, context=None): return self.pool.get("rbs.archivo.pdf").create(cr, uid, {}, context=None) _defaults = { 'anio_id': _getUltimoAnio, 'libro_id': _getUltimoLibro, 'tomo_id': _getUltimoTomo, 'filedata_id': _create_pdf, } _rec_name = 'numero_inscripcion' @api.onchange('filedata') def on_change_filedata(self): a = self.env['rbs.contenedor'].create({'name': 'A'}) im = Image.open(BytesIO(base64.b64decode(self.filedata))) #raise osv.except_osv('Esto es un Mesaje!',repr(im.info)) n = 0 self.contenedor_id = a.id while True: try: n = n + 1 im.seek(n) #im.save('Block_%s.tif'%(n,)) jpeg_image_buffer = cStringIO.StringIO() im.save(jpeg_image_buffer, format="PNG") imgStr = base64.b64encode(jpeg_image_buffer.getvalue()) a.imagenes_ids |= self.env['rbs.imagenes'].create({ 'imagen': imgStr, 'contenedor_id': a.id }) #raise osv.except_osv('Esto es un Mesaje!',imgStr) except EOFError: print "Se Cargo la imagen tiff", n break @api.depends('ubicacion_dato_id', 'persona_cedula', 'numero_inscripcion') def _compute_upper(self): for rec in self: try: rec.identificacion_unica = '01' + rec.ubicacion_dato_id.name + rec.persona_cedula + rec.numero_inscripcion except: pass def on_change_anio_id(self, cr, uid, ids, anio_id, context=None): result = {} if (self._getUltimoAnio(cr, uid, context=None) != anio_id): result['libro_id'] = 0 return { 'value': result, } def on_change_libro_id(self, cr, uid, ids, libro_id, context=None): result = {} if (self._getUltimoLibro(cr, uid, context=None) != libro_id): result['tomo_id'] = 0 return { 'value': result, } def codigoascii(self, text): return unicode(text).encode('utf-8') def onchange_persona_id(self, cr, uid, ids, persona_id, context=None): persona_id = self.pool.get('rbs.persona').search( cr, uid, [ ('id', '=', persona_id), ]) persona = self.pool.get('rbs.persona').browse(cr, uid, persona_id, context=None) result = {} try: if persona: try: if persona.persona_nombres: result['persona_nombres'] = self.codigoascii( persona.persona_nombres) except: pass try: if persona.persona_apellidos: result['persona_apellidos'] = self.codigoascii( persona.persona_apellidos) except: pass try: if persona.name: result['persona_cedula'] = str(persona.name) except: pass except: pass return { 'value': result, } def onchange_compania_id(self, cr, uid, ids, companiaid, context=None): compania_id = self.pool.get('rbs.compania').search( cr, uid, [ ('id', '=', companiaid), ]) compania = self.pool.get('rbs.compania').browse(cr, uid, compania_id, context=None) result = {} try: if compania: try: if compania.compania_nombres: result['compania_nombres'] = self.codigoascii( compania.compania_nombres) except: pass try: if compania.name: result['compania_identificacion'] = str(compania.name) except: pass try: if compania.compania_especie_id.id: result[ 'compania_especie_id'] = compania.compania_especie_id.id except: pass except: pass return { 'value': result, } def onchange_inscripcion(self, cr, uid, ids, inscripcion_num, libro_id, context=None): acta_id = self.pool.get('rbs.documento.mercantil.acta').search( cr, uid, [('numero_inscripcion', '=', inscripcion_num), ('libro_id', '=', libro_id)]) acta = self.pool.get('rbs.documento.mercantil.acta').browse( cr, uid, acta_id, context=None) result = {} try: if acta: acta = acta[0] #raise osv.except_osv('Esto es un Mesaje!',establecimiento) try: if acta.fecha_inscripcion: result['fecha_inscripcion'] = str( acta.fecha_inscripcion) except: pass try: if acta.tomo_id: result['tomo_id'] = acta.tomo_id.id except: pass try: if acta.anio_id: result['anio_id'] = acta.anio_id.id except: pass try: if acta.libro_id: result['libro_id'] = acta.libro_id.id except: pass try: if acta.numero_inscripcion: result[ 'numero_inscripcion'] = acta.numero_inscripcion.id except: pass try: if acta.autoridad_emisora: result['autoridad_emisora'] = self.codigoascii( acta.autoridad_emisora) except: pass try: if acta.disposicion: result['disposicion'] = self.codigoascii( acta.disposicion) except: pass try: if acta.fecha_disposicion: result['fecha_disposicion'] = str( acta.fecha_disposicion) except: pass try: if acta.numero_Disposicion: result['numero_Disposicion'] = str( acta.numero_Disposicion) except: pass try: if acta.fecha_ecritura: result['fecha_ecritura'] = str(acta.fecha_ecritura) except: pass try: if acta.nombre_instancia_publica: result['nombre_instancia_publica'] = self.codigoascii( acta.nombre_instancia_publica) except: pass try: if acta.canton_id: result['canton_id'] = acta.canton_id.id except: pass try: if acta.tipo_tramite_id: result['tipo_tramite_id'] = acta.tipo_tramite_id.id except: pass try: if acta.fecha_ultima_modificacion: result['fecha_ultima_modificacion'] = str( acta.fecha_ultima_modificacion) except: pass try: if acta.estado_inscripcion_id: result[ 'estado_inscripcion_id'] = acta.estado_inscripcion_id.id except: pass try: if acta.ubicacion_dato_id: result['ubicacion_dato_id'] = acta.ubicacion_dato_id.id except: pass try: if acta.canton_id: result['canton_id'] = acta.canton_id.id except: pass try: if acta.filedata_id: result['filedata_id'] = acta.filedata_id.id except: pass if not acta: result['filedata_id'] = self._create_pdf(cr, uid, context=None) except: pass return { 'value': result, }
class ImLivechatChannel(models.Model): """ Livechat Channel Define a communication channel, which can be accessed with 'script_external' (script tag to put on external website), 'script_internal' (code to be integrated with odoo website) or via 'web_page' link. It provides rating tools, and access rules for anonymous people. """ _name = 'im_livechat.channel' _description = 'Livechat Channel' def _default_image(self): image_path = openerp.modules.get_module_resource('im_livechat', 'static/src/img', 'default.png') return tools.image_resize_image_big(open(image_path, 'rb').read().encode('base64')) def _default_user_ids(self): return [(6, 0, [self._uid])] # attribute fields name = fields.Char('Name', required=True, help="The name of the channel") button_text = fields.Char('Text of the Button', default='Have a Question? Chat with us.', help="Default text displayed on the Livechat Support Button") default_message = fields.Char('Welcome Message', default='How may I help you?', help="This is an automated 'welcome' message that your visitor will see when they initiate a new conversation.") input_placeholder = fields.Char('Chat Input Placeholder') # computed fields web_page = fields.Char('Web Page', compute='_compute_web_page_link', store=False, readonly=True, help="URL to a static page where you client can discuss with the operator of the channel.") are_you_inside = fields.Boolean(string='Are you inside the matrix?', compute='_are_you_inside', store=False, readonly=True) script_external = fields.Text('Script (external)', compute='_compute_script_external', store=False, readonly=True) nbr_channel = fields.Integer('Number of conversation', compute='_compute_nbr_channel', store=False, readonly=True) rating_percentage_satisfaction = fields.Integer( '% Happy', compute='_compute_percentage_satisfaction', store=False, default=-1, help="Percentage of happy ratings over the past 7 days") # images fields image = fields.Binary('Image', default=_default_image, attachment=True, help="This field holds the image used as photo for the group, limited to 1024x1024px.") image_medium = fields.Binary('Medium', attachment=True, help="Medium-sized photo of the group. It is automatically "\ "resized as a 128x128px image, with aspect ratio preserved. "\ "Use this field in form views or some kanban views.") image_small = fields.Binary('Thumbnail', attachment=True, help="Small-sized photo of the group. It is automatically "\ "resized as a 64x64px image, with aspect ratio preserved. "\ "Use this field anywhere a small image is required.") # relationnal fields user_ids = fields.Many2many('res.users', 'im_livechat_channel_im_user', 'channel_id', 'user_id', string='Operators', default=_default_user_ids) channel_ids = fields.One2many('mail.channel', 'livechat_channel_id', 'Sessions') rule_ids = fields.One2many('im_livechat.channel.rule', 'channel_id', 'Rules') @api.one def _are_you_inside(self): self.are_you_inside = bool(self.env.uid in [u.id for u in self.user_ids]) @api.multi def _compute_script_external(self): view = self.env['ir.model.data'].get_object('im_livechat', 'external_loader') values = { "url": self.env['ir.config_parameter'].sudo().get_param('web.base.url'), "dbname": self._cr.dbname, } for record in self: values["channel_id"] = record.id record.script_external = view.render(values) @api.multi def _compute_web_page_link(self): base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url') for record in self: record.web_page = "%s/im_livechat/support/%i" % (base_url, record.id) @api.multi @api.depends('channel_ids') def _compute_nbr_channel(self): for record in self: record.nbr_channel = len(record.channel_ids) @api.multi @api.depends('channel_ids.rating_ids') def _compute_percentage_satisfaction(self): for record in self: dt = fields.Datetime.to_string(datetime.utcnow() - timedelta(days=7)) repartition = record.channel_ids.rating_get_grades([('create_date', '>=', dt)]) total = sum(repartition.values()) if total > 0: happy = repartition['great'] record.rating_percentage_satisfaction = ((happy*100) / total) if happy > 0 else 0 else: record.rating_percentage_satisfaction = -1 @api.model def create(self, vals): tools.image_resize_images(vals) return super(ImLivechatChannel, self).create(vals) @api.multi def write(self, vals): tools.image_resize_images(vals) return super(ImLivechatChannel, self).write(vals) # -------------------------- # Action Methods # -------------------------- @api.multi def action_join(self): self.ensure_one() return self.write({'user_ids': [(4, self._uid)]}) @api.multi def action_quit(self): self.ensure_one() return self.write({'user_ids': [(3, self._uid)]}) @api.multi def action_view_rating(self): """ Action to display the rating relative to the channel, so all rating of the sessions of the current channel :returns : the ir.action 'action_view_rating' with the correct domain """ self.ensure_one() action = self.env['ir.actions.act_window'].for_xml_id('rating', 'action_view_rating') action['domain'] = [('res_id', 'in', [s.id for s in self.channel_ids]), ('res_model', '=', 'mail.channel')] return action # -------------------------- # Channel Methods # -------------------------- @api.multi def get_available_users(self): """ get available user of a given channel :retuns : return the res.users having their im_status online """ self.ensure_one() return self.sudo().user_ids.filtered(lambda user: user.im_status == 'online') @api.model def get_mail_channel(self, livechat_channel_id, anonymous_name): """ Return a mail.channel given a livechat channel. It creates one with a connected operator, or return false otherwise :param livechat_channel_id : the identifier if the im_livechat.channel :param anonymous_name : the name of the anonymous person of the channel :type livechat_channel_id : int :type anonymous_name : str :return : channel header :rtype : dict """ # get the avalable user of the channel users = self.sudo().browse(livechat_channel_id).get_available_users() if len(users) == 0: return False # choose the res.users operator and get its partner id user = random.choice(users) operator_partner_id = user.partner_id.id # partner to add to the mail.channel channel_partner_to_add = [(4, operator_partner_id)] if self.env.uid: # if the user if logged (portal user), he can be identify channel_partner_to_add.append((4, self.env.user.partner_id.id)) # create the session, and add the link with the given channel mail_channel = self.env["mail.channel"].with_context(mail_create_nosubscribe=False).sudo().create({ 'channel_partner_ids': channel_partner_to_add, 'livechat_channel_id': livechat_channel_id, 'anonymous_name': anonymous_name, 'channel_type': 'livechat', 'name': ', '.join([anonymous_name, user.name]), 'public': 'private', 'email_send': False, }) return mail_channel.sudo().with_context(im_livechat_operator_partner_id=operator_partner_id).channel_info()[0] @api.model def get_channel_infos(self, channel_id): channel = self.browse(channel_id) return { 'button_text': channel.button_text, 'input_placeholder': channel.input_placeholder, 'default_message': channel.default_message, "channel_name": channel.name, "channel_id": channel.id, } @api.model def get_livechat_info(self, channel_id, username='******'): info = {} info['available'] = len(self.browse(channel_id).get_available_users()) > 0 info['server_url'] = self.env['ir.config_parameter'].get_param('web.base.url') if info['available']: info['options'] = self.sudo().get_channel_infos(channel_id) info['options']["default_username"] = username return info
class TestModel(models.Model): _name = 'test.model' _inherit = ['mail.thread'] _columns = {} # deprecated columns _defaults = {} # deprecated defaults length = fields.Integer() # Deprecated length by js errors name = fields.Char( _(u"Näme"), # Don't need translate help=u"My hëlp", required=False, compute='_compute_name', # good compute method name search='_search_name', # good search method name inverse='_inverse_name', # good inverse method name ) # Imported openerp.fields use Char (Upper case) other_field = fields.char( name=_("Other field"), copy=True, compute='my_method_compute', # bad compute method name search='my_method_search', # bad search method name inverse='my_method_inverse', # bad inverse method name ) compute_none = fields.Char(compute=None) other_field2 = fields.char( 'Other Field2', copy=True, ) # This is a inherit overwrite field then don't should show errors related # with creation of fields. def method_date(self): date = fields.Date.to_string( fields.Datetime.context_timestamp(self, timestamp=fields.Datetime.now())) return date my_ok_field = fields.Float( "My correctly named field", digits=(6, 6), # OK: Valid field parameter index=True, # OK: Valid field parameter help="My ok field", ) my_ko_field = fields.Float( digits_compute=lambda cr: (6, 6), # Deprecated field parameter select=True, # Deprecated field parameter help="My ko field", string="My Ko Field", # String parameter equal to name of variable ) """The name of the variable is equal to the string parameter Tested all fields.*""" boolean_variable_1 = fields.Boolean(string='Boolean Variable 1', help="Help") boolean_variable_2 = fields.Boolean("Boolean Variable 2", help="Help") char_variable_1 = fields.Char(string='Char Variable 1', help="Help") char_variable_2 = fields.Char("Char Variable 2", help="Help") text_variable_1 = fields.Text(string='Text Variable 1', help="Help") text_variable_2 = fields.Text("Text Variable 2", help="Help") html_variable_1 = fields.Html(string='Html Variable 1', help="Help") html_variable_2 = fields.Html("Html Variable 2", help="Help") integer_variable_1 = fields.Integer(string='Integer Variable 1', help="Help") integer_variable_2 = fields.Integer("Integer Variable 2", help="Help") float_variable_1 = fields.Float(string='Float Variable 1', help="Help") float_variable_2 = fields.Float("Float Variable 2", help="Help") date_variable_1 = fields.Date(string='Date Variable 1', help="Help") date_variable_2 = fields.Date("Date Variable 2", help="Help") date_time_variable_1 = fields.DateTime(string='Date Time Variable 1', help="Help") date_time_variable_2 = fields.DateTime("Date Time Variable 2", help="Help") binary_variable_1 = fields.Binary(string='Binary Variable 1', help="Help") binary_variable_2 = fields.Binary("Binary Variable 2", help="Help") selection_variable_1 = fields.Selection(selection=[('a', 'A')], string='Selection Variable 1', help="Help") selection_variable_2 = fields.Selection([('a', 'A')], "Selection Variable 2", help="Help") reference_variable_1 = fields.Reference(selection=[('res.user', 'User')], string="Reference Variable 1", help="Help") reference_variable_2 = fields.Reference([('res.user', 'User')], "Reference Variable 2", help="Help") many_2_one_variable_1 = fields.Many2one(comodel_name='res.users', string='Many 2 One Variable 1', help="Help") many_2_one_variable_2 = fields.Many2one('res.users', "Many 2 One Variable 2", help="Help") one_2_many_variable_1 = fields.One2many(comodel_name='res.users', inverse_name='rel_id', string='One 2 Many Variable 1', help="Help") one_2_many_variable_2 = fields.One2many('res.users', 'rel_id', "One 2 Many Variable 2", help="Help") many_2_many_variable_1 = fields.Many2many(comodel_name='res.users', relation='table_name', column1='col_name', column2='other_col_name', string='Many 2 Many Variable 1', help="Help") many_2_many_variable_2 = fields.Many2many('res.users', 'table_name', 'col_name', 'other_col_name', "Many 2 Many Variable 2", help="Help") field_case_sensitive = fields.Char('Field Case SENSITIVE', help="Field case sensitive") name_equal_to_string = fields.Float("Name equal to string", help="Name Equal To String") many_2_one = fields.Many2one('res.users', "Many 2 One", help="Many 2 one") many_2_many = fields.Many2many('res.users', 'relation', 'fk_column_from', 'fk_column_to', "Many 2 many", help="Many 2 Many") def my_method1(self, variable1): # Shouldn't show error of field-argument-translate self.my_method2(_('hello world')) # Message post without translation function self.message_post(subject='Subject not translatable', body='Body not translatable %s' % variable1) self.message_post(subject='Subject not translatable %(variable)s' % {'variable': variable1}, body='Body not translatable {}'.format(variable1), message_type='notification') self.message_post('Body not translatable', 'Subject not translatable {a}'.format(a=variable1)) self.message_post( 'Body not translatable %s' % variable1, 'Subject not translatable %(variable)s' % {'variable': variable1}) self.message_post('Body not translatable', subject='Subject not translatable') self.message_post( body='<h1>%s</h1><p>%s</p>' % (_('Paragraph translatable'), 'Paragraph not translatable')) # Message post with translation function self.message_post(subject=_('Subject translatable'), body=_('Body translatable')) self.message_post(_('Body translatable'), _('Subject translatable')) self.message_post(_('Body translatable'), subject=_('Subject translatable')) self.message_post(_('A CDR has been recovered for %s') % (variable1, )) self.message_post(_('A CDR has been recovered for %s') % variable1) self.message_post(_('Var {a}').format(a=variable1)) self.message_post(_('Var %(variable)s') % {'variable': variable1}) self.message_post(subject=_('Subject translatable'), body=_('Body translatable %s') % variable1) self.message_post(subject=_('Subject translatable %(variable)s') % {'variable': variable1}, message_type='notification') self.message_post(_('Body translatable'), _('Subject translatable {a}').format(a=variable1)) self.message_post( _('Body translatable %s') % variable1, _('Subject translatable %(variable)s') % {'variable': variable1}) self.message_post('<p>%s</p>' % _('Body translatable')) self.message_post(body='<p>%s</p>' % _('Body translatable')) # There is no way to know if the variable is translated, then ignoring self.message_post(variable1) self.message_post(body=variable1 + variable1) self.message_post(body=(variable1 + variable1)) self.message_post(body=variable1 % variable1) self.message_post(body=(variable1 % variable1)) # translation function with variables in the term variable2 = variable1 self.message_post(_('Variable not translatable: %s' % variable1)) self.message_post( _('Variables not translatable: %s, %s' % (variable1, variable2))) self.message_post(body=_('Variable not translatable: %s' % variable1)) self.message_post(body=_('Variables not translatable: %s %s' % (variable1, variable2))) error_msg = _('Variable not translatable: %s' % variable1) error_msg = _('Variables not translatable: %s, %s' % (variable1, variable2)) error_msg = _('Variable not translatable: {}'.format(variable1)) error_msg = _('Variables not translatable: {}, {variable2}'.format( variable1, variable2=variable2)) return error_msg def my_method2(self, variable2): return variable2 def my_method3(self, cr): cr.commit() # Dangerous use of commit old api self.env.cr.commit() # Dangerous use of commit self._cr.commit() # Dangerous use of commit self.cr.commit() # Dangerous use of commit return cr def my_method4(self, variable2): self.env.cr2.commit() # This should not be detected return variable2 def my_method5(self, variable2): self.env.cr.commit2() # This should not be detected return variable2 def my_method6(self): user_id = 1 if user_id != 99: # Method without translation raise UserError('String without translation') def my_method7(self): user_id = 1 if user_id != 99: # Method with translation raise UserError(_('String with translation')) def my_method8(self): user_id = 1 if user_id != 99: str_error = 'String with translation 2' # Don't check raise UserError(str_error) def my_method9(self): user_id = 1 if user_id != 99: # Method without translation raise UserError("String without translation 2") def my_method10(self): # A example of built-in raise without parameters # Shouldn't show error from lint raise ZeroDivisionError raise ZeroDivisionError() def my_method11(self): # A example of built-in raise with parameters # Shouldn't show error from lint raise ZeroDivisionError("String without translation") # raise without class-exception to increase coverage raise raise "obsolete case" def my_method12(self): # Should show error raise exceptions.Warning( 'String with params format {p1}'.format(p1='v1')) raise exceptions.Warning('qp2w String with params format %(p1)s' % {'p1': 'v1'}) def my_method13(self): # Shouldn't show error raise exceptions.Warning( _('String with params format {p1}').format(p1='v1')) raise exceptions.Warning( _('String with params format {p1}'.format(p1='v1'))) raise exceptions.Warning( _('String with params format %(p1)s') % {'p1': 'v1'}) raise exceptions.Warning( _('String with params format %(p1)s' % {'p1': 'v1'})) def old_api_method_alias(self, cursor, user, ids, context=None): # old api pass def sql_method(self, ids, cr): # Use of query parameters: nothing wrong here self._cr.execute('SELECT name FROM account WHERE id IN %s', (tuple(ids), )) self.env.cr.execute('SELECT name FROM account WHERE id IN %s', (tuple(ids), )) cr.execute('SELECT name FROM account WHERE id IN %s', (tuple(ids), )) self.cr.execute('SELECT name FROM account WHERE id IN %s', (tuple(ids), )) def sql_injection_ignored_cases(self, ids, cr2): # This cr.execute2 or cr2.execute should not be detected self._cr.execute2('SELECT name FROM account WHERE id IN %s' % (tuple(ids), )) cr2.execute('SELECT name FROM account WHERE id IN %s' % (tuple(ids), )) # Ignore when the query is built using private attributes self._cr.execute('DELETE FROM %s WHERE id IN %%s' % self._table, (tuple(ids), )) # Ignore string parsed with "".format() if args are psycopg2.sql.* calls query = "SELECT * FROM table" # imported from pyscopg2 import sql self._cr.execute( sql.SQL("""CREATE or REPLACE VIEW {} as ({})""").format( sql.Identifier(self._table), sql.SQL(query))) self._cr.execute( sql.SQL("""CREATE or REPLACE VIEW {table} as ({query})""").format( table=sql.Identifier(self._table), query=sql.SQL(query), )) # imported from pyscopg2.sql import SQL, Identifier self._cr.execute( SQL("""CREATE or REPLACE VIEW {} as ({})""").format( Identifier(self._table), SQL(query), )) self._cr.execute( SQL("""CREATE or REPLACE VIEW {table} as ({query})""").format( table=Identifier(self._table), query=SQL(query), )) # imported from pyscopg2 direclty self._cr.execute( psycopg2.SQL("""CREATE or REPLACE VIEW {} as ({})""").format( psycopg2.sql.Identifier(self._table), psycopg2.sql.SQL(query), )) self._cr.execute( psycopg2.sql.SQL( """CREATE or REPLACE VIEW {table} as ({query})""").format( table=Identifier(self._table), query=SQL(query), )) # Variables build using pyscopg2.sql.* callers table = Identifier('table_name') sql_query = SQL(query) # format params self._cr.execute( SQL("""CREATE or REPLACE VIEW {} as ({})""").format( table, sql_query, )) # format dict self._cr.execute( SQL("""CREATE or REPLACE VIEW {table} as ({query})""").format( table=table, query=sql_query, )) # old api def sql_injection_modulo_operator(self, cr, uid, ids, context=None): # Use of % operator: risky self._cr.execute('SELECT name FROM account WHERE id IN %s' % (tuple(ids), )) self.env.cr.execute('SELECT name FROM account WHERE id IN %s' % (tuple(ids), )) cr.execute('SELECT name FROM account WHERE id IN %s' % (tuple(ids), )) self.cr.execute('SELECT name FROM account WHERE id IN %s' % (tuple(ids), )) operator = 'WHERE' self._cr.execute('SELECT name FROM account %s id IN %%s' % operator, ids) var = 'SELECT name FROM account WHERE id IN %s' values = ([ 1, 2, 3, ], ) self._cr.execute(var % values) def sql_injection_executemany(self, ids, cr, v1, v2): # Check executemany() as well self.cr.executemany('INSERT INTO account VALUES (%s, %s)' % (v1, v2)) def sql_injection_format(self, ids, cr): # Use of .format(): risky self.cr.execute('SELECT name FROM account WHERE id IN {}'.format(ids)) def sql_injection_plus_operator(self, ids, cr): # Use of +: risky self.cr.execute('SELECT name FROM account WHERE id IN ' + str(tuple(ids))) operator = 'WHERE' self._cr.execute('SELECT name FROM account ' + operator + ' id IN %s', ids) self.cr.execute( ('SELECT name FROM account ' + operator + ' id IN (1)')) self.cr.execute('SELECT name FROM account ' + operator + ' id IN %s' % (tuple(ids), )) self.cr.execute( ('SELECT name FROM account ' + operator + ' id IN %s') % (tuple(ids), )) def sql_injection_before(self, ids): # query built before execute: risky as well var = 'SELECT name FROM account WHERE id IN %s' % tuple(ids) self._cr.execute(var) var[1] = 'SELECT name FROM account WHERE id IN %s' % tuple(ids) self._cr.execute(var[1]) def sql_no_injection_private_attributes(self, _variable, variable): # Skip sql-injection using private attributes self._cr.execute("CREATE VIEW %s AS (SELECT * FROM res_partner)" % self._table) # Real sql-injection cases self._cr.execute("CREATE VIEW %s AS (SELECT * FROM res_partner)" % self.table) self._cr.execute("CREATE VIEW %s AS (SELECT * FROM res_partner)" % _variable) self._cr.execute("CREATE VIEW %s AS (SELECT * FROM res_partner)" % variable)
class SmsTemplate(models.Model): _name = "sms.template" name = fields.Char(required=True, string='Template Name', translate=True) model_id = fields.Many2one( 'ir.model', string='Applies to', help="The kind of document with with this template can be used") model = fields.Char(related="model_id.model", string='Related Document Model', store=True, readonly=True) template_body = fields.Text( 'Body', translate=True, help="Plain text version of the message (placeholders may be used here)" ) sms_from = fields.Char( string='From (Mobile)', help= "Sender mobile number (placeholders may be used here). If not set, the default value will be the author's mobile number." ) sms_to = fields.Char( string='To (Mobile)', help="To mobile number (placeholders may be used here)") account_gateway_id = fields.Many2one('sms.account', string="Account") model_object_field_id = fields.Many2one( 'ir.model.fields', string="Field", help= "Select target field from the related document model.\nIf it is a relationship field you will be able to select a target field at the destination of the relationship." ) sub_object_id = fields.Many2one( 'ir.model', string='Sub-model', readonly=True, help= "When a relationship field is selected as first field, this field shows the document model the relationship goes to." ) sub_model_object_field_id = fields.Many2one( 'ir.model.fields', string='Sub-field', help= "When a relationship field is selected as first field, this field lets you select the target field within the destination document model (sub-model)." ) null_value = fields.Char( string='Default Value', help="Optional value to use if the target field is empty") copyvalue = fields.Char( string='Placeholder Expression', help= "Final placeholder expression, to be copy-pasted in the desired template field." ) lang = fields.Char( string='Language', help= "Optional translation language (ISO code) to select when sending out an email. If not set, the english version will be used. This should usually be a placeholder expression that provides the appropriate language, e.g. ${object.partner_id.lang}.", placeholder="${object.partner_id.lang}") from_mobile_verified_id = fields.Many2one('sms.number', string="From Mobile (stored)") from_mobile = fields.Char(string="From Mobile", help="Placeholders are allowed here") media_id = fields.Binary(string="Media(MMS)") media_filename = fields.Char(string="Media Filename") media_ids = fields.Many2many('ir.attachment', string="Media(MMS)[Automated Actions Only]") @api.onchange('model_object_field_id') def _onchange_model_object_field_id(self): if self.model_object_field_id.relation: self.sub_object_id = self.env['ir.model'].search([ ('model', '=', self.model_object_field_id.relation) ])[0].id else: self.sub_object_id = False if self.model_object_field_id: self.copyvalue = self.build_expression( self.model_object_field_id.name, self.sub_model_object_field_id.name, self.null_value) @api.onchange('sub_model_object_field_id') def _onchange_sub_model_object_field_id(self): if self.sub_model_object_field_id: self.copyvalue = self.build_expression( self.model_object_field_id.name, self.sub_model_object_field_id.name, self.null_value) @api.onchange('from_mobile_verified_id') def _onchange_from_mobile_verified_id(self): if self.from_mobile_verified_id: self.from_mobile = self.from_mobile_verified_id.mobile_number @api.model def send_sms(self, template_id, record_id): """Send the sms using all the details in this sms template, using the specified record ID""" sms_template = self.env['sms.template'].browse(int(template_id)) rendered_sms_template_body = self.env['sms.template'].render_template( sms_template.template_body, sms_template.model_id.model, record_id) rendered_sms_to = self.env['sms.template'].render_template( sms_template.sms_to, sms_template.model_id.model, record_id) gateway_model = sms_template.from_mobile_verified_id.account_id.account_gateway_id.gateway_model_name #Queue the SMS message since we can't directly send MMS queued_sms = self.env['sms.message'].create({ 'record_id': record_id, 'model_id': sms_template.model_id.id, 'account_id': sms_template.from_mobile_verified_id.account_id.id, 'from_mobile': sms_template.from_mobile, 'to_mobile': rendered_sms_to, 'sms_content': rendered_sms_template_body, 'direction': 'O', 'message_date': datetime.utcnow(), 'status_code': 'queued' }) #Also create the MMS attachment if sms_template.media_id: self.env['ir.attachment'].sudo().create({ 'name': 'mms ' + str(queued_sms.id), 'type': 'binary', 'datas': sms_template.media_id, 'public': True, 'res_model': 'sms.message', 'res_id': queued_sms.id }) #Turn the queue manager on self.env['ir.model.data'].get_object('sms_frame', 'sms_queue_check').active = True def render_template(self, template, model, res_id): """Render the given template text, replace mako expressions ``${expr}`` with the result of evaluating these expressions with an evaluation context containing: * ``user``: browse_record of the current user * ``object``: browse_record of the document record this mail is related to * ``context``: the context passed to the mail composition wizard :param str template: the template text to render :param str model: model name of the document record this mail is related to. :param int res_id: id of document records those mails are related to. """ # try to load the template #try: template = mako_template_env.from_string(tools.ustr(template)) #except Exception: # _logger.error("Failed to load template %r", template) # return False # prepare template variables user = self.env.user record = self.env[model].browse(res_id) variables = {'user': user} variables['object'] = record try: render_result = template.render(variables) except Exception: _logger.error("Failed to render template %r using values %r" % (template, variables)) render_result = u"" if render_result == u"False": render_result = u"" return render_result @api.model def build_expression(self, field_name, sub_field_name, null_value): """Returns a placeholder expression for use in a template field, based on the values provided in the placeholder assistant. :param field_name: main field name :param sub_field_name: sub field name (M2O) :param null_value: default value if the target value is empty :return: final placeholder expression """ expression = '' if field_name: expression = "${object." + field_name if sub_field_name: expression += "." + sub_field_name if null_value: expression += " or '''%s'''" % null_value expression += "}" return expression
class website_menu(models.Model): _inherit = 'website.menu' page_title = fields.Char(default='Page Title') image = fields.Binary()
class msl_report(models.TransientModel): _name = 'msl.report' _description = "MSL Report" name = fields.Char(string="MSLReport", compute="_get_name") date_from = fields.Date(string="Date From", default=lambda self: fields.datetime.now()) date_to = fields.Date(string="Date To", default=lambda self: fields.datetime.now()) attachment_id = fields.Many2one('ir.attachment', string="Attachment", ondelete='cascade') datas = fields.Binary(string="XLS Report", related="attachment_id.datas") @api.constrains('date_from', 'date_to') @api.depends('date_from', 'date_to') def date_range_check(self): if self.date_from and self.date_to and self.date_from > self.date_to: raise ValidationError( _("Start Date should be before or be the same as End Date.")) return True @api.depends('date_from', 'date_to') @api.multi def _get_name(self): rep_name = "MSL_Report" if self.date_from and self.date_to: date_from = datetime.datetime.strptime( self.date_from, tools.DEFAULT_SERVER_DATE_FORMAT).strftime('%d-%b-%Y') date_to = datetime.datetime.strptime( self.date_to, tools.DEFAULT_SERVER_DATE_FORMAT).strftime('%d-%b-%Y') if self.date_from == self.date_to: rep_name = "MSL Report(%s)" % (date_from, ) else: rep_name = "MSL Report(%s|%s)" % (date_from, date_to) self.name = rep_name @api.multi def print_report(self): if self.date_from and self.date_to: if not self.attachment_id: quant_list = [] file_name = self.name # Created Excel Workbook and Sheet workbook = xlwt.Workbook() worksheet = workbook.add_sheet('Sheet 1') main_style = xlwt.easyxf( 'font: bold on, height 400; align: wrap 1, vert centre, horiz center; borders: bottom thick, top thick, left thick, right thick' ) sp_style = xlwt.easyxf('font: bold on, height 350;') header_style = xlwt.easyxf( 'font: bold on, height 220; align: wrap 1, horiz center; borders: bottom thin, top thin, left thin, right thin' ) base_style = xlwt.easyxf( 'align: wrap 1; borders: bottom thin, top thin, left thin, right thin' ) worksheet.write_merge(0, 1, 0, 4, file_name, main_style) row_index = 2 worksheet.col(0).width = 4000 worksheet.col(1).width = 4000 worksheet.col(2).width = 10000 worksheet.col(3).width = 4000 worksheet.col(4).width = 4000 worksheet.col(5).width = 4000 # Headers header_fields = [ 'Code', 'HSN', 'Description', 'MSL', 'Closing Bal', 'Supplier' ] row_index += 1 for index, value in enumerate(header_fields): worksheet.write(row_index, index, value, header_style) row_index += 1 product_ids = self.env['product.product'].search([]) quant_ids = self.env['stock.quant'].sudo().search([]) for quant_id in quant_ids: in_date = datetime.datetime.strptime( quant_id.in_date, tools.DEFAULT_SERVER_DATETIME_FORMAT).date().strftime( tools.DEFAULT_SERVER_DATE_FORMAT) if in_date >= self.date_from and in_date <= self.date_to: quant_list.append(quant_id) if (not quant_list): # not quant_ids raise Warning(_('Record Not Found')) if quant_list: for rec in quant_list: worksheet.write(row_index, 0, rec.product_id.default_code or '', base_style) worksheet.write(row_index, 1, rec.product_id.hsn_code or '', base_style) worksheet.write(row_index, 2, rec.product_id.name, base_style) worksheet.write(row_index, 3, '', base_style) worksheet.write(row_index, 4, '', base_style) worksheet.write(row_index, 5, '', base_style) row_index += 1 fp = StringIO() workbook.save(fp) fp.seek(0) data = fp.read() fp.close() encoded_data = base64.encodestring(data) local_tz = pytz.timezone(self._context.get('tz') or 'UTC') attach_vals = { 'name': '%s' % (file_name), 'datas': encoded_data, 'datas_fname': '%s.xls' % (file_name), 'res_model': 'msl.report', } doc_id = self.env['ir.attachment'].create(attach_vals) self.attachment_id = doc_id.id return { 'type': 'ir.actions.act_url', 'url': '/web/binary/download_document?model=%s&field=%s&id=%s&filename=%s.xls' % (self.attachment_id.res_model, 'datas', self.id, self.attachment_id.name), 'target': 'self', }