def __new__(cls, name, bases, nmspc): columns = nmspc['_columns'] size = int(config.get_misc('analytic', 'analytic_size', 5)) for n in xrange(1, size + 1): columns['ns{}_id'.format(n)] = fields.one2many( 'analytic.structure', 'nd_id', "Generated Subset of Structures", domain=[('ordering', '=', n)], auto_join=True, ) return super(_dimension_meta, cls).__new__(cls, name, bases, nmspc)
class module(osv.osv): _name = "ir.module.module" _rec_name = "shortdesc" _description = "Module" def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False, submenu=False): res = super(module, self).fields_view_get(cr, uid, view_id=view_id, view_type=view_type, context=context, toolbar=toolbar, submenu=False) result = self.pool.get('ir.model.data').get_object_reference( cr, uid, 'base', 'action_server_module_immediate_install')[1] if view_type == 'form': if res.get('toolbar', False): list = [ rec for rec in res['toolbar']['action'] if rec.get('id', False) != result ] res['toolbar'] = {'action': list} return res @classmethod def get_module_info(cls, name): info = {} try: info = modules.load_information_from_description_file(name) except Exception: _logger.debug( 'Error when trying to fetch informations for ' 'module %s', name, exc_info=True) return info def _get_desc(self, cr, uid, ids, field_name=None, arg=None, context=None): res = dict.fromkeys(ids, '') for module in self.browse(cr, uid, ids, context=context): path = get_module_resource(module.name, 'static/description/index.html') if path: with tools.file_open(path, 'rb') as desc_file: doc = desc_file.read() html = lxml.html.document_fromstring(doc) for element, attribute, link, pos in html.iterlinks(): if element.get('src') and not '//' in element.get( 'src') and not 'static/' in element.get('src'): element.set( 'src', "/%s/static/description/%s" % (module.name, element.get('src'))) res[module.id] = lxml.html.tostring(html) else: overrides = { 'embed_stylesheet': False, 'doctitle_xform': False, 'output_encoding': 'unicode', 'xml_declaration': False, } output = publish_string(source=module.description or '', settings_overrides=overrides, writer=MyWriter()) res[module.id] = output return res def _get_latest_version(self, cr, uid, ids, field_name=None, arg=None, context=None): default_version = modules.adapt_version('1.0') res = dict.fromkeys(ids, default_version) for m in self.browse(cr, uid, ids): res[m.id] = self.get_module_info(m.name).get( 'version', default_version) return res def _get_views(self, cr, uid, ids, field_name=None, arg=None, context=None): res = {} model_data_obj = self.pool.get('ir.model.data') dmodels = [] if field_name is None or 'views_by_module' in field_name: dmodels.append('ir.ui.view') if field_name is None or 'reports_by_module' in field_name: dmodels.append('ir.actions.report.xml') if field_name is None or 'menus_by_module' in field_name: dmodels.append('ir.ui.menu') assert dmodels, "no models for %s" % field_name for module_rec in self.browse(cr, uid, ids, context=context): res_mod_dic = res[module_rec.id] = { 'menus_by_module': [], 'reports_by_module': [], 'views_by_module': [] } # Skip uninstalled modules below, no data to find anyway. if module_rec.state not in ('installed', 'to upgrade', 'to remove'): continue # then, search and group ir.model.data records imd_models = dict([(m, []) for m in dmodels]) imd_ids = model_data_obj.search(cr, uid, [('module', '=', module_rec.name), ('model', 'in', tuple(dmodels))]) for imd_res in model_data_obj.read(cr, uid, imd_ids, ['model', 'res_id'], context=context): imd_models[imd_res['model']].append(imd_res['res_id']) def browse(model): M = self.pool[model] # as this method is called before the module update, some xmlid may be invalid at this stage # explictly filter records before reading them ids = M.exists(cr, uid, imd_models.get(model, []), context) return M.browse(cr, uid, ids, context) def format_view(v): aa = v.inherit_id and '* INHERIT ' or '' return '%s%s (%s)' % (aa, v.name, v.type) res_mod_dic['views_by_module'] = map(format_view, browse('ir.ui.view')) res_mod_dic['reports_by_module'] = map( attrgetter('name'), browse('ir.actions.report.xml')) res_mod_dic['menus_by_module'] = map(attrgetter('complete_name'), browse('ir.ui.menu')) for key in res.iterkeys(): for k, v in res[key].iteritems(): res[key][k] = "\n".join(sorted(v)) return res def _get_icon_image(self, cr, uid, ids, field_name=None, arg=None, context=None): res = dict.fromkeys(ids, '') for module in self.browse(cr, uid, ids, context=context): path = get_module_resource(module.name, 'static', 'description', 'icon.png') if path: image_file = tools.file_open(path, 'rb') try: res[module.id] = image_file.read().encode('base64') finally: image_file.close() return res _columns = { 'name': fields.char("Technical Name", readonly=True, required=True, select=True), 'category_id': fields.many2one('ir.module.category', 'Category', readonly=True, select=True), 'shortdesc': fields.char('Module Name', readonly=True, translate=True), 'summary': fields.char('Summary', readonly=True, translate=True), 'description': fields.text("Description", readonly=True, translate=True), 'description_html': fields.function(_get_desc, string='Description HTML', type='html', method=True, readonly=True), 'author': fields.char("Author", readonly=True), 'maintainer': fields.char('Maintainer', readonly=True), 'contributors': fields.text('Contributors', readonly=True), 'website': fields.char("Website", readonly=True), # attention: Incorrect field names !! # installed_version refers the latest version (the one on disk) # latest_version refers the installed version (the one in database) # published_version refers the version available on the repository 'installed_version': fields.function(_get_latest_version, string='Latest Version', type='char'), 'latest_version': fields.char('Installed Version', readonly=True), 'published_version': fields.char('Published Version', readonly=True), 'url': fields.char('URL', readonly=True), 'sequence': fields.integer('Sequence'), 'dependencies_id': fields.one2many('ir.module.module.dependency', 'module_id', 'Dependencies', readonly=True), 'auto_install': fields.boolean( 'Automatic Installation', help='An auto-installable module is automatically installed by the ' 'system when all its dependencies are satisfied. ' 'If the module has no dependency, it is always installed.'), 'state': fields.selection([('uninstallable', 'Not Installable'), ('uninstalled', 'Not Installed'), ('installed', 'Installed'), ('to upgrade', 'To be upgraded'), ('to remove', 'To be removed'), ('to install', 'To be installed')], string='Status', readonly=True, select=True), 'demo': fields.boolean('Demo Data', readonly=True), 'license': fields.selection( [('GPL-2', 'GPL Version 2'), ('GPL-2 or any later version', 'GPL-2 or later version'), ('GPL-3', 'GPL Version 3'), ('GPL-3 or any later version', 'GPL-3 or later version'), ('AGPL-3', 'Affero GPL-3'), ('LGPL-3', 'LGPL Version 3'), ('Other OSI approved licence', 'Other OSI Approved Licence'), ('Other proprietary', 'Other Proprietary')], string='License', readonly=True), 'menus_by_module': fields.function(_get_views, string='Menus', type='text', multi="meta", store=True), 'reports_by_module': fields.function(_get_views, string='Reports', type='text', multi="meta", store=True), 'views_by_module': fields.function(_get_views, string='Views', type='text', multi="meta", store=True), 'application': fields.boolean('Application', readonly=True), 'icon': fields.char('Icon URL'), 'icon_image': fields.function(_get_icon_image, string='Icon', type="binary"), } _defaults = { 'state': 'uninstalled', 'sequence': 100, 'demo': False, 'license': 'AGPL-3', } _order = 'sequence,name' def _name_uniq_msg(self, cr, uid, ids, context=None): return _('The name of the module must be unique !') _sql_constraints = [ ('name_uniq', 'UNIQUE (name)', _name_uniq_msg), ] def unlink(self, cr, uid, ids, context=None): if not ids: return True if isinstance(ids, (int, long)): ids = [ids] mod_names = [] for mod in self.read(cr, uid, ids, ['state', 'name'], context): if mod['state'] in ('installed', 'to upgrade', 'to remove', 'to install'): raise UserError( _('You try to remove a module that is installed or will be installed' )) mod_names.append(mod['name']) #Removing the entry from ir_model_data #ids_meta = self.pool.get('ir.model.data').search(cr, uid, [('name', '=', 'module_meta_information'), ('module', 'in', mod_names)]) #if ids_meta: # self.pool.get('ir.model.data').unlink(cr, uid, ids_meta, context) return super(module, self).unlink(cr, uid, ids, context=context) @staticmethod def _check_external_dependencies(terp): depends = terp.get('external_dependencies') if not depends: return for pydep in depends.get('python', []): try: importlib.import_module(pydep) except ImportError: raise ImportError('No module named %s' % (pydep, )) for binary in depends.get('bin', []): try: tools.find_in_path(binary) except IOError: raise Exception('Unable to find %r in path' % (binary, )) @classmethod def check_external_dependencies(cls, module_name, newstate='to install'): terp = cls.get_module_info(module_name) try: cls._check_external_dependencies(terp) except Exception, e: if newstate == 'to install': msg = _( 'Unable to install module "%s" because an external dependency is not met: %s' ) elif newstate == 'to upgrade': msg = _( 'Unable to upgrade module "%s" because an external dependency is not met: %s' ) else: msg = _( 'Unable to process module "%s" because an external dependency is not met: %s' ) raise UserError(msg % (module_name, e.args[0]))
class tms_maintenance_order(osv.Model): _inherit = ['mail.thread', 'ir.needaction_mixin'] _name = 'tms.maintenance.order' _description = 'Order Maintenace' ########################### Columnas : Atributos ####################################################################### _columns = { 'name': fields.char('Order Maintenance'), 'description': fields.char('Description'), 'notes': fields.text('Notes'), 'state': fields.selection([('draft', 'Draft'), ('confirmed', 'Confirmed'), ('done', 'Done'), ('cancel', 'Cancelled')], 'Estados'), 'cheduled_start': fields.datetime('Cheduled Start'), 'cheduled_end': fields.datetime('Cheduled End'), 'cheduled_start_real': fields.datetime('Cheduled Start Real'), 'cheduled_end_real': fields.datetime('Cheduled End Real'), ########Many2One########### 'unit_id': fields.many2one('tms.unit', 'Unit'), 'concept_id': fields.many2one('product.product', 'Concept Maintenance'), 'supervisor_id': fields.many2one('hr.employee', 'Supervisor'), 'driver_report_id': fields.many2one('hr.employee', 'Driver Report'), 'user_register_order_id': fields.many2one('hr.employee', 'User Register Report'), ########One2Many########### 'activities_ids': fields.one2many('tms.maintenance.order.activity', 'maintenance_order_id', 'Activities'), } ########################### Metodos #################################################################################### ########## Metodos para el 'state' ########## def action_draft(self, cr, uid, ids, context={}): self.write(cr, uid, ids, {'state': 'draft'}) return True def action_confirmed(self, cr, uid, ids, context=None): self.write(cr, uid, ids, {'state': 'confirmed'}) return True def action_done(self, cr, uid, ids, context={}): self.write(cr, uid, ids, {'state': 'done'}) return True def action_cancel(self, cr, uid, ids, context=None): self.write(cr, uid, ids, {'state': 'cancel'}) return True ########################### Valores por Defecto ######################################################################## _defaults = { 'state': lambda *a: 'draft', } ########################### Criterio de ordenamiento ################################################################### _order = 'name'
'author': fields.char("Author", size=128, readonly=True), 'maintainer': fields.char('Maintainer', size=128, readonly=True), 'contributors': fields.text('Contributors', readonly=True), 'website': fields.char("Website", size=256, readonly=True), # attention: Incorrect field names !! # installed_version refers the latest version (the one on disk) # latest_version refers the installed version (the one in database) # published_version refers the version available on the repository 'installed_version': fields.function(_get_latest_version, string='Latest Version', type='char'), 'latest_version': fields.char('Installed Version', size=64, readonly=True), 'published_version': fields.char('Published Version', size=64, readonly=True), 'url': fields.char('URL', size=128, readonly=True), 'sequence': fields.integer('Sequence'), 'dependencies_id': fields.one2many('ir.module.module.dependency', 'module_id', 'Dependencies', readonly=True), 'auto_install': fields.boolean('Automatic Installation', help='An auto-installable module is automatically installed by the ' 'system when all its dependencies are satisfied. ' 'If the module has no dependency, it is always installed.'), 'state': fields.selection([ ('uninstallable', 'Not Installable'), ('uninstalled', 'Not Installed'), ('installed', 'Installed'), ('to upgrade', 'To be upgraded'), ('to remove', 'To be removed'), ('to install', 'To be installed') ], string='Status', readonly=True, select=True), 'demo': fields.boolean('Demo Data', readonly=True), 'license': fields.selection([ ('GPL-2', 'GPL Version 2'),
except osv.except_osv, e: # no suitable delivery method found, probably configuration error _logger.error("Carrier %s: %s\n%s" % (carrier.name, e.name, e.value)) price = 0.0 else: price = 0.0 res[carrier.id] = {"price": price, "available": available} return res _columns = { "name": fields.char("Delivery Method", required=True), "partner_id": fields.many2one( "res.partner", "Transport Company", required=True, help="The partner that is doing the delivery service." ), "product_id": fields.many2one("product.product", "Delivery Product", required=True), "grids_id": fields.one2many("delivery.grid", "carrier_id", "Delivery Grids"), "available": fields.function( get_price, string="Available", type="boolean", multi="price", help="Is the carrier method possible with the current order.", ), "price": fields.function(get_price, string="Price", multi="price"), "active": fields.boolean( "Active", help="If the active field is set to False, it will allow you to hide the delivery carrier without removing it.", ), "normal_price": fields.float( "Normal Price", help="Keep empty if the pricing depends on the advanced pricing per destination" ),
'ups_shipper_id': fields.many2one('ups.account.shipping', 'Shipping Account'), ======= 'ups_shipper_id': fields.many2one('ups.account.shipping', 'Shipper'), >>>>>>> c1979f64b3360c86d60e00c92be0271d89f97f2d 'ups_service_id': fields.many2one('ups.shipping.service.type', 'Service Type'), 'ups_pickup_type': fields.selection([ ('01', 'Daily Pickup'), ('03', 'Customer Counter'), ('06', 'One Time Pickup'), ('07', 'On Call Air'), ('11', 'Suggested Retail Rates'), ('19', 'Letter Center'), ('20', 'Air Service Center'), ], 'Pickup Type'), 'ups_packaging_type': fields.many2one('shipping.package.type', 'Packaging Type'), 'shipping_rates': fields.one2many('shipping.rates.sales', 'sales_id', 'Rate Quotes'), 'status_message': fields.char('Status', size=128, readonly=True), # From partner address validation 'address_validation_method': fields.selection(_method_get, 'Address Validation Method', size=32), } def _get_sale_account(self, cr, uid, context=None): if context is None: context = {} logsitic_obj = self.pool.get('logistic.company') user_rec = self.pool.get('res.users').browse(cr , uid, uid, context) logis_company = logsitic_obj.search(cr, uid, []) if not logis_company: return False return logsitic_obj.browse(cr, uid, logis_company[0], context).ship_account_id.id
FISCAL_RULE_COLUMNS = { "partner_fiscal_type_id": fields.many2one("l10n_br_account.partner.fiscal.type", "Tipo Fiscal do Parceiro"), "fiscal_category_id": fields.many2one("l10n_br_account.fiscal.category", "Categoria"), "fiscal_type": fields.selection(COMPANY_FISCAL_TYPE, u"Regime Tributário", required=True), "revenue_start": fields.float( "Faturamento Inicial", digits_compute=dp.get_precision("Account"), help="Faixa inicial de faturamento bruto" ), "revenue_end": fields.float( "Faturamento Final", digits_compute=dp.get_precision("Account"), help="Faixa inicial de faturamento bruto" ), } OTHERS_FISCAL_RULE_COLUMNS_TEMPLATE = { "parent_id": fields.many2one("account.fiscal.position.rule.template", "Regra Pai"), "child_ids": fields.one2many("account.fiscal.position.rule.template", "parent_id", "Regras Filhas"), } OTHERS_FISCAL_RULE_COLUMNS = { "parent_id": fields.many2one("account.fiscal.position.rule", "Regra Pai"), "child_ids": fields.one2many("account.fiscal.position.rule", "parent_id", "Regras Filhas"), } FISCAL_RULE_DEFAULTS = {"fiscal_type": COMPANY_FISCAL_TYPE_DEFAULT, "revenue_start": 0.00, "revenue_end": 0.00} class AccountFiscalPositionRuleTemplate(orm.Model): _inherit = "account.fiscal.position.rule.template" _columns = dict(FISCAL_RULE_COLUMNS.items() + OTHERS_FISCAL_RULE_COLUMNS_TEMPLATE.items()) _defaults = FISCAL_RULE_DEFAULTS
_columns = { 'name' : fields.char('Name', required=True), 'partner_id' : fields.many2one('res.partner','Principle',domain=[('supplier','=',True)],required=True), 'product_id' : fields.many2one('product.product','Bonus Product'), 'qty_2' : fields.float('Bonus Qty2', digits_compute=dp.get_precision('Product Unit of Measure')), 'qty' : fields.function(_qty_all_1,type="float",string='Bonus Qty',digits_compute=dp.get_precision('Product Unit of Measure')), 'uom_id' : fields.many2one('product.uom','UoM',required=True), 'uom_id2' : fields.many2one('product.uom','UoM',required=True), 'value' : fields.float('Price Value',domain=[('is_percent','=',False)]), 'per_product' : fields.boolean('Per Product'), 'persentase' : fields.float('Percent Value', digits_compute= dp.get_precision('Discount'),domain=[('is_percent','=',True)]), 'multi' : fields.boolean('Multiples'), 'is_active' : fields.boolean('Active?'), 'date_from' : fields.date('Start Date', required=True), 'date_to' : fields.date('End Date', required=True), 'condition_ids' : fields.one2many('master.condition','discount_id','Value Condition'), 'condition2_ids' : fields.one2many('master.condition2','discount_id','Product Condition'), 'condition3_ids' : fields.one2many('master.condition3','discount_id','Product Condition 2'), 'condition4_ids' : fields.one2many('master.condition4','discount_id','Product Condition 3'), 'condition5_ids' : fields.one2many('master.condition5','discount_id','Product Condition 4'), 'group_price_ids' : fields.many2many('res.partner.category', id1='discount_id', id2='category_id', string='Group Price Category'), 'is_percent' : fields.boolean('Is Percent'), 'is_flat' : fields.boolean('Flat'), 'type' :fields.selection([('regular','Regular Discount'),('promo','Promo Discount'),('extra','Extra Discount'),('cash','Cash Discount'),('mix','Mix Discount')],string='Type Discount',required=True), 'min_qty_product' : fields.float('Min. Product Item',digits_compute=dp.get_precision('Product Unit of Measure')), 'multi2' : fields.boolean('Value Condition'), 'multi3' : fields.boolean('Multiples for New Product'), # 'multi_sel' : fields.selection([('general','General Multiples'),('specific','Specific Multiples for New Product')],string="Multiples"), 'product_id2' : fields.many2one('product.product','Bonus New Product'), 'qty2_2' : fields.float('Bonus Qty', digits_compute=dp.get_precision('Product Unit of Measure')), 'qty2' : fields.function(_qty_all_2,type="float",string='Bonus Qty',digits_compute=dp.get_precision('Product Unit of Measure')),
class MergePartnerAutomatic(osv.TransientModel): """ The idea behind this wizard is to create a list of potential partners to merge. We use two objects, the first one is the wizard for the end-user. And the second will contain the partner list to merge. """ _name = 'base.partner.merge.automatic.wizard' _columns = { # Group by 'group_by_email': fields.boolean('Email'), 'group_by_name': fields.boolean('Name'), 'group_by_is_company': fields.boolean('Is Company'), 'group_by_vat': fields.boolean('VAT'), 'group_by_parent_id': fields.boolean('Parent Company'), 'state': fields.selection([('option', 'Option'), ('selection', 'Selection'), ('finished', 'Finished')], 'State', readonly=True, required=True), 'number_group': fields.integer("Group of Contacts", readonly=True), 'current_line_id': fields.many2one('base.partner.merge.line', 'Current Line'), 'line_ids': fields.one2many('base.partner.merge.line', 'wizard_id', 'Lines'), 'partner_ids': fields.many2many('res.partner', string='Contacts'), 'dst_partner_id': fields.many2one('res.partner', string='Destination Contact'), 'exclude_contact': fields.boolean('A user associated to the contact'), 'exclude_journal_item': fields.boolean('Journal Items associated to the contact'), 'maximum_group': fields.integer("Maximum of Group of Contacts"), } def default_get(self, cr, uid, fields, context=None): if context is None: context = {} res = super(MergePartnerAutomatic, self).default_get(cr, uid, fields, context) if context.get('active_model') == 'res.partner' and context.get( 'active_ids'): partner_ids = context['active_ids'] res['state'] = 'selection' res['partner_ids'] = partner_ids res['dst_partner_id'] = self._get_ordered_partner( cr, uid, partner_ids, context=context)[-1].id return res _defaults = {'state': 'option'} def get_fk_on(self, cr, table): q = """ SELECT cl1.relname as table, att1.attname as column FROM pg_constraint as con, pg_class as cl1, pg_class as cl2, pg_attribute as att1, pg_attribute as att2 WHERE con.conrelid = cl1.oid AND con.confrelid = cl2.oid AND array_lower(con.conkey, 1) = 1 AND con.conkey[1] = att1.attnum AND att1.attrelid = cl1.oid AND cl2.relname = %s AND att2.attname = 'id' AND array_lower(con.confkey, 1) = 1 AND con.confkey[1] = att2.attnum AND att2.attrelid = cl2.oid AND con.contype = 'f' """ return cr.execute(q, (table, )) def _update_foreign_keys(self, cr, uid, src_partners, dst_partner, context=None): _logger.debug( '_update_foreign_keys for dst_partner: %s for src_partners: %r', dst_partner.id, list(map(operator.attrgetter('id'), src_partners))) # find the many2one relation to a partner proxy = self.pool.get('res.partner') self.get_fk_on(cr, 'res_partner') # ignore two tables for table, column in cr.fetchall(): if 'base_partner_merge_' in table: continue partner_ids = tuple(map(int, src_partners)) query = "SELECT column_name FROM information_schema.columns WHERE table_name LIKE '%s'" % ( table) cr.execute(query, ()) columns = [] for data in cr.fetchall(): if data[0] != column: columns.append(data[0]) query_dic = { 'table': table, 'column': column, 'value': columns[0], } if len(columns) <= 1: # unique key treated query = """ UPDATE "%(table)s" as ___tu SET %(column)s = %%s WHERE %(column)s = %%s AND NOT EXISTS ( SELECT 1 FROM "%(table)s" as ___tw WHERE %(column)s = %%s AND ___tu.%(value)s = ___tw.%(value)s )""" % query_dic for partner_id in partner_ids: cr.execute(query, (dst_partner.id, partner_id, dst_partner.id)) else: try: with mute_logger('openerp.sql_db'), cr.savepoint(): query = 'UPDATE "%(table)s" SET %(column)s = %%s WHERE %(column)s IN %%s' % query_dic cr.execute(query, ( dst_partner.id, partner_ids, )) if column == proxy._parent_name and table == 'res_partner': query = """ WITH RECURSIVE cycle(id, parent_id) AS ( SELECT id, parent_id FROM res_partner UNION SELECT cycle.id, res_partner.parent_id FROM res_partner, cycle WHERE res_partner.id = cycle.parent_id AND cycle.id != cycle.parent_id ) SELECT id FROM cycle WHERE id = parent_id AND id = %s """ cr.execute(query, (dst_partner.id, )) except psycopg2.Error: # updating fails, most likely due to a violated unique constraint # keeping record with nonexistent partner_id is useless, better delete it query = 'DELETE FROM %(table)s WHERE %(column)s = %%s' % query_dic cr.execute(query, (partner_id, )) def _update_reference_fields(self, cr, uid, src_partners, dst_partner, context=None): _logger.debug( '_update_reference_fields for dst_partner: %s for src_partners: %r', dst_partner.id, list(map(operator.attrgetter('id'), src_partners))) def update_records(model, src, field_model='model', field_id='res_id', context=None): proxy = self.pool.get(model) if proxy is None: return domain = [(field_model, '=', 'res.partner'), (field_id, '=', src.id)] ids = proxy.search(cr, openerp.SUPERUSER_ID, domain, context=context) try: with mute_logger('openerp.sql_db'), cr.savepoint(): return proxy.write(cr, openerp.SUPERUSER_ID, ids, {field_id: dst_partner.id}, context=context) except psycopg2.Error: # updating fails, most likely due to a violated unique constraint # keeping record with nonexistent partner_id is useless, better delete it return proxy.unlink(cr, openerp.SUPERUSER_ID, ids, context=context) update_records = functools.partial(update_records, context=context) for partner in src_partners: update_records('calendar', src=partner, field_model='model_id.model') update_records('ir.attachment', src=partner, field_model='res_model') update_records('mail.followers', src=partner, field_model='res_model') update_records('mail.message', src=partner) update_records('marketing.campaign.workitem', src=partner, field_model='object_id.model') update_records('ir.model.data', src=partner) proxy = self.pool['ir.model.fields'] domain = [('ttype', '=', 'reference')] record_ids = proxy.search(cr, openerp.SUPERUSER_ID, domain, context=context) for record in proxy.browse(cr, openerp.SUPERUSER_ID, record_ids, context=context): try: proxy_model = self.pool[record.model] field_type = proxy_model._columns[record.name].__class__._type except KeyError: # unknown model or field => skip continue if field_type == 'function': continue for partner in src_partners: domain = [(record.name, '=', 'res.partner,%d' % partner.id)] model_ids = proxy_model.search(cr, openerp.SUPERUSER_ID, domain, context=context) values = { record.name: 'res.partner,%d' % dst_partner.id, } proxy_model.write(cr, openerp.SUPERUSER_ID, model_ids, values, context=context) def _update_values(self, cr, uid, src_partners, dst_partner, context=None): _logger.debug( '_update_values for dst_partner: %s for src_partners: %r', dst_partner.id, list(map(operator.attrgetter('id'), src_partners))) columns = dst_partner._columns def write_serializer(column, item): if isinstance(item, browse_record): return item.id else: return item values = dict() for column, field in columns.iteritems(): if field._type not in ('many2many', 'one2many') and not isinstance( field, fields.function): for item in itertools.chain(src_partners, [dst_partner]): if item[column]: values[column] = write_serializer(column, item[column]) values.pop('id', None) parent_id = values.pop('parent_id', None) dst_partner.write(values) if parent_id and parent_id != dst_partner.id: try: dst_partner.write({'parent_id': parent_id}) except (osv.except_osv, orm.except_orm): _logger.info( 'Skip recursive partner hierarchies for parent_id %s of partner: %s', parent_id, dst_partner.id) @mute_logger('openerp.osv.expression', 'openerp.models') def _merge(self, cr, uid, partner_ids, dst_partner=None, context=None): proxy = self.pool.get('res.partner') partner_ids = proxy.exists(cr, uid, list(partner_ids), context=context) if len(partner_ids) < 2: return if len(partner_ids) > 3: raise osv.except_osv( _('Error'), _("For safety reasons, you cannot merge more than 3 contacts together. You can re-open the wizard several times if needed." )) if openerp.SUPERUSER_ID != uid and len( set(partner.email for partner in proxy.browse( cr, uid, partner_ids, context=context))) > 1: raise osv.except_osv( _('Error'), _("All contacts must have the same email. Only the Administrator can merge contacts with different emails." )) if dst_partner and dst_partner.id in partner_ids: src_partners = proxy.browse( cr, uid, [id for id in partner_ids if id != dst_partner.id], context=context) else: ordered_partners = self._get_ordered_partner( cr, uid, partner_ids, context) dst_partner = ordered_partners[-1] src_partners = ordered_partners[:-1] _logger.info("dst_partner: %s", dst_partner.id) if openerp.SUPERUSER_ID != uid and self._model_is_installed(cr, uid, 'account.move.line', context=context) and \ self.pool.get('account.move.line').search(cr, openerp.SUPERUSER_ID, [('partner_id', 'in', [partner.id for partner in src_partners])], context=context): raise osv.except_osv( _('Error'), _("Only the destination contact may be linked to existing Journal Items. Please ask the Administrator if you need to merge several contacts linked to existing Journal Items." )) call_it = lambda function: function( cr, uid, src_partners, dst_partner, context=context) call_it(self._update_foreign_keys) call_it(self._update_reference_fields) call_it(self._update_values) _logger.info('(uid = %s) merged the partners %r with %s', uid, list(map(operator.attrgetter('id'), src_partners)), dst_partner.id) dst_partner.message_post(body='%s %s' % (_("Merged with the following partners:"), ", ".join('%s<%s>(ID %s)' % (p.name, p.email or 'n/a', p.id) for p in src_partners))) for partner in src_partners: partner.unlink() def clean_emails(self, cr, uid, context=None): """ Clean the email address of the partner, if there is an email field with a mimum of two addresses, the system will create a new partner, with the information of the previous one and will copy the new cleaned email into the email field. """ context = dict(context or {}) proxy_model = self.pool['ir.model.fields'] field_ids = proxy_model.search(cr, uid, [('model', '=', 'res.partner'), ('ttype', 'like', '%2many')], context=context) fields = proxy_model.read(cr, uid, field_ids, context=context) reset_fields = dict((field['name'], []) for field in fields) proxy_partner = self.pool['res.partner'] context['active_test'] = False ids = proxy_partner.search(cr, uid, [], context=context) fields = ['name', 'var' 'partner_id' 'is_company', 'email'] partners = proxy_partner.read(cr, uid, ids, fields, context=context) partners.sort(key=operator.itemgetter('id')) partners_len = len(partners) _logger.info('partner_len: %r', partners_len) for idx, partner in enumerate(partners): if not partner['email']: continue percent = (idx / float(partners_len)) * 100.0 _logger.info('idx: %r', idx) _logger.info('percent: %r', percent) try: emails = sanitize_email(partner['email']) head, tail = emails[:1], emails[1:] email = head[0] if head else False proxy_partner.write(cr, uid, [partner['id']], {'email': email}, context=context) for email in tail: values = dict(reset_fields, email=email) proxy_partner.copy(cr, uid, partner['id'], values, context=context) except Exception: _logger.exception("There is a problem with this partner: %r", partner) raise return True def close_cb(self, cr, uid, ids, context=None): return {'type': 'ir.actions.act_window_close'} def _generate_query(self, fields, maximum_group=100): sql_fields = [] for field in fields: if field in ['email', 'name']: sql_fields.append('lower(%s)' % field) elif field in ['vat']: sql_fields.append("replace(%s, ' ', '')" % field) else: sql_fields.append(field) group_fields = ', '.join(sql_fields) filters = [] for field in fields: if field in ['email', 'name', 'vat']: filters.append((field, 'IS NOT', 'NULL')) criteria = ' AND '.join('%s %s %s' % (field, operator, value) for field, operator, value in filters) text = [ "SELECT min(id), array_agg(id)", "FROM res_partner", ] if criteria: text.append('WHERE %s' % criteria) text.extend([ "GROUP BY %s" % group_fields, "HAVING COUNT(*) >= 2", "ORDER BY min(id)", ]) if maximum_group: text.extend([ "LIMIT %s" % maximum_group, ]) return ' '.join(text) def _compute_selected_groupby(self, this): group_by_str = 'group_by_' group_by_len = len(group_by_str) fields = [ key[group_by_len:] for key in self._columns.keys() if key.startswith(group_by_str) ] groups = [ field for field in fields if getattr(this, '%s%s' % (group_by_str, field), False) ] if not groups: raise osv.except_osv( _('Error'), _("You have to specify a filter for your selection")) return groups def next_cb(self, cr, uid, ids, context=None): """ Don't compute any thing """ context = dict(context or {}, active_test=False) this = self.browse(cr, uid, ids[0], context=context) if this.current_line_id: this.current_line_id.unlink() return self._next_screen(cr, uid, this, context) def _get_ordered_partner(self, cr, uid, partner_ids, context=None): partners = self.pool.get('res.partner').browse(cr, uid, list(partner_ids), context=context) ordered_partners = sorted(sorted( partners, key=operator.attrgetter('create_date'), reverse=True), key=operator.attrgetter('active'), reverse=True) return ordered_partners def _next_screen(self, cr, uid, this, context=None): this.refresh() values = {} if this.line_ids: # in this case, we try to find the next record. current_line = this.line_ids[0] current_partner_ids = literal_eval(current_line.aggr_ids) values.update({ 'current_line_id': current_line.id, 'partner_ids': [(6, 0, current_partner_ids)], 'dst_partner_id': self._get_ordered_partner(cr, uid, current_partner_ids, context)[-1].id, 'state': 'selection', }) else: values.update({ 'current_line_id': False, 'partner_ids': [], 'state': 'finished', }) this.write(values) return { 'type': 'ir.actions.act_window', 'res_model': this._name, 'res_id': this.id, 'view_mode': 'form', 'target': 'new', } def _model_is_installed(self, cr, uid, model, context=None): proxy = self.pool.get('ir.model') domain = [('model', '=', model)] return proxy.search_count(cr, uid, domain, context=context) > 0 def _partner_use_in(self, cr, uid, aggr_ids, models, context=None): """ Check if there is no occurence of this group of partner in the selected model """ for model, field in models.iteritems(): proxy = self.pool.get(model) domain = [(field, 'in', aggr_ids)] if proxy.search_count(cr, uid, domain, context=context): return True return False def compute_models(self, cr, uid, ids, context=None): """ Compute the different models needed by the system if you want to exclude some partners. """ assert is_integer_list(ids) this = self.browse(cr, uid, ids[0], context=context) models = {} if this.exclude_contact: models['res.users'] = 'partner_id' if self._model_is_installed( cr, uid, 'account.move.line', context=context) and this.exclude_journal_item: models['account.move.line'] = 'partner_id' return models def _process_query(self, cr, uid, ids, query, context=None): """ Execute the select request and write the result in this wizard """ proxy = self.pool.get('base.partner.merge.line') this = self.browse(cr, uid, ids[0], context=context) models = self.compute_models(cr, uid, ids, context=context) cr.execute(query) counter = 0 for min_id, aggr_ids in cr.fetchall(): if models and self._partner_use_in( cr, uid, aggr_ids, models, context=context): continue values = { 'wizard_id': this.id, 'min_id': min_id, 'aggr_ids': aggr_ids, } proxy.create(cr, uid, values, context=context) counter += 1 values = { 'state': 'selection', 'number_group': counter, } this.write(values) _logger.info("counter: %s", counter) def start_process_cb(self, cr, uid, ids, context=None): """ Start the process. * Compute the selected groups (with duplication) * If the user has selected the 'exclude_XXX' fields, avoid the partners. """ assert is_integer_list(ids) context = dict(context or {}, active_test=False) this = self.browse(cr, uid, ids[0], context=context) groups = self._compute_selected_groupby(this) query = self._generate_query(groups, this.maximum_group) self._process_query(cr, uid, ids, query, context=context) return self._next_screen(cr, uid, this, context) def automatic_process_cb(self, cr, uid, ids, context=None): assert is_integer_list(ids) this = self.browse(cr, uid, ids[0], context=context) this.start_process_cb() this.refresh() for line in this.line_ids: partner_ids = literal_eval(line.aggr_ids) self._merge(cr, uid, partner_ids, context=context) line.unlink() cr.commit() this.write({'state': 'finished'}) return { 'type': 'ir.actions.act_window', 'res_model': this._name, 'res_id': this.id, 'view_mode': 'form', 'target': 'new', } def parent_migration_process_cb(self, cr, uid, ids, context=None): assert is_integer_list(ids) context = dict(context or {}, active_test=False) this = self.browse(cr, uid, ids[0], context=context) query = """ SELECT min(p1.id), array_agg(DISTINCT p1.id) FROM res_partner as p1 INNER join res_partner as p2 ON p1.email = p2.email AND p1.name = p2.name AND (p1.parent_id = p2.id OR p1.id = p2.parent_id) WHERE p2.id IS NOT NULL GROUP BY p1.email, p1.name, CASE WHEN p1.parent_id = p2.id THEN p2.id ELSE p1.id END HAVING COUNT(*) >= 2 ORDER BY min(p1.id) """ self._process_query(cr, uid, ids, query, context=context) for line in this.line_ids: partner_ids = literal_eval(line.aggr_ids) self._merge(cr, uid, partner_ids, context=context) line.unlink() cr.commit() this.write({'state': 'finished'}) cr.execute(""" UPDATE res_partner SET is_company = NULL, parent_id = NULL WHERE parent_id = id """) return { 'type': 'ir.actions.act_window', 'res_model': this._name, 'res_id': this.id, 'view_mode': 'form', 'target': 'new', } def update_all_process_cb(self, cr, uid, ids, context=None): assert is_integer_list(ids) # WITH RECURSIVE cycle(id, parent_id) AS ( # SELECT id, parent_id FROM res_partner # UNION # SELECT cycle.id, res_partner.parent_id # FROM res_partner, cycle # WHERE res_partner.id = cycle.parent_id AND # cycle.id != cycle.parent_id # ) # UPDATE res_partner # SET parent_id = NULL # WHERE id in (SELECT id FROM cycle WHERE id = parent_id); this = self.browse(cr, uid, ids[0], context=context) self.parent_migration_process_cb(cr, uid, ids, context=None) list_merge = [ { 'group_by_vat': True, 'group_by_email': True, 'group_by_name': True }, # {'group_by_name': True, 'group_by_is_company': True, 'group_by_parent_id': True}, # {'group_by_email': True, 'group_by_is_company': True, 'group_by_parent_id': True}, # {'group_by_name': True, 'group_by_vat': True, 'group_by_is_company': True, 'exclude_journal_item': True}, # {'group_by_email': True, 'group_by_vat': True, 'group_by_is_company': True, 'exclude_journal_item': True}, # {'group_by_email': True, 'group_by_is_company': True, 'exclude_contact': True, 'exclude_journal_item': True}, # {'group_by_name': True, 'group_by_is_company': True, 'exclude_contact': True, 'exclude_journal_item': True} ] for merge_value in list_merge: id = self.create(cr, uid, merge_value, context=context) self.automatic_process_cb(cr, uid, [id], context=context) cr.execute(""" UPDATE res_partner SET is_company = NULL WHERE parent_id IS NOT NULL AND is_company IS NOT NULL """) # cr.execute(""" # UPDATE # res_partner as p1 # SET # is_company = NULL, # parent_id = ( # SELECT p2.id # FROM res_partner as p2 # WHERE p2.email = p1.email AND # p2.parent_id != p2.id # LIMIT 1 # ) # WHERE # p1.parent_id = p1.id # """) return self._next_screen(cr, uid, this, context) def merge_cb(self, cr, uid, ids, context=None): assert is_integer_list(ids) context = dict(context or {}, active_test=False) this = self.browse(cr, uid, ids[0], context=context) partner_ids = set(map(int, this.partner_ids)) if not partner_ids: this.write({'state': 'finished'}) return { 'type': 'ir.actions.act_window', 'res_model': this._name, 'res_id': this.id, 'view_mode': 'form', 'target': 'new', } self._merge(cr, uid, partner_ids, this.dst_partner_id, context=context) if this.current_line_id: this.current_line_id.unlink() return self._next_screen(cr, uid, this, context) def auto_set_parent_id(self, cr, uid, ids, context=None): assert is_integer_list(ids) # select partner who have one least invoice partner_treated = ['@gmail.com'] cr.execute(""" SELECT p.id, p.email FROM res_partner as p LEFT JOIN account_invoice as a ON p.id = a.partner_id AND a.state in ('open','paid') WHERE p.grade_id is NOT NULL GROUP BY p.id ORDER BY COUNT(a.id) DESC """) re_email = re.compile(r".*@") for id, email in cr.fetchall(): # check email domain email = re_email.sub("@", email or "") if not email or email in partner_treated: continue partner_treated.append(email) # don't update the partners if they are more of one who have invoice cr.execute(""" SELECT * FROM res_partner as p WHERE p.id != %s AND p.email LIKE '%%%s' AND EXISTS (SELECT * FROM account_invoice as a WHERE p.id = a.partner_id AND a.state in ('open','paid')) """ % (id, email)) if len(cr.fetchall()) > 1: _logger.info("%s MORE OF ONE COMPANY", email) continue # to display changed values cr.execute(""" SELECT id,email FROM res_partner WHERE parent_id != %s AND id != %s AND email LIKE '%%%s' """ % (id, id, email)) _logger.info("%r", cr.fetchall()) # upgrade cr.execute(""" UPDATE res_partner SET parent_id = %s WHERE id != %s AND email LIKE '%%%s' """ % (id, id, email)) return False
class hr_rpt_attend_emp_day(osv.osv_memory): _name = "hr.rpt.attend.emp.day" _inherit = "rpt.base" _description = "HR Attendance Employee Day Report" _columns = { #report data lines 'rpt_lines': fields.one2many('hr.rpt.attend.emp.day.line', 'rpt_id', string='Report Line'), 'date_from': fields.datetime("Start Date", required=True), 'date_to': fields.datetime("End Date", required=True), 'emp_ids': fields.many2many('hr.employee', string='Employees'), } _defaults = { 'type': 'attend_emp_day', # 'emp_ids':[342,171] } def default_get(self, cr, uid, fields, context=None): vals = super(hr_rpt_attend_emp_day, self).default_get(cr, uid, fields, context=context) if 'date_from' in fields: #For the datetime value in defaults, need convert the local time to UTC, the web framework will convert them back to local time on GUI date_from = datetime.strptime(time.strftime('%Y-%m-01 00:00:00'), '%Y-%m-%d %H:%M:%S') date_from_utc = utils.utc_timestamp(cr, uid, date_from, context) vals.update({ 'date_from': date_from_utc.strftime(DEFAULT_SERVER_DATETIME_FORMAT) }) if 'date_to' in fields: date_to = datetime.strptime(time.strftime('%Y-%m-%d 23:59:59'), '%Y-%m-%d %H:%M:%S') date_to_utc = utils.utc_timestamp(cr, uid, date_to, context) vals.update({ 'date_to': date_to_utc.strftime(DEFAULT_SERVER_DATETIME_FORMAT) }) return vals def _check_dates(self, cr, uid, ids, context=None): for wiz in self.browse(cr, uid, ids, context=context): if wiz.date_from and wiz.date_to and wiz.date_from > wiz.date_to: return False return True _constraints = [ (_check_dates, 'The date end must be after the date start.', ['date_from', 'date_to']), ] def get_report_name(self, cr, uid, id, rpt_name, context=None): return "Attendance Employee Day Report" def name_get(self, cr, uid, ids, context=None): if not ids: return [] res = [] for id in ids: res.append((id, '%s' % (id, ))) return res def _convert_save_dates(self, cr, uid, vals, context): #convert to the date like '2013-01-01' to UTC datetime to store if 'date_from' in vals and len(vals['date_from']) == 10: date_from = vals['date_from'] date_from = utils.utc_timestamp( cr, uid, datetime.strptime(date_from + ' 00:00:00', DEFAULT_SERVER_DATETIME_FORMAT), context=context) date_from = date_from.strftime(DEFAULT_SERVER_DATETIME_FORMAT) vals['date_from'] = date_from if 'date_to' in vals and len(vals['date_to']) == 10: date_to = vals['date_to'] date_to = utils.utc_timestamp(cr, uid, datetime.strptime( date_to + ' 23:59:59', DEFAULT_SERVER_DATETIME_FORMAT), context=context) date_to = date_to.strftime(DEFAULT_SERVER_DATETIME_FORMAT) vals['date_to'] = date_to def create(self, cr, uid, vals, context=None): self._convert_save_dates(cr, uid, vals, context) id_new = super(hr_rpt_attend_emp_day, self).create(cr, uid, vals, context=context) return id_new def write(self, cr, uid, ids, vals, context=None): self._convert_save_dates(cr, uid, vals, context) resu = super(hr_rpt_attend_emp_day, self).write(cr, uid, ids, vals, context=context) return resu def _attend_hours(self, hours_valid, period): ''' if hours_valid > period.hours_work_normal: hours_normal = period.hours_work_normal else: hours_normal = hours_valid hours_ot = hours_valid - hours_normal if hours_ot > period.hours_work_ot: hours_ot = period.hours_work_ot #the second time group if hours_valid > period.hours_work_normal2: hours_normal2 = period.hours_work_normal2 else: hours_normal2 = hours_valid hours_ot2 = hours_valid - hours_normal2 if hours_ot2 > period.hours_work_ot2: hours_ot2 = period.hours_work_ot2 ''' if hours_valid > period.hours_work_normal: hours_normal = period.hours_work_normal else: hours_normal = hours_valid hours_ot = hours_valid - hours_normal if hours_ot > period.hours_work_ot: hours_ot = period.hours_work_ot #the second time group if hours_valid > period.hours_work_normal2: hours_normal2 = period.hours_work_normal2 else: hours_normal2 = hours_valid hours_ot2 = hours_valid - hours_normal2 if hours_ot2 > period.hours_work_ot2: hours_ot2 = period.hours_work_ot2 return hours_normal, hours_ot, hours_normal2, hours_ot2 def run_attend_emp_day(self, cr, uid, ids, context=None): ''' 1.Query all data with both in/out by date range, store the result in attends_normal 2.Loop on by days and employees ''' emp_obj = self.pool.get('hr.employee') attend_obj = self.pool.get('hr.attendance') if context is None: context = {} rpt = self.browse(cr, uid, ids, context=context)[0] date_from = datetime.strptime(rpt.date_from, DEFAULT_SERVER_DATETIME_FORMAT) date_to = datetime.strptime(rpt.date_to, DEFAULT_SERVER_DATETIME_FORMAT) #report data line rpt_lns = [] #context for the query c = context.copy() #get the employees emp_ids = [emp.id for emp in rpt.emp_ids] if not emp_ids: emp_ids = emp_obj.search(cr, uid, [], context=context) ''' 1.Query all data with both in/out by date range, store the result in attends_normal ''' sql = ''' select emp.id as emp_id, period.id as period_id, sign_in.day, sign_in.action as in_action, sign_in.name as in_time, sign_out.action out_action, sign_out.name out_time from hr_employee emp left join (select name,employee_id,cale_period_id,action,day from hr_attendance where name between %s and %s and action in('sign_in','sign_in_late')) as sign_in on emp.id = sign_in.employee_id left join (select name,employee_id,cale_period_id,action,day from hr_attendance where name between %s and %s and action in('sign_out','sign_out_early')) as sign_out on emp.id = sign_out.employee_id and sign_in.day = sign_out.day and sign_in.cale_period_id = sign_out.cale_period_id join resource_calendar_attendance period on sign_in.cale_period_id = period.id and sign_out.cale_period_id = period.id where emp.id = ANY(%s) ''' cr.execute(sql, (date_from, date_to, date_from, date_to, (emp_ids, ))) attends = cr.dictfetchall() #use the emp_id-day-period_id as the key to store the normal attendance # attends_normal = dict(('%s-%s-%s'%(attend['emp_id'], attend['day'], attend['period_id']), attend) for attend in attends) attends_normal = {} for attend in attends: key = '%s-%s-%s' % (attend['emp_id'], attend['day'], attend['period_id']) in_time = fields.datetime.context_timestamp( cr, uid, datetime.strptime(attend['in_time'], DEFAULT_SERVER_DATETIME_FORMAT), context=context) out_time = fields.datetime.context_timestamp( cr, uid, datetime.strptime(attend['out_time'], DEFAULT_SERVER_DATETIME_FORMAT), context=context) attend['in_time'] = in_time attend['out_time'] = out_time attends_normal[key] = attend ''' 2.Loop on by days and employees ''' date_from_local = fields.datetime.context_timestamp( cr, uid, date_from, context) date_to_local = fields.datetime.context_timestamp( cr, uid, date_to, context) days = rrule.rrule(rrule.DAILY, dtstart=date_from_local, until=date_to_local) emps = emp_obj.browse(cr, uid, emp_ids, context) seq = 0 for emp in emps: for day_dt in days: day = day_dt.strftime('%Y-%m-%d') #if there is no working time defined to employee then continue to next employee directly if not emp.calendar_id or not emp.calendar_id.attendance_ids: seq += 1 ''' init a new empty line by employee/day without period info ''' rpt_line = { 'seq': seq, 'emp_id': emp.id, 'day': day, 'period_id': None, 'sign_in': None, 'sign_out': None, 'hours_normal': None, 'hours_ot': None, 'is_late': False, 'is_early': False, 'is_absent': False, 'hours_normal2': None, 'hours_ot2': None, } rpt_lns.append(rpt_line) continue for period in emp.calendar_id.attendance_ids: if day_dt.isoweekday() != (int(period.dayofweek) + 1): continue ''' init a new empty line by employee/day/period ''' seq += 1 rpt_line = { 'seq': seq, 'emp_id': emp.id, 'day': day, 'period_id': period.id, 'sign_in': None, 'sign_out': None, 'hours_normal': None, 'hours_ot': None, 'is_late': False, 'is_early': False, 'is_absent': False, 'hours_normal2': None, 'hours_ot2': None, } rpt_lns.append(rpt_line) #find the normal attendance by employee/day/period attend_key = '%s-%s-%s' % (emp.id, day, period.id) attend = attends_normal.get(attend_key, False) if attend: #found the normal attendance, with sign in and out record, put the data directly hour_in = attend[ 'in_time'].hour + attend['in_time'].minute / 60.0 hour_out = attend[ 'out_time'].hour + attend['out_time'].minute / 60.0 hours_valid = hour_out - hour_in - period.hours_non_work attend_hours = self._attend_hours(hours_valid, period) rpt_line.update({ 'period_id': period.id, 'sign_in': hour_in, 'sign_out': hour_out, 'hours_normal': attend_hours[0], 'hours_ot': attend_hours[1], 'is_late': attend['in_action'] == 'sign_in_late', 'is_early': attend['out_action'] == 'sign_out_early', 'hours_normal2': attend_hours[2], 'hours_ot2': attend_hours[3], }) continue #the abnormal attendance, with sign in or out record only, or without any attendance attend_ids = attend_obj.search( cr, uid, [('employee_id', '=', emp.id), ('day', '=', day), ('cale_period_id', '=', period.id), ('action', 'in', ('sign_in', 'sign_in_late', 'sign_out', 'sign_out_early'))], context=context) if attend_ids: #found sign in or sign out data, there shoule be only one record, so use the first ID to get data attend = attend_obj.browse(cr, uid, attend_ids[0], context=context) attend_time = fields.datetime.context_timestamp( cr, uid, datetime.strptime(attend.name, DEFAULT_SERVER_DATETIME_FORMAT), context) hour_in = None hour_out = None hours_valid = None hours_normal = None hours_ot = None is_late = False is_early = False is_absent = False hours_normal2 = None hours_ot2 = None #Only have sign in record if attend.action in ('sign_in', 'sign_in_late'): hour_in = attend_time.hour + attend_time.minute / 60.0 if emp.calendar_id.no_out_option == 'early': #treat as leave early if not period.is_full_ot: is_early = True hours_valid = period.hour_to - hour_in - period.hours_non_work - emp.calendar_id.no_out_time / 60.0 else: #treat as absent if not period.is_full_ot: is_absent = True hours_valid = 0.0 #Only have sign out record if attend.action in ('sign_out', 'sign_out_early'): hour_out = attend_time.hour + attend_time.minute / 60.0 if emp.calendar_id.no_in_option == 'late': #treat as leave early if not period.is_full_ot: is_late = True hours_valid = hour_out - period.hour_from - period.hours_non_work - emp.calendar_id.no_in_time / 60.0 else: #treat as absent if not period.is_full_ot: is_absent = True hours_valid = 0.0 if hours_valid: hours_normal, hours_ot, hours_normal2, hours_ot2 = self._attend_hours( hours_valid, period) rpt_line.update({ 'period_id': period.id, 'sign_in': hour_in, 'sign_out': hour_out, 'hours_normal': hours_normal, 'hours_ot': hours_ot, 'is_late': is_late, 'is_early': is_early, 'is_absent': is_absent, 'hours_normal2': hours_normal2, 'hours_ot2': hours_ot2, }) else: if not period.is_full_ot: rpt_line.update({'is_absent': True}) '''========return data to rpt_base.run_report()=========''' return self.pool.get('hr.rpt.attend.emp.day.line'), rpt_lns def _pdf_data(self, cr, uid, ids, form_data, context=None): return {'xmlrpt_name': 'hr.rpt.attend.emp.day'}
class Post(osv.Model): _name = 'forum.post' _description = 'Forum Post' _inherit = ['mail.thread', 'website.seo.metadata'] _order = "is_correct DESC, vote_count DESC, write_date DESC" def _get_user_vote(self, cr, uid, ids, field_name, arg, context): res = dict.fromkeys(ids, 0) vote_ids = self.pool['forum.post.vote'].search(cr, uid, [('post_id', 'in', ids), ('user_id', '=', uid)], context=context) for vote in self.pool['forum.post.vote'].browse(cr, uid, vote_ids, context=context): res[vote.post_id.id] = vote.vote return res def _get_vote_count(self, cr, uid, ids, field_name, arg, context): res = dict.fromkeys(ids, 0) for post in self.browse(cr, uid, ids, context=context): for vote in post.vote_ids: res[post.id] += int(vote.vote) return res def _get_post_from_vote(self, cr, uid, ids, context=None): result = {} for vote in self.pool['forum.post.vote'].browse(cr, uid, ids, context=context): result[vote.post_id.id] = True return result.keys() def _get_user_favourite(self, cr, uid, ids, field_name, arg, context): res = dict.fromkeys(ids, False) for post in self.browse(cr, uid, ids, context=context): if uid in [f.id for f in post.favourite_ids]: res[post.id] = True return res def _get_favorite_count(self, cr, uid, ids, field_name, arg, context): res = dict.fromkeys(ids, 0) for post in self.browse(cr, uid, ids, context=context): res[post.id] += len(post.favourite_ids) return res def _get_post_from_hierarchy(self, cr, uid, ids, context=None): post_ids = set(ids) for post in self.browse(cr, SUPERUSER_ID, ids, context=context): if post.parent_id: post_ids.add(post.parent_id.id) return list(post_ids) def _get_child_count(self, cr, uid, ids, field_name=False, arg={}, context=None): res = dict.fromkeys(ids, 0) for post in self.browse(cr, uid, ids, context=context): if post.parent_id: res[post.parent_id.id] = len(post.parent_id.child_ids) else: res[post.id] = len(post.child_ids) return res def _get_uid_answered(self, cr, uid, ids, field_name, arg, context=None): res = dict.fromkeys(ids, False) for post in self.browse(cr, uid, ids, context=context): res[post.id] = any(answer.create_uid.id == uid for answer in post.child_ids) return res def _get_has_validated_answer(self, cr, uid, ids, field_name, arg, context=None): res = dict.fromkeys(ids, False) ans_ids = self.search(cr, uid, [('parent_id', 'in', ids), ('is_correct', '=', True)], context=context) for answer in self.browse(cr, uid, ans_ids, context=context): res[answer.parent_id.id] = True return res def _is_self_reply(self, cr, uid, ids, field_name, arg, context=None): res = dict.fromkeys(ids, False) for post in self.browse(cr, uid, ids, context=context): res[post. id] = post.parent_id and post.parent_id.create_uid == post.create_uid or False return res def _get_post_karma_rights(self, cr, uid, ids, field_name, arg, context=None): user = self.pool['res.users'].browse(cr, uid, uid, context=context) res = dict.fromkeys(ids, False) for post in self.browse(cr, uid, ids, context=context): res[post.id] = { 'karma_ask': post.forum_id.karma_ask, 'karma_answer': post.forum_id.karma_answer, 'karma_accept': post.parent_id and post.parent_id.create_uid.id == uid and post.forum_id.karma_answer_accept_own or post.forum_id.karma_answer_accept_all, 'karma_edit': post.create_uid.id == uid and post.forum_id.karma_edit_own or post.forum_id.karma_edit_all, 'karma_close': post.create_uid.id == uid and post.forum_id.karma_close_own or post.forum_id.karma_close_all, 'karma_unlink': post.create_uid.id == uid and post.forum_id.karma_unlink_own or post.forum_id.karma_unlink_all, 'karma_upvote': post.forum_id.karma_upvote, 'karma_downvote': post.forum_id.karma_downvote, 'karma_comment': post.create_uid.id == uid and post.forum_id.karma_comment_own or post.forum_id.karma_comment_all, 'karma_comment_convert': post.create_uid.id == uid and post.forum_id.karma_comment_convert_own or post.forum_id.karma_comment_convert_all, } res[post.id].update({ 'can_ask': uid == SUPERUSER_ID or user.karma >= res[post.id]['karma_ask'], 'can_answer': uid == SUPERUSER_ID or user.karma >= res[post.id]['karma_answer'], 'can_accept': uid == SUPERUSER_ID or user.karma >= res[post.id]['karma_accept'], 'can_edit': uid == SUPERUSER_ID or user.karma >= res[post.id]['karma_edit'], 'can_close': uid == SUPERUSER_ID or user.karma >= res[post.id]['karma_close'], 'can_unlink': uid == SUPERUSER_ID or user.karma >= res[post.id]['karma_unlink'], 'can_upvote': uid == SUPERUSER_ID or user.karma >= res[post.id]['karma_upvote'], 'can_downvote': uid == SUPERUSER_ID or user.karma >= res[post.id]['karma_downvote'], 'can_comment': uid == SUPERUSER_ID or user.karma >= res[post.id]['karma_comment'], 'can_comment_convert': uid == SUPERUSER_ID or user.karma >= res[post.id]['karma_comment_convert'], }) return res _columns = { 'name': fields.char('Title'), 'forum_id': fields.many2one('forum.forum', 'Forum', required=True), 'content': fields.html('Content'), 'tag_ids': fields.many2many('forum.tag', 'forum_tag_rel', 'forum_id', 'forum_tag_id', 'Tags'), 'state': fields.selection([('active', 'Active'), ('close', 'Close'), ('offensive', 'Offensive')], 'Status'), 'views': fields.integer('Number of Views'), 'active': fields.boolean('Active'), 'is_correct': fields.boolean( 'Valid Answer', help='Correct Answer or Answer on this question accepted.'), 'website_message_ids': fields.one2many( 'mail.message', 'res_id', domain=lambda self: [ '&', ('model', '=', self._name), ('type', 'in', ['email', 'comment']) ], string='Post Messages', help="Comments on forum post", ), # history 'create_date': fields.datetime('Asked on', select=True, readonly=True), 'create_uid': fields.many2one('res.users', 'Created by', select=True, readonly=True), 'write_date': fields.datetime('Update on', select=True, readonly=True), 'write_uid': fields.many2one('res.users', 'Updated by', select=True, readonly=True), # vote fields 'vote_ids': fields.one2many('forum.post.vote', 'post_id', 'Votes'), 'user_vote': fields.function(_get_user_vote, string='My Vote', type='integer'), 'vote_count': fields.function(_get_vote_count, string="Votes", type='integer', store={ 'forum.post': (lambda self, cr, uid, ids, c={}: ids, ['vote_ids'], 10), 'forum.post.vote': (_get_post_from_vote, [], 10), }), # favorite fields 'favourite_ids': fields.many2many('res.users', string='Favourite'), 'user_favourite': fields.function(_get_user_favourite, string="My Favourite", type='boolean'), 'favourite_count': fields.function(_get_favorite_count, string='Favorite Count', type='integer', store={ 'forum.post': (lambda self, cr, uid, ids, c={}: ids, ['favourite_ids'], 10), }), # hierarchy 'parent_id': fields.many2one('forum.post', 'Question', ondelete='cascade'), 'self_reply': fields.function(_is_self_reply, 'Reply to own question', type='boolean', store={ 'forum.post': (lambda self, cr, uid, ids, c={}: ids, ['parent_id', 'create_uid'], 10), }), 'child_ids': fields.one2many('forum.post', 'parent_id', 'Answers'), 'child_count': fields.function(_get_child_count, string="Answers", type='integer', store={ 'forum.post': (_get_post_from_hierarchy, ['parent_id', 'child_ids'], 10), }), 'uid_has_answered': fields.function( _get_uid_answered, string='Has Answered', type='boolean', ), 'has_validated_answer': fields.function(_get_has_validated_answer, string='Has a Validated Answered', type='boolean', store={ 'forum.post': (_get_post_from_hierarchy, ['parent_id', 'child_ids', 'is_correct'], 10), }), # closing 'closed_reason_id': fields.many2one('forum.post.reason', 'Reason'), 'closed_uid': fields.many2one('res.users', 'Closed by', select=1), 'closed_date': fields.datetime('Closed on', readonly=True), # karma 'karma_ask': fields.function(_get_post_karma_rights, string='Karma to ask', type='integer', multi='_get_post_karma_rights'), 'karma_answer': fields.function(_get_post_karma_rights, string='Karma to answer', type='integer', multi='_get_post_karma_rights'), 'karma_accept': fields.function(_get_post_karma_rights, string='Karma to accept this answer', type='integer', multi='_get_post_karma_rights'), 'karma_edit': fields.function(_get_post_karma_rights, string='Karma to edit', type='integer', multi='_get_post_karma_rights'), 'karma_close': fields.function(_get_post_karma_rights, string='Karma to close', type='integer', multi='_get_post_karma_rights'), 'karma_unlink': fields.function(_get_post_karma_rights, string='Karma to unlink', type='integer', multi='_get_post_karma_rights'), 'karma_upvote': fields.function(_get_post_karma_rights, string='Karma to upvote', type='integer', multi='_get_post_karma_rights'), 'karma_downvote': fields.function(_get_post_karma_rights, string='Karma to downvote', type='integer', multi='_get_post_karma_rights'), 'karma_comment': fields.function(_get_post_karma_rights, string='Karma to comment', type='integer', multi='_get_post_karma_rights'), 'karma_comment_convert': fields.function(_get_post_karma_rights, string='karma to convert as a comment', type='integer', multi='_get_post_karma_rights'), # access rights 'can_ask': fields.function(_get_post_karma_rights, string='Can Ask', type='boolean', multi='_get_post_karma_rights'), 'can_answer': fields.function(_get_post_karma_rights, string='Can Answer', type='boolean', multi='_get_post_karma_rights'), 'can_accept': fields.function(_get_post_karma_rights, string='Can Accept', type='boolean', multi='_get_post_karma_rights'), 'can_edit': fields.function(_get_post_karma_rights, string='Can Edit', type='boolean', multi='_get_post_karma_rights'), 'can_close': fields.function(_get_post_karma_rights, string='Can Close', type='boolean', multi='_get_post_karma_rights'), 'can_unlink': fields.function(_get_post_karma_rights, string='Can Unlink', type='boolean', multi='_get_post_karma_rights'), 'can_upvote': fields.function(_get_post_karma_rights, string='Can Upvote', type='boolean', multi='_get_post_karma_rights'), 'can_downvote': fields.function(_get_post_karma_rights, string='Can Downvote', type='boolean', multi='_get_post_karma_rights'), 'can_comment': fields.function(_get_post_karma_rights, string='Can Comment', type='boolean', multi='_get_post_karma_rights'), 'can_comment_convert': fields.function(_get_post_karma_rights, string='Can Convert to Comment', type='boolean', multi='_get_post_karma_rights'), } _defaults = { 'state': 'active', 'views': 0, 'active': True, 'vote_ids': list(), 'favourite_ids': list(), 'child_ids': list(), } def create(self, cr, uid, vals, context=None): if context is None: context = {} create_context = dict(context, mail_create_nolog=True) post_id = super(Post, self).create(cr, uid, vals, context=create_context) post = self.browse( cr, SUPERUSER_ID, post_id, context=context ) # SUPERUSER_ID to avoid read access rights issues when creating # karma-based access if post.parent_id and not post.can_ask: raise KarmaError('Not enough karma to create a new question') elif not post.parent_id and not post.can_answer: raise KarmaError('Not enough karma to answer to a question') # messaging and chatter base_url = self.pool['ir.config_parameter'].get_param( cr, uid, 'web.base.url') if post.parent_id: body = _( '<p>A new answer for <i>%s</i> has been posted. <a href="%s/forum/%s/question/%s">Click here to access the post.</a></p>' % (post.parent_id.name, base_url, slug( post.parent_id.forum_id), slug(post.parent_id))) self.message_post(cr, uid, post.parent_id.id, subject=_('Re: %s') % post.parent_id.name, body=body, subtype='website_forum.mt_answer_new', context=context) else: body = _( '<p>A new question <i>%s</i> has been asked on %s. <a href="%s/forum/%s/question/%s">Click here to access the question.</a></p>' % (post.name, post.forum_id.name, base_url, slug( post.forum_id), slug(post))) self.message_post(cr, uid, post_id, subject=post.name, body=body, subtype='website_forum.mt_question_new', context=context) self.pool['res.users'].add_karma( cr, SUPERUSER_ID, [uid], post.forum_id.karma_gen_question_new, context=context) return post_id def write(self, cr, uid, ids, vals, context=None): posts = self.browse(cr, uid, ids, context=context) if 'state' in vals: if vals['state'] in ['active', 'close'] and any(not post.can_close for post in posts): raise KarmaError('Not enough karma to close or reopen a post.') if 'active' in vals: if any(not post.can_unlink for post in posts): raise KarmaError( 'Not enough karma to delete or reactivate a post') if 'is_correct' in vals: if any(not post.can_accept for post in posts): raise KarmaError( 'Not enough karma to accept or refuse an answer') # update karma except for self-acceptance mult = 1 if vals['is_correct'] else -1 for post in self.browse(cr, uid, ids, context=context): if vals['is_correct'] != post.is_correct and post.create_uid.id != uid: self.pool['res.users'].add_karma( cr, SUPERUSER_ID, [post.create_uid.id], post.forum_id.karma_gen_answer_accepted * mult, context=context) self.pool['res.users'].add_karma( cr, SUPERUSER_ID, [uid], post.forum_id.karma_gen_answer_accept * mult, context=context) if any(key not in [ 'state', 'active', 'is_correct', 'closed_uid', 'closed_date', 'closed_reason_id' ] for key in vals.keys()) and any(not post.can_edit for post in posts): raise KarmaError('Not enough karma to edit a post.') res = super(Post, self).write(cr, uid, ids, vals, context=context) # if post content modify, notify followers if 'content' in vals or 'name' in vals: for post in posts: if post.parent_id: body, subtype = _( 'Answer Edited'), 'website_forum.mt_answer_edit' obj_id = post.parent_id.id else: body, subtype = _( 'Question Edited'), 'website_forum.mt_question_edit' obj_id = post.id self.message_post(cr, uid, obj_id, body=body, subtype=subtype, context=context) return res def close(self, cr, uid, ids, reason_id, context=None): if any(post.parent_id for post in self.browse(cr, uid, ids, context=context)): return False return self.pool['forum.post'].write( cr, uid, ids, { 'state': 'close', 'closed_uid': uid, 'closed_date': datetime.today().strftime( tools.DEFAULT_SERVER_DATETIME_FORMAT), 'closed_reason_id': reason_id, }, context=context) def unlink(self, cr, uid, ids, context=None): posts = self.browse(cr, uid, ids, context=context) if any(not post.can_unlink for post in posts): raise KarmaError('Not enough karma to unlink a post') # if unlinking an answer with accepted answer: remove provided karma for post in posts: if post.is_correct: self.pool['res.users'].add_karma( cr, SUPERUSER_ID, [post.create_uid.id], post.forum_id.karma_gen_answer_accepted * -1, context=context) self.pool['res.users'].add_karma( cr, SUPERUSER_ID, [uid], post.forum_id.karma_gen_answer_accept * -1, context=context) return super(Post, self).unlink(cr, uid, ids, context=context) def vote(self, cr, uid, ids, upvote=True, context=None): posts = self.browse(cr, uid, ids, context=context) if upvote and any(not post.can_upvote for post in posts): raise KarmaError('Not enough karma to upvote.') elif not upvote and any(not post.can_downvote for post in posts): raise KarmaError('Not enough karma to downvote.') Vote = self.pool['forum.post.vote'] vote_ids = Vote.search(cr, uid, [('post_id', 'in', ids), ('user_id', '=', uid)], context=context) new_vote = '1' if upvote else '-1' voted_forum_ids = set() if vote_ids: for vote in Vote.browse(cr, uid, vote_ids, context=context): if upvote: new_vote = '0' if vote.vote == '-1' else '1' else: new_vote = '0' if vote.vote == '1' else '-1' Vote.write(cr, uid, vote_ids, {'vote': new_vote}, context=context) voted_forum_ids.add(vote.post_id.id) for post_id in set(ids) - voted_forum_ids: for post_id in ids: Vote.create(cr, uid, { 'post_id': post_id, 'vote': new_vote }, context=context) return { 'vote_count': self._get_vote_count(cr, uid, ids, None, None, context=context)[ids[0]], 'user_vote': new_vote } def convert_answer_to_comment(self, cr, uid, id, context=None): """ Tools to convert an answer (forum.post) to a comment (mail.message). The original post is unlinked and a new comment is posted on the question using the post create_uid as the comment's author. """ post = self.browse(cr, SUPERUSER_ID, id, context=context) if not post.parent_id: return False # karma-based action check: use the post field that computed own/all value if not post.can_comment_convert: raise KarmaError( 'Not enough karma to convert an answer to a comment') # post the message question = post.parent_id values = { 'author_id': post.create_uid.partner_id.id, 'body': html2plaintext(post.content), 'type': 'comment', 'subtype': 'mail.mt_comment', 'date': post.create_date, } message_id = self.pool['forum.post'].message_post( cr, uid, question.id, context=dict(context, mail_create_nosubcribe=True), **values) # unlink the original answer, using SUPERUSER_ID to avoid karma issues self.pool['forum.post'].unlink(cr, SUPERUSER_ID, [post.id], context=context) return message_id def convert_comment_to_answer(self, cr, uid, message_id, default=None, context=None): """ Tool to convert a comment (mail.message) into an answer (forum.post). The original comment is unlinked and a new answer from the comment's author is created. Nothing is done if the comment's author already answered the question. """ comment = self.pool['mail.message'].browse(cr, SUPERUSER_ID, message_id, context=context) post = self.pool['forum.post'].browse(cr, uid, comment.res_id, context=context) user = self.pool['res.users'].browse(cr, uid, uid, context=context) if not comment.author_id or not comment.author_id.user_ids: # only comment posted by users can be converted return False # karma-based action check: must check the message's author to know if own / all karma_convert = comment.author_id.id == user.partner_id.id and post.forum_id.karma_comment_convert_own or post.forum_id.karma_comment_convert_all can_convert = uid == SUPERUSER_ID or user.karma >= karma_convert if not can_convert: raise KarmaError( 'Not enough karma to convert a comment to an answer') # check the message's author has not already an answer question = post.parent_id if post.parent_id else post post_create_uid = comment.author_id.user_ids[0] if any(answer.create_uid.id == post_create_uid.id for answer in question.child_ids): return False # create the new post post_values = { 'forum_id': question.forum_id.id, 'content': comment.body, 'parent_id': question.id, } # done with the author user to have create_uid correctly set new_post_id = self.pool['forum.post'].create(cr, post_create_uid.id, post_values, context=context) # delete comment self.pool['mail.message'].unlink(cr, SUPERUSER_ID, [comment.id], context=context) return new_post_id def unlink_comment(self, cr, uid, id, message_id, context=None): comment = self.pool['mail.message'].browse(cr, SUPERUSER_ID, message_id, context=context) post = self.pool['forum.post'].browse(cr, uid, id, context=context) user = self.pool['res.users'].browse(cr, SUPERUSER_ID, uid, context=context) if not comment.model == 'forum.post' or not comment.res_id == id: return False # karma-based action check: must check the message's author to know if own or all karma_unlink = comment.author_id.id == user.partner_id.id and post.forum_id.karma_comment_unlink_own or post.forum_id.karma_comment_unlink_all can_unlink = uid == SUPERUSER_ID or user.karma >= karma_unlink if not can_unlink: raise KarmaError('Not enough karma to unlink a comment') return self.pool['mail.message'].unlink(cr, SUPERUSER_ID, [message_id], context=context) def set_viewed(self, cr, uid, ids, context=None): cr.execute("""UPDATE forum_post SET views = views+1 WHERE id IN %s""", (tuple(ids), )) return True def _get_access_link(self, cr, uid, mail, partner, context=None): post = self.pool['forum.post'].browse(cr, uid, mail.res_id, context=context) res_id = post.parent_id and "%s#answer-%s" % (post.parent_id.id, post.id) or post.id return "/forum/%s/question/%s" % (post.forum_id.id, res_id)
class ProductionPlan(osv.osv): _inherit = 'production.plan' _columns = { 'plan_list': fields.one2many('production.plan.list', 'plan_id', 'Production Plan List', readonly=True), } def compute(self, cr, uid, ids, context=None): val = self.browse(cr, uid, ids, context={})[0] product_obj = self.pool.get('product.product') def _create_list(ID,name,product,qty): self.pool.get('production.plan.list').create(cr,uid,{'plan_id':ID,'name':name,'product_id': product.id,'qty': qty,'ean13':product.ean13 or ''}) if val.plan_line: for x in val.plan_line: plan = x.plan if x.real - x.total == 0 : plan = x.max elif x.real - x.total <= 0 : plan = abs(x.real - x.total) + x.max elif x.real - x.total < x.min: plan = x.max - (x.real - x.total) self.pool.get('production.plan.line').write(cr, uid, [x.id], {'plan': plan, 'end': x.real - x.total + plan}) else: product = [] list_product = [] for x in val.order_ids: for l in x.order_line: product.append({'product_id': l.product_id.id, 'line': l, 'qty': l.product_uom_qty, 'uom': l.product_uom.id}) _create_list(val.id,x.name,l.product_id,l.product_uom_qty) for x in val.stock_ids: for l in x.stock_line: product.append({'source':x.name,'product_id': l.product_id.id, 'line': l, 'qty': l.product_qty, 'uom': l.product_uom.id}) _create_list(val.id,x.name,l.product_id,l.product_qty) for x in val.stockw_ids: for l in x.stock_line: product.append({'product_id': l.product_id.id, 'line': l, 'qty': l.product_qty, 'uom': l.product_uom.id}) data = {} for p in product: data[p['product_id']] = {'qty': [], 'uom': p['uom'], 'line': []} for p in product: data[p['product_id']]['qty'].append(p['qty']) data[p['product_id']]['line'].append(p['line']) for i in data: order = sum(data[i]['qty']) brg = product_obj.browse(cr, uid, i) min = 0; max = 0; plan = order sid = self.pool.get('stock.warehouse.orderpoint').search(cr, uid, [('product_id', '=', i)]) if sid: sto = self.pool.get('stock.warehouse.orderpoint').browse(cr, uid, sid)[0] min = sto.product_min_qty max = sto.product_max_qty plan = 0 if brg.qty_available - order == 0 : plan = max elif brg.qty_available - order <= 0 : plan = abs(brg.qty_available - order) + max elif brg.qty_available - order < min: plan = max - (brg.qty_available - order) self.pool.get('production.plan.line').create(cr, uid, { 'plan_id': val.id, 'product_id': i, 'product_uom': data[i]['uom'], 'total': order, 'name': product_obj.name_get(cr, uid, [i])[0][1], 'real': brg.qty_available, 'min': min, 'max': max, 'plan': plan, 'end': brg.qty_available - order + plan }) return True
class mrp_barcode_setting(osv.osv): _name = 'mrp.barcode.setting' def compose_barcode(self, cr, uid, ids, context=None): vals = self.browse(cr,uid,ids[0],) content1 = [] content2 =[] content3 = [] Ap4 = {'1':12,'2':'16'} Y1=0 Y23=0 list_obj = self.pool.get('mrp.barcode.setting.list') ul = [i.id for i in vals.result_ids] if ul : list_obj.unlink(cr, uid, ul , context=context) def construct_label(A,X,Y,R): return "\n"+",".join([A+X,Y,R,'1,1,1,N,']) def construct_barcode(B,X,Y,R,T,H): return "\n"+",".join([B+X,Y,R,T,'2,2',H,'N,']) if vals.detail_ids: for l in vals.detail_ids: if l.type == "A": Y1+=int(Ap4[l.size]) str1 = construct_label("A",str(vals.initX1),str(Y1),l.rotation) else : Y1+=int(l.height)+4 str1 = construct_barcode("B",str(vals.initX1),str(Y1),l.rotation,l.barcode,str(l.height)) list_obj.create(cr,uid,{'setting_id':ids[0],'type' :l.type,'kolom':1,'list':str1}) if vals.detail_ids2: for l in vals.detail_ids2: if l.type == "A": str2 = construct_label("A",str(vals.initX2),str(Y23),l.rotation) str3 = construct_label("A",str(vals.initX3),str(Y23),l.rotation) Y23+=int(Ap4[l.size]) else : str2 = construct_barcode("B",str(vals.initX2),str(Y23),l.rotation,l.barcode,str(l.height)) str3 = construct_barcode("B",str(vals.initX3),str(Y23),l.rotation,l.barcode,str(l.height)) Y23+=int(l.height)+4 list_obj.create(cr,uid,{'setting_id':ids[0],'type' :l.type,'kolom':2,'list':str2}) list_obj.create(cr,uid,{'setting_id':ids[0],'type' :l.type,'kolom':3,'list':str3}) return True _columns = { 'name' : fields.char('Name',size=10), 'detail_ids2': fields.one2many('mrp.barcode.setting.line2','setting_id',string='Setting'), 'detail_ids': fields.one2many('mrp.barcode.setting.line','setting_id',string='Setting'), 'deltaY' : fields.integer('Delta Y',size=3), 'initX1' : fields.integer('X0 column 1',size=3), 'initX2' : fields.integer('X0 column 2',size=3), 'initX3' : fields.integer('X0 column 3',size=3), 'result_ids':fields.one2many('mrp.barcode.setting.list','setting_id',string='Setting',readonly=True), 'active' :fields.boolean("Active"), 'initRX' : fields.integer('X0 Form',size=3), 'initRY' : fields.integer('Y0 Form',size=3), } _defaults = { 'deltaY' :145, 'initX1' : 240, 'initX2' : 270, 'initX3' : 550, 'active' : True, 'initRX' : 0, 'initRY' : 0, }
class ebay_user(osv.osv): _name = "ebay.user" _description = "a registered eBay user" @staticmethod def get_shipping_service_type(): return [ ('cnam', _('China Post Normal Air Mail')), ('cnram', _('China Post Registered Air Mail')), ('hkam', _('HongKong Post Normal Air Mail')), ('hkram', _('HongKong Post Registered Air Mail')), ('sgam', _('Sing Post Normal Air Mail')), ('sgram', _('Sing Post Registered Air Mail')), ] def _get_shipping_service_type(self, cr, uid, context=None): return self.get_shipping_service_type() _columns = { 'email': fields.char('Email', size=128, readonly=True), 'feedback_rating_star': fields.selection( [('Blue', 'Blue Star'), ('CustomCode', 'Reserved for internal or future use.'), ('Green', 'Green Star'), ('GreenShooting', 'Green Shooting Star'), ('None', 'No graphic displayed'), ('Purple', 'Purple Star'), ('PurpleShooting', 'Purple Shooting Star'), ('Red', 'Red Star'), ('RedShooting', 'Red Shooting Star'), ('SilverShooting', 'Silver Shooting Star'), ('Turquoise', 'Turquoise Star'), ('TurquoiseShooting', 'Turquoise Shooting Star'), ('Yellow', 'Yellow Star'), ('YellowShooting', 'Yellow Shooting Star')], 'Feedback Rating Star', readonly=True), 'feedback_score': fields.integer('Feedback Score', readonly=True), 'positive_feedback_percent': fields.float('Feedback Percent', readonly=True), 'registration_date': fields.datetime('Registration Date', readonly=True), 'store_owner': fields.boolean('Store Owner', readonly=True), 'store_site': fields.char('Store Site', readonly=True), 'store_url': fields.char('Store URL', readonly=True), 'top_rated_seller': fields.boolean('Top-rated Seller', readonly=True), 'site': fields.char('Site', readonly=True), 'unique_negative_feedback_count': fields.integer('Negative', readonly=True), 'unique_neutral_feedback_count': fields.integer('Neutral', readonly=True), 'unique_positive_feedback_count': fields.integer('Positive', readonly=True), 'name': fields.char('User ID', required=True, select=True), # Selleris 'seller_list_ids': fields.one2many('ebay.seller.list', 'user_id', 'Seller Lists', readonly=True), 'last_updated': fields.datetime('Last Updated'), # Application keys for authorization 'ownership': fields.boolean('Ownership', readonly=True), 'sandbox': fields.boolean('Sandbox'), 'sale_site': fields.selection([ ('0', 'US'), ('2', 'Canada'), ('3', 'UK'), ('15', 'Australia'), ('201', 'HongKong'), ], 'Sale Site'), 'app_id': fields.char('AppID', size=64), 'dev_id': fields.char('DevID', size=64), 'cert': fields.char('CERT', size=64), 'ru_name': fields.char('RuName', size=64), # Auth info, get from FetchToken 'ebay_auth_token': fields.char('eBayAuthToken', readonly=True), 'hard_expiration_time': fields.datetime('HardExpirationTime', readonly=True), 'rest_token': fields.char('RESTToken', readonly=True), # Sale status 'monthly_sales': fields.float('Monthly Sales', readonly=True), 'monthly_sales_volume': fields.integer('Monthly Sales Volume', readonly=True), # Additional Info 'ebay_item_ids': fields.one2many('ebay.item', 'ebay_user_id', 'Items'), 'paypal_email_address': fields.char('Paypal Email Address'), 'country': fields.char('Country', size=2), 'location': fields.char('Location'), 'shipping_service': fields.selection(_get_shipping_service_type, 'Shipping service'), 'after_service_7_template': fields.text('7 days template'), 'after_service_15_template': fields.text('15 days template'), 'after_service_25_template': fields.text('25 days template'), # User Preferences 'exclude_ship_to_location': fields.text('Exclude Ship To Location', readonly=True), } _defaults = { 'feedback_score': 0, 'store_owner': 0, 'ownership': 0, 'sandbox': 0, 'sale_site': '0', 'country': 'CN', 'location': 'ShenZhen', 'shipping_service': 'sgam', 'after_service_7_template': ''' Hi friend. Your item has been shipped on {{ shipped_time }} by air mail, and it may take about 10~20 days to arrive, sometimes it may be delayed by unexpected reason like holiday, custom`s process, weather condition etc. It may be delayed up to 35 days to arrive. We will be very appreciated for your patience. If you have any question, feel free to contact us asap. Thanks for your purchase. Yours Sincerely ''', 'after_service_15_template': ''' Hi friend. Your item has been shipped on {{ shipped_time }} by air mail. {{ elapse }} days have passed since your item was shipped, When you receive it, we sincerely hope that you will like it and appreciate our customer services. If there is anything you feel unsatisfied with, please do tell us. This will help us know what we should do to help you as well as how we should improve. If you are satisfied, we sincerely hope that you can leave us a positive comment, which is of vital importance to the growth of our small company. PLEASE DO NOT leaves us negative feedback. If you are not satisfied in any regard, please tell us. Thanks once more for your purchase. Yours Sincerely ''', 'after_service_25_template': ''' Hi friend. Your item has been shipped on {{ shipped_time }} by air mail. If you haven't received your item and this situation lasts to the 35th day, please do contact us. WE WILL DO OUR BEST TO SOLVE YOUR PROBLEM. We do not want to give you a bad buying experience even when the shipping is out of our control. But if you receive it, we sincerely hope you can leave us a positive comment if you like it and appreciate our customer services. Thanks once more for your purchase. Yours Sincerely ''' } _order = 'monthly_sales desc' _sql_constraints = [ ('name_uniq', 'unique(name, sandbox)', 'User ID must be unique!'), ] def copy(self, cr, uid, id, default=None, context=None): if default is None: default = {} name = self.read(cr, uid, id, ['name'], context=context)['name'] default = default.copy() default.update({ 'name': name + _(' (Copy)'), 'session_id': '', 'ebay_auth_token': '', }) return super(ebay_user, self).copy(cr, uid, id, default, context) def action_get_user(self, cr, uid, ids, context=None): for user in self.browse(cr, uid, ids, context=context): call_data = dict() call_data['UserID'] = user.name error_msg = 'Get the data for the specified user %s' % user.name reply = self.pool.get('ebay.ebay').call( cr, uid, user, 'GetUser', call_data, error_msg, context=context).response.reply vals = dict() user_dict = reply.User vals['email'] = user_dict.Email vals['feedback_rating_star'] = user_dict.FeedbackRatingStar vals['feedback_score'] = user_dict.FeedbackScore vals[ 'positive_feedback_percent'] = user_dict.PositiveFeedbackPercent vals['registration_date'] = user_dict.RegistrationDate seller_info = user_dict.SellerInfo vals['store_owner'] = seller_info.StoreOwner == "true" if vals['store_owner']: vals['store_site'] = seller_info.StoreSite vals['store_url'] = seller_info.StoreURL vals['top_rated_seller'] = seller_info.get('TopRatedSeller', False) vals['site'] = user_dict.Site vals[ 'unique_negative_feedback_count'] = user_dict.UniqueNegativeFeedbackCount vals[ 'unique_neutral_feedback_count'] = user_dict.UniqueNeutralFeedbackCount vals[ 'unique_positive_feedback_count'] = user_dict.UniquePositiveFeedbackCount call_data = dict() call_data['ShowSellerExcludeShipToLocationPreference'] = 'true' error_msg = 'Get the user perferences for the user %s' % user.name reply = self.pool.get('ebay.ebay').call( cr, uid, user, 'GetUserPreferences', call_data, error_msg, context=context).response.reply exclude_ship_to_location = reply.SellerExcludeShipToLocationPreferences.ExcludeShipToLocation if type(exclude_ship_to_location) != list: vals['exclude_ship_to_location'] = exclude_ship_to_location else: vals['exclude_ship_to_location'] = '|'.join( exclude_ship_to_location) user.write(vals) def action_get_seller_list(self, cr, uid, ids, context=None): ebay_seller_list_obj = self.pool.get('ebay.seller.list') try: for user in self.browse(cr, uid, ids, context=context): ebay_seller_list_obj.get_seller_list(cr, uid, user, context=context) except (ConnectionError, ConnectionResponseError, RequestException) as e: return self.pool.get('ebay.ebay').exception(cr, uid, 'GetSellerList', e, context=context) else: return True
], 'Package Type', help='Indicates the type of package'), 'bill_shipping': fields.selection([ ('shipper', 'Shipper'), ('receiver', 'Receiver'), ('thirdparty', 'Third Party') ], 'Bill Shipping to', help='Shipper, Receiver, or Third Party.'), 'with_ret_service': fields.boolean('With Return Services', help='Include Return Shipping Information in the package.'), 'tot_ship_weight': fields.function(_total_weight_net, method=True, type='float', digits=(16, 3), string='Total Shipment Weight', store={ 'stock.picking': (lambda self, cr, uid, ids, c={}: ids, ['packages_ids'], -10), 'stock.packages': (_get_order, ['weight'], -10), }, help="Adds the Total Weight of all the packages in the Packages Table.", ), 'tot_del_order_weight': fields.function(_total_ord_weight_net, method=True, readonly=True, string='Total Order Weight', store=False, help="Adds the Total Weight of all the packages in the Packages Table."), 'packages_ids': fields.one2many("stock.packages", 'pick_id', 'Packages Table'), 'ship_state': fields.selection([ ('draft', 'Draft'), ('in_process', 'In Process'), ('ready_pick', 'Ready for Pickup'), ('shipped', 'Shipped'), ('delivered', 'Delivered'), ('void', 'Void'), ('hold', 'Hold'), ('cancelled', 'Cancelled') ], 'Shipping Status', readonly=True, help='The current status of the shipment'), 'trade_mark': fields.text('Trademarks AREA'), 'ship_message': fields.text('Message'), 'address_validate': fields.selection([ ('validate', 'Validate'), ('nonvalidate', 'No Validation')
_columns = { 'name': fields.char('Name', size=64, help="Exchange description like the name of the supplier, bank,...", require=True), 'type': fields.selection([('in','IN'),('out','OUT'),('in-out', 'IN & OUT')], 'Type',help=("IN for files coming from the other system" "and to be imported in the ERP ; OUT for files to be" "generated from the ERP and send to the other system")), 'mapping_id':fields.many2one('external.mapping', 'External Mapping', require="True", domain="[('referential_id', '=', referential_id)]"), 'format' : fields.selection([('csv','CSV'),('csv_no_header','CSV WITHOUT HEADER'), ('xls', 'XLS')], 'File format'), 'referential_id':fields.many2one('external.referential', 'Referential',help="Referential to use for connection and mapping", require=True), 'scheduler':fields.many2one('ir.cron', 'Scheduler',help="Scheduler that will execute the cron task"), 'search_filter': fields.char('Search Filter', size=256), 'filename': fields.char('Filename', size=128, help="Filename will be used to generate the output file name or to read the incoming file. It is possible to use variables (check in sequence for syntax)", require=True), 'folder_path': fields.char('Folder Path', size=128, help="folder that containt the incomming or the outgoing file"), 'archive_folder_path': fields.char('Archive Folder Path', size=128, help="if a path is set when a file is imported the file will be automatically moved to this folder"), 'encoding': fields.selection(_get_encoding, 'Encoding', require=True), 'field_ids': fields.one2many('file.fields', 'file_id', 'Fields'), 'action_before_all': fields.text('Action Before All', help="This python code will executed after the import/export"), 'action_after_all': fields.text('Action After All', help="This python code will executed after the import/export"), 'action_before_each': fields.text('Action Before Each', help="This python code will executed after each element of the import/export"), 'action_after_each': fields.text('Action After Each', help="This python code will executed after each element of the import/export"), 'check_if_import': fields.text('Check If Import', help="This python code will be executed before each element of the import"), 'delimiter':fields.char('Fields delimiter', size=64, help="Delimiter used in the CSV file"), 'lang': fields.many2one('res.lang', 'Language'), 'import_default_fields':fields.one2many('file.default.import.values', 'file_id', 'Default Field'), 'do_not_update':fields.boolean('Do Not Update'), 'pre_processing': fields.text('Pre-Processing', help="This python code will be executed before merge of elements of the import"), 'mapping_template_id':fields.many2one('external.mapping.template', 'External Mapping Template', require="True"), 'notes': fields.text('Notes'), 'related_mapping_ids': fields.function(_get_related_mapping_ids, type="many2many", relation="external.mapping", string='Related Mappings'), 'synchronize_from': fields.selection([('referential', 'Referential'), ('pop_up', 'Pop Up')], string='Synchronize From'), 'linked_task': fields.many2one('file.exchange', 'Linked Task'),
class mrp_servicemc(osv.osv): _name = 'mrp.servicemc' _inherit = 'mail.thread' _description = 'servicemc Order' def _amount_untaxed(self, cr, uid, ids, field_name, arg, context=None): """ Calculates untaxed amount. @param self: The object pointer @param cr: The current row, from the database cursor, @param uid: The current user ID for security checks @param ids: List of selected IDs @param field_name: Name of field. @param arg: Argument @param context: A standard dictionary for contextual values @return: Dictionary of values. """ res = {} cur_obj = self.pool.get('res.currency') for servicemc in self.browse(cr, uid, ids, context=context): res[servicemc.id] = 0.0 for line in servicemc.operations: res[servicemc.id] += line.price_subtotal for line in servicemc.fees_lines: res[servicemc.id] += line.price_subtotal cur = servicemc.pricelist_id.currency_id res[servicemc.id] = cur_obj.round(cr, uid, cur, res[servicemc.id]) return res def _amount_tax(self, cr, uid, ids, field_name, arg, context=None): """ Calculates taxed amount. @param field_name: Name of field. @param arg: Argument @return: Dictionary of values. """ res = {} #return {}.fromkeys(ids, 0) cur_obj = self.pool.get('res.currency') tax_obj = self.pool.get('account.tax') for servicemc in self.browse(cr, uid, ids, context=context): val = 0.0 cur = servicemc.pricelist_id.currency_id for line in servicemc.operations: #manage prices with tax included use compute_all instead of compute if line.to_invoice: tax_calculate = tax_obj.compute_all(cr, uid, line.tax_id, line.price_unit, line.product_uom_qty, line.product_id, servicemc.partner_id) for c in tax_calculate['taxes']: val += c['amount'] for line in servicemc.fees_lines: if line.to_invoice: tax_calculate = tax_obj.compute_all(cr, uid, line.tax_id, line.price_unit, line.product_uom_qty, line.product_id, servicemc.partner_id) for c in tax_calculate['taxes']: val += c['amount'] res[servicemc.id] = cur_obj.round(cr, uid, cur, val) return res def _amount_total(self, cr, uid, ids, field_name, arg, context=None): """ Calculates total amount. @param field_name: Name of field. @param arg: Argument @return: Dictionary of values. """ res = {} untax = self._amount_untaxed(cr, uid, ids, field_name, arg, context=context) tax = self._amount_tax(cr, uid, ids, field_name, arg, context=context) cur_obj = self.pool.get('res.currency') for id in ids: servicemc = self.browse(cr, uid, id, context=context) cur = servicemc.pricelist_id.currency_id res[id] = cur_obj.round(cr, uid, cur, untax.get(id, 0.0) + tax.get(id, 0.0)) return res def _get_default_address(self, cr, uid, ids, field_name, arg, context=None): res = {} partner_obj = self.pool.get('res.partner') for data in self.browse(cr, uid, ids, context=context): adr_id = False if data.partner_id: adr_id = partner_obj.address_get(cr, uid, [data.partner_id.id], ['default'])['default'] res[data.id] = adr_id return res def _get_lines(self, cr, uid, ids, context=None): return self.pool['mrp.servicemc'].search( cr, uid, [('operations', 'in', ids)], context=context) def _get_fee_lines(self, cr, uid, ids, context=None): return self.pool['mrp.servicemc'].search( cr, uid, [('fees_lines', 'in', ids)], context=context) _columns = { 'facproducto': fields.many2one('product.product','Producto'), 'facpreciounitario': fields.float('Precio unitario', help = 'Precio unitario', required=True), 'facimpuestos': fields.many2many('account.tax', 'repair_operation_line_tax', 'repair_operation_line_id', 'tax_id', 'Impuesto'), 'facafacturar':fields.boolean('A facturar'), 'facsubtotal':fields.float('Subtotal'), 'total': fields.float('Total'), 'faccantidad': fields.float('Cantidad',help = 'Cantidad',required=True), 'noeconomicomc':fields.char('Numero Economico',size=24), 'noseriemc':fields.char('Numero de Serie',size=24), 'name': fields.char('servicemc Reference',size=24, required=True, states={'confirmed':[('readonly',True)]}), 'product_id': fields.many2one('product.product', string='Product to give service', required=True, readonly=True, states={'draft':[('readonly',False)]}), 'partner_id' : fields.many2one('res.partner', 'Partner', select=True, help='Choose partner for whom the order will be invoiced and delivered.', states={'confirmed':[('readonly',True)]}), 'address_id': fields.many2one('res.partner', 'Delivery Address', domain="[('parent_id','=',partner_id)]", states={'confirmed':[('readonly',True)]}), 'default_address_id': fields.function(_get_default_address, type="many2one", relation="res.partner"), 'prodlot_id': fields.many2one('stock.production.lot', 'Lot Number', select=True, states={'draft':[('readonly',False)]},domain="[('product_id','=',product_id)]"), 'state': fields.selection([ ('draft','Quotation'), ('cancel','Cancelled'), ('confirmed','Confirmed'), ('under_servicemc','Under servicio'), ('ready','listo para dar servicio'), ('2binvoiced','To be Invoiced'), ('invoice_except','Invoice Exception'), ('done','Hecho') ], 'Status', readonly=True, track_visibility='onchange', help=' * The \'Draft\' status is used when a user is encoding a new and unconfirmed servicemc order. \ \n* The \'Confirmed\' status is used when a user confirms the servicemc order. \ \n* The \'Ready to servicemc\' status is used to start to servicemcing, user can start servicemcing only after servicemc order is confirmed. \ \n* The \'To be Invoiced\' status is used to generate the invoice before or after servicemcing done. \ \n* The \'Done\' status is set when servicemcing is completed.\ \n* The \'Cancelled\' status is used when user cancel servicemc order.'), 'location_id': fields.many2one('stock.location', 'Current Location', select=True, readonly=True, states={'draft':[('readonly',False)], 'confirmed':[('readonly',True)]}), 'location_dest_id': fields.many2one('stock.location', 'Delivery Location', readonly=True, states={'draft':[('readonly',False)], 'confirmed':[('readonly',True)]}), 'move_id': fields.many2one('stock.move', 'Move',required=True, domain="[('product_id','=',product_id)]", readonly=True, states={'draft':[('readonly',False)]}), 'guarantee_limit': fields.date('Warranty Expiration', help="The warranty expiration limit is computed as: last move date + warranty defined on selected product. If the current date is below the warranty expiration limit, each operation and fee you will add will be set as 'not to invoiced' by default. Note that you can change manually afterwards.", states={'confirmed':[('readonly',True)]}), 'operations' : fields.one2many('mrp.servicemc.line', 'servicemc_id', 'Operation Lines', readonly=True, states={'draft':[('readonly',False)]}), 'pricelist_id': fields.many2one('product.pricelist', 'Pricelist', help='Pricelist of the selected partner.'), 'partner_invoice_id':fields.many2one('res.partner', 'Invoicing Address'), 'invoice_method':fields.selection([ ("none","No Invoice"), ("b4servicemc","Before servicemc"), ("after_servicemc","After servicemc") ], "Invoice Method", select=True, required=True, states={'draft':[('readonly',False)]}, readonly=True, help='Selecting \'Before servicemc\' or \'After servicemc\' will allow you to generate invoice before or after the servicemc is done respectively. \'No invoice\' means you don\'t want to generate invoice for this servicemc order.'), 'invoice_id': fields.many2one('account.invoice', 'Invoice', readonly=True), 'picking_id': fields.many2one('stock.picking', 'Picking',readonly=True), 'fees_lines': fields.one2many('mrp.servicemc.fee', 'servicemc_id', 'Fees Lines', readonly=True, states={'draft':[('readonly',False)]}), 'internal_notes': fields.text('Internal Notes'), 'quotation_notes': fields.text('Quotation Notes'), 'company_id': fields.many2one('res.company', 'Company'), 'deliver_bool': fields.boolean('Deliver', help="Check this box if you want to manage the delivery once the product is servicemced and create a picking with selected product. Note that you can select the locations in the Info tab, if you have the extended view.", states={'confirmed':[('readonly',True)]}), 'invoiced': fields.boolean('Invoiced', readonly=True), 'servicemced': fields.boolean('Entregado', readonly=True), 'amount_untaxed': fields.function(_amount_untaxed, string='Untaxed Amount', store={ 'mrp.servicemc': (lambda self, cr, uid, ids, c={}: ids, ['operations', 'fees_lines'], 10), 'mrp.servicemc.line': (_get_lines, ['price_unit', 'price_subtotal', 'product_id', 'tax_id', 'product_uom_qty', 'product_uom'], 10), 'mrp.servicemc.fee': (_get_fee_lines, ['price_unit', 'price_subtotal', 'product_id', 'tax_id', 'product_uom_qty', 'product_uom'], 10), }), 'amount_tax': fields.function(_amount_tax, string='Taxes', store={ 'mrp.servicemc': (lambda self, cr, uid, ids, c={}: ids, ['operations', 'fees_lines'], 10), 'mrp.servicemc.line': (_get_lines, ['price_unit', 'price_subtotal', 'product_id', 'tax_id', 'product_uom_qty', 'product_uom'], 10), 'mrp.servicemc.fee': (_get_fee_lines, ['price_unit', 'price_subtotal', 'product_id', 'tax_id', 'product_uom_qty', 'product_uom'], 10), }), 'amount_total': fields.function(_amount_total, string='Total', store={ 'mrp.servicemc': (lambda self, cr, uid, ids, c={}: ids, ['operations', 'fees_lines'], 10), 'mrp.servicemc.line': (_get_lines, ['price_unit', 'price_subtotal', 'product_id', 'tax_id', 'product_uom_qty', 'product_uom'], 10), 'mrp.servicemc.fee': (_get_fee_lines, ['price_unit', 'price_subtotal', 'product_id', 'tax_id', 'product_uom_qty', 'product_uom'], 10), }), 'clienteNombre': fields.many2one('res.partner','Nombre del Cliente', required= True), 'clienteEntregaNombre': fields.many2one('res.partner','Nombre del Cliente'), 'empresaEntregaNombre': fields.many2one('hr.employee','Nombre'), 'empresaNombre': fields.many2one('hr.employee','Nombre Jefe de Area'), 'produccion_fecha_final': fields.date('Fecha final', required = False), 'produccion_notas': fields.text('Notas'), 'produccion_re_ter_unidad': fields.many2one('hr.employee','Reporta Terminio de la Unidad', required=False), 'calidad_fecha_inicial': fields.date('Fecha Inicial', required = False), 'calidad_fecha_final': fields.date('Fecha Final', required = False), 'calidad_notas': fields.text('Notas'), 'calidad_re_li_unidad': fields.many2one('hr.employee','Reporta Terminio de la Unidad', required=False), 'calidad_fecha_liberacion': fields.date('Fecha de Liberacion', required = False), 'calidad_pri_inpeccion': fields.boolean('Primera Inspeccion'), 'calidad_liberada': fields.boolean('Liberada'), 'fecha_alta': fields.date('Fecha de Alta', required = True), 'modelo_id': fields.many2one('fleet.vehicle','Modelo',required = True), } _defaults = { 'state': lambda *a: 'draft', 'deliver_bool': lambda *a: True, 'name': lambda obj, cr, uid, context: obj.pool.get('ir.sequence').get(cr, uid, 'mrp.servicemc'), 'invoice_method': lambda *a: 'none', 'company_id': lambda self, cr, uid, context: self.pool.get('res.company')._company_default_get(cr, uid, 'mrp.servicemc', context=context), 'pricelist_id': lambda self, cr, uid,context : self.pool.get('product.pricelist').search(cr, uid, [('type','=','sale')])[0] } def copy(self, cr, uid, id, default=None, context=None): if not default: default = {} default.update({ 'state':'draft', 'servicemced':False, 'invoiced':False, 'invoice_id': False, 'picking_id': False, 'name': self.pool.get('ir.sequence').get(cr, uid, 'mrp.servicemc'), }) return super(mrp_servicemc, self).copy(cr, uid, id, default, context) def onchange_product_id(self, cr, uid, ids, product_id=None): """ On change of product sets some values. @param product_id: Changed product @return: Dictionary of values. """ return {'value': { 'prodlot_id': False, 'move_id': False, 'guarantee_limit' :False, 'location_id': False, 'location_dest_id': False, } } def onchange_move_id(self, cr, uid, ids, prod_id=False, move_id=False): """ On change of move id sets values of guarantee limit, source location, destination location, partner and partner address. @param prod_id: Id of product in current record. @param move_id: Changed move. @return: Dictionary of values. """ data = {} data['value'] = {'guarantee_limit': False, 'location_id': False, 'prodlot_id': False, 'partner_id': False} if not prod_id: return data if move_id: move = self.pool.get('stock.move').browse(cr, uid, move_id) product = self.pool.get('product.product').browse(cr, uid, prod_id) limit = datetime.strptime(move.date_expected, '%Y-%m-%d %H:%M:%S') + relativedelta(months=int(product.warranty)) data['value']['guarantee_limit'] = limit.strftime('%Y-%m-%d') data['value']['location_id'] = move.location_dest_id.id data['value']['location_dest_id'] = move.location_dest_id.id data['value']['prodlot_id'] = move.prodlot_id.id if move.partner_id: data['value']['partner_id'] = move.partner_id.id else: data['value']['partner_id'] = False d = self.onchange_partner_id(cr, uid, ids, data['value']['partner_id'], data['value']['partner_id']) data['value'].update(d['value']) return data def button_dummy(self, cr, uid, ids, context=None): return True def onchange_partner_id(self, cr, uid, ids, part, address_id): """ On change of partner sets the values of partner address, partner invoice address and pricelist. @param part: Changed id of partner. @param address_id: Address id from current record. @return: Dictionary of values. """ part_obj = self.pool.get('res.partner') pricelist_obj = self.pool.get('product.pricelist') if not part: return {'value': { 'address_id': False, 'partner_invoice_id': False, 'pricelist_id': pricelist_obj.search(cr, uid, [('type','=','sale')])[0] } } addr = part_obj.address_get(cr, uid, [part], ['delivery', 'invoice', 'default']) partner = part_obj.browse(cr, uid, part) pricelist = partner.property_product_pricelist and partner.property_product_pricelist.id or False return {'value': { 'address_id': addr['delivery'] or addr['default'], 'partner_invoice_id': addr['invoice'], 'pricelist_id': pricelist } } def onchange_lot_id(self, cr, uid, ids, lot, product_id): """ On change of Serial Number sets the values of source location, destination location, move and guarantee limit. @param lot: Changed id of Serial Number. @param product_id: Product id from current record. @return: Dictionary of values. """ move_obj = self.pool.get('stock.move') data = {} data['value'] = { 'location_id': False, 'location_dest_id': False, 'move_id': False, 'guarantee_limit': False } if not lot: return data move_ids = move_obj.search(cr, uid, [('prodlot_id', '=', lot)]) if not len(move_ids): return data def get_last_move(lst_move): while lst_move.move_dest_id and lst_move.move_dest_id.state == 'done': lst_move = lst_move.move_dest_id return lst_move move_id = move_ids[0] move = get_last_move(move_obj.browse(cr, uid, move_id)) data['value']['move_id'] = move.id d = self.onchange_move_id(cr, uid, ids, product_id, move.id) data['value'].update(d['value']) return data def action_cancel_draft(self, cr, uid, ids, *args): """ Cancels servicemc order when it is in 'Draft' state. @param *arg: Arguments @return: True """ if not len(ids): return False mrp_line_obj = self.pool.get('mrp.servicemc.line') for servicemc in self.browse(cr, uid, ids): mrp_line_obj.write(cr, uid, [l.id for l in servicemc.operations], {'state': 'draft'}) self.write(cr, uid, ids, {'state':'draft'}) wf_service = netsvc.LocalService("workflow") for id in ids: wf_service.trg_create(uid, 'mrp.servicemc', id, cr) return True def action_confirm(self, cr, uid, ids, *args): """ servicemc order state is set to 'To be invoiced' when invoice method is 'Before servicemc' else state becomes 'Confirmed'. @param *arg: Arguments @return: True """ mrp_line_obj = self.pool.get('mrp.servicemc.line') for o in self.browse(cr, uid, ids): if (o.invoice_method == 'b4servicemc'): self.write(cr, uid, [o.id], {'state': '2binvoiced'}) else: self.write(cr, uid, [o.id], {'state': 'confirmed'}) for line in o.operations: if line.product_id.track_production and not line.prodlot_id: raise osv.except_osv(_('Warning!'), _("Serial number is required for operation line with product '%s'") % (line.product_id.name)) mrp_line_obj.write(cr, uid, [l.id for l in o.operations], {'state': 'confirmed'}) return True def action_cancel(self, cr, uid, ids, context=None): """ Cancels servicemc order. @return: True """ mrp_line_obj = self.pool.get('mrp.servicemc.line') for servicemc in self.browse(cr, uid, ids, context=context): if not servicemc.invoiced: mrp_line_obj.write(cr, uid, [l.id for l in servicemc.operations], {'state': 'cancel'}, context=context) else: raise osv.except_osv(_('Warning!'),_('servicemc order is already invoiced.')) return self.write(cr,uid,ids,{'state':'cancel'}) def wkf_invoice_create(self, cr, uid, ids, *args): self.action_invoice_create(cr, uid, ids) return True def action_invoice_create(self, cr, uid, ids, group=False, context=None): """ Creates invoice(s) for servicemc order. @param group: It is set to true when group invoice is to be generated. @return: Invoice Ids. """ res = {} invoices_group = {} inv_line_obj = self.pool.get('account.invoice.line') inv_obj = self.pool.get('account.invoice') servicemc_line_obj = self.pool.get('mrp.servicemc.line') servicemc_fee_obj = self.pool.get('mrp.servicemc.fee') for servicemc in self.browse(cr, uid, ids, context=context): res[servicemc.id] = False if servicemc.state in ('draft','cancel') or servicemc.invoice_id: continue if not (servicemc.partner_id.id and servicemc.partner_invoice_id.id): raise osv.except_osv(_('No partner!'),_('You have to select a Partner Invoice Address in the servicemc form!')) comment = servicemc.quotation_notes if (servicemc.invoice_method != 'none'): if group and servicemc.partner_invoice_id.id in invoices_group: inv_id = invoices_group[servicemc.partner_invoice_id.id] invoice = inv_obj.browse(cr, uid, inv_id) invoice_vals = { 'name': invoice.name +', '+servicemc.name, 'origin': invoice.origin+', '+servicemc.name, 'comment':(comment and (invoice.comment and invoice.comment+"\n"+comment or comment)) or (invoice.comment and invoice.comment or ''), } inv_obj.write(cr, uid, [inv_id], invoice_vals, context=context) else: if not servicemc.partner_id.property_account_receivable: raise osv.except_osv(_('Error!'), _('No account defined for partner "%s".') % servicemc.partner_id.name ) account_id = servicemc.partner_id.property_account_receivable.id inv = { 'name': servicemc.name, 'origin':servicemc.name, 'type': 'out_invoice', 'account_id': account_id, 'partner_id': servicemc.partner_id.id, 'currency_id': servicemc.pricelist_id.currency_id.id, 'comment': servicemc.quotation_notes, 'fiscal_position': servicemc.partner_id.property_account_position.id } inv_id = inv_obj.create(cr, uid, inv) invoices_group[servicemc.partner_invoice_id.id] = inv_id self.write(cr, uid, servicemc.id, {'invoiced': True, 'invoice_id': inv_id}) for operation in servicemc.operations: if operation.to_invoice == True: if group: name = servicemc.name + '-' + operation.name else: name = operation.name if operation.product_id.property_account_income: account_id = operation.product_id.property_account_income.id elif operation.product_id.categ_id.property_account_income_categ: account_id = operation.product_id.categ_id.property_account_income_categ.id else: raise osv.except_osv(_('Error!'), _('No account defined for product "%s".') % operation.product_id.name ) invoice_line_id = inv_line_obj.create(cr, uid, { 'invoice_id': inv_id, 'name': name, 'origin': servicemc.name, 'account_id': account_id, 'quantity': operation.product_uom_qty, 'invoice_line_tax_id': [(6,0,[x.id for x in operation.tax_id])], 'uos_id': operation.product_uom.id, 'price_unit': operation.price_unit, 'price_subtotal': operation.product_uom_qty*operation.price_unit, 'product_id': operation.product_id and operation.product_id.id or False }) servicemc_line_obj.write(cr, uid, [operation.id], {'invoiced': True, 'invoice_line_id': invoice_line_id}) for fee in servicemc.fees_lines: if fee.to_invoice == True: if group: name = servicemc.name + '-' + fee.name else: name = fee.name if not fee.product_id: raise osv.except_osv(_('Warning!'), _('No product defined on Fees!')) if fee.product_id.property_account_income: account_id = fee.product_id.property_account_income.id elif fee.product_id.categ_id.property_account_income_categ: account_id = fee.product_id.categ_id.property_account_income_categ.id else: raise osv.except_osv(_('Error!'), _('No account defined for product "%s".') % fee.product_id.name) invoice_fee_id = inv_line_obj.create(cr, uid, { 'invoice_id': inv_id, 'name': name, 'origin': servicemc.name, 'account_id': account_id, 'quantity': fee.product_uom_qty, 'invoice_line_tax_id': [(6,0,[x.id for x in fee.tax_id])], 'uos_id': fee.product_uom.id, 'product_id': fee.product_id and fee.product_id.id or False, 'price_unit': fee.price_unit, 'price_subtotal': fee.product_uom_qty*fee.price_unit }) servicemc_fee_obj.write(cr, uid, [fee.id], {'invoiced': True, 'invoice_line_id': invoice_fee_id}) res[servicemc.id] = inv_id return res def action_servicemc_ready(self, cr, uid, ids, context=None): """ Writes servicemc order state to 'Ready' @return: True """ for servicemc in self.browse(cr, uid, ids, context=context): self.pool.get('mrp.servicemc.line').write(cr, uid, [l.id for l in servicemc.operations], {'state': 'confirmed'}, context=context) self.write(cr, uid, [servicemc.id], {'state': 'ready'}) return True def action_servicemc_start(self, cr, uid, ids, context=None): """ Writes servicemc order state to 'Under servicemc' @return: True """ servicemc_line = self.pool.get('mrp.servicemc.line') for servicemc in self.browse(cr, uid, ids, context=context): servicemc_line.write(cr, uid, [l.id for l in servicemc.operations], {'state': 'confirmed'}, context=context) servicemc.write({'state': 'under_servicemc'}) return True def action_servicemc_end(self, cr, uid, ids, context=None): """ Writes servicemc order state to 'To be invoiced' if invoice method is After servicemc else state is set to 'Ready'. @return: True """ for order in self.browse(cr, uid, ids, context=context): val = {} val['servicemced'] = True if (not order.invoiced and order.invoice_method=='after_servicemc'): val['state'] = '2binvoiced' elif (not order.invoiced and order.invoice_method=='b4servicemc'): val['state'] = 'ready' else: pass self.write(cr, uid, [order.id], val) return True def wkf_servicemc_done(self, cr, uid, ids, *args): self.action_servicemc_done(cr, uid, ids) return True def action_servicemc_done(self, cr, uid, ids, context=None): """ Creates stock move and picking for servicemc order. @return: Picking ids. """ res = {} move_obj = self.pool.get('stock.move') wf_service = netsvc.LocalService("workflow") servicemc_line_obj = self.pool.get('mrp.servicemc.line') seq_obj = self.pool.get('ir.sequence') pick_obj = self.pool.get('stock.picking') for servicemc in self.browse(cr, uid, ids, context=context): for move in servicemc.operations: move_id = move_obj.create(cr, uid, { 'name': move.name, 'product_id': move.product_id.id, 'product_qty': move.product_uom_qty, 'product_uom': move.product_uom.id, 'partner_id': servicemc.address_id and servicemc.address_id.id or False, 'location_id': move.location_id.id, 'location_dest_id': move.location_dest_id.id, 'tracking_id': False, 'prodlot_id': move.prodlot_id and move.prodlot_id.id or False, 'state': 'assigned', }) move_obj.action_done(cr, uid, [move_id], context=context) servicemc_line_obj.write(cr, uid, [move.id], {'move_id': move_id, 'state': 'done'}, context=context) if servicemc.deliver_bool: pick_name = seq_obj.get(cr, uid, 'stock.picking.out') picking = pick_obj.create(cr, uid, { 'name': pick_name, 'origin': servicemc.name, 'state': 'draft', 'move_type': 'one', 'partner_id': servicemc.address_id and servicemc.address_id.id or False, 'note': servicemc.internal_notes, 'invoice_state': 'none', 'type': 'out', }) move_id = move_obj.create(cr, uid, { 'name': servicemc.name, 'picking_id': picking, 'product_id': servicemc.product_id.id, 'product_uom': servicemc.product_id.uom_id.id, 'prodlot_id': servicemc.prodlot_id and servicemc.prodlot_id.id or False, 'partner_id': servicemc.address_id and servicemc.address_id.id or False, 'location_id': servicemc.location_id.id, 'location_dest_id': servicemc.location_dest_id.id, 'tracking_id': False, 'state': 'assigned', }) wf_service.trg_validate(uid, 'stock.picking', picking, 'button_confirm', cr) self.write(cr, uid, [servicemc.id], {'state': 'done', 'picking_id': picking}) res[servicemc.id] = picking else: self.write(cr, uid, [servicemc.id], {'state': 'done'}) return res
class res_users(osv.osv): _inherit = 'res.users' _columns = { 'quarantine_files_ids': fields.one2many('antivir.quarantine', 'user_id', 'Quarantine files') }
class hr_contract_mod_wiz(osv.TransientModel): _name = 'hr.contract.mod.wiz' _description = 'Mis a jour salaire en masse' _columns = { 'date': fields.date('Date', required=True), 'perc_increase': fields.float('Pourcentage augmentation', required=True), 'amount_increase': fields.float('Montant augmentation', required=True), 'start': fields.many2one('account.period', 'Date effet'), # Rétro-actif depuis 'period_id': fields.many2one('account.period', 'Periode applicable', required=True, domain=[('date_start', '>', datetime.date.today().strftime('%Y-01-01'))]), 'employee_ids': fields.many2many('hr.employee', 'cont_dept_emp_rel', 'sum_id', 'emp_id', 'Employee(s)', domain=[('active', '=', True)]), 'rubrique_ids':fields.one2many('rubrique.line.wiz', 'cont_mod_id', 'Rubriques'), } def generate(self, cr, uid, ids, context=None): data = self.read(cr, uid, ids, [])[0] # raise osv.except_osv(_('data'),_('data = %s')%(data)) contract_obj = self.pool.get('hr.contract') period_obj = self.pool.get('account.period') proposal_obj = self.pool.get('hr.salary.proposal') proposal_line_obj = self.pool.get('hr.salary.proposal.line') period_id = period_obj.browse(cr, uid, [data['period_id'][0]])[0] start = period_obj.browse(cr, uid, [data['start'][0]])[0] prev_period_id = period_obj.browse(cr, uid, [data['period_id'][0] - 1])[0] rub_line_obj = self.pool.get('rub.update.line') ############################################################ # if data: # raise osv.except_osv(_('data'), _('%s')%data) v = data['period_id'][0] period_id = period_obj.browse(cr, uid, [v])[0] # periode de paie et return an object type class start = period_obj.browse(cr, uid, [data['start'][0]])[0] # periode pour les rappels # prev_period_id=period_obj.browse(cr,uid,[data['period_id'][0]-1])[0] created = [] if not data['employee_ids']: raise osv.except_osv(_('Error'), _('You have to select at least 1 Employee. And try again')) proposal = proposal_obj.search(cr, uid, [('name', '=', period_id.id)]) # return list of result if proposal == []: proposal = proposal_obj.create(cr, uid, {'name':period_id.id, 'start':start.id, 'date':datetime.date.today().strftime('%Y-%m-%d')}) else: proposal = proposal[0] created.append(proposal) # "id du proposition salariale (list) identifier par la période" date_today = datetime.date.today().strftime('%Y-%m-%d') contract_ids1 = contract_obj.search(cr, uid, [('employee_id', 'in', data['employee_ids']), '|', ('date_end', '=', False), ('date_end', '>=', date_today)]) # ou date_end est dans le futur(> today) contract_ids = contract_obj.read(cr, uid, contract_ids1, ['wage']) # raise osv.except_osv(_('contract_ids'),_('contract_ids = %s \n contract_ids1 = %s')%(contract_ids,contract_ids1)) for contract in contract_ids: proposal_line = proposal_line_obj.search(cr, uid, [('proposal_id', '=', created[0]), ('contract_id', '=', contract['id'])]) if proposal_line == []: wage = contract['wage'] + (contract['wage'] * (data['perc_increase']) / 100) + data['amount_increase'] pl = proposal_line_obj.create(cr, uid, {'contract_id':contract['id'], 'salary_proposal':wage, 'proposal_id':created[0]}) rubrique_lines = self.pool.get('rubrique.line.wiz').browse(cr, uid, data['rubrique_ids']) for rubrique in rubrique_lines: rub = {'proposal_line_id':pl, 'name':rubrique.name.id, 'perc_increase': rubrique.perc_increase, 'amount_increase': rubrique.amount_increase, } rub_line_obj.create(cr, uid, rub) else: wage = 0 pl = 0 if data['perc_increase'] != 0 or data['amount_increase'] != 0: wage = contract['wage'] + (contract['wage'] * (data['perc_increase']) / 100) + data['amount_increase'] pl = proposal_line_obj.write(cr, uid, proposal_line[0], {'contract_id':contract['id'], 'salary_proposal':wage, 'proposal_id':created[0]}) else: pl = proposal_line_obj.write(cr, uid, proposal_line[0], {'contract_id':contract['id'], 'proposal_id':created[0]}) # pl=proposal_line_obj.write(cr,uid,proposal_line[0],{'contract_id':contract['id'],'salary_proposal':wage,'proposal_id':created[0]}) rubrique_lines = self.pool.get('rubrique.line.wiz').browse(cr, uid, data['rubrique_ids']) for rubrique in rubrique_lines: condition = [('name', '=', rubrique.name.id), ('proposal_line_id', '=', proposal_line[0])] search_id = rub_line_obj.search(cr, uid, condition) rub = {'proposal_line_id':proposal_line[0], 'name':rubrique.name.id, 'perc_increase': rubrique.perc_increase, 'amount_increase': rubrique.amount_increase, } is_rub_exist = False if len(search_id) == 0: is_rub_exist = False else: is_rub_exist = True if not is_rub_exist: rub_line_obj.create(cr, uid, rub) else: rub_line_obj.write(cr, uid, search_id[0], rub) ################################################## # test={ # 'domain': "[('id','in', ["+','.join(map(str,created))+"])]", # 'name': 'Contrats', # 'view_type': 'form', # 'view_mode': 'tree,form', # 'res_model': 'hr.salary.proposal', # 'view_id': False, # 'type': 'ir.actions.act_window', # } # if test: # raise osv.except_osv(_('test'), _('%s')%test) ################################################## return { 'domain': "[('id','in', [" + ','.join(map(str, created)) + "])]", 'name': 'Contrats', 'view_type': 'form', 'view_mode': 'tree,form', 'res_model': 'hr.salary.proposal', 'view_id': False, 'type': 'ir.actions.act_window', } def _from_date(self, cursor, user, context={}): return datetime.date.today().strftime('%Y-%m-%d'); _defaults = { 'date': _from_date, }
return resu _columns = { 'employee_id': fields.many2one('hr.employee', 'Employee', required=True, select=True), 'department_id':fields.related('employee_id','department_id', type='many2one', relation='hr.department', string='Department', store=True), 'job_id':fields.related('employee_id','job_id', type='many2one', relation='hr.job', string='Title', store=True), 'emp_code':fields.related('employee_id','emp_code', type='char', string='Employee Code', store=True), 'mobile_phone':fields.related('employee_id','mobile_phone', type='char', string='Work Mobile', store=True), 'borrow_money_residual':fields.related('employee_id','money_residual', type='float', string='Borrowed residual', readonly=True), 'dimmission_reason':fields.text('Dimission Reason', required=True), 'advice_to_company':fields.text('Advice to company'), 'employment_start':fields.date('Employment Started'), 'date_request':fields.date('Request Date', required=True), 'date_done':fields.date('Done Date', required=False, readonly=True), 'approve_ids': fields.one2many('hr.dimission.item', 'dimission_id', 'Approvals', domain=[('type','=','approve')]), 'transfer_ids': fields.one2many('hr.dimission.item', 'dimission_id', 'Transfers', domain=[('type','=','transfer')]), 'payslip_id': fields.many2many('hr.emppay', string='Payslip'), 'attrpt_ids': fields.many2many('hr.rpt.attend.month', string='Attendance Reports'), 'hr_clock_ids': fields.function(_emp_clocks, string='HR Clocks', type='many2many', relation='hr.clock', readonly=True), 'attachment_lines': fields.one2many('ir.attachment', 'hr_admission_id','Attachment'), 'company_id':fields.many2one('res.company', 'Company', required=True), 'state': fields.selection([ ('draft', 'Draft'), ('in_progress', 'In Progress'), ('done', 'Done'), ('cancel', 'Cancel'), ], 'Status', select=True, readonly=True), }
class hr_salary_proposal(osv.osv): _name = "hr.salary.proposal" _description = "Proposition de salaire" _columns = { 'date':fields.date('Date'), 'name': fields.many2one('account.period', 'Periode applicable', required=True), 'start': fields.many2one('account.period', 'Periode effet'), 'salary_line':fields.one2many('hr.salary.proposal.line', 'proposal_id', 'Nouvelle Grille'), } _order = "name desc" def validate (self, cr, uid, ids, context=None): """ Function doc """ contract_obj = self.pool.get('hr.contract') rubrique_obj = self.pool.get('hr.payroll_ma.ligne_rubrique') salary_line_obj = self.pool.get('hr.salary.proposal.line') rubrique_objt = self.pool.get('hr.payroll_ma.rubrique') # new line diff = 1 for proposal in self.browse(cr, uid, ids): for line in proposal.salary_line: date_start = datetime.datetime.strptime(proposal.name.date_start, '%Y-%m-%d') # _logger.info(line.contract_id.rubrique_ids) contract_info = contract_obj.copy(cr, uid, line.contract_id.id, default={'date_start':date_start, 'wage':line.salary_proposal}) perc = {} amt = {} rubriques = [] for rub in line.rubrique_ids: perc[rub.name.id] = rub.perc_increase amt[rub.name.id] = rub.amount_increase rubriques.append(rub.name.id) for rubrique in line.contract_id.rubrique_ids: if rubrique.rubrique_id.id in rubriques: amount = rubrique.montant + (rubrique.montant * perc[rubrique.rubrique_id.id] / 100) + amt[rubrique.rubrique_id.id] amount_arrondi = int(amount / 10) # * 10 reste_arrondi = amount % 10 if reste_arrondi >= 5: amount_arrondi += 1 amount_arrondi = amount_arrondi * 10 amount = amount_arrondi amount_diff = amount - rubrique.montant rubrique_obj.copy(cr, uid, rubrique.id, default={'id_contract':contract_info, 'montant':amount, }) if proposal.start: date1 = datetime.datetime.strptime(proposal.start.date_start, '%Y-%m-%d') date2 = datetime.datetime.strptime(proposal.name.date_start, '%Y-%m-%d') r = relativedelta.relativedelta(date2, date1) diff = r.months amount = amount_diff * diff rubrique_obj.copy(cr, uid, rubrique.id, default={'rubrique_id':rubrique.rubrique_id.rappel_rubrique_id.id, 'id_contract':contract_info, 'montant':amount, 'permanent':False, 'date_stop':datetime.datetime.strptime(proposal.name.date_stop, '%Y-%m-%d'), 'date_start':datetime.datetime.strptime(proposal.name.date_start, '%Y-%m-%d') }) else: rubrique_obj.copy(cr, uid, rubrique.id, default={'id_contract':contract_info}) # rappel saleire de base si il y avait augmentation # rubrique_obj.copy(cr,uid,rubrique.id, # default={ 'rubrique_id':rubrique.rubrique_id.rappel_rubrique_id.id, # 'id_contract':contract_info,'montant':amount,'permanent':False, # 'date_stop':datetime.datetime.strptime(proposal.name.date_stop,'%Y-%m-%d'), # 'date_start':datetime.datetime.strptime(proposal.name.date_start,'%Y-%m-%d')}) ################################################################################################ T = False if line.wage != line.salary_proposal: T = True if T: # rubrique_objt = self.pool.get('hr.payroll_ma.rubrique') rubrique_id = rubrique_objt.search(cr, uid, [('code', '=', '02')]) # id du rubrique rappel base if len(rubrique_id) == 0: raise osv.except_osv(_('Error'), _('This rubrique doesn\'t exist! \n create it! His code is: 02')) amount = line.wage * (line.perc_increase / 100) * diff new_rub_base = rubrique_obj.create(cr, uid, {'rubrique_id':rubrique_id[0], 'id_contract':contract_info, 'montant':amount, 'permanent':False, 'date_stop':datetime.datetime.strptime(proposal.name.date_stop, '%Y-%m-%d'), 'date_start':datetime.datetime.strptime(proposal.name.date_start, '%Y-%m-%d')}) ################################################################################################ new_contract = contract_info salary_line_obj.write(cr, uid, line.id, {'new_contract_id':new_contract})
), "product_uom": fields.many2one( "product.uom", "Unit of Measure ", required=True, readonly=True, states={"draft": [("readonly", False)]} ), "product_uos_qty": fields.float( "Quantity (UoS)", digits_compute=dp.get_precision("Product UoS"), readonly=True, states={"draft": [("readonly", False)]}, ), "product_uos": fields.many2one("product.uom", "Product UoS"), "product_rent_qty": fields.function( _product_rent_qty, string="Rent Quantity", digits_compute=dp.get_precision("Product UoS") ), "th_weight": fields.float("Weight", readonly=True, states={"draft": [("readonly", False)]}), "move_ids": fields.one2many("stock.move", "rent_line_id", "Inventory Moves", readonly=True), "state": fields.selection( [ ("draft", "Draft"), ("cancel", "Cancelled"), ("confirmed", "Waiting Approval"), ("accepted", "Approved"), ("returned", "Returned"), ("done", "Done"), ], "Status", required=True, readonly=True, ), "order_partner_id": fields.related( "order_id", "partner_id", type="many2one", relation="res.partner", store=True, string="Customer"
class account_bank_statement(osv.osv): def create(self, cr, uid, vals, context=None): if 'line_ids' in vals: for idx, line in enumerate(vals['line_ids']): line[2]['sequence'] = idx + 1 return super(account_bank_statement, self).create(cr, uid, vals, context=context) def write(self, cr, uid, ids, vals, context=None): res = super(account_bank_statement, self).write(cr, uid, ids, vals, context=context) account_bank_statement_line_obj = self.pool.get( 'account.bank.statement.line') for statement in self.browse(cr, uid, ids, context): for idx, line in enumerate(statement.line_ids): account_bank_statement_line_obj.write(cr, uid, [line.id], {'sequence': idx + 1}, context=context) return res def _default_journal_id(self, cr, uid, context=None): if context is None: context = {} journal_pool = self.pool.get('account.journal') journal_type = context.get('journal_type', False) company_id = self.pool.get('res.company')._company_default_get( cr, uid, 'account.bank.statement', context=context) if journal_type: ids = journal_pool.search(cr, uid, [('type', '=', journal_type), ('company_id', '=', company_id)]) if ids: return ids[0] return False def _end_balance(self, cursor, user, ids, name, attr, context=None): res = {} for statement in self.browse(cursor, user, ids, context=context): res[statement.id] = statement.balance_start for line in statement.line_ids: res[statement.id] += line.amount return res def _get_period(self, cr, uid, context=None): periods = self.pool.get('account.period').find(cr, uid, context=context) if periods: return periods[0] return False def _currency(self, cursor, user, ids, name, args, context=None): res = {} res_currency_obj = self.pool.get('res.currency') res_users_obj = self.pool.get('res.users') default_currency = res_users_obj.browse( cursor, user, user, context=context).company_id.currency_id for statement in self.browse(cursor, user, ids, context=context): currency = statement.journal_id.currency if not currency: currency = default_currency res[statement.id] = currency.id currency_names = {} for currency_id, currency_name in res_currency_obj.name_get( cursor, user, [x for x in res.values()], context=context): currency_names[currency_id] = currency_name for statement_id in res.keys(): currency_id = res[statement_id] res[statement_id] = (currency_id, currency_names[currency_id]) return res def _get_statement(self, cr, uid, ids, context=None): result = {} for line in self.pool.get('account.bank.statement.line').browse( cr, uid, ids, context=context): result[line.statement_id.id] = True return result.keys() _order = "date desc, id desc" _name = "account.bank.statement" _description = "Bank Statement" _inherit = ['mail.thread'] _columns = { 'name': fields.char( 'Reference', size=64, required=True, states={'draft': [('readonly', False)]}, readonly=True, help= 'if you give the Name other then /, its created Accounting Entries Move will be with same name as statement name. This allows the statement entries to have the same references than the statement itself' ), # readonly for account_cash_statement 'date': fields.date('Date', required=True, states={'confirm': [('readonly', True)]}, select=True), 'journal_id': fields.many2one('account.journal', 'Journal', required=True, readonly=True, states={'draft': [('readonly', False)]}), 'period_id': fields.many2one('account.period', 'Period', required=True, states={'confirm': [('readonly', True)]}), 'balance_start': fields.float('Starting Balance', digits_compute=dp.get_precision('Account'), states={'confirm': [('readonly', True)]}), 'balance_end_real': fields.float('Ending Balance', digits_compute=dp.get_precision('Account'), states={'confirm': [('readonly', True)]}), 'balance_end': fields.function( _end_balance, store={ 'account.bank.statement': (lambda self, cr, uid, ids, c={}: ids, ['line_ids', 'move_line_ids', 'balance_start'], 10), 'account.bank.statement.line': (_get_statement, ['amount'], 10), }, string="Computed Balance", help= 'Balance as calculated based on Starting Balance and transaction lines' ), 'company_id': fields.related('journal_id', 'company_id', type='many2one', relation='res.company', string='Company', store=True, readonly=True), 'line_ids': fields.one2many('account.bank.statement.line', 'statement_id', 'Statement lines', states={'confirm': [('readonly', True)]}), 'move_line_ids': fields.one2many('account.move.line', 'statement_id', 'Entry lines', states={'confirm': [('readonly', True)]}), 'state': fields.selection( [ ('draft', 'New'), ('open', 'Open'), # used by cash statements ('confirm', 'Closed') ], 'Status', required=True, readonly="1", help='When new statement is created the status will be \'Draft\'.\n' 'And after getting confirmation from the bank it will be in \'Confirmed\' status.' ), 'currency': fields.function(_currency, string='Currency', type='many2one', relation='res.currency'), 'account_id': fields.related( 'journal_id', 'default_debit_account_id', type='many2one', relation='account.account', string='Account used in this journal', readonly=True, help= 'used in statement reconciliation domain, but shouldn\'t be used elswhere.' ), } _defaults = { 'name': "/", 'date': fields.date.context_today, 'state': 'draft', 'journal_id': _default_journal_id, 'period_id': _get_period, 'company_id': lambda self, cr, uid, c: self.pool.get('res.company'). _company_default_get(cr, uid, 'account.bank.statement', context=c), } def _check_company_id(self, cr, uid, ids, context=None): for statement in self.browse(cr, uid, ids, context=context): if statement.company_id.id != statement.period_id.company_id.id: return False return True _constraints = [ (_check_company_id, 'The journal and period chosen have to belong to the same company.', ['journal_id', 'period_id']), ] def onchange_date(self, cr, uid, ids, date, company_id, context=None): """ Find the correct period to use for the given date and company_id, return it and set it in the context """ res = {} period_pool = self.pool.get('account.period') if context is None: context = {} ctx = context.copy() ctx.update({'company_id': company_id}) pids = period_pool.find(cr, uid, dt=date, context=ctx) if pids: res.update({'period_id': pids[0]}) context.update({'period_id': pids[0]}) return { 'value': res, 'context': context, } def button_dummy(self, cr, uid, ids, context=None): return self.write(cr, uid, ids, {}, context=context) def _prepare_move(self, cr, uid, st_line, st_line_number, context=None): """Prepare the dict of values to create the move from a statement line. This method may be overridden to implement custom move generation (making sure to call super() to establish a clean extension chain). :param browse_record st_line: account.bank.statement.line record to create the move from. :param char st_line_number: will be used as the name of the generated account move :return: dict of value to create() the account.move """ return { 'journal_id': st_line.statement_id.journal_id.id, 'period_id': st_line.statement_id.period_id.id, 'date': st_line.date, 'name': st_line_number, 'ref': st_line.ref, } def _prepare_bank_move_line(self, cr, uid, st_line, move_id, amount, company_currency_id, context=None): """Compute the args to build the dict of values to create the bank move line from a statement line by calling the _prepare_move_line_vals. This method may be overridden to implement custom move generation (making sure to call super() to establish a clean extension chain). :param browse_record st_line: account.bank.statement.line record to create the move from. :param int/long move_id: ID of the account.move to link the move line :param float amount: amount of the move line :param int/long company_currency_id: ID of currency of the concerned company :return: dict of value to create() the bank account.move.line """ anl_id = st_line.analytic_account_id and st_line.analytic_account_id.id or False debit = ((amount < 0) and -amount) or 0.0 credit = ((amount > 0) and amount) or 0.0 cur_id = False amt_cur = False if st_line.statement_id.currency.id <> company_currency_id: cur_id = st_line.statement_id.currency.id if st_line.account_id and st_line.account_id.currency_id and st_line.account_id.currency_id.id <> company_currency_id: cur_id = st_line.account_id.currency_id.id if cur_id: res_currency_obj = self.pool.get('res.currency') amt_cur = -res_currency_obj.compute( cr, uid, company_currency_id, cur_id, amount, context=context) res = self._prepare_move_line_vals(cr, uid, st_line, move_id, debit, credit, amount_currency=amt_cur, currency_id=cur_id, analytic_id=anl_id, context=context) return res def _get_counter_part_account(sefl, cr, uid, st_line, context=None): """Retrieve the account to use in the counterpart move. This method may be overridden to implement custom move generation (making sure to call super() to establish a clean extension chain). :param browse_record st_line: account.bank.statement.line record to create the move from. :return: int/long of the account.account to use as counterpart """ if st_line.amount >= 0: return st_line.statement_id.journal_id.default_credit_account_id.id return st_line.statement_id.journal_id.default_debit_account_id.id def _get_counter_part_partner(sefl, cr, uid, st_line, context=None): """Retrieve the partner to use in the counterpart move. This method may be overridden to implement custom move generation (making sure to call super() to establish a clean extension chain). :param browse_record st_line: account.bank.statement.line record to create the move from. :return: int/long of the res.partner to use as counterpart """ return st_line.partner_id and st_line.partner_id.id or False def _prepare_counterpart_move_line(self, cr, uid, st_line, move_id, amount, company_currency_id, context=None): """Compute the args to build the dict of values to create the counter part move line from a statement line by calling the _prepare_move_line_vals. This method may be overridden to implement custom move generation (making sure to call super() to establish a clean extension chain). :param browse_record st_line: account.bank.statement.line record to create the move from. :param int/long move_id: ID of the account.move to link the move line :param float amount: amount of the move line :param int/long account_id: ID of account to use as counter part :param int/long company_currency_id: ID of currency of the concerned company :return: dict of value to create() the bank account.move.line """ account_id = self._get_counter_part_account(cr, uid, st_line, context=context) partner_id = self._get_counter_part_partner(cr, uid, st_line, context=context) debit = ((amount > 0) and amount) or 0.0 credit = ((amount < 0) and -amount) or 0.0 cur_id = False amt_cur = False if st_line.statement_id.currency.id <> company_currency_id: amt_cur = st_line.amount cur_id = st_line.statement_id.currency.id return self._prepare_move_line_vals(cr, uid, st_line, move_id, debit, credit, amount_currency=amt_cur, currency_id=cur_id, account_id=account_id, partner_id=partner_id, context=context) def _prepare_move_line_vals(self, cr, uid, st_line, move_id, debit, credit, currency_id=False, amount_currency=False, account_id=False, analytic_id=False, partner_id=False, context=None): """Prepare the dict of values to create the move line from a statement line. All non-mandatory args will replace the default computed one. This method may be overridden to implement custom move generation (making sure to call super() to establish a clean extension chain). :param browse_record st_line: account.bank.statement.line record to create the move from. :param int/long move_id: ID of the account.move to link the move line :param float debit: debit amount of the move line :param float credit: credit amount of the move line :param int/long currency_id: ID of currency of the move line to create :param float amount_currency: amount of the debit/credit expressed in the currency_id :param int/long account_id: ID of the account to use in the move line if different from the statement line account ID :param int/long analytic_id: ID of analytic account to put on the move line :param int/long partner_id: ID of the partner to put on the move line :return: dict of value to create() the account.move.line """ acc_id = account_id or st_line.account_id.id cur_id = currency_id or st_line.statement_id.currency.id par_id = partner_id or (( (st_line.partner_id) and st_line.partner_id.id) or False) return { 'name': st_line.name, 'date': st_line.date, 'ref': st_line.ref, 'move_id': move_id, 'partner_id': par_id, 'account_id': acc_id, 'credit': credit, 'debit': debit, 'statement_id': st_line.statement_id.id, 'journal_id': st_line.statement_id.journal_id.id, 'period_id': st_line.statement_id.period_id.id, 'currency_id': amount_currency and cur_id, 'amount_currency': amount_currency, 'analytic_account_id': analytic_id, } def create_move_from_st_line(self, cr, uid, st_line_id, company_currency_id, st_line_number, context=None): """Create the account move from the statement line. :param int/long st_line_id: ID of the account.bank.statement.line to create the move from. :param int/long company_currency_id: ID of the res.currency of the company :param char st_line_number: will be used as the name of the generated account move :return: ID of the account.move created """ if context is None: context = {} res_currency_obj = self.pool.get('res.currency') account_move_obj = self.pool.get('account.move') account_move_line_obj = self.pool.get('account.move.line') account_bank_statement_line_obj = self.pool.get( 'account.bank.statement.line') st_line = account_bank_statement_line_obj.browse(cr, uid, st_line_id, context=context) st = st_line.statement_id context.update({'date': st_line.date}) move_vals = self._prepare_move(cr, uid, st_line, st_line_number, context=context) move_id = account_move_obj.create(cr, uid, move_vals, context=context) account_bank_statement_line_obj.write( cr, uid, [st_line.id], {'move_ids': [(4, move_id, False)]}) torec = [] acc_cur = ( (st_line.amount <= 0) and st.journal_id.default_debit_account_id) or st_line.account_id context.update({ 'res.currency.compute.account': acc_cur, }) amount = res_currency_obj.compute(cr, uid, st.currency.id, company_currency_id, st_line.amount, context=context) bank_move_vals = self._prepare_bank_move_line(cr, uid, st_line, move_id, amount, company_currency_id, context=context) move_line_id = account_move_line_obj.create(cr, uid, bank_move_vals, context=context) torec.append(move_line_id) counterpart_move_vals = self._prepare_counterpart_move_line( cr, uid, st_line, move_id, amount, company_currency_id, context=context) account_move_line_obj.create(cr, uid, counterpart_move_vals, context=context) for line in account_move_line_obj.browse( cr, uid, [ x.id for x in account_move_obj.browse( cr, uid, move_id, context=context).line_id ], context=context): if line.state <> 'valid': raise osv.except_osv( _('Error!'), _('Journal item "%s" is not valid.') % line.name) # Bank statements will not consider boolean on journal entry_posted account_move_obj.post(cr, uid, [move_id], context=context) return move_id def get_next_st_line_number(self, cr, uid, st_number, st_line, context=None): return st_number + '/' + str(st_line.sequence) def balance_check(self, cr, uid, st_id, journal_type='bank', context=None): st = self.browse(cr, uid, st_id, context=context) if not ((abs((st.balance_end or 0.0) - st.balance_end_real) < 0.0001) or (abs((st.balance_end or 0.0) - st.balance_end_real) < 0.0001)): raise osv.except_osv( _('Error!'), _('The statement balance is incorrect !\nThe expected balance (%.2f) is different than the computed one. (%.2f)' ) % (st.balance_end_real, st.balance_end)) return True def statement_close(self, cr, uid, ids, journal_type='bank', context=None): return self.write(cr, uid, ids, {'state': 'confirm'}, context=context) def check_status_condition(self, cr, uid, state, journal_type='bank'): return state in ('draft', 'open') def button_confirm_bank(self, cr, uid, ids, context=None): obj_seq = self.pool.get('ir.sequence') if context is None: context = {} for st in self.browse(cr, uid, ids, context=context): j_type = st.journal_id.type company_currency_id = st.journal_id.company_id.currency_id.id if not self.check_status_condition( cr, uid, st.state, journal_type=j_type): continue self.balance_check(cr, uid, st.id, journal_type=j_type, context=context) if (not st.journal_id.default_credit_account_id) \ or (not st.journal_id.default_debit_account_id): raise osv.except_osv( _('Configuration Error!'), _('Please verify that an account is defined in the journal.' )) if not st.name == '/': st_number = st.name else: c = {'fiscalyear_id': st.period_id.fiscalyear_id.id} if st.journal_id.sequence_id: st_number = obj_seq.next_by_id( cr, uid, st.journal_id.sequence_id.id, context=c) else: st_number = obj_seq.next_by_code(cr, uid, 'account.bank.statement', context=c) for line in st.move_line_ids: if line.state <> 'valid': raise osv.except_osv( _('Error!'), _('The account entries lines are not in valid state.')) for st_line in st.line_ids: if st_line.analytic_account_id: if not st.journal_id.analytic_journal_id: raise osv.except_osv( _('No Analytic Journal!'), _("You have to assign an analytic journal on the '%s' journal!" ) % (st.journal_id.name, )) if not st_line.amount: continue st_line_number = self.get_next_st_line_number( cr, uid, st_number, st_line, context) self.create_move_from_st_line(cr, uid, st_line.id, company_currency_id, st_line_number, context) self.write(cr, uid, [st.id], { 'name': st_number, 'balance_end_real': st.balance_end }, context=context) self.message_post( cr, uid, [st.id], body=_('Statement %s confirmed, journal items were created.') % (st_number, ), context=context) return self.write(cr, uid, ids, {'state': 'confirm'}, context=context) def button_cancel(self, cr, uid, ids, context=None): done = [] account_move_obj = self.pool.get('account.move') for st in self.browse(cr, uid, ids, context=context): if st.state == 'draft': continue move_ids = [] for line in st.line_ids: move_ids += [x.id for x in line.move_ids] account_move_obj.button_cancel(cr, uid, move_ids, context=context) account_move_obj.unlink(cr, uid, move_ids, context) done.append(st.id) return self.write(cr, uid, done, {'state': 'draft'}, context=context) def _compute_balance_end_real(self, cr, uid, journal_id, context=None): res = False if journal_id: cr.execute( 'SELECT balance_end_real \ FROM account_bank_statement \ WHERE journal_id = %s AND NOT state = %s \ ORDER BY date DESC,id DESC LIMIT 1', (journal_id, 'draft')) res = cr.fetchone() return res and res[0] or 0.0 def onchange_journal_id(self, cr, uid, statement_id, journal_id, context=None): if not journal_id: return {} balance_start = self._compute_balance_end_real(cr, uid, journal_id, context=context) journal_data = self.pool.get('account.journal').read( cr, uid, journal_id, ['company_id', 'currency'], context=context) company_id = journal_data['company_id'] currency_id = journal_data['currency'] or self.pool.get( 'res.company').browse(cr, uid, company_id[0], context=context).currency_id.id return { 'value': { 'balance_start': balance_start, 'company_id': company_id, 'currency': currency_id } } def unlink(self, cr, uid, ids, context=None): stat = self.read(cr, uid, ids, ['state'], context=context) unlink_ids = [] for t in stat: if t['state'] in ('draft'): unlink_ids.append(t['id']) else: raise osv.except_osv( _('Invalid Action!'), _('In order to delete a bank statement, you must first cancel it to delete related journal items.' )) osv.osv.unlink(self, cr, uid, unlink_ids, context=context) return True def copy(self, cr, uid, id, default=None, context=None): if default is None: default = {} if context is None: context = {} default = default.copy() default['move_line_ids'] = [] return super(account_bank_statement, self).copy(cr, uid, id, default, context=context) def button_journal_entries(self, cr, uid, ids, context=None): ctx = (context or {}).copy() ctx['journal_id'] = self.browse(cr, uid, ids[0], context=context).journal_id.id return { 'view_type': 'form', 'view_mode': 'tree', 'res_model': 'account.move.line', 'view_id': False, 'type': 'ir.actions.act_window', 'domain': [('statement_id', 'in', ids)], 'context': ctx, }
('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): _name = 'export.%s' % name _columns = { 'const': fields.integer(), 'value': field, } _defaults = { 'const': 4,
class rhwl_config(osv.osv): _name = "rhwl.weixin.base" _columns = { "name": fields.char("Name", size=20), "original_id": fields.char("Original ID", size=20), "code": fields.char("Code", size=10), "token_flag": fields.char(u"Token(令牌)", size=10), "appid": fields.char("AppID"), "appsecret": fields.char("AppSecret"), "token": fields.char("Token", readonly=True), "token_create": fields.datetime("TokenCreate", readonly=True), "expires_in": fields.integer("Expires_IN", readonly=True), "user_menu": fields.text("User Menu"), "ticket": fields.char("Ticket", readonly=True), "ticket_create": fields.datetime("TicketCreate", readonly=True), "ticket_expires": fields.integer("Ticket Expires", readonly=True), "welcome": fields.text("Welcome"), "users": fields.one2many("rhwl.weixin", "base_id", u"关注用户"), "menu": fields.one2many("rhwl.weixin.usermenu", "base_id", u"自定义菜单"), "is_valid": fields.boolean(u"已认证"), "service_type": fields.selection([("1", u"订阅号"), ("2", u"服务号"), ("3", u"企业号")], u"帐号类型") } def _get_memcache(self, key): return MEMCACHE.get(key, None) def _set_memcache(self, key, val): MEMCACHE[key] = val def _get_memcache_id(self, cr, original, AgentID): ids = self._get_memcache((original, AgentID)) if not ids: if (not AgentID) or AgentID == "0": ids = self.search(cr, SUPERUSER_ID, [("original_id", "=", original)]) else: ids = self.search(cr, SUPERUSER_ID, [("original_id", "=", original), ("appid", "=", AgentID)]) self._set_memcache((original, AgentID), ids) return ids #用户关注时,记录用户的OpenId信息,并返回设置的欢迎文字 def action_subscribe(self, cr, original, fromUser, AgentID="0"): origId = self._get_memcache_id(cr, original, AgentID) user = self.pool.get('rhwl.weixin') for o in origId: id = user.search(cr, SUPERUSER_ID, [("base_id", "=", o), ('openid', '=', fromUser), '|', ('active', '=', False), ("active", "=", True)]) if id: user.write(cr, SUPERUSER_ID, id, {"active": True}) else: user.create( cr, SUPERUSER_ID, { "base_id": o, 'openid': fromUser, 'active': True, 'state': 'draft' }) cr.commit() obj = self.browse(cr, SUPERUSER_ID, origId[0]) return obj.welcome def action_unsubscribe(self, cr, original, fromUser, AgentID="0"): origId = self._get_memcache_id(cr, original, AgentID) user = self.pool.get('rhwl.weixin') for o in origId: id = user.search(cr, SUPERUSER_ID, [("base_id", "=", o), ('openid', '=', fromUser)]) if id: user.write(cr, SUPERUSER_ID, id, {"active": False}) cr.commit() def action_event_clicked(self, cr, key, original, fromUser, appid=None): origId = self._get_memcache_id(cr, original, appid) obj = self.browse(cr, SUPERUSER_ID, origId) if obj.code == "rhwc" and key == "ONLINE_QUERY": return u"请您输入送检编号!" articles = self._get_htmlmsg(cr, origId[0], key) _logger.debug(articles) if articles[0]: userid = self._get_userid(cr, origId[0], fromUser) if not userid: articles = { "Title": "内部ERP帐号绑定", "Description": "您查阅的功能需要授权,请先进行内部ERP帐号绑定", "PicUrl": "/rhwl_weixin/static/img/logo1.png", "Url": "/rhwl_weixin/static/weixinbind.html" } return (obj.code.encode("utf-8"), [ articles, ]) if articles[1]: is_has_group = False uobj = self.pool.get("res.users") for i in articles[1].split(","): is_has_group = uobj.has_group(cr, userid, i) if is_has_group: break if not is_has_group: articles = { "Title": "访问权限不足", "Description": "您查阅的功能需要特别授权,请与管理员联系。", "PicUrl": "/rhwl_weixin/static/img/logo1.png", } return (obj.code.encode("utf-8"), [ articles, ]) _logger.debug(articles[2]) if articles[2]: return (obj.code.encode("utf-8"), articles[2]) else: return u"此功能在开发中,敬请稍候!" def action_text_input(self, cr, content, original, fromUser): origId = self._get_memcache_id(cr, original, None) obj = self.browse(cr, SUPERUSER_ID, origId) if obj.code == "rhwc": #人和无创公众号 sample = self.pool.get("sale.sampleone") user = self.pool.get('rhwl.weixin') if content.isalnum() and len(content) == 6: id = user.search(cr, SUPERUSER_ID, [("base_id", "=", origId[0]), ("active", '=', True), ("state", "=", "process"), ("checkNum", "=", content)]) if not id: return u"请先输入样品编码。" else: obj = user.browse(cr, SUPERUSER_ID, id) mindate = datetime.datetime.utcnow() - datetime.timedelta( minutes=5) if obj.checkDateTime < mindate.strftime( "%Y-%m-%d %H:%M:%S"): return u"验证码已过期,请重新输入样品编码查询。" else: id = sample.search(cr, SUPERUSER_ID, [("name", "=", obj.sampleno)]) sample_obj = sample.browse(cr, SUPERUSER_ID, id) user.write(cr, SUPERUSER_ID, obj.id, {"state": "pass"}) cr.commit() return u"您的样品编码" + obj.sampleno + u"目前进度为【" + rhwl_sale.rhwl_sale_state_select.get( sample_obj.check_state) + u"】,完成后详细的检测报告请与检测医院索取。" else: id = sample.search(cr, SUPERUSER_ID, [('name', '=', content)]) if id: openid = user.search(cr, SUPERUSER_ID, [('openid', '=', fromUser)]) obj = sample.browse(cr, SUPERUSER_ID, id) rand = random.randint(111111, 999999) checkDateTime = datetime.datetime.utcnow() user.write( cr, SUPERUSER_ID, openid, { "telno": obj.yftelno, "state": "process", "checkNum": rand, "checkDateTime": checkDateTime, "sampleno": content }) cr.commit() if obj.yftelno: self.pool.get("res.company").send_sms( cr, SUPERUSER_ID, obj.yftelno, u"您查询样品检测结果的验证码为%s,请在五分钟内输入,如果不是您本人操作,请不用处理。" % (rand, )) return u"验证码已经发送至检测知情同意书上登记的电话" + obj.yftelno[:3] + u"****" + obj.yftelno[ -4:] + u",请收到验证码后在五分钟内输入。" else: return u"您查询的样品编码在检测知情同意书上没有登记电话,不能发送验证码,请与送检医院查询结果。" else: #if re.search("[^0-9a-zA-Z]",content): # return self.customer_service(fromUser,toUser) #else: return u"您所查询的样品编码[%s]不存在,请重新输入,输入时注意区分大小写字母,并去掉多余的空格!" % ( content) else: return u"欢迎光临" def _get_htmlmsg(self, cr, orig_id, key): msg = self.pool.get("rhwl.weixin.usermenu2") id = msg.search(cr, SUPERUSER_ID, [("parent.base_id.id", "=", orig_id), ("key", "=", key)]) if not id: return (False, "", None) obj = msg.browse(cr, SUPERUSER_ID, id) if not obj.htmlmsg: return (obj.need_user, obj.groups, None) articles = [] for j in obj.htmlmsg: val = { "Title": j.title.encode("utf-8"), "Description": j.description.encode("utf-8"), "PicUrl": j.picurl.encode("utf-8"), } if j.url: val["Url"] = j.url and j.url.encode("utf-8") or "" articles.append(val) return (obj.need_user, obj.groups, articles) def _get_userid(self, cr, orig_id, openid): weixin = self.pool.get("rhwl.weixin") id = weixin.search(cr, SUPERUSER_ID, [("base_id", "=", orig_id), '|', ('openid', '=', openid), ("rhwlid", "=", openid)]) if id: obj = weixin.browse(cr, SUPERUSER_ID, id) return obj.user_id.id return None def _get_ticket(self, cr, uid, val, valType="code", context=None): arg = {"access_token": "", "type": "jsapi"} ids = self.search(cr, uid, [(valType, "=", val)], limit=1) obj = self.browse(cr, uid, ids, context=context) if not obj.ticket or ( datetime.datetime.now() - datetime.datetime.strptime( obj.ticket_create, tools.DEFAULT_SERVER_DATETIME_FORMAT) ).total_seconds() > (obj.ticket_expires - 30): arg['access_token'] = self._get_token(cr, uid, val, valType, obj, context=context) if obj.service_type == "3": s = requests.post( "https://qyapi.weixin.qq.com/cgi-bin/get_jsapi_ticket", params=arg) else: s = requests.post( "https://api.weixin.qq.com/cgi-bin/ticket/getticket", params=arg) ref = s.content s.close() res = eval(ref) if res.get("errcode") == 0: self.write( cr, uid, obj.id, { "ticket": res.get("ticket"), "ticket_create": fields.datetime.now(), "ticket_expires": res.get("expires_in") }) else: raise osv.except_osv("错误", res.get("errmsg")) return res.get("ticket") elif obj.token: return obj.ticket.encode('utf-8') def _get_token(self, cr, uid, val, valType="code", obj=None, context=None): arg = { "grant_type": "client_credential", "appid": "", "secret": "", } arg_qy = {"corpid": "", "corpsecret": ""} if not obj: ids = self.search(cr, uid, [(valType, "=", val)], limit=1) obj = self.browse(cr, uid, ids, context=context) if obj.service_type == "3": #企业号处理 if (not obj.token ) or (datetime.datetime.now() - datetime.datetime.strptime( obj.token_create, tools.DEFAULT_SERVER_DATETIME_FORMAT) ).total_seconds() > (obj.expires_in - 30): arg_qy["corpid"] = obj.original_id arg_qy["corpsecret"] = obj.appsecret s = requests.post( "https://qyapi.weixin.qq.com/cgi-bin/gettoken", params=arg_qy) ref = s.content s.close() res = eval(ref) if res.get("access_token"): self.write( cr, uid, obj.id, { "token": res.get("access_token"), "token_create": fields.datetime.now(), "expires_in": res.get("expires_in") }) else: raise osv.except_osv("错误", res.get("errmsg")) return res.get("access_token") else: return obj.token.encode('utf-8') else: if (not obj.token ) or (datetime.datetime.now() - datetime.datetime.strptime( obj.token_create, tools.DEFAULT_SERVER_DATETIME_FORMAT) ).total_seconds() > (obj.expires_in - 30): arg["appid"] = obj.appid arg["secret"] = obj.appsecret s = requests.post("https://api.weixin.qq.com/cgi-bin/token", params=arg) ref = s.content s.close() res = eval(ref) if res.get("access_token"): self.write( cr, uid, obj.id, { "token": res.get("access_token"), "token_create": fields.datetime.now(), "expires_in": res.get("expires_in") }) else: raise osv.except_osv("错误", res.get("errmsg")) _logger.info("Get New Token:" + res.get("access_token")) return res.get("access_token") elif obj.token: _logger.info("Get Old Token:" + obj.token.encode('utf-8')) return obj.token.encode('utf-8') def action_token(self, cr, uid, ids, context=None): for i in self.browse(cr, uid, ids, context=context): self._get_token(cr, uid, None, None, i, context) def _get_menu_detail_json(self, cr, uid, ids, context=None): d = { "sub_button": [], } obj = self.pool.get("rhwl.weixin.usermenu").browse(cr, uid, ids, context=context) if obj.details: d["name"] = obj.name.encode('utf-8') for i in obj.details: dic = { "type": i.type.encode('utf-8'), "name": i.name.encode('utf-8'), } if i.type == "view": dic["url"] = i.url.encode('utf-8') elif i.type == "click": dic["key"] = i.key.encode('utf-8') d['sub_button'].append(dic) return d else: d = {} d["type"] = obj.type.encode('utf-8') d["name"] = obj.name.encode('utf-8') if obj.type == "view": d["url"] = obj.url.encode('utf-8') if obj.type == "click": d["key"] = obj.key.encode('utf-8') return d def _get_menu_json(self, cr, uid, id, context=None): m = { "button": [], } ids = self.pool.get("rhwl.weixin.usermenu").search( cr, uid, [("base_id", "=", id)], context=context) if not ids: raise osv.except_osv(u"错误", u"您还没有配置用户自定义菜单内容。") if isinstance(ids, (long, int)): ids = [ ids, ] for i in ids: m['button'].append( self._get_menu_detail_json(cr, uid, i, context=context)) return m def action_usermenu(self, cr, uid, ids, context=None): args = {} for i in self.browse(cr, uid, ids, context=context): if i.service_type == "3": create_url = "https://qyapi.weixin.qq.com/cgi-bin/menu/create" args["access_token"] = self._get_token(cr, uid, None, None, i, context) args["agentid"] = i.appid else: create_url = "https://api.weixin.qq.com/cgi-bin/menu/create" args["access_token"] = self._get_token(cr, uid, None, None, i, context) i.user_menu = str( self._get_menu_json(cr, uid, i.id, context=context)) s = requests.post( create_url, params=args, data=json.dumps(eval(i.user_menu), ensure_ascii=False), headers={'content-type': 'application/json; encoding=utf-8'}, allow_redirects=False) ref = s.content s.close() res = eval(ref) if res.get("errcode") != 0: raise osv.except_osv("错误" + str(res.get("errcode")), res.get("errmsg")) def send_template1(self, cr, uid, to_user, json_dict, context=None): id = self.pool.get("rhwl.weixin").search( cr, SUPERUSER_ID, [("base_id.code", "=", "rhwc"), ("user_id", "=", to_user)]) if not id: return id = id[0] obj = self.pool.get("rhwl.weixin").browse(cr, SUPERUSER_ID, id) json_dict["touser"] = obj.openid.encode('utf-8') if json_dict["url"]: json_dict["url"] += "?openid=" + obj.openid.encode('utf-8') token = self._get_token(cr, SUPERUSER_ID, "rhwc", context=context) s = requests.post( "https://api.weixin.qq.com/cgi-bin/message/template/send", params={"access_token": token}, data=json.dumps(json_dict, ensure_ascii=False), headers={'content-type': 'application/json; encoding=utf-8'}, allow_redirects=False) ref = s.content s.close() def send_template2(self, cr, uid, json_dict, col, context=None): template = { "touser": "******", "template_id": "D2fDRIhwFe9jpHgLtTjkRy5jOz_AqQnvuGzpYQFkgRs", "url": "", "topcolor": "#FF0000", "data": { "first": { "value": json_dict["first"], "color": "#173177" }, "keyword1": { "value": json_dict["keyword1"], "color": "#173177" }, "keyword2": { "value": json_dict["keyword2"], "color": "#173177" }, "keyword3": { "value": json_dict["keyword3"], "color": "#173177" }, "remark": { "value": json_dict["remark"], "color": "#173177" } } } id = self.pool.get("rhwl.weixin").search(cr, SUPERUSER_ID, [(col, "=", True)]) for i in id: obj = self.pool.get("rhwl.weixin").browse(cr, SUPERUSER_ID, i, context=context) token = self._get_token(cr, SUPERUSER_ID, "rhwc", context=context) template["touser"] = obj.openid.encode('utf-8') s = requests.post( "https://api.weixin.qq.com/cgi-bin/message/template/send", params={"access_token": token}, data=json.dumps(template, ensure_ascii=False), headers={'content-type': 'application/json; encoding=utf-8'}, allow_redirects=False) ref = s.content s.close() def send_qy_text_ids(self, cr, uid, ids, content, context=None): vals = { "touser": "", "toparty": "", "totag": "", "msgtype": "text", "agentid": None, "text": { "content": "" }, "safe": "0" } touser = [] if ids: for i in self.pool.get("rhwl.weixin").browse(cr, uid, ids, context=context): touser.append(i.openid.encode('utf-8')) if not vals["agentid"]: vals["agentid"] = i.base_id.appid.encode('utf-8') token = self._get_token(cr, SUPERUSER_ID, i.base_id.code.encode('utf-8'), context=context) vals["touser"] = '******'.join(touser) vals["text"]["content"] = content.encode('utf-8') #_logger.error(vals) s = requests.post( "https://qyapi.weixin.qq.com/cgi-bin/message/send", params={"access_token": token}, data=json.dumps(vals, ensure_ascii=False), headers={'content-type': 'application/json; encoding=utf-8'}, allow_redirects=False) ref = s.content s.close() def send_qy_text_openid(self, cr, uid, code, openid, content, context=None): ids = self.pool.get("rhwl.weixin").search(cr, uid, [("base_id.code", "=", code), ("openid", "=", openid)], context=context) self.send_qy_text_ids(cr, uid, ids, content, context=context) def send_qy_text(self, cr, uid, code, field_name, content, context=None): ids = self.pool.get("rhwl.weixin").search(cr, uid, [("base_id.code", "=", code), (field_name, "=", True)], context=context) self.send_qy_text_ids(cr, uid, ids, content, context=context) def get_dept_user(self, cr, uid, id, context=None): obj = self.browse(cr, uid, id, context=context) token = self._get_token(cr, SUPERUSER_ID, obj.code.encode("utf-8"), context=context) vals = { "access_token": token, "department_id": 1, "fetch_child": 1, "status": 0 } s = requests.post( "https://qyapi.weixin.qq.com/cgi-bin/user/simplelist", params=vals, headers={'content-type': 'application/json; encoding=utf-8'}, allow_redirects=False) ref = eval(s.content) s.close() if ref["errcode"] == 0: for i in ref["userlist"]: u_id = self.pool.get("rhwl.weixin").search( cr, SUPERUSER_ID, [("base_id", "=", obj.id), ("openid", "=", i["userid"])]) if not u_id: self.pool.get("rhwl.weixin").create( cr, SUPERUSER_ID, { "base_id": obj.id, "openid": i["userid"], "active": True, "state": "draft" })
try: file_data = image_file.read() self._logo_image = base64.encodestring(file_data) return self._logo_image finally: image_file.close() else: self._logo_image = base64.encodestring(im.read()) return self._logo_image def _get_image_fn(self, cr, uid, ids, name, args, context=None): image = self._get_image(cr, uid, context) return dict.fromkeys(ids, image) # ok to use .fromkeys() as the image is same for all _columns = { 'printer_ids':fields.one2many('aeroo.printers.temp', 'install_id', 'Printers'), 'config_logo': fields.function(_get_image_fn, string='Image', type='binary', method=True), 'state':fields.selection([ ('init','Init'), ('done','Done'), ],'State', select=True, readonly=True), } def default_get(self, cr, uid, fields, context=None): printers_obj = self.pool.get('aeroo.printers') data = super(aeroo_printer_installer, self).default_get(cr, uid, fields, context=context) conn = cups.Connection() printers = conn.getPrinters() installed_ids = printers_obj.search(cr, 1, ['|',('active','=',False),('active','=',True)], context=context) printers_installed = printers_obj.read(cr, uid, installed_ids, context=context)
class sale_order(osv.osv): _inherit = 'sale.order' def _get_total(self, cr, uid, ids, name, arg, context=None): res = {} for order in self.browse(cr, uid, ids, context=context): total = 0.0 for line in order.order_line: total += line.price_subtotal + line.price_unit * ((line.discount or 0.0) / 100.0) * line.product_uom_qty res[order.id] = total return res _columns = { 'access_token': fields.char('Security Token', required=True, copy=False), 'template_id': fields.many2one('sale.quote.template', 'Quotation Template', readonly=True, states={'draft': [('readonly', False)], 'sent': [('readonly', False)]}), 'website_description': fields.html('Description'), 'options' : fields.one2many('sale.order.option', 'order_id', 'Optional Products Lines', readonly=True, states={'draft': [('readonly', False)], 'sent': [('readonly', False)]}, copy=True), 'amount_undiscounted': fields.function(_get_total, string='Amount Before Discount', type="float", digits=0), 'quote_viewed': fields.boolean('Quotation Viewed'), 'require_payment': fields.selection([ (0, 'Not mandatory on website quote validation'), (1, 'Immediate after website order validation') ], 'Payment', help="Require immediate payment by the customer when validating the order from the website quote"), } def _get_template_id(self, cr, uid, context=None): try: template_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'website_quote', 'website_quote_template_default')[1] except ValueError: template_id = False return template_id _defaults = { 'access_token': lambda self, cr, uid, ctx={}: str(uuid.uuid4()), 'template_id' : _get_template_id, } def open_quotation(self, cr, uid, quote_id, context=None): quote = self.browse(cr, uid, quote_id[0], context=context) self.write(cr, uid, quote_id[0], {'quote_viewed': True}, context=context) return { 'type': 'ir.actions.act_url', 'target': 'self', 'url': '/quote/%s/%s' % (quote.id, quote.access_token) } def onchange_template_id(self, cr, uid, ids, template_id, partner=False, fiscal_position_id=False, pricelist_id=False, context=None): if not template_id: return {} if partner: context = dict(context or {}) context['lang'] = self.pool['res.partner'].browse(cr, uid, partner, context).lang pricelist_obj = self.pool['product.pricelist'] lines = [(5,)] quote_template = self.pool.get('sale.quote.template').browse(cr, uid, template_id, context=context) for line in quote_template.quote_line: res = self.pool.get('sale.order.line').product_id_change(cr, uid, False, False, line.product_id.id, line.product_uom_qty, line.product_uom_id.id, line.product_uom_qty, line.product_uom_id.id, line.name, partner, False, True, time.strftime('%Y-%m-%d'), False, fiscal_position_id, True, context) data = res.get('value', {}) if pricelist_id: uom_context = context.copy() uom_context['uom'] = line.product_uom_id.id price = pricelist_obj.price_get(cr, uid, [pricelist_id], line.product_id.id, 1, context=uom_context)[pricelist_id] else: price = line.price_unit if 'tax_id' in data: data['tax_id'] = [(6, 0, data['tax_id'])] data.update({ 'name': line.name, 'price_unit': price, 'discount': line.discount, 'product_uom_qty': line.product_uom_qty, 'product_id': line.product_id.id, 'product_uom': line.product_uom_id.id, 'website_description': line.website_description, 'state': 'draft', }) lines.append((0, 0, data)) options = [] for option in quote_template.options: if pricelist_id: uom_context = context.copy() uom_context['uom'] = option.uom_id.id price = pricelist_obj.price_get(cr, uid, [pricelist_id], option.product_id.id, 1, context=uom_context)[pricelist_id] else: price = option.price_unit options.append((0, 0, { 'product_id': option.product_id.id, 'name': option.name, 'quantity': option.quantity, 'uom_id': option.uom_id.id, 'price_unit': price, 'discount': option.discount, 'website_description': option.website_description, })) date = False if quote_template.number_of_days > 0: date = (datetime.datetime.now() + datetime.timedelta(quote_template.number_of_days)).strftime("%Y-%m-%d") data = { 'order_line': lines, 'website_description': quote_template.website_description, 'options': options, 'validity_date': date, 'require_payment': quote_template.require_payment } if quote_template.note: data['note'] = quote_template.note return {'value': data} def recommended_products(self, cr, uid, ids, context=None): order_line = self.browse(cr, uid, ids[0], context=context).order_line product_pool = self.pool.get('product.product') products = [] for line in order_line: products += line.product_id.product_tmpl_id.recommended_products(context=context) return products def get_access_action(self, cr, uid, ids, context=None): """ Override method that generated the link to access the document. Instead of the classic form view, redirect to the online quote if exists. """ quote = self.browse(cr, uid, ids[0], context=context) if not quote.template_id: return super(sale_order, self).get_access_action(cr, uid, ids, context=context) return { 'type': 'ir.actions.act_url', 'url': '/quote/%s' % quote.id, 'target': 'self', 'res_id': quote.id, } def action_quotation_send(self, cr, uid, ids, context=None): action = super(sale_order, self).action_quotation_send(cr, uid, ids, context=context) ir_model_data = self.pool.get('ir.model.data') quote_template_id = self.read(cr, uid, ids, ['template_id'], context=context)[0]['template_id'] if quote_template_id: try: template_id = ir_model_data.get_object_reference(cr, uid, 'website_quote', 'email_template_edi_sale')[1] except ValueError: pass else: action['context'].update({ 'default_template_id': template_id, 'default_use_template': True }) return action def _confirm_online_quote(self, cr, uid, order_id, tx, context=None): """ Payment callback: validate the order and write tx details in chatter """ order = self.browse(cr, uid, order_id, context=context) # create draft invoice if transaction is ok if tx and tx.state == 'done': if order.state in ['draft', 'sent']: self.signal_workflow(cr, SUPERUSER_ID, [order.id], 'manual_invoice', context=context) message = _('Order payed by %s. Transaction: %s. Amount: %s.') % (tx.partner_id.name, tx.acquirer_reference, tx.amount) self.message_post(cr, uid, order_id, body=message, type='comment', subtype='mt_comment', context=context) return True return False def create(self, cr, uid, values, context=None): if not values.get('template_id'): defaults = self.default_get(cr, uid, ['template_id'], context=context) template_values = self.onchange_template_id(cr, uid, [], defaults.get('template_id'), partner=values.get('partner_id'), fiscal_position_id=values.get('fiscal_position'), context=context).get('value', {}) values = dict(template_values, **values) return super(sale_order, self).create(cr, uid, values, context=context)
class prestashop_backend(orm.Model): _name = 'prestashop.backend' _doc = 'Prestashop Backend' _inherit = 'connector.backend' _backend_type = 'prestashop' def _select_versions(self, cr, uid, context=None): """ Available versions Can be inherited to add custom versions. """ return [('1.5', '1.5')] _columns = { 'version': fields.selection(_select_versions, string='Version', required=True), 'location': fields.char('Location'), 'webservice_key': fields.char('Webservice key', help="You have to put it in 'username' of the PrestaShop " "Webservice api path invite"), 'warehouse_id': fields.many2one( 'stock.warehouse', 'Warehouse', required=True, help='Warehouse used to compute the stock quantities.'), 'taxes_included': fields.boolean("Use tax included prices"), 'import_partners_since': fields.datetime('Import partners since'), 'import_orders_since': fields.datetime('Import Orders since'), 'import_products_since': fields.datetime('Import Products since'), 'import_refunds_since': fields.datetime('Import Refunds since'), 'import_suppliers_since': fields.datetime('Import Suppliers since'), 'language_ids': fields.one2many('prestashop.res.lang', 'backend_id', 'Languages'), 'company_id': fields.many2one('res.company', 'Company', select=1, required=True), 'discount_product_id': fields.many2one('product.product', 'Dicount Product', select=1, required=False), 'shipping_product_id': fields.many2one('product.product', 'Shipping Product', select=1, required=False), } _defaults = { 'company_id': lambda s, cr, uid, c: s.pool.get('res.company')._company_default_get( cr, uid, 'prestashop.backend', context=c), } 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 ('prestashop.shop.group', 'prestashop.shop'): # 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 synchronize_basedata(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_name in [ 'prestashop.res.lang', 'prestashop.res.country', 'prestashop.res.currency', 'prestashop.account.tax', ]: env = get_environment(session, model_name, backend_id) directBinder = env.get_connector_unit(DirectBinder) directBinder.run() import_batch(session, 'prestashop.account.tax.group', backend_id) import_batch(session, 'prestashop.sale.order.state', backend_id) return True def _date_as_user_tz(self, cr, uid, dtstr): if not dtstr: return None users_obj = self.pool.get('res.users') user = users_obj.browse(cr, uid, uid) timezone = pytz.timezone(user.partner_id.tz or 'utc') dt = datetime.strptime(dtstr, DEFAULT_SERVER_DATETIME_FORMAT) dt = pytz.utc.localize(dt) dt = dt.astimezone(timezone) return dt def import_customers_since(self, cr, uid, ids, context=None): if not hasattr(ids, '__iter__'): ids = [ids] session = ConnectorSession(cr, uid, context=context) for backend_record in self.browse(cr, uid, ids, context=context): since_date = self._date_as_user_tz( cr, uid, backend_record.import_partners_since) import_customers_since.delay( session, backend_record.id, since_date, priority=10, ) return True def import_products(self, cr, uid, ids, context=None): if not hasattr(ids, '__iter__'): ids = [ids] session = ConnectorSession(cr, uid, context=context) for backend_record in self.browse(cr, uid, ids, context=context): since_date = self._date_as_user_tz( cr, uid, backend_record.import_products_since) import_products.delay(session, backend_record.id, since_date, priority=10) return True def import_carriers(self, cr, uid, ids, context=None): if not hasattr(ids, '__iter__'): ids = [ids] session = ConnectorSession(cr, uid, context=context) for backend_id in ids: import_carriers.delay(session, backend_id, priority=10) return True def update_product_stock_qty(self, cr, uid, ids, context=None): if not hasattr(ids, '__iter__'): ids = [ids] session = ConnectorSession(cr, uid, context=context) export_product_quantities.delay(session, ids) return True def import_stock_qty(self, cr, uid, ids, context=None): if not hasattr(ids, '__iter__'): ids = [ids] session = ConnectorSession(cr, uid, context=context) for backend_id in ids: import_inventory.delay(session, backend_id) def import_sale_orders(self, cr, uid, ids, context=None): if not hasattr(ids, '__iter__'): ids = [ids] session = ConnectorSession(cr, uid, context=context) for backend_record in self.browse(cr, uid, ids, context=context): since_date = self._date_as_user_tz( cr, uid, backend_record.import_orders_since) import_orders_since.delay( session, backend_record.id, since_date, priority=5, ) return True def import_payment_methods(self, cr, uid, ids, context=None): if not hasattr(ids, '__iter__'): ids = [ids] session = ConnectorSession(cr, uid, context=context) for backend_record in self.browse(cr, uid, ids, context=context): import_batch.delay(session, 'payment.method', backend_record.id) return True def import_refunds(self, cr, uid, ids, context=None): if not hasattr(ids, '__iter__'): ids = [ids] session = ConnectorSession(cr, uid, context=context) for backend_record in self.browse(cr, uid, ids, context=context): since_date = self._date_as_user_tz( cr, uid, backend_record.import_refunds_since) import_refunds.delay(session, backend_record.id, since_date) return True def import_suppliers(self, cr, uid, ids, context=None): if not hasattr(ids, '__iter__'): ids = [ids] session = ConnectorSession(cr, uid, context=context) for backend_record in self.browse(cr, uid, ids, context=context): since_date = self._date_as_user_tz( cr, uid, backend_record.import_suppliers_since) import_suppliers.delay(session, backend_record.id, since_date) return True def _scheduler_launch(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_update_product_stock_qty(self, cr, uid, domain=None, context=None): self._scheduler_launch(cr, uid, self.update_product_stock_qty, domain=domain, context=context) def _scheduler_import_sale_orders(self, cr, uid, domain=None, context=None): self._scheduler_launch(cr, uid, self.import_sale_orders, domain=domain, context=context) def _scheduler_import_customers(self, cr, uid, domain=None, context=None): self._scheduler_launch(cr, uid, self.import_customers_since, domain=domain, context=context) def _scheduler_import_products(self, cr, uid, domain=None, context=None): self._scheduler_launch(cr, uid, self.import_products, domain=domain, context=context) def _scheduler_import_carriers(self, cr, uid, domain=None, context=None): self._scheduler_launch(cr, uid, self.import_carriers, domain=domain, context=context) def _scheduler_import_payment_methods(self, cr, uid, domain=None, context=None): self._scheduler_launch(cr, uid, self.import_payment_methods, domain=domain, context=context) def _scheduler_import_refunds(self, cr, uid, domain=None, context=None): self._scheduler_launch(cr, uid, self.import_refunds, domain=domain, context=context) def _scheduler_import_suppliers(self, cr, uid, domain=None, context=None): self._scheduler_launch(cr, uid, self.import_suppliers, domain=domain, context=context) def import_record(self, cr, uid, backend_id, model_name, ext_id, context=None): session = ConnectorSession(cr, uid, context=context) import_record(session, model_name, backend_id, ext_id) return True
class sale_devis(osv.osv): _name = "sale.devis" _description = "Sales Devis" _rec_name = 'reference' _order = "reference desc, id desc" def draft(self, cr, uid, ids): self.write(cr, uid, ids, {'state': 'draft'}) return True def envoyer(self, cr, uid, ids, context): ''' Methode du workflow: changer l'état du devis à l'état envoyé ''' self.reset_taxes(cr, uid, ids, context) self.write(cr, uid, ids, {'state': 'sent'}) return True def confirmer(self, cr, uid, ids, context): ''' Methode du workflow: permet la confirmation du devis et la création du Bon de commande ''' self.reset_taxes(cr, uid, ids, context) self.write(cr, uid, ids, {'state': 'confirmed'}) return True def create(self, cr, uid, vals, context=None): vals['reference'] = self.pool.get('ir.sequence').get( cr, uid, 'sale.devis') new_id = super(sale_devis, self).create(cr, uid, vals, context=context) self.reset_taxes(cr, uid, [new_id], context) return new_id def action_view_order(self, cr, uid, ids, context=None): for devis in self.browse(cr, uid, ids): mod_obj = self.pool.get('ir.model.data') act_obj = self.pool.get('ir.actions.act_window') result = mod_obj.get_object_reference(cr, uid, 'sale', 'action_order_tree') id = result and result[1] or False result = act_obj.read(cr, uid, [id], context=context)[0] res = mod_obj.get_object_reference(cr, uid, 'sale', 'view_order_form') result['views'] = [(res and res[1] or False, 'form')] cr.execute("select id from sale_order where devis_id = %s", (devis.id, )) res = cr.dictfetchone() result['res_id'] = res['id'] return result def _currency_get(self, cr, uid, context=None): ids = self.pool.get('res.currency').search(cr, uid, [('name', '=', 'TND')], context=context) return ids[0] @api.one @api.depends('devis_lines.price_subtotal', 'tax_lines.amount') def _amount_all(self): ''' Methode qui calcule les montants suivants amount_untaxed amount_tax amount_total undiscount_total discount_total ''' print "partner_id.exone===", self.partner_id.exoner if self.partner_id.exoner: self.amount_tax = 0 else: self.amount_tax = sum(line.amount for line in self.tax_lines) self.amount_untaxed = sum(line.price_subtotal for line in self.devis_lines) self.discount_total = sum((line.product_qty * line.price_unit * ((line.discount or 0.0) / 100.0)) for line in self.devis_lines) self.undiscount_total = sum(line.product_qty * line.price_unit for line in self.devis_lines) self.amount_total = self.amount_untaxed + self.amount_tax _columns = { 'reference': fields.char('Référence', size=64, readonly=True), 'date': fields.datetime('Date', required=True), 'partner_id': fields.many2one('res.partner', 'Client', required=True, domain="[('customer','=',True)]"), 'company_id': fields.many2one('res.company', 'Company'), 'currency_id': fields.many2one('res.currency', 'Devise', required=True), 'devis_lines': fields.one2many('sale.devis.line', 'devis_id', 'Ligne de devis'), 'tax_lines': fields.one2many( 'sale.devis.taxe', 'devis_id', 'Lignes Tax', ), 'discount_total': fields.float(string='Total Remise', digits_compute=dp.get_precision('Account'), store=True, readonly=True, compute='_amount_all', track_visibility='always'), 'undiscount_total': fields.float(string='Total HT sans remise', digits_compute=dp.get_precision('Account'), store=True, readonly=True, compute='_amount_all', track_visibility='always'), 'amount_untaxed': fields.float(string='Total HT', digits_compute=dp.get_precision('Account'), store=True, readonly=True, compute='_amount_all', track_visibility='always'), 'amount_tax': fields.float(string='Total Taxe', digits_compute=dp.get_precision('Account'), store=True, readonly=True, compute='_amount_all', track_visibility='always'), 'amount_total': fields.float(string='Total', digits_compute=dp.get_precision('Account'), store=True, readonly=True, compute='_amount_all', track_visibility='always'), 'state': fields.selection([('draft', 'Brouillon'), ('sent', 'Envoyé'), ('confirmed', 'Confirmé')]), #'comment' : fields.char('comment', size=64), 'note': fields.text(), } _defaults = { 'state': 'draft', 'company_id': lambda self, cr, uid, c: self.pool.get('res.company'). _company_default_get(cr, uid, 'procurement.order', context=c), 'currency_id': _currency_get, } def button_reset_taxes(self, cr, uid, ids, context=None): ''' Action du bouton reset Taxes ''' self.reset_taxes(cr, uid, ids, context) return True def reset_taxes(self, cr, uid, ids, context=None): ''' Methode qui permet de calculer et mettre à jour les lignes de taxes ''' if context is None: context = {} ctx = context.copy() ait_obj = self.pool.get('sale.devis.taxe') for id in ids: partner = self.browse(cr, uid, id, context=ctx).partner_id if partner.lang: cr.execute("DELETE FROM sale_devis_taxe WHERE devis_id=%s", (id, )) ctx.update({'lang': partner.lang}) for taxe in ait_obj.compute(cr, uid, id, context=ctx).values(): ait_obj.create(cr, uid, taxe) return True
def _default_location(self, cr, uid, ids, context=None): try: loc_model, location_id = self.pool.get("ir.model.data").get_object_reference( cr, uid, "stock", "stock_location_stock" ) except ValueError, e: return False return location_id or False _columns = { "location_id": fields.many2one("stock.location", "Location", required=True), "import_file": fields.binary("File", filters="*.xls"), # to consider the product current inventory or not, if yes then add the current inventory to the upload excel quantity as the quantity to do physical inventory "consider_inventory": fields.boolean("Consider Current Inventory", select=True), "all_done": fields.boolean("All Data Imported", readonly=True, select=True), "result_line": fields.one2many("stock.import.inventory.result", "import_id", "Importing Result", readonly=True), } _defaults = {"location_id": _default_location} def view_init(self, cr, uid, fields_list, context=None): """ Creates view dynamically and adding fields at runtime. @param self: The object pointer. @param cr: A database cursor @param uid: ID of the user currently logged in @param context: A standard dictionary @return: New arch of view with new columns. """ if context is None: context = {} super(stock_import_inventory, self).view_init(cr, uid, fields_list, context=context)
class product_ebay(osv.osv): _inherit = "product.template" _columns = { 'copies': fields.char(string="NoOfCopies"), 'ebay_oem_code': fields.char(string="EbayOEM-obsolete"), 'with_chip': fields.boolean(string="With chip"), 'ebay_sync': fields.boolean(string="Sync with ebay"), 'ebay_id': fields.one2many('ebay.ids', 'product_id', string="Ebay_ids"), 'ebay_date_added': fields.datetime(string="Added to Ebay"), 'ebay_price': fields.float(string="Ebay price"), 'ebay_template_id': fields.many2one('ebay.template'), 'ebay_item_location': fields.char(string="Ebay postal"), 'ebay_payment_instruction': fields.text(string="Ebay payment instructions"), 'ebay_shipping_cost': fields.float(string="Ebay shipping cost"), 'ebay_additional_item_cost': fields.float(string="Ebay add. shipping cost"), 'ebay_free_shipping': fields.boolean(string="Ebay free shipping"), 'ebay_extra_name': fields.char(string="Ebay extra att name"), 'ebay_extra_value': fields.char(string="Ebay extra att value"), 'main_name_part': fields.char(string="Ebay main name part"), 'name_parts': fields.one2many('ebay.name.parts', 'np_id'), 'stock_limit': fields.integer(default=5, string="Ebay stock limit"), 'ebay_listing_duration': fields.selection((('Days_7', '7 days'), ('Days_30', '30 days'), ('GTC', 'Good `Till Canceled')), string="Ebay listing duration"), 'ebay_custom_desc': fields.text(string="Custom description"), 'ebay_force_shipping_cost': fields.boolean(string="Use this shipping cost") } def export_now(self, cr, uid, ids, context=None): self.pool.get('ebay').export_products(cr, uid, ids, product_id=ids, context=None) def remove_product(self, cr, uid, ids, context=None): self.pool.get('ebay').remove_product(cr, uid, ids, context=None) def open_on_ebay(self, cr, uid, ids, context=None): #This opens link for product on ebay product = self.browse(cr, uid, ids, context=context) product = product[0] ebay_ids = [x.ebay_id for x in product.ebay_ids] if ebay_ids: for e in ebay_ids: url = 'http://cgi.ebay.it/ws/eBayISAPI.dll?ViewItem&item=%s' % str( e) webbrowser.open(url, new=2, autoraise=True) def set_price(self, cr, uid, ids, context=None): for record in self.browse(cr, uid, ids, context=context): ebay_price = record.list_price - 0.1 record.ebay_price = ebay_price return True def divide_name(self, cr, uid, ids, context=None): current_record = None for record in self.browse(cr, uid, ids, context=context): current_record = record desc = current_record.description if len(desc) <= 80: return True split = desc.split('FOR ') main = split[0] + 'FOR ' rest = '' for x in range(1, len(split)): rest += split[x] others = rest.split(',') parts = [] line = '' current_record.main_name_part = main for y in range(0, len(others)): if (len(line) + len(others[y])) < (80 - len(main)): if (len(line) > 0): line += ", " line += others[y] if y == len(others) - 1: parts.append(line) else: parts.append(line) line = '' for p in parts: if (p[0] == ' '): p = p.replace(p[0], '') pro_id = current_record.id self.pool.get('ebay.name.parts').create(cr, uid, { 'np_id': pro_id, 'name': p }) return True
return val STATE_SELECTION = [ ('draft', 'New'), ('open', 'Accepted'), ('cancel', 'Refused'), ('close', 'Done') ] _name='devil.formulas' _description='Formula Calculation' _columns={ 'name': fields.char('Transaction Code',size=124), 'date': fields.date('Transaction Date'), 'cust_id': fields.many2one('devil.customer','Customer'), 'formula_line': fields.one2many('devil.items.lines','formula_id','FormulaLines'), <<<<<<< HEAD 'total_amt_disc': fields.float('Amount Discount', required=True, ), ======= >>>>>>> 08375b10183304dea2ebfe2187b2858b17177cbb 'total_amount': fields.function(_amount_all, string='TotalAmount'), 'state': fields.selection(STATE_SELECTION, 'Status', readonly=True, select=True), } _defaults = { 'state': lambda *a: 'draft', } def button_dummy(self, cr, uid, ids, context=None): return True
class change_account_move_line_wizard(TransientModel): _name = 'change.account.move.line.wizard' _description = 'Wizard to manage move of move lines' def default_get(self, cr, uid, fields, context): res = super(change_account_move_line_wizard, self).default_get(cr, uid, fields, context=context) account = self.pool.get('account.account').browse(cr, uid, context['active_id'], context=context) # Get move line without partners per company partners = [] sql_req = """ SELECT company_id, count(*) as quantity FROM account_move_line WHERE partner_id is NULL AND account_id = %s group by company_id """ % (account.id) cr.execute(sql_req) for item in cr.fetchall(): partners.append((0, 0, { 'company_id': item[0], 'move_number': item[1], 'partner_id': False, })) res.update({ 'source_account_id': account.id, 'source_company_id': account.company_id.id, 'source_type': account.type, 'source_move_number': account.move_number, 'source_reconciled_move_number': account.reconciled_move_number, 'source_closed_period_move_number': account.closed_period_move_number, 'source_invoice_number': account.invoice_number, 'source_voucher_line_number': account.voucher_line_number, 'line_ids': partners, }) return res # --- Columns _columns = { 'source_account_id': fields.many2one('account.account', 'Source account', domain=[('type', '=', 'view')], readonly=True), 'source_company_id': fields.many2one('res.company', 'Company of the source account', readonly=True), 'source_type': fields.char('Type of the source account', readonly=True), 'source_move_number': fields.integer('Number of moves in the source account', readonly=True), 'source_invoice_number': fields.integer('Number of invoices in the source account', readonly=True), 'source_voucher_line_number': fields.integer('Number of voucher line in the source account', readonly=True), 'source_reconciled_move_number': fields.integer('Number of reconciled moves in the source account', readonly=True), 'source_closed_period_move_number': fields.integer('Number of moves in closed periods', readonly=True), 'destination_account_id': fields.many2one('account.account', 'Destination account', required=True, domain=[('type', '!=', 'view')]), 'destination_company_id': fields.many2one('res.company', 'Company of the destination account', readonly=True), 'destination_type': fields.char('Type of the destination account', readonly=True), 'destination_move_number': fields.integer('Number of moves in the destination account', readonly=True), 'change_view_type': fields.boolean('Change source account in view type'), 'line_ids': fields.one2many('change.account.move.line.wizard.line', 'wizard_id', 'Partners list'), } def onchange_destination_account_id(self, cr, uid, ids, destination_account_id, destination_company_id, destination_type, destination_move_number, context): if destination_account_id: account = self.pool.get('account.account').browse( cr, uid, destination_account_id, context=context) return { 'value': { 'destination_company_id': account.company_id.id, 'destination_type': account.type, 'destination_move_number': account.move_number, } } else: return { 'value': { 'destination_company_id': None, 'destination_type': None, 'destination_move_number': None, } } return {} def button_change_move_line(self, cr, uid, ids, context=None): aa_obj = self.pool.get('account.account') ai_obj = self.pool.get('account.invoice') am_obj = self.pool.get('account.move') aml_obj = self.pool.get('account.move.line') ap_obj = self.pool.get('account.period') avl_obj = self.pool.get('account.voucher.line') reconcile_infos = {} close_period_infos = [] for data in self.browse(cr, uid, ids, context=context): # check constraint if not (data.source_account_id.company_id.id != data.destination_account_id.company_id.id): assert 'Incorrect request', _( 'Source and destination account must be belong to the same company.' ) # Select all account_move_line to change aml_ids = aml_obj.search( cr, uid, [ ('account_id', '=', data.source_account_id.id), ], context=context) # Select all account_invoice to change ai_ids = ai_obj.search( cr, uid, [ ('account_id', '=', data.source_account_id.id), ], context=context) # Select all account_invoice to change avl_ids = avl_obj.search( cr, uid, [ ('account_id', '=', data.source_account_id.id), ], context=context) print avl_ids if aml_ids: # Search reconciled move lines aml_reconcile_ids = aml_obj.search( cr, uid, [ ('account_id', '=', data.source_account_id.id), ('reconcile_id', '!=', False), ], context=context) # Select all account_move associated to set them in draft state cr.execute( "SELECT distinct(move_id) FROM account_move_line WHERE id in (%s)" % (str(aml_ids).strip('[]'), )) move_ids = [r[0] for r in cr.fetchall()] # backup reconcile information for aml in aml_obj.browse(cr, uid, aml_reconcile_ids, context=context): reconcile_infos[aml.id] = aml.reconcile_id.id # Redo reconcile aml_obj.write(cr, uid, aml_reconcile_ids, { 'reconcile_id': False, }, context=context) # Backup periods cr.execute(""" SELECT distinct(period_id) FROM account_move_line aml INNER JOIN account_period ap ON aml.period_id =ap.id WHERE aml.id in (%s) AND ap.state in ('done') """ % (str(aml_ids).strip('[]'), )) close_period_infos = [r[0] for r in cr.fetchall()] # Open Closed periods if close_period_infos: ap_obj.action_draft(cr, uid, close_period_infos) # Cancel all account_move associated am_obj.button_cancel(cr, uid, move_ids, context=context) # Change account_move_line account aml_obj.write(cr, uid, aml_ids, { 'account_id': data.destination_account_id.id, }, context=context) # Change account_move_line partner, if it not set for line_id in data.line_ids: aml_partner_ids = aml_obj.search( cr, uid, [ ('id', 'in', aml_ids), ('partner_id', '=', False), ('company_id', '=', line_id.company_id.id), ], context=context) aml_obj.write(cr, uid, aml_partner_ids, { 'partner_id': line_id.partner_id.id, }, context=context) # Validate again all account_move associated am_obj.button_validate(cr, uid, move_ids, context=context) # Redo reconcile for aml_reconcile_id in aml_reconcile_ids: aml_obj.write( cr, uid, aml_reconcile_id, { 'reconcile_id': reconcile_infos[aml_reconcile_id], }, context=context) # Close periods # NOTA : A function doesn't exist to do that. (except in a transient model) if close_period_infos: mode = 'done' cr.execute( 'update account_journal_period set state=%s where period_id in %s', ( mode, tuple(close_period_infos), )) cr.execute( 'update account_period set state=%s where id in %s', ( mode, tuple(close_period_infos), )) if ai_ids: # change account_invoice account ai_obj.write(cr, uid, ai_ids, { 'account_id': data.destination_account_id.id, }, context=context) if avl_ids: print avl_ids # change account_voucher_line account avl_obj.write(cr, uid, avl_ids, { 'account_id': data.destination_account_id.id, }, context=context) # (Optional) change type of the source account if data.change_view_type: aa_obj.write(cr, uid, [data.source_account_id.id], { 'type': 'view', }, context=context) return {}
_columns = { 'name': fields.text('Description', required=True, readonly=True, states={'draft': [('readonly', False)]}), 'order_id': fields.many2one('rent.order', 'Rent Reference', required=True, ondelete='cascade', select=True, readonly=True, states={'draft':[('readonly',False)]}), 'sequence': fields.integer('Sequence'), 'product_id': fields.many2one('product.product', 'Product', domain=[('is_rent', '=', True)], change_default=True), 'invoice_lines': fields.many2many('account.invoice.line', 'rent_order_line_invoice_rel', 'order_line_id', 'invoice_id', 'Invoice Lines', readonly=True), 'price_unit': fields.float('Unit Price', required=True, digits_compute= dp.get_precision('Product Price'), readonly=True, states={'draft': [('readonly', False)]}), 'price_subtotal': fields.function(_amount_line, string='Subtotal', digits_compute= dp.get_precision('Account')), 'tax_id': fields.many2many('account.tax', 'rent_order_tax', 'order_line_id', 'tax_id', 'Taxes', readonly=True, states={'draft': [('readonly', False)]}), 'product_uom_qty': fields.float('Quantity', digits_compute= dp.get_precision('Product Unit of Measure'), required=True, readonly=True, states={'draft': [('readonly', False)]}), 'product_uom': fields.many2one('product.uom', 'Unit of Measure ', required=True, readonly=True, states={'draft': [('readonly', False)]}), 'product_uos_qty': fields.float('Quantity (UoS)' ,digits_compute= dp.get_precision('Product UoS'), readonly=True, states={'draft': [('readonly', False)]}), 'product_uos': fields.many2one('product.uom', 'Product UoS'), 'product_rent_qty': fields.function(_product_rent_qty, string='Rent Quantity', digits_compute= dp.get_precision('Product UoS')), 'th_weight': fields.float('Weight', readonly=True, states={'draft': [('readonly', False)]}), 'move_ids': fields.one2many('stock.move', 'rent_line_id', 'Inventory Moves', readonly=True), 'state': fields.selection([ ('draft', 'Draft'), ('cancel', 'Cancelled'), ('confirmed', 'Waiting Approval'), ('accepted', 'Approved'), ('returned', 'Returned'), ('done', 'Done'), ], 'Status', required=True, readonly=True), 'order_partner_id': fields.related('order_id', 'partner_id', type='many2one', relation='res.partner', store=True, string='Customer'), 'salesman_id':fields.related('order_id', 'user_id', type='many2one', relation='res.users', store=True, string='Salesperson'), 'company_id': fields.related('order_id', 'company_id', type='many2one', relation='res.company', string='Company', store=True, readonly=True), } _order = 'order_id desc, sequence, id'
class sale_order(osv.osv): _inherit = "sale.order" def copy(self, cr, uid, id, default=None, context=None): if not default: default = {} default.update({ 'shipped': False, 'picking_ids': [], }) return super(sale_order, self).copy(cr, uid, id, default, context=context) def shipping_policy_change(self, cr, uid, ids, policy, context=None): if not policy: return {} inv_qty = 'order' if policy == 'prepaid': inv_qty = 'order' elif policy == 'picking': inv_qty = 'procurement' return {'value': {'invoice_quantity': inv_qty}} def write(self, cr, uid, ids, vals, context=None): if vals.get('order_policy', False): if vals['order_policy'] == 'prepaid': vals.update({'invoice_quantity': 'order'}) elif vals['order_policy'] == 'picking': vals.update({'invoice_quantity': 'procurement'}) return super(sale_order, self).write(cr, uid, ids, vals, context=context) def create(self, cr, uid, vals, context=None): if vals.get('order_policy', False): if vals['order_policy'] == 'prepaid': vals.update({'invoice_quantity': 'order'}) if vals['order_policy'] == 'picking': vals.update({'invoice_quantity': 'procurement'}) order = super(sale_order, self).create(cr, uid, vals, context=context) return order # This is False def _picked_rate(self, cr, uid, ids, name, arg, context=None): if not ids: return {} res = {} tmp = {} for id in ids: tmp[id] = {'picked': 0.0, 'total': 0.0} cr.execute( '''SELECT p.sale_id as sale_order_id, sum(m.product_qty) as nbr, mp.state as procurement_state, m.state as move_state, p.type as picking_type FROM stock_move m LEFT JOIN stock_picking p on (p.id=m.picking_id) LEFT JOIN procurement_order mp on (mp.move_id=m.id) WHERE p.sale_id IN %s GROUP BY m.state, mp.state, p.sale_id, p.type''', (tuple(ids), )) for item in cr.dictfetchall(): if item['move_state'] == 'cancel': continue if item['picking_type'] == 'in': #this is a returned picking tmp[item['sale_order_id']]['total'] -= item[ 'nbr'] or 0.0 # Deducting the return picking qty if item['procurement_state'] == 'done' or item[ 'move_state'] == 'done': tmp[item['sale_order_id']]['picked'] -= item['nbr'] or 0.0 else: tmp[item['sale_order_id']]['total'] += item['nbr'] or 0.0 if item['procurement_state'] == 'done' or item[ 'move_state'] == 'done': tmp[item['sale_order_id']]['picked'] += item['nbr'] or 0.0 for order in self.browse(cr, uid, ids, context=context): if order.shipped: res[order.id] = 100.0 else: res[order.id] = tmp[order.id]['total'] and ( 100.0 * tmp[order.id]['picked'] / tmp[order.id]['total']) or 0.0 return res _columns = { 'state': fields.selection( [ ('draft', 'Draft Quotation'), ('sent', 'Quotation Sent'), ('cancel', 'Cancelled'), ('waiting_date', 'Waiting Schedule'), ('progress', 'Sales Order'), ('manual', 'Sale to Invoice'), ('shipping_except', 'Shipping Exception'), ('invoice_except', 'Invoice Exception'), ('done', 'Done'), ], 'Status', readonly=True, help="Gives the status of the quotation or sales order.\ \nThe exception status is automatically set when a cancel operation occurs \ in the invoice validation (Invoice Exception) or in the picking list process (Shipping Exception).\nThe 'Waiting Schedule' status is set when the invoice is confirmed\ but waiting for the scheduler to run on the order date.", select=True), 'incoterm': fields.many2one( 'stock.incoterms', 'Incoterm', help= "International Commercial Terms are a series of predefined commercial terms used in international transactions." ), 'picking_policy': fields.selection( [('direct', 'Deliver each product when available'), ('one', 'Deliver all products at once')], 'Shipping Policy', required=True, readonly=True, states={ 'draft': [('readonly', False)], 'sent': [('readonly', False)] }, help= """Pick 'Deliver each product when available' if you allow partial delivery.""" ), 'order_policy': fields.selection( [ ('manual', 'On Demand'), ('picking', 'On Delivery Order'), ('prepaid', 'Before Delivery'), ], 'Create Invoice', required=True, readonly=True, states={ 'draft': [('readonly', False)], 'sent': [('readonly', False)] }, help= """On demand: A draft invoice can be created from the sales order when needed. \nOn delivery order: A draft invoice can be created from the delivery order when the products have been delivered. \nBefore delivery: A draft invoice is created from the sales order and must be paid before the products can be delivered.""" ), 'picking_ids': fields.one2many( 'stock.picking.out', 'sale_id', 'Related Picking', readonly=True, help= "This is a list of delivery orders that has been generated for this sales order." ), 'shipped': fields.boolean( 'Delivered', readonly=True, help= "It indicates that the sales order has been delivered. This field is updated only after the scheduler(s) have been launched." ), 'picked_rate': fields.function(_picked_rate, string='Picked', type='float'), 'invoice_quantity': fields.selection( [('order', 'Ordered Quantities'), ('procurement', 'Shipped Quantities')], 'Invoice on', help= "The sales order will automatically create the invoice proposition (draft invoice).\ You have to choose if you want your invoice based on ordered ", required=True, readonly=True, states={'draft': [('readonly', False)]}), } _defaults = { 'picking_policy': 'direct', 'order_policy': 'manual', 'invoice_quantity': 'order', } # Form filling def unlink(self, cr, uid, ids, context=None): sale_orders = self.read(cr, uid, ids, ['state'], context=context) unlink_ids = [] for s in sale_orders: if s['state'] in ['draft', 'cancel']: unlink_ids.append(s['id']) else: raise osv.except_osv( _('Invalid Action!'), _('In order to delete a confirmed sales order, you must cancel it.\nTo do so, you must first cancel related picking for delivery orders.' )) return osv.osv.unlink(self, cr, uid, unlink_ids, context=context) def action_view_delivery(self, cr, uid, ids, context=None): ''' This function returns an action that display existing delivery orders of given sales order ids. It can either be a in a list or in a form view, if there is only one delivery order to show. ''' mod_obj = self.pool.get('ir.model.data') act_obj = self.pool.get('ir.actions.act_window') result = mod_obj.get_object_reference(cr, uid, 'stock', 'action_picking_tree') id = result and result[1] or False result = act_obj.read(cr, uid, [id], context=context)[0] #compute the number of delivery orders to display pick_ids = [] for so in self.browse(cr, uid, ids, context=context): pick_ids += [picking.id for picking in so.picking_ids] #choose the view_mode accordingly if len(pick_ids) > 1: result['domain'] = "[('id','in',[" + ','.join(map( str, pick_ids)) + "])]" else: res = mod_obj.get_object_reference(cr, uid, 'stock', 'view_picking_out_form') result['views'] = [(res and res[1] or False, 'form')] result['res_id'] = pick_ids and pick_ids[0] or False return result def action_invoice_create(self, cr, uid, ids, grouped=False, states=['confirmed', 'done', 'exception'], date_invoice=False, context=None): picking_obj = self.pool.get('stock.picking') res = super(sale_order, self).action_invoice_create(cr, uid, ids, grouped=grouped, states=states, date_invoice=date_invoice, context=context) for order in self.browse(cr, uid, ids, context=context): if order.order_policy == 'picking': picking_obj.write(cr, uid, map(lambda x: x.id, order.picking_ids), {'invoice_state': 'invoiced'}) return res def action_cancel(self, cr, uid, ids, context=None): wf_service = netsvc.LocalService("workflow") if context is None: context = {} sale_order_line_obj = self.pool.get('sale.order.line') proc_obj = self.pool.get('procurement.order') for sale in self.browse(cr, uid, ids, context=context): for pick in sale.picking_ids: if pick.state not in ('draft', 'cancel'): raise osv.except_osv( _('Cannot cancel sales order!'), _('You must first cancel all delivery order(s) attached to this sales order.' )) if pick.state == 'cancel': for mov in pick.move_lines: proc_ids = proc_obj.search(cr, uid, [('move_id', '=', mov.id)]) if proc_ids: for proc in proc_ids: wf_service.trg_validate( uid, 'procurement.order', proc, 'button_check', cr) for r in self.read(cr, uid, ids, ['picking_ids']): for pick in r['picking_ids']: wf_service.trg_validate(uid, 'stock.picking', pick, 'button_cancel', cr) return super(sale_order, self).action_cancel(cr, uid, ids, context=context) def action_wait(self, cr, uid, ids, context=None): res = super(sale_order, self).action_wait(cr, uid, ids, context=context) for o in self.browse(cr, uid, ids): noprod = self.test_no_product(cr, uid, o, context) if noprod and o.order_policy == 'picking': self.write(cr, uid, [o.id], {'order_policy': 'manual'}, context=context) return res def procurement_lines_get(self, cr, uid, ids, *args): res = [] for order in self.browse(cr, uid, ids, context={}): for line in order.order_line: if line.procurement_id: res.append(line.procurement_id.id) return res def date_to_datetime(self, cr, uid, userdate, context=None): """ Convert date values expressed in user's timezone to server-side UTC timestamp, assuming a default arbitrary time of 12:00 AM - because a time is needed. :param str userdate: date string in in user time zone :return: UTC datetime string for server-side use """ # TODO: move to fields.datetime in server after 7.0 user_date = datetime.strptime(userdate, DEFAULT_SERVER_DATE_FORMAT) if context and context.get('tz'): tz_name = context['tz'] else: tz_name = self.pool.get('res.users').read(cr, SUPERUSER_ID, uid, ['tz'])['tz'] if tz_name: utc = pytz.timezone('UTC') context_tz = pytz.timezone(tz_name) user_datetime = user_date + relativedelta(hours=12.0) local_timestamp = context_tz.localize(user_datetime, is_dst=False) user_datetime = local_timestamp.astimezone(utc) return user_datetime.strftime(DEFAULT_SERVER_DATETIME_FORMAT) return user_date.strftime(DEFAULT_SERVER_DATETIME_FORMAT) # if mode == 'finished': # returns True if all lines are done, False otherwise # if mode == 'canceled': # returns True if there is at least one canceled line, False otherwise def test_state(self, cr, uid, ids, mode, *args): assert mode in ('finished', 'canceled'), _("invalid mode for test_state") finished = True canceled = False write_done_ids = [] write_cancel_ids = [] for order in self.browse(cr, uid, ids, context={}): for line in order.order_line: if (not line.procurement_id) or (line.procurement_id.state == 'done'): if line.state != 'done': write_done_ids.append(line.id) else: finished = False if line.procurement_id: if (line.procurement_id.state == 'cancel'): canceled = True if line.state != 'exception': write_cancel_ids.append(line.id) if write_done_ids: self.pool.get('sale.order.line').write(cr, uid, write_done_ids, {'state': 'done'}) if write_cancel_ids: self.pool.get('sale.order.line').write(cr, uid, write_cancel_ids, {'state': 'exception'}) if mode == 'finished': return finished elif mode == 'canceled': return canceled def _prepare_order_line_procurement(self, cr, uid, order, line, move_id, date_planned, context=None): return { 'name': line.name, 'origin': order.name, 'date_planned': date_planned, 'product_id': line.product_id.id, 'product_qty': line.product_uom_qty, 'product_uom': line.product_uom.id, 'product_uos_qty': (line.product_uos and line.product_uos_qty)\ or line.product_uom_qty, 'product_uos': (line.product_uos and line.product_uos.id)\ or line.product_uom.id, 'location_id': order.shop_id.warehouse_id.lot_stock_id.id, 'procure_method': line.product_id.procure_method, 'move_id': move_id, 'company_id': order.company_id.id, 'note': line.name, } def _prepare_order_line_move(self, cr, uid, order, line, picking_id, date_planned, context=None): location_id = order.shop_id.warehouse_id.lot_stock_id.id output_id = order.shop_id.warehouse_id.lot_output_id.id return { 'name': line.name, 'picking_id': picking_id, 'product_id': line.product_id.id, 'date': date_planned, 'date_expected': date_planned, 'product_qty': line.product_uom_qty, 'product_uom': line.product_uom.id, 'product_uos_qty': (line.product_uos and line.product_uos_qty) or line.product_uom_qty, 'product_uos': (line.product_uos and line.product_uos.id)\ or line.product_uom.id, 'product_packaging': line.product_packaging.id, 'partner_id': line.address_allotment_id.id or order.partner_shipping_id.id, 'location_id': location_id, 'location_dest_id': output_id, 'sale_line_id': line.id, 'tracking_id': False, 'state': 'draft', #'state': 'waiting', 'company_id': order.company_id.id, 'price_unit': line.product_id.standard_price or 0.0 } def _prepare_order_picking(self, cr, uid, order, context=None): pick_name = self.pool.get('ir.sequence').get(cr, uid, 'stock.picking.out') return { 'name': pick_name, 'origin': order.name, 'date': self.date_to_datetime(cr, uid, order.date_order, context), 'type': 'out', 'state': 'auto', 'move_type': order.picking_policy, 'sale_id': order.id, 'partner_id': order.partner_shipping_id.id, 'note': order.note, 'invoice_state': (order.order_policy == 'picking' and '2binvoiced') or 'none', 'company_id': order.company_id.id, } def ship_recreate(self, cr, uid, order, line, move_id, proc_id): # FIXME: deals with potentially cancelled shipments, seems broken (specially if shipment has production lot) """ Define ship_recreate for process after shipping exception param order: sales order to which the order lines belong param line: sales order line records to procure param move_id: the ID of stock move param proc_id: the ID of procurement """ move_obj = self.pool.get('stock.move') if order.state == 'shipping_except': for pick in order.picking_ids: for move in pick.move_lines: if move.state == 'cancel': mov_ids = move_obj.search( cr, uid, [('state', '=', 'cancel'), ('sale_line_id', '=', line.id), ('picking_id', '=', pick.id)]) if mov_ids: for mov in move_obj.browse(cr, uid, mov_ids): # FIXME: the following seems broken: what if move_id doesn't exist? What if there are several mov_ids? Shouldn't that be a sum? move_obj.write( cr, uid, [move_id], { 'product_qty': mov.product_qty, 'product_uos_qty': mov.product_uos_qty }) self.pool.get('procurement.order').write( cr, uid, [proc_id], { 'product_qty': mov.product_qty, 'product_uos_qty': mov.product_uos_qty }) return True def _get_date_planned(self, cr, uid, order, line, start_date, context=None): start_date = self.date_to_datetime(cr, uid, start_date, context) date_planned = datetime.strptime( start_date, DEFAULT_SERVER_DATETIME_FORMAT) + relativedelta( days=line.delay or 0.0) date_planned = (date_planned - timedelta(days=order.company_id.security_lead) ).strftime(DEFAULT_SERVER_DATETIME_FORMAT) return date_planned def _create_pickings_and_procurements(self, cr, uid, order, order_lines, picking_id=False, context=None): """Create the required procurements to supply sales order lines, also connecting the procurements to appropriate stock moves in order to bring the goods to the sales order's requested location. If ``picking_id`` is provided, the stock moves will be added to it, otherwise a standard outgoing picking will be created to wrap the stock moves, as returned by :meth:`~._prepare_order_picking`. Modules that wish to customize the procurements or partition the stock moves over multiple stock pickings may override this method and call ``super()`` with different subsets of ``order_lines`` and/or preset ``picking_id`` values. :param browse_record order: sales order to which the order lines belong :param list(browse_record) order_lines: sales order line records to procure :param int picking_id: optional ID of a stock picking to which the created stock moves will be added. A new picking will be created if ommitted. :return: True """ move_obj = self.pool.get('stock.move') picking_obj = self.pool.get('stock.picking') procurement_obj = self.pool.get('procurement.order') proc_ids = [] for line in order_lines: if line.state == 'done': continue date_planned = self._get_date_planned(cr, uid, order, line, order.date_order, context=context) if line.product_id: if line.product_id.type in ('product', 'consu'): if not picking_id: picking_id = picking_obj.create( cr, uid, self._prepare_order_picking(cr, uid, order, context=context)) move_id = move_obj.create( cr, uid, self._prepare_order_line_move(cr, uid, order, line, picking_id, date_planned, context=context)) else: # a service has no stock move move_id = False proc_id = procurement_obj.create( cr, uid, self._prepare_order_line_procurement(cr, uid, order, line, move_id, date_planned, context=context)) proc_ids.append(proc_id) line.write({'procurement_id': proc_id}) self.ship_recreate(cr, uid, order, line, move_id, proc_id) wf_service = netsvc.LocalService("workflow") if picking_id: wf_service.trg_validate(uid, 'stock.picking', picking_id, 'button_confirm', cr) for proc_id in proc_ids: wf_service.trg_validate(uid, 'procurement.order', proc_id, 'button_confirm', cr) val = {} if order.state == 'shipping_except': val['state'] = 'progress' val['shipped'] = False if (order.order_policy == 'manual'): for line in order.order_line: if (not line.invoiced) and (line.state not in ('cancel', 'draft')): val['state'] = 'manual' break order.write(val) return True def action_ship_create(self, cr, uid, ids, context=None): for order in self.browse(cr, uid, ids, context=context): self._create_pickings_and_procurements(cr, uid, order, order.order_line, None, context=context) return True def action_ship_end(self, cr, uid, ids, context=None): for order in self.browse(cr, uid, ids, context=context): val = {'shipped': True} if order.state == 'shipping_except': val['state'] = 'progress' if (order.order_policy == 'manual'): for line in order.order_line: if (not line.invoiced) and (line.state not in ('cancel', 'draft')): val['state'] = 'manual' break for line in order.order_line: towrite = [] if line.state == 'exception': towrite.append(line.id) if towrite: self.pool.get('sale.order.line').write(cr, uid, towrite, {'state': 'done'}, context=context) res = self.write(cr, uid, [order.id], val) return True def has_stockable_products(self, cr, uid, ids, *args): for order in self.browse(cr, uid, ids): for order_line in order.order_line: if order_line.product_id and order_line.product_id.type in ( 'product', 'consu'): return True return False
else: kip_ids=",".join(map(str,ids)) cr.execute("Select payment_import_id id from kderp_import_payment_line where payment_import_id in (%s) and state='draft'" % (kip_ids)) list_error=[] for new_id in cr.fetchall(): list_error.append(new_id[0]) for id in ids: if id not in list_error: self.write(cr, uid, [id], {'state':'done'}) return True _columns={ 'date':fields.date('Date', required=True, states={'done':[('readonly',True)]}, help="Date of Accounting Import Payment to Supplier to ERP"), 'name':fields.char('Code Import',size=32,required=True,select=True,states={'done':[('readonly',True)]}), 'description':fields.char('Desc.',size=128,states={'done':[('readonly',True)]}), 'import_line':fields.one2many('kderp.import.payment.line','payment_import_id','Details',states={'done':[('readonly',True)]}), 'state':fields.selection([('draft','Draft'),('done','Done')],'State',readonly=True,select=True) } _sql_constraints = [ ('supplier_payment_import_unique',"unique(name)","KDERP Error: The Code Import must be unique !") ] _defaults = { 'state': 'draft', 'date': lambda *a: time.strftime('%Y-%m-%d'), 'name':lambda *a: time.strftime('AISP-%Y%b%d.%H%M') } def load(self, cr, uid, fields, data, context=None): #def import_data(self, cr, uid, fields, datas, mode='init', current_module='', noupdate=False, context=None, filename=None): try: payment_id_pos = fields.index('import_line/payment_number')
class sale_order_line(osv.osv): def _number_packages(self, cr, uid, ids, field_name, arg, context=None): res = {} for line in self.browse(cr, uid, ids, context=context): try: res[line.id] = int( (line.product_uom_qty + line.product_packaging.qty - 0.0001) / line.product_packaging.qty) except: res[line.id] = 1 return res _inherit = 'sale.order.line' _columns = { 'delay': fields.float( 'Delivery Lead Time', required=True, help= "Number of days between the order confirmation and the shipping of the products to the customer", readonly=True, states={'draft': [('readonly', False)]}), 'procurement_id': fields.many2one('procurement.order', 'Procurement'), 'property_ids': fields.many2many('mrp.property', 'sale_order_line_property_rel', 'order_id', 'property_id', 'Properties', readonly=True, states={'draft': [('readonly', False)]}), 'product_packaging': fields.many2one('product.packaging', 'Packaging'), 'move_ids': fields.one2many('stock.move', 'sale_line_id', 'Inventory Moves', readonly=True), 'number_packages': fields.function(_number_packages, type='integer', string='Number Packages'), } _defaults = { 'delay': 0.0, 'product_packaging': False, } def _get_line_qty(self, cr, uid, line, context=None): if line.procurement_id and not (line.order_id.invoice_quantity == 'order'): return self.pool.get('procurement.order').quantity_get( cr, uid, line.procurement_id.id, context=context) else: return super(sale_order_line, self)._get_line_qty(cr, uid, line, context=context) def _get_line_uom(self, cr, uid, line, context=None): if line.procurement_id and not (line.order_id.invoice_quantity == 'order'): return self.pool.get('procurement.order').uom_get( cr, uid, line.procurement_id.id, context=context) else: return super(sale_order_line, self)._get_line_uom(cr, uid, line, context=context) def button_cancel(self, cr, uid, ids, context=None): res = super(sale_order_line, self).button_cancel(cr, uid, ids, context=context) for line in self.browse(cr, uid, ids, context=context): for move_line in line.move_ids: if move_line.state != 'cancel': raise osv.except_osv( _('Cannot cancel sales order line!'), _('You must first cancel stock moves attached to this sales order line.' )) return res def copy_data(self, cr, uid, id, default=None, context=None): if not default: default = {} default.update({'move_ids': []}) return super(sale_order_line, self).copy_data(cr, uid, id, default, context=context) def product_packaging_change(self, cr, uid, ids, pricelist, product, qty=0, uom=False, partner_id=False, packaging=False, flag=False, context=None): if not product: return {'value': {'product_packaging': False}} product_obj = self.pool.get('product.product') product_uom_obj = self.pool.get('product.uom') pack_obj = self.pool.get('product.packaging') warning = {} result = {} warning_msgs = '' if flag: res = self.product_id_change(cr, uid, ids, pricelist=pricelist, product=product, qty=qty, uom=uom, partner_id=partner_id, packaging=packaging, flag=False, context=context) warning_msgs = res.get('warning') and res['warning']['message'] products = product_obj.browse(cr, uid, product, context=context) if not products.packaging: packaging = result['product_packaging'] = False elif not packaging and products.packaging and not flag: packaging = products.packaging[0].id result['product_packaging'] = packaging if packaging: default_uom = products.uom_id and products.uom_id.id pack = pack_obj.browse(cr, uid, packaging, context=context) q = product_uom_obj._compute_qty(cr, uid, uom, pack.qty, default_uom) # qty = qty - qty % q + q if qty and (q and not (qty % q) == 0): ean = pack.ean or _('(n/a)') qty_pack = pack.qty type_ul = pack.ul if not warning_msgs: warn_msg = _("You selected a quantity of %d Units.\n" "But it's not compatible with the selected packaging.\n" "Here is a proposition of quantities according to the packaging:\n" "EAN: %s Quantity: %s Type of ul: %s") % \ (qty, ean, qty_pack, type_ul.name) warning_msgs += _( "Picking Information ! : ") + warn_msg + "\n\n" warning = { 'title': _('Configuration Error!'), 'message': warning_msgs } result['product_uom_qty'] = qty return {'value': result, 'warning': warning} def product_id_change(self, cr, uid, ids, pricelist, product, qty=0, uom=False, qty_uos=0, uos=False, name='', partner_id=False, lang=False, update_tax=True, date_order=False, packaging=False, fiscal_position=False, flag=False, context=None): context = context or {} product_uom_obj = self.pool.get('product.uom') partner_obj = self.pool.get('res.partner') product_obj = self.pool.get('product.product') warning = {} res = super(sale_order_line, self).product_id_change(cr, uid, ids, pricelist, product, qty=qty, uom=uom, qty_uos=qty_uos, uos=uos, name=name, partner_id=partner_id, lang=lang, update_tax=update_tax, date_order=date_order, packaging=packaging, fiscal_position=fiscal_position, flag=flag, context=context) if not product: res['value'].update({'product_packaging': False}) return res #update of result obtained in super function product_obj = product_obj.browse(cr, uid, product, context=context) res['value']['delay'] = (product_obj.sale_delay or 0.0) res['value']['type'] = product_obj.procure_method #check if product is available, and if not: raise an error uom2 = False if uom: uom2 = product_uom_obj.browse(cr, uid, uom) if product_obj.uom_id.category_id.id != uom2.category_id.id: uom = False if not uom2: uom2 = product_obj.uom_id # Calling product_packaging_change function after updating UoM res_packing = self.product_packaging_change(cr, uid, ids, pricelist, product, qty, uom, partner_id, packaging, context=context) res['value'].update(res_packing.get('value', {})) warning_msgs = res_packing.get( 'warning') and res_packing['warning']['message'] or '' compare_qty = float_compare( product_obj.virtual_available * uom2.factor, qty * product_obj.uom_id.factor, precision_rounding=product_obj.uom_id.rounding) if (product_obj.type=='product') and int(compare_qty) == -1 \ and (product_obj.procure_method=='make_to_stock'): warn_msg = _('You plan to sell %.2f %s but you only have %.2f %s available !\nThe real stock is %.2f %s. (without reservations)') % \ (qty, uom2 and uom2.name or product_obj.uom_id.name, max(0,product_obj.virtual_available), product_obj.uom_id.name, max(0,product_obj.qty_available), product_obj.uom_id.name) warning_msgs += _("Not enough stock ! : ") + warn_msg + "\n\n" #update of warning messages if warning_msgs: warning = { 'title': _('Configuration Error!'), 'message': warning_msgs } res.update({'warning': warning}) return res
'l10n_br_account.fiscal.category', 'Categoria'), 'fiscal_type': fields.selection(COMPANY_FISCAL_TYPE, u'Regime Tributário', required=True), 'revenue_start': fields.float( 'Faturamento Inicial', digits_compute=dp.get_precision('Account'), help="Faixa inicial de faturamento bruto"), 'revenue_end': fields.float( 'Faturamento Final', digits_compute=dp.get_precision('Account'), help="Faixa inicial de faturamento bruto") } OTHERS_FISCAL_RULE_COLUMNS_TEMPLATE = { 'parent_id': fields.many2one( 'account.fiscal.position.rule.template', 'Regra Pai'), 'child_ids': fields.one2many( 'account.fiscal.position.rule.template', 'parent_id', 'Regras Filhas'), } OTHERS_FISCAL_RULE_COLUMNS = { 'parent_id': fields.many2one( 'account.fiscal.position.rule', 'Regra Pai'), 'child_ids': fields.one2many( 'account.fiscal.position.rule', 'parent_id', 'Regras Filhas'), } FISCAL_RULE_DEFAULTS = { 'fiscal_type': COMPANY_FISCAL_TYPE_DEFAULT, 'revenue_start': 0.00, 'revenue_end': 0.00 }
class account_asset_asset(osv.osv): _name = 'account.asset.asset' _description = 'Asset' def unlink(self, cr, uid, ids, context=None): for asset in self.browse(cr, uid, ids, context=context): if asset.account_move_line_ids: raise osv.except_osv( _('Error!'), _('You cannot delete an asset that contains posted depreciation lines.' )) return super(account_asset_asset, self).unlink(cr, uid, ids, context=context) def _get_period(self, cr, uid, context=None): periods = self.pool.get('account.period').find(cr, uid, context=context) if periods: return periods[0] else: return False def _get_last_depreciation_date(self, cr, uid, ids, context=None): """ @param id: ids of a account.asset.asset objects @return: Returns a dictionary of the effective dates of the last depreciation entry made for given asset ids. If there isn't any, return the purchase date of this asset """ cr.execute( """ SELECT a.id as id, COALESCE(MAX(l.date),a.purchase_date) AS date FROM account_asset_asset a LEFT JOIN account_move_line l ON (l.asset_id = a.id) WHERE a.id IN %s GROUP BY a.id, a.purchase_date """, (tuple(ids), )) return dict(cr.fetchall()) def _compute_board_amount(self, cr, uid, asset, i, residual_amount, amount_to_depr, undone_dotation_number, posted_depreciation_line_ids, total_days, depreciation_date, context=None): #by default amount = 0 amount = 0 if i == undone_dotation_number: amount = residual_amount else: if asset.method == 'linear': amount = amount_to_depr / (undone_dotation_number - len(posted_depreciation_line_ids)) if asset.prorata: amount = amount_to_depr / asset.method_number days = total_days - float(depreciation_date.strftime('%j')) if i == 1: amount = (amount_to_depr / asset.method_number) / total_days * days elif i == undone_dotation_number: amount = (amount_to_depr / asset.method_number ) / total_days * (total_days - days) elif asset.method == 'degressive': amount = residual_amount * asset.method_progress_factor if asset.prorata: days = total_days - float(depreciation_date.strftime('%j')) if i == 1: amount = ( residual_amount * asset.method_progress_factor) / total_days * days elif i == undone_dotation_number: amount = (residual_amount * asset.method_progress_factor ) / total_days * (total_days - days) return amount def _compute_board_undone_dotation_nb(self, cr, uid, asset, depreciation_date, total_days, context=None): undone_dotation_number = asset.method_number if asset.method_time == 'end': end_date = datetime.strptime(asset.method_end, '%Y-%m-%d') undone_dotation_number = 0 while depreciation_date <= end_date: depreciation_date = ( datetime(depreciation_date.year, depreciation_date.month, depreciation_date.day) + relativedelta(months=+asset.method_period)) undone_dotation_number += 1 if asset.prorata: undone_dotation_number += 1 return undone_dotation_number def compute_depreciation_board(self, cr, uid, ids, context=None): depreciation_lin_obj = self.pool.get('account.asset.depreciation.line') currency_obj = self.pool.get('res.currency') for asset in self.browse(cr, uid, ids, context=context): if asset.value_residual == 0.0: continue posted_depreciation_line_ids = depreciation_lin_obj.search( cr, uid, [('asset_id', '=', asset.id), ('move_check', '=', True)], order='depreciation_date desc') old_depreciation_line_ids = depreciation_lin_obj.search( cr, uid, [('asset_id', '=', asset.id), ('move_id', '=', False)]) if old_depreciation_line_ids: depreciation_lin_obj.unlink(cr, uid, old_depreciation_line_ids, context=context) amount_to_depr = residual_amount = asset.value_residual if asset.prorata: depreciation_date = datetime.strptime( self._get_last_depreciation_date(cr, uid, [asset.id], context)[asset.id], '%Y-%m-%d') else: # depreciation_date = 1st January of purchase year purchase_date = datetime.strptime(asset.purchase_date, '%Y-%m-%d') #if we already have some previous validated entries, starting date isn't 1st January but last entry + method period if (len(posted_depreciation_line_ids) > 0): last_depreciation_date = datetime.strptime( depreciation_lin_obj.browse( cr, uid, posted_depreciation_line_ids[0], context=context).depreciation_date, '%Y-%m-%d') depreciation_date = ( last_depreciation_date + relativedelta(months=+asset.method_period)) else: depreciation_date = datetime(purchase_date.year, 1, 1) day = depreciation_date.day month = depreciation_date.month year = depreciation_date.year total_days = (year % 4) and 365 or 366 undone_dotation_number = self._compute_board_undone_dotation_nb( cr, uid, asset, depreciation_date, total_days, context=context) for x in range(len(posted_depreciation_line_ids), undone_dotation_number): i = x + 1 amount = self._compute_board_amount( cr, uid, asset, i, residual_amount, amount_to_depr, undone_dotation_number, posted_depreciation_line_ids, total_days, depreciation_date, context=context) company_currency = asset.company_id.currency_id.id current_currency = asset.currency_id.id # compute amount into company currency amount = currency_obj.compute(cr, uid, current_currency, company_currency, amount, context=context) residual_amount -= amount vals = { 'amount': amount, 'asset_id': asset.id, 'sequence': i, 'name': str(asset.id) + '/' + str(i), 'remaining_value': residual_amount, 'depreciated_value': (asset.purchase_value - asset.salvage_value) - (residual_amount + amount), 'depreciation_date': depreciation_date.strftime('%Y-%m-%d'), } depreciation_lin_obj.create(cr, uid, vals, context=context) # Considering Depr. Period as months depreciation_date = ( datetime(year, month, day) + relativedelta(months=+asset.method_period)) day = depreciation_date.day month = depreciation_date.month year = depreciation_date.year return True def validate(self, cr, uid, ids, context=None): if context is None: context = {} return self.write(cr, uid, ids, {'state': 'open'}, context) def set_to_close(self, cr, uid, ids, context=None): return self.write(cr, uid, ids, {'state': 'close'}, context=context) def set_to_draft(self, cr, uid, ids, context=None): return self.write(cr, uid, ids, {'state': 'draft'}, context=context) def _amount_residual(self, cr, uid, ids, name, args, context=None): cr.execute( """SELECT l.asset_id as id, SUM(abs(l.debit-l.credit)) AS amount FROM account_move_line l WHERE l.asset_id IN %s GROUP BY l.asset_id """, (tuple(ids), )) res = dict(cr.fetchall()) for asset in self.browse(cr, uid, ids, context): res[asset.id] = asset.purchase_value - res.get( asset.id, 0.0) - asset.salvage_value for id in ids: res.setdefault(id, 0.0) return res def onchange_company_id(self, cr, uid, ids, company_id=False, context=None): val = {} if company_id: company = self.pool.get('res.company').browse(cr, uid, company_id, context=context) if company.currency_id.company_id and company.currency_id.company_id.id != company_id: val['currency_id'] = False else: val['currency_id'] = company.currency_id.id return {'value': val} def onchange_purchase_salvage_value(self, cr, uid, ids, purchase_value, salvage_value, context=None): val = {} for asset in self.browse(cr, uid, ids, context=context): if purchase_value: val['value_residual'] = purchase_value - salvage_value if salvage_value: val['value_residual'] = purchase_value - salvage_value return {'value': val} def _entry_count(self, cr, uid, ids, field_name, arg, context=None): res = dict(map(lambda x: (x, 0), ids)) try: for entry in self.browse(cr, uid, ids, context=context): res[entry.id] = len(entry.account_move_line_ids) except: pass return res _columns = { 'account_move_line_ids': fields.one2many('account.move.line', 'asset_id', 'Entries', readonly=True, states={'draft':[('readonly',False)]}), 'entry_count': fields.function(_entry_count, string='# Asset Entries', type='integer'), 'name': fields.char('Asset Name', size=64, required=True, readonly=True, states={'draft':[('readonly',False)]}), 'code': fields.char('Reference', size=32, readonly=True, states={'draft':[('readonly',False)]}), 'purchase_value': fields.float('Gross Value', required=True, readonly=True, states={'draft':[('readonly',False)]}), 'currency_id': fields.many2one('res.currency','Currency',required=True, readonly=True, states={'draft':[('readonly',False)]}), 'company_id': fields.many2one('res.company', 'Company', required=True, readonly=True, states={'draft':[('readonly',False)]}), 'note': fields.text('Note'), 'category_id': fields.many2one('account.asset.category', 'Asset Category', required=True, change_default=True, readonly=True, states={'draft':[('readonly',False)]}), 'parent_id': fields.many2one('account.asset.asset', 'Parent Asset', readonly=True, states={'draft':[('readonly',False)]}), 'child_ids': fields.one2many('account.asset.asset', 'parent_id', 'Children Assets'), 'purchase_date': fields.date('Purchase Date', required=True, readonly=True, states={'draft':[('readonly',False)]}), 'state': fields.selection([('draft','Draft'),('open','Running'),('close','Close')], 'Status', required=True, help="When an asset is created, the status is 'Draft'.\n" \ "If the asset is confirmed, the status goes in 'Running' and the depreciation lines can be posted in the accounting.\n" \ "You can manually close an asset when the depreciation is over. If the last line of depreciation is posted, the asset automatically goes in that status."), 'active': fields.boolean('Active'), 'partner_id': fields.many2one('res.partner', 'Partner', readonly=True, states={'draft':[('readonly',False)]}), 'method': fields.selection([('linear','Linear'),('degressive','Degressive')], 'Computation Method', required=True, readonly=True, states={'draft':[('readonly',False)]}, help="Choose the method to use to compute the amount of depreciation lines.\n"\ " * Linear: Calculated on basis of: Gross Value / Number of Depreciations\n" \ " * Degressive: Calculated on basis of: Residual Value * Degressive Factor"), 'method_number': fields.integer('Number of Depreciations', readonly=True, states={'draft':[('readonly',False)]}, help="The number of depreciations needed to depreciate your asset"), 'method_period': fields.integer('Number of Months in a Period', required=True, readonly=True, states={'draft':[('readonly',False)]}, help="The amount of time between two depreciations, in months"), 'method_end': fields.date('Ending Date', readonly=True, states={'draft':[('readonly',False)]}), 'method_progress_factor': fields.float('Degressive Factor', readonly=True, states={'draft':[('readonly',False)]}), 'value_residual': fields.function(_amount_residual, method=True, digits_compute=dp.get_precision('Account'), string='Residual Value'), 'method_time': fields.selection([('number','Number of Depreciations'),('end','Ending Date')], 'Time Method', required=True, readonly=True, states={'draft':[('readonly',False)]}, help="Choose the method to use to compute the dates and number of depreciation lines.\n"\ " * Number of Depreciations: Fix the number of depreciation lines and the time between 2 depreciations.\n" \ " * Ending Date: Choose the time between 2 depreciations and the date the depreciations won't go beyond."), 'prorata':fields.boolean('Prorata Temporis', readonly=True, states={'draft':[('readonly',False)]}, help='Indicates that the first depreciation entry for this asset have to be done from the purchase date instead of the first January'), 'history_ids': fields.one2many('account.asset.history', 'asset_id', 'History', readonly=True), 'depreciation_line_ids': fields.one2many('account.asset.depreciation.line', 'asset_id', 'Depreciation Lines', readonly=True, states={'draft':[('readonly',False)],'open':[('readonly',False)]}), 'salvage_value': fields.float('Salvage Value', digits_compute=dp.get_precision('Account'), help="It is the amount you plan to have that you cannot depreciate.", readonly=True, states={'draft':[('readonly',False)]}), } _defaults = { 'code': lambda obj, cr, uid, context: obj.pool.get('ir.sequence').get( cr, uid, 'account.asset.code'), 'purchase_date': lambda obj, cr, uid, context: time.strftime('%Y-%m-%d'), 'active': True, 'state': 'draft', 'method': 'linear', 'method_number': 5, 'method_time': 'number', 'method_period': 12, 'method_progress_factor': 0.3, 'currency_id': lambda self, cr, uid, c: self.pool.get('res.users').browse( cr, uid, uid, c).company_id.currency_id.id, 'company_id': lambda self, cr, uid, context: self.pool.get('res.company'). _company_default_get(cr, uid, 'account.asset.asset', context=context), } def _check_recursion(self, cr, uid, ids, context=None, parent=None): return super(account_asset_asset, self)._check_recursion(cr, uid, ids, context=context, parent=parent) def _check_prorata(self, cr, uid, ids, context=None): for asset in self.browse(cr, uid, ids, context=context): if asset.prorata and asset.method_time != 'number': return False return True _constraints = [ (_check_recursion, 'Error ! You cannot create recursive assets.', ['parent_id']), (_check_prorata, 'Prorata temporis can be applied only for time method "number of depreciations".', ['prorata']), ] def onchange_category_id(self, cr, uid, ids, category_id, context=None): res = {'value': {}} asset_categ_obj = self.pool.get('account.asset.category') if category_id: category_obj = asset_categ_obj.browse(cr, uid, category_id, context=context) res['value'] = { 'method': category_obj.method, 'method_number': category_obj.method_number, 'method_time': category_obj.method_time, 'method_period': category_obj.method_period, 'method_progress_factor': category_obj.method_progress_factor, 'method_end': category_obj.method_end, 'prorata': category_obj.prorata, } return res def onchange_method_time(self, cr, uid, ids, method_time='number', context=None): res = {'value': {}} if method_time != 'number': res['value'] = {'prorata': False} return res def copy(self, cr, uid, id, default=None, context=None): if default is None: default = {} if context is None: context = {} default.update({ 'depreciation_line_ids': [], 'account_move_line_ids': [], 'history_ids': [], 'state': 'draft' }) return super(account_asset_asset, self).copy(cr, uid, id, default, context=context) def _compute_entries(self, cr, uid, ids, period_id, context=None): result = [] period_obj = self.pool.get('account.period') depreciation_obj = self.pool.get('account.asset.depreciation.line') period = period_obj.browse(cr, uid, period_id, context=context) depreciation_ids = depreciation_obj.search( cr, uid, [('asset_id', 'in', ids), ('depreciation_date', '<=', period.date_stop), ('depreciation_date', '>=', period.date_start), ('move_check', '=', False)], context=context) if context is None: context = {} context.update({'depreciation_date': period.date_stop}) return depreciation_obj.create_move(cr, uid, depreciation_ids, context=context) def create(self, cr, uid, vals, context=None): asset_id = super(account_asset_asset, self).create(cr, uid, vals, context=context) self.compute_depreciation_board(cr, uid, [asset_id], context=context) return asset_id def open_entries(self, cr, uid, ids, context=None): if context is None: context = {} context.update({ 'search_default_asset_id': ids, 'default_asset_id': ids }) return { 'name': _('Journal Items'), 'view_type': 'form', 'view_mode': 'tree,form', 'res_model': 'account.move.line', 'view_id': False, 'type': 'ir.actions.act_window', 'context': context, }
_columns = { 'name':fields.char('Memo', size=256), 'log_ref': fields.char('Check-log Ref', size=128), <<<<<<< HEAD # 'origin' : fields.char('Origin', size=128), 'check_status' :fields.selection([('void','Voided'),('print','Printed'),('re_print','Re-Printed'),('clear','Cleared')]), 'chk_seq': fields.char("Check Number", size=64, readonly=True), 'invoice_ids': fields.one2many('account.invoice', 'voucher_id', 'Invoices', ondelete='cascade'), 'jtype':fields.related('journal_id','type', string="Journal Type", type='selection', selection=[('sale', 'Sale'),('sale_refund','Sale Refund'), ('purchase', 'Purchase'), ('purchase_refund','Purchase Refund'), ('cash', 'Cash'), ('bank', 'Bank and Checks'), ('general', 'General'), ('situation', 'Opening/Closing Situation')],), } ======= # 'origin' : fields.char('Origin', size=128), 'check_status' :fields.selection([('void','Voided'),('print','Printed'),('re_print','Re-Printed'),('clear','Cleared')]), 'chk_seq': fields.char("Check Number", size=64, readonly=True), 'invoice_ids': fields.one2many('account.invoice', 'voucher_id', 'Invoices', ondelete='cascade'), 'reference': fields.char('Origin', size=64, readonly=True, states={'draft':[('readonly',False)]}, help="Source document which generated the payment."), 'jtype':fields.related('journal_id','type', string="Journal Type", type='selection', selection=[('sale', 'Sale'),('sale_refund','Sale Refund'), ('purchase', 'Purchase'), ('purchase_refund','Purchase Refund'), ('cash', 'Cash'), ('bank', 'Bank and Checks'), ('general', 'General'), ('situation', 'Opening/Closing Situation')],), } >>>>>>> c1979f64b3360c86d60e00c92be0271d89f97f2d def print_checks(self, cr, uid, ids, context=None): check_state = self.browse(cr, uid, ids[0],context=None).check_status view_ref = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'account_check_writing', 'view_account_check_write') view_id = view_ref and view_ref[1] or False, context.update({'active_ids':ids, 'check_state': check_state}) return { 'type': 'ir.actions.act_window', 'name': 'Print Checks', 'view_mode': 'form', 'view_type': 'form',
class hr_employee(osv.osv): _name = "hr.employee" _description = "Employee" _order = 'name_related' _inherits = {'resource.resource': "resource_id"} _inherit = ['mail.thread'] _mail_post_access = 'read' def _get_image(self, cr, uid, ids, name, args, context=None): result = dict.fromkeys(ids, False) for obj in self.browse(cr, uid, ids, context=context): result[obj.id] = tools.image_get_resized_images(obj.image) return result def _set_image(self, cr, uid, id, name, value, args, context=None): return self.write(cr, uid, [id], {'image': tools.image_resize_image_big(value)}, context=context) _columns = { #we need a related field in order to be able to sort the employee by name 'name_related': fields.related('resource_id', 'name', type='char', string='Name', readonly=True, store=True), 'country_id': fields.many2one('res.country', 'Nationality'), 'birthday': fields.date("Date of Birth"), 'ssnid': fields.char('SSN No', help='Social Security Number'), 'sinid': fields.char('SIN No', help="Social Insurance Number"), 'identification_id': fields.char('Identification No'), 'otherid': fields.char('Other Id'), 'gender': fields.selection([('male', 'Male'), ('female', 'Female')], 'Gender'), 'marital': fields.selection([('single', 'Single'), ('married', 'Married'), ('widower', 'Widower'), ('divorced', 'Divorced')], 'Marital Status'), 'department_id': fields.many2one('hr.department', 'Department'), 'address_id': fields.many2one('res.partner', 'Working Address'), 'address_home_id': fields.many2one('res.partner', 'Home Address'), 'bank_account_id': fields.many2one('res.partner.bank', 'Bank Account Number', domain="[('partner_id','=',address_home_id)]", help="Employee bank salary account"), 'work_phone': fields.char('Work Phone', readonly=False), 'mobile_phone': fields.char('Work Mobile', readonly=False), 'work_email': fields.char('Work Email', size=240), 'work_location': fields.char('Office Location'), 'notes': fields.text('Notes'), 'parent_id': fields.many2one('hr.employee', 'Manager'), 'category_ids': fields.many2many('hr.employee.category', 'employee_category_rel', 'emp_id', 'category_id', 'Tags'), 'child_ids': fields.one2many('hr.employee', 'parent_id', 'Subordinates'), 'resource_id': fields.many2one('resource.resource', 'Resource', ondelete='cascade', required=True), 'coach_id': fields.many2one('hr.employee', 'Coach'), 'job_id': fields.many2one('hr.job', 'Job Title'), # image: all image fields are base64 encoded and PIL-supported 'image': fields.binary("Photo", help="This field holds the image used as photo for the employee, limited to 1024x1024px."), 'image_medium': fields.function(_get_image, fnct_inv=_set_image, string="Medium-sized photo", type="binary", multi="_get_image", store = { 'hr.employee': (lambda self, cr, uid, ids, c={}: ids, ['image'], 10), }, help="Medium-sized photo of the employee. It is automatically "\ "resized as a 128x128px image, with aspect ratio preserved. "\ "Use this field in form views or some kanban views."), 'image_small': fields.function(_get_image, fnct_inv=_set_image, string="Small-sized photo", type="binary", multi="_get_image", store = { 'hr.employee': (lambda self, cr, uid, ids, c={}: ids, ['image'], 10), }, help="Small-sized photo of the employee. It is automatically "\ "resized as a 64x64px image, with aspect ratio preserved. "\ "Use this field anywhere a small image is required."), 'passport_id': fields.char('Passport No'), 'color': fields.integer('Color Index'), 'city': fields.related('address_id', 'city', type='char', string='City'), 'login': fields.related('user_id', 'login', type='char', string='Login', readonly=1), 'last_login': fields.related('user_id', 'date', type='datetime', string='Latest Connection', readonly=1), } def _get_default_image(self, cr, uid, context=None): image_path = get_module_resource('hr', 'static/src/img', 'default_image.png') return tools.image_resize_image_big( open(image_path, 'rb').read().encode('base64')) defaults = { 'active': 1, 'image': _get_default_image, 'color': 0, } def _broadcast_welcome(self, cr, uid, employee_id, context=None): """ Broadcast the welcome message to all users in the employee company. """ employee = self.browse(cr, uid, employee_id, context=context) partner_ids = [] _model, group_id = self.pool['ir.model.data'].get_object_reference( cr, uid, 'base', 'group_user') if employee.user_id: company_id = employee.user_id.company_id.id elif employee.company_id: company_id = employee.company_id.id elif employee.job_id: company_id = employee.job_id.company_id.id elif employee.department_id: company_id = employee.department_id.company_id.id else: company_id = self.pool['res.company']._company_default_get( cr, uid, 'hr.employee', context=context) res_users = self.pool['res.users'] user_ids = res_users.search(cr, SUPERUSER_ID, [('company_id', '=', company_id), ('groups_id', 'in', group_id)], context=context) partner_ids = list( set(u.partner_id.id for u in res_users.browse( cr, SUPERUSER_ID, user_ids, context=context))) self.message_post( cr, uid, [employee_id], body= _('Welcome to %s! Please help him/her take the first steps with Odoo!' ) % (employee.name), partner_ids=partner_ids, subtype='mail.mt_comment', context=context) return True def create(self, cr, uid, data, context=None): context = dict(context or {}) if context.get("mail_broadcast"): context['mail_create_nolog'] = True employee_id = super(hr_employee, self).create(cr, uid, data, context=context) if context.get("mail_broadcast"): self._broadcast_welcome(cr, uid, employee_id, context=context) return employee_id def unlink(self, cr, uid, ids, context=None): resource_ids = [] for employee in self.browse(cr, uid, ids, context=context): resource_ids.append(employee.resource_id.id) super(hr_employee, self).unlink(cr, uid, ids, context=context) return self.pool.get('resource.resource').unlink(cr, uid, resource_ids, context=context) def onchange_address_id(self, cr, uid, ids, address, context=None): if address: address = self.pool.get('res.partner').browse(cr, uid, address, context=context) return { 'value': { 'work_phone': address.phone, 'mobile_phone': address.mobile } } return {'value': {}} def onchange_company(self, cr, uid, ids, company, context=None): address_id = False if company: company_id = self.pool.get('res.company').browse(cr, uid, company, context=context) address = self.pool.get('res.partner').address_get( cr, uid, [company_id.partner_id.id], ['default']) address_id = address and address['default'] or False return {'value': {'address_id': address_id}} def onchange_department_id(self, cr, uid, ids, department_id, context=None): value = {'parent_id': False} if department_id: department = self.pool.get('hr.department').browse( cr, uid, department_id) value['parent_id'] = department.manager_id.id return {'value': value} def onchange_user(self, cr, uid, ids, user_id, context=None): work_email = False if user_id: work_email = self.pool.get('res.users').browse( cr, uid, user_id, context=context).email return {'value': {'work_email': work_email}} def action_follow(self, cr, uid, ids, context=None): """ Wrapper because message_subscribe_users take a user_ids=None that receive the context without the wrapper. """ return self.message_subscribe_users(cr, uid, ids, context=context) def action_unfollow(self, cr, uid, ids, context=None): """ Wrapper because message_unsubscribe_users take a user_ids=None that receive the context without the wrapper. """ return self.message_unsubscribe_users(cr, uid, ids, context=context) def get_suggested_thread(self, cr, uid, removed_suggested_threads=None, context=None): """Show the suggestion of employees if display_employees_suggestions if the user perference allows it. """ user = self.pool.get('res.users').browse(cr, uid, uid, context) if not user.display_employees_suggestions: return [] else: return super(hr_employee, self).get_suggested_thread(cr, uid, removed_suggested_threads, context) def _message_get_auto_subscribe_fields(self, cr, uid, updated_fields, auto_follow_fields=None, context=None): """ Overwrite of the original method to always follow user_id field, even when not track_visibility so that a user will follow it's employee """ if auto_follow_fields is None: auto_follow_fields = ['user_id'] user_field_lst = [] for name, column_info in self._all_columns.items(): if name in auto_follow_fields and name in updated_fields and column_info.column._obj == 'res.users': user_field_lst.append(name) return user_field_lst def _check_recursion(self, cr, uid, ids, context=None): level = 100 while len(ids): cr.execute( 'SELECT DISTINCT parent_id FROM hr_employee WHERE id IN %s AND parent_id!=id', (tuple(ids), )) ids = filter(None, map(lambda x: x[0], cr.fetchall())) if not level: return False level -= 1 return True _constraints = [ (_check_recursion, 'Error! You cannot create recursive hierarchy of Employee(s).', ['parent_id']), ]
return {} def on_change_intervall(self, cr, uid, id, interval): ###Function that will update the cron ###freqeuence self.pool.get("currency.rate.update").save_cron(cr, uid, {"interval_type": interval}) compagnies = self.search(cr, uid, []) for comp in compagnies: self.write(cr, uid, comp, {"interval_type": interval}) return {} _inherit = "res.company" _columns = { ### activate the currency update "auto_currency_up": fields.boolean("Automatical update of the currency this company"), "services_to_use": fields.one2many("currency.rate.update.service", "company_id", "Currency update services"), ###predifine cron frequence "interval_type": fields.selection( [("days", "Day(s)"), ("weeks", "Week(s)"), ("months", "Month(s)")], "Currency update frequence", help="""changing this value will also affect other compagnies""", ), ###function field that allows to know the ###mutli company currency implementation "multi_company_currency_enable": fields.function( _multi_curr_enable, method=True, type="boolean", string="Multi company currency", help="if this case is not check you can" + " not set currency is active on two company",
class hr_department(osv.osv): _name = "hr.department" _description = "HR Department" _inherit = ['mail.thread', 'ir.needaction_mixin'] def _dept_name_get_fnc(self, cr, uid, ids, prop, unknow_none, context=None): res = self.name_get(cr, uid, ids, context=context) return dict(res) _columns = { 'name': fields.char('Department Name', required=True), 'complete_name': fields.function(_dept_name_get_fnc, type="char", string='Name'), 'company_id': fields.many2one('res.company', 'Company', select=True, required=False), 'parent_id': fields.many2one('hr.department', 'Parent Department', select=True), 'child_ids': fields.one2many('hr.department', 'parent_id', 'Child Departments'), 'manager_id': fields.many2one('hr.employee', 'Manager', track_visibility='onchange'), 'member_ids': fields.one2many('hr.employee', 'department_id', 'Members', readonly=True), 'jobs_ids': fields.one2many('hr.job', 'department_id', 'Jobs'), 'note': fields.text('Note'), } _defaults = { 'company_id': lambda self, cr, uid, c: self.pool.get('res.company'). _company_default_get(cr, uid, 'hr.department', context=c), } def _check_recursion(self, cr, uid, ids, context=None): if context is None: context = {} level = 100 while len(ids): cr.execute( 'select distinct parent_id from hr_department where id IN %s', (tuple(ids), )) ids = filter(None, map(lambda x: x[0], cr.fetchall())) if not level: return False level -= 1 return True _constraints = [ (_check_recursion, 'Error! You cannot create recursive departments.', ['parent_id']) ] def name_get(self, cr, uid, ids, context=None): if context is None: context = {} if not ids: return [] reads = self.read(cr, uid, ids, ['name', 'parent_id'], context=context) res = [] for record in reads: name = record['name'] if record['parent_id']: name = record['parent_id'][1] + ' / ' + name res.append((record['id'], name)) return res def create(self, cr, uid, vals, context=None): # TDE note: auto-subscription of manager done by hand, because currently # the tracking allows to track+subscribe fields linked to a res.user record # An update of the limited behavior should come, but not currently done. manager_id = vals.get("manager_id") new_id = super(hr_department, self).create(cr, uid, vals, context=context) if manager_id: employee = self.pool.get('hr.employee').browse(cr, uid, manager_id, context=context) if employee.user_id: self.message_subscribe_users(cr, uid, [new_id], user_ids=[employee.user_id.id], context=context) return new_id def write(self, cr, uid, ids, vals, context=None): # TDE note: auto-subscription of manager done by hand, because currently # the tracking allows to track+subscribe fields linked to a res.user record # An update of the limited behavior should come, but not currently done. if isinstance(ids, (int, long)): ids = [ids] manager_id = vals.get("manager_id") if manager_id: employee = self.pool.get('hr.employee').browse(cr, uid, manager_id, context=context) if employee.user_id: self.message_subscribe_users(cr, uid, [ids], user_ids=[employee.user_id.id], context=context) return super(hr_department, self).write(cr, uid, ids, vals, context=context)
'cc_charge':fields.boolean('Charge'), 'cc_info_hide':fields.boolean('Credit Info Hide'), 'cc_status':fields.text('Status Message'), 'cc_details_autofill':fields.boolean('Credit Card Details Auto Fill'), 'cc_reseller':fields.boolean('Reseller'), 'rel_sale_order_id':fields.many2one('sale.order', 'Related Sale Order'), 'cc_trans_id':fields.char('Transaction ID', size=128), 'cc_bank':fields.many2one('res.bank', 'Bank'), 'cc_details':fields.many2one('res.partner.bank', 'Bank'), 'cc_length':fields.integer('CC Length'), 'cc_transaction':fields.boolean('Transaction Done'), 'key':fields.char('Encryption Key', size=1024, help="The Key used to Encrypt the Credit Card Number"), 'cc_refund_amt':fields.float('Refund Amt'), 'is_charged': fields.boolean('CreditCard Charged'), 'trans_history_ids': fields.one2many('transaction.details', 'voucher_id', 'Transaction History') } _defaults = { 'cc_info_hide': lambda * a: True, 'cc_p_authorize': lambda * a: True, } def onchange_cc_details(self, cr, uid, ids, cc_details, context={}): dic = {} if cc_details: context['cc_no'] = 'no_mask' bank = self.pool.get('res.partner.bank').browse(cr, uid, cc_details, context=context) dic['cc_e_d_month'] = bank.cc_e_d_month dic['cc_e_d_year'] = bank.cc_e_d_year dic['cc_number'] = bank.cc_number dic['cc_v'] = bank.cc_v
class hr_job(osv.Model): def _get_nbr_employees(self, cr, uid, ids, name, args, context=None): res = {} for job in self.browse(cr, uid, ids, context=context): nb_employees = len(job.employee_ids or []) res[job.id] = { 'no_of_employee': nb_employees, 'expected_employees': nb_employees + job.no_of_recruitment, } return res def _get_job_position(self, cr, uid, ids, context=None): res = [] for employee in self.pool.get('hr.employee').browse(cr, uid, ids, context=context): if employee.job_id: res.append(employee.job_id.id) return res _name = "hr.job" _description = "Job Position" _inherit = ['mail.thread'] _columns = { 'name': fields.char('Job Name', required=True, select=True), 'expected_employees': fields.function( _get_nbr_employees, string='Total Forecasted Employees', help= 'Expected number of employees for this job position after new recruitment.', store={ 'hr.job': (lambda self, cr, uid, ids, c=None: ids, ['no_of_recruitment'], 10), 'hr.employee': (_get_job_position, ['job_id'], 10), }, type='integer', multi='_get_nbr_employees'), 'no_of_employee': fields.function( _get_nbr_employees, string="Current Number of Employees", help='Number of employees currently occupying this job position.', store={ 'hr.employee': (_get_job_position, ['job_id'], 10), }, type='integer', multi='_get_nbr_employees'), 'no_of_recruitment': fields.integer('Expected New Employees', copy=False, help='Number of new employees you expect to recruit.'), 'no_of_hired_employee': fields.integer( 'Hired Employees', copy=False, help= 'Number of hired employees for this job position during recruitment phase.' ), 'employee_ids': fields.one2many('hr.employee', 'job_id', 'Employees', groups='base.group_user'), 'description': fields.text('Job Description'), 'requirements': fields.text('Requirements'), 'department_id': fields.many2one('hr.department', 'Department'), 'company_id': fields.many2one('res.company', 'Company'), 'state': fields.selection( [('open', 'Recruitment Closed'), ('recruit', 'Recruitment in Progress')], string='Status', readonly=True, required=True, track_visibility='always', copy=False, help= "By default 'Closed', set it to 'In Recruitment' if recruitment process is going on for this job position." ), 'write_date': fields.datetime('Update Date', readonly=True), } _defaults = { 'company_id': lambda self, cr, uid, ctx=None: self.pool.get('res.company'). _company_default_get(cr, uid, 'hr.job', context=ctx), 'state': 'open', } _sql_constraints = [ ('name_company_uniq', 'unique(name, company_id, department_id)', 'The name of the job position must be unique per department in company!' ), ('hired_employee_check', "CHECK ( no_of_hired_employee <= no_of_recruitment )", "Number of hired employee must be less than expected number of employee in recruitment." ), ] def set_recruit(self, cr, uid, ids, context=None): for job in self.browse(cr, uid, ids, context=context): no_of_recruitment = job.no_of_recruitment == 0 and 1 or job.no_of_recruitment self.write(cr, uid, [job.id], { 'state': 'recruit', 'no_of_recruitment': no_of_recruitment }, context=context) return True def set_open(self, cr, uid, ids, context=None): self.write(cr, uid, ids, { 'state': 'open', 'no_of_recruitment': 0, 'no_of_hired_employee': 0 }, context=context) return True def copy(self, cr, uid, id, default=None, context=None): if default is None: default = {} if 'name' not in default: job = self.browse(cr, uid, id, context=context) default['name'] = _("%s (copy)") % (job.name) return super(hr_job, self).copy(cr, uid, id, default=default, context=context) # ---------------------------------------- # Compatibility methods # ---------------------------------------- _no_of_employee = _get_nbr_employees # v7 compatibility job_open = set_open # v7 compatibility job_recruitment = set_recruit # v7 compatibility
kail.write({'reason':e}) done = False if done: kai.write({'state':'done'}) pass IMPORT_TYPE = (('lq','Liquidation'),('usage','Usage'),('spec','Specification')) _columns={ 'name':fields.date("Import Date", states={'done':[('readonly',True)]}, required=True), 'remarks':fields.char('Remarks',size=256, states={'done':[('readonly',True)]}), 'state':fields.selection((('draft','Draft'),('done','Completed')),'State',readonly=True), 'detail_ids':fields.one2many('kderp.import.asset.detail','import_id','Details',states={'done':[('readonly',True)]}), 'detail_spec_ids':fields.one2many('kderp.import.asset.detail','import_id','Details',states={'done':[('readonly',True)]}), 'detail_usage_ids':fields.one2many('kderp.import.asset.detail','import_id','Details',states={'done':[('readonly',True)]}), 'import_type':fields.selection(IMPORT_TYPE,'Import type',states={'done':[('readonly',True)]}), } _defaults={ 'name':lambda *a: time.strftime('%Y-%m-%d'), 'state':lambda *a: 'draft' } kderp_asset_import() class kderp_import_asset_detail(Model): _name = 'kderp.import.asset.detail' _rec_name = 'asset_id'
class ElectricComponent(electric_component_base): _inherit = 'component.component' _description = 'Components' def electric_info(self, cr, uid, ids, field_name, arg, context=None): return super(ElectricComponent, self).electric_info(cr, uid, ids, field_name, arg, context=context) # def _electric_info(self, cr, uid, ids, field_name, arg, context=None): # res = dict.fromkeys(ids, "") # for component in self.browse(cr, uid, ids, context=context): # cmodel = self.pool[component.component_model] # for c in cmodel.browse(cr, uid, [('delegated_id' in ids)], context=context): # if 'component_info' in c: # res[c.delegated_id] = c.component_info; # return res; def _get_attachment_number(self, cr, uid, ids, field_name, arg, context=None): res = dict.fromkeys(ids, 0) return res def _test_count(self, cr, uid, ids, field_name, arg, context=None): res = dict.fromkeys(ids, 0) for component in self.browse(cr, uid, ids, context=context): if component.component_model_test in self.pool: if 'delegated_id' in component: def_id = component.id else: true_components = self.pool[component.component_model] def_id = true_components.search(cr, uid, [('delegated_id', '=', component.id)], limit=1) count = self.pool[component.component_model_test].search_count(cr, uid, [('component_id',"=",def_id)], context); res[component.id] = count return res def _get_attachment_number(self, cr, uid, ids, field_name, arg, context=None): res = dict.fromkeys(ids, 0) component_docs = self.pool['ir.attachment'] for docs in component_docs.read_group(cr, uid, [('res_model', '=', 'component.component'), ('res_id', 'in', ids)], ['res_id'], ['res_id'], context): res[docs['res_id']] = component_docs.search_count(cr,uid, [('res_id', '=', docs['res_id'])], context=context) return res def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False, submenu=False): result = super(ElectricComponent, self).fields_view_get(cr, uid, view_id, view_type, context, toolbar, submenu) return result _columns = { 'electric_info': fields.function(electric_info, 'Information', type='char'), 'customer_id': fields.many2one('res.partner', 'Customer'), 'component_model': fields.char('Component Model'), 'component_model_test': fields.char('Component Model Test'), 'test_count': fields.function(_test_count, string='Test Sheets', type='integer'), 'attachment_number': fields.function(_get_attachment_number, string="Documents Attached", type="integer"), 'attachment_ids': fields.one2many('ir.attachment', 'res_id', domain=[('res_model', '=', 'component.component')], string='Attachments') } @api.model def create(self, values): # values = self._test_image_small(values) return super(ElectricComponent, self).create(values) @api.multi def write(self, vals): # self._test_image_small(vals) res = super(ElectricComponent, self).write(vals) return res def can_create(self): return self.electric_component_type != 'all_components' _defaults = { 'electric_component_type': 'all_components', } def unlink(self, cr, uid, ids, context=None): for component in self.browse(cr, uid, ids, context=context): if not('delegated_id' in component): true_components = self.pool[component.component_model] def_id = true_components.search(cr, uid, [('delegated_id', '=', component.id)], limit=1) self.pool[component.component_model].unlink(cr, uid, def_id, context=context) return super(ElectricComponent, self).unlink(cr, uid, ids, context)
_description = "Import Inventory" def _default_location(self, cr, uid, ids, context=None): try: loc_model, location_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'stock', 'stock_location_stock') except ValueError, e: return False return location_id or False _columns = { 'location_id': fields.many2one('stock.location', 'Location', required=True), 'import_file': fields.binary('File', filters="*.xls"), #to consider the product current inventory or not, if yes then add the current inventory to the upload excel quantity as the quantity to do physical inventory 'consider_inventory': fields.boolean('Consider Current Inventory', select=True), 'all_done': fields.boolean('All Data Imported', readonly=True, select=True), 'result_line': fields.one2many('stock.import.inventory.result', 'import_id', 'Importing Result', readonly=True), 'file_template': fields.binary('Template File', readonly=True), 'file_template_name': fields.char('Template File Name'), } def _get_template(self, cr, uid, context): cur_path = os.path.split(os.path.realpath(__file__))[0] path = os.path.join(cur_path,'stock_import_template.xls') data = open(path,'rb').read().encode('base64') # data = os.path.getsize(path) return data _defaults = { 'location_id': _default_location, 'file_template': _get_template, 'file_template_name': 'stock_import_template.xls'
class periodic_inventory_valuation(osv.osv): _name = "periodic.inventory.valuation" _description = "Periodic Inventory Valuation" _columns = { 'name': fields.char('Name', size=64, required=True, help=""), 'move_id': fields.many2one( 'account.move', 'Journal Entry', help= 'Journal Entry For this Periodic Inventory Valuation Document, it will be created when Document is Posted' ), 'company_id': fields.many2one('res.company', 'Company', help='Company for this Document'), 'period_id': fields.many2one( 'account.period', 'Period', help= 'Accounting Period to be used when creating Journal Entries and Accounting Entries' ), 'inventory_valuation_journal_id': fields.many2one( 'account.journal', 'Journal', help= 'Accounting Journal to be used when creating Journal Entries and Accounting Entries' ), 'currency_id': fields.many2one( 'res.currency', 'Currency', help= 'Currency to be used when creating Journal Entries and Accounting Entries' ), 'date': fields.date( 'Valuation Date', help= 'Date to be used when creating Journal Entries and Accounting Entries' ), 'state': fields.selection([('draft', 'Readying Valuation'), ('confirm', 'Ready to Valuate'), ('done', 'Valuated Inventory')]), 'product_ids': fields.many2many('product.product', 'piv_prod_rel', 'product_id', 'piv_id', 'Valuating Products', help='Products to be Valuated'), 'stock_move_ids': fields.many2many('stock.move', 'piv_sm_rel', 'stock_move_id', 'piv_id', 'Stock Moves', help='Stock Moves to be used as Control Sample'), 'ail_ids': fields.many2many( 'account.invoice.line', 'piv_ail_rel', 'ail_id', 'piv_id', 'Account Invoice Lines', help='Account Invoice Lines to be used to Valuate Inventory'), 'aml_ids': fields.many2many( 'account.move.line', 'piv_aml_rel', 'aml_id', 'piv_id', 'Account Move Lines', help='Account Move Lines to be Created to Valuate Inventory'), 'pivl_ids': fields.one2many( 'periodic.inventory.valuation.line', 'piv_id', 'Periodic Inventory Valuation Lines', help= 'Periodic Inventory Valuation Lines created to valuate Inventory'), 'first': fields.boolean('First run'), } _defaults = { 'state': 'draft', 'company_id': lambda s, c, u, ctx: s.pool.get('res.users').browse( c, u, u, context=ctx).company_id.id, 'first': False, 'currency_id': lambda s, c, u, ctx: s.pool.get('res.users').browse( c, u, u, context=ctx).company_id.currency_id.id, 'inventory_valuation_journal_id': lambda s, c, u, ctx: s.pool.get('res.users').browse( c, u, u, context=ctx).company_id.inventory_valuation_journal_id.id, } def get_period(self, cr, uid, ids, date, context=None): if context is None: context = {} period_obj = self.pool.get('account.period') period_ids = period_obj.find(cr, uid, dt=date, context=context) period_ids = period_obj.search(cr, uid, [('id', 'in', period_ids), ('special', '=', False)], context=context) period_ids = period_ids and period_ids[0] or False if not period_ids: raise osv.except_osv( _('Error!'), _('There is no fiscal year defined for this date.\nPlease create one from the configuration of the accounting menu.' )) return period_ids def exchange(self, cr, uid, ids, from_amount, to_currency_id, from_currency_id, exchange_date, context=None): if context is None: context = {} if from_currency_id == to_currency_id: return from_amount curr_obj = self.pool.get('res.currency') context['date'] = exchange_date return curr_obj.compute(cr, uid, from_currency_id, to_currency_id, from_amount, context=context) def validate_data(self, cr, uid, ids, date, context=None): if context is None: context = {} if ids: if type(ids) is list: peri_inv_allowed = self.search(cr, uid, [('id', '!=', ids[0])], order='id desc', limit=1, context=context) else: peri_inv_allowed = self.search(cr, uid, [('id', '!=', ids)], order='id desc', limit=1, context=context) else: peri_inv_allowed = self.search(cr, uid, [], order='id desc', limit=1, context=context) all_per_inv = self.browse(cr, uid, peri_inv_allowed, context=context) #$$$ for i in all_per_inv: if date <= i.date: raise osv.except_osv( 'Record with this data existing !', 'Can not create a record with repeated date') return True def write(self, cr, uid, ids, vals, context=None): if context is None: context = {} if type(ids) is list: brw_per_inv = self.browse(cr, uid, ids[0], context=context) else: brw_per_inv = self.browse(cr, uid, ids, context=context) if brw_per_inv.state == 'done': raise osv.except_osv('Can not write the record', 'When a stock is done, can not be write') self.validate_data(cr, uid, ids, brw_per_inv.date, context=context) vals['period_id'] = self.get_period(cr, uid, ids, vals.get('date'), context=context) return super(periodic_inventory_valuation, self).write(cr, uid, ids, vals, context=context) def create(self, cr, uid, vals, context=None): if context is None: context = {} inv = self.pool.get('res.users').browse( cr, uid, uid, context=context).company_id.inventory_valuation_journal_id if not inv.id: raise osv.except_osv( 'You need to define the journal', 'Must be defined in the company the journal to generate the journal items for periodic inventory' ) self.validate_data(cr, uid, False, vals.get('date'), context=context) vals['period_id'] = self.get_period(cr, uid, False, vals.get('date'), context=context) return super(periodic_inventory_valuation, self).create(cr, uid, vals, context=context) def unlink(self, cr, uid, ids, context=None): if context is None: context = {} brw_per_inv = self.browse(cr, uid, ids[0], context=context) if brw_per_inv.state == 'done': raise osv.except_osv('Can not delete the record', 'When a stock is done, can not be deleted') return super(periodic_inventory_valuation, self).unlink(cr, uid, ids, context=context) def load_valuation_items(self, cr, uid, ids, context=None): context = context or {} ids = isinstance(ids, (int, long)) and [ids] or ids prod_obj = self.pool.get('product.product') prod_ids = prod_obj.search(cr, uid, [ ('type', '=', 'product'), ('valuation', '=', 'manual_periodic'), ], context=context) period_obj = self.pool.get('account.period') piv_brw = self.browse(cr, uid, ids[0], context=context) date = piv_brw.date company_id = piv_brw.company_id.id currency_id = piv_brw.currency_id.id inventory_valuation_journal_id = piv_brw.company_id.inventory_valuation_journal_id.id period_id = piv_brw.period_id.id inv_obj = self.pool.get('account.invoice') # Se obtiene la linea del producto del registro anterior if type(ids) is list: piv_id = self.search(cr, uid, [('id', '!=', ids[0]), ('state', '=', 'done')], order='id desc', limit=1, context=context) else: piv_id = self.search(cr, uid, [('id', '!=', ids), ('state', '=', 'done')], order='id desc', limit=1, context=context) piv = self.browse(cr, uid, ids[0], context=context) fecha_now = datetime.datetime.strptime(piv.date, '%Y-%m-%d') if piv_id: piv_id = piv_id[0] piv_before = self.browse(cr, uid, piv_id, context=context) fecha_before = datetime.datetime.strptime(piv_before.date, '%Y-%m-%d') else: fecha_before = False inv_ids = [] if fecha_before: inv_ids = inv_obj.search(cr, uid, [('state', 'in', ('open', 'paid')), ('date_invoice', '>', fecha_before), ('date_invoice', '<=', fecha_now), ('company_id', '=', company_id)], context=context) else: inv_ids = inv_obj.search(cr, uid, [('state', 'in', ('open', 'paid')), ('date_invoice', '<=', fecha_now), ('company_id', '=', company_id)], context=context) if not inv_ids: raise osv.except_osv( _('Error!'), _('There are no invoices defined for this period.\nMake sure you are using the right date.' )) ail_obj = self.pool.get('account.invoice.line') ail_ids = ail_obj.search(cr, uid, [('invoice_id', 'in', inv_ids), ('product_id', 'in', prod_ids)], context=context) if not ail_ids: raise osv.except_osv( _('Error!'), _('There are no invoices lines defined for this period.\nMake sure you are using the right date.' )) period_brw = period_obj.browse(cr, uid, period_id, context=context) date_start = period_brw.date_start date_stop = period_brw.date_stop sl_obj = self.pool.get('stock.location') int_sl_ids = sl_obj.search(cr, uid, [('usage', '=', 'internal')], context=context) ext_sl_ids = sl_obj.search(cr, uid, [('usage', '!=', 'internal')], context=context) sm_obj = self.pool.get('stock.move') incoming_sm_ids = sm_obj.search( cr, uid, [ ('state', '=', 'done'), ('company_id', '=', company_id), ('location_id', 'in', ext_sl_ids), ('location_dest_id', 'in', int_sl_ids), ('date', '>=', date_start), ('date', '<=', date_stop), ], context=context) outgoing_sm_ids = sm_obj.search( cr, uid, [ ('state', '=', 'done'), ('company_id', '=', company_id), ('location_id', 'in', int_sl_ids), ('location_dest_id', 'in', ext_sl_ids), ('date', '>=', date_start), ('date', '<=', date_stop), ], context=context) # Se establecen parametros para usar en los calculos periodic_line = self.pool.get('periodic.inventory.valuation.line') lineas = [] move_id = False state = 'draft' # Si no se han hecho calculos, se cargan datos iniciales, aqui la condicion deberia ser si el estado es draft # Se debe validar que si es el primer registro cargar datos en 0, si no es el primer registro entonces tomar # valores del ultimo registro if not piv.first: state = 'confirm' pivline_init_ids = [] # Se itera sobre los productos que sean de tipo producto y con valuation tipo manual_periodic for prod_id in prod_ids: prod = prod_obj.browse(cr, uid, prod_id, context=context) piv_line_id = False if piv_id: piv_line_id = periodic_line.search( cr, uid, [('piv_id', '=', piv_id), ('product_id', '=', prod_id)], context=context) # condicional aqui de piv_line_brw, puede que no exista if piv_line_id: piv_line_brw = periodic_line.browse(cr, uid, piv_line_id, context=context)[0] line_qty_init = piv_line_brw.qty_final line_average_cost = piv_line_brw.average_cost line_valuation = piv_line_brw.valuation else: line_qty_init = 0.0 line_average_cost = 0.0 line_valuation = 0.0 # Guardar informacion de la linea piv a crear en el registro actual pivline_init_ids.append( periodic_line.create(cr, uid, { 'piv_id': ids[0], 'product_id': prod_id, 'qty_init': line_qty_init, 'qty_final': 0.0, 'qty_sale': 0.0, 'qty_purchase': 0.0, 'uom_id': prod.uom_id.id, 'average_cost': line_average_cost, 'valuation': line_valuation, }, context=context)) # Cargar lineas nuevas en el registro actual self.write(cr, uid, ids[0], { 'pivl_ids': [(6, 0, pivline_init_ids)], }, context=context) else: state = 'done' product_price_purs = {} product_price_sales = {} # Se iteran que esten pagadas o abiertas y que esten dentro del periodo al que corresponde # la fecha actual product_price = [] for ail_id in ail_ids: ail = ail_obj.browse(cr, uid, ail_id, context=context) # si la factura se relaciona a la lista de productos que se filtraron if ail.product_id.id in prod_ids: produc_obj = prod_obj.browse(cr, uid, ail.product_id.id, context=context) price_unit = self.exchange(cr, uid, ids, ail.price_unit, ail.invoice_id.currency_id.id, currency_id, date, context=context) if ail.invoice_id.type == 'in_invoice': p_p_pur = {'qty': ail.quantity, 'price': price_unit} if product_price_purs.get(ail.product_id.id, False): product_price_purs[ail.product_id.id].append( p_p_pur) else: product_price_purs[ail.product_id.id] = [p_p_pur] elif ail.invoice_id.type == 'out_invoice': p_p_sale = {'qty': ail.quantity, 'price': price_unit} if product_price_sales.get(ail.product_id.id, False): product_price_sales[ail.product_id.id].append( p_p_sale) else: product_price_sales[ail.product_id.id] = [p_p_sale] else: print ail.invoice_id.type product_price.append(ail.product_id.id) lineas = [] for i in prod_ids: prod = prod_obj.browse(cr, uid, i, context=context) val_line_ids = periodic_line.search(cr, uid, [('product_id', '=', i), ('piv_id', '=', ids[0])], context=context) val_line = periodic_line.browse(cr, uid, val_line_ids, context=context)[0] #~~~~~~~~~~~ qty_pur = 0 costo = 0.0 qty_sale = 0 # Si el producto fue parte de una compra if product_price_purs.get(i, False): for j in product_price_purs[i]: costo += j.get('qty') * j.get('price') qty_pur += j.get('qty') # Si el producto fue parte de una venta if product_price_sales.get(i, False): for k in product_price_sales[i]: #inventario_final -= k.get('qty') qty_sale += k.get('qty') inventario_final = val_line.qty_init + qty_pur - qty_sale costo += val_line.valuation qty = val_line.qty_init + qty_pur # este val_line.init es el final de la linea anterior if qty == 0: costo_promedio = 0 else: costo_promedio = round(costo / qty, 2) valuation = (val_line.valuation) + ( qty_pur * costo_promedio) - (qty_sale * costo_promedio) # ~~~~~~~~~~~ # Algo pasa con prod.property_account_expense y prod.property_account_income # Establezco los diarios para hacer los asientos # Product valuation and journal item amount journal_item = valuation - val_line.valuation debit = journal_item > 0 and journal_item or 0.0 credit = journal_item < 0 and (journal_item * -1) or 0.0 if journal_item != 0: if prod.property_account_expense: account_expense = prod.property_account_expense else: account_expense = prod.product_tmpl_id.categ_id.property_account_expense_categ account_income = prod.product_tmpl_id.categ_id.property_stock_valuation_account_id if not account_expense or not account_income: raise osv.except_osv( _('Error!'), _('Product Account.\nThere are no accounts defined for the product %s.' % (prod.name))) context['journal_id'] = inventory_valuation_journal_id context['period_id'] = period_id move_line = { 'name': 'GANANCIA O PERDIDA DE INVENTARIO', 'partner_id': False, 'product_id': prod.id, 'account_id': account_income.id, 'move_id': False, 'journal_id': inventory_valuation_journal_id, 'period_id': period_id, 'date': date_stop, 'debit': debit, 'credit': credit, } line_id = self.pool.get('account.move.line').create( cr, uid, move_line, context=context) lineas.append(line_id) move_line['account_id'] = account_expense.id move_line['debit'] = credit move_line['credit'] = debit line_id = self.pool.get('account.move.line').create( cr, uid, move_line, context=context) lineas.append(line_id) periodic_line.write( cr, uid, val_line.id, { 'average_cost': costo_promedio, 'valuation': valuation, 'qty_sale': qty_sale, 'qty_purchase': qty_pur, 'qty_final': inventario_final, }) ############################################################## if lineas: move_id = self.pool.get('account.move.line').browse( cr, uid, lineas[0], context=context).move_id.id else: move_id = False self.write( cr, uid, ids[0], { 'product_ids': [(6, 0, prod_ids)], 'ail_ids': [(6, 0, ail_ids)], 'date': date or fields.date.today(), 'stock_move_ids': [(6, 0, incoming_sm_ids + outgoing_sm_ids)], 'first': True, 'aml_ids': [(6, 0, lineas)], 'move_id': move_id, 'state': state, }, context=context) return True
_logger.info("Carrier %s: %s", carrier.name, e.name) price = 0.0 else: price = 0.0 res[carrier.id] = { 'price': price, 'available': available } return res _columns = { 'name': fields.char('Delivery Method', required=True, translate=True), 'sequence': fields.integer('Sequence', help="Determine the display order"), 'partner_id': fields.many2one('res.partner', 'Transport Company', required=True, help="The partner that is doing the delivery service."), 'product_id': fields.many2one('product.product', 'Delivery Product', required=True), 'grids_id': fields.one2many('delivery.grid', 'carrier_id', 'Delivery Grids'), 'available' : fields.function(get_price, string='Available',type='boolean', multi='price', help="Is the carrier method possible with the current order."), 'price' : fields.function(get_price, string='Price', multi='price'), 'active': fields.boolean('Active', help="If the active field is set to False, it will allow you to hide the delivery carrier without removing it."), 'normal_price': fields.float('Normal Price', help="Keep empty if the pricing depends on the advanced pricing per destination"), 'free_if_more_than': fields.boolean('Free If Order Total Amount Is More Than', help="If the order is more expensive than a certain amount, the customer can benefit from a free shipping"), 'amount': fields.float('Amount', help="Amount of the order to benefit from a free shipping, expressed in the company currency"), 'use_detailed_pricelist': fields.boolean('Advanced Pricing per Destination', help="Check this box if you want to manage delivery prices that depends on the destination, the weight, the total of the order, etc."), 'pricelist_ids': fields.one2many('delivery.grid', 'carrier_id', 'Advanced Pricing'), } _defaults = { 'active': 1, 'free_if_more_than': False, 'sequence': 10,
class create_purchase_requestion(osv.osv_memory): """ class to manage the wizard of creating the purchase requestion """ _description='create purchase requestion' _name = 'create.purchase.requestion' _columns = { 'srock_exchange': fields.many2one('exchange.order', 'Stock Exchange', readonly=True), 'current_date': fields.date('Current Date', readonly=True), 'products_ids':fields.one2many('create.purchase.requestion.products', 'wizard_id' , 'Products'), } _defaults = { #'srock_exchange':lambda cr,uid,ids,context:context['active_id'] or False, 'current_date': lambda *a: time.strftime('%Y-%m-%d'), } def default_get(self, cr, uid, fields, context=None): """ To get default values for the object. @return: A dictionary which of fields with values. """ if context is None: context = {} exchang_obj = self.pool.get('exchange.order') res ={} exchang_ids = context.get('active_ids', []) if not exchang_ids: return res result = [] for req in exchang_obj.browse(cr, uid, exchang_ids, context=context): for product in req.order_line: result.append(self.__create_products(product)) res.update({'products_ids': result}) if 'current_date' in fields: res.update({'current_date': time.strftime('%Y-%m-%d %H:%M:%S')}) return res def __create_products(self, product): product_memory = { 'product_id' : product.product_id.id, 'product_qty':product.product_qty, 'stock_exchange_line' : product.id, 'description': product.notes, } return product_memory def create_purchase_requestion(self, cr, uid, ids, context=None): #TODO change the state of the purchase requestion to quotes and let the wizard in specefic state """ Button function to create purchase requestion from the @return: Purchase Requestion Id """ purchase_requestion_obj = self.pool.get('ireq.m') exchange = self.pool.get('exchange.order').browse(cr, uid, context['active_id']) requestion_lines_obj = self.pool.get('ireq.products') prod = self.pool.get('product.product') wf_service = netsvc.LocalService("workflow") if exchange.purchase_requestion_id: raise osv.except_osv(_('Warning'), _('You allredy create a purchase requestion for this exchange order ')) for wizard in self.browse(cr, uid, ids): requestion_id = purchase_requestion_obj.create(cr, uid, {'company_id': exchange.company_id.id, 'user': context['uid'], 'cat_id':exchange.category_id.id or False, 'ir_ref': exchange.name, 'department_id' : exchange.department_id.id, 'exchane_order_id':[(4, exchange.id)],}) for wizard_lines in wizard.products_ids: product = prod.browse(cr, uid,wizard_lines.product_id.id) requestion_lines_obj.create(cr, uid, {'pr_rq_id':requestion_id, 'product_id': wizard_lines.product_id.id, 'name': product.name, 'product_qty': wizard_lines.product_qty, 'product_uom': product.uom_po_id.id, 'desc': wizard_lines.description,}) exchange.write({'purchase_requestion_id':requestion_id , 'state' : 'wait_purchase' }) wf_service.trg_validate(uid, 'ireq.m', requestion_id, 'draft', cr) return requestion_id
cr, uid, save_cron ) return super(res_company, self).write(cr, uid, ids, vals, context=context) _inherit = "res.company" _columns = { ### activate the currency update 'auto_currency_up': fields.boolean('Automatical update of the currency this company'), 'services_to_use' : fields.one2many( 'currency.rate.update.service', 'company_id', 'Currency update services' ), ###predifine cron frequence 'interval_type': fields.selection( [ ('days','Day(s)'), ('weeks', 'Week(s)'), ('months', 'Month(s)') ], 'Currency update frequence', help="""changing this value will also affect other compagnies""" ), ###function field that allows to know the ###mutli company currency implementation
class dym_penyerahan_bpkb(osv.osv): _name = "dym.penyerahan.bpkb" def _get_default_branch(self,cr,uid,ids,context=None): user_obj = self.pool.get('res.users') user = user_obj.browse(cr,uid,uid) if user.branch_type!='HO': if not user.branch_id: return False return user.branch_id.id else: return False @api.depends('penyerahan_line.name') def _amount_all(self): for ib in self: amount_total = 0.0 for line in ib.penyerahan_line: ib.update({ 'total_record': len(ib.penyerahan_line), }) _columns = { 'name': fields.char('No Reference', readonly=True), 'branch_id': fields.many2one('dym.branch', string='Branch', required=True), 'division':fields.selection([('Unit','Showroom')], 'Division', change_default=True, select=True), 'penerima':fields.char('Penerima'), 'partner_id':fields.many2one('res.partner','Customer'), 'partner_cabang': fields.many2one('dym.cabang.partner',string='Customer Branch'), 'keterangan':fields.char('Keterangan'), 'tanggal':fields.date('Tanggal'), 'penyerahan_line' : fields.one2many('dym.penyerahan.bpkb.line','penyerahan_id',string="Penyerahan STNK"), 'state': fields.selection([('draft', 'Draft'), ('posted','Posted'),('cancel','Canceled')], 'State', readonly=True), 'engine_no': fields.related('penyerahan_line', 'name', type='char', string='No Engine'), 'customer_stnk': fields.related('penyerahan_line', 'customer_stnk', type='many2one', relation='res.partner', string='Customer STNK', help=' Syarat Penyerahan BKPB: \ \n* Semua tagihan harus sudah lunas (termasuk pajak progresif). \ \n* Sudah proses STNK. \ \n* Sudah terima BPKB'), 'no_bpkb': fields.related('penyerahan_line', 'no_bpkb', type='char', string='No BPKB'), 'tgl_penyerahan_bpkb' :fields.date('Tgl Penyerahan BPKB'), 'cetak_ke' : fields.integer('Cetak Ke'), 'confirm_uid':fields.many2one('res.users',string="Posted by"), 'confirm_date':fields.datetime('Posted on'), 'total_record' : fields.integer(string='Total Engine', store=True, readonly=True, compute='_amount_all'), } _defaults = { 'state':'draft', 'division' : 'Unit', 'tanggal': fields.date.context_today, 'tgl_penyerahan_bpkb': fields.date.context_today, 'cetak_ke' : 0, 'branch_id': _get_default_branch, } def post_penyerahan(self,cr,uid,ids,context=None): val = self.browse(cr,uid,ids) lot_pool = self.pool.get('stock.production.lot') tanggal = datetime.now() for x in val.penyerahan_line : lot_search = lot_pool.search(cr,uid,[ ('id','=',x.name.id) ]) lot_browse = lot_pool.browse(cr,uid,lot_search) lot_browse.write({ 'tgl_penyerahan_bpkb':x.tgl_ambil_bpkb, 'lokasi_bpkb_id':False, }) self.write(cr, uid, ids, {'state': 'posted','tanggal':tanggal,'confirm_uid':uid,'confirm_date':datetime.now()}) return True def create(self, cr, uid, vals, context=None): # if not vals['penyerahan_line'] : # raise osv.except_osv(('Perhatian !'), ("Tidak ada detail penyerahan. Data tidak bisa di save.")) lot_penyerahan = [] for x in vals['penyerahan_line']: lot_penyerahan.append(x.pop(2)) lot_pool = self.pool.get('stock.production.lot') penyerahan_pool = self.pool.get('dym.penyerahan.bpkb.line') vals['name'] = self.pool.get('ir.sequence').get_per_branch(cr, uid, vals['branch_id'], 'PBK', division='Unit') vals['tanggal'] = time.strftime('%Y-%m-%d'), del[vals['penyerahan_line']] penyerahan_id = super(dym_penyerahan_bpkb, self).create(cr, uid, vals, context=context) if penyerahan_id : for x in lot_penyerahan : lot_search = lot_pool.search(cr,uid,[ ('id','=',x['name']) ]) if not lot_search : raise osv.except_osv(('Perhatian !'), ("No Engine tidak ditemukan !")) lot_browse = lot_pool.browse(cr,uid,lot_search) lot_browse.write({ 'penyerahan_bpkb_id':penyerahan_id, }) penyerahan_pool.create(cr, uid, { 'name':lot_browse.id, 'penyerahan_id':penyerahan_id, 'customer_stnk':lot_browse.customer_stnk.id, 'no_bpkb':lot_browse.no_bpkb, 'no_urut':lot_browse.no_urut_bpkb, 'tgl_ambil_bpkb':x['tgl_ambil_bpkb'] }) else : return False return penyerahan_id def write(self, cr, uid, ids, vals, context=None): if context is None: context = {} vals.get('penyerahan_line',[]).sort(reverse=True) collect = self.browse(cr,uid,ids) lot_penyerahan = [] lot_pool = self.pool.get('stock.production.lot') line_pool = self.pool.get('dym.penyerahan.bpkb.line') lot = vals.get('penyerahan_line', False) if lot : for x,item in enumerate(lot) : lot_id = item[1] if item[0] == 2 : line_search = line_pool.search(cr,uid,[ ('id','=',lot_id) ]) line_browse = line_pool.browse(cr,uid,line_search) lot_search = lot_pool.search(cr,uid,[ ('id','=',line_browse.name.id) ]) if not line_search : raise osv.except_osv(('Perhatian !'), ("Nomor Engine tidak ada didalam daftar Penerimaan Line")) if not lot_search : raise osv.except_osv(('Perhatian !'), ("Nomor Engine tidak ada didalam daftar Engine Nomor")) lot_browse = lot_pool.browse(cr,uid,lot_search) # del[vals['penyerahan_line']] lot_browse.write({ 'penyerahan_bpkb_id':False, 'tgl_penyerahan_bpkb':False }) # line_pool.unlink(cr,uid,lot_id, context=context) elif item[0] == 0 : values = item[2] lot_search = lot_pool.search(cr,uid,[ ('id','=',values['name']) ]) if not lot_search : raise osv.except_osv(('Perhatian !'), ("Nomor Engine tidak ada didalam daftar Engine Nomor")) lot_browse = lot_pool.browse(cr,uid,lot_search) lot_browse.write({ 'penyerahan_bpkb_id':collect.id, }) return super(dym_penyerahan_bpkb, self).write(cr, uid, ids, vals, context=context) def unlink(self, cr, uid, ids, context=None): for item in self.browse(cr, uid, ids, context=context): if item.state != 'draft': raise osv.except_osv(('Perhatian !'), ("Penyerahan BPKB sudah di post ! tidak bisa didelete !")) lot_pool = self.pool.get('stock.production.lot') lot_search = lot_pool.search(cr,uid,[ ('penyerahan_bpkb_id','=',ids) ]) lot_browse = lot_pool.browse(cr,uid,lot_search) for x in lot_browse : x.write({ 'tgl_penyerahan_bpkb':False, }) return super(dym_penyerahan_bpkb, self).unlink(cr, uid, ids, context=context) def onchange_partner(self,cr,uid,ids,partner,penerima,context=None): warning = {} value = {} result = {} obj_browse = self.pool.get('res.partner').browse(cr,uid,[partner]) if partner: res_partner = self.pool.get('res.partner').search(cr,uid,[ ('id','=',partner) ]) res_partner_browse = self.pool.get('res.partner').browse(cr,uid,res_partner) if obj_browse.finance_company : value = {'penerima':res_partner_browse.name} if partner and penerima : if obj_browse.finance_company and penerima != obj_browse.name: warning = { 'title': ('Perhatian !'), 'message': ('A/N BPKB adalah Finance Company, Nama Penerima harus sama'), } if warning : value = {'penerima':False} result['value'] = value result['warning'] = warning return result def onchange_branch(self, cr, uid, ids, branch_id, context=None): warning = {} domain = {} value = {} result = {} if branch_id: branch = self.pool.get('dym.branch').browse(cr,uid,[branch_id]) domain_lot = ['&','&','&','&',('tgl_proses_birojasa','!=',False),('tgl_terima_bpkb','!=',False),('state_stnk','=','proses_stnk'),('branch_id','=',branch_id),('tgl_penyerahan_bpkb','=',False),'|',('finco_id','!=',False),'&',('customer_id','!=',False),('finco_id','=',False)] lot_ids = self.pool.get('stock.production.lot').search(cr, uid, domain_lot) lot = self.pool.get('stock.production.lot').browse(cr, uid, lot_ids) finco = lot.mapped('finco_id') partner = lot.filtered(lambda r: not r.finco_id).mapped('customer_id') domain['partner_id'] = ['|',('id','in',finco.ids),('id','in',partner.ids)] result['domain'] = domain result['value'] = value result['warning'] = warning return result
raise orm.except_orm('Error', 'Failure creating the' ' account move lines.') else: logging.getLogger(self._name).info("Este activo ya esta asentado!") _columns = { 'asset_code': fields.char('Codigo', size=32, required=False, readonly=False), 'category_id': fields.many2one('account.asset.category', 'Asset Category', required=True, change_default=True, readonly=True, states={'draft':[('readonly',False)]}, domain=[('type','=','normal')]), 'category_parent_id': fields.many2one("account.asset.category", string="Categoria Padre del Activo", required=False, readonly=True, states={'draft':[('readonly',False)]}, domain=[('type','=','view')] ), 'account_analytic_id': fields.many2one("account.analytic.account", string="Cuenta analitica", required=True, domain=[('type','=','normal')]), 'asset_move_ids': fields.one2many('account.asset.move', 'asset_id','Movimientos'), #'asset_move_ids': fields.one2many('account.asset.move', 'asset_id', 'Movements') } _defaults = { 'asset_code': lambda obj, cr, uid, context: obj.pool.get('ir.sequence').get(cr, uid, 'asset.number') } class AssetMove(orm.Model): _name = 'account.asset.move' _description = 'Movimiento de Activo Fijo' READONLY_STATES = {
class ResUser(orm.Model): _inherit = 'res.users' _columns = { 'user_profile': fields.boolean('Is User Profile'), 'user_profile_id': fields.many2one('res.users', 'User Profile', domain=[('user_profile', '=', True)], context={'active_test': False}), 'user_ids': fields.one2many('res.users', 'user_profile_id', 'Users', domain=[('user_profile', '=', False)]), 'field_ids': fields.many2many('ir.model.fields', 'res_users_fields_rel', 'user_id', 'field_id', 'Fields to update', domain=[('model', 'in', ('res.users', 'res.partner')), ('name', 'not in', ('user_profile', 'user_profile_id', 'user_ids', 'field_ids'))]), } def _get_default_field_ids(self, cr, uid, ids, context=None): return self.pool.get('ir.model.fields').search( cr, uid, [ ('model', 'in', ('res.users', 'res.partner')), ('name', 'in', ('action_id', 'menu_id', 'groups_id')), ], context=context) _defaults = { 'field_ids': _get_default_field_ids, } _sql_constraints = [ ('active_admin_check', 'CHECK (id = 1 AND active = TRUE OR id <> 1)', 'The user with id = 1 must be always active!'), ('profile_without_profile_id', 'CHECK( (user_profile = TRUE AND user_profile_id IS NULL) OR user_profile = FALSE )', 'Profile users cannot be linked to a profile!'), ] def onchange_user_profile(self, cr, uid, ids, user_profile): if user_profile: return { 'value': { 'active': ids == [1] and True or False, 'user_profile_id': False } } return {} def _get_user_vals_from_profile(self, cr, uid, user_profile_id, context=None): vals = {} user_profile = self.read(cr, uid, user_profile_id) for field in self.pool.get('ir.model.fields').read( cr, uid, user_profile['field_ids'], ['name']): value = user_profile[field['name']] if isinstance(value, tuple): value = value[0] if isinstance(value, list): value = [(6, 0, value)] vals[field['name']] = value vals['user_ids'] = [(5, 0)] return vals def create(self, cr, uid, vals, context=None): if vals.get('user_profile_id'): vals.update( self._get_user_vals_from_profile(cr, uid, vals['user_profile_id'], context)) return super(ResUser, self).create(cr, uid, vals, context) def write(self, cr, uid, ids, vals, context=None): if isinstance(ids, (int, long)): ids = [ids] if vals.get('user_profile_id'): new_profile_user_ids = [] same_profile_user_ids = [] for user in self.read(cr, uid, ids, ['user_profile', 'user_profile_id'], context, '_classic_write'): if user['user_profile']: raise orm.except_orm( _('Warning!'), _('You cannot change the profile of a user which is itself a profile!' )) if user['user_profile_id'] == vals['user_profile_id']: same_profile_user_ids.append(user['id']) else: new_profile_user_ids.append(user['id']) if same_profile_user_ids: super(ResUser, self).write(cr, uid, same_profile_user_ids, vals, context) if new_profile_user_ids: vals.update( self._get_user_vals_from_profile(cr, uid, vals['user_profile_id'], context)) super(ResUser, self).write(cr, uid, new_profile_user_ids, vals, context) else: super(ResUser, self).write(cr, uid, ids, vals, context) for user_profile in self.browse(cr, uid, ids, context): if user_profile.user_profile and user_profile.user_ids and any( field.name in vals for field in user_profile.field_ids): profile_vals = self._get_user_vals_from_profile( cr, uid, user_profile.id, context) self.write(cr, uid, [user.id for user in user_profile['user_ids']], profile_vals, context) return True def copy_data(self, cr, uid, user_id, default=None, context=None): default = default.copy() if default else {} default['user_ids'] = [] return super(ResUser, self).copy_data(cr, uid, user_id, default, context)