def confirm(cls, sales): Warning = Pool().get('res.user.warning') # make sure noone is able to confirm a sale with shipment or invoice methods we do not want for sale in sales: if sale.shipment_method != 'order': raise UserError('Liefermethode ungültig') if sale.invoice_method != 'shipment': raise UserError('Rechnungmethode ungültig') if not sale.payment_term: raise UserError('Keine Zahlungsbedingungen angegeben!') # first check if we have a line without product and issue a warning warning_name = 'saleline_noproduct,%s' % cls need_fixing = [] for sale in sales: if not sale.party.pn_name or len(sale.party.pn_name.strip()) < 1: raise UserError( 'Verkaufsparteien müssen einen PN Namen zugewiesen haben.') for line in sale.lines: if not line.product: need_fixing.append(line.rec_name) if Warning.check(warning_name): if need_fixing: msg = 'Position ohne Produkt gefunden!!' #msg += '\n'.join(need_fixing) raise UserWarning(warning_name, msg) # check if we already have an order fromt his customer for this date with the same sale_date_extra warning_sale_date_extra = 'sale_date_extra,%s' % cls warn_sale_date = [] for sale in sales: others = Pool().get('sale.sale').search([ ('sale_folder_postfix', '=', sale.sale_folder_postfix), ('party', '=', sale.party), ('sale_date', '=', sale.sale_date), ('number', '!=', sale.number), ]) for s in others: warn_sale_date.append(s.number) if Warning.check(warning_sale_date_extra): if warn_sale_date: msg = 'Verkauf für diesen Kunden mit gleichem Bestelldatum und Bestellordner Zusatz existiert bereits:' msg += '\n'.join(warn_sale_date) raise UserWarning(warning_sale_date_extra, msg) # give the users a warning before actually confirming an order and creating shipments,.. confirm_warning = 'sale_confirm,%s' % cls if Warning.check(confirm_warning): raise UserWarning( confirm_warning, 'Bestätigen des Verkaufs erzeugt einen Lieferschein - fortfahren?' ) super(Sale, cls).confirm(sales)
def raise_user_warning(cls, warning_name, warning, warning_args=None, warning_description='', warning_description_args=None): ''' Raise an exception that will be displayed as a warning message in the client, if the user has not yet bypassed it. :param warning_name: the unique warning name :param warning: the key of the dictionary _error_messages used for warning message :param warning_args: the arguments that will be used for "%"-based substitution :param warning_description: the key of the dictionary _error_messages used for warning description :param warning_description_args: the arguments that will be used for "%"-based substitution ''' Warning_ = Pool().get('res.user.warning') if Warning_.check(warning_name): if warning_description: warning, warning_description = cls.raise_user_error(warning, error_args=warning_args, error_description=warning_description, error_description_args=warning_description_args, raise_exception=False) raise UserWarning(warning_name, warning, warning_description) else: warning = cls.raise_user_error(warning, error_args=warning_args, raise_exception=False) raise UserWarning(warning_name, warning)
def raise_user_warning(cls, warning_name, warning, warning_args=None, warning_description='', warning_description_args=None): ''' Raise an exception that will be displayed as a warning message in the client, if the user has not yet bypassed it. :param warning_name: the unique warning name :param warning: the key of the dictionary _error_messages used for warning message :param warning_args: the arguments that will be used for "%"-based substitution :param warning_description: the key of the dictionary _error_messages used for warning description :param warning_description_args: the arguments that will be used for "%"-based substitution ''' Warning_ = Pool().get('res.user.warning') if Warning_.check(warning_name): if warning_description: warning, warning_description = cls.raise_user_error( warning, error_args=warning_args, error_description=warning_description, error_description_args=warning_description_args, raise_exception=False) raise UserWarning(warning_name, warning, warning_description) else: warning = cls.raise_user_error(warning, error_args=warning_args, raise_exception=False) raise UserWarning(warning_name, warning)
def delete(self, ids): ''' Delete records. :param ids: a list of ids or an id :return: True if succeed ''' model_access_obj = Pool().get('ir.model.access') model_access_obj.check(self._name, 'delete') if not self.check_xml_record(ids, None): self.raise_user_error('delete_xml_record', error_description='xml_record_desc') # Clean cursor cache for cache in Transaction().cursor.cache.values(): for cache in (cache, cache.get('_language_cache', {}).values()): if self._name in cache: if isinstance(ids, (int, long)): ids = [ids] for i in ids: if i in cache[self._name]: del cache[self._name][i] return False
def copy_from(self, from_table): Warning = Pool().get('res.user.warning') fields = {x.name for x in self.fields} from_fields = {x.name for x in from_table.fields} missing = sorted(list(from_fields - fields)) existing = fields & from_fields fields = {} for field in self.fields: if field.name in existing: fields[field.name] = field.type different_types = [] for field in from_table.fields: if field.name in existing: if (FIELD_TYPE_TRYTON[field.type] != FIELD_TYPE_TRYTON[fields[field.name]]): different_types.append( "%s (%s -> %s)" % (field.name, field.type, fields[field.name])) existing.remove(field.name) if missing or different_types: message = ['- %s' % x for x in (missing + different_types)] key = 'shine_copy_from_warning.%s.%s' % (self.name, from_table.id), if Warning.check(key): raise UserWarning( key, gettext('shine.copy_from_warning', fields='\n'.join(message), from_table=from_table.rec_name, table=self.rec_name)) if not existing: return existing = sorted(list(existing)) table = sql.Table(from_table.name) subquery = table.select() subquery.columns = [sql.Column(table, x) for x in existing] table = sql.Table(self.name) query = table.insert([sql.Column(table, x) for x in existing], subquery) cursor = Transaction().connection.cursor() cursor.execute(*query)
def check_diagnosis_length(cls, details): Warning = Pool().get('res.user.warning') for detail in details: if not detail.template or not detail.template.diagnosis_length: continue diagnosis_length = detail.template.diagnosis_length for sample in detail.samples: if not sample.diagnosis: continue if len(sample.diagnosis) > diagnosis_length: key = 'lims_diagnosis_length@%s' % sample.id if Warning.check(key): raise UserWarning( key, gettext( 'lims_diagnosis.msg_invalid_diagnosis_length', length=str(len(sample.diagnosis)), allowed=str(diagnosis_length)))
def set_totp_secret(cls, users, name, value): Warning = Pool().get('res.user.warning') if value: try: key = _TOTPFactory(key=value).to_json() except BinAsciiError: raise TOTPInvalidSecretError( gettext('authentication_totp.msg_user_invalid_totp_secret', login=users[0].login)) else: key = None if cls._totp_admin() and cls._totp_key_length_too_short(key): warning_name = 'authentication_totp.key_too_short' if Warning.check(warning_name): raise TOTPKeyTooShortWarning( warning_name, gettext('authentication_totp.msg_user_totp_too_short', login=users[0].login)) cls.write(list(users), { 'totp_key': key, })
class WfsRequest(object): def __init__(self): self.tmpl_loader = TemplateLoader( os.path.join(os.path.dirname(__file__), 'templates'), auto_reload=True, default_class=MarkupTemplate, ) WfsConf = Pool().get('wfs.conf') conf = WfsConf.search([]) if len(conf) == 0: self.show_non_geo = False self.default_geo = False else: self.show_non_geo = conf[0].show_non_geo self.default_geo = conf[0].default_geo self.url = WfsConf.get_url() self.model_access = Pool().get('ir.model.access') self.field_access = Pool().get('ir.model.field.access') def access_check(self, model, field=None, mode='read', raise_exception=True): allowed = True try: allowed &= self.model_access.check(model, mode, raise_exception=False) if field is not None: allowed &= self.field_access.check(model, [field], mode, raise_exception=False) except: allowed = False if not allowed and raise_exception: raise Exception('Permission denied') return allowed def _parse_args(self, **kw): _kw = {} for arg, val in kw.iteritems(): if isinstance(val, str): _kw[arg.lower()] = unquote(val) if 'acceptversions' in _kw: version = _kw.pop('acceptversions') if WFS_VERSION not in version.split(','): raise Exception('Unsupported version, server version %s, client version %s' % (WFS_VERSION, version)) if 'version' in _kw: self.version = _kw.pop('version') if self.version.split('.') > WFS_VERSION.split('.'): logger.warning('Wfs version of client is superior than our version (1.0.0)') else: self.version = '' service = _kw.pop('service', 'wfs').lower() if service != 'wfs': raise Exception('Invalid service %s, expected WFS' % service) if 'srsname' in _kw: _kw['srsname'] = int(_kw['srsname'].split(':')[1]) return _kw def handle(self, **kw): _kw = self._parse_args(**kw) request = _kw.pop('request').lower() if request in WFS_REQUESTS and hasattr(self, request): return getattr(self, request)(**_kw) return self.getcapabilities() def getcapabilities(self, bbox=[], srsname=0, **kw): Field = Pool().get('ir.model.field') features = [] models = [] if bbox != []: bbox = [float(nbr) for nbr in bbox.split(',')] domain = ['OR'] + [[('ttype', '=', geo_type)] for geo_type in GEO_TYPES] fields = Field.search(domain) for field in fields: model = field.model.model if not self.access_check(model, raise_exception=False): continue Model = Pool().get(model) records = Model.search([], limit=1) # Check the table contains records in the bbox models.append(model) cursor = Transaction().cursor table = model.replace('.', '_') if Model.table_query() : table = '('+Model.table_query()[0]%tuple(Model.table_query()[1])+') AS mytable' col = field.name if bbox != [] and srsname != 0: sql = 'SELECT ST_Extent(Box2D(%(col)s)) FROM %(table)s WHERE\ ST_Intersects(\ ST_SetSRID(\ ST_MakeBox2D(\ ST_MakePoint(%(xmin)s, %(ymin)s),\ ST_MakePoint(%(xmax)s, %(ymax)s)\ ), %(srsname)s\ ), %(col)s )' % { 'col': col, 'table': table, 'xmin' : bbox[0], 'ymin' : bbox[1], 'xmax' : bbox[2], 'ymax' : bbox[3], 'srsname' : srsname} cursor.execute(sql) else: try: cursor.execute('SELECT ST_Estimated_Extent(\'%s\', \'%s\');' % (table, col)) except: cursor.connection.rollback() cursor.execute('SELECT ST_Extent(Box2D(%s)) FROM %s;' % (col, table)) feature_bbox = cursor.fetchall() if len(feature_bbox) != 0 and len(feature_bbox[0]) != 0 and feature_bbox[0][0] is not None: feature_bbox = feature_bbox[0][0] feature_bbox = feature_bbox.replace('BOX(', '') feature_bbox = feature_bbox.replace(')', '') tl, ur = feature_bbox.split(',') feature_bbox = tl.split(' ') + ur.split(' ') else: feature_bbox = None features.append({ 'title': field.model.name, 'name': field.model.model, 'srs': 'EPSG:%s' % getattr(Model, field.name).srid, 'bbox': feature_bbox, }) if self.show_non_geo: Model = Pool().get('ir.model') domain = [('model', '!=', model) for model in models] for model in Model.search(domain): if not self.access_check(model.model, raise_exception=False): continue m = Pool().get(model.model) if not hasattr(m, 'search'): continue records = m.search([], limit=1) features.append({ 'title': model.name, 'name': model.model, 'srs': '', 'bbox': None, }) # Sort models features = sorted(features, key=lambda x: x['title']) wfs_capabilities = self.tmpl_loader.load('wfs_capabilities.xml') rendered = wfs_capabilities.generate(name='Tryton', title='Tryton WFS module', abstract='Tryton WFS module', url=self.url, features=features).render() return rendered def describefeaturetype(self, typename, **kw): tryton, model = typename.split(':', 1) if tryton != 'tryton': raise Exception('Unknown feature type %s' % typename) self.access_check(model) Fields = Pool().get('ir.model.field') fields = Fields.search([('model.model', '=', model)]) elements = [] for field in fields: if field.name in TRYTON_FIELDS: continue if not self.access_check(model, field.name, raise_exception=False): continue nillable = 'true' if hasattr(field, 'required') and field.required: nillable = 'false' if get_wfs_type(field.ttype) == {}: continue element = { 'name': field.name, 'type': get_wfs_type(field.ttype), 'nillable': nillable, } elements.append(element) wfs_featuretype = self.tmpl_loader.load('wfs_featuretype.xml') rendered = wfs_featuretype.generate(name=fields[0].model.model, elements=elements).render() return rendered def getfeature(self, typename, filter='', srsname=0, maxfeatures=1024, bbox=[], **kw): tryton, model = typename.split(':', 1) if tryton != 'tryton': raise Exception('Unknown feature %s' % typename) self.access_check(model) if bbox != []: bbox = [float(nbr) for nbr in bbox.split(',')] Fields = Pool().get('ir.model.field') fields = Fields.search([('model.model', '=', model)]) Model = Pool().get(model) factory = ElementFactory() cursor = Transaction().cursor records = None filter_domain = filter2domain(filter) # Find a geometry field and select records in the bbox if there is one if bbox != []: for field in fields: if field.ttype not in GEO_TYPES: continue if not self.access_check(model, field.name, raise_exception=False): continue sql = 'SELECT id FROM %(table)s WHERE\ ST_Intersects(\ ST_SetSRID(\ ST_MakeBox2D(\ ST_MakePoint(%(xmin)s, %(ymin)s),\ ST_MakePoint(%(xmax)s, %(ymax)s)\ ), %(srsname)s\ ), %(col)s\ ) LIMIT %(maxfeatures)s' % { 'table' : model.replace('.', '_'), 'col' : field.name, 'xmin' : bbox[0], 'ymin' : bbox[1], 'xmax' : bbox[2], 'ymax' : bbox[3], 'srsname' : srsname, 'maxfeatures' : maxfeatures } cursor.execute(sql) domain = [[('id', '=', col[0])] for col in cursor.fetchall()] if len(domain) == 0: continue domain = ['AND', filter_domain, [['OR'] + domain]] records = Model.search(domain, limit=maxfeatures) break else: records = Model.search(filter_domain, limit=maxfeatures) if not records: records = [] print len(records), ' features returned' fbbox = None elems = [] for record in records: elem = getattr(factory, 'gml:featureMember') tag = getattr(factory, 'tryton:%s' % model)(fid='%s.%i' % (model, record.id)) elem.children.append(tag) elems.append(elem) for field in fields: if field.name in TRYTON_FIELDS: continue if not self.access_check(model, field.name, raise_exception=False): continue if get_wfs_type(field.ttype) == {}: continue if field.ttype in GEO_TYPES: cursor.execute('SELECT ST_AsGML(%s) FROM %s WHERE id=%s' % (field.name, model.replace('.', '_'), record.id)) ret = cursor.fetchall() if ret[0][0] is None and self.default_geo: # when there is no geometry, create one if bbox == []: if srsname == 0 or srsname == 2154: srsname = 2154 # EPSG:2154 projected boundaries fbbox = [ -357823.2365, 6037008.6939, 1313632.3628, 7230727.3772 ] else: # TODO: handle this case raise Exception('You must specify a bounding box when using an srsname different of EPSG:2154') else: fbbox = bbox xmin = fbbox[0] + ((fbbox[2] - fbbox[0]) * 0.25) xmax = fbbox[0] + ((fbbox[2] - fbbox[0]) * 0.75) ymin = fbbox[1] + ((fbbox[3] - fbbox[1]) * 0.25) ymax = fbbox[1] + ((fbbox[3] - fbbox[1]) * 0.75) if field.ttype == 'multipolygon': cursor.execute("SELECT ST_AsGML(ST_GeomFromEWKT('srid=%i;multipolygon( ((%s %s, %s %s, %s %s, %s %s, %s %s)) )'))" % (srsname, xmin, ymin, xmin, ymax, xmax, ymax, xmax, ymin, xmin, ymin), ()) val = Markup(cursor.fetchall()[0][0]) elif field.ttype == 'multilinestring': cursor.execute("SELECT ST_AsGML(ST_GeomFromEWKT('srid=%i;multilinestring( (%s %s, %s %s, %s %s, %s %s) )'))" % (srsname, xmin, ymin, xmin, ymax, xmax, ymax, xmax, ymin), ()) val = Markup(cursor.fetchall()[0][0]) elif field.ttype == 'multipoint': cursor.execute("SELECT ST_AsGML(ST_GeomFromEWKT('srid=%i;multipoint(%s %s, %s %s)'))" % (srsname, xmin, ymin, xmin, ymax), ()) val = Markup(cursor.fetchall()[0][0]) elif ret[0][0] is None: val = '' else: val = Markup(ret[0][0]) else: val = getattr(record, field.name) if val is None: val = '' elif field.ttype == 'many2one': val = val.id _field = getattr(ElementFactory(), 'tryton:%s' % field.name)() _field.children.append(val) tag.children.append(_field) wfs_feature = self.tmpl_loader.load('wfs_feature.xml') rendered = wfs_feature.generate(url=self.url, ttype='tryton:%s' % model, elems=elems).render() return rendered def post(self, data, **kw): data = parseString(data) data = data.firstChild if data.nodeName != 'Transaction': raise Exception('Invalid transaction') inserts = [] deletes = [] updates = [] _kw = self._parse_args(**kw) srsname = _kw.get('srsname', 0) for trans_type in ('Delete', 'Update', 'Insert'): for transaction in data.childNodes: if transaction.nodeName != trans_type: continue if transaction.nodeName in ('Update', 'Delete'): typename = transaction.getAttribute('typeName') tryton, model = typename.split(':', 1) else: if transaction.firstChild is None: raise Exception('Invalid transaction') typename = transaction.firstChild.nodeName model = typename tryton = 'tryton' tryton_op = WFS_OPERATIONS[transaction.nodeName] self.access_check(model, mode=tryton_op) Model = None try: Model = Pool().get(model) except: pass if Model is None or tryton != 'tryton': raise Exception('Unknown feature type %s' % typename) if srsname == 0: for field in Model._fields.itervalues(): if field._type in GEO_TYPES: srsname = field.srid break else: raise Exception('Srid is not set, cannot modify geometry') geo_field = None field = None value = None record_id = None to_delete = [] record = {} if transaction.nodeName in ('Update', 'Delete'): children = transaction.childNodes elif transaction.nodeName == 'Insert': children = transaction.firstChild.childNodes for child in children: if transaction.nodeName in ('Update', 'Delete'): if child.nodeName == 'Property': for property in child.childNodes: if property.nodeName == 'Name': field = property.firstChild.data self.access_check(model, field, mode=tryton_op) elif property.nodeName == 'Value': if (property.hasChildNodes() and property.firstChild.namespaceURI == GML_NS): value = gml2sql(property.firstChild.toxml(), getattr(Model, field)) geo_field = field else: if property.firstChild is not None: value = property.firstChild.nodeValue else: value = None else: raise Exception('Unhandled node type %s' % property.nodeName) elif child.nodeName == 'Filter': for subchild in child.childNodes: if subchild.nodeName == 'FeatureId': fid = subchild.getAttribute('fid') _model, record_id = fid.rsplit('.', 1) if transaction.nodeName == 'Delete': to_delete.append(int(record_id)) if model != _model: raise Exception('fid doesn\'t match the typename of the model (%s != %s)' % (model, _model)) else: raise Exception('Unhandled node type %s' % child.nodeName) else: raise Exception('Unhandled node type %s' % child.nodeName) elif transaction.nodeName == 'Insert': field = child.nodeName if (child.hasChildNodes() and child.firstChild.namespaceURI == GML_NS): value = gml2sql(child.firstChild.toxml(), getattr(Model, field)) geo_field = field else: if child.firstChild is None: value = None else: value = child.firstChild.nodeValue if trans_type != 'Delete': if field == 'id': continue if getattr(Model, field).readonly: continue record[field] = value if transaction.nodeName == 'Insert' and record != {}: if geo_field is not None: value = record.pop(geo_field) record = Model.create([record])[0] if geo_field is not None: cursor = Transaction().cursor cursor.execute('UPDATE %s SET %s = %s WHERE id = %%s' % (model.replace('.', '_'), field, value), (record.id,)) inserts.append('%s.%i' % (model, record.id)) elif transaction.nodeName == 'Delete': Model.delete(to_delete) to_delete = ['%s.%s' % (model, _id) for _id in to_delete] deletes += to_delete elif transaction.nodeName == 'Update' and record != {}: fields = record.keys() sql = 'UPDATE %s SET ' % model.replace('.', '_') sql += ', '.join(['%s = %%s' % field for field in fields]) sql += ' WHERE id = %s' sql_args = [record[field] for field in fields] sql_args.append(record_id) cursor = Transaction().cursor cursor.execute(sql, sql_args) updates.append('%s.%s' % (model, record_id)) wfs_trans_summary = self.tmpl_loader.load('wfs_trans_response.xml') rendered = wfs_trans_summary.generate(updates=updates, deletes=deletes, inserts=inserts).render() return rendered def format_exc(self): wfs_error = self.tmpl_loader.load('wfs_error.xml') if CONFIG['log_level'].upper() == 'DEBUG': tb_s = ''.join(format_exception(*sys.exc_info())) for path in sys.path: tb_s = tb_s.replace(path, '') else: tb_s = ''.join(format_exception_only(*sys.exc_info()[:2])) error_msg = escape(tb_s.decode('utf-8')) rendered = wfs_error.generate(error_msg=error_msg).render() return rendered
def _totp_admin(cls): ModelAccess = Pool().get('ir.model.access') return ModelAccess.check('res.user', mode='write', raise_exception=False)