def __init__(self, pool, cr): """ Dynamically add columns.""" super(report_prompt_class, self).__init__(pool, cr) for counter in range(0, MAX_PARAMS): field_name = PARAM_XXX_STRING_VALUE % counter self._columns[field_name] = fields.char('String Value', size=64) field_name = PARAM_XXX_BOOLEAN_VALUE % counter self._columns[field_name] = fields.boolean('Boolean Value') field_name = PARAM_XXX_INTEGER_VALUE % counter self._columns[field_name] = fields.integer('Integer Value') field_name = PARAM_XXX_NUMBER_VALUE % counter self._columns[field_name] = fields.float('Number Value') field_name = PARAM_XXX_DATE_VALUE % counter self._columns[field_name] = fields.date('Date Value') field_name = PARAM_XXX_TIME_VALUE % counter self._columns[field_name] = fields.datetime('Time Value') self.paramfile = False
def __init__(self, pool, cr): """ Dynamically add columns.""" super(report_prompt_class, self).__init__(pool, cr) for counter in range(0, MAX_PARAMS): field_name = PARAM_XXX_STRING_VALUE % counter self._columns[field_name] = fields.char('String Value', size=64) field_name = PARAM_XXX_BOOLEAN_VALUE % counter self._columns[field_name] = fields.boolean('Boolean Value') field_name = PARAM_XXX_INTEGER_VALUE % counter self._columns[field_name] = fields.integer('Integer Value') field_name = PARAM_XXX_NUMBER_VALUE % counter self._columns[field_name] = fields.float('Number Value') field_name = PARAM_XXX_DATE_VALUE % counter self._columns[field_name] = fields.date('Date Value') field_name = PARAM_XXX_TIME_VALUE % counter self._columns[field_name] = fields.datetime('Time Value') field_name = PARAM_XXX_2M_VALUE % counter self._columns[field_name] = fields.function(self._multi_select_values.im_func, arg={"entry_num": counter}, fnct_inv=self._multi_select_values_store.im_func, fnct_inv_arg={"entry_num": counter}, method=False, type='many2many', relation='ir.actions.report.multivalues.promptwizard', string='Multi-Select')
class purchase_report(osv.osv): _name = "purchase.report" _description = "Purchases Orders" _auto = False _columns = { 'date': fields.datetime('Order Date', readonly=True, help="Date on which this document has been created" ), # TDE FIXME master: rename into date_order 'state': fields.selection([('draft', 'Request for Quotation'), ('confirmed', 'Waiting Vendor Ack'), ('approved', 'Approved'), ('except_picking', 'Shipping Exception'), ('except_invoice', 'Invoice Exception'), ('done', 'Done'), ('cancel', 'Cancelled')], 'Order Status', readonly=True), 'product_id': fields.many2one('product.product', 'Product', readonly=True), 'picking_type_id': fields.many2one('stock.warehouse', 'Warehouse', readonly=True), 'location_id': fields.many2one('stock.location', 'Destination', readonly=True), 'partner_id': fields.many2one('res.partner', 'Vendor', readonly=True), 'pricelist_id': fields.many2one('product.pricelist', 'Pricelist', readonly=True), 'date_approve': fields.date('Date Approved', readonly=True), 'expected_date': fields.date('Expected Date', readonly=True), 'validator': fields.many2one('res.users', 'Validated By', readonly=True), 'product_uom': fields.many2one('product.uom', 'Reference Unit of Measure', required=True), 'company_id': fields.many2one('res.company', 'Company', readonly=True), 'user_id': fields.many2one('res.users', 'Responsible', readonly=True), 'delay': fields.float('Days to Validate', digits=(16, 2), readonly=True), 'delay_pass': fields.float('Days to Deliver', digits=(16, 2), readonly=True), 'quantity': fields.float( 'Product Quantity', readonly=True), # TDE FIXME master: rename into unit_quantity 'price_total': fields.float('Total Price', readonly=True), 'price_average': fields.float('Average Price', readonly=True, group_operator="avg"), 'negociation': fields.float('Purchase-Standard Price', readonly=True, group_operator="avg"), 'price_standard': fields.float('Products Value', readonly=True, group_operator="sum"), 'nbr': fields.integer( '# of Lines', readonly=True), # TDE FIXME master: rename into nbr_lines 'category_id': fields.many2one('product.category', 'Product Category', readonly=True), 'product_tmpl_id': fields.many2one('product.template', 'Product Template', readonly=True), 'country_id': fields.many2one('res.country', 'Partner Country', readonly=True), 'fiscal_position_id': fields.many2one('account.fiscal.position', string='Fiscal Position', oldname='fiscal_position', readonly=True), 'account_analytic_id': fields.many2one('account.analytic.account', 'Analytic Account', readonly=True), 'commercial_partner_id': fields.many2one('res.partner', 'Commercial Entity', readonly=True), } _order = 'date desc, price_total desc' def init(self, cr): tools.sql.drop_view_if_exists(cr, 'purchase_report') cr.execute(""" create or replace view purchase_report as ( select min(l.id) as id, s.date_order as date, l.state, s.date_approve, s.minimum_planned_date as expected_date, s.dest_address_id, s.pricelist_id, s.validator, spt.warehouse_id as picking_type_id, s.partner_id as partner_id, s.create_uid as user_id, s.company_id as company_id, s.fiscal_position_id as fiscal_position_id, l.product_id, p.product_tmpl_id, t.categ_id as category_id, t.uom_id as product_uom, s.location_id as location_id, sum(l.product_qty/u.factor*u2.factor) as quantity, extract(epoch from age(s.date_approve,s.date_order))/(24*60*60)::decimal(16,2) as delay, extract(epoch from age(l.date_planned,s.date_order))/(24*60*60)::decimal(16,2) as delay_pass, count(*) as nbr, sum(l.price_unit*l.product_qty)::decimal(16,2) as price_total, avg(100.0 * (l.price_unit*l.product_qty) / NULLIF(ip.value_float*l.product_qty/u.factor*u2.factor, 0.0))::decimal(16,2) as negociation, sum(ip.value_float*l.product_qty/u.factor*u2.factor)::decimal(16,2) as price_standard, (sum(l.product_qty*l.price_unit)/NULLIF(sum(l.product_qty/u.factor*u2.factor),0.0))::decimal(16,2) as price_average, partner.country_id as country_id, partner.commercial_partner_id as commercial_partner_id, analytic_account.id as account_analytic_id from purchase_order_line l join purchase_order s on (l.order_id=s.id) join res_partner partner on s.partner_id = partner.id left join product_product p on (l.product_id=p.id) left join product_template t on (p.product_tmpl_id=t.id) LEFT JOIN ir_property ip ON (ip.name='standard_price' AND ip.res_id=CONCAT('product.template,',t.id) AND ip.company_id=s.company_id) left join product_uom u on (u.id=l.product_uom) left join product_uom u2 on (u2.id=t.uom_id) left join stock_picking_type spt on (spt.id=s.picking_type_id) left join account_analytic_account analytic_account on (l.account_analytic_id = analytic_account.id) group by s.company_id, s.create_uid, s.partner_id, u.factor, s.location_id, l.price_unit, s.date_approve, l.date_planned, l.product_uom, s.minimum_planned_date, s.pricelist_id, s.validator, s.dest_address_id, s.fiscal_position_id, l.product_id, p.product_tmpl_id, t.categ_id, s.date_order, l.state, spt.warehouse_id, u.uom_type, u.category_id, t.uom_id, u.id, u2.factor, partner.country_id, partner.commercial_partner_id, analytic_account.id ) """)
class ir_attachment(osv.osv): """Attachments are used to link binary files or url to any openerp document. External attachment storage --------------------------- The 'data' function field (_data_get,data_set) is implemented using _file_read, _file_write and _file_delete which can be overridden to implement other storage engines, shuch methods should check for other location pseudo uri (example: hdfs://hadoppserver) The default implementation is the file:dirname location that stores files on the local filesystem using name based on their sha1 hash """ _order = 'id desc' def _name_get_resname(self, cr, uid, ids, object, method, context): data = {} for attachment in self.browse(cr, uid, ids, context=context): model_object = attachment.res_model res_id = attachment.res_id if model_object and res_id: model_pool = self.pool[model_object] res = model_pool.name_get(cr, uid, [res_id], context) res_name = res and res[0][1] or None if res_name: field = self._columns.get('res_name', False) if field and len(res_name) > field.size: res_name = res_name[:30] + '...' data[attachment.id] = res_name or False else: data[attachment.id] = False return data def _storage(self, cr, uid, context=None): return self.pool['ir.config_parameter'].get_param( cr, SUPERUSER_ID, 'ir_attachment.location', 'file') @tools.ormcache(skiparg=3) def _filestore(self, cr, uid, context=None): return tools.config.filestore(cr.dbname) def force_storage(self, cr, uid, context=None): """Force all attachments to be stored in the currently configured storage""" if not self.pool['res.users'].has_group(cr, uid, 'base.group_erp_manager'): raise AccessError( _('Only administrators can execute this action.')) location = self._storage(cr, uid, context) domain = { 'db': [('store_fname', '!=', False)], 'file': [('db_datas', '!=', False)], }[location] ids = self.search(cr, uid, domain, context=context) for attach in self.browse(cr, uid, ids, context=context): attach.write({'datas': attach.datas}) return True # 'data' field implementation def _full_path(self, cr, uid, path): # sanitize ath path = re.sub('[.]', '', path) path = path.strip('/\\') return os.path.join(self._filestore(cr, uid), path) def _get_path(self, cr, uid, bin_data, sha): # retro compatibility fname = sha[:3] + '/' + sha full_path = self._full_path(cr, uid, fname) if os.path.isfile(full_path): return fname, full_path # keep existing path # scatter files across 256 dirs # we use '/' in the db (even on windows) fname = sha[:2] + '/' + sha full_path = self._full_path(cr, uid, fname) dirname = os.path.dirname(full_path) if not os.path.isdir(dirname): os.makedirs(dirname) return fname, full_path def _file_read(self, cr, uid, fname, bin_size=False): full_path = self._full_path(cr, uid, fname) r = '' try: if bin_size: r = os.path.getsize(full_path) else: r = open(full_path, 'rb').read().encode('base64') except IOError: _logger.info("_read_file reading %s", full_path, exc_info=True) return r def _file_write(self, cr, uid, value, checksum): bin_value = value.decode('base64') fname, full_path = self._get_path(cr, uid, bin_value, checksum) if not os.path.exists(full_path): try: with open(full_path, 'wb') as fp: fp.write(bin_value) except IOError: _logger.info("_file_write writing %s", full_path, exc_info=True) return fname def _file_delete(self, cr, uid, fname): count = self.search_count(cr, 1, [('store_fname', '=', fname)]) full_path = self._full_path(cr, uid, fname) if not count and os.path.exists(full_path): try: os.unlink(full_path) except OSError: _logger.info("_file_delete could not unlink %s", full_path, exc_info=True) except IOError: # Harmless and needed for race conditions _logger.info("_file_delete could not unlink %s", full_path, exc_info=True) def _data_get(self, cr, uid, ids, name, arg, context=None): if context is None: context = {} result = {} bin_size = context.get('bin_size') for attach in self.browse(cr, uid, ids, context=context): if attach.store_fname: result[attach.id] = self._file_read(cr, uid, attach.store_fname, bin_size) else: result[attach.id] = attach.db_datas return result def _data_set(self, cr, uid, id, name, value, arg, context=None): # compute the field depending of datas, supporting the case of a empty/None datas bin_data = value and value.decode( 'base64') or '' # empty string to compute its hash checksum = self._compute_checksum(bin_data) vals = { 'file_size': len(bin_data), 'checksum': checksum, } # We dont handle setting data to null # datas is false, but file_size and checksum are not (computed as datas is an empty string) if not value: # reset computed fields super(ir_attachment, self).write(cr, SUPERUSER_ID, [id], vals, context=context) return True if context is None: context = {} # browse the attachment and get the file to delete attach = self.browse(cr, uid, id, context=context) fname_to_delete = attach.store_fname location = self._storage(cr, uid, context) # compute the index_content field vals['index_content'] = self._index(cr, SUPERUSER_ID, bin_data, attach.datas_fname, attach.mimetype), if location != 'db': # create the file fname = self._file_write(cr, uid, value, checksum) vals.update({'store_fname': fname, 'db_datas': False}) else: vals.update({'store_fname': False, 'db_datas': value}) # SUPERUSER_ID as probably don't have write access, trigger during create super(ir_attachment, self).write(cr, SUPERUSER_ID, [id], vals, context=context) # After de-referencing the file in the database, check whether we need # to garbage-collect it on the filesystem if fname_to_delete: self._file_delete(cr, uid, fname_to_delete) return True def _compute_checksum(self, bin_data): """ compute the checksum for the given datas :param bin_data : datas in its binary form """ if bin_data: return hashlib.sha1(bin_data).hexdigest() return False def _compute_mimetype(self, values): """ compute the mimetype of the given values :param values : dict of values to create or write an ir_attachment :return mime : string indicating the mimetype, or application/octet-stream by default """ mimetype = 'application/octet-stream' if values.get('datas_fname'): mimetype = mimetypes.guess_type(values['datas_fname'])[0] if values.get('datas'): mimetype = guess_mimetype(values['datas'].decode('base64')) return mimetype def _index(self, cr, uid, bin_data, datas_fname, file_type): """ compute the index content of the given filename, or binary data. This is a python implementation of the unix command 'strings'. :param bin_data : datas in binary form :return index_content : string containing all the printable character of the binary data """ index_content = False if file_type: index_content = file_type.split('/')[0] if index_content == 'text': # compute index_content only for text type words = re.findall("[^\x00-\x1F\x7F-\xFF]{4,}", bin_data) index_content = ustr("\n".join(words)) return index_content _name = 'ir.attachment' _columns = { 'name': fields.char('Attachment Name', required=True), 'datas_fname': fields.char('File Name'), 'description': fields.text('Description'), 'res_name': fields.function(_name_get_resname, type='char', string='Resource Name', store=True), 'res_model': fields.char( 'Resource Model', readonly=True, help="The database object this attachment will be attached to"), 'res_id': fields.integer('Resource ID', readonly=True, help="The record id this is attached to"), 'create_date': fields.datetime('Date Created', readonly=True), 'create_uid': fields.many2one('res.users', 'Owner', readonly=True), 'company_id': fields.many2one('res.company', 'Company', change_default=True), 'type': fields.selection([ ('url', 'URL'), ('binary', 'Binary'), ], 'Type', help="Binary File or URL", required=True, change_default=True), 'url': fields.char('Url', size=1024), # al: We keep shitty field names for backward compatibility with document 'datas': fields.function(_data_get, fnct_inv=_data_set, string='File Content', type="binary", nodrop=True), 'store_fname': fields.char('Stored Filename'), 'db_datas': fields.binary('Database Data'), # computed fields depending on datas 'file_size': fields.integer('File Size', readonly=True), 'checksum': fields.char("Checksum/SHA1", size=40, select=True, readonly=True), 'mimetype': fields.char('Mime Type', readonly=True), 'index_content': fields.text('Indexed Content', readonly=True), } _defaults = { 'type': 'binary', 'file_size': 0, 'mimetype': False, 'company_id': lambda s, cr, uid, c: s.pool.get('res.company')._company_default_get( cr, uid, 'ir.attachment', context=c), } def _auto_init(self, cr, context=None): super(ir_attachment, self)._auto_init(cr, context) cr.execute('SELECT indexname FROM pg_indexes WHERE indexname = %s', ('ir_attachment_res_idx', )) if not cr.fetchone(): cr.execute( 'CREATE INDEX ir_attachment_res_idx ON ir_attachment (res_model, res_id)' ) cr.commit() def check(self, cr, uid, ids, mode, context=None, values=None): """Restricts the access to an ir.attachment, according to referred model In the 'document' module, it is overriden to relax this hard rule, since more complex ones apply there. """ res_ids = {} require_employee = False if ids: if isinstance(ids, (int, long)): ids = [ids] cr.execute( 'SELECT DISTINCT res_model, res_id FROM ir_attachment WHERE id = ANY (%s)', (ids, )) for rmod, rid in cr.fetchall(): if not (rmod and rid): require_employee = True continue res_ids.setdefault(rmod, set()).add(rid) if values: if values.get('res_model') and values.get('res_id'): res_ids.setdefault(values['res_model'], set()).add(values['res_id']) ima = self.pool.get('ir.model.access') for model, mids in res_ids.items(): # ignore attachments that are not attached to a resource anymore when checking access rights # (resource was deleted but attachment was not) if not self.pool.get(model): require_employee = True continue existing_ids = self.pool[model].exists(cr, uid, mids) if len(existing_ids) != len(mids): require_employee = True # For related models, check if we can write to the model, as unlinking # and creating attachments can be seen as an update to the model if (mode in ['unlink', 'create']): ima.check(cr, uid, model, 'write') else: ima.check(cr, uid, model, mode) self.pool[model].check_access_rule(cr, uid, existing_ids, mode, context=context) if require_employee: if not uid == SUPERUSER_ID and not self.pool[ 'res.users'].has_group(cr, uid, 'base.group_user'): raise AccessError( _("Sorry, you are not allowed to access this document.")) def _search(self, cr, uid, args, offset=0, limit=None, order=None, context=None, count=False, access_rights_uid=None): ids = super(ir_attachment, self)._search(cr, uid, args, offset=offset, limit=limit, order=order, context=context, count=False, access_rights_uid=access_rights_uid) if not ids: if count: return 0 return [] # Work with a set, as list.remove() is prohibitive for large lists of documents # (takes 20+ seconds on a db with 100k docs during search_count()!) orig_ids = ids ids = set(ids) # For attachments, the permissions of the document they are attached to # apply, so we must remove attachments for which the user cannot access # the linked document. # Use pure SQL rather than read() as it is about 50% faster for large dbs (100k+ docs), # and the permissions are checked in super() and below anyway. cr.execute( """SELECT id, res_model, res_id FROM ir_attachment WHERE id = ANY(%s)""", (list(ids), )) targets = cr.dictfetchall() model_attachments = {} for target_dict in targets: if not target_dict['res_model']: continue # model_attachments = { 'model': { 'res_id': [id1,id2] } } model_attachments.setdefault(target_dict['res_model'], {}).setdefault( target_dict['res_id'] or 0, set()).add(target_dict['id']) # To avoid multiple queries for each attachment found, checks are # performed in batch as much as possible. ima = self.pool.get('ir.model.access') for model, targets in model_attachments.iteritems(): if model not in self.pool: continue if not ima.check(cr, uid, model, 'read', False): # remove all corresponding attachment ids for attach_id in itertools.chain(*targets.values()): ids.remove(attach_id) continue # skip ir.rule processing, these ones are out already # filter ids according to what access rules permit target_ids = targets.keys() allowed_ids = [0] + self.pool[model].search( cr, uid, [('id', 'in', target_ids)], context=context) disallowed_ids = set(target_ids).difference(allowed_ids) for res_id in disallowed_ids: for attach_id in targets[res_id]: ids.remove(attach_id) # sort result according to the original sort ordering result = [id for id in orig_ids if id in ids] return len(result) if count else list(result) def read(self, cr, uid, ids, fields_to_read=None, context=None, load='_classic_read'): if isinstance(ids, (int, long)): ids = [ids] self.check(cr, uid, ids, 'read', context=context) return super(ir_attachment, self).read(cr, uid, ids, fields_to_read, context=context, load=load) def write(self, cr, uid, ids, vals, context=None): if isinstance(ids, (int, long)): ids = [ids] self.check(cr, uid, ids, 'write', context=context, values=vals) # remove computed field depending of datas for field in ['file_size', 'checksum']: vals.pop(field, False) return super(ir_attachment, self).write(cr, uid, ids, vals, context) def copy(self, cr, uid, id, default=None, context=None): self.check(cr, uid, [id], 'write', context=context) return super(ir_attachment, self).copy(cr, uid, id, default, context) def unlink(self, cr, uid, ids, context=None): if isinstance(ids, (int, long)): ids = [ids] self.check(cr, uid, ids, 'unlink', context=context) # First delete in the database, *then* in the filesystem if the # database allowed it. Helps avoid errors when concurrent transactions # are deleting the same file, and some of the transactions are # rolled back by PostgreSQL (due to concurrent updates detection). to_delete = [ a.store_fname for a in self.browse(cr, uid, ids, context=context) if a.store_fname ] res = super(ir_attachment, self).unlink(cr, uid, ids, context) for file_path in to_delete: self._file_delete(cr, uid, file_path) return res def create(self, cr, uid, values, context=None): # remove computed field depending of datas for field in ['file_size', 'checksum']: values.pop(field, False) # if mimetype not given, compute it ! if 'mimetype' not in values: values['mimetype'] = self._compute_mimetype(values) self.check(cr, uid, [], mode='write', context=context, values=values) return super(ir_attachment, self).create(cr, uid, values, context) def action_get(self, cr, uid, context=None): return self.pool.get('ir.actions.act_window').for_xml_id( cr, uid, 'base', 'action_attachment', context=context) def invalidate_bundle(self, cr, uid, type='%', xmlid=None, context=None): assert type in ('%', 'css', 'js'), "Unhandled bundle type" xmlid = '%' if xmlid is None else xmlid + '%' domain = [('url', '=like', '/web/%s/%s/%%' % (type, xmlid))] ids = self.search(cr, uid, domain, context=context) if ids: self.unlink(cr, uid, ids, context=context)
class stock_production_lot(osv.osv): _inherit = 'stock.production.lot' _name = 'stock.production.lot' # Array que contiene los estados de los niveles de humedad _MSL_STATUS=[('ready', 'Ready'), ('alert', 'Alert'), ('donotuse','Don\'t Use')] #Metodo que da el nombre de los seriales #=========================================================================== # def name_get(self, cr, uid, ids, context=None): # result = [] # for record in self.browse(cr, uid, ids, context=context): # name = record.name # for status in self._MSL_STATUS: # if status[0] == record.msl_status: # name += ' [' + status[1] + ']' # result.append((record.id,name)) # return result #=========================================================================== # Metodo que analiza el estado en que se encuentra el serial def _msl_calculate(self, cr, uid, ids, name, args, context=None): res = {} for lot in self.browse(cr,uid,ids): res[lot.id] = {'msl_status':''} control = False #=============================================================== # cr.execute('select moisture_exposed_time from stock_production_lot where id=%s', (lot.id,)) # time_read = map(lambda x: x[0], cr.fetchall()) #=============================================================== met, factor, open_time = 0.0, 0.0, 0.0 # Si existe serial se busca sus variables asociadas al msl # las condiciones estan dadas por los porcentajes de humedad que soporte el producto # segun su msl if lot.moisture_exposed_time: met = lot.moisture_exposed_time elif context is not None and 'moisture_exposed_time' in context: met = context.get('moisture_exposed_time', 0.0) #=========================================================== # if met == 0.0: # met = time_read[0] #=========================================================== if lot.product_id.msl_id: factor = lot.product_id.msl_id.alarm_percentage/100 control = lot.product_id.msl_id.control if lot.open_time: open_time = lot.open_time if control: res[lot.id] = 'ready' elif met == 0.0 and factor == 0.0 and open_time == 0.0: res[lot.id] = 'ready' elif met < factor * open_time: res[lot.id] = 'ready' elif met > factor * open_time and met < open_time: res[lot.id] = 'alert' elif met >= open_time: res[lot.id] = 'donotuse' return res # Se busca todos los stock.moves que tengan humedad su bodega origen ya que es el fin del movimiento # ademas debe ser mayor que la fecha de last baked time, y que tenga los mismos seriales el movimiento def _moisture_exposed_time_calculate(self, cr, uid, ids, name, args, context=None): res = {} time_baked = "1900-01-01 00:00:00" move_pool = self.pool.get('stock.move') picking_pool = self.pool.get('stock.picking') move_ids = move_pool.search(cr, uid, [('prodlot_id', 'not in', [0.0])],context=context) for lot in self.browse(cr,uid,ids): res[lot.id] = 0.0 if lot.product_id.msl_id: moisture_exposed_time = 0.0 for move_id in move_ids: move = move_pool.browse(cr,uid,move_id) if lot.last_baket_time: time_baked = lot.last_baket_time if lot == move.prodlot_id and move.location_id.hasmoisture and datetime.strptime(move.date, "%Y-%m-%d %H:%M:%S") > datetime.strptime(time_baked, "%Y-%m-%d %H:%M:%S"): moisture_exposed_time += move.duration res[lot.id] = moisture_exposed_time context.update({'moisture_exposed_time':moisture_exposed_time}) if res[lot.id] == 0.0: picking_ids = picking_pool.search(cr, uid, [ ('state', '=', 'done'), ('type', '=', 'internal')],context=context) prev_move_ids = move_pool.search(cr, uid, [ ('state', '=', 'done'), ('location_dest_id.hasmoisture', '=', True), ('prodlot_id', '=', lot.id), ('picking_id','in', picking_ids), ('date', '>', (lot.last_baket_time if lot.last_baket_time else time_baked))], order='date desc', context=context) if prev_move_ids: timeNow = datetime.now() timeRest = (timeNow - datetime.strptime( move_pool.browse(cr, uid, prev_move_ids[0]).date, '%Y-%m-%d %H:%M:%S' )) real_time = move_pool.total_seconds(timeRest) / 60.0 / 60.0 res[lot.id] = real_time return res # obtiene los lotes que estan siendo modificados las variables, ver _store_rules def _get_lots(self, cr, uid, ids, context=None): lot_ids = [] for lot in self.browse(cr, uid, ids, context=context): lot_ids.append(lot.id) return lot_ids # obtiene los lotes que estan siendo modificados de los stock.moves, ver _store_rules def _get_by_moves(self, cr, uid, ids, context=None): lot_ids = [] move_ids = [] for move in self.browse(cr, uid, ids, context=context): if move.prodlot_id and move.prodlot_id.id not in lot_ids: lot_ids.append(move.prodlot_id.id) return lot_ids # obtiene los lotes que estan siendo modificados product ver _store_rules def _get_msl(self, cr, uid, ids, context=None): lot_ids = [] lot_pool = self.pool.get('stock.production.lot') product_id = False for product in self.browse(cr, uid, ids, context=context): lot_ids = lot_pool.search(cr,uid,[('product_id','=',product.id)]) return lot_ids # obtiene los lotes que estan siendo modificados product.msl ver _store_rules def _get_prod_msl(self, cr, uid, ids, context=None): lot_ids = [] lot_pool = self.pool.get('stock.production.lot') product_pool = self.pool.get('product.product') product_id = False for product_msl in self.browse(cr, uid, ids, context=context): product_ids = product_pool.search(cr,uid,[('msl_id','=', product_msl.id)]) lot_ids = lot_pool.search(cr,uid,[('product_id','in',product_ids)]) return lot_ids _store_rules = { 'product.product': (_get_msl, ['msl_id'],0), 'product.msl': (_get_prod_msl, ['open_time'],0), 'stock.production.lot': (_get_lots, ['product_id', 'moisture_exposed_time', 'last_baket_time', 'move_ids', 'msl_id','open_time'], 0), 'stock.move': (_get_by_moves, ['duration'], 0), } _columns = { 'msl_status': fields.function(_msl_calculate, method=True, type='selection', selection=_MSL_STATUS, string='MSL Status', help="Ready, Alerted or Don't Use. If state is in alerted or don't use you should send the lot to baking"), 'moisture_exposed_time': fields.function(_moisture_exposed_time_calculate, method=True, type='float', string='Moisture exposed time', digits=(15,2), help="The time this specific lot has been exposed to moisture, is calculated according to the times in the related stock moves in locations with moisture."), 'msl_id': fields.related('product_id', 'msl_id', type='many2one', relation='product.msl', string="MSL", help="Moisture Sensitivity Level relates to the packaging and handling precautions for some semiconductors"), 'open_time': fields.related('product_id', 'open_time', type='float', relation='product.product', string="Open Time in hours", help="Maximum period of time that the component can be used, after that time the component must be sent to bake."), 'last_baket_time': fields.datetime('Last Baked Time', type='datetime',help="Last date that the component had been sent to bake."), } _default = { 'msl_status': 'ready', 'last_baket_time': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'), }
class ir_property(osv.osv): _name = 'ir.property' _columns = { 'name': fields.char('Name', select=1), 'res_id': fields.char( 'Resource', help="If not set, acts as a default value for new resources", select=1), 'company_id': fields.many2one('res.company', 'Company', select=1), 'fields_id': fields.many2one('ir.model.fields', 'Field', ondelete='cascade', required=True, select=1), 'value_float': fields.float('Value'), 'value_integer': fields.integer('Value'), 'value_text': fields.text('Value'), # will contain (char, text) 'value_binary': fields.binary('Value'), 'value_reference': fields.char('Value'), 'value_datetime': fields.datetime('Value'), 'type': fields.selection([ ('char', 'Char'), ('float', 'Float'), ('boolean', 'Boolean'), ('integer', 'Integer'), ('text', 'Text'), ('binary', 'Binary'), ('many2one', 'Many2One'), ('date', 'Date'), ('datetime', 'DateTime'), ('selection', 'Selection'), ], 'Type', required=True, select=1), } _defaults = { 'type': 'many2one', } def _update_values(self, cr, uid, ids, values): value = values.pop('value', None) if not value: return values prop = None type_ = values.get('type') if not type_: if ids: prop = self.browse(cr, uid, ids[0]) type_ = prop.type else: type_ = self._defaults['type'] field = TYPE2FIELD.get(type_) if not field: raise osv.except_osv('Error', 'Invalid type') if field == 'value_reference': if isinstance(value, orm.BaseModel): value = '%s,%d' % (value._name, value.id) elif isinstance(value, (int, long)): field_id = values.get('fields_id') if not field_id: if not prop: raise ValueError() field_id = prop.fields_id else: field_id = self.pool.get('ir.model.fields').browse( cr, uid, field_id) value = '%s,%d' % (field_id.relation, value) values[field] = value return values def write(self, cr, uid, ids, values, context=None): return super(ir_property, self).write(cr, uid, ids, self._update_values(cr, uid, ids, values), context=context) def create(self, cr, uid, values, context=None): return super(ir_property, self).create(cr, uid, self._update_values(cr, uid, None, values), context=context) def get_by_record(self, cr, uid, record, context=None): if record.type in ('char', 'text', 'selection'): return record.value_text elif record.type == 'float': return record.value_float elif record.type == 'boolean': return bool(record.value_integer) elif record.type == 'integer': return record.value_integer elif record.type == 'binary': return record.value_binary elif record.type == 'many2one': if not record.value_reference: return False model, resource_id = record.value_reference.split(',') value = self.pool[model].browse(cr, uid, int(resource_id), context=context) return value.exists() elif record.type == 'datetime': return record.value_datetime elif record.type == 'date': if not record.value_datetime: return False return time.strftime( '%Y-%m-%d', time.strptime(record.value_datetime, '%Y-%m-%d %H:%M:%S')) return False def get(self, cr, uid, name, model, res_id=False, context=None): domain = self._get_domain(cr, uid, name, model, context=context) if domain is not None: domain = [('res_id', '=', res_id)] + domain #make the search with company_id asc to make sure that properties specific to a company are given first nid = self.search(cr, uid, domain, limit=1, order='company_id asc', context=context) if not nid: return False record = self.browse(cr, uid, nid[0], context=context) return self.get_by_record(cr, uid, record, context=context) return False def _get_domain(self, cr, uid, prop_name, model, context=None): context = context or {} cr.execute('select id from ir_model_fields where name=%s and model=%s', (prop_name, model)) res = cr.fetchone() if not res: return None cid = context.get('force_company') if not cid: company = self.pool.get('res.company') cid = company._company_default_get(cr, uid, model, res[0], context=context) return [('fields_id', '=', res[0]), ('company_id', 'in', [cid, False])] @api.model def get_multi(self, name, model, ids): """ Read the property field `name` for the records of model `model` with the given `ids`, and return a dictionary mapping `ids` to their corresponding value. """ if not ids: return {} domain = self._get_domain(name, model) if domain is None: return dict.fromkeys(ids, False) # retrieve the values for the given ids and the default value, too refs = {('%s,%s' % (model, id)): id for id in ids} refs[False] = False domain += [('res_id', 'in', list(refs))] # note: order by 'company_id asc' will return non-null values first props = self.search(domain, order='company_id asc') result = {} for prop in props: # for a given res_id, take the first property only id = refs.pop(prop.res_id, None) if id is not None: result[id] = self.get_by_record(prop) # set the default value to the ids that are not in result default_value = result.pop(False, False) for id in ids: result.setdefault(id, default_value) return result @api.model def set_multi(self, name, model, values): """ Assign the property field `name` for the records of model `model` with `values` (dictionary mapping record ids to their value). """ def clean(value): return value.id if isinstance(value, models.BaseModel) else value if not values: return domain = self._get_domain(name, model) if domain is None: raise Exception() # retrieve the default value for the field default_value = clean(self.get(name, model)) # retrieve the properties corresponding to the given record ids self._cr.execute( "SELECT id FROM ir_model_fields WHERE name=%s AND model=%s", (name, model)) field_id = self._cr.fetchone()[0] company_id = self.env.context.get( 'force_company') or self.env['res.company']._company_default_get( model, field_id) refs = {('%s,%s' % (model, id)): id for id in values} props = self.search([ ('fields_id', '=', field_id), ('company_id', '=', company_id), ('res_id', 'in', list(refs)), ]) # modify existing properties for prop in props: id = refs.pop(prop.res_id) value = clean(values[id]) if value == default_value: prop.unlink() elif value != clean(prop.get_by_record(prop)): prop.write({'value': value}) # create new properties for records that do not have one yet for ref, id in refs.iteritems(): value = clean(values[id]) if value != default_value: self.create({ 'fields_id': field_id, 'company_id': company_id, 'res_id': ref, 'name': name, 'value': value, 'type': self.env[model]._fields[name].type, }) @api.model def search_multi(self, name, model, operator, value): """ Return a domain for the records that match the given condition. """ default_matches = False include_zero = False field = self.env[model]._fields[name] if field.type == 'many2one': comodel = field.comodel_name def makeref(value): return value and '%s,%s' % (comodel, value) if operator == "=": value = makeref(value) # if searching properties not set, search those not in those set if value is False: default_matches = True elif operator in ('!=', '<=', '<', '>', '>='): value = makeref(value) elif operator in ('in', 'not in'): value = map(makeref, value) elif operator in ('=like', '=ilike', 'like', 'not like', 'ilike', 'not ilike'): # most probably inefficient... but correct target = self.env[comodel] target_names = target.name_search(value, operator=operator, limit=None) target_ids = map(itemgetter(0), target_names) operator, value = 'in', map(makeref, target_ids) elif field.type in ('integer', 'float'): # No record is created in ir.property if the field's type is float or integer with a value # equal to 0. Then to match with the records that are linked to a property field equal to 0, # the negation of the operator must be taken to compute the goods and the domain returned # to match the searched records is just the opposite. if value == 0 and operator == '=': operator = '!=' include_zero = True elif value <= 0 and operator == '>=': operator = '<' include_zero = True elif value <= 0 and operator == '>': operator = '<=' include_zero = True elif value >= 0 and operator == '<=': operator = '>' include_zero = True elif value >= 0 and operator == '<': operator = '>=' include_zero = True # retrieve the properties that match the condition domain = self._get_domain(name, model) if domain is None: raise Exception() props = self.search(domain + [(TYPE2FIELD[field.type], operator, value)]) # retrieve the records corresponding to the properties that match good_ids = [] for prop in props: if prop.res_id: res_model, res_id = prop.res_id.split(',') good_ids.append(int(res_id)) else: default_matches = True if include_zero: return [('id', 'not in', good_ids)] elif default_matches: # exclude all records with a property that does not match all_ids = [] props = self.search(domain + [('res_id', '!=', False)]) for prop in props: res_model, res_id = prop.res_id.split(',') all_ids.append(int(res_id)) bad_ids = list(set(all_ids) - set(good_ids)) return [('id', 'not in', bad_ids)] else: return [('id', 'in', good_ids)]
class banking_export_sdd(orm.Model): '''SEPA Direct Debit export''' _name = 'banking.export.sdd' _description = __doc__ _rec_name = 'filename' def _generate_filename(self, cr, uid, ids, name, arg, context=None): res = {} for sepa_file in self.browse(cr, uid, ids, context=context): ref = sepa_file.payment_order_ids[0].reference if ref: label = unidecode(ref.replace('/', '-')) else: label = 'error' res[sepa_file.id] = 'sdd_%s.xml' % label return res _columns = { 'payment_order_ids': fields.many2many( 'payment.order', 'account_payment_order_sdd_rel', 'banking_export_sepa_id', 'account_order_id', 'Payment Orders', readonly=True), 'nb_transactions': fields.integer( 'Number of Transactions', readonly=True), 'total_amount': fields.float( 'Total Amount', digits_compute=dp.get_precision('Account'), readonly=True), 'batch_booking': fields.boolean( 'Batch Booking', readonly=True, help="If true, the bank statement will display only one credit " "line for all the direct debits of the SEPA file ; if false, " "the bank statement will display one credit line per direct " "debit of the SEPA file."), 'charge_bearer': fields.selection([ ('SLEV', 'Following Service Level'), ('SHAR', 'Shared'), ('CRED', 'Borne by Creditor'), ('DEBT', 'Borne by Debtor'), ], 'Charge Bearer', readonly=True, help="Following service level : transaction charges are to be " "applied following the rules agreed in the service level and/or " "scheme (SEPA Core messages must use this). Shared : " "transaction charges on the creditor side are to be borne by " "the creditor, transaction charges on the debtor side are to be " "borne by the debtor. Borne by creditor : all transaction " "charges are to be borne by the creditor. Borne by debtor : " "all transaction charges are to be borne by the debtor."), 'create_date': fields.datetime('Generation Date', readonly=True), 'file': fields.binary('SEPA File', readonly=True), 'filename': fields.function( _generate_filename, type='char', size=256, string='Filename', readonly=True, store=True), 'state': fields.selection([ ('draft', 'Draft'), ('sent', 'Sent'), ('done', 'Reconciled'), ], 'State', readonly=True), } _defaults = { 'state': 'draft', }
class laboratory_ihce(osv.Model): _name = 'laboratory.ihce' def _get_percent(self, cr, uid, ids, field, arg, context=None): res = {} for rows in self.browse(cr, uid, ids, context=context): percent = 0 suma = 0 con = 0 for row in rows: for line in row.lines_services: if line.state != 'detained': suma += line.percent con = con + 1 if suma > 0: percent = suma / con res[row.id] = percent return res def _get_services(self, cr, uid, ids, field, arg, context=None): res = {} for rows in self.browse(cr, uid, ids, context=context): suma = 0 for row in rows: for line in row.lines_services: if line.state == 'pre_done' or line.state == 'done': suma = suma + 1 res[row.id] = suma return res def _get_advices(self, cr, uid, ids, field, arg, context=None): res = {} for rows in self.browse(cr, uid, ids, context=context): suma = 0 for row in rows: res[row.id] = len(row.lines_advices) return res def _get_state(self, cr, uid, ids, field, arg, context=None): res = {} for rows in self.browse(cr, uid, ids, context=context): done = False detained = False pro = False for row in rows: if row.state == 'process': for line in row.lines_services: if line.state == 'pre_done' or line.state == 'done': done = True elif line.state == 'detained': detained = True else: pro = True if done and not detained and not pro: #~ Si todos los servicios estan terminados cambiamos el estado y enviamos la encuesta self.send_test(cr, uid, ids, context=context) res[row.id] = True else: if done and detained and not pro: #~ Si todos los servicios estan terminados cambiamos el estado y enviamos la encuesta self.send_test(cr, uid, ids, context=context) res[row.id] = True else: if (done and detained and pro) or ( pro and done) or (detained and pro) or pro: self.write(cr, uid, row.id, {'state': 'process'}) res[row.id] = False else: if not done and not pro and detained: self.write(cr, uid, row.id, {'state': 'detained'}) return res _columns = { 'name': fields.char("ID de Proyecto", size=200), 'company_id': fields.many2one('companies.ihce', 'Beneficiario'), 'date': fields.datetime("Fecha de inicio"), 'percent': fields.function(_get_percent, type='integer', string="Porcentaje de avance"), 'notes': fields.text("Observación General"), 'state': fields.selection([('process', 'Proceso'), ('stand', 'Encuesta Enviada'), ('done', 'Terminado'), ('detained', 'Abandonado')], 'Estado', select=True), 'servicio': fields.function(_get_services, type='integer', string="No. Servicios"), 'advices': fields.function(_get_advices, type='integer', string="No. Asesorías"), 'user_id': fields.many2one( 'res.users', "Responsable", help="Es el usuario al que se le contarán los indicadores."), 'lines_services': fields.one2many('desing.laboratory', 'id_project', 'Servicios'), 'lines_advices': fields.one2many('advices.laboratory', 'laboratory', 'Asesorías'), 'url_test': fields.char("Url de Encuesta", size=200), 'test': fields.one2many('test.laboratory', 'laboratory', "Encuesta de Satisfacción"), 'state_done': fields.function(_get_state, type='boolean', string="Estado del proyecto"), 'tests_bol': fields.boolean("Encuestas"), 'sector': fields.many2one('sector.actividad.economica', "Sector", help="Sector económico"), } _defaults = { 'state': 'process', 'percent': 0, 'user_id': lambda obj, cr, uid, context: uid, 'date': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'), 'tests_bol': False, } _order = "name desc" def create(self, cr, uid, vals, context=None): return super(laboratory_ihce, self).create(cr, uid, vals, context) def write(self, cr, uid, ids, vals, context=None): return super(laboratory_ihce, self).write(cr, uid, ids, vals, context=context) #~ Función para enviar correo con la liga de encuesta de satisfacción def send_test(self, cr, uid, ids, context=None): fecha_actual = datetime.now() email_vals = {} row = self.browse(cr, uid, ids[0], context=context) mail_message_obj = self.pool.get('mail.mail') user_row = self.pool.get('res.users').browse(cr, uid, row.user_id.id) companies = self.pool.get('companies.ihce').browse(cr, uid, row.company_id.id, context=context) url = "http://192.241.169.197/encuesta/index.php?&token=" + str(row.id) self.write(cr, uid, row.id, { 'url_test': url, 'state': 'done' }, context=context) if user_row.email: subject = "ENCUESTA DE SATISFACCIÓN LABORATORIO DE DISEÑO" body_text = "Estimado " + str( companies.name.encode('utf-8') ) + "</br></br><p>Para brindarte un mejor servicio el Laboratorio de Diseño te envita a contestar la siguiente encuesta de satisfacción.</p> <p></br></br>" + str( url) + "</p> </br></br> <p>Gracias.</p>" email_vals.update({ 'subject': subject, 'body_html': body_text, 'body': body_text, 'email_to': companies.email, 'email_from': user_row.email }) mail_id = mail_message_obj.create(cr, uid, email_vals) mail_message_obj.send(cr, uid, [mail_id], False, None, context=context) #~ Linea de historial del beneficiario self.pool.get('crm.ihce').create( cr, uid, { 'company_id': row.company_id.id, 'date': fecha_actual, 'name': 'Se ha enviado encuesta de satisfacción al beneficiario del proyecto ' + str(row.name.encode('utf-8')) + " del laboratorio de diseño.", 'user': uid, 'date_compromise': fecha_actual, 'state': 'done' }, context=context) #~ self.message_post(cr, uid, [row.id], body=_("Encuesta Enviada"), context=context) else: raise osv.except_osv(_('Advertencia!'), _('El usuario no tiene correo electrónico!')) return True
class PaymentTransaction(osv.Model): """ Transaction Model. Each specific acquirer can extend the model by adding its own fields. Methods that can be added in an acquirer-specific implementation: - ``<name>_create``: method receiving values used when creating a new transaction and that returns a dictionary that will update those values. This method can be used to tweak some transaction values. Methods defined for convention, depending on your controllers: - ``<name>_form_feedback(self, cr, uid, data, context=None)``: method that handles the data coming from the acquirer after the transaction. It will generally receives data posted by the acquirer after the transaction. """ _name = 'payment.transaction' _description = 'Payment Transaction' _inherit = ['mail.thread'] _order = 'id desc' _rec_name = 'reference' _columns = { 'date_create': fields.datetime('Creation Date', readonly=True, required=True), 'date_validate': fields.datetime('Validation Date'), 'acquirer_id': fields.many2one( 'payment.acquirer', 'Acquirer', required=True, ), 'type': fields.selection([('server2server', 'Server To Server'), ('form', 'Form')], string='Type', required=True), 'state': fields.selection([('draft', 'Draft'), ('pending', 'Pending'), ('done', 'Done'), ('error', 'Error'), ('cancel', 'Canceled')], 'Status', required=True, track_visibility='onchange', copy=False), 'state_message': fields.text( 'Message', help= 'Field used to store error and/or validation messages for information' ), # payment 'amount': fields.float('Amount', required=True, digits=(16, 2), track_visibility='always', help='Amount in cents'), 'fees': fields.float( 'Fees', digits=(16, 2), track_visibility='always', help= 'Fees amount; set by the system because depends on the acquirer'), 'currency_id': fields.many2one('res.currency', 'Currency', required=True), 'reference': fields.char('Order Reference', required=True), 'acquirer_reference': fields.char( 'Acquirer Order Reference', help='Reference of the TX as stored in the acquirer database'), # duplicate partner / transaction data to store the values at transaction time 'partner_id': fields.many2one( 'res.partner', 'Partner', track_visibility='onchange', ), 'partner_name': fields.char('Partner Name'), 'partner_lang': fields.char('Lang'), 'partner_email': fields.char('Email'), 'partner_zip': fields.char('Zip'), 'partner_address': fields.char('Address'), 'partner_city': fields.char('City'), 'partner_country_id': fields.many2one('res.country', 'Country', required=True), 'partner_phone': fields.char('Phone'), 'partner_reference': fields.char('Partner Reference', help='Reference of the customer in the acquirer database'), } def _check_reference(self, cr, uid, ids, context=None): transaction = self.browse(cr, uid, ids[0], context=context) if transaction.state not in ['cancel', 'error']: if self.search(cr, uid, [('reference', '=', transaction.reference), ('id', '!=', transaction.id)], context=context, count=True): return False return True _constraints = [ (_check_reference, 'The payment transaction reference must be unique!', ['reference', 'state']), ] _defaults = { 'date_create': fields.datetime.now, 'type': 'form', 'state': 'draft', 'partner_lang': 'en_US', } def create(self, cr, uid, values, context=None): Acquirer = self.pool['payment.acquirer'] if values.get('partner_id'): # @TDENOTE: not sure values.update( self.on_change_partner_id(cr, uid, None, values.get('partner_id'), context=context)['values']) # call custom create method if defined (i.e. ogone_create for ogone) if values.get('acquirer_id'): acquirer = self.pool['payment.acquirer'].browse( cr, uid, values.get('acquirer_id'), context=context) # compute fees custom_method_name = '%s_compute_fees' % acquirer.provider if hasattr(Acquirer, custom_method_name): fees = getattr(Acquirer, custom_method_name)(cr, uid, acquirer.id, values.get('amount', 0.0), values.get('currency_id'), values.get('country_id'), context=None) values['fees'] = float_round(fees, 2) # custom create custom_method_name = '%s_create' % acquirer.provider if hasattr(self, custom_method_name): values.update( getattr(self, custom_method_name)(cr, uid, values, context=context)) return super(PaymentTransaction, self).create(cr, uid, values, context=context) def write(self, cr, uid, ids, values, context=None): Acquirer = self.pool['payment.acquirer'] if ('acquirer_id' in values or 'amount' in values) and 'fees' not in values: # The acquirer or the amount has changed, and the fees are not explicitely forced. Fees must be recomputed. if isinstance(ids, (int, long)): ids = [ids] for txn_id in ids: vals = dict(values) vals['fees'] = 0.0 transaction = self.browse(cr, uid, txn_id, context=context) if 'acquirer_id' in values: acquirer = Acquirer.browse( cr, uid, values['acquirer_id'], context=context) if values['acquirer_id'] else None else: acquirer = transaction.acquirer_id if acquirer: custom_method_name = '%s_compute_fees' % acquirer.provider if hasattr(Acquirer, custom_method_name): amount = (values['amount'] if 'amount' in values else transaction.amount) or 0.0 currency_id = values.get( 'currency_id') or transaction.currency_id.id country_id = values.get( 'partner_country_id' ) or transaction.partner_country_id.id fees = getattr(Acquirer, custom_method_name)(cr, uid, acquirer.id, amount, currency_id, country_id, context=None) vals['fees'] = float_round(fees, 2) res = super(PaymentTransaction, self).write(cr, uid, txn_id, vals, context=context) return res return super(PaymentTransaction, self).write(cr, uid, ids, values, context=context) def on_change_partner_id(self, cr, uid, ids, partner_id, context=None): partner = None if partner_id: partner = self.pool['res.partner'].browse(cr, uid, partner_id, context=context) return { 'values': { 'partner_name': partner and partner.name or False, 'partner_lang': partner and partner.lang or 'en_US', 'partner_email': partner and partner.email or False, 'partner_zip': partner and partner.zip or False, 'partner_address': _partner_format_address(partner and partner.street or '', partner and partner.street2 or ''), 'partner_city': partner and partner.city or False, 'partner_country_id': partner and partner.country_id.id or False, 'partner_phone': partner and partner.phone or False, } } # -------------------------------------------------- # FORM RELATED METHODS # -------------------------------------------------- def form_feedback(self, cr, uid, data, acquirer_name, context=None): invalid_parameters, tx = None, None tx_find_method_name = '_%s_form_get_tx_from_data' % acquirer_name if hasattr(self, tx_find_method_name): tx = getattr(self, tx_find_method_name)(cr, uid, data, context=context) invalid_param_method_name = '_%s_form_get_invalid_parameters' % acquirer_name if hasattr(self, invalid_param_method_name): invalid_parameters = getattr(self, invalid_param_method_name)( cr, uid, tx, data, context=context) if invalid_parameters: _error_message = '%s: incorrect tx data:\n' % (acquirer_name) for item in invalid_parameters: _error_message += '\t%s: received %s instead of %s\n' % ( item[0], item[1], item[2]) _logger.error(_error_message) return False feedback_method_name = '_%s_form_validate' % acquirer_name if hasattr(self, feedback_method_name): return getattr(self, feedback_method_name)(cr, uid, tx, data, context=context) return True # -------------------------------------------------- # SERVER2SERVER RELATED METHODS # -------------------------------------------------- def s2s_create(self, cr, uid, values, cc_values, context=None): tx_id, tx_result = self.s2s_send(cr, uid, values, cc_values, context=context) self.s2s_feedback(cr, uid, tx_id, tx_result, context=context) return tx_id def s2s_send(self, cr, uid, values, cc_values, context=None): """ Create and send server-to-server transaction. :param dict values: transaction values :param dict cc_values: credit card values that are not stored into the payment.transaction object. Acquirers should handle receiving void or incorrect cc values. Should contain : - holder_name - number - cvc - expiry_date - brand - expiry_date_yy - expiry_date_mm """ tx_id, result = None, None if values.get('acquirer_id'): acquirer = self.pool['payment.acquirer'].browse( cr, uid, values.get('acquirer_id'), context=context) custom_method_name = '_%s_s2s_send' % acquirer.provider if hasattr(self, custom_method_name): tx_id, result = getattr(self, custom_method_name)(cr, uid, values, cc_values, context=context) if tx_id is None and result is None: tx_id = super(PaymentTransaction, self).create(cr, uid, values, context=context) return (tx_id, result) def s2s_feedback(self, cr, uid, tx_id, data, context=None): """ Handle the feedback of a server-to-server transaction. """ tx = self.browse(cr, uid, tx_id, context=context) invalid_parameters = None invalid_param_method_name = '_%s_s2s_get_invalid_parameters' % tx.acquirer_id.provider if hasattr(self, invalid_param_method_name): invalid_parameters = getattr(self, invalid_param_method_name)( cr, uid, tx, data, context=context) if invalid_parameters: _error_message = '%s: incorrect tx data:\n' % (tx.acquirer_id.name) for item in invalid_parameters: _error_message += '\t%s: received %s instead of %s\n' % ( item[0], item[1], item[2]) _logger.error(_error_message) return False feedback_method_name = '_%s_s2s_validate' % tx.acquirer_id.provider if hasattr(self, feedback_method_name): return getattr(self, feedback_method_name)(cr, uid, tx, data, context=context) return True def s2s_get_tx_status(self, cr, uid, tx_id, context=None): """ Get the tx status. """ tx = self.browse(cr, uid, tx_id, context=context) invalid_param_method_name = '_%s_s2s_get_tx_status' % tx.acquirer_id.provider if hasattr(self, invalid_param_method_name): return getattr(self, invalid_param_method_name)(cr, uid, tx, context=context) return True
class vit_rework_wizard(osv.osv_memory): _name = 'vit.rework.wizard' def default_get(self, cr, uid, fields, context=None): if context is None: context = {} res = super(vit_rework_wizard, self).default_get(cr, uid, fields, context=context) if context.get('active_id'): move = self.pool.get('stock.move').browse(cr, uid, context['active_id'], context=context) if 'workorder_id' in fields: res.update({'workorder_id': context['active_id']}) return res _columns = { 'workorder_id': fields.many2one( 'mrp.production.workcenter.line', 'Work Order', ), 'partner_id': fields.many2one('res.partner', 'Partner'), 'date': fields.datetime('Schedule Date', required=True, help='waktu yang diminta untuk barang-barang ini'), 'rework_detail_ids': fields.one2many('vit.rework.detail.wizard', 'wizard_id', string='Details Product'), } _defaults = { 'date': fields.datetime.now, } def create_internal_move(self, cr, uid, ids, context=None): picking_obj = self.pool.get('stock.picking') move_obj = self.pool.get('stock.move') partner_id = False #import pdb;pdb.set_trace() for data in self.browse(cr, uid, ids, context=context): if not data.rework_detail_ids: raise osv.except_osv(_('Error'), _('Data Product tidak boleh kosong !.')) if data.partner_id: partner_id = data.partner_id.id # create picking # picking_id = picking_obj.create(cr,uid,{'partner_id': partner_id, # 'origin': data.workorder_id.production_id.name+' ['+data.workorder_id.name+']', # 'workorder_id':context['active_id'], # 'picking_type_id':3,#internal transfer # 'min_date': data.date, # 'invoice_state':'none', # 'move_type':'direct'},context=context) # diganti langsung ke stock.move karena jadi ada error: # MissingError: ('MissingError', u'One of the documents you are trying to access has been deleted, please try again after refreshing.') moves = [] for move in data.rework_detail_ids: product_id = move.product_id.id product_name = move.product_id.name move_qty = move.qty move_uom = move.uom_id.id # Create stock.move move_id = move_obj.create( cr, uid, { 'product_id': product_id, #'picking_id':picking_id, 'workorder_id': context['active_id'], 'origin': data.workorder_id.production_id.name + ' [' + data.workorder_id.name + ']', 'name': product_name, 'product_uom_qty': move_qty, 'product_uom': move_uom, 'location_id': 12, # WH/stock 'location_dest_id': 5, #virtual loss }, context=context) moves.append(move_id) return moves
class hr_so_project(osv.osv_memory): _name = 'hr.sign.out.project' _description = 'Sign Out By Project' _columns = { 'account_id': fields.many2one('account.analytic.account', 'Project / Analytic Account', domain=[('type', '=', 'normal')]), 'info': fields.char('Work Description', size=256, required=True), 'date_start': fields.datetime('Starting Date', readonly=True), 'date': fields.datetime('Closing Date'), 'analytic_amount': fields.float('Minimum Analytic Amount'), 'name': fields.char('Employee\'s Name', size=32, required=True, readonly=True), 'state': fields.related('emp_id', 'state', string='Current Status', type='selection', selection=[('present', 'Present'), ('absent', 'Absent')], required=True, readonly=True), 'server_date': fields.datetime('Current Date', required=True, readonly=True), 'emp_id': fields.many2one('hr.employee', 'Employee ID') } def _get_empid(self, cr, uid, context=None): emp_obj = self.pool.get('hr.employee') emp_ids = emp_obj.search(cr, uid, [('user_id', '=', uid)], context=context) if emp_ids: for employee in emp_obj.browse(cr, uid, emp_ids, context=context): return { 'name': employee.name, 'state': employee.state, 'emp_id': emp_ids[0], 'server_date': time.strftime('%Y-%m-%d %H:%M:%S') } def _get_empid2(self, cr, uid, context=None): res = self._get_empid(cr, uid, context=context) cr.execute( 'select name,action from hr_attendance where employee_id=%s order by name desc limit 1', (res['emp_id'], )) res['server_date'] = time.strftime('%Y-%m-%d %H:%M:%S') date_start = cr.fetchone() if date_start: res['date_start'] = date_start[0] return res def default_get(self, cr, uid, fields_list, context=None): res = super(hr_so_project, self).default_get(cr, uid, fields_list, context=context) res.update(self._get_empid2(cr, uid, context=context)) return res def _write(self, cr, uid, data, emp_id, context=None): timesheet_obj = self.pool.get('hr.analytic.timesheet') emp_obj = self.pool.get('hr.employee') if context is None: context = {} hour = (time.mktime( time.strptime(data['date'] or time.strftime('%Y-%m-%d %H:%M:%S'), '%Y-%m-%d %H:%M:%S')) - time.mktime( time.strptime(data['date_start'], '%Y-%m-%d %H:%M:%S'))) / 3600.0 minimum = data['analytic_amount'] if minimum: hour = round(round((hour + minimum / 2) / minimum) * minimum, 2) res = timesheet_obj.default_get(cr, uid, ['product_id', 'product_uom_id'], context=context) if not res['product_uom_id']: raise osv.except_osv( _('User Error!'), _('Please define cost unit for this employee.')) up = timesheet_obj.on_change_unit_amount( cr, uid, False, res['product_id'], hour, False, res['product_uom_id'])['value'] res['name'] = data['info'] res['account_id'] = data['account_id'].id res['unit_amount'] = hour emp_journal = emp_obj.browse(cr, uid, emp_id, context=context).journal_id res['journal_id'] = emp_journal and emp_journal.id or False res.update(up) up = timesheet_obj.on_change_account_id(cr, uid, [], res['account_id']).get( 'value', {}) res.update(up) return timesheet_obj.create(cr, uid, res, context=context) def sign_out_result_end(self, cr, uid, ids, context=None): emp_obj = self.pool.get('hr.employee') for data in self.browse(cr, uid, ids, context=context): emp_id = data.emp_id.id emp_obj.attendance_action_change(cr, uid, [emp_id], { 'action': 'sign_out', 'action_date': data.date }) self._write(cr, uid, data, emp_id, context=context) return {'type': 'ir.actions.act_window_close'} def sign_out_result(self, cr, uid, ids, context=None): emp_obj = self.pool.get('hr.employee') for data in self.browse(cr, uid, ids, context=context): emp_id = data.emp_id.id emp_obj.attendance_action_change(cr, uid, [emp_id], { 'action': 'action', 'action_date': data.date }) self._write(cr, uid, data, emp_id, context=context) return {'type': 'ir.actions.act_window_close'}
class hr_si_project(osv.osv_memory): _name = 'hr.sign.in.project' _description = 'Sign In By Project' _columns = { 'name': fields.char('Employee\'s Name', size=32, readonly=True), 'state': fields.related('emp_id', 'state', string='Current Status', type='selection', selection=[('present', 'Present'), ('absent', 'Absent')], required=True, readonly=True), 'date': fields.datetime('Starting Date'), 'server_date': fields.datetime('Current Date', readonly=True), 'emp_id': fields.many2one('hr.employee', 'Employee ID') } def view_init(self, cr, uid, fields, context=None): """ This function checks for precondition before wizard executes @param self: The object pointer @param cr: the current row, from the database cursor, @param uid: the current user’s ID for security checks, @param fields: List of fields for default value @param context: A standard dictionary for contextual values """ emp_obj = self.pool.get('hr.employee') emp_id = emp_obj.search(cr, uid, [('user_id', '=', uid)], context=context) if not emp_id: raise osv.except_osv(_('User Error!'), _('Please define employee for your user.')) return False def check_state(self, cr, uid, ids, context=None): obj_model = self.pool.get('ir.model.data') emp_id = self.default_get(cr, uid, ['emp_id'], context)['emp_id'] # get the latest action (sign_in or out) for this employee cr.execute( 'select action from hr_attendance where employee_id=%s and action in (\'sign_in\',\'sign_out\') order by name desc limit 1', (emp_id, )) res = (cr.fetchone() or ('sign_out', ))[0] in_out = (res == 'sign_out') and 'in' or 'out' #TODO: invert sign_in et sign_out model_data_ids = obj_model.search( cr, uid, [('model', '=', 'ir.ui.view'), ('name', '=', 'view_hr_timesheet_sign_%s' % in_out)], context=context) resource_id = obj_model.read(cr, uid, model_data_ids, fields=['res_id'], context=context)[0]['res_id'] return { 'name': _('Sign in / Sign out'), 'view_type': 'form', 'view_mode': 'tree,form', 'res_model': 'hr.sign.%s.project' % in_out, 'views': [(resource_id, 'form')], 'type': 'ir.actions.act_window', 'target': 'new' } def sign_in_result(self, cr, uid, ids, context=None): emp_obj = self.pool.get('hr.employee') for data in self.browse(cr, uid, ids, context=context): emp_id = data.emp_id.id emp_obj.attendance_action_change(cr, uid, [emp_id], { 'action': 'sign_in', 'action_date': data.date }) return {'type': 'ir.actions.act_window_close'} def default_get(self, cr, uid, fields_list, context=None): res = super(hr_si_project, self).default_get(cr, uid, fields_list, context=context) emp_obj = self.pool.get('hr.employee') emp_id = emp_obj.search(cr, uid, [('user_id', '=', uid)], context=context) if emp_id: for employee in emp_obj.browse(cr, uid, emp_id, context=context): res.update({ 'name': employee.name, 'state': employee.state, 'emp_id': emp_id[0], 'server_date': time.strftime('%Y-%m-%d %H:%M:%S') }) return res
class loewieec_shop(osv.osv): _name = 'loewieec.shop' _description = u"电商店铺" _columns = { 'active': fields.boolean(string='Active', default=False), 'tmall_time': fields.datetime(string='TMall Time'), 'name': fields.char(u'店铺名称', size=16, required=True), 'code': fields.char(u'店铺前缀', size=8, required=True, help=u"系统会自动给该店铺的订单编号.客户昵称加上此前缀.通常同一个平台的店铺前缀设置成一样"), 'platform': fields.selection([ ('tb', u'淘宝天猫'), ('sb', u'淘宝沙箱'), ], string=u'电商平台', required=True, help=u"淘宝、京东等电商平台"), #'categ_id': fields.many2one('product.category', string=u"商品默认分类", required=True), 'location_id': fields.many2one('stock.location', string=u"店铺库位", required=True), 'journal_id': fields.many2one('account.journal', string=u"默认销售账簿", required=True), 'post_product_id': fields.many2one('product.product', string=u"邮费"), #'coupon_product_id': fields.many2one('product.product', string=u"优惠减款", required=True), 'gift_product_id': fields.many2one( 'product.product', string=u"赠品", ), 'partner_id': fields.many2one('res.partner', string='Partner', required=True), 'pricelist_id': fields.many2one('product.pricelist', string='Price List', required=True), 'warehouse_id': fields.many2one('stock.warehouse', string='Warehouse', required=True), 'appkey': fields.char(u'App Key', ), 'appsecret': fields.char(u'App Secret', ), 'sessionkey': fields.char(u'Session Key', ), 'apiurl': fields.char(u'API URL', ), 'authurl': fields.char(u'Auth URL', ), 'tokenurl': fields.char(u'Token URL', ), 'products': fields.one2many('product.tmalljd', 'ec_shop_id', string="Products"), 'orders': fields.one2many('sale.order', 'shop_id', string="Orders"), 'start_modified': fields.datetime(string='Start Modified'), 'end_modified': fields.datetime(string='End Modified'), 'sync_interval': fields.integer(u'同步最近多少小时的订单', default=24), 'import_salesorder': fields.many2one('sale.order', u'天猫COE信息的目标订单'), 'last_log': fields.text(u'同步信息'), 'tmi_state': fields.selection([ ('WAIT_BUYER_PAY', u'等待买家付款'), ('WAIT_SELLER_SEND_GOODS', u'等待卖家发货'), ('WAIT_BUYER_CONFIRM_GOODS', u'等待买家确认收货'), ('TRADE_FINISHED', u'交易成功'), ('TRADE_CLOSED', u'交易关闭'), ('TRADE_CLOSED_BY_TAOBAO', '交易被淘宝关闭'), ('ALL_WAIT_PAY', u'所有买家未付款的交易'), ('ALL_CLOSED', u'所有关闭的交易'), ], '订单的天猫订单状态', default='WAIT_SELLER_SEND_GOODS'), } def update_waybill_no_tmall(self, cr, uid, ids, context=None): # port = 80 shop = self.browse(cr, uid, ids[0], context=context) setDefaultAppInfo(shop.appkey, shop.appsecret) req = LogisticsOfflineSendRequest(shop.apiurl, port) req.company_code = "EMS" sale_id = shop.import_salesorder.id domain = [('order_id', '=', sale_id)] coe_tmino = self.pool.get('sale.order.line').read_group( cr, uid, domain, ['tmi_jdi_no', 'coe_no'], ['product_id'], context=context) resp = req.getResponse(shop.sessionkey) companies = resp.get('logistics_companies_get_response').get( 'logistics_companies', False) comp_list = companies.get('logistics_company', False) return True def get_losgistic_company_code(self, cr, uid, ids, context=None): # port = 80 shop = self.browse(cr, uid, ids[0], context=context) setDefaultAppInfo(shop.appkey, shop.appsecret) req = LogisticsCompaniesGetRequest(shop.apiurl, port) req.fields = "id,code,name,reg_mail_no" req.order_mode = "all" resp = req.getResponse(shop.sessionkey) companies = resp.get('logistics_companies_get_response').get( 'logistics_companies', False) comp_list = companies.get('logistics_company', False) carrier_obj = self.pool.get('loewie.carrier') for comp in comp_list: comp_ids = carrier_obj.search(cr, uid, [('name', '=', comp.get('name'))], context=context) comp_ids = comp_ids and comp_ids[0] or 0 if not comp_ids: vals = { 'name': comp.get('name'), 'id_tm': str(comp.get('id')), 'code_tm': comp.get('code'), 'reg_mail_no': comp.get('reg_mail_no') } carrier_obj.create(cr, uid, vals, context=context) return True def set_losgistic_confirm(self, cr, uid, ids, context=None, salesorder=None): # port = 80 shop = self.browse(cr, uid, ids[0], context=context) setDefaultAppInfo(shop.appkey, shop.appsecret) req = LogisticsOnlineConfirmRequest(shop.apiurl, port) tmi_jdi_list = {} for line in salesorder.order_line: tmi_jdi_no, coe_no, is_sent = line.tmi_jdi_no, line.coe_no, line.logistic_sent tmi_jdi_no = tmi_jdi_no.strip() coe_no = coe_no and coe_no.name.strip() or False if not tmi_jdi_no or not coe_no or is_sent: continue tmi_jdi_list[tmi_jdi_no] = coe_no is_sent_list = [] for tmi_jdi_num in tmi_jdi_list.keys(): req.tid = tmi_jdi_num req.out_sid = tmi_jdi_list[tmi_jdi_num] resp = req.getResponse(shop.sessionkey) is_ok = resp.get('logistics_online_confirm_response').get( 'shipping', False).get('is_success') if is_ok: is_sent_list.append(tmi_jdi_num) for line3 in salesorder.order_line: tmi_jdi = line3.tmi_jdi_no if tmi_jdi.strip() in is_sent_list: line3.logistic_sent = True return True def get_full_path(self, cr, uid, path): # sanitize ath path = re.sub('[.]', '', path) path = path.strip('/\\') return os.path.join(tools.config.filestore(cr.dbname), path) def create_order_from_excel(self, cr, uid, ids, coe_lines, product_lines, tmijdi_fname, context=None): order_obj = self.pool.get('sale.order') shop = self.browse(cr, uid, ids[0], context=context) product_gift_id = shop.gift_product_id.id partner_id = shop.partner_id.id # 检查所有产品名是否 在ERP中有匹配的项 product_obj = self.pool.get('product.product') for product in product_lines: product_name = product.get('product', "").strip() product_ids = product_obj.search( cr, uid, [('name_template', '=ilike', product_name)], context=context) if not product_ids: name = self.string_refactor(product_name) product_ids = product_obj.search( cr, uid, [('name_template', 'ilike', name)], context=context) if product_ids: product['desc'] = u"产品名未能精确匹配" if not product_ids: raise osv.except_osv( u'Excel产品名错误', u'''无法再ERP中找到 - %s. \r\n请检查名字 并纠正如下情况:\r\n 1. 125 ml -> 125ml. \r\n 2. Eros - Eros Warming - 150ml -> Eros - Warming - 150ml''' % product_name) return False product['product_id'] = product_ids[0] # 销售订单 值列表 order_name = tmijdi_fname.strip().split(".")[0] order_val = { 'name': tmijdi_fname.strip().split(".")[0], 'shop_id': shop.id, 'date_order': datetime.now(), #订单支付时间 'partner_id': partner_id, 'partner_invoice_id': partner_id, 'partner_shipping_id': partner_id, 'warehouse_id': shop.warehouse_id.id, 'pricelist_id': shop.pricelist_id.id, 'company_id': 1, 'all_discounts': 0, 'picking_policy': 'direct', 'state': 'draft', 'user_id': uid, 'order_policy': 'picking', 'client_order_ref': order_name, 'order_line': [], 'note': '', } note = "" coe_obj = self.pool.get('sale.coe') for key in coe_lines: coe_line = coe_lines[key] coe_vals = { # 为每个收件人 创建COE 条目 'tmi_jdi_no': coe_line["tmi_jdi_no"], 'name': coe_line["express_no"], 'name': coe_line["name"], 'mobile': coe_line["mobile"], 'state': coe_line["state"], 'city': coe_line["city"], 'address': coe_line["address"], 'zip': coe_line["zip"], } coe_id = coe_obj.search(cr, uid, [('name', '=', coe_line["express_no"])], context=context) if coe_id: coe_id = coe_id[0] if not coe_id: coe_id = coe_obj.create(cr, uid, coe_vals, context=context) coe_line["id"] = coe_id gift_product_vals = { # 为每个 TMI/JDI单 加入一个赠品 'product_uos_qty': 1, 'product_id': product_gift_id, 'product_uom': 1, 'express_no': coe_id, 'price_unit': 0, 'product_uom_qty': 1, 'name': '.', 'delay': 7, 'discount': 0, } order_val['order_line'].append((0, 0, gift_product_vals)) note += u"TMJD NO:%s, COE:%s, 姓名:%s, 电话:%s, 省份:%s, 城市%s, 收货地址:%s, 邮编:%s;" % ( coe_line["tmi_jdi_no"], coe_line["express_no"], coe_line["name"], coe_line["mobile"], coe_line["state"], coe_line["city"], coe_line["address"], coe_line["zip"]) note += chr(10) order_val.update({"note": note}) for o in product_lines: desc = o.get('desc', '.').strip() if desc == "": desc = '-' line_vals = { 'product_uos_qty': o.get('qty', 0), 'product_id': o['product_id'], 'product_uom': 1, 'express_no': coe_lines[o.get('tmi_jdi_no')]["id"], 'price_unit': o.get('price', 0), 'product_uom_qty': o.get('qty', 0), 'name': desc, 'delay': 7, 'discount': 0, } order_val['order_line'].append((0, 0, line_vals)) order_id = order_obj.create(cr, uid, order_val, context=context) return order_id def string_refactor(self, name): if not name: return False name = name.replace("/", "%") name = name.replace("|", "%") ll = name.split("-") ll = [l.strip() for l in ll] ll = "%".join(ll) return ll.replace(" ", "%") def import_orders_from_excel(self, cr, uid, ids, context=None): attachment_obj = self.pool.get('ir.attachment') attachment_id = attachment_obj.search(cr, uid, [('res_id', '=', ids[0])], context=context) if len(attachment_id) < 1: return False attach = attachment_obj.browse(cr, uid, attachment_id[0], context=context) fname = attach.store_fname display_name = attach.name if not fname: return False fname = self.get_full_path(cr, uid, fname) wb = load_workbook(filename=fname) #ws = wb.get_sheet_by_name("Sheet1") ws = wb.get_sheet_by_name(wb.get_sheet_names()[0]) highest_row = ws.get_highest_row() highest_col = ws.get_highest_column() title_order = ws.cell(row=1, column=1).value title_product = ws.cell(row=1, column=2).value title_qty = ws.cell(row=1, column=3).value title_coe = ws.cell(row=1, column=5).value if highest_col < 12 or title_order != u"订单編號" or title_product != u"产品名称" or title_coe != u"COE": #attach.unlink() raise osv.except_osv(u'Excel错误', u'''文件:%s 格式不正确.''' % display_name) row_start = 2 coe_lines = {} last_tmi_jdi_no = None last_express_no = None while row_start <= highest_row and ws.cell(row=row_start, column=2).value: tmi_jdi_no = ws.cell(row=row_start, column=1).value express_no = ws.cell(row=row_start, column=5).value name = ws.cell(row=row_start, column=6).value mobile = ws.cell(row=row_start, column=7).value address = ws.cell(row=row_start, column=8).value if bool(tmi_jdi_no) != bool(express_no): #attach.unlink() raise osv.except_osv( u'Excel错误', u'''文件'%s'第:%d行不正确地合并单元格.''' % (display_name, row_start + 1)) if tmi_jdi_no and express_no and name and mobile and address: city = ws.cell(row=row_start, column=9).value state = ws.cell(row=row_start, column=10).value zip = str(ws.cell(row=row_start, column=11).value) last_tmi_jdi_no = tmi_jdi_no = str(tmi_jdi_no) coe_lines[last_tmi_jdi_no] = { "id": 1, "tmi_jdi_no": tmi_jdi_no, "express_no": express_no, "name": name, "mobile": mobile, "address": address, "city": city, "state": state, "zip": zip } row_start += 1 row_start = 2 product_lines = [] last_tmi_jdi_no = None last_express_no = None while row_start <= highest_row and ws.cell(row=row_start, column=2).value: line = {} line["product_id"] = 1 line["desc"] = "" line["product"] = ws.cell(row=row_start, column=2).value qty_tmp = ws.cell(row=row_start, column=3) line["qty"] = qty_tmp.get_original_value() or 1 cell_price = ws.cell(row=row_start, column=4) price_tmp = cell_price.get_original_value() or 0 if line["qty"] > 1: price_tmp = price_tmp / line["qty"] line["price"] = price_tmp tmi_jdi_no = ws.cell(row=row_start, column=1).value express_no = ws.cell(row=row_start, column=5).value if tmi_jdi_no: last_tmi_jdi_no = str(tmi_jdi_no) last_express_no = express_no line['tmi_jdi_no'] = last_tmi_jdi_no line['express_no'] = last_express_no product_lines.append(line) row_start += 1 self.create_order_from_excel(cr, uid, ids, coe_lines, product_lines, display_name, context=context) attach.unlink() return True def search_product_sku(self, cr, uid, ids, num_iids=None, context=None): port = 80 shop = self.browse(cr, uid, ids[0], context=context) setDefaultAppInfo(shop.appkey, shop.appsecret) req = ItemSkusGetRequest(shop.apiurl, port) req.fields = "sku_id, num_iid, properties, price, status, memo, properties_name, outer_id,quantity,barcode,change_prop,sku_spec_id,extra_id" if not num_iids: req.num_iids = shop.tokenurl else: req.num_iids = num_iids resp = req.getResponse(shop.sessionkey) skus = resp.get('item_skus_get_response').get('skus', False).get('sku', False) return skus def create_product_tmalljd_nosku(self, cr, uid, ids, item, context=None): product_tmalljd_objs = self.pool.get('product.tmalljd') product_vals = { 'ec_shop_id': ids[0], 'ec_price': float(item.get('price')), 'ec_qty': item.get('num'), 'ec_outer_code': item.get('outer_id'), 'ec_num_iid': str(item.get('num_iid')), 'ec_title': item.get('title') } pids = product_tmalljd_objs.search( cr, uid, [('ec_num_iid', '=', str(item.get('num_iid'))), ('ec_shop_id', '=', ids[0])], context=context) if len(pids) < 1: product_tmalljd_objs.create(cr, uid, product_vals) return True def search_product(self, cr, uid, ids, context=None): this = self.browse(cr, uid, ids, context=context)[0] res = self._search_product(cr, uid, ids, product_name=None, start_modified=this.start_modified, end_modified=this.end_modified, context=context) if len(res) < 1: return product_tmalljd_objs = self.pool.get('product.tmalljd') num_iids = [str(o['num_iid']) for o in res] titles = {} for item in res: titles[str(item.get('num_iid'))] = item.get('title') skus_list = [] skus_list2 = [] interval = 40 start = end = 0 final_end = len(num_iids) while start < final_end: if start + interval > final_end: end = final_end else: end = start + interval sub_list = num_iids[start:end] sub_num_iids = ",".join(sub_list) skus_list += self.search_product_sku(cr, uid, ids, num_iids=sub_num_iids, context=context) start = end for sku_item in skus_list: str_num_iid = str(sku_item.get('num_iid')) if str_num_iid not in skus_list2: skus_list2.append(str_num_iid) no_sku_num_iids = [] for item in res: if str(item["num_iid"]) not in skus_list2: self.create_product_tmalljd_nosku(cr, uid, ids, item, context=context) for sku in skus_list: product_vals = { 'ec_shop_id': this.id, 'ec_price': float(sku.get('price')), 'ec_qty': sku.get('quantity'), 'ec_outer_code': sku.get('outer_id'), 'ec_sku_id': str(sku.get('sku_id')) } #, 'ec_ean13':sku.get('barcode','')} num_iid = str(sku['num_iid']) product_vals['ec_num_iid'] = num_iid product_vals['ec_title'] = titles[num_iid] pids = product_tmalljd_objs.search( cr, uid, [('ec_sku_id', '=', str(sku['sku_id'])), ('ec_shop_id', '=', this.id)], context=context) #if len(pids)>0: # product_tmalljd_objs.write(cr,uid,pids[0],product_vals) #else: if len(pids) < 1: product_tmalljd_objs.create(cr, uid, product_vals) return True def _search_product(self, cr, uid, ids, product_name=None, start_modified=None, end_modified=None, context=None): """ 1) 按商品名称,商品修改时间搜索店铺商品 2) start_modified、end_modified 都是UTC时间,需要加上8小时传给电商平台 """ shop_id = self.browse(cr, uid, ids[0], context=context) setDefaultAppInfo(shop_id.appkey, shop_id.appsecret) req = ItemsOnsaleGetRequest(shop_id.apiurl, 80) req.fields = "approve_status,num_iid,title,nick,type,num,list_time,price,modified,delist_time,outer_id" if product_name: req.q = product_name req.page_no = 1 req.page_size = 100 total_get = 0 total_results = 100 res = [] while total_get < total_results: resp = req.getResponse(shop_id.sessionkey) total_results = resp.get('items_onsale_get_response').get( 'total_results') if total_results > 0: res += resp.get('items_onsale_get_response').get('items').get( 'item') total_get += req.page_size req.page_no = req.page_no + 1 # # 时间需要减去8小时 for r in res: r['modified'] = (datetime.strptime( r['modified'], '%Y-%m-%d %H:%M:%S', ) - timedelta(hours=8)).strftime('%Y-%m-%d %H:%M:%S') return res def create_shipping_address(self, cr, uid, partner_id, vals, context=None): partner_objs = self.pool.get('res.partner') #state_objs = self.pool.get('res.country.state') state_id = 0 if vals.get('state', False): state_id = self.pool.get('res.country.state').search( cr, uid, [('name', 'like', vals.get('state'))]) if not partner_id: return 0 partner_vals = { 'parent_id': partner_id, 'name': vals.get('name'), 'phone': vals.get('phone'), 'street': vals.get('street'), 'mobile': vals.get('mobile'), 'city': vals.get('city'), 'zip': vals.get('zip'), 'type': 'delivery', 'is_company': False, 'customer': False, 'supplier': False, } if state_id: partner_vals.update({'state': state_id[0]}) id = partner_objs.create(cr, uid, partner_vals, context=context) return id or 0 def remove_duplicate_orders(self, cr, uid, orders, context=None): sale_obj = self.pool.get('sale.order') submitted_references = [o['sale_code'] for o in orders] existing_order_ids = sale_obj.search( cr, uid, [('name', 'in', submitted_references)], context=context) existing_orders = sale_obj.read(cr, uid, existing_order_ids, ['name'], context=context) existing_references = set([o['name'] for o in existing_orders]) orders_to_save = [ o for o in orders if o['sale_code'] not in existing_references ] return orders_to_save def search_orders_by_modified_time(self, cr, uid, ids, status='WAIT_SELLER_SEND_GOODS', date_start=None, date_end=None, context=None): port = 80 shop = self.browse(cr, uid, ids[0], context=context) partner_id = shop.partner_id.id setDefaultAppInfo(shop.appkey, shop.appsecret) req = TradesSoldIncrementGetRequest(shop.apiurl, port) req.fields = "type,seller_nick,buyer_nick,created,sid,tid,status,buyer_memo,seller_memo,payment,discount_fee,adjust_fee,post_fee,total_fee, pay_time,end_time,modified,received_payment,price,alipay_id,receiver_name,receiver_state,receiver_city,receiver_district,receiver_address, receiver_zip,receiver_mobile,receiver_phone,orders.price,orders.num,orders.iid,orders.num_iid,orders.sku_id,orders.refund_status,orders.status,orders.oid, orders.total_fee,orders.payment,orders.discount_fee,orders.adjust_fee,orders.sku_properties_name,orders.outer_iid,orders.outer_sku_id" req.status = status req.type = "instant_trade,auto_delivery,guarantee_trade,tmall_i18n" if shop.start_modified: req.start_modified = shop.start_modified if shop.end_modified: req.end_modified = shop.end_modified res = [] req.page_no = 1 req.page_size = 100 total_get = 0 total_results = 100 while total_get < total_results: resp = req.getResponse(shop.sessionkey) trades = resp.get('trades_sold_increment_get_response').get( 'trades', False) total_results = resp.get('trades_sold_increment_get_response').get( 'total_results') _logger.info("Jimmy total_results :%d" % total_results) if total_results > 0: res += trades.get('trade') total_get += req.page_size req.page_no = req.page_no + 1 _logger.info("Jimmy page_size :%d" % req.page_size) _logger.info("Jimmy total_get :%d" % total_get) # 时间需要减去8小时 # 单号加上店铺前缀 order_ids = [] for trade in res: trade['created'] = (datetime.strptime( trade['created'], '%Y-%m-%d %H:%M:%S', ) - timedelta(hours=8)).strftime('%Y-%m-%d %H:%M:%S') trade['pay_time'] = (datetime.strptime( trade.get('pay_time'), '%Y-%m-%d %H:%M:%S', ) - timedelta(hours=8)).strftime('%Y-%m-%d %H:%M:%S') trade['sale_code'] = '%s_%s' % (shop.code, trade.get('tid')) orders = self.remove_duplicate_orders(cr, uid, res, context=context) #orders = res for trade in orders: #try: # #_logger.info("Jimmy before create_order") #order_id = self.create_order(cr, uid, ids, trade, context = context ) order_id = self.create_order(cr, uid, ids, trade, context=context) # _logger.info("Jimmy after create_order") # order_ids.append(order_id) #except Exception, e: # syncerr = u"店铺[%s]订单[%s]同步错误: %s" % (shop.name, trade['tid'], e) # self.pool.get('loewieec.error').create(cr, uid, {'name':syncerr, 'shop_id': shop.id}, context = context ) # continue return order_ids def get_tmall_time(self, cr, uid, ids, context=None): shop = self.browse(cr, uid, ids[0], context=context) setDefaultAppInfo(shop.appkey, shop.appsecret) req = TimeGetRequest(shop.apiurl, 80) resp = req.getResponse(shop.sessionkey) ttime = resp.get('time_get_response').get('time', False) if ttime: shop.tmall_time = ttime return True def create_order(self, cr, uid, ids, trade, context=None): order_obj = self.pool.get('sale.order') shop = self.browse(cr, uid, ids[0], context=context) partner_id = shop.partner_id.id gift_product_id = shop.gift_product_id.id order_val = { 'name': "%s_%s" % (shop.code, self.pool.get('ir.sequence').get(cr, uid, 'sale.order') or '/'), 'shop_id': shop.id, 'date_order': datetime.now(), #订单支付时间 trade.get('pay_time') or 'create_date': datetime.now(), #trade.get('created'), #订单创建时间 'partner_id': partner_id, 'partner_invoice_id': partner_id, 'partner_shipping_id': partner_id, 'warehouse_id': shop.warehouse_id.id, 'pricelist_id': shop.pricelist_id.id, 'company_id': 1, 'all_discounts': 0, 'picking_policy': 'direct', 'state': 'draft', 'user_id': uid, 'order_policy': 'picking', 'client_order_ref': u'Loewieec_sync Generated', 'order_line': [], } product_null_id = self.pool.get('product.product').search( cr, uid, [('name_template', '=', u'刷单空包')], context=context) product_null_id = product_null_id and product_null_id[0] or 0 if not product_null_id: raise osv.except_osv(u'ERP错误', u'''ERP中不存在 '刷单空包' 产品!''') order_lines = [] tids = [] for order in trade: tid = str(order['tid']) if order['is_jaycee']: jaycee_vals = { 'product_id': product_null_id, 'product_uos_qty': 1, 'tmi_jdi_no': tid, 'product_uom': 1, 'price_unit': 0, 'product_uom_qty': 1, 'name': '-', 'delay': 7, 'discount': 0, } order_val['order_line'].append((0, 0, jaycee_vals)) continue lines = order["orders"]["order"] for line in lines: order_lines.append(line) tids.append(tid) for order_line in order_lines: tid = str(order_line.get('tid') or order_line.get('oid')) line_vals = { 'product_uos_qty': order_line.get('num'), 'product_id': 1, 'tmi_jdi_no': tid, 'product_uom': 1, 'price_unit': 1, 'product_uom_qty': order_line.get('num'), 'name': '-', 'delay': 7, 'discount': 0, } product_tmalljd_ids = self.pool.get('product.tmalljd').search( cr, uid, [('ec_sku_id', '=', order_line.get('sku_id') or order_line.get('num_iid'))], context=context) #如果没有匹配到产品,报同步异常 coe_lines if not product_tmalljd_ids: syncerr = u"订单导入错误: 匹配不到商品。tid=%s, 商品num_iid=%s, outer_sku_id=%s, sku_id=%s " % ( tid, order_line.get( 'num_iid', ''), order_line.get( 'outer_sku_id', ''), order_line.get('sku_id', '')) self.pool.get('loewieec.error').create(cr, uid, { 'name': syncerr, 'shop_id': shop.id }, context=context) return False product_tmalljd_obj = self.pool.get('product.tmalljd').browse( cr, uid, product_tmalljd_ids[0], context=context) product_id = product_tmalljd_obj.erp_product_id.id uom_id = product_tmalljd_obj.erp_product_id.uom_id.id #添加订单明细行 price_unit = float(order_line.get( 'payment', 0)) / order_line.get('num') or float( order_line.get('total_fee', 0)) / order_line.get('num') line_vals.update({ 'product_id': product_id, 'price_unit': price_unit, 'product_uom': uom_id }) order_val['order_line'].append((0, 0, line_vals)) for tid in tids: gift_vals = { 'product_uos_qty': 1, 'product_id': gift_product_id, 'tmi_jdi_no': tid, 'product_uom': 1, 'price_unit': 0, 'product_uom_qty': 1, 'name': '.', 'delay': 7, 'discount': 0, } order_val['order_line'].append((0, 0, gift_vals)) order_id = order_obj.create(cr, uid, order_val, context=context) return order_id def search_orders_sent_on_tmall(self, cr, uid, ids, context=None): return self.search_orders_by_created_time( cr, uid, ids, context=context, status=['WAIT_BUYER_CONFIRM_GOODS', 'WAIT_SELLER_SEND_GOODS']) def search_orders_seller_memo(self, cr, uid, ids, context=None, orders={}): port = 80 shop = self.browse(cr, uid, ids[0], context=context) partner_id = shop.partner_id.id setDefaultAppInfo(shop.appkey, shop.appsecret) req = TradeGetRequest(shop.apiurl, port) req.fields = "seller_memo" for order in orders: req.tid = order["tid"] resp = req.getResponse(shop.sessionkey) seller_memo = resp.get('trade_get_response', '').get('trade', '').get('seller_memo', '') order['is_jaycee'] = seller_memo.find(u'jaycee订单') >= 0 return orders def search_orders_by_created_time(self, cr, uid, ids, context=None, status=[]): port = 80 shop = self.browse(cr, uid, ids[0], context=context) partner_id = shop.partner_id.id setDefaultAppInfo(shop.appkey, shop.appsecret) req = TradesSoldGetRequest(shop.apiurl, port) req.fields = "sid,tid,receiver_name,receiver_state,receiver_city,receiver_district,receiver_address, receiver_zip,receiver_mobile,receiver_phone,orders.num,orders.store_code,orders.num_iid,orders.sku_id,orders.oid, orders.total_fee,orders.payment,orders.outer_sku_id" req.type = "instant_trade,auto_delivery,guarantee_trade,tmall_i18n" hours_interval = shop.sync_interval if hours_interval: hours_interval -= 8 else: hours_interval = 16 req.start_created = ( datetime.now() - timedelta(hours=hours_interval)).strftime('%Y-%m-%d %H:%M:%S') req.end_created = (datetime.now() + timedelta(hours=8)).strftime('%Y-%m-%d %H:%M:%S') res = [] if len(status) < 1: status.append(shop.tmi_state or 'WAIT_SELLER_SEND_GOODS') for order_status in status: req.status = order_status req.page_no = 1 req.page_size = 100 total_get = 0 total_results = 100 while total_get < total_results: resp = req.getResponse(shop.sessionkey) trades = resp.get('trades_sold_get_response').get( 'trades', False) total_results = resp.get('trades_sold_get_response').get( 'total_results') _logger.info("Jimmy total_results :%d" % total_results) if total_results > 0: res += trades.get('trade') total_get += req.page_size req.page_no = req.page_no + 1 if total_results < 1: shop.last_log = u"在%d小时内没有状态:%s 的订单可下载" % (shop.sync_interval, shop.tmi_state) return True orders = self.remove_duplicate_tmi_jdi_no(cr, uid, ids, res, shop, context=context) filtered_orders = self.search_orders_seller_memo( cr, uid, ids, context, orders) order_id = self.create_order(cr, uid, ids, filtered_orders, context=context) if order_id: shop.import_salesorder = order_id return order_id def remove_duplicate_tmi_jdi_no(self, cr, uid, ids, orders, shop, context=None): statement = "select tmi_jdi_no from sale_order_line where state not in ('cancel','draft') group by tmi_jdi_no" cr.execute(statement) exist_tmi_jdi_no = [] res = [] last_log = [] for item in cr.fetchall(): exist_tmi_jdi_no.append(item[0]) for order in orders: if str(order["tid"]) not in exist_tmi_jdi_no: res.append(order) else: last_log.append(str(order["tid"])) if len(last_log) > 0: shop.last_log = u"以下电商单号ERP中已存在,所以此次未导入: " + chr(10) + ",".join( last_log) + chr(10) return res def search_orders_by_tid(self, cr, uid, ids, context=None): port = 80 shop = self.browse(cr, uid, ids[0], context=context) partner_id = shop.partner_id.id setDefaultAppInfo(shop.appkey, shop.appsecret) req = TradeFullinfoGetRequest(shop.apiurl, port) req.fields = "type,receiver_name,receiver_state,receiver_city,receiver_district,receiver_address, receiver_zip,receiver_mobile,receiver_phone" req.tid = shop.authurl resp = req.getResponse(shop.sessionkey) trade = resp.get('trade_fullinfo_get_response').get('trade', False) return True def import_express_no(self, cr, uid, ids, context=None): attachment_obj = self.pool.get('ir.attachment') attachment_id = attachment_obj.search(cr, uid, [('res_id', '=', ids[0])], context=context) if len(attachment_id) < 1: return False attach = attachment_obj.browse(cr, uid, attachment_id[0], context=context) fname = attach.store_fname display_name = attach.name if not fname: return False fname = self.get_full_path(cr, uid, fname) shop = self.browse(cr, uid, ids[0], context=context) salesorder = shop.import_salesorder if not salesorder: raise osv.except_osv(u'错误', u'''请选择一个目标订单来导入COE收货人信息!!!''') wb = load_workbook(filename=fname) ws = wb.get_sheet_by_name(wb.get_sheet_names()[0]) highest_row = ws.get_highest_row() highest_col = ws.get_highest_column() title_order = ws.cell(row=0, column=0).value title_coe = ws.cell(row=0, column=1).value title_name = ws.cell(row=0, column=2).value if highest_col < 10 or title_order != u"參考編號" or title_coe != u"e特快單號" or title_name != u"收件人姓名": raise osv.except_osv(u'Excel错误', u'''文件:%s 格式不正确.''' % display_name) row_start = 1 coe_lines = {} note = "" while row_start <= highest_row and ws.cell(row=row_start, column=0).value: tmi_jdi_no = str(ws.cell(row=row_start, column=0).value) express_no = ws.cell(row=row_start, column=1).value name = ws.cell(row=row_start, column=2).value mobile = ws.cell(row=row_start, column=3).value address = ws.cell(row=row_start, column=4).value city = ws.cell(row=row_start, column=6).value state = ws.cell(row=row_start, column=7).value zip = str(ws.cell(row=row_start, column=8).value) coe_lines[tmi_jdi_no] = { "tmi_jdi_no": tmi_jdi_no, "name": express_no, "name": name, "mobile": mobile, "address": address, "city": city, "state": state, "zip": zip } note += u"TMJD NO:%s, COE:%s, 姓名:%s, 电话:%s, 省份:%s, 城市%s, 收货地址:%s, 邮编:%s;" % ( tmi_jdi_no, express_no, name, mobile, state, city, address, zip) note += chr(10) row_start += 1 # 从ERP数据库中搜索 是否已存在 COE订单号,如未存在则创建新的COE信息,并将ID赋值到 coe_lines的"id" coe_obj = self.pool.get("sale.coe") for val in coe_lines.values(): coe_id = coe_obj.search(cr, uid, [('name', '=', val["name"])], context=context) coe_id = coe_id and coe_id[0] or 0 if not coe_id: coe_id = coe_obj.create(cr, uid, val, context=context) else: coe_obj_id = coe_obj.browse(cr, uid, [coe_id], context=context) tmp_val = coe_obj_id.tmi_jdi_no if tmp_val.strip() != val["tmi_jdi_no"].strip(): coe_obj_id.tmi_jdi_no = tmp_val + "," + val["tmi_jdi_no"] val["id"] = coe_id # 按照销售订单行的 TMall订单号,找到并填写对应的COE单号。 last_log = [] for line in salesorder.order_line: tmijdino = line.tmi_jdi_no if tmijdino not in coe_lines.keys(): last_log.append(tmijdino) continue line.express_no = coe_lines[tmijdino]["id"] # 通知信息 if len(last_log) > 0: shop.last_log = ",".join( last_log) + u" - COE-e特快excel文件中不存在以上TMI单号." salesorder.note = note attach.unlink() return True
class magento_storeview(orm.Model): _name = 'magento.storeview' _inherit = 'magento.binding' _description = "Magento Storeview" _order = 'sort_order ASC, id ASC' _columns = { 'name': fields.char('Name', required=True, readonly=True), 'code': fields.char('Code', readonly=True), 'enabled': fields.boolean('Enabled', readonly=True), 'sort_order': fields.integer('Sort Order', readonly=True), 'store_id': fields.many2one('magento.store', 'Store', ondelete='cascade', readonly=True), 'lang_id': fields.many2one('res.lang', 'Language'), 'backend_id': fields.related('store_id', 'website_id', 'backend_id', type='many2one', relation='magento.backend', string='Magento Backend', store=True, readonly=True), 'import_orders_from_date': fields.datetime( 'Import sale orders from date', help='do not consider non-imported sale orders before this date. ' 'Leave empty to import all sale orders'), 'no_sales_order_sync': fields.boolean('No Sales Order Synchronization', help='Check if the storeview is active in Magento ' 'but its sales orders should not be imported.'), } _defaults = { 'no_sales_order_sync': False, } _sql_constraints = [ ('magento_uniq', 'unique(backend_id, magento_id)', 'A storeview with same ID on Magento already exists.'), ] def import_sale_orders(self, cr, uid, ids, context=None): session = ConnectorSession(cr, uid, context=context) import_start_time = datetime.now() for storeview in self.browse(cr, uid, ids, context=context): if storeview.no_sales_order_sync: _logger.debug("The storeview '%s' is active in Magento " "but its sales orders should not be imported." % storeview.name) continue backend_id = storeview.backend_id.id if storeview.import_orders_from_date: from_date = datetime.strptime( storeview.import_orders_from_date, DEFAULT_SERVER_DATETIME_FORMAT) else: from_date = None sale_order_import_batch.delay( session, 'magento.sale.order', backend_id, { 'magento_storeview_id': storeview.magento_id, 'from_date': from_date, 'to_date': import_start_time }, priority=1) # executed as soon as possible # Records from Magento are imported based on their `created_at` # date. This date is set on Magento at the beginning of a # transaction, so if the import is run between the beginning and # the end of a transaction, the import of a record may be # missed. That's why we add a small buffer back in time where # the eventually missed records will be retrieved. This also # means that we'll have jobs that import twice the same records, # but this is not a big deal because the sales orders will be # imported the first time and the jobs will be skipped on the # subsequent imports next_time = import_start_time - timedelta(seconds=IMPORT_DELTA_BUFFER) next_time = next_time.strftime(DEFAULT_SERVER_DATETIME_FORMAT) self.write(cr, uid, ids, {'import_orders_from_date': next_time}, context=context) return True
class magento_backend(orm.Model): _name = 'magento.backend' _description = 'Magento Backend' _inherit = 'connector.backend' _backend_type = 'magento' def select_versions(self, cr, uid, context=None): """ Available versions in the backend. Can be inherited to add custom versions. Using this method to add a version from an ``_inherit`` does not constrain to redefine the ``version`` field in the ``_inherit`` model. """ return [('1.7', '1.7')] def _select_versions(self, cr, uid, context=None): """ Available versions in the backend. If you want to add a version, do not override this method, but ``select_version``. """ return self.select_versions(cr, uid, context=context) def _get_stock_field_id(self, cr, uid, context=None): field_ids = self.pool.get('ir.model.fields').search( cr, uid, [('model', '=', 'product.product'), ('name', '=', 'virtual_available')], context=context) return field_ids[0] _columns = { 'version': fields.selection(_select_versions, string='Version', required=True), 'location': fields.char('Location', required=True, help="Url to magento application"), 'admin_location': fields.char('Admin Location'), 'use_custom_api_path': fields.boolean( 'Custom Api Path', help="The default API path is '/index.php/api/xmlrpc'. " "Check this box if you use a custom API path, in that case, " "the location has to be completed with the custom API path "), 'username': fields.char('Username', help="Webservice user"), 'password': fields.char('Password', help="Webservice password"), 'use_auth_basic': fields.boolean( 'Use HTTP Auth Basic', help="Use a Basic Access Authentication for the API. " "The Magento server could be configured to restrict access " "using a HTTP authentication based on a username and " "a password."), 'auth_basic_username': fields.char( 'Basic Auth. Username', help="Basic access authentication web server side username"), 'auth_basic_password': fields.char( 'Basic Auth. Password', help="Basic access authentication web server side password"), 'sale_prefix': fields.char( 'Sale Prefix', help="A prefix put before the name of imported sales orders.\n" "For instance, if the prefix is 'mag-', the sales " "order 100000692 in Magento, will be named 'mag-100000692' " "in OpenERP."), 'warehouse_id': fields.many2one('stock.warehouse', 'Warehouse', required=True, help='Warehouse used to compute the ' 'stock quantities.'), 'website_ids': fields.one2many('magento.website', 'backend_id', string='Website', readonly=True), 'default_lang_id': fields.many2one( 'res.lang', 'Default Language', help="If a default language is selected, the records " "will be imported in the translation of this language.\n" "Note that a similar configuration exists " "for each storeview."), 'default_category_id': fields.many2one( 'product.category', string='Default Product Category', help='If a default category is selected, products imported ' 'without a category will be linked to it.'), # add a field `auto_activate` -> activate a cron 'import_products_from_date': fields.datetime('Import products from date'), 'import_categories_from_date': fields.datetime('Import categories from date'), 'catalog_price_tax_included': fields.boolean('Prices include tax'), 'product_stock_field_id': fields.many2one( 'ir.model.fields', string='Stock Field', domain="[('model', 'in', ['product.product', 'product.template'])," " ('ttype', '=', 'float')]", help="Choose the field of the product which will be used for " "stock inventory updates.\nIf empty, Quantity Available " "is used."), 'product_binding_ids': fields.one2many('magento.product.product', 'backend_id', string='Magento Products', readonly=True), } _defaults = { 'product_stock_field_id': _get_stock_field_id, 'use_custom_api_path': False, 'use_auth_basic': False, } _sql_constraints = [('sale_prefix_uniq', 'unique(sale_prefix)', "A backend with the same sale prefix already exists")] def check_magento_structure(self, cr, uid, ids, context=None): """ Used in each data import. Verify if a website exists for each backend before starting the import. """ for backend_id in ids: website_ids = self.pool['magento.website'].search( cr, uid, [('backend_id', '=', backend_id)], context=context) if not website_ids: self.synchronize_metadata(cr, uid, backend_id, context=context) return True def synchronize_metadata(self, cr, uid, ids, context=None): if not hasattr(ids, '__iter__'): ids = [ids] session = ConnectorSession(cr, uid, context=context) for backend_id in ids: for model in ('magento.website', 'magento.store', 'magento.storeview'): # import directly, do not delay because this # is a fast operation, a direct return is fine # and it is simpler to import them sequentially import_batch(session, model, backend_id) return True def import_partners(self, cr, uid, ids, context=None): """ Import partners from all websites """ if not hasattr(ids, '__iter__'): ids = [ids] self.check_magento_structure(cr, uid, ids, context=context) for backend in self.browse(cr, uid, ids, context=context): for website in backend.website_ids: website.import_partners() return True def import_sale_orders(self, cr, uid, ids, context=None): """ Import sale orders from all store views """ if not hasattr(ids, '__iter__'): ids = [ids] storeview_obj = self.pool.get('magento.storeview') storeview_ids = storeview_obj.search(cr, uid, [('backend_id', 'in', ids)], context=context) storeviews = storeview_obj.browse(cr, uid, storeview_ids, context=context) for storeview in storeviews: storeview.import_sale_orders() return True def import_customer_groups(self, cr, uid, ids, context=None): if not hasattr(ids, '__iter__'): ids = [ids] self.check_magento_structure(cr, uid, ids, context=context) session = ConnectorSession(cr, uid, context=context) for backend_id in ids: import_batch.delay(session, 'magento.res.partner.category', backend_id) return True def _import_from_date(self, cr, uid, ids, model, from_date_field, context=None): if not hasattr(ids, '__iter__'): ids = [ids] self.check_magento_structure(cr, uid, ids, context=context) session = ConnectorSession(cr, uid, context=context) import_start_time = datetime.now() for backend in self.browse(cr, uid, ids, context=context): from_date = getattr(backend, from_date_field) if from_date: from_date = datetime.strptime(from_date, DEFAULT_SERVER_DATETIME_FORMAT) else: from_date = None import_batch.delay(session, model, backend.id, filters={ 'from_date': from_date, 'to_date': import_start_time }) # Records from Magento are imported based on their `created_at` # date. This date is set on Magento at the beginning of a # transaction, so if the import is run between the beginning and # the end of a transaction, the import of a record may be # missed. That's why we add a small buffer back in time where # the eventually missed records will be retrieved. This also # means that we'll have jobs that import twice the same records, # but this is not a big deal because they will be skipped when # the last `sync_date` is the same. next_time = import_start_time - timedelta(seconds=IMPORT_DELTA_BUFFER) next_time = next_time.strftime(DEFAULT_SERVER_DATETIME_FORMAT) self.write(cr, uid, ids, {from_date_field: next_time}, context=context) def import_product_categories(self, cr, uid, ids, context=None): self._import_from_date(cr, uid, ids, 'magento.product.category', 'import_categories_from_date', context=context) return True def import_product_product(self, cr, uid, ids, context=None): self._import_from_date(cr, uid, ids, 'magento.product.product', 'import_products_from_date', context=context) return True def update_product_stock_qty(self, cr, uid, ids, context=None): if not hasattr(ids, '__iter__'): ids = [ids] mag_product_obj = self.pool.get('magento.product.product') product_ids = mag_product_obj.search(cr, uid, [('backend_id', 'in', ids), ('no_stock_sync', '=', False)], context=context) mag_product_obj.recompute_magento_qty(cr, uid, product_ids, context=context) return True def _magento_backend(self, cr, uid, callback, domain=None, context=None): if domain is None: domain = [] ids = self.search(cr, uid, domain, context=context) if ids: callback(cr, uid, ids, context=context) def _scheduler_import_sale_orders(self, cr, uid, domain=None, context=None): self._magento_backend(cr, uid, self.import_sale_orders, domain=domain, context=context) def _scheduler_import_customer_groups(self, cr, uid, domain=None, context=None): self._magento_backend(cr, uid, self.import_customer_groups, domain=domain, context=context) def _scheduler_import_partners(self, cr, uid, domain=None, context=None): self._magento_backend(cr, uid, self.import_partners, domain=domain, context=context) def _scheduler_import_product_categories(self, cr, uid, domain=None, context=None): self._magento_backend(cr, uid, self.import_product_categories, domain=domain, context=context) def _scheduler_import_product_product(self, cr, uid, domain=None, context=None): self._magento_backend(cr, uid, self.import_product_product, domain=domain, context=context) def _scheduler_update_product_stock_qty(self, cr, uid, domain=None, context=None): self._magento_backend(cr, uid, self.update_product_stock_qty, domain=domain, context=context) def output_recorder(self, cr, uid, ids, context=None): """ Utility method to output a file containing all the recorded requests / responses with Magento. Used to generate test data. Should be called with ``erppeek`` for instance. """ from .unit.backend_adapter import output_recorder import os import tempfile fmt = '%Y-%m-%d-%H-%M-%S' timestamp = datetime.now().strftime(fmt) filename = 'output_%s_%s' % (cr.dbname, timestamp) path = os.path.join(tempfile.gettempdir(), filename) output_recorder(path) return path
class magento_website(orm.Model): _name = 'magento.website' _inherit = 'magento.binding' _description = 'Magento Website' _order = 'sort_order ASC, id ASC' _columns = { 'name': fields.char('Name', required=True, readonly=True), 'code': fields.char('Code', readonly=True), 'sort_order': fields.integer('Sort Order', readonly=True), 'store_ids': fields.one2many('magento.store', 'website_id', string="Stores", readonly=True), 'import_partners_from_date': fields.datetime('Import partners from date'), 'product_binding_ids': fields.many2many('magento.product.product', string='Magento Products', readonly=True), } _sql_constraints = [ ('magento_uniq', 'unique(backend_id, magento_id)', 'A website with the same ID on Magento already exists.'), ] def import_partners(self, cr, uid, ids, context=None): if not hasattr(ids, '__iter__'): ids = [ids] session = ConnectorSession(cr, uid, context=context) import_start_time = datetime.now() for website in self.browse(cr, uid, ids, context=context): backend_id = website.backend_id.id if website.import_partners_from_date: from_date = datetime.strptime( website.import_partners_from_date, DEFAULT_SERVER_DATETIME_FORMAT) else: from_date = None partner_import_batch.delay( session, 'magento.res.partner', backend_id, { 'magento_website_id': website.magento_id, 'from_date': from_date, 'to_date': import_start_time }) # Records from Magento are imported based on their `created_at` # date. This date is set on Magento at the beginning of a # transaction, so if the import is run between the beginning and # the end of a transaction, the import of a record may be # missed. That's why we add a small buffer back in time where # the eventually missed records will be retrieved. This also # means that we'll have jobs that import twice the same records, # but this is not a big deal because they will be skipped when # the last `sync_date` is the same. next_time = import_start_time - timedelta(seconds=IMPORT_DELTA_BUFFER) next_time = next_time.strftime(DEFAULT_SERVER_DATETIME_FORMAT) self.write(cr, uid, ids, {'import_partners_from_date': next_time}, context=context) return True
class project_task_work(orm.Model): _inherit = 'project.task.work' def _get_display_button(self, cr, uid, ids, name, arg, context=None): res = {} for work_data in self.browse(cr, uid, ids, context=context): res[work_data.id] = False if work_data.type_id: pt_obj = self.pool.get('accreditation.task.work.type') pt_data = pt_obj.browse(cr, uid, work_data.type_id.id) if pt_data.create_audit \ or pt_data.create_line_to_invoice \ or pt_data.create_quotation \ or pt_data.create_purchase_requisition \ or pt_data.create_sale_quotation \ or pt_data.update_agenda \ or pt_data.accreditation_request_generation \ or pt_data.set_obtained_accreditation \ or pt_data.del_obtained_accreditation \ or pt_data.create_maintenance_fee_tasks \ or pt_data.create_maintenance_fee_offer \ or pt_data.create_child_project \ or pt_data.get_accreditation_test \ or pt_data.req_supervision \ or pt_data.doclite_action: res[work_data.id] = True return res def _display_date_obtained_accreditation(self, cr, uid, ids, name, arg, context=None): res = {} for work_data in self.browse(cr, uid, ids, context=context): res[work_data.id] = False if work_data.type_id and work_data.type_id.set_obtained_accreditation: res[work_data.id] = True return res _columns = { 'type_id': fields.many2one('accreditation.task.work.type', 'Type of work', ondelete="cascade"), 'description': fields.text('Description'), 'phase_id': fields.related('task_id', 'phase_id', type="many2one", relation="project.phase", string='Audit', store=False), 'department_id': fields.related('task_id', 'project_id', 'analytic_account_id', 'department_id', type="many2one", relation="hr.department", string='Dipartimento', store=False), 'project_state': fields.related('task_id', 'project_id', 'state', type="char", relation="project.project", string='Project State', store=False), 'project_task_planned_hours': fields.related('task_id', 'planned_hours', type="float", relation="project.task", string='Task Planned Hours', store=False), 'project_task_effective_hours': fields.related('task_id', 'effective_hours', type="float", relation="project.task", string='Task Effective Hours', store=False), 'not_billing': fields.boolean('Not Billing'), 'project_task_state': fields.related('task_id', 'state', type="char", relation="project.task", string='Task State', store=False), 'person_id': fields.many2one('res.partner', domain=[ ('individual', '=', True), ], string='Persona Fisica'), 'customer_order_reference': fields.char('Riferimento ordine cliente', size=64), 'meeting_id': fields.many2one('calendar.event', 'Meeting'), 'unit_id': fields.many2one('accreditation.units', 'Unità'), 'date_end': fields.date('Data Finale'), 'audit_visit_doc_review': fields.boolean('Attività di Visita/Esame documentale'), 'audit_visit_accompaniment': fields.boolean('Attività di Visita in Accompagnamento'), 'display_button': fields.function(_get_display_button, type='boolean', string="Hidden", store=False), 'display_date_obtained_accreditation': fields.function(_display_date_obtained_accreditation, type='boolean', string="Hidden", store=False), 'date_obtained_accreditation': fields.date('Data di Accreditamento'), 'exec_date': fields.datetime('Data e Ora Esecuzione'), 'last_protocol': fields.char(size=100, string='Ultimo Protocollo'), } _defaults = { 'date': None, 'date_obtained_accreditation': None, } def onchange_project(self, cr, uid, ids, project_id, task_id, context=None): if task_id and context: if not context.get('wiew_task_form', False): return { 'value': { 'task_id': None, 'unit_id': None, } } return { 'value': { 'unit_id': None, } } def onchange_type_id(self, cr, uid, ids, type_id, context=None): if type_id: pt_obj = self.pool.get('accreditation.task.work.type') pt_data = pt_obj.browse(cr, uid, type_id) t_display_button = False if pt_data.create_audit \ or pt_data.create_line_to_invoice \ or pt_data.create_quotation \ or pt_data.create_purchase_requisition \ or pt_data.create_sale_quotation \ or pt_data.update_agenda \ or pt_data.accreditation_request_generation \ or pt_data.set_obtained_accreditation \ or pt_data.del_obtained_accreditation \ or pt_data.create_maintenance_fee_tasks \ or pt_data.create_maintenance_fee_offer \ or pt_data.create_child_project \ or pt_data.get_accreditation_test \ or pt_data.req_supervision \ or pt_data.doclite_action: t_display_button = True return { 'value': { 'audit_visit_doc_review': pt_data.audit_visit_doc_review, 'audit_visit_accompaniment': pt_data.audit_visit_accompaniment, 'display_button': t_display_button, } } return { 'value': { 'audit_visit_doc_review': None, 'audit_visit_accompaniment': None, 'display_button': False, } } def duplicate_work(self, cr, uid, ids, default={}, context=None): context = context or {} if default is None: default = {} default.update({ 'date_end': None, 'date': None, 'exec_date': None, }) t_person = default.get('person_id') context.update({'person_id': t_person}) res = super(project_task_work, self).duplicate_work(cr, uid, ids, default, context) return res def copy(self, cr, uid, ids, default=None, context=None): context = context or {} if default is None: default = {} default.update({ 'date_end': None, 'date': None, 'exec_date': None, }) res = super(project_task_work, self).copy(cr, uid, ids, default, context) return res def save_work_and_next(self, cr, uid, ids, default={}, context=None): if context is None: context = {} super(project_task_work, self).write(cr, uid, ids, default, context) mod_obj = self.pool.get('ir.model.data') result = mod_obj.get_object_reference( cr, uid, 'project_accredia', 'view_project_task_work_form_accredia') view_id = result and result[1] or False return { 'name': _('Add New Work'), 'view_type': 'form', 'view_mode': 'form', 'res_model': 'project.task.work', 'type': 'ir.actions.act_window', 'context': context, 'view_id': view_id, 'target': 'new', } def save_work(self, cr, uid, ids, default={}, context=None): if context is None: context = {} res = super(project_task_work, self).write(cr, uid, ids, default, context) t_date = self.browse(cr, uid, ids[0]).date if t_date: context.update({'day': t_date[:10]}) t_user_id = default.get('user_id') context.update({'user_id': t_user_id}) t_flag = default.get('default_day_works_flag') or default.get( 'day_works_flag') if t_flag: return self.pool.get('wizard.select.date').view_day_works( cr, uid, ids, context) return res def save_work_complete_task(self, cr, uid, ids, default={}, context=None): if context is None: context = {} res = super(project_task_work, self).write(cr, uid, ids, default, context) value = self.browse(cr, uid, ids)[0] t_task = value.task_id.id task_obj = self.pool.get('project.task') data = task_obj.browse(cr, uid, [t_task]) if data and data[0]: # task_obj._check_child_task(cr, uid, ids, context=context) task_obj.case_close(cr, uid, [t_task], context=context) t_date = self.browse(cr, uid, ids[0]).date context.update({'day': t_date and t_date[:10] or None}) t_user_id = default.get('user_id') context.update({'user_id': t_user_id}) t_flag = default.get('default_day_works_flag') or default.get( 'day_works_flag') if t_flag: return self.pool.get('wizard.select.date').view_day_works( cr, uid, ids, context) return res # a seconda del flag di not_billing. Il controllo non viene # effettuato se il lavoro è di tipo # ZZ che serve per gestire il pregresso id=30 utilizzo l'id perchè # da vals ho solo l'id def onchange_task(self, cr, uid, ids, task_id, context=None): if not task_id: return {} task_data = self.pool.get('project.task').browse(cr, uid, task_id) t_task_planned = task_data.planned_hours t_task_effective = task_data.effective_hours return { 'value': { 'project_task_planned_hours': t_task_planned, 'project_task_effective_hours': t_task_effective, } } return {} def create(self, cr, uid, vals, context=None): if context is None: context = {} ctx = context.copy() if not context.get('no_analytic_entry', False): ctx.update({'no_analytic_entry': True}) task_res = super(project_task_work, self).create(cr, uid, vals, context=ctx) return task_res def name_get(self, cr, uid, ids, context=None): if not len(ids): return [] res = [] for data in self.browse(cr, uid, ids): t_date = data.date or '' descr = ("%s %s") % (data.name, t_date) if not data.name: if data.type_id and data.type_id.name: descr = ("%s %s") % (data.type_id.name, t_date) res.append((data.id, descr)) return res
class hr_holidays(osv.osv): _name = "hr.holidays" _description = "Leave" _order = "type desc, date_from asc" _inherit = ['mail.thread', 'ir.needaction_mixin'] _track = { 'state': { 'hr_holidays.mt_holidays_approved': lambda self, cr, uid, obj, ctx=None: obj.state == 'validate', 'hr_holidays.mt_holidays_refused': lambda self, cr, uid, obj, ctx=None: obj.state == 'refuse', 'hr_holidays.mt_holidays_confirmed': lambda self, cr, uid, obj, ctx=None: obj.state == 'confirm', }, } def _employee_get(self, cr, uid, context=None): emp_id = context.get('default_employee_id', False) if emp_id: return emp_id ids = self.pool.get('hr.employee').search(cr, uid, [('user_id', '=', uid)], context=context) if ids: return ids[0] return False def _compute_number_of_days(self, cr, uid, ids, name, args, context=None): result = {} for hol in self.browse(cr, uid, ids, context=context): if hol.type=='remove': result[hol.id] = -hol.number_of_days_temp else: result[hol.id] = hol.number_of_days_temp return result def _get_can_reset(self, cr, uid, ids, name, arg, context=None): """User can reset a leave request if it is its own leave request or if he is an Hr Manager. """ user = self.pool['res.users'].browse(cr, uid, uid, context=context) group_hr_manager_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'base', 'group_hr_manager')[1] if group_hr_manager_id in [g.id for g in user.groups_id]: return dict.fromkeys(ids, True) result = dict.fromkeys(ids, False) for holiday in self.browse(cr, uid, ids, context=context): if holiday.employee_id and holiday.employee_id.user_id and holiday.employee_id.user_id.id == uid: result[holiday.id] = True return result def _check_date(self, cr, uid, ids, context=None): for holiday in self.browse(cr, uid, ids, context=context): domain = [ ('date_from', '<=', holiday.date_to), ('date_to', '>=', holiday.date_from), ('employee_id', '=', holiday.employee_id.id), ('id', '!=', holiday.id), ('type', '=', holiday.type), ('state', 'not in', ['cancel', 'refuse']), ] nholidays = self.search_count(cr, uid, domain, context=context) if nholidays: return False return True _check_holidays = lambda self, cr, uid, ids, context=None: self.check_holidays(cr, uid, ids, context=context) _columns = { 'name': fields.char('Description', size=64), 'state': fields.selection([('draft', 'To Submit'), ('cancel', 'Cancelled'),('confirm', 'To Approve'), ('refuse', 'Refused'), ('validate1', 'Second Approval'), ('validate', 'Approved')], 'Status', readonly=True, track_visibility='onchange', copy=False, help='The status is set to \'To Submit\', when a holiday request is created.\ \nThe status is \'To Approve\', when holiday request is confirmed by user.\ \nThe status is \'Refused\', when holiday request is refused by manager.\ \nThe status is \'Approved\', when holiday request is approved by manager.'), 'user_id':fields.related('employee_id', 'user_id', type='many2one', relation='res.users', string='User', store=True), 'date_from': fields.datetime('Start Date', readonly=True, states={'draft':[('readonly',False)], 'confirm':[('readonly',False)]}, select=True, copy=False), 'date_to': fields.datetime('End Date', readonly=True, states={'draft':[('readonly',False)], 'confirm':[('readonly',False)]}, copy=False), 'holiday_status_id': fields.many2one("hr.holidays.status", "Leave Type", required=True,readonly=True, states={'draft':[('readonly',False)], 'confirm':[('readonly',False)]}), 'employee_id': fields.many2one('hr.employee', "Employee", select=True, invisible=False, readonly=True, states={'draft':[('readonly',False)], 'confirm':[('readonly',False)]}), 'manager_id': fields.many2one('hr.employee', 'First Approval', invisible=False, readonly=True, copy=False, help='This area is automatically filled by the user who validate the leave'), 'notes': fields.text('Reasons',readonly=True, states={'draft':[('readonly',False)], 'confirm':[('readonly',False)]}), 'number_of_days_temp': fields.float('Allocation', readonly=True, states={'draft':[('readonly',False)], 'confirm':[('readonly',False)]}, copy=False), 'number_of_days': fields.function(_compute_number_of_days, string='Number of Days', store=True), 'meeting_id': fields.many2one('calendar.event', 'Meeting'), 'type': fields.selection([('remove','Leave Request'),('add','Allocation Request')], 'Request Type', required=True, readonly=True, states={'draft':[('readonly',False)], 'confirm':[('readonly',False)]}, help="Choose 'Leave Request' if someone wants to take an off-day. \nChoose 'Allocation Request' if you want to increase the number of leaves available for someone", select=True), 'parent_id': fields.many2one('hr.holidays', 'Parent'), 'linked_request_ids': fields.one2many('hr.holidays', 'parent_id', 'Linked Requests',), 'department_id':fields.related('employee_id', 'department_id', string='Department', type='many2one', relation='hr.department', readonly=True, store=True), 'category_id': fields.many2one('hr.employee.category', "Employee Tag", help='Category of Employee', readonly=True, states={'draft':[('readonly',False)], 'confirm':[('readonly',False)]}), 'holiday_type': fields.selection([('employee','By Employee'),('category','By Employee Tag')], 'Allocation Mode', readonly=True, states={'draft':[('readonly',False)], 'confirm':[('readonly',False)]}, help='By Employee: Allocation/Request for individual Employee, By Employee Tag: Allocation/Request for group of employees in category', required=True), 'manager_id2': fields.many2one('hr.employee', 'Second Approval', readonly=True, copy=False, help='This area is automaticly filled by the user who validate the leave with second level (If Leave type need second validation)'), 'double_validation': fields.related('holiday_status_id', 'double_validation', type='boolean', relation='hr.holidays.status', string='Apply Double Validation'), 'can_reset': fields.function( _get_can_reset, type='boolean'), } _defaults = { 'employee_id': _employee_get, 'state': 'confirm', 'type': 'remove', 'user_id': lambda obj, cr, uid, context: uid, 'holiday_type': 'employee' } _constraints = [ (_check_date, 'You can not have 2 leaves that overlaps on same day!', ['date_from','date_to']), (_check_holidays, 'The number of remaining leaves is not sufficient for this leave type', ['state','number_of_days_temp']) ] _sql_constraints = [ ('type_value', "CHECK( (holiday_type='employee' AND employee_id IS NOT NULL) or (holiday_type='category' AND category_id IS NOT NULL))", "The employee or employee category of this request is missing. Please make sure that your user login is linked to an employee."), ('date_check2', "CHECK ( (type='add') OR (date_from <= date_to))", "The start date must be anterior to the end date."), ('date_check', "CHECK ( number_of_days_temp >= 0 )", "The number of days must be greater than 0."), ] def _create_resource_leave(self, cr, uid, leaves, context=None): '''This method will create entry in resource calendar leave object at the time of holidays validated ''' obj_res_leave = self.pool.get('resource.calendar.leaves') for leave in leaves: vals = { 'name': leave.name, 'date_from': leave.date_from, 'holiday_id': leave.id, 'date_to': leave.date_to, 'resource_id': leave.employee_id.resource_id.id, 'calendar_id': leave.employee_id.resource_id.calendar_id.id } obj_res_leave.create(cr, uid, vals, context=context) return True def _remove_resource_leave(self, cr, uid, ids, context=None): '''This method will create entry in resource calendar leave object at the time of holidays cancel/removed''' obj_res_leave = self.pool.get('resource.calendar.leaves') leave_ids = obj_res_leave.search(cr, uid, [('holiday_id', 'in', ids)], context=context) return obj_res_leave.unlink(cr, uid, leave_ids, context=context) def onchange_type(self, cr, uid, ids, holiday_type, employee_id=False, context=None): result = {} if holiday_type == 'employee' and not employee_id: ids_employee = self.pool.get('hr.employee').search(cr, uid, [('user_id','=', uid)]) if ids_employee: result['value'] = { 'employee_id': ids_employee[0] } elif holiday_type != 'employee': result['value'] = { 'employee_id': False } return result def onchange_employee(self, cr, uid, ids, employee_id): result = {'value': {'department_id': False}} if employee_id: employee = self.pool.get('hr.employee').browse(cr, uid, employee_id) result['value'] = {'department_id': employee.department_id.id} return result # TODO: can be improved using resource calendar method def _get_number_of_days(self, date_from, date_to): """Returns a float equals to the timedelta between two dates given as string.""" DATETIME_FORMAT = "%Y-%m-%d %H:%M:%S" from_dt = datetime.datetime.strptime(date_from, DATETIME_FORMAT) to_dt = datetime.datetime.strptime(date_to, DATETIME_FORMAT) timedelta = to_dt - from_dt diff_day = timedelta.days + float(timedelta.seconds) / 86400 return diff_day def unlink(self, cr, uid, ids, context=None): for rec in self.browse(cr, uid, ids, context=context): if rec.state not in ['draft', 'cancel', 'confirm']: raise osv.except_osv(_('Warning!'),_('You cannot delete a leave which is in %s state.')%(rec.state)) return super(hr_holidays, self).unlink(cr, uid, ids, context) def onchange_date_from(self, cr, uid, ids, date_to, date_from): """ If there are no date set for date_to, automatically set one 8 hours later than the date_from. Also update the number_of_days. """ # date_to has to be greater than date_from if (date_from and date_to) and (date_from > date_to): raise osv.except_osv(_('Warning!'),_('The start date must be anterior to the end date.')) result = {'value': {}} # No date_to set so far: automatically compute one 8 hours later if date_from and not date_to: date_to_with_delta = datetime.datetime.strptime(date_from, tools.DEFAULT_SERVER_DATETIME_FORMAT) + datetime.timedelta(hours=8) result['value']['date_to'] = str(date_to_with_delta) # Compute and update the number of days if (date_to and date_from) and (date_from <= date_to): diff_day = self._get_number_of_days(date_from, date_to) result['value']['number_of_days_temp'] = round(math.floor(diff_day))+1 else: result['value']['number_of_days_temp'] = 0 return result def onchange_date_to(self, cr, uid, ids, date_to, date_from): """ Update the number_of_days. """ # date_to has to be greater than date_from if (date_from and date_to) and (date_from > date_to): raise osv.except_osv(_('Warning!'),_('The start date must be anterior to the end date.')) result = {'value': {}} # Compute and update the number of days if (date_to and date_from) and (date_from <= date_to): diff_day = self._get_number_of_days(date_from, date_to) result['value']['number_of_days_temp'] = round(math.floor(diff_day))+1 else: result['value']['number_of_days_temp'] = 0 return result def add_follower(self, cr, uid, ids, employee_id, context=None): employee = self.pool['hr.employee'].browse(cr, uid, employee_id, context=context) if employee.user_id: self.message_subscribe(cr, uid, ids, [employee.user_id.partner_id.id], context=context) def create(self, cr, uid, values, context=None): """ Override to avoid automatic logging of creation """ if context is None: context = {} employee_id = values.get('employee_id', False) context = dict(context, mail_create_nolog=True, mail_create_nosubscribe=True) if values.get('state') and values['state'] not in ['draft', 'confirm', 'cancel'] and not self.pool['res.users'].has_group(cr, uid, 'base.group_hr_user'): raise osv.except_osv(_('Warning!'), _('You cannot set a leave request as \'%s\'. Contact a human resource manager.') % values.get('state')) hr_holiday_id = super(hr_holidays, self).create(cr, uid, values, context=context) self.add_follower(cr, uid, [hr_holiday_id], employee_id, context=context) return hr_holiday_id def write(self, cr, uid, ids, vals, context=None): employee_id = vals.get('employee_id', False) if vals.get('state') and vals['state'] not in ['draft', 'confirm', 'cancel'] and not self.pool['res.users'].has_group(cr, uid, 'base.group_hr_user'): raise osv.except_osv(_('Warning!'), _('You cannot set a leave request as \'%s\'. Contact a human resource manager.') % vals.get('state')) hr_holiday_id = super(hr_holidays, self).write(cr, uid, ids, vals, context=context) self.add_follower(cr, uid, ids, employee_id, context=context) return hr_holiday_id def holidays_reset(self, cr, uid, ids, context=None): self.write(cr, uid, ids, { 'state': 'draft', 'manager_id': False, 'manager_id2': False, }) to_unlink = [] for record in self.browse(cr, uid, ids, context=context): for record2 in record.linked_request_ids: self.holidays_reset(cr, uid, [record2.id], context=context) to_unlink.append(record2.id) if to_unlink: self.unlink(cr, uid, to_unlink, context=context) return True def holidays_first_validate(self, cr, uid, ids, context=None): obj_emp = self.pool.get('hr.employee') ids2 = obj_emp.search(cr, uid, [('user_id', '=', uid)]) manager = ids2 and ids2[0] or False self.holidays_first_validate_notificate(cr, uid, ids, context=context) return self.write(cr, uid, ids, {'state':'validate1', 'manager_id': manager}) def holidays_validate(self, cr, uid, ids, context=None): obj_emp = self.pool.get('hr.employee') ids2 = obj_emp.search(cr, uid, [('user_id', '=', uid)]) manager = ids2 and ids2[0] or False self.write(cr, uid, ids, {'state':'validate'}) data_holiday = self.browse(cr, uid, ids) for record in data_holiday: if record.double_validation: self.write(cr, uid, [record.id], {'manager_id2': manager}) else: self.write(cr, uid, [record.id], {'manager_id': manager}) if record.holiday_type == 'employee' and record.type == 'remove': meeting_obj = self.pool.get('calendar.event') meeting_vals = { 'name': record.name or _('Leave Request'), 'categ_ids': record.holiday_status_id.categ_id and [(6,0,[record.holiday_status_id.categ_id.id])] or [], 'duration': record.number_of_days_temp * 8, 'description': record.notes, 'user_id': record.user_id.id, 'start': record.date_from, 'stop': record.date_to, 'allday': False, 'state': 'open', # to block that meeting date in the calendar 'class': 'confidential' } #Add the partner_id (if exist) as an attendee if record.user_id and record.user_id.partner_id: meeting_vals['partner_ids'] = [(4,record.user_id.partner_id.id)] ctx_no_email = dict(context or {}, no_email=True) meeting_id = meeting_obj.create(cr, uid, meeting_vals, context=ctx_no_email) self._create_resource_leave(cr, uid, [record], context=context) self.write(cr, uid, ids, {'meeting_id': meeting_id}) elif record.holiday_type == 'category': emp_ids = obj_emp.search(cr, uid, [('category_ids', 'child_of', [record.category_id.id])]) leave_ids = [] batch_context = dict(context, mail_notify_force_send=False) for emp in obj_emp.browse(cr, uid, emp_ids, context=context): vals = { 'name': record.name, 'type': record.type, 'holiday_type': 'employee', 'holiday_status_id': record.holiday_status_id.id, 'date_from': record.date_from, 'date_to': record.date_to, 'notes': record.notes, 'number_of_days_temp': record.number_of_days_temp, 'parent_id': record.id, 'employee_id': emp.id } leave_ids.append(self.create(cr, uid, vals, context=batch_context)) for leave_id in leave_ids: # TODO is it necessary to interleave the calls? for sig in ('confirm', 'validate', 'second_validate'): self.signal_workflow(cr, uid, [leave_id], sig) return True def holidays_confirm(self, cr, uid, ids, context=None): for record in self.browse(cr, uid, ids, context=context): if record.employee_id and record.employee_id.parent_id and record.employee_id.parent_id.user_id: self.message_subscribe_users(cr, uid, [record.id], user_ids=[record.employee_id.parent_id.user_id.id], context=context) return self.write(cr, uid, ids, {'state': 'confirm'}) def holidays_refuse(self, cr, uid, ids, context=None): obj_emp = self.pool.get('hr.employee') ids2 = obj_emp.search(cr, uid, [('user_id', '=', uid)]) manager = ids2 and ids2[0] or False for holiday in self.browse(cr, uid, ids, context=context): if holiday.state == 'validate1': self.write(cr, uid, [holiday.id], {'state': 'refuse', 'manager_id': manager}) else: self.write(cr, uid, [holiday.id], {'state': 'refuse', 'manager_id2': manager}) self.holidays_cancel(cr, uid, ids, context=context) return True def holidays_cancel(self, cr, uid, ids, context=None): for record in self.browse(cr, uid, ids, context=context): # Delete the meeting if record.meeting_id: record.meeting_id.unlink() # If a category that created several holidays, cancel all related self.signal_workflow(cr, uid, map(attrgetter('id'), record.linked_request_ids or []), 'refuse') self._remove_resource_leave(cr, uid, ids, context=context) return True def check_holidays(self, cr, uid, ids, context=None): for record in self.browse(cr, uid, ids, context=context): if record.holiday_type != 'employee' or record.type != 'remove' or not record.employee_id or record.holiday_status_id.limit: continue leave_days = self.pool.get('hr.holidays.status').get_days(cr, uid, [record.holiday_status_id.id], record.employee_id.id, context=context)[record.holiday_status_id.id] if float_compare(leave_days['remaining_leaves'], 0, precision_digits=2) == -1 or \ float_compare(leave_days['virtual_remaining_leaves'], 0, precision_digits=2) == -1: # Raising a warning gives a more user-friendly feedback than the default constraint error raise Warning(_('The number of remaining leaves is not sufficient for this leave type.\n' 'Please verify also the leaves waiting for validation.')) return True # ----------------------------- # OpenChatter and notifications # ----------------------------- def _needaction_domain_get(self, cr, uid, context=None): emp_obj = self.pool.get('hr.employee') empids = emp_obj.search(cr, uid, [('parent_id.user_id', '=', uid)], context=context) dom = ['&', ('state', '=', 'confirm'), ('employee_id', 'in', empids)] # if this user is a hr.manager, he should do second validations if self.pool.get('res.users').has_group(cr, uid, 'base.group_hr_manager'): dom = ['|'] + dom + [('state', '=', 'validate1')] return dom def holidays_first_validate_notificate(self, cr, uid, ids, context=None): for obj in self.browse(cr, uid, ids, context=context): self.message_post(cr, uid, [obj.id], _("Request approved, waiting second validation."), context=context)
class desing_laboratory(osv.Model): _name = 'desing.laboratory' def _get_date_new(self, cr, uid, ids, field, arg, context=None): res = {} for row in self.browse(cr, uid, ids, context=context): if row.state == 'out_time': if row.return_date2: self.write(cr, uid, row.id, {'state': 'process'}) return res _columns = { 'name': fields.char("Nombre"), 'service': fields.many2one('services.laboratory', 'Servicio'), 'app': fields.many2one('app.laboratory', 'Aplicación'), 'company_id': fields.many2one('companies.ihce', 'Beneficiario'), 'id_project': fields.many2one('laboratory.ihce', "ID de Proyecto"), 'date': fields.datetime("Fecha de inicio"), 'date_fin': fields.datetime("Fecha de termino"), 'date_next': fields.datetime("Fecha de próxima cita"), 'percent': fields.integer("Porcentaje de avance"), 'notes': fields.text("Observación General"), 'state': fields.selection([ ('draft', 'Nuevo'), ('process', 'Proceso'), ('out_time', 'Fuera de tiempo'), ('pre_done', 'Para Terminar'), ('done', 'Terminado'), ('detained', 'Abandonado'), ], 'Estado', select=True), 'servicio': fields.integer("Servicio"), 'asesoria': fields.integer("Asesoría"), 'crm_id': fields.many2one('crm.project.ihce', "Proyecto crm"), 'task_id': fields.integer("Tarea crm"), 'user_id': fields.many2one( 'res.users', "Responsable", help="Es el usuario al que se le contarán los indicadores."), 'binnacle_lines': fields.one2many('binnacle.laboratory', 'service', 'Bitácora de trabajo'), 'cron_id': fields.many2one('ir.cron', "Tarea en proceso"), 'return_date': fields.function(_get_date_new, type='boolean', string="Fecha cambiada"), 'return_date2': fields.boolean("Fecha cambiada"), 'option_service': fields.selection([('0', 'Servicio'), ('1', 'Aplicación')], 'Opción'), 'option': fields.selection([('ihce', 'IHCE'), ('emprered', 'Emprered')], 'Oficina'), 'area': fields.many2one('responsible.area', "Departamento"), 'emprered': fields.many2one('emprereds', 'Emprered'), 'sector': fields.many2one('sector.actividad.economica', "Sector", help="Sector económico"), } _defaults = { 'state': 'draft', 'percent': 0, 'return_date2': False, 'user_id': lambda obj, cr, uid, context: uid, 'option': lambda self, cr, uid, obj, ctx=None: self.pool['res.users'].browse( cr, uid, uid).option, 'area': lambda self, cr, uid, obj, ctx=None: self.pool['res.users'].browse( cr, uid, uid).area.id, 'emprered': lambda self, cr, uid, obj, ctx=None: self.pool['res.users'].browse( cr, uid, uid).emprered.id, } _order = "date_next asc" def create(self, cr, uid, vals, context=None): name = '' # Generamos id consecutivo, verificamos que el beneficiario no tenga id aún row = self.pool.get('companies.ihce').browse(cr, uid, vals.get('company_id'), context=context) new_seq = "" if not row.id_project_laboratory: new_seq = self.pool.get('ir.sequence').get(cr, uid, 'sector.laboratorio') #~ Guardamos el numero de proyecto al beneficiario id_project = self.pool.get('laboratory.ihce').create( cr, uid, { 'name': new_seq, 'company_id': vals.get('company_id'), 'user_id': vals.get('user_id'), 'sector': row.sector.id }) self.pool.get('companies.ihce').write( cr, uid, row.id, {'id_project_laboratory': id_project}) vals.update({'id_project': id_project}) else: vals.update({'id_project': row.id_project_laboratory.id}) self.pool.get('laboratory.ihce').write(cr, uid, vals.get('id_project'), {'state': 'process'}) if vals.get('option_service') == '0': servi = self.pool.get('services.laboratory').browse( cr, uid, vals.get('service'), context=context) name = servi.name else: if vals.get('option_service') == '1': app = self.pool.get('app.laboratory').browse(cr, uid, vals.get('app'), context=context) name = app.name vals.update({'name': name, 'sector': row.sector.id}) return super(desing_laboratory, self).create(cr, uid, vals, context) def write(self, cr, uid, ids, vals, context=None): return super(desing_laboratory, self).write(cr, uid, ids, vals, context=context) def _check_laboratory(self, cr, uid, ids, context=None): row = self.browse(cr, uid, ids[0], context=context) fecha_ejecucion = datetime.now() if row.date_next: fecha_compromiso = datetime.strptime(row.date_next, "%Y-%m-%d %H:%M:%S") if row.state == 'process': if row.date_next: if fecha_compromiso < fecha_ejecucion: self.write(cr, uid, ids[0], { 'state': 'out_time', 'return_date2': False }, context=context) #~ Apartir del momento en que se encuentra fuera de tiempo, tiene 10 días para reagendar o para que se presente el beneficiario, pasado este tiempo el servicio se pondrá en estado detenido. fecha_detenido = fecha_ejecucion + timedelta(days=14) #~ Linea de historial del beneficiario self.pool.get('crm.ihce').create( cr, uid, { 'company_id': row.company_id.id, 'date': fecha_ejecucion, 'name': 'El servicio de ' + str(row.service.name.encode('utf-8')) + " del laboratorio de diseño se encuentra fuera de tiempo. No se realizó cita en la fecha establecida.", 'user': uid, 'date_compromise': fecha_ejecucion, 'state': 'done' }, context=context) #~ self.pool.get('crm.project.ihce').write(cr, uid, [row.crm_id.id], {'state': 'c-out_time'}) #~ Enviar correo que el tiempo de la tarea se terminó titulo = "Aviso CRM" texto = "<p>El tiempo para el servicio " + str( row.service.name.encode('utf-8') ) + " del beneficiario " + str( row.company_id.name.encode('utf-8') ) + " con número " + str( row.id_project ) + " está fuera de tiempo. Requerie se agende nueva fecha para cita.</p> " self.pool.get('mail.ihce').send_mail_user( cr, uid, ids, titulo, texto, row.user_id.id, context=context) if row.state == 'out_time': if fecha_detenido == fecha_ejecucion: self.write(cr, uid, ids[0], {'state': 'detained'}, context=context) #~ Linea de historial del beneficiario self.pool.get('crm.ihce').create( cr, uid, { 'company_id': row.company_id.id, 'date': fecha_ejecucion, 'name': 'El servicio de ' + str(row.service.name.encode('utf-8')) + " del laboratorio de diseño se encuentra detenido. No se realizó cita en la fecha establecida.", 'user': uid, 'date_compromise': fecha_ejecucion, 'state': 'done' }, context=context) #~ self.pool.get('crm.project.ihce').write(cr, uid, [row.crm_id.id], {'state': 'e-abandoned'}) #~ Enviar correo que el tiempo de la tarea se terminó, el servicio pasa a detenido titulo = "Aviso CRM" texto = "<p>El tiempo para el servicio " + str( row.name.encode('utf-8') ) + " del beneficiario " + row.company_id.name.encode( 'utf-8' ) + " con número " + row.id_project + " está fuera de tiempo. El servicio pasa a estado DETENIDO, ya que se le dieron 10 días de plazo después de la última cita.</p> " self.pool.get('mail.ihce').send_mail_user(cr, uid, ids, titulo, texto, row.user_id.id, context=context) return True def start_process(self, cr, uid, ids, context=None): row = self.browse(cr, uid, ids[0], context=context) fecha_actual = datetime.now() res = { 'name': 'Process : ' + row.id_project.name, 'model': 'desing.laboratory', 'args': repr([ids]), 'function': '_check_laboratory', 'priority': 5, 'interval_number': 1, 'interval_type': 'hours', 'user_id': uid, 'numbercall': -1, 'doall': False, 'active': True } id_cron = self.pool.get('ir.cron').create(cr, uid, res) if row.option_service == '0': servi = row.service.name.encode('utf-8') else: servi = row.app.name.encode('utf-8') #~ Linea de historial del beneficiario self.pool.get('crm.ihce').create( cr, uid, { 'company_id': row.company_id.id, 'date': fecha_actual, 'name': 'Se ha iniciado el servicio de ' + str(servi) + " del laboratorio de diseño.", 'user': uid, 'date_compromise': fecha_actual, 'state': 'done' }, context=context) #~ Al aprobarse el registro se crea un proyecto en el crm del usuario. valores = { 'name': servi + " " + str(row.id_project.name), 'company_id': row.company_id.id, 'state': 'a-draft', 'type_crm': 'automatico', } crm_id = self.pool.get('crm.project.ihce').create(cr, uid, valores, context=context) self.pool.get('crm.project.ihce').comenzar(cr, uid, [crm_id], context=context) self.write(cr, uid, ids[0], { 'cron_id': id_cron, 'state': 'process', 'date': fecha_actual, 'crm_id': crm_id }, context=context) #~ self.message_post(cr, uid, [row.id], body=_("Servicio Iniciado"), context=context) def onchange_date_next(self, cr, uid, ids, fecha, context=None): result = {} result['value'] = {} fecha_actual = datetime.now() if fecha: fecha_next = datetime.strptime(fecha, "%Y-%m-%d %H:%M:%S") #~ if fecha_next < fecha_actual: #~ raise osv.except_osv(_('Advertencia!'), _('La fecha de la próxima cita debe ser posterior al día de hoy!')) #~ return False #~ else: result['value'].update({'date_next': fecha, 'return_date2': True}) #~ self.message_post(cr, uid, ids, body=_("Cita Reprogramada"), context=context) return result def detained_process(self, cr, uid, ids, context=None): fecha_actual = datetime.now() row = self.browse(cr, uid, ids[0], context=context) self.write(cr, uid, ids[0], {'state': 'detained'}, context=context) self.pool.get('crm.project.ihce').write(cr, uid, [row.crm_id.id], {'state': 'e-abandoned'}) #~ Linea de historial del beneficiario if row.option_service == '0': servi = row.service.name.encode('utf-8') else: servi = row.app.name.encode('utf-8') self.pool.get('crm.ihce').create( cr, uid, { 'company_id': row.company_id.id, 'date': fecha_actual, 'name': 'El servicio de ' + str(servi) + " del laboratorio de diseño ha sido detenido/abandonado.", 'user': uid, 'date_compromise': fecha_actual, 'state': 'done' }, context=context) #~ self.message_post(cr, uid, [row.id], body=_("Servicio Detenido"), context=context) return True def action_detained_wizard(self, cr, uid, ids, context=None): """ Método para crear el wizard y seleccionar el motivo de la cancelación """ # Wizard para cancelar el proyecto cancel_project_id = self.pool.get("detained.services").create( cr, uid, {'service_id': ids[0]}, context=context) res = { 'name': ("Abandonar Servicio"), 'view_mode': 'form', 'view_id': False, 'view_type': 'form', 'res_model': 'detained.services', 'res_id': cancel_project_id, 'type': 'ir.actions.act_window', 'nodestroy': True, 'target': 'new', 'domain': '[]', 'context': context, } return res def refresh_process(self, cr, uid, ids, context=None): fecha_actual = datetime.now() row = self.browse(cr, uid, ids[0], context=context) self.write(cr, uid, ids[0], { 'state': 'process', 'return_date2': False }, context=context) self.pool.get('crm.project.ihce').write(cr, uid, [row.crm_id.id], {'state': 'b-progress'}) #~ Linea de historial del beneficiario if row.option_service == '0': servi = row.service.name.encode('utf-8') else: servi = row.app.name.encode('utf-8') self.pool.get('crm.ihce').create( cr, uid, { 'company_id': row.company_id.id, 'date': fecha_actual, 'name': 'El servicio de ' + str(servi) + " del laboratorio de diseño ha sido reabierto.", 'user': uid, 'date_compromise': fecha_actual, 'state': 'done' }, context=context) #~ self.message_post(cr, uid, [row.id], body=_("Servicio Reabierto"), context=context) return True def done_process(self, cr, uid, ids, context=None): fecha_actual = datetime.now() row = self.browse(cr, uid, ids[0], context=context) self.write(cr, uid, ids[0], {'state': 'done'}, context=context) self.pool.get('crm.project.ihce').write(cr, SUPERUSER_ID, [row.crm_id.id], {'state': 'd-done'}) #~ Linea de historial del beneficiario if row.option_service == '0': servi = row.service.name.encode('utf-8') else: servi = row.app.name.encode('utf-8') self.pool.get('crm.ihce').create( cr, uid, { 'company_id': row.company_id.id, 'date': fecha_actual, 'name': 'El servicio de ' + str(servi) + " del laboratorio de diseño ha sido concluido.", 'user': uid, 'date_compromise': fecha_actual, 'state': 'done' }, context=context) #~ self.message_post(cr, uid, [row.id], body=_("Servicio Terminado"), context=context) return True def onchange_company(self, cr, uid, ids, company, user, service, app, context=None): result = {} result['value'] = {} if user: us = self.pool.get('res.users').browse(cr, uid, user) if company: if service: services_ids = self.search(cr, uid, [('company_id', '=', company), ('service', '=', service)]) if services_ids: raise osv.except_osv( _('Advertencia!'), _('Ya existe un servicio para la empresa seleccionada, que ha creado el usuario ' + str(us.name.encode('utf-8')) + '. Por favor verifique si es necesario crear otro!')) if app: app_ids = self.search(cr, uid, [('company_id', '=', company), ('app', '=', app)]) if app_ids: raise osv.except_osv( _('Advertencia!'), _('Ya existe una aplicación para la empresa seleccionada, que ha creado el usuario ' + str(us.name.encode('utf-8')) + '. Por favor verifique si es necesario crear otra!') ) return result def unlink(self, cr, uid, ids, context=None): data = self.read(cr, uid, ids, ['state'], context=context) unlink_ids = [] for row in data: if row['state'] in ['draft']: unlink_ids.append(row['id']) else: raise osv.except_osv( _('Acción Invalida!'), _('No puede eliminar el servicio/aplicación.!')) return super(desing_laboratory, self).unlink(cr, uid, unlink_ids, context=context) def onchange_user(self, cr, uid, ids, user_id, context=None): result = {} result['value'] = {} if user_id: row = self.pool.get('res.users').browse(cr, uid, user_id) result['value'].update({ 'option': row.option, 'area': row.area.id, 'emprered': row.emprered.id }) return result
class user_story_phase(osv.Model): _name = "user.story.phase" _description = "User Story Phase" def _check_recursion(self, cr, uid, ids, context=None): if context is None: context = {} data_phase = self.browse(cr, uid, ids[0], context=context) prev_ids = data_phase.previous_phase_ids next_ids = data_phase.next_phase_ids # it should neither be in prev_ids nor in next_ids if (data_phase in prev_ids) or (data_phase in next_ids): return False ids = [id for id in prev_ids if id in next_ids] # both prev_ids and next_ids must be unique if ids: return False # unrelated user_story prev_ids = [rec.id for rec in prev_ids] next_ids = [rec.id for rec in next_ids] # iter prev_ids while prev_ids: cr.execute( 'SELECT distinct prv_phase_id FROM user_story_phase_rel WHERE next_phase_id IN %s', (tuple(prev_ids), )) prv_phase_ids = filter(None, map(lambda x: x[0], cr.fetchall())) if data_phase.id in prv_phase_ids: return False ids = [id for id in prv_phase_ids if id in next_ids] if ids: return False prev_ids = prv_phase_ids # iter next_ids while next_ids: cr.execute( 'SELECT distinct next_phase_id FROM user_story_phase_rel WHERE prv_phase_id IN %s', (tuple(next_ids), )) next_phase_ids = filter(None, map(lambda x: x[0], cr.fetchall())) if data_phase.id in next_phase_ids: return False ids = [id for id in next_phase_ids if id in prev_ids] if ids: return False next_ids = next_phase_ids return True def _check_dates(self, cr, uid, ids, context=None): for phase in self.read(cr, uid, ids, ['date_start', 'date_end'], context=context): if phase['date_start'] and phase[ 'date_end'] and phase['date_start'] > phase['date_end']: return False return True # # def _compute_progress(self, cr, uid, ids, field_name, arg, context=None): # res = {} # if not ids: # return res # for phase in self.browse(cr, uid, ids, context=context): # if phase.state=='done': # res[phase.id] = 100.0 # continue # elif phase.state=="cancelled": # res[phase.id] = 0.0 # continue # elif not phase.task_ids: # res[phase.id] = 0.0 # continue # # tot = done = 0.0 # for task in phase.task_ids: # tot += task.total_hours # done += min(task.effective_hours, task.total_hours) # # if not tot: # res[phase.id] = 0.0 # else: # res[phase.id] = round(100.0 * done / tot, 2) # return res _columns = { 'name': fields.char("Name", size=64, required=True), 'user_story_id': fields.many2one('user.story', 'User Story', required=True, select=True), 'state': fields.selection( [('draft', 'New'), ('cancelled', 'Cancelled'), ('open', 'In Progress'), ('pending', 'Pending'), ('done', 'Done')], 'Status', readonly=True, required=True, help= 'If the phase is created the status \'Draft\'.\n If the phase is started, the status becomes \'In Progress\'.\n If review is needed the phase is in \'Pending\' status.\ \n If the phase is over, the status is set to \'Done\'.' ), 'date_start': fields.datetime( 'Start Date', select=True, help= "It's computed by the scheduler according the project date or the end date of the previous phase.", states={ 'done': [('readonly', True)], 'cancelled': [('readonly', True)] }), 'date_end': fields.datetime( 'End Date', help= " It's computed by the scheduler according to the start date and the duration.", states={ 'done': [('readonly', True)], 'cancelled': [('readonly', True)] }), 'sequence': fields.integer( 'Sequence', select=True, help="Gives the sequence order when displaying a list of phases."), 'duration': fields.float('Duration', required=True, help="By default in days", states={ 'done': [('readonly', True)], 'cancelled': [('readonly', True)] }), 'next_phase_ids': fields.many2many('user.story.phase', 'user_story_phase_rel', 'prv_phase_id', 'next_phase_id', 'Next Phases', states={'cancelled': [('readonly', True)]}), 'previous_phase_ids': fields.many2many('user.story.phase', 'user_story_phase_rel', 'next_phase_id', 'prv_phase_id', 'Previous Phases', states={'cancelled': [('readonly', True)]}), 'product_uom': fields.many2one( 'product.uom', 'Duration Unit of Measure', required=True, help= "Unit of Measure (Unit of Measure) is the unit of measurement for Duration", states={ 'done': [('readonly', True)], 'cancelled': [('readonly', True)] }), 'constraint_date_start': fields.datetime('Minimum Start Date', help='force the phase to start after this date', states={ 'done': [('readonly', True)], 'cancelled': [('readonly', True)] }), 'constraint_date_end': fields.datetime('Deadline', help='force the phase to finish before this date', states={ 'done': [('readonly', True)], 'cancelled': [('readonly', True)] }), 'user_force_ids': fields.many2many('res.users', string='Force Assigned Users'), 'user_ids': fields.one2many( 'user.story.user.allocation', 'phase_id', "Assigned Users", states={ 'done': [('readonly', True) ], 'cancelled': [('readonly', True)] }, help= "The resources on the project can be computed automatically by the scheduler." ), } # 'task_ids': fields.one2many('project.task', 'phase_id', "Project Tasks", states={'done':[('readonly',True)], 'cancelled':[('readonly',True)]}), # 'progress': fields.function(_compute_progress, string='Progress', help="Computed based on related tasks"), _defaults = { 'state': 'draft', 'sequence': 10, } _order = "user_story_id, date_start, sequence" _constraints = [ (_check_recursion, 'Loops in phases not allowed', ['next_phase_ids', 'previous_phase_ids']), (_check_dates, 'Phase start-date must be lower than phase end-date.', ['date_start', 'date_end']), ] def onchange_user_story(self, cr, uid, ids, user_story, context=None): return {} def copy(self, cr, uid, id, default=None, context=None): if default is None: default = {} if not default.get('name', False): default.update(name=_('%s (copy)') % (self.browse(cr, uid, id, context=context).name)) return super(user_story_phase, self).copy(cr, uid, id, default, context) def set_draft(self, cr, uid, ids, *args): self.write(cr, uid, ids, {'state': 'draft'}) return True def set_open(self, cr, uid, ids, *args): self.write(cr, uid, ids, {'state': 'open'}) return True def set_pending(self, cr, uid, ids, *args): self.write(cr, uid, ids, {'state': 'pending'}) return True def set_cancel(self, cr, uid, ids, *args): self.write(cr, uid, ids, {'state': 'cancelled'}) return True def set_done(self, cr, uid, ids, *args): self.write(cr, uid, ids, {'state': 'done'}) return True
class binnacle_laboratory(osv.Model): _name = 'binnacle.laboratory' _columns = { 'name': fields.char("Actividad", size=200), 'id_project': fields.many2one('laboratory.ihce', "ID de Proyecto"), 'service': fields.many2one('desing.laboratory', 'Servicio'), 'date': fields.datetime("Fecha"), 'date_next': fields.datetime("Próxima cita"), 'notes': fields.text("Comentarios/Acuerdos"), 'user_id': fields.many2one( 'res.users', "Responsable", help="Es el usuario al que se le contarán los indicadores."), 'percent': fields.integer("Porcentaje de avance"), 'state': fields.selection([ ('draft', 'Nuevo'), ('done', 'Terminado'), ], 'Estado'), } _defaults = { 'user_id': lambda obj, cr, uid, context: uid, 'date': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'), 'state': 'draft', } def create(self, cr, uid, vals, context=None): fecha_actual = datetime.now() row = self.pool.get('desing.laboratory').browse( cr, uid, vals.get('service')) vals.update({'id_project': row.id_project.id}) if vals.get('percent') >= 0 and vals.get('percent') <= 100: #~ Creamos la tarea en el crm notas = vals.get('notes') if notas: notas = notas.encode('utf-8') else: notas = "" if vals.get('percent') == 100: if row.task_id != 0: self.pool.get('crm.task').terminar(cr, SUPERUSER_ID, [row.task_id], context=context) self.pool.get('desing.laboratory').write( cr, uid, vals.get('service'), { 'percent': vals.get('percent'), 'date_next': False, 'state': 'pre_done', 'date_fin': fecha_actual }) else: if row.task_id != 0: self.pool.get('crm.task').terminar(cr, SUPERUSER_ID, [row.task_id], context=context) datos = { 'name': vals.get('name').encode('utf-8'), 'date_compromise': vals.get('date_next'), 'user_id': uid, 'crm_id': row.crm_id.id, 'notes': notas, 'type_task': 'automatico', } task_id = self.pool.get('crm.task').create(cr, SUPERUSER_ID, datos, context=context) self.pool.get('desing.laboratory').write( cr, uid, vals.get('service'), { 'percent': vals.get('percent'), 'date_next': vals.get('date_next'), 'task_id': task_id, 'state': 'process' }) vals.update({'state': 'done'}) #~ Linea de historial del beneficiario self.pool.get('crm.ihce').create( cr, uid, { 'company_id': row.company_id.id, 'date': fecha_actual, 'name': str(vals.get('name').encode('utf-8')) + " para el servicio de " + str(row.name.encode('utf-8')) + " del laboratorio de diseño. " + notas, 'user': uid, 'date_compromise': fecha_actual, 'state': 'done' }, context=context) else: raise osv.except_osv( _('Advertencia!'), _('El porcentaje ingresado no se encuentra dentro del rango correcto.!' )) return False return super(binnacle_laboratory, self).create(cr, uid, vals, context)
class payment_line(osv.osv): _name = 'payment.line' _description = 'Payment Line' def translate(self, orig): return { "due_date": "date_maturity", "reference": "ref" }.get(orig, orig) def _info_owner(self, cr, uid, ids, name=None, args=None, context=None): result = {} for line in self.browse(cr, uid, ids, context=context): owner = line.order_id.mode.bank_id.partner_id result[line.id] = self._get_info_partner(cr, uid, owner, context=context) return result def _get_info_partner(self, cr, uid, partner_record, context=None): if not partner_record: return False st = partner_record.street or '' st1 = partner_record.street2 or '' zip = partner_record.zip or '' city = partner_record.city or '' zip_city = zip + ' ' + city cntry = partner_record.country_id and partner_record.country_id.name or '' return partner_record.name + "\n" + st + " " + st1 + "\n" + zip_city + "\n" + cntry def _info_partner(self, cr, uid, ids, name=None, args=None, context=None): result = {} for line in self.browse(cr, uid, ids, context=context): result[line.id] = False if not line.partner_id: break result[line.id] = self._get_info_partner(cr, uid, line.partner_id, context=context) return result #dead code def select_by_name(self, cr, uid, ids, name, args, context=None): if not ids: return {} partner_obj = self.pool.get('res.partner') cr.execute( """SELECT pl.id, ml.%s FROM account_move_line ml INNER JOIN payment_line pl ON (ml.id = pl.move_line_id) WHERE pl.id IN %%s""" % self.translate(name), (tuple(ids), )) res = dict(cr.fetchall()) if name == 'partner_id': partner_name = {} for p_id, p_name in partner_obj.name_get( cr, uid, filter(lambda x: x and x != 0, res.values()), context=context): partner_name[p_id] = p_name for id in ids: if id in res and partner_name: res[id] = (res[id], partner_name[res[id]]) else: res[id] = (False, False) else: for id in ids: res.setdefault(id, (False, "")) return res def _amount(self, cursor, user, ids, name, args, context=None): if not ids: return {} currency_obj = self.pool.get('res.currency') if context is None: context = {} res = {} for line in self.browse(cursor, user, ids, context=context): ctx = context.copy() ctx['date'] = line.order_id.date_done or time.strftime('%Y-%m-%d') res[line.id] = currency_obj.compute(cursor, user, line.currency.id, line.company_currency.id, line.amount_currency, context=ctx) return res def _get_currency(self, cr, uid, context=None): user_obj = self.pool.get('res.users') currency_obj = self.pool.get('res.currency') user = user_obj.browse(cr, uid, uid, context=context) if user.company_id: return user.company_id.currency_id.id else: return currency_obj.search(cr, uid, [('rate', '=', 1.0)])[0] def _get_date(self, cr, uid, context=None): if context is None: context = {} payment_order_obj = self.pool.get('payment.order') date = False if context.get('order_id') and context['order_id']: order = payment_order_obj.browse(cr, uid, context['order_id'], context=context) if order.date_prefered == 'fixed': date = order.date_scheduled else: date = time.strftime('%Y-%m-%d') return date def _get_ml_inv_ref(self, cr, uid, ids, *a): res = {} for id in self.browse(cr, uid, ids): res[id.id] = False if id.move_line_id: if id.move_line_id.invoice: res[id.id] = id.move_line_id.invoice.id return res def _get_ml_maturity_date(self, cr, uid, ids, *a): res = {} for id in self.browse(cr, uid, ids): if id.move_line_id: res[id.id] = id.move_line_id.date_maturity else: res[id.id] = False return res def _get_ml_created_date(self, cr, uid, ids, *a): res = {} for id in self.browse(cr, uid, ids): if id.move_line_id: res[id.id] = id.move_line_id.date_created else: res[id.id] = False return res _columns = { 'name': fields.char('Your Reference', required=True), 'communication': fields.char( 'Communication', required=True, help= "Used as the message between ordering customer and current company. Depicts 'What do you want to say to the recipient about this order ?'" ), 'communication2': fields.char('Communication 2', help='The successor message of Communication.'), 'move_line_id': fields.many2one( 'account.move.line', 'Entry line', domain=[('reconcile_id', '=', False), ('account_id.type', '=', 'payable')], select=True, help= 'This Entry Line will be referred for the information of the ordering customer.' ), 'amount_currency': fields.float('Amount in Partner Currency', digits=(16, 2), required=True, help='Payment amount in the partner currency'), 'currency': fields.many2one('res.currency', 'Partner Currency', required=True), 'company_currency': fields.many2one('res.currency', 'Company Currency', readonly=True), 'bank_id': fields.many2one('res.partner.bank', 'Destination Bank Account'), 'order_id': fields.many2one('payment.order', 'Order', required=True, ondelete='cascade', select=True), 'partner_id': fields.many2one('res.partner', string="Partner", required=True, help='The Ordering Customer'), 'amount': fields.function(_amount, string='Amount in Company Currency', type='float', help='Payment amount in the company currency'), 'ml_date_created': fields.function(_get_ml_created_date, string="Effective Date", type='date', help="Invoice Effective Date"), 'ml_maturity_date': fields.function(_get_ml_maturity_date, type='date', string='Due Date'), 'ml_inv_ref': fields.function(_get_ml_inv_ref, type='many2one', relation='account.invoice', string='Invoice Ref.'), 'info_owner': fields.function(_info_owner, string="Owner Account", type="text", help='Address of the Main Partner'), 'info_partner': fields.function(_info_partner, string="Destination Account", type="text", help='Address of the Ordering Customer.'), 'date': fields.date( 'Payment Date', help= "If no payment date is specified, the bank will treat this payment line directly" ), 'create_date': fields.datetime('Created', readonly=True), 'state': fields.selection([('normal', 'Free'), ('structured', 'Structured')], 'Communication Type', required=True), 'bank_statement_line_id': fields.many2one('account.bank.statement.line', 'Bank statement line'), 'company_id': fields.related('order_id', 'company_id', type='many2one', relation='res.company', string='Company', store=True, readonly=True), } _defaults = { 'name': lambda obj, cursor, user, context: obj.pool.get('ir.sequence').get( cursor, user, 'payment.line'), 'state': 'normal', 'currency': _get_currency, 'company_currency': _get_currency, 'date': _get_date, } _sql_constraints = [ ('name_uniq', 'UNIQUE(name, company_id)', 'The payment line name must be unique per company!'), ] def onchange_move_line(self, cr, uid, ids, move_line_id, payment_type, date_prefered, date_scheduled, currency=False, company_currency=False, context=None): data = {} move_line_obj = self.pool.get('account.move.line') data['amount_currency'] = data['communication'] = data[ 'partner_id'] = data['bank_id'] = data['amount'] = False if move_line_id: line = move_line_obj.browse(cr, uid, move_line_id, context=context) data['amount_currency'] = line.amount_residual_currency res = self.onchange_amount(cr, uid, ids, data['amount_currency'], currency, company_currency, context) if res: data['amount'] = res['value']['amount'] data['partner_id'] = line.partner_id.id temp = line.currency_id and line.currency_id.id or False if not temp: if line.invoice: data['currency'] = line.invoice.currency_id.id else: data['currency'] = temp # calling onchange of partner and updating data dictionary temp_dict = self.onchange_partner(cr, uid, ids, line.partner_id.id, payment_type) data.update(temp_dict['value']) data['communication'] = line.ref if date_prefered == 'now': #no payment date => immediate payment data['date'] = False elif date_prefered == 'due': data['date'] = line.date_maturity elif date_prefered == 'fixed': data['date'] = date_scheduled return {'value': data} def onchange_amount(self, cr, uid, ids, amount, currency, cmpny_currency, context=None): if (not amount) or (not cmpny_currency): return {'value': {'amount': False}} res = {} currency_obj = self.pool.get('res.currency') company_amount = currency_obj.compute(cr, uid, currency, cmpny_currency, amount) res['amount'] = company_amount return {'value': res} def onchange_partner(self, cr, uid, ids, partner_id, payment_type, context=None): data = {} partner_obj = self.pool.get('res.partner') payment_mode_obj = self.pool.get('payment.mode') data['info_partner'] = data['bank_id'] = False if partner_id: part_obj = partner_obj.browse(cr, uid, partner_id, context=context) partner = part_obj.name or '' data['info_partner'] = self._get_info_partner(cr, uid, part_obj, context=context) if part_obj.bank_ids and payment_type: bank_type = payment_mode_obj.suitable_bank_types( cr, uid, payment_type, context=context) for bank in part_obj.bank_ids: if bank.state in bank_type: data['bank_id'] = bank.id break return {'value': data} def fields_get(self, cr, uid, fields=None, context=None, write_access=True, attributes=None): res = super(payment_line, self).fields_get(cr, uid, fields, context, write_access, attributes) if 'communication2' in res: res['communication2'].setdefault('states', {}) res['communication2']['states']['structured'] = [('readonly', True) ] res['communication2']['states']['normal'] = [('readonly', False)] return res
class wizard(osv.TransientModel): """ A wizard to manage the modification of protocol object """ _name = 'protocollo.fascicola.wizard' _description = 'Fascicola Protocollo' def set_before(self, before, label, value): if not value: value = '' before += value + '\n' return before def set_after(self, after, label, value): after += value + '\n' return after _columns = { 'complete_name': fields.char('Numero Protocollo', size=256, required=True, readonly=True), 'registration_date': fields.datetime('Data Registrazione', readonly=True), 'type': fields.selection([('out', 'Uscita'), ('in', 'Ingresso'), ('internal', 'Interno')], 'Tipo', size=32, required=True, readonly=True), 'cause': fields.text('Motivo della Modifica', required=True), 'dossier_ids': fields.many2many('protocollo.dossier', 'protocollo_fascicola_wizard_dossier_rel', 'wizard_id', 'dossier_id', 'Fascicoli'), } def _default_complete_name(self, cr, uid, context): protocollo = self.pool.get('protocollo.protocollo').browse( cr, uid, context['active_id']) return protocollo.complete_name def _default_registration_date(self, cr, uid, context): protocollo = self.pool.get('protocollo.protocollo').browse( cr, uid, context['active_id']) return protocollo.registration_date def _default_type(self, cr, uid, context): protocollo = self.pool.get('protocollo.protocollo').browse( cr, uid, context['active_id']) return protocollo.type def _default_dossier_ids(self, cr, uid, context): protocollo = self.pool.get('protocollo.protocollo').browse( cr, uid, context['active_id']) dossier_ids = [] for dossier_id in protocollo.dossier_ids: dossier_ids.append(dossier_id.id) return [(6, 0, dossier_ids)] _defaults = { 'complete_name': _default_complete_name, 'registration_date': _default_registration_date, 'type': _default_type, 'dossier_ids': _default_dossier_ids, } def action_save(self, cr, uid, ids, context=None): vals = {} before = {} after = {} wizard = self.browse(cr, uid, ids[0], context) protocollo_obj = self.pool.get('protocollo.protocollo') protocollo = protocollo_obj.browse(cr, uid, context['active_id'], context=context) before['Fascicolo'] = "" after['Fascicolo'] = "" vals['dossier_ids'] = [[6, 0, [d.id for d in wizard.dossier_ids]]] before['Fascicolo'] = self.set_before( before['Fascicolo'], 'Fascicolo', ', '.join([d.name for d in protocollo.dossier_ids])) after['Fascicolo'] = self.set_after( after['Fascicolo'], 'Fascicolo', ', '.join([dw.name for dw in wizard.dossier_ids])) protocollo_obj.write(cr, uid, [context['active_id']], vals) action_class = "history_icon update" body = "<div class='%s'><ul>" % action_class for key, before_item in before.items(): if before[key] != after[key]: body = body + "<li>%s: <span style='color:#990000'> %s</span> -> <span style='color:#009900'> %s </span></li>" \ % (str(key), before_item.encode("utf-8"), after[key].encode("utf-8")) else: body = body + "<li>%s: <span style='color:#999'> %s</span> -> <span style='color:#999'> %s </span></li>" \ % (str(key), before_item.encode("utf-8"), after[key].encode("utf-8")) post_vars = { 'subject': "Modifica Fascicolazione: \'%s\'" % wizard.cause, 'body': body, 'model': "protocollo.protocollo", 'res_id': context['active_id'], } body += "</ul></div>" new_context = dict(context).copy() # if protocollo.typology.name == 'PEC': new_context.update({'pec_messages': True}) thread_pool = self.pool.get('protocollo.protocollo') thread_pool.message_post(cr, uid, context['active_id'], type="notification", context=new_context, **post_vars) return {'type': 'ir.actions.act_window_close'}
class survey(osv.osv): _name = 'survey' _description = 'Survey' _rec_name = 'title' def default_get(self, cr, uid, fields, context=None): data = super(survey, self).default_get(cr, uid, fields, context) return data _columns = { 'id': fields.integer('ID'), 'title': fields.char('Survey Title', size=128, required=1), 'page_ids': fields.one2many('survey.page', 'survey_id', 'Page'), 'date_open': fields.datetime('Survey Open Date', readonly=1), 'date_close': fields.datetime('Survey Close Date', readonly=1), 'max_response_limit': fields.integer('Maximum Answer Limit', help="Set to one if survey is answerable only once"), 'response_user': fields.integer( 'Maximum Answer per User', help="Set to one if you require only one Answer per user"), 'state': fields.selection([('open', 'Open'), ('cancel', 'Cancelled'), ('close', 'Closed')], 'Status', readonly=True), 'responsible_id': fields.many2one('res.users', 'Responsible', help="User responsible for survey"), 'tot_start_survey': fields.integer("Total Started Survey", readonly=1), 'tot_comp_survey': fields.integer("Total Completed Survey", readonly=1), 'note': fields.text('Description', size=128), 'history': fields.one2many('survey.history', 'survey_id', 'History Lines', readonly=True), 'users': fields.many2many('res.users', 'survey_users_rel', 'sid', 'uid', 'Users'), 'send_response': fields.boolean('Email Notification on Answer'), 'type': fields.many2one('survey.type', 'Type'), 'color': fields.integer('Color Index'), 'invited_user_ids': fields.many2many('res.users', 'survey_invited_user_rel', 'sid', 'uid', 'Invited User'), } _defaults = { 'state': lambda *a: "open", 'tot_start_survey': lambda *a: 0, 'tot_comp_survey': lambda *a: 0, 'send_response': lambda *a: 1, 'response_user': lambda *a: 1, 'date_open': fields.datetime.now, } def survey_open(self, cr, uid, ids, arg): self.write(cr, uid, ids, { 'state': 'open', 'date_open': strftime("%Y-%m-%d %H:%M:%S") }) return True def survey_close(self, cr, uid, ids, arg): self.write(cr, uid, ids, { 'state': 'close', 'date_close': strftime("%Y-%m-%d %H:%M:%S") }) return True def survey_cancel(self, cr, uid, ids, arg): self.write(cr, uid, ids, {'state': 'cancel'}) return True def copy(self, cr, uid, ids, default=None, context=None): vals = {} current_rec = self.read(cr, uid, ids, context=context) title = _("%s (copy)") % (current_rec.get('title')) vals.update({'title': title}) vals.update({ 'history': [], 'tot_start_survey': 0, 'tot_comp_survey': 0 }) return super(survey, self).copy(cr, uid, ids, vals, context=context) def action_print_survey(self, cr, uid, ids, context=None): """ If response is available then print this response otherwise print survey form(print template of the survey). @param self: The object pointer @param cr: the current row, from the database cursor, @param uid: the current user’s ID for security checks, @param ids: List of Survey IDs @param context: A standard dictionary for contextual values @return : Dictionary value for print survey form. """ if context is None: context = {} datas = {} if 'response_id' in context: response_id = context.get('response_id', 0) datas['ids'] = [context.get('survey_id', 0)] else: response_id = self.pool.get('survey.response').search( cr, uid, [('survey_id', '=', ids)], context=context) datas['ids'] = ids page_setting = { 'orientation': 'vertical', 'without_pagebreak': 0, 'paper_size': 'letter', 'page_number': 1, 'survey_title': 1 } report = {} if response_id and response_id[0]: context.update({'survey_id': datas['ids']}) datas['form'] = page_setting datas['model'] = 'survey.print.answer' report = { 'type': 'ir.actions.report.xml', 'report_name': 'survey.browse.response', 'datas': datas, 'context': context, 'nodestroy': True, } else: datas['form'] = page_setting datas['model'] = 'survey.print' report = { 'type': 'ir.actions.report.xml', 'report_name': 'survey.form', 'datas': datas, 'context': context, 'nodestroy': True, } return report def fill_survey(self, cr, uid, ids, context=None): sur_obj = self.read(cr, uid, ids, ['title', 'page_ids'], context=context) for sur in sur_obj: name = sur['title'] pages = sur['page_ids'] if not pages: raise osv.except_osv( _('Warning!'), _('This survey has no question defined. Please define the questions and answers first.' )) context.update({'active': False, 'survey_id': ids[0]}) return { 'view_type': 'form', 'view_mode': 'form', 'res_model': 'survey.question.wiz', 'type': 'ir.actions.act_window', 'target': 'new', 'name': name, 'context': context } def test_survey(self, cr, uid, ids, context=None): sur_obj = self.read(cr, uid, ids, ['title', 'page_ids'], context=context) for sur in sur_obj: name = sur['title'] pages = sur['page_ids'] if not pages: raise osv.except_osv( _('Warning!'), _('This survey has no pages defined. Please define pages first.' )) context.update({'active': False, 'survey_id': ids[0]}) return { 'view_type': 'form', 'view_mode': 'form', 'res_model': 'survey.question.wiz', 'type': 'ir.actions.act_window', 'target': 'new', 'name': name, 'context': context } def edit_survey(self, cr, uid, ids, context=None): sur_obj = self.read(cr, uid, ids, ['title', 'page_ids'], context=context) for sur in sur_obj: name = sur['title'] pages = sur['page_ids'] if not pages: raise osv.except_osv( _('Warning!'), _('This survey has no question defined. Please define the questions and answers first.' )) context.update({'survey_id': ids[0]}) return { 'view_type': 'form', 'view_mode': 'form', 'res_model': 'survey.question.wiz', 'type': 'ir.actions.act_window', 'target': 'new', 'name': name, 'context': context }
class kg_partner(osv.osv): _name = "res.partner" _inherit = "res.partner" _description = "Partner Managment" def _get_modify(self, cr, uid, ids, field_name, arg, context=None): res={} if field_name == 'modify': for h in self.browse(cr, uid, ids, context=None): res[h.id] = 'no' cr.execute(""" select * from (SELECT tc.table_schema, tc.constraint_name, tc.table_name, kcu.column_name, ccu.table_name AS foreign_table_name, ccu.column_name AS foreign_column_name FROM information_schema.table_constraints tc JOIN information_schema.key_column_usage kcu ON tc.constraint_name = kcu.constraint_name JOIN information_schema.constraint_column_usage ccu ON ccu.constraint_name = tc.constraint_name WHERE constraint_type = 'FOREIGN KEY' AND ccu.table_name='%s') as sam """ %('res_partner')) data = cr.dictfetchall() if data: for var in data: data = var chk_sql = 'Select COALESCE(count(*),0) as cnt from '+str(data['table_name'])+' where '+data['column_name']+' = '+str(ids[0]) cr.execute(chk_sql) out_data = cr.dictfetchone() if out_data: if out_data['cnt'] > 0: res[h.id] = 'yes' return res _columns = { 'city_id' : fields.many2one('res.city', 'City'), 'tin_no' : fields.char('TIN'), 'vat_no' : fields.char('VAT'), 'pan_no' : fields.char('PAN'), 'tan_no' : fields.char('TAN'), 'cst_no' : fields.char('CST'), 'gst_no' : fields.char('GST'), 'supply_type': fields.selection([('material','Material'),('service','Service'),('contractor','Contractor'),('labour','Labour'),('all','All')],'Supply Type'), 'company_type': fields.selection([('individual','Individual'),('company','Company'),('trust','Trust')],'Type'), 'tds': fields.selection([('yes','Yes'),('no','No')],'TDS Applicable'), 'grade': fields.selection([('a','A'),('b','B'),('c','C')],'Grade'), 'payment_id': fields.many2one('kg.payment.master','Payment Terms'), 'language': fields.selection([('tamil', 'Tamil'),('english', 'English'),('hindi', 'Hindi'),('malayalam', 'Malayalam'),('others','Others')],'Preferred Language'), 'cheque_in_favour': fields.char('Cheque in Favor Of'), 'advance_limit': fields.float('Credit Limit'), 'transport_id': fields.many2one('kg.transport','Transport'), 'contact_person': fields.char('Contact Person', size=128), 'landmark': fields.char('Landmark', size=128), #~ 'partner_state': fields.selection([('draft','Draft'),('confirm','WFA'),('approve','Approved'),('reject','Rejected'),('cancel','Cancelled')],'Status'), 'group_flag': fields.boolean('Is Group Company'), 'delivery_id': fields.many2one('kg.delivery.master','Delivery Type'), #'child_ids': fields.one2many('res.partner', 'parent_id', 'Contacts', domain=[('active','=',True)]), 'con_designation': fields.char('Designation'), 'con_whatsapp': fields.char('Whatsapp No'), #~ 'acc_number': fields.char('Whatsapp No'), #~ 'bank_name': fields.char('Whatsapp No'), #~ 'bank_bic': fields.char('Whatsapp No'), 'delivery_ids':fields.one2many('kg.delivery.address', 'src_id', 'Delivery Address'), 'billing_ids':fields.one2many('kg.billing.address', 'bill_id', 'Billing Address'), 'consult_ids':fields.one2many('kg.consultant.fee', 'consult_id', 'Consultant Fees'), 'dealer': fields.boolean('Dealer'), 'economic_category': fields.selection([('budget','Budget'),('loyalty','Loyalty')],'Economic Category'), 'sector': fields.selection([('cp','CP'),('ip','IP'),('both','Both')],'Marketing Division'), 'industry_id': fields.many2one('kg.industry.master','Sector'), 'dealer_id': fields.many2one('res.partner','Dealer Name',domain=[('dealer','=',True)]), 'remark': fields.text('Approve/Reject'), 'cancel_remark': fields.text('Cancel Remarks'), 'modify': fields.function(_get_modify, string='Modify', method=True, type='char', size=3), 'user_ref_id': fields.many2one('res.users','User Name'), 'adhar_id': fields.char('Adhar ID'), 'contractor': fields.boolean('Contractor'), 'tin_flag': fields.boolean('TIN Flag'), 'mobile_2': fields.char('Mobile2',size=12), 'email_applicable': fields.selection([('yes','Yes'),('no','No')],'Email Applicable'), 'sms_applicable': fields.selection([('yes','Yes'),('no','No')],'SMS Applicable'), ## Entry Info 'creation_date': fields.datetime('Created Date',readonly=True), 'created_by': fields.many2one('res.users', 'Created by',readonly=True), 'confirmed_date': fields.datetime('Confirmed Date',readonly=True), 'confirmed_by': fields.many2one('res.users','Confirmed By',readonly=True), 'rej_user_id': fields.many2one('res.users', 'Rejected By', readonly=True), 'reject_date': fields.datetime('Reject Date', readonly=True), 'approved_date': fields.datetime('Approved Date',readonly=True), 'approved_by': fields.many2one('res.users','Approved By',readonly=True), 'cancel_date': fields.datetime('Cancelled Date', readonly=True), 'cancel_user_id': fields.many2one('res.users', 'Cancelled By', readonly=True), 'updated_date': fields.datetime('Last Updated Date',readonly=True), 'updated_by': fields.many2one('res.users','Last Updated By',readonly=True), } _defaults = { 'is_company': True, 'creation_date': lambda * a: time.strftime('%Y-%m-%d %H:%M:%S'), 'created_by': lambda obj, cr, uid, context: uid, 'partner_state': 'draft', 'modify': 'no', 'tin_flag': False, 'company_type': 'company', } def onchange_city(self, cr, uid, ids, city_id, context=None): if city_id: state_id = self.pool.get('res.city').browse(cr, uid, city_id, context).state_id.id return {'value':{'state_id':state_id}} return {} def onchange_zip(self,cr,uid,ids,zip,context=None): if len(str(zip)) in (6,7,8): value = {'zip':zip} else: raise osv.except_osv(_('Check zip number !!'), _('zip should contain 6-8 digit numerics. Else system not allow to save. !!')) if zip.isdigit() == False: raise osv.except_osv(_('Check zip number !!'), _('Please enter numeric values !!')) return {'value': value} #~ def onchange_tin_cst(self,cr,uid,ids,tin_no,cst_no,context=None): #~ if tin_no: #~ if len(str(tin_no)) == 11: #~ value = {'tin_no':tin_no} #~ else: #~ raise osv.except_osv(_('Check TIN number !!'), #~ _('Please enter 11 digit number !!')) #~ if cst_no: #~ if len(str(cst_no)) == 11: #~ value = {'cst_no':cst_no} #~ else: #~ raise osv.except_osv(_('Check CST number !!'), #~ _('Please enter 11 digit number !!')) #~ return {'value': value} def confirm_partner(self, cr, uid, ids, context=None): rec = self.browse(cr, uid, ids[0]) if rec.partner_state == 'draft': self.write(cr, uid, ids, {'partner_state': 'confirm','confirmed_by':uid,'confirmed_date': time.strftime('%Y-%m-%d %H:%M:%S')}) return True def reject_partner(self, cr, uid, ids, context=None): rec = self.browse(cr, uid, ids[0]) if rec.partner_state == 'confirm': if rec.remark: self.write(cr, uid, ids, {'partner_state': 'reject','update_user_id':uid,'reject_date': time.strftime('%Y-%m-%d %H:%M:%S')}) else: raise osv.except_osv(_('Rejection remark is must !!'), _('Enter rejection remark in remark field !!')) return True def approve_partner(self, cr, uid, ids, context=None): rec = self.browse(cr, uid, ids[0]) if rec.partner_state == 'confirm': self.write(cr, uid, ids, {'partner_state': 'approve','approved_by':uid,'approved_date': time.strftime('%Y-%m-%d %H:%M:%S')}) return True def entry_draft(self,cr,uid,ids,context=None): rec = self.browse(cr, uid, ids[0]) if rec.partner_state == 'approve': self.write(cr, uid, ids, {'partner_state': 'draft'}) return True def entry_cancel(self,cr,uid,ids,context=None): rec = self.browse(cr,uid,ids[0]) if rec.partner_state == 'approve': if rec.cancel_remark: self.write(cr, uid, ids, {'partner_state': 'cancel','cancel_user_id': uid, 'cancel_date': time.strftime('%Y-%m-%d %H:%M:%S')}) else: raise osv.except_osv(_('Cancel remark is must !!'), _('Enter the remarks in Cancel remarks field !!')) return True def unlink(self,cr,uid,ids,context=None): unlink_ids = [] for rec in self.browse(cr,uid,ids): if rec.partner_state != 'draft': raise osv.except_osv(_('Warning!'), _('You can not delete this entry !!')) else: unlink_ids.append(rec.id) return osv.osv.unlink(self, cr, uid, unlink_ids, context=context) def write(self, cr, uid, ids, vals, context=None): print"valsssssS",vals #if len(str(vals['zip'])) == 6: # pass #else: # raise osv.except_osv(_('Check zip number !!'), # _('Please enter six digit number !!')) vals.update({'updated_date': time.strftime('%Y-%m-%d %H:%M:%S'),'updated_by':uid}) return super(kg_partner, self).write(cr, uid, ids, vals, context) def _check_zip(self, cr, uid, ids, context=None): rec = self.browse(cr, uid, ids[0]) if rec.zip: if len(str(rec.zip)) in (6,7,8) and rec.zip.isdigit() == True: return True else: return True return False def _check_tin(self, cr, uid, ids, context=None): rec = self.browse(cr, uid, ids[0]) if rec.tin_no: if len(str(rec.tin_no)) == 11 and rec.tin_no.isdigit() == True: return True else: return True return False def _check_cst(self, cr, uid, ids, context=None): rec = self.browse(cr, uid, ids[0]) if rec.cst_no: if len(str(rec.cst_no)) == 11 and rec.cst_no.isdigit() == True: return True else: return True return False def _check_vat(self, cr, uid, ids, context=None): rec = self.browse(cr, uid, ids[0]) if rec.vat_no: if len(str(rec.vat_no)) == 15: return True else: return True return False def _check_phone(self, cr, uid, ids, context=None): rec = self.browse(cr, uid, ids[0]) if rec.phone: if len(str(rec.phone)) in (8,9,10,11,12,13,14,15) and rec.phone.isdigit() == True: return True else: return True return False def _validate_email(self, cr, uid, ids, context=None): rec = self.browse(cr,uid,ids[0]) if rec.email==False: return True else: if re.match("^.+\\@(\\[?)[a-zA-Z0-9\\-\\.]+\\.([a-zA-Z]{2,3}|[0-9]{1,3})(\\]?)$", rec.email) != None: return True else: raise osv.except_osv('Invalid Email', 'Please enter a valid email address') def _check_website(self, cr, uid, ids, context=None): rec = self.browse(cr, uid, ids[0]) if rec.website != False: #~ if re.match('www?.(?:www)?(?:[\w-]{2,255}(?:\.\w{2,6}){1,2})(?:/[\w&%?#-]{1,300})?',rec.website): if re.match('www.(?:www)?(?:[\w-]{2,255}(?:\.\w{2,6}){1,2})(?:/[\w&%?#-]{1,300})?',rec.website): return True else: return False return True def _check_ifsc(self, cr, uid, ids, context=None): rec = self.browse(cr, uid, ids[0]) if rec.bank_ids: for item in rec.bank_ids: if item.bank_bic: if len(str(item.bank_bic)) == 11: return True else: return True else: return True return False def _check_acc_no(self, cr, uid, ids, context=None): rec = self.browse(cr, uid, ids[0]) if rec.bank_ids: for item in rec.bank_ids: if item.acc_number: if len(str(item.acc_number)) in (6,7,8,9,10,11,12,13,14,15,16,17,18) and item.acc_number.isdigit() == True: return True else: return True else: return True return False def _check_mobile_no(self, cr, uid, ids, context=None): rec = self.browse(cr, uid, ids[0]) if rec.mobile: if len(str(rec.mobile)) in (10,11,12) and rec.mobile.isdigit() == True: return True else: return True return False def _name_validate(self, cr, uid,ids, context=None): rec = self.browse(cr,uid,ids[0]) res = True data='' if rec.name: partner_name = rec.name name=partner_name.upper() if rec.customer == True: cr.execute(""" select upper(name) from res_partner where upper(name) = '%s' and customer = True """ %(name)) data = cr.dictfetchall() elif rec.supplier == True: cr.execute(""" select upper(name) from res_partner where upper(name) = '%s' and supplier = True """ %(name)) data = cr.dictfetchall() elif rec.dealer == True: cr.execute(""" select upper(name) from res_partner where upper(name) = '%s' and dealer = True """ %(name)) data = cr.dictfetchall() if len(data) > 1: res = False else: res = True return res def _unique_tin(self, cr, uid,ids, context=None): rec = self.browse(cr,uid,ids[0]) res = True if rec.tin_no: tin_no = rec.tin_no name = tin_no.upper() cr.execute(""" select tin_no from res_partner where tin_no = '%s' """ %(name)) data = cr.dictfetchall() if len(data) > 1: res = False else: res = True return res def _spl_name(self, cr, uid, ids, context=None): rec = self.browse(cr, uid, ids[0]) if rec.name: name_special_char = ''.join(c for c in rec.name if c in '!@#$%^~*{}?+/=') if name_special_char: raise osv.except_osv(_('Warning!'), _('Special Character Not Allowed in Name!')) if rec.adhar_id: adhar_special_char = ''.join(c for c in rec.adhar_id if c in '!@#$%^~*{}?+/=') if adhar_special_char: raise osv.except_osv(_('Warning!'), _('Special Character Not Allowed in Adhar ID!')) if rec.pan_no: pan_special_char = ''.join(c for c in rec.pan_no if c in '!@#$%^~*{}?+/=') if pan_special_char: raise osv.except_osv(_('Warning!'), _('Special Character Not Allowed in PAN!')) if rec.gst_no: gst_special_char = ''.join(c for c in rec.gst_no if c in '!@#$%^~*{}?+/=') if gst_special_char: raise osv.except_osv(_('Warning!'), _('Special Character Not Allowed in GST!')) if rec.tan_no: tan_special_char = ''.join(c for c in rec.tan_no if c in '!@#$%^~*{}?+/=') if tan_special_char: raise osv.except_osv(_('Warning!'), _('Special Character Not Allowed in TAN!')) if rec.cst_no: cst_special_char = ''.join(c for c in rec.cst_no if c in '!@#$%^~*{}?+/=') if cst_special_char: raise osv.except_osv(_('Warning!'), _('Special Character Not in CST!')) if rec.vat_no: vat_special_char = ''.join(c for c in rec.vat_no if c in '!@#$%^~*{}?+/=') if vat_special_char: raise osv.except_osv(_('Warning!'), _('Special Character Not in VAT!')) if rec.cheque_in_favour: cheque_special_char = ''.join(c for c in rec.cheque_in_favour if c in '!@#$%^~*{}?+/=') if cheque_special_char: raise osv.except_osv(_('Warning!'), _('Special Character Not in Cheque in Favour Of!')) if rec.contact_person: contact_special_char = ''.join(c for c in rec.contact_person if c in '!@#$%^~*{}?+/=') if contact_special_char: raise osv.except_osv(_('Warning!'), _('Special Character Not in Contact Person!')) return True else: return True return False _constraints = [ (_check_zip,'ZIP should contain 6-8 digit numerics. Else system not allow to save.',['ZIP']), (_check_tin,'TIN No. should contain 11 digit numerics. Else system not allow to save.',['TIN']), (_check_cst,'CST No. should contain 11 digit numerics. Else system not allow to save.',['CST']), (_check_vat,'VAT No. should contain 15 letters. Else system not allow to save.',['VAT']), (_validate_email,'Check Email !',['']), (_check_website,'Check Website !',['Website']), (_check_phone,'Phone No. should contain 8-15 digit numerics. Else system not allow to save.',['Phone']), (_check_ifsc,'IFSC should contain 11 letters. Else system not allow to save.',['IFSC']), (_check_acc_no,'A/C No. should contain 6-18 digit numerics. Else system not allow to save.',['A/C No.']), (_check_mobile_no,'Mobile No. should contain 10-12 digit numerics. Else system not allow to save.',['Mobile']), (_name_validate, 'Name must be unique !!', ['Name']), (_unique_tin, 'TIN must be unique !!', ['TIN']), (_spl_name, 'Special Character Not Allowed!', ['']), ]
class crm_claim(osv.osv): """ Crm claim """ _name = "crm.claim" _description = "Claim" _order = "priority,date desc" _inherit = ['mail.thread'] def _get_default_section_id(self, cr, uid, context=None): """ Gives default section by checking if present in the context """ return self.pool.get('crm.lead')._resolve_section_id_from_context( cr, uid, context=context) or False def _get_default_stage_id(self, cr, uid, context=None): """ Gives default stage_id """ section_id = self._get_default_section_id(cr, uid, context=context) return self.stage_find(cr, uid, [], section_id, [('sequence', '=', '1')], context=context) _columns = { 'id': fields.integer('ID', readonly=True), 'name': fields.char('Claim Subject', size=128, required=True), 'active': fields.boolean('Active'), 'action_next': fields.char('Next Action', size=200), 'date_action_next': fields.datetime('Next Action Date'), 'description': fields.text('Description'), 'resolution': fields.text('Resolution'), 'create_date': fields.datetime('Creation Date' , readonly=True), 'write_date': fields.datetime('Update Date' , readonly=True), 'date_deadline': fields.date('Deadline'), 'date_closed': fields.datetime('Closed', readonly=True), 'date': fields.datetime('Claim Date', select=True), 'ref': fields.reference('Reference', selection=openerp.addons.base.res.res_request.referencable_models), 'categ_id': fields.many2one('crm.case.categ', 'Category', \ domain="[('section_id','=',section_id),\ ('object_id.model', '=', 'crm.claim')]" ), 'priority': fields.selection(crm.AVAILABLE_PRIORITIES, 'Priority'), 'type_action': fields.selection([('correction','Corrective Action'),('prevention','Preventive Action')], 'Action Type'), 'user_id': fields.many2one('res.users', 'Responsible'), 'user_fault': fields.char('Trouble Responsible', size=64), 'section_id': fields.many2one('crm.case.section', 'Sales Team', \ select=True, help="Responsible sales team."\ " Define Responsible user and Email account for"\ " mail gateway."), 'company_id': fields.many2one('res.company', 'Company'), 'partner_id': fields.many2one('res.partner', 'Partner'), 'email_cc': fields.text('Watchers Emails', size=252, help="These email addresses will be added to the CC field of all inbound and outbound emails for this record before being sent. Separate multiple email addresses with a comma"), 'email_from': fields.char('Email', size=128, help="Destination email for email gateway."), 'partner_phone': fields.char('Phone', size=32), 'stage_id': fields.many2one ('crm.claim.stage', 'Stage', track_visibility='onchange', domain="['|', ('section_ids', '=', section_id), ('case_default', '=', True)]"), 'cause': fields.text('Root Cause'), } _defaults = { 'user_id': lambda s, cr, uid, c: uid, 'section_id': lambda s, cr, uid, c: s._get_default_section_id(cr, uid, c), 'date': fields.datetime.now, 'company_id': lambda s, cr, uid, c: s.pool.get('res.company')._company_default_get( cr, uid, 'crm.case', context=c), 'priority': lambda *a: crm.AVAILABLE_PRIORITIES[2][0], 'active': lambda *a: 1, 'stage_id': lambda s, cr, uid, c: s._get_default_stage_id(cr, uid, c) } def stage_find(self, cr, uid, cases, section_id, domain=[], order='sequence', context=None): """ Override of the base.stage method Parameter of the stage search taken from the lead: - section_id: if set, stages must belong to this section or be a default case """ if isinstance(cases, (int, long)): cases = self.browse(cr, uid, cases, context=context) # collect all section_ids section_ids = [] if section_id: section_ids.append(section_id) for claim in cases: if claim.section_id: section_ids.append(claim.section_id.id) # OR all section_ids and OR with case_default search_domain = [] if section_ids: search_domain += [('|')] * len(section_ids) for section_id in section_ids: search_domain.append(('section_ids', '=', section_id)) search_domain.append(('case_default', '=', True)) # AND with the domain in parameter search_domain += list(domain) # perform search, return the first found stage_ids = self.pool.get('crm.claim.stage').search(cr, uid, search_domain, order=order, context=context) if stage_ids: return stage_ids[0] return False def onchange_partner_id(self, cr, uid, ids, partner_id, email=False, context=None): """This function returns value of partner address based on partner :param email: ignored """ if not partner_id: return {'value': {'email_from': False, 'partner_phone': False}} address = self.pool.get('res.partner').browse(cr, uid, partner_id, context=context) return { 'value': { 'email_from': address.email, 'partner_phone': address.phone } } def create(self, cr, uid, vals, context=None): if context is None: context = {} if vals.get('section_id') and not context.get('default_section_id'): context['default_section_id'] = vals.get('section_id') # context: no_log, because subtype already handle this return super(crm_claim, self).create(cr, uid, vals, context=context) def copy(self, cr, uid, id, default=None, context=None): claim = self.browse(cr, uid, id, context=context) default = dict(default or {}, stage_id=self._get_default_stage_id(cr, uid, context=context), name=_('%s (copy)') % claim.name) return super(crm_claim, self).copy(cr, uid, id, default, context=context) # ------------------------------------------------------- # Mail gateway # ------------------------------------------------------- def message_new(self, cr, uid, msg, custom_values=None, context=None): """ Overrides mail_thread message_new that is called by the mailgateway through message_process. This override updates the document according to the email. """ if custom_values is None: custom_values = {} desc = html2plaintext(msg.get('body')) if msg.get('body') else '' defaults = { 'name': msg.get('subject') or _("No Subject"), 'description': desc, 'email_from': msg.get('from'), 'email_cc': msg.get('cc'), 'partner_id': msg.get('author_id', False), } if msg.get('priority'): defaults['priority'] = msg.get('priority') defaults.update(custom_values) return super(crm_claim, self).message_new(cr, uid, msg, custom_values=defaults, context=context)
class closing_stock(osv.osv): _name = "closing_stock" _description = "closing_stock" _columns = { 'date':fields.datetime('Date'), 'line_ids': fields.one2many('closing_stock.line','closing_id','Line Id', size=128), } def load_stock(self, cr, uid, ids, context=None): cr.execute("""delete from closing_stock_line""") product_list = [] psql1 = """select distinct product_id from stock_move """ cr.execute(psql1) pdata = cr.dictfetchall() rec = self.browse(cr, uid, ids[0]) for i in pdata: pro_rec = self.pool.get('product.product').browse(cr,uid,i['product_id']) product_list.append(pro_rec) for item in product_list: in_qty = 0.00 out_qty = 0.00 in_move_obj = self.pool.get('stock.move').search(cr,uid,[('location_dest_id','=',23),('product_id','=',item.id)]) in_move_rec = self.pool.get('stock.move').browse(cr,uid,in_move_obj) if in_move_rec: for i in in_move_rec: in_qty +=i.product_qty out_move_obj = self.pool.get('stock.move').search(cr,uid,[('location_id','=',23),('product_id','=',item.id)]) out_move_rec = self.pool.get('stock.move').browse(cr,uid,out_move_obj) if out_move_rec: for j in out_move_rec: out_qty +=j.product_qty close_qty = in_qty - out_qty if close_qty > 0: self.pool.get('closing_stock.line').create(cr, uid, { 'closing_id': rec.id, 'product_id': item.id, 'uom': item.uom_id.id, 'receive_qty':in_qty, 'issued_qty': out_qty, 'closing_stocks':close_qty, }) return True
class reportx(osv.Model): _name = "cash.count.reportx" _rec_name = 'number' def _compute_total(self, cr, uid, ids, fieldnames, args, context=None): context = context or {} result = dict() for record in self.browse(cr, uid, ids, context=context): total = 0.0 for line in record.lines: total += line.end_balance result[record.id] = total return result def create_from_ui(self, cr, uid, data, context=None): context = context or {} cs_id = data.get('cashier_session_id') cs_obj = self.pool.get('cash.count.cashier.session') cs = cs_obj.browse(cr, uid, cs_id, context=context) lines = [] for line in data.get('lines'): for s in cs.session_id.statement_ids: if s.journal_id.id == line[ 'journal_id'] and s.instrument_id.id == line[ 'instrument_id']: lines.append((0, 0, { 'statement_id': s.id, 'end_balance': line['amount'] })) data['lines'] = lines data['date'] = time.strftime('%Y-%m-%d %H:%M:%S') r_id = self.create(cr, uid, data, context=context) cs_obj.write(cr, uid, cs_id, {'reportx_id': r_id}, context=context) wf_service = netsvc.LocalService("workflow") wf_service.trg_validate(uid, 'cash.count.cashier.session', cs_id, 'close', cr) return r_id _columns = { 'number': fields.char('Report Number', size=50), 'date': fields.datetime('Date', readonly=True), 'cashier_session_id': fields.many2one('cash.count.cashier.session', 'Cashier Session'), 'cashier_id': fields.related('cashier_session_id', 'cashier_id', type='many2one', relation='hr.employee', string='Cashier'), 'pos_session_id': fields.many2one('pos.session', 'PoS Session'), 'printer_serial': fields.char('Printer Serial', size=64, required=True), 'printer_id': fields.many2one('fiscal_printer.printer', 'Printer'), 'lines': fields.one2many('cash.count.reportx.line', 'reportx_id', 'Report Details'), 'total': fields.function(_compute_total, type='float', string='Total', digits_compute=dp.get_precision('Account')), }
class import_ftp_ajri(osv.osv): _name = "reliance.import_ftp_ajri" _rec_name = "input_file" _columns = { 'date_start' : fields.datetime('Date Start'), 'date_end' : fields.datetime('Date End'), 'user_id' : fields.many2one('res.users', 'Users'), 'input_file' : fields.char('Input File'), 'total_records' : fields.integer('Total Records'), 'notes' : fields.char('Notes'), } _defaults = { 'user_id' : lambda obj, cr, uid, context: uid, } ########################################################### # dipanggil dari cron job ########################################################### def cron_process(self, cr, uid, context=None): _logger.warning('running FTP AJRI cron_process') self.check_new_files(cr, uid, [], context=context) return True ########################################################### # # is there new files on the ftp upload folder ? # called from cron job # if type=zip: unzip # process the extracted CSV ########################################################### def check_new_files(self, cr, uid, ids, context=None): ftp_utils = ftp.ftp_utils() ftp_ajri_folder = self.pool.get('ir.config_parameter').get_param(cr, uid, 'ftp_ajri_folder') ftp_utils.check_done_folder(ftp_ajri_folder) if context==None: context={} context.update({'date_start':time.strftime('%Y-%m-%d %H:%M:%S')}) # search and extract ZIP and move zip to done folder # zip_files = glob.glob(ftp_ajri_folder + '/*.zip') zip_files = ftp_utils.insensitive_glob(ftp_ajri_folder + '/*.zip') for f in zip_files: if zipfile.is_zipfile(f): ftp_utils.unzip(f, ftp_ajri_folder) done = ftp_utils.done_filename(cr, uid, f, context=context) shutil.move(f, done) else: _logger.error('wrong zip file') # search CSV # csv_files = glob.glob(ftp_ajri_folder + '/*.csv') csv_files = ftp_utils.insensitive_glob(ftp_ajri_folder + '/*.csv') for csv_file in csv_files: if csv_file.upper().find('AJRI') != -1: self.insert_ajri_customer(cr, uid, csv_file, context=context) return ########################################################### # read the CSV into ls partner ########################################################### def insert_ajri_customer(self, cr, uid, csv_file, context=None): _logger.warning('importing csv data insert_ajri_customer') ftp_utils = ftp.ftp_utils() import_ajri = self.pool.get('reliance.import_ajri') cron_obj = self.pool.get('ir.cron') cron_id = cron_obj.search(cr, uid, [('name','=', "Auto Import AJRI Partner")], context=context) if not cron_id: raise osv.except_osv(_('error'),_("no cron job Auto Import AJRI Partner") ) fields_map = [ "nomor_polis" , "nama_pemegang" , "nomor_partisipan" , "nama_partisipan" , "produk" , "tgl_lahir" , "tgl_mulai" , "tgl_selesai" , "status" , "up" , "total_premi" , "status_klaim" , "status_bayar" , "tgl_bayar" , "klaim_disetujui" , ] i = ftp_utils.read_csv_insert(cr, uid, csv_file, fields_map, import_ajri, delimiter=DELIMITER, quotechar=QUOTECHAR, cron_id=cron_id, cron_obj=cron_obj, context=context) if isinstance(i, dict): self.create(cr, uid, i, context=context ) cr.commit() return # move csv_file to processed folder done = ftp_utils.done_filename(cr, uid, csv_file, context=context) shutil.move(csv_file, done) data = { 'date_start' : context.get('date_start',False), 'date_end' : time.strftime('%Y-%m-%d %H:%M:%S'), 'input_file' : csv_file, 'total_records' : i, 'notes' : '%s moved to %s' % (csv_file, done), } self.create(cr, uid, data, context=context ) cr.commit() return
class cashier_session(osv.Model): _name = "cash.count.cashier.session" SESSION_STATE = [ ('opened', 'In Progress'), # Signal closing ('closed', 'Closed & Posted'), ] def login(self, cr, uid, username, password, context=None): context = context or {} obj = self.pool.get('hr.employee') criteria = [('username', '=', username), ('password', '=', password)] if context.get('manager'): criteria.append(('role', '=', 'manager')) ids = obj.search(cr, uid, criteria, context=context) if ids: return ids[0] else: return False def wkf_action_open(self, cr, uid, ids, context=None): context = context or {} values = {'opening_date': time.strftime('%Y-%m-%d %H:%M:%S')} return self.write(cr, uid, ids, values, context=context) def open_session(self, cr, uid, session_id, username, password, context=None): context = context or {} cashier_id = self.login(cr, uid, username, password, context=context) if cashier_id: c = [('session_id', '=', session_id), ('state', '=', 'opened')] session_ids = self.search(cr, uid, c, context=context) if len(session_ids) == 0: values = {'session_id': session_id, 'cashier_id': cashier_id} s_id = self.create(cr, uid, values, context=context) session = self.read(cr, uid, s_id, context=context) result = {'status': 0, 'session': session} else: result = { 'status': 1, 'msg': _("You can open only one session at a time") } else: result = {'status': 1, 'msg': _("Wrong user name or password")} return result def close_session(self, cr, uid, session_id, context=None): context = context or {} session = self.browse(cr, uid, session_id, context=context) if session.state == 'opened': wf_service = netsvc.LocalService("workflow") wf_service.trg_validate(uid, 'cash.count.cashier.session', session_id, 'close', cr) return True return False def wkf_action_close(self, cr, uid, ids, context=None): context = context or {} values = {'closing_date': time.strftime('%Y-%m-%d %H:%M:%S')} values.update({'state': 'closed'}) return self.write(cr, uid, ids, values, context=context) def unlock_session(self, cr, uid, session_id, username, password, context=None): context = context or {} cashier_id = self.login(cr, uid, username, password, context=context) if cashier_id: c = [('session_id', '=', session_id), ('state', '=', 'opened'), ('cashier_id', '=', cashier_id)] session_ids = self.search(cr, uid, c, context=context) if len(session_ids) == 1: return True return False def create(self, cr, uid, values, context=None): context = context or {} s_obj = self.pool.get('pos.session') s_id = values.get('session_id') session = s_obj.browse(cr, uid, s_id, context=context) values.update({'name': session.sequence_id._next()}) return super(cashier_session, self).create(cr, uid, values, context=context) _columns = { 'name': fields.char('Cashier Session ID', size=32, required=True, readonly=True), 'session_id': fields.many2one('pos.session', 'Pos Session', required=True), 'cashier_id': fields.many2one('hr.employee', 'Cashier', required=True), 'opening_date': fields.datetime('Opening Date', readonly=True), 'closing_date': fields.datetime('Closing Date', readonly=True), 'state': fields.selection(SESSION_STATE, 'Status', required=True, readonly=True, select=1), 'reportx_id': fields.many2one('cash.count.reportx', 'Report X'), } _defaults = { 'state': 'opened', } _order = "name" class reportx(osv.Model): _name = "cash.count.reportx" _rec_name = 'number' def _compute_total(self, cr, uid, ids, fieldnames, args, context=None): context = context or {} result = dict() for record in self.browse(cr, uid, ids, context=context): total = 0.0 for line in record.lines: total += line.end_balance result[record.id] = total return result def create_from_ui(self, cr, uid, data, context=None): context = context or {} cs_id = data.get('cashier_session_id') cs_obj = self.pool.get('cash.count.cashier.session') cs = cs_obj.browse(cr, uid, cs_id, context=context) lines = [] for line in data.get('lines'): for s in cs.session_id.statement_ids: if s.journal_id.id == line[ 'journal_id'] and s.instrument_id.id == line[ 'instrument_id']: lines.append((0, 0, { 'statement_id': s.id, 'end_balance': line['amount'] })) data['lines'] = lines data['date'] = time.strftime('%Y-%m-%d %H:%M:%S') r_id = self.create(cr, uid, data, context=context) cs_obj.write(cr, uid, cs_id, {'reportx_id': r_id}, context=context) wf_service = netsvc.LocalService("workflow") wf_service.trg_validate(uid, 'cash.count.cashier.session', cs_id, 'close', cr) return r_id _columns = { 'number': fields.char('Report Number', size=50), 'date': fields.datetime('Date', readonly=True), 'cashier_session_id': fields.many2one('cash.count.cashier.session', 'Cashier Session'), 'cashier_id': fields.related('cashier_session_id', 'cashier_id', type='many2one', relation='hr.employee', string='Cashier'), 'pos_session_id': fields.many2one('pos.session', 'PoS Session'), 'printer_serial': fields.char('Printer Serial', size=64, required=True), 'printer_id': fields.many2one('fiscal_printer.printer', 'Printer'), 'lines': fields.one2many('cash.count.reportx.line', 'reportx_id', 'Report Details'), 'total': fields.function(_compute_total, type='float', string='Total', digits_compute=dp.get_precision('Account')), } class reportx_line(osv.Model): _name = "cash.count.reportx.line" _columns = { 'reportx_id': fields.many2one('cash.count.reportx', 'Report X'), 'statement_id': fields.many2one('account.bank.statement', 'Statement'), 'journal_id': fields.related('statement_id', 'journal_id', type='many2one', relation='account.journal', string='Journal'), 'instrument_id': fields.related('statement_id', 'instrument_id', type='many2one', relation='payment_instrument.instrument', string='Instrument'), 'end_balance': fields.float('Ending Balance', required=True, digits_compute=dp.get_precision('Account')), }
"during order shipment and invoice, else it won't."), 'language':fields.selection(_lang_get, "Default Language", help="Selected language is loaded in the system, " "all documents related to this contact will be synched in this language."), 'category':fields.many2one('product.category', "Default Category", help="Selected Category will be set default category for odoo's product, " "in case when magento product doesn\'t belongs to any catgeory."), 'state':fields.selection([('enable','Enable'),('disable','Disable')],'Status', help="status will be consider during order invoice, " "order delivery and order cancel, to stop asynchronous process at other end.", size=100), 'inventory_sync':fields.selection([ ('enable','Enable'), ('disable','Disable')], 'Inventory Update', help="If Enable, Invetory will Forcely Update During Product Update Operation.", size=100), 'warehouse_id':fields.many2one('stock.warehouse','Warehouse', help="Used During Inventory Synchronization From Magento to Odoo."), 'location_id': fields.related('warehouse_id', 'lot_stock_id', type='many2one', relation='stock.location', string='Location'), 'create_date':fields.datetime('Created Date'), 'correct_mapping':fields.boolean('Correct Mapping'), 'route_id':fields.many2one('stock.location.route','Route', help="Used During Sale Order From Magento to Odoo."), } _defaults = { 'correct_mapping':True, 'instance_name':_default_instance_name, 'active':lambda *a: 1, 'auto_ship':lambda *a: 1, 'auto_invoice':lambda *a: 1, 'credential':lambda *a: 1, 'language': api.model(lambda self: self.env.lang), 'category':_default_category, 'state':'enable', 'inventory_sync':'enable',
class stock_production_lot(osv.osv): _inherit = 'stock.production.lot' def _get_date(dtype): """Return a function to compute the limit date for this type""" def calc_date(self, cr, uid, context=None): """Compute the limit date for a given date""" if context is None: context = {} if not context.get('product_id', False): date = False else: product = openerp.registry( cr.dbname)['product.product'].browse( cr, uid, context['product_id']) duration = getattr(product, dtype) # set date to False when no expiry time specified on the product date = duration and (datetime.datetime.today() + datetime.timedelta(days=duration)) return date and date.strftime('%Y-%m-%d %H:%M:%S') or False return calc_date _columns = { 'life_date': fields.datetime( 'End of Life Date', help= 'This is the date on which the goods with this Serial Number may become dangerous and must not be consumed.' ), 'use_date': fields.datetime( 'Best before Date', help= 'This is the date on which the goods with this Serial Number start deteriorating, without being dangerous yet.' ), 'removal_date': fields.datetime( 'Removal Date', help= 'This is the date on which the goods with this Serial Number should be removed from the stock.' ), 'alert_date': fields.datetime( 'Alert Date', help= "This is the date on which an alert should be notified about the goods with this Serial Number." ), } # Assign dates according to products data def create(self, cr, uid, vals, context=None): context = dict(context or {}) context['product_id'] = vals.get('product_id', context.get('default_product_id')) return super(stock_production_lot, self).create(cr, uid, vals, context=context) _defaults = { 'life_date': _get_date('life_time'), 'use_date': _get_date('use_time'), 'removal_date': _get_date('removal_time'), 'alert_date': _get_date('alert_time'), }
myids = self.search(cr, uid, [], context=context) for user in self.browse(cr,uid,myids,context=context): res = user.counter +1; isTrue = self.write(cr, uid, user.id, {'counter': res}, context=context) return isTrue _name = "saas.user.info" _description = "saas.user.info" _columns = { 'name': fields.char('Note', required=False,track_visibility='always', help=""), 'user': fields.many2one('res.partner', 'partner', help=""), 'host_name': fields.char('host_name',required=True, help=""), 'host_type': fields.char('host_type',required=False , help=""), 'server': fields.many2one('saas.server', 'server',required=True, help=""), 'url_addres': fields.function(_get_full_url, type='char',string='url_addres'), 'start_date': fields.datetime('start_date',required=False, help=""), 'end_date': fields.function(_compute_exp_date, type = 'datetime',string='end_date'), 'product_id':fields.many2one('product.product','product_id',required = False,help=''), 'state': fields.function(_get_server_state, type='char', string='state'), 'counter': fields.integer('counter',required=False , help=""), } _defaults = { 'start_date': fields.datetime.now, } _sql_constraints = [ ('host_name_uniq', 'unique (host_name)', 'host_name must be unique !'), ] class saas_server(osv.osv): _inherit = ['mail.thread'] _name = "saas.server"
class travel_journey(orm.Model): """Journey of travel""" _name = 'travel.journey' _description = _(__doc__) _journey_type_classes = {} @staticmethod def _check_dep_arr_dates(departure, arrival): return not departure or not arrival or departure <= arrival def _estimate_datetime(self, cr, uid, ids, field_name, context=None): """If there is no start date from journey, get it from travel""" if type(ids) in (int, long): ids = [ids] res = {} for journey in self.browse(cr, uid, ids, context=context): date = False if journey.type: try: journey_class = self._journey_type_classes[journey.type] date = journey_class._estimate_typed_date( self, journey, field_name) except KeyError: _logger.error( _('Transportation type "%s" has not registered its ' 'class in _journey_types, skipping its dates') % journey.type) except AttributeError: _logger.error( _('Transportation type "%s" has not registered a ' '_estimate_typed_date() function, skipping its dates' ) % journey.type) if field_name == 'date_start': date = (date or journey.departure or journey.passenger_id.travel_id.date_start) elif field_name == 'date_stop': date = (date or journey.arrival or journey.passenger_id.travel_id.date_stop) # Make sure every date is in datetime format and not simply date try: date = datetime.strptime(date, DEFAULT_SERVER_DATE_FORMAT) except ValueError: date = datetime.strptime(date, DEFAULT_SERVER_DATETIME_FORMAT) res[journey.id] = date return res def _estimate_date(self, cr, uid, ids, field_name, arg=None, context=None): datetimes = self._estimate_datetime(cr, uid, ids, field_name, context=context) return { i: datetimes[i].strftime(DEFAULT_SERVER_DATE_FORMAT) for i in datetimes } def _estimate_time(self, cr, uid, ids, field_name, arg=None, context=None): datetimes = self._estimate_datetime(cr, uid, ids, field_name, context=context) return { i: datetimes[i].strftime(DEFAULT_SERVER_TIME_FORMAT) for i in datetimes } def _inv_estimate_date(self, cr, uid, ids, field_name, val, arg, context=None): """If there is no start date in journey, set it in travel""" if type(ids) in (int, long): ids = [ids] for journey in self.browse(cr, uid, ids, context=context): if journey.type: try: journey_class = self._journey_type_classes[journey.type] if (journey_class._inv_estimate_typed_date( self, journey, field_name, val)): continue except KeyError: _logger.error( _('Transportation type "%s" has not registered its ' 'class in _journey_types, skipping its dates') % journey.type) except AttributeError: _logger.error( _('Transportation type "%s" has not registered a ' '_inv_estimate_typed_date() function, skipping its ' 'dates') % journey.type) if field_name == 'date_start': if journey.departure: journey.write({'departure': val}) elif journey.passenger_id.travel_id.date_start: journey.passenger_id.travel_id.write({'date_start': val}) elif field_name == 'date_stop': if journey.arrival: journey.write({'arrival': val}) elif journey.passenger_id.travel_id.date_stop: journey.passenger_id.travel_id.write({'date_stop': val}) def _default_class(self, cr, uid, context=None): ir_model_data = self.pool.get('ir.model.data') return ir_model_data.get_object_reference( cr, uid, 'travel_journey', 'travel_journey_class_directive', )[1] def _get_type(self, cr, uid, context=None): acc_type_obj = self.pool.get('travel.journey.type') ids = acc_type_obj.search(cr, uid, []) res = acc_type_obj.read(cr, uid, ids, ['code', 'name'], context) return [(r['code'], r['name']) for r in res] def create(self, cr, uid, vals, context=None): """If is_return is checked, create a return trip after.""" def clear_return_vals(mVals): mVals = mVals.copy() if mVals.get('is_return'): mVals['is_return'] = False mVals['return_origin'] = False mVals['return_destination'] = False mVals['return_departure'] = False mVals['return_arrival'] = False return mVals return_vals = None if vals.get('is_return'): return_vals = clear_return_vals(vals.copy()) return_vals['is_return'] = False return_vals['origin'] = vals.get('destination', False) return_vals['destination'] = vals.get('origin', False) return_vals['departure'] = vals.get('return_departure', False) return_vals['arrival'] = vals.get('return_arrival', False) vals = clear_return_vals(vals) res = super(travel_journey, self).create(cr, uid, vals, context=context) if return_vals: super(travel_journey, self).create(cr, uid, return_vals, context=context) return res @staticmethod def on_change_return(cr, uid, ids, key, location, context=None): return {'value': {key: location}} def on_change_times(self, cr, uid, ids, departure, arrival, return_trip=False, context=None): if self._check_dep_arr_dates(departure, arrival): return {} return { 'value': { 'return_arrival' if return_trip else 'arrival': False, }, 'warning': { 'title': 'Arrival after Departure', 'message': ('Departure (%s) cannot be before Arrival (%s).' % (departure, arrival)), }, } def check_date_exists(self, cr, uid, ids, context=None): if type(ids) is not list: ids = [ids] if not ids: # pragma: no cover return False journey = self.browse(cr, uid, ids[0], context=context) return journey.departure or journey.arrival def check_date_exists_return(self, cr, uid, ids, context=None): if type(ids) is not list: ids = [ids] if not ids: # pragma: no cover return False journey = self.browse(cr, uid, ids[0], context=context) return (not journey.is_return or journey.return_departure or journey.return_arrival) def check_date(self, cr, uid, ids, context=None): if type(ids) is not list: ids = [ids] if not ids: # pragma: no cover return False journey = self.browse(cr, uid, ids[0], context=context) return self._check_dep_arr_dates(journey.departure, journey.arrival) def check_date_return(self, cr, uid, ids, context=None): if type(ids) is not list: ids = [ids] if not ids: # pragma: no cover return False journey = self.browse(cr, uid, ids[0], context=context) return self._check_dep_arr_dates(journey.return_departure, journey.return_arrival) def check_uom(self, cr, uid, ids, context=None): if type(ids) is not list: ids = [ids] if not ids: # pragma: no cover return False journey = self.browse(cr, uid, ids[0], context=context) return not (bool(journey.baggage_weight) ^ bool(journey.baggage_weight_uom)) def name_get(self, cr, uid, ids, context=None): return [(journey.id, "%s (%s -> %s)" % (journey.passenger_id.partner_id.name, journey.origin.name_get()[0][1], journey.destination.name_get()[0][1])) for journey in self.browse(cr, uid, ids, context=context)] def company_get(self, cr, uid, ids, context=None): res = _("N/A") if type(ids) not in (int, long) and ids: ids = ids[0] journey = self.browse(cr, uid, ids, context=context) try: if journey.type: journey_class = self._journey_type_classes[journey.type] res = journey_class._company_typed_get(self, journey) except KeyError: _logger.error( _('Transportation type "%s" has not registered its ' 'class in _journey_types, skipping its company') % journey.type) except AttributeError: _logger.error( _('Transportation type "%s" has not registered a ' '_estimate_typed_date() function, skipping its company') % journey.type) finally: return res def origin_get(self, cr, uid, ids, context=None): if type(ids) is not list: ids = [ids] if ids: return self.browse(cr, uid, ids[0], context=context).origin def destination_get(self, cr, uid, ids, context=None): if type(ids) is not list: ids = [ids] if ids: return self.browse(cr, uid, ids[0], context=context).destination def departure_date_get(self, cr, uid, ids, context=None): if type(ids) is not list: ids = [ids] if ids: return self._estimate_date(cr, uid, ids, 'date_start', context=context)[ids[0]] def arrival_date_get(self, cr, uid, ids, context=None): if type(ids) is not list: ids = [ids] if ids: return self._estimate_date(cr, uid, ids, 'date_stop', context=context)[ids[0]] def departure_time_get(self, cr, uid, ids, context=None): if type(ids) is not list: ids = [ids] if ids: return self._estimate_time(cr, uid, ids, 'date_start', context=context)[ids[0]] def arrival_time_get(self, cr, uid, ids, context=None): if type(ids) is not list: ids = [ids] if ids: return self._estimate_time(cr, uid, ids, 'date_stop', context=context)[ids[0]] _columns = { 'origin': fields.many2one('res.better.zip', 'Origin', required='True', help='Source city of travel.'), 'destination': fields.many2one('res.better.zip', 'Destination', required='True', help='Destination city of travel.'), 'return_origin': fields.many2one('res.better.zip', 'Origin (return)'), 'return_destination': fields.many2one('res.better.zip', 'Destination (return)'), 'is_return': fields.boolean('Return Trip', help='Generate a return trip'), 'departure': fields.datetime('Desired Departure', help='Desired date and time of departure.'), 'arrival': fields.datetime('Desired Arrival', help='Desired date and time of Arrival.'), 'return_departure': fields.datetime('Desired Departure (return)'), 'return_arrival': fields.datetime('Desired Arrival (return)'), 'class_id': fields.many2one('travel.journey.class', 'Class', required=True, help='Desired class of voyage.'), 'baggage_qty': fields.integer('Baggage Quantity', help='Number of articles in baggage.'), 'baggage_weight': fields.float('Baggage Weight', help='Weight of baggage.'), 'baggage_weight_uom': fields.many2one('product.uom', 'Baggage Weight Unit of Measure', help='Unit of Measure for Baggage Weight'), 'comment': fields.text('Comments'), 'passenger_id': fields.many2one('travel.passenger', 'Passenger', required=True, help='Passenger on this journey.'), 'travel': fields.related('passenger_id', 'travel_name', type='char', string='Travel', store=True), 'state': fields.related('passenger_id', 'travel_state', type='selection', string='State', store=True), 'type': fields.selection(_get_type, 'Travel journey type', help='Travel journey type.'), 'reservation': fields.char('Reservation Number', size=256, help="Number of the ticket reservation."), 'cancellation': fields.text('Cancellation', help='Notes on cancellation.'), 'date_start': fields.function( _estimate_date, fnct_inv=_inv_estimate_date, type="date", help="Best estimate of start date calculated from filled fields."), 'date_stop': fields.function( _estimate_date, fnct_inv=_inv_estimate_date, type="date", help="Best estimate of end date calculated from filled fields."), } _defaults = {'class_id': _default_class} _constraints = [ (check_date_exists, _('A desired date of arrival or departure must be set on journey.'), ['departure', 'arrival']), (check_date_exists_return, _('A desired date of arrival or departure must be set on journey for ' 'return.'), ['return_departure', 'return_arrival']), (check_date, _('Departure date cannot be after arrival date on journey.'), ['departure', 'arrival']), (check_date_return, _('Departure date cannot be after arrival date on journey for ' 'return.'), ['return_departure', 'return_arrival']), (check_uom, _('Unit of Measure not specified for Baggage Weight.'), [ 'budget', 'budget_currency', ]) ]
def function_fn_write(model, cr, uid, id, field_name, field_value, fnct_inv_arg, context): """ just so CreatorCase.export can be used """ pass models = [ ('boolean', fields.boolean()), ('integer', fields.integer()), ('float', fields.float()), ('decimal', fields.float(digits=(16, 3))), ('string.bounded', fields.char('unknown', size=16)), ('string.required', fields.char('unknown', size=None, required=True)), ('string', fields.char('unknown', size=None)), ('date', fields.date()), ('datetime', fields.datetime()), ('text', fields.text()), ('selection', fields.selection([(1, "Foo"), (2, "Bar"), (3, "Qux"), (4, '')])), # here use size=-1 to store the values as integers instead of strings ('selection.function', fields.selection(selection_fn, size=-1)), # just relate to an integer ('many2one', fields.many2one('export.integer')), ('one2many', fields.one2many('export.one2many.child', 'parent_id')), ('many2many', fields.many2many('export.many2many.other')), ('function', fields.function(function_fn, fnct_inv=function_fn_write, type="integer")), # related: specialization of fields.function, should work the same way # TODO: reference ] for name, field in models: class NewModel(orm.Model):
with mute_logger('openerp.osv.orm'): location.check_access_rule('read', context=context) location_id = location.id except (ValueError, orm.except_orm), e: return False return location_id or False _columns = { 'location_id': fields.many2one( 'stock.location', 'Location', required=True, help='The location where you want the valuation (this will ' 'include all the child locations.'), 'to_date': fields.datetime( 'Date', help='Date at which the analysis need to be done.'), } _defaults = { 'location_id': _default_location, } def _get_product_qty(self, cr, uid, context=None): """Return all product ids that have a qty at the given location for the given date in the context. Use SQL for performance here. """ if context is None: context = {} location_id = context.get('location') location_obj = self.pool.get('stock.location') child_location_ids = location_obj.search(cr, uid,