def _update_models(self, cr, models={}): if not models: checklist_ids = self.search(cr, 1, []) models = dict([(checklist['model_id'][0], {'checklist_id': checklist['id'], 'active_field': checklist['active_field']}) for checklist in self.read(cr, 1, checklist_ids, ['model_id', 'active_field'])]) for model in self.pool.get('ir.model').read(cr, 1, models.keys(), ['model']): if self.pool.get(model['model']): model_columns = self.pool.get(model['model'])._columns checklist_id = models[model['id']] and models[model['id']].get('checklist_id', False) if checklist_id: model_columns.update({ 'checklist_task_instance_ids': fields.function(self._get_checklist_task_instances, type='one2many', relation='checklist.task.instance', string='Checklist Task Instances', store=False), 'total_progress_rate': fields.float('Progress Rate', digits=(16, 2)), }) columns_to_add = {'total_progress_rate': 'NUMERIC(16,2)'} if models[model['id']].get('active_field', False): if 'active' not in model_columns or model_columns['active']._type != 'boolean': model_columns.update({'active': fields.boolean('Active')}) model_columns.update({'total_progress_rate_mandatory': fields.float('Mandatory Progress Rate', digits=(16, 2))}) columns_to_add.update({'active': 'BOOLEAN', 'total_progress_rate_mandatory': 'NUMERIC(16,2)'}) for column in columns_to_add: cr.execute("""SELECT c.relname FROM pg_class c, pg_attribute a WHERE c.relname=%s AND a.attname=%s AND c.oid=a.attrelid""", (model['model'].replace('.', '_'), column)) if not cr.rowcount: cr.execute('ALTER TABLE "%s" ADD COLUMN "%s" %s' % (model['model'].replace('.', '_'), column, columns_to_add[column])) cr.commit() else: if 'checklist_task_instance_ids' in model_columns: del model_columns['checklist_task_instance_ids'] if 'total_progress_rate' in model_columns: del model_columns['total_progress_rate'] return self._update_checklists_cache(cr)
def __init__(self, pool, cr): cr.execute("select id,name from stock_warehouse") model_obj = pool.get("ir.model.data") view_obj = pool.get("ir.ui.view") tree_arch = '<tree string="Productos por almacen">\n' tree_arch += '<field name="name"/>\n' tree_arch += '<field name="default_code"/>\n' tree_arch += '<field name="list_price"/>\n' tree_arch += '<field name="standard_price"/>\n' unsorted_warehouse=[] for row in cr.fetchall(): field_name = "qty_warehouse_%s"%row[0] self._columns[field_name] = fields.function(get_qty_warehouse, type="float", method=False, string=row[1], multi="qtys") unsorted_warehouse.append(['<field name="%s"/>\n'%field_name,row[1]]) sorted_warehouse=sorted(unsorted_warehouse,key=itemgetter(1)) ordered_fields="" for item in sorted_warehouse: ordered_fields+=item[0] tree_arch += ordered_fields+'</tree>' res = super(reporte_almacenes, self).__init__(pool, cr) try: view_rec = model_obj.get_object_reference(cr, 1, 'reporte_almacenes', 'reporte_view_tree') view_id_tree = view_rec and view_rec[1] or False if view_id_tree: view_obj.write(cr, 1, view_id_tree, {'arch': tree_arch}) except ValueError: pass return res
def _report_content_txt_inv(self, cr, uid, id, name, value, arg, context=None): self.write(cr,uid,id,{'report_rml_content':str(value)},context=context) _name = 'ir.actions.report.xml' _inherit = 'ir.actions.report.xml' _columns = { 'report_rml_content_txt': fields.function(_report_content_txt, fnct_inv=_report_content_txt_inv, method=True, type='text', string='RML text content'), }
def _get_alias_domain(self, cr, uid, ids, name, args, context=None): if context is None: context = {} userid = context.get('uid',uid) ir_config_parameter = self.pool.get("ir.config_parameter") #domain = ir_config_parameter.get_param(cr, uid, "mail.catchall.domain", context=context) domain = self.pool.get('res.users').browse(cr, uid, userid, context=context).company_id.email_domain print 'wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww' print domain return dict.fromkeys(ids, domain or "") _columns = { 'alias_domain': fields.function(_get_alias_domain, string="Alias domain", type='char', size=None), }
def __init__(self, pool, cr): """ Dynamically add columns.""" super(report_prompt_class, self).__init__(pool, cr) for counter in range(0, MAX_PARAMS): field_name = PARAM_XXX_STRING_VALUE % counter self._columns[field_name] = fields.char('String Value', size=64) field_name = PARAM_XXX_BOOLEAN_VALUE % counter self._columns[field_name] = fields.boolean('Boolean Value') field_name = PARAM_XXX_INTEGER_VALUE % counter self._columns[field_name] = fields.integer('Integer Value') field_name = PARAM_XXX_NUMBER_VALUE % counter self._columns[field_name] = fields.float('Number Value') field_name = PARAM_XXX_DATE_VALUE % counter self._columns[field_name] = fields.date('Date Value') field_name = PARAM_XXX_TIME_VALUE % counter self._columns[field_name] = fields.datetime('Time Value') field_name = PARAM_XXX_2M_VALUE % counter self._columns[field_name] = fields.function(self._multi_select_values.im_func, arg={"entry_num": counter}, fnct_inv=self._multi_select_values_store.im_func, fnct_inv_arg={"entry_num": counter}, method=False, type='many2many', relation='ir.actions.report.multivalues.promptwizard', string='Multi-Select')
###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 purchase_order_line(osv.osv): _inherit = 'purchase.order.line' def compute_list(self, total_paid, quantities, prices, ids): new_prices = [Decimal(str(p)) for p in prices] new_quantities = [Decimal(str(qty)) for qty in quantities] totals_ary = [p * qty for p, qty in zip(new_quantities, new_prices)] total = sum(totals_ary) total_paid = Decimal(str(total_paid)) # totals + importation expenses total_importation = [n + total_paid * (n / total) for n in totals_ary] # prices + importantion expenses expenses = [ imp / qty for qty, imp in zip(new_quantities, total_importation) ] ret = [round(float(expend), 2) for expend in expenses] return [{'id': t[0], 'price': t[1]} for t in zip(ids, ret)] def extract_lists(self, products): ids = [] prices = [] quantities = [] for product_info in products: ids.append(product_info['id']) prices.append(product_info['price']) quantities.append(product_info['qty']) return {'ids': ids, 'prices': prices, 'quantities': quantities} def _amount_line_liquidation(self, cr, uid, ids, prop, arg, context=None): order = self.browse(cr, uid, ids, context=context)[0] response = {} if order.order_id.importation: res_list = [] rate = order.order_id.custom_rate lines = self.browse(cr, uid, ids, context=context) for line in lines: if line.price_subtotal <= 0: raise osv.except_osv( 'Alerta!', "No puede agragar productos con valor cero") elif rate < 0: raise osv.except_osv( 'Alerta!', "Debe de expecificar la taza de la planilla de importacion" ) elif order.order_id.dop_total_cost <= 0: raise osv.except_osv( 'Alerta!', "Debe de expecificar el total de los gastos en pesos para esta importacion" ) elif order.order_id.usd_total_cost <= 0: raise osv.except_osv( 'Alerta!', "Debe de expecificar el total de los gastos en dolares para esta importacion" ) res = {} res["id"] = line.id res["qty"] = line.product_qty res["price"] = line.price_subtotal / line.product_qty res_list.append(res) lista = self.extract_lists(res_list) total_importacion = (order.order_id.dop_total_cost / rate) + order.order_id.usd_total_cost rets = self.compute_list(total_importacion, lista['quantities'], lista['prices'], lista['ids']) for ret in rets: response[ret["id"]] = ret["price"] return response return {} _columns = { 'price_unit_pesos': fields.function(_amount_line_liquidation, string='Cost unit (USD)', digits_compute=dp.get_precision('Account')) }
class IslrWhDocInvoices(osv.osv): _inherit = 'islr.wh.doc.invoices' def _amount_all(self, cr, uid, ids, fieldname, args, context=None): """ Return all amount relating to the invoices lines _13DIC2016_rsosa: changes.. """ res = {} ut_obj = self.pool.get('l10n.ut') for ret_line in self.browse(cr, uid, ids, context): flag = ret_line.invoice_id.flag_currency or False f_xc = ut_obj.sxc(cr, uid, ret_line.invoice_id.company_id.currency_id.id, ret_line.invoice_id.currency_id.id, ret_line.islr_wh_doc_id.date_uid) res[ret_line.id] = { 'amount_islr_ret': 0.0, 'base_ret': 0.0, 'currency_amount_islr_ret': 0.0, 'currency_base_ret': 0.0, } for line in ret_line.iwdl_ids: res[ret_line.id]['amount_islr_ret'] += line.amount res[ret_line.id]['base_ret'] += line.base_amount #_14DIC2016_rsosa: res[ret_line.id]['currency_amount_islr_ret'] += flag and round((line.amount / line.invoice_id.res_currency_rate),4) \ or f_xc(line.amount) if flag: res[ret_line.id][ 'currency_base_ret'] = line.invoice_id.amount_untaxed else: res[ret_line.id]['currency_base_ret'] += f_xc( line.base_amount) return res #_14DIC2016_rsosa: Se agrega la definicion de estos campos funcionales no para cambiarlos, sino para poder sobreescribir el metodo # que los alimenta (_amount_all). _columns = { 'amount_islr_ret': fields.function(_amount_all, method=True, digits=(16, 2), string='Withheld Amount', multi='all', help="Amount withheld from the base amount"), 'base_ret': fields.function( _amount_all, method=True, digits=(16, 2), string='Base Amount', multi='all', help="Amount where a withholding is going to be compute from"), 'currency_amount_islr_ret': fields.function(_amount_all, method=True, digits=(16, 2), string='Foreign Currency Withheld Amount', multi='all', help="Amount withheld from the base amount"), 'currency_base_ret': fields.function( _amount_all, method=True, digits=(16, 2), string='Foreign Currency Base Amount', multi='all', help="Amount where a withholding is going to be compute from"), } def _get_wh(self, cr, uid, ids, concept_id, context=None): """ Return a dictionary containing all the values of the retention of an invoice line. @param concept_id: Withholding reason """ # TODO: Change the signature of this method # This record already has the concept_id built-in context = context or {} ids = isinstance(ids, (int, long)) and [ids] or ids ixwl_obj = self.pool.get('islr.xml.wh.line') iwdl_obj = self.pool.get('islr.wh.doc.line') iwdl_brw = iwdl_obj.browse(cr, uid, ids[0], context=context) ut_date = iwdl_brw.islr_wh_doc_id.date_uid ut_obj = self.pool.get('l10n.ut') money2ut = ut_obj.compute ut2money = ut_obj.compute_ut_to_money vendor, buyer, wh_agent = self._get_partners(cr, uid, iwdl_brw.invoice_id) wh_agent = wh_agent apply_income = not vendor.islr_exempt residence = self._get_residence(cr, uid, vendor, buyer) nature = self._get_nature(cr, uid, vendor) concept_id = iwdl_brw.concept_id.id # rate_base,rate_minimum,rate_wh_perc,rate_subtract,rate_code,rate_id, # rate_name # Add a Key in context to store date of ret fot U.T. value # determination # TODO: Future me, this context update need to be checked with the # other date in the withholding in order to take into account the # customer income withholding. context.update({ 'wh_islr_date_ret': iwdl_brw.islr_wh_doc_id.date_uid or iwdl_brw.islr_wh_doc_id.date_ret or False }) base = 0 wh_concept = 0.0 # Using a clousure to make this call shorter f_xc = ut_obj.sxc(cr, uid, iwdl_brw.invoice_id.currency_id.id, iwdl_brw.invoice_id.company_id.currency_id.id, iwdl_brw.invoice_id.date_invoice) if iwdl_brw.invoice_id.type in ('in_invoice', 'in_refund'): for line in iwdl_brw.xml_ids: if line.account_invoice_id.type == 'in_invoice' and line.account_invoice_id.flag_currency: rate_c = line.account_invoice_id.res_currency_rate #base += f_xc(line.account_invoice_line_id.price_subtotal) base += round( (line.account_invoice_line_id.price_subtotal * rate_c), 4) else: base += f_xc(line.account_invoice_line_id.price_subtotal) # rate_base, rate_minimum, rate_wh_perc, rate_subtract, rate_code, # rate_id, rate_name, rate2 = self._get_rate( # cr, uid, ail_brw.concept_id.id, residence, nature, base=base, # inv_brw=ail_brw.invoice_id, context=context) rate_tuple = self._get_rate(cr, uid, concept_id, residence, nature, base=base, inv_brw=iwdl_brw.invoice_id, context=context) if rate_tuple[7]: apply_income = True residual_ut = ((rate_tuple[0] / 100.0) * (rate_tuple[2] / 100.0) * rate_tuple[7]['cumulative_base_ut']) residual_ut -= rate_tuple[7]['cumulative_tax_ut'] residual_ut -= rate_tuple[7]['subtrahend'] else: apply_income = (apply_income and base >= rate_tuple[0] * rate_tuple[1] / 100.0) wh = 0.0 subtract = apply_income and rate_tuple[3] or 0.0 subtract_write = 0.0 sb_concept = subtract for line in iwdl_brw.xml_ids: if line.account_invoice_id.type == 'in_invoice' and line.account_invoice_id.flag_currency: #_13DIC2016_rsosa: rate_c = line.account_invoice_id.res_currency_rate #base_line = f_xc(line.account_invoice_line_id.price_subtotal) base_line = round( (line.account_invoice_line_id.price_subtotal * rate_c), 4) else: base_line = f_xc( line.account_invoice_line_id.price_subtotal) base_line_ut = money2ut(cr, uid, base_line, ut_date) values = {} if apply_income and not rate_tuple[7]: wh_calc = ((rate_tuple[0] / 100.0) * (rate_tuple[2] / 100.0) * base_line) if subtract >= wh_calc: wh = 0.0 subtract -= wh_calc else: wh = wh_calc - subtract subtract_write = subtract subtract = 0.0 values = { 'wh': wh, 'raw_tax_ut': money2ut(cr, uid, wh, ut_date), 'sustract': subtract or subtract_write, } elif apply_income and rate_tuple[7]: tax_line_ut = (base_line_ut * (rate_tuple[0] / 100.0) * (rate_tuple[2] / 100.0)) if residual_ut >= tax_line_ut: wh_ut = 0.0 residual_ut -= tax_line_ut else: wh_ut = tax_line_ut + residual_ut subtract_write_ut = residual_ut residual_ut = 0.0 wh = ut2money(cr, uid, wh_ut, ut_date) values = { 'wh': wh, 'raw_tax_ut': wh_ut, 'sustract': ut2money(cr, uid, residual_ut or subtract_write_ut, ut_date), } values.update({ 'base': base_line * (rate_tuple[0] / 100.0), 'raw_base_ut': base_line_ut, 'rate_id': rate_tuple[5], 'porcent_rete': rate_tuple[2], 'concept_code': rate_tuple[4], }) ixwl_obj.write(cr, uid, line.id, values, context=context) wh_concept += wh else: for line in iwdl_brw.invoice_id.invoice_line: if line.concept_id.id == concept_id: base += f_xc(line.price_subtotal) rate_tuple = self._get_rate(cr, uid, concept_id, residence, nature, base=0.0, inv_brw=iwdl_brw.invoice_id, context=context) if rate_tuple[7]: apply_income = True else: apply_income = (apply_income and base >= rate_tuple[0] * rate_tuple[1] / 100.0) sb_concept = apply_income and rate_tuple[3] or 0.0 if apply_income: wh_concept = ((rate_tuple[0] / 100.0) * rate_tuple[2] * base / 100.0) wh_concept -= sb_concept values = { 'amount': wh_concept, 'raw_tax_ut': money2ut(cr, uid, wh_concept, ut_date), 'subtract': sb_concept, 'base_amount': base * (rate_tuple[0] / 100.0), 'raw_base_ut': money2ut(cr, uid, base, ut_date), 'retencion_islr': rate_tuple[2], 'islr_rates_id': rate_tuple[5], } iwdl_obj.write(cr, uid, ids[0], values, context=context) return True
def _save_file(self, path, b64_file): """Save a file encoded in base 64""" self._check_filestore(path) with open(path, 'w') as ofile: ofile.write(base64.b64decode(b64_file)) return True def _set_image(self, cr, uid, id, name, value, arg, context=None): image = self.browse(cr, uid, id, context=context) full_path = self._image_path(cr, uid, image, context=context) if full_path: return self._save_file(full_path, value) return self.write(cr, uid, id, {'file_db_store' : value}, context=context) _columns = { 'name':fields.char('Image Title', size=100, required=True), 'extention': fields.char('file extention', size=6), 'link':fields.boolean('Link?', help="Images can be linked from files on your file system or remote (Preferred)"), 'file_db_store':fields.binary('Image stored in database'), 'file':fields.function(_get_image, fnct_inv=_set_image, type="binary", filters='*.png,*.jpg,*.gif'), 'url':fields.char('File Location', size=250), 'comments':fields.text('Comments'), 'product_id':fields.many2one('product.product', 'Product') } _defaults = { 'link': lambda *a: False, } _sql_constraints = [('uniq_name_product_id', 'UNIQUE(product_id, name)', _('A product can have only one image with the same name'))]
_logger.warning('Data not found for items of %s %s', module_rec.name, str(e)) except Exception, e: _logger.warning('Unknown error while fetching data of %s', module_rec.name, exc_info=True) for key in res.iterkeys(): res[key]['models_by_module'] = '<table width="100%"><tr>' \ + '<th colspan="2" style="text-align: center;">Models</th></tr><tr>' \ + '<th>Name</th><th>Technical Name</th></tr><tr>' \ + '</tr><tr>'.join(sorted(res[key]['models_by_module'])) \ + '</tr></table>' res[key]['fields_by_module'] = '<table width="100%"><tr>' \ + '<th colspan="8" style="text-align: center;">Fields</th></tr><tr>' \ + '<th>Name</th><th>Technical Name</th>' \ + '<th>Model</th><th>ModelTechnical Name</th>' \ + '<th>Type</th><th>Object Relation</th>' \ + '<th>Required</th><th>Readonly</th></tr><tr>' \ + '</tr><tr>'.join(sorted(res[key]['fields_by_module'])) \ + '</tr></table>' res[key]['data_by_module'] = '<table width="100%"><tr>' \ + '<th colspan="4" style="text-align: center;">Data Records</th></tr><tr>' \ + '<th>XML ID</th><th>Model</th><th>Model Technical Name</th><th>ID</th></tr><tr>' \ + '</tr><tr>'.join(sorted(res[key]['data_by_module'])) \ + '</tr></table>' return res _columns = { 'models_by_module': fields.function(_get_model_data, string='Models', type='html', multi="metadata"), 'fields_by_module': fields.function(_get_model_data, string='Fields', type='html', multi="metadata"), 'data_by_module': fields.function(_get_model_data, string='Data', type='html', multi="metadata"), }
Employee ''' _inherit = 'hr.employee' def _payslip_count(self, cr, uid, ids, field_name, arg, context=None): try: res = super(hr_employee, self)._payslip_count(cr, uid, ids, field_name, arg, context) except AccessError, e: res = { employee_id: 0 for employee_id in ids } return res _columns = { 'payslip_count': old_fields.function(_payslip_count, type='integer', string='Payslips'), } def _get_access_to_employee_information(self): access_by_group = self.env.ref('access_custom.group_employee_private_information').id in self.env.user.groups_id.ids for r in self: r.access_to_employee_information = access_by_group or (r.user_id.id == self.env.uid) access_to_employee_information = fields.Boolean('Access to employee information', compute=_get_access_to_employee_information, store=False) class res_partner(models.Model): _inherit = 'res.partner' @api.multi def read(self, fields=None, load='_classic_read'):
def _sale_order_count(self, cr, uid, ids, field_name, arg, context=None): res = dict(map(lambda x: (x,0), ids)) # The current user may not have access rights for sale orders try: for partner in self.browse(cr, uid, ids, context): res[partner.id] = self.get_partner_sales(cr, uid, partner) for child in partner.mapped('child_ids'): res[partner.id] += self.get_partner_sales(cr, uid, child) except Exception, e: pass return res def _sale_quote_count(self, cr, uid, ids, field_name, arg, context=None): res = dict(map(lambda x: (x,0), ids)) # The current user may not have access rights for sale orders try: for partner in self.browse(cr, uid, ids, context): res[partner.id] = self.get_partner_quotes(cr, uid, partner) for child in partner.mapped('child_ids'): res[partner.id] += self.get_partner_quotes(cr, uid, child) except Exception, e: print e pass return res _columns = { 'sale_order_count': fields.function(_sale_order_count, string='# of Sales Order', type='integer'), 'sale_quote_count': fields.function(_sale_quote_count, string='# of Quotes', type='integer'), }
class IrMail(orm.Model): _inherit = "ir.mail_server" def _get_smtp_conf(self, cr, uid, ids, name, args, context=None): """ Return configuration """ res = {} for mail_server in self.browse(cr, uid, ids, context=context): global_section_name = 'outgoing_mail' # default vals config_vals = {'smtp_port': 587} if serv_config.has_section(global_section_name): config_vals.update((serv_config.items(global_section_name))) custom_section_name = '.'.join( (global_section_name, mail_server.name)) if serv_config.has_section(custom_section_name): config_vals.update(serv_config.items(custom_section_name)) if config_vals.get('smtp_port'): config_vals['smtp_port'] = int(config_vals['smtp_port']) res[mail_server.id] = config_vals return res _columns = { 'smtp_host': fields.function(_get_smtp_conf, string='SMTP Server', type="char", multi='outgoing_mail_config', states={'draft': [('readonly', True)]}, help="Hostname or IP of SMTP server"), 'smtp_port': fields.function(_get_smtp_conf, string='SMTP Port', type="integer", multi='outgoing_mail_config', states={'draft': [('readonly', True)]}, help="SMTP Port. Usually 465 for SSL, " "and 25 or 587 for other cases.", size=5), 'smtp_user': fields.function(_get_smtp_conf, string='Username', type="char", multi='outgoing_mail_config', states={'draft': [('readonly', True)]}, help="Optional username for SMTP authentication", size=64), 'smtp_pass': fields.function(_get_smtp_conf, string='Password', type="char", multi='outgoing_mail_config', states={'draft': [('readonly', True)]}, help="Optional password for SMTP authentication", size=64), 'smtp_encryption': fields.function(_get_smtp_conf, string='smtp_encryption', type="selection", multi='outgoing_mail_config', selection=[('none', 'None'), ('starttls', 'TLS (STARTTLS)'), ('ssl', 'SSL/TLS')], states={'draft': [('readonly', True)]}, help="Choose the connection encryption scheme:\n" "- none: SMTP sessions are done in cleartext.\n" "- starttls: TLS encryption is requested at start " "of SMTP session (Recommended)\n" "- ssl: SMTP sessions are encrypted with SSL/TLS " "through a dedicated port (default: 465)") }
class FetchmailServer(orm.Model): """Incoming POP/IMAP mail server account""" _inherit = 'fetchmail.server' def _get_incom_conf(self, cr, uid, ids, name, args, context=None): """ Return configuration """ res = {} for fetchmail in self.browse(cr, uid, ids, context=context): global_section_name = 'incoming_mail' key_types = { 'port': int, 'is_ssl': lambda a: bool(int(a)), 'attach': lambda a: bool(int(a)), 'original': lambda a: bool(int(a)), } # default vals config_vals = { 'port': 993, 'is_ssl': 0, 'attach': 0, 'original': 0, } if serv_config.has_section(global_section_name): config_vals.update(serv_config.items(global_section_name)) custom_section_name = '.'.join( (global_section_name, fetchmail.name)) if serv_config.has_section(custom_section_name): config_vals.update(serv_config.items(custom_section_name)) for key, to_type in key_types.iteritems(): if config_vals.get(key): config_vals[key] = to_type(config_vals[key]) res[fetchmail.id] = config_vals return res def _type_search(self, cr, uid, obj, name, args, context=None): result_ids = [] # read all incoming servers values all_ids = self.search(cr, uid, [], context=context) results = self.read(cr, uid, all_ids, ['id', 'type'], context=context) args = args[:] i = 0 while i < len(args): operator = args[i][1] if operator == '=': for res in results: if (res['type'] == args[i][2] and res['id'] not in result_ids): result_ids.append(res['id']) elif operator == 'in': for search_vals in args[i][2]: for res in results: if (res['type'] == search_vals and res['id'] not in result_ids): result_ids.append(res['id']) else: continue i += 1 return [('id', 'in', result_ids)] _columns = { 'server': fields.function(_get_incom_conf, string='Server', type="char", multi='income_mail_config', states={'draft': [('readonly', True)]}, help="Hostname or IP of the mail server"), 'port': fields.function(_get_incom_conf, string='Port', type="integer", states={'draft': [('readonly', True)]}, multi='income_mail_config'), 'type': fields.function(_get_incom_conf, string='Type', type="selection", selection=[ ('pop', 'POP Server'), ('imap', 'IMAP Server'), ('local', 'Local Server'), ], multi='income_mail_config', fnct_search=_type_search, states={'draft': [('readonly', True)]}, help="pop, imap, local"), 'is_ssl': fields.function(_get_incom_conf, string='Is SSL', type="boolean", multi='income_mail_config', states={'draft': [('readonly', True)]}, help='Connections are encrypted with SSL/TLS through' ' a dedicated port (default: IMAPS=993, POP3S=995)'), 'attach': fields.function( _get_incom_conf, string='Keep Attachments', type="boolean", multi='income_mail_config', states={'draft': [('readonly', True)]}, help="Whether attachments should be downloaded. " "If not enabled, incoming emails will be stripped of any " "attachments before being processed"), 'original': fields.function( _get_incom_conf, string='Keep Original', type="boolean", multi='income_mail_config', states={'draft': [('readonly', True)]}, help="Whether a full original copy of each email should be kept " "for reference and attached to each processed message. This " "will usually double the size of your message database."), 'user': fields.function(_get_incom_conf, string='Username', type="char", states={'draft': [('readonly', True)]}, multi='income_mail_config'), 'password': fields.function(_get_incom_conf, string='password', type="char", states={'draft': [('readonly', True)]}, multi='income_mail_config') }
class res_partner_category(osv.osv): def name_get(self, cr, uid, ids, context=None): """Return the categories' display name, including their direct parent by default. :param dict context: the ``partner_category_display`` key can be used to select the short version of the category name (without the direct parent), when set to ``'short'``. The default is the long version.""" if context is None: context = {} if context.get('partner_category_display') == 'short': return super(res_partner_category, self).name_get(cr, uid, ids, context=context) if isinstance(ids, (int, long)): ids = [ids] 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 name_search(self, cr, uid, name, args=None, operator='ilike', context=None, limit=100): if not args: args = [] if not context: context = {} if name: # Be sure name_search is symetric to name_get name = name.split(' / ')[-1] ids = self.search(cr, uid, [('name', operator, name)] + args, limit=limit, context=context) else: ids = self.search(cr, uid, args, limit=limit, context=context) return self.name_get(cr, uid, ids, context) def _name_get_fnc(self, cr, uid, ids, prop, unknow_none, context=None): res = self.name_get(cr, uid, ids, context=context) return dict(res) _description = 'Partner Categories' _name = 'res.partner.category' _columns = { 'name': fields.char('Category Name', required=True, size=64, translate=True), 'parent_id': fields.many2one('res.partner.category', 'Parent Category', select=True, ondelete='cascade'), 'complete_name': fields.function(_name_get_fnc, type="char", string='Full Name'), 'child_ids': fields.one2many('res.partner.category', 'parent_id', 'Child Categories'), 'active': fields.boolean( 'Active', help= "The active field allows you to hide the category without removing it." ), 'parent_left': fields.integer('Left parent', select=True), 'parent_right': fields.integer('Right parent', select=True), 'partner_ids': fields.many2many('res.partner', id1='category_id', id2='partner_id', string='Partners'), } _constraints = [ (osv.osv._check_recursion, 'Error ! You can not create recursive categories.', ['parent_id']) ] _defaults = { 'active': 1, } _parent_store = True _parent_order = 'name' _order = 'parent_left'
class res_partner(osv.osv, format_address): _description = 'Partner' _name = "res.partner" def _address_display(self, cr, uid, ids, name, args, context=None): res = {} for partner in self.browse(cr, uid, ids, context=context): res[partner.id] = self._display_address(cr, uid, partner, context=context) return res 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 _get_tz_offset(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] = datetime.datetime.now( pytz.timezone(obj.tz or 'GMT')).strftime('%z') 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) def _has_image(self, cr, uid, ids, name, args, context=None): result = {} for obj in self.browse(cr, uid, ids, context=context): result[obj.id] = obj.image != False return result _order = "name" _columns = { 'name': fields.char('Name', size=128, required=True, select=True), 'date': fields.date('Date', select=1), 'title': fields.many2one('res.partner.title', 'Title'), 'parent_id': fields.many2one('res.partner', 'Related Company'), 'child_ids': fields.one2many('res.partner', 'parent_id', 'Contacts'), 'ref': fields.char('Reference', size=64, select=1), 'lang': fields.selection(_lang_get, 'Language', help="If the selected language is loaded in the system, all documents related to this contact will be printed in this language. If not, it will be English."), 'tz': fields.selection(_tz_get, 'Timezone', size=64, help="The partner's timezone, used to output proper date and time values inside printed reports. " "It is important to set a value for this field. You should use the same timezone " "that is otherwise used to pick and render date and time values: your computer's timezone."), 'tz_offset': fields.function(_get_tz_offset, type='char', size=5, string='Timezone offset', invisible=True), 'user_id': fields.many2one('res.users', 'Salesperson', help='The internal user that is in charge of communicating with this contact if any.'), 'vat': fields.char('TIN', size=32, help="Tax Identification Number. Check the box if this contact is subjected to taxes. Used by the some of the legal statements."), 'bank_ids': fields.one2many('res.partner.bank', 'partner_id', 'Banks'), 'website': fields.char('Website', size=64, help="Website of Partner or Company"), 'comment': fields.text('Notes'), 'category_id': fields.many2many('res.partner.category', id1='partner_id', id2='category_id', string='Tags'), 'credit_limit': fields.float(string='Credit Limit'), 'ean13': fields.char('EAN13', size=13), 'active': fields.boolean('Active'), 'customer': fields.boolean('Customer', help="Check this box if this contact is a customer."), 'supplier': fields.boolean('Supplier', help="Check this box if this contact is a supplier. If it's not checked, purchase people will not see it when encoding a purchase order."), 'employee': fields.boolean('Employee', help="Check this box if this contact is an Employee."), 'function': fields.char('Job Position', size=128), 'type': fields.selection([('default', 'Default'), ('invoice', 'Invoice'), ('delivery', 'Shipping'), ('contact', 'Contact'), ('other', 'Other')], 'Address Type', help="Used to select automatically the right address according to the context in sales and purchases documents."), 'street': fields.char('Street', size=128), 'street2': fields.char('Street2', size=128), 'zip': fields.char('Zip', change_default=True, size=24), 'city': fields.char('City', size=128), 'state_id': fields.many2one("res.country.state", 'State'), 'country_id': fields.many2one('res.country', 'Country'), 'country': fields.related('country_id', type='many2one', relation='res.country', string='Country', deprecated="This field will be removed as of OpenERP 7.1, use country_id instead"), 'email': fields.char('Email', size=240), 'phone': fields.char('Phone', size=64), 'fax': fields.char('Fax', size=64), 'mobile': fields.char('Mobile', size=64), 'birthdate': fields.char('Birthdate', size=64), 'is_company': fields.boolean('Is a Company', help="Check if the contact is a company, otherwise it is a person"), 'use_parent_address': fields.boolean('Use Company Address', help="Select this if you want to set company's address information for this contact"), # image: all image fields are base64 encoded and PIL-supported 'image': fields.binary("Image", help="This field holds the image used as avatar for this contact, limited to 1024x1024px"), 'image_medium': fields.function(_get_image, fnct_inv=_set_image, string="Medium-sized image", type="binary", multi="_get_image", store={ 'res.partner': (lambda self, cr, uid, ids, c={}: ids, ['image'], 10), }, help="Medium-sized image of this contact. 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 image", type="binary", multi="_get_image", store={ 'res.partner': (lambda self, cr, uid, ids, c={}: ids, ['image'], 10), }, help="Small-sized image of this contact. It is automatically "\ "resized as a 64x64px image, with aspect ratio preserved. "\ "Use this field anywhere a small image is required."), 'has_image': fields.function(_has_image, type="boolean"), 'company_id': fields.many2one('res.company', 'Company', select=1), 'color': fields.integer('Color Index'), 'user_ids': fields.one2many('res.users', 'partner_id', 'Users'), 'contact_address': fields.function(_address_display, type='char', string='Complete Address'), } def _default_category(self, cr, uid, context=None): if context is None: context = {} if context.get('category_id'): return [context['category_id']] return False def _get_default_image(self, cr, uid, is_company, context=None, colorize=False): img_path = openerp.modules.get_module_resource( 'base', 'static/src/img', ('company_image.png' if is_company else 'avatar.png')) with open(img_path, 'rb') as f: image = f.read() # colorize user avatars if not is_company: image = tools.image_colorize(image) return tools.image_resize_image_big(image.encode('base64')) def fields_view_get(self, cr, user, view_id=None, view_type='form', context=None, toolbar=False, submenu=False): if (not view_id) and (view_type == 'form') and context and context.get( 'force_email', False): view_id = self.pool.get('ir.model.data').get_object_reference( cr, user, 'base', 'view_partner_simple_form')[1] res = super(res_partner, self).fields_view_get(cr, user, view_id, view_type, context, toolbar=toolbar, submenu=submenu) if view_type == 'form': res['arch'] = self.fields_view_get_address(cr, user, res['arch'], context=context) return res _defaults = { 'active': True, 'lang': lambda self, cr, uid, ctx: ctx.get('lang', 'en_US'), 'tz': lambda self, cr, uid, ctx: ctx.get('tz', False), 'customer': True, 'category_id': _default_category, 'company_id': lambda self, cr, uid, ctx: self.pool.get('res.company'). _company_default_get(cr, uid, 'res.partner', context=ctx), 'color': 0, 'is_company': False, 'type': 'default', 'use_parent_address': True, 'image': False, } def copy(self, cr, uid, id, default=None, context=None): if default is None: default = {} name = self.read(cr, uid, [id], ['name'], context)[0]['name'] default.update({'name': _('%s (copy)') % name}) return super(res_partner, self).copy(cr, uid, id, default, context) def onchange_type(self, cr, uid, ids, is_company, context=None): value = {} value['title'] = False if is_company: value['parent_id'] = False domain = {'title': [('domain', '=', 'partner')]} else: domain = {'title': [('domain', '=', 'contact')]} return {'value': value, 'domain': domain} def onchange_address(self, cr, uid, ids, use_parent_address, parent_id, context=None): def value_or_id(val): """ return val or val.id if val is a browse record """ return val if isinstance(val, (bool, int, long, float, basestring)) else val.id if use_parent_address and parent_id: parent = self.browse(cr, uid, parent_id, context=context) return { 'value': dict((key, value_or_id(parent[key])) for key in ADDRESS_FIELDS) } return {} def onchange_state(self, cr, uid, ids, state_id, context=None): if state_id: country_id = self.pool.get('res.country.state').browse( cr, uid, state_id, context).country_id.id return {'value': {'country_id': country_id}} return {} def _check_ean_key(self, cr, uid, ids, context=None): for partner_o in pooler.get_pool(cr.dbname).get('res.partner').read( cr, uid, ids, [ 'ean13', ]): thisean = partner_o['ean13'] if thisean and thisean != '': if len(thisean) != 13: return False sum = 0 for i in range(12): if not (i % 2): sum += int(thisean[i]) else: sum += 3 * int(thisean[i]) if math.ceil(sum / 10.0) * 10 - sum != int(thisean[12]): return False return True # _constraints = [(_check_ean_key, 'Error: Invalid ean code', ['ean13'])] def write(self, cr, uid, ids, vals, context=None): # Update parent and siblings or children records if isinstance(ids, (int, long)): ids = [ids] if vals.get('is_company') == False: vals.update({'child_ids': [(5, )]}) for partner in self.browse(cr, uid, ids, context=context): update_ids = [] if partner.is_company: domain_children = [('parent_id', '=', partner.id), ('use_parent_address', '=', True)] update_ids = self.search(cr, uid, domain_children, context=context) elif partner.parent_id: if vals.get('use_parent_address') == True: domain_siblings = [('parent_id', '=', partner.parent_id.id), ('use_parent_address', '=', True)] update_ids = [partner.parent_id.id] + self.search( cr, uid, domain_siblings, context=context) if 'use_parent_address' not in vals and partner.use_parent_address: domain_siblings = [('parent_id', '=', partner.parent_id.id), ('use_parent_address', '=', True)] update_ids = [partner.parent_id.id] + self.search( cr, uid, domain_siblings, context=context) self.update_address(cr, uid, update_ids, vals, context) return super(res_partner, self).write(cr, uid, ids, vals, context=context) def create(self, cr, uid, vals, context=None): if context is None: context = {} # Update parent and siblings records if vals.get('parent_id') and vals.get('use_parent_address'): domain_siblings = [('parent_id', '=', vals['parent_id']), ('use_parent_address', '=', True)] update_ids = [vals['parent_id']] + self.search( cr, uid, domain_siblings, context=context) self.update_address(cr, uid, update_ids, vals, context) return super(res_partner, self).create(cr, uid, vals, context=context) def update_address(self, cr, uid, ids, vals, context=None): addr_vals = dict( (key, vals[key]) for key in POSTAL_ADDRESS_FIELDS if vals.get(key)) if addr_vals: return super(res_partner, self).write(cr, uid, ids, addr_vals, context) def name_get(self, cr, uid, ids, context=None): if context is None: context = {} if isinstance(ids, (int, long)): ids = [ids] res = [] for record in self.browse(cr, uid, ids, context=context): name = record.name if record.parent_id: name = "%s (%s)" % (name, record.parent_id.name) if context.get('show_address'): name = name + "\n" + self._display_address( cr, uid, record, without_company=True, context=context) name = name.replace('\n\n', '\n') name = name.replace('\n\n', '\n') if context.get('show_email') and record.email: name = "%s <%s>" % (name, record.email) res.append((record.id, name)) return res def _parse_partner_name(self, text, context=None): """ Supported syntax: - 'Raoul <*****@*****.**>': will find name and email address - otherwise: default, everything is set as the name """ match = re.search(r'([^\s,<@]+@[^>\s,]+)', text) if match: email = match.group(1) name = text[:text.index(email)].replace('"', '').replace('<', '').strip() else: name, email = text, '' return name, email def name_create(self, cr, uid, name, context=None): """ Override of orm's name_create method for partners. The purpose is to handle some basic formats to create partners using the name_create. If only an email address is received and that the regex cannot find a name, the name will have the email value. If 'force_email' key in context: must find the email address. """ if context is None: context = {} name, email = self._parse_partner_name(name, context=context) if context.get('force_email') and not email: raise osv.except_osv( _('Warning'), _("Couldn't create contact without email address !")) if not name and email: name = email rec_id = self.create(cr, uid, { self._rec_name: name or email, 'email': email or False }, context=context) return self.name_get(cr, uid, [rec_id], context)[0] def name_search(self, cr, uid, name, args=None, operator='ilike', context=None, limit=100): if not args: args = [] if name and operator in ('=', 'ilike', '=ilike', 'like', '=like'): # search on the name of the contacts and of its company search_name = name if operator in ('ilike', 'like'): search_name = '%%%s%%' % name if operator in ('=ilike', '=like'): operator = operator[1:] query_args = {'name': search_name} limit_str = '' if limit: limit_str = ' limit %(limit)s' query_args['limit'] = limit cr.execute( '''SELECT partner.id FROM res_partner partner LEFT JOIN res_partner company ON partner.parent_id = company.id WHERE partner.email ''' + operator + ''' %(name)s OR partner.name || ' (' || COALESCE(company.name,'') || ')' ''' + operator + ' %(name)s ' + limit_str, query_args) ids = map(lambda x: x[0], cr.fetchall()) ids = self.search(cr, uid, [('id', 'in', ids)] + args, limit=limit, context=context) if ids: return self.name_get(cr, uid, ids, context) return super(res_partner, self).name_search(cr, uid, name, args, operator=operator, context=context, limit=limit) def find_or_create(self, cr, uid, email, context=None): """ Find a partner with the given ``email`` or use :py:method:`~.name_create` to create one :param str email: email-like string, which should contain at least one email, e.g. ``"Raoul Grosbedon <*****@*****.**>"``""" assert email, 'an email is required for find_or_create to work' emails = tools.email_split(email) if emails: email = emails[0] ids = self.search(cr, uid, [('email', 'ilike', email)], context=context) if not ids: return self.name_create(cr, uid, email, context=context)[0] return ids[0] def _email_send(self, cr, uid, ids, email_from, subject, body, on_error=None): partners = self.browse(cr, uid, ids) for partner in partners: if partner.email: tools.email_send(email_from, [partner.email], subject, body, on_error) return True def email_send(self, cr, uid, ids, email_from, subject, body, on_error=''): while len(ids): self.pool.get('ir.cron').create( cr, uid, { 'name': 'Send Partner Emails', 'user_id': uid, 'model': 'res.partner', 'function': '_email_send', 'args': repr( [ids[:16], email_from, subject, body, on_error]) }) ids = ids[16:] return True def address_get(self, cr, uid, ids, adr_pref=None): if adr_pref is None: adr_pref = ['default'] result = {} # retrieve addresses from the partner itself and its children res = [] # need to fix the ids ,It get False value in list like ids[False] if ids and ids[0] != False: for p in self.browse(cr, uid, ids): res.append((p.type, p.id)) res.extend((c.type, c.id) for c in p.child_ids) address_dict = dict(reversed(res)) # get the id of the (first) default address if there is one, # otherwise get the id of the first address in the list default_address = False if res: default_address = address_dict.get('default', res[0][1]) for adr in adr_pref: result[adr] = address_dict.get(adr, default_address) return result def view_header_get(self, cr, uid, view_id, view_type, context): res = super(res_partner, self).view_header_get(cr, uid, view_id, view_type, context) if res: return res if not context.get('category_id', False): return False return _('Partners: ') + self.pool.get('res.partner.category').browse( cr, uid, context['category_id'], context).name def main_partner(self, cr, uid): ''' Return the id of the main partner ''' model_data = self.pool.get('ir.model.data') return model_data.browse( cr, uid, model_data.search(cr, uid, [('module', '=', 'base'), ('name', '=', 'main_partner')])[0], ).res_id def _display_address(self, cr, uid, address, without_company=False, context=None): ''' The purpose of this function is to build and return an address formatted accordingly to the standards of the country where it belongs. :param address: browse record of the res.partner to format :returns: the address formatted in a display that fit its country habits (or the default ones if not country is specified) :rtype: string ''' # get the information that will be injected into the display format # get the address format address_format = address.country_id and address.country_id.address_format or \ "%(street)s\n%(street2)s\n%(city)s %(state_code)s %(zip)s\n%(country_name)s" args = { 'state_code': address.state_id and address.state_id.code or '', 'state_name': address.state_id and address.state_id.name or '', 'country_code': address.country_id and address.country_id.code or '', 'country_name': address.country_id and address.country_id.name or '', 'company_name': address.parent_id and address.parent_id.name or '', } address_field = ['title', 'street', 'street2', 'zip', 'city'] for field in address_field: args[field] = getattr(address, field) or '' if without_company: args['company_name'] = '' elif address.parent_id: address_format = '%(company_name)s\n' + address_format return address_format % args
class booking_chart(osv.osv): _name = "booking.chart" _description = "Booking Chart" def extra_fields(self, cr, uid, ids, field_names, arg, context=None): result = {} supported_models = [] for chart in self.browse(cr, uid, ids, context=context): for supported_model in chart.supported_model_ids: supported_models.append( (supported_model.model, supported_model.name)) result[chart.id] = { 'resource_model_name': chart.resource_model.model, 'supported_models': supported_models } return result _columns = { 'name': fields.char('Chart Name'), 'resource_model': fields.many2one( 'ir.model', 'Model of the Resource', required=True, help='OpenERP model that represents the booked resource.'), 'resource_domain': fields.char('Domain to filter the resources', help='''This Domain has the format of an domain expression (see: https://doc.openerp.com/trunk/web/rpc/ ). It is used if we want to display only some resources filtered based on that domain. Example: [["is_company","=",false]]''' ), 'resource_name': fields.char('Resource Name'), 'supported_model_ids': fields.many2many( 'ir.model', 'booking_chart_to_model_rel', id1='chart_id', id2='model_id', required=True, string='Target/Orgin Resource Models', help='Models used for Resource Booking Target and Origin.'), 'resource_model_name': fields.function(extra_fields, method=True, type='serialized', string='Resource Model Name', multi=True, readonly=True), 'supported_models': fields.function(extra_fields, method=True, type='serialized', string='Supported Model Array', multi=True, readonly=True) }
class im_livechat_channel(osv.osv): _name = 'im_livechat.channel' def _get_default_image(self, cr, uid, context=None): image_path = openerp.modules.get_module_resource( 'im_livechat', 'static/src/img', 'default.png') return tools.image_resize_image_big( open(image_path, 'rb').read().encode('base64')) def _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) def _are_you_inside(self, cr, uid, ids, name, arg, context=None): res = {} for record in self.browse(cr, uid, ids, context=context): res[record.id] = False for user in record.user_ids: if user.id == uid: res[record.id] = True break return res def _script(self, cr, uid, ids, name, arg, context=None): res = {} for record in self.browse(cr, uid, ids, context=context): res[record.id] = env.get_template("include.html").render({ "url": self.pool.get('ir.config_parameter').get_param( cr, uid, 'web.base.url'), "parameters": { "db": cr.dbname, "channel": record.id }, }) return res def _web_page(self, cr, uid, ids, name, arg, context=None): res = {} for record in self.browse(cr, uid, ids, context=context): res[record.id] = self.pool.get('ir.config_parameter').get_param(cr, uid, 'web.base.url') + \ "/im_livechat/web_page?p=" + json.dumps({"db":cr.dbname, "channel":record.id}) return res _columns = { 'name': fields.char(string="Channel Name", size=200, required=True), 'user_ids': fields.many2many('res.users', 'im_livechat_channel_im_user', 'channel_id', 'user_id', string="Users"), 'are_you_inside': fields.function(_are_you_inside, type='boolean', string='Are you inside the matrix?', store=False), 'script': fields.function(_script, type='text', string='Script', store=False), 'web_page': fields.function(_web_page, type='url', string='Web Page', store=False, size="200"), 'button_text': fields.char(string="Text of the Button", size=200), 'input_placeholder': fields.char(string="Chat Input Placeholder", size=200), 'default_message': fields.char(string="Welcome Message", size=200, help="This is an automated 'welcome' message that your visitor will see when they initiate a new chat session."), # 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 group, limited to 1024x1024px."), 'image_medium': fields.function(_get_image, fnct_inv=_set_image, string="Medium-sized photo", type="binary", multi="_get_image", store={ 'im_livechat.channel': (lambda self, cr, uid, ids, c={}: ids, ['image'], 10), }, help="Medium-sized photo of the group. It is automatically "\ "resized as a 128x128px image, with aspect ratio preserved. "\ "Use this field in form views or some kanban views."), 'image_small': fields.function(_get_image, fnct_inv=_set_image, string="Small-sized photo", type="binary", multi="_get_image", store={ 'im_livechat.channel': (lambda self, cr, uid, ids, c={}: ids, ['image'], 10), }, help="Small-sized photo of the group. It is automatically "\ "resized as a 64x64px image, with aspect ratio preserved. "\ "Use this field anywhere a small image is required."), } def _default_user_ids(self, cr, uid, context=None): return [(6, 0, [uid])] _defaults = { 'button_text': "Have a Question? Chat with us.", 'input_placeholder': "How may I help you?", 'default_message': '', 'user_ids': _default_user_ids, 'image': _get_default_image, } def get_available_users(self, cr, uid, channel_id, context=None): channel = self.browse(cr, openerp.SUPERUSER_ID, channel_id, context=context) im_user_ids = self.pool.get("im.user").search( cr, uid, [["user_id", "in", [user.id for user in channel.user_ids]]], context=context) users = [] for iuid in im_user_ids: imuser = self.pool.get("im.user").browse(cr, uid, iuid, context=context) if imuser.im_status: users.append(imuser) return users def get_session(self, cr, uid, channel_id, uuid, context=None): self.pool.get("im.user").get_my_id(cr, uid, uuid, context=context) users = self.get_available_users(cr, openerp.SUPERUSER_ID, channel_id, context=context) if len(users) == 0: return False user_id = random.choice(users).id session = self.pool.get("im.session").session_get(cr, uid, [user_id], uuid, context=context) self.pool.get("im.session").write(cr, openerp.SUPERUSER_ID, session.get("id"), {'channel_id': channel_id}, context=context) return session.get("id") def test_channel(self, cr, uid, channel, context=None): if not channel: return {} return { 'url': self.browse(cr, uid, channel[0], context=context or {}).web_page, 'type': 'ir.actions.act_url' } def get_info_for_chat_src(self, cr, uid, channel, context=None): url = self.pool.get('ir.config_parameter').get_param( cr, openerp.SUPERUSER_ID, 'web.base.url') chan = self.browse(cr, uid, channel, context=context) return { "url": url, 'buttonText': chan.button_text, 'inputPlaceholder': chan.input_placeholder, 'defaultMessage': chan.default_message, "channelName": chan.name, } def join(self, cr, uid, ids, context=None): self.write(cr, uid, ids, {'user_ids': [(4, uid)]}) return True def quit(self, cr, uid, ids, context=None): self.write(cr, uid, ids, {'user_ids': [(3, uid)]}) return True
class sale_order_line(orm.Model): _inherit = 'sale.order.line' def _is_stock_reservable(self, cr, uid, ids, fields, args, context=None): result = {}.fromkeys(ids, False) for line in self.browse(cr, uid, ids, context=context): if line.state != 'draft': continue if line.type == 'make_to_order': continue if (not line.product_id or line.product_id.type == 'service'): continue if not line.reservation_ids: result[line.id] = True return result _columns = { 'reservation_ids': fields.one2many('stock.reservation', 'sale_line_id', string='Stock Reservation'), 'is_stock_reservable': fields.function(_is_stock_reservable, type='boolean', readonly=True, string='Can be reserved'), } def copy_data(self, cr, uid, id, default=None, context=None): if default is None: default = {} default['reservation_ids'] = False return super(sale_order_line, self).copy_data(cr, uid, id, default=default, context=context) def release_stock_reservation(self, cr, uid, ids, context=None): lines = self.browse(cr, uid, ids, context=context) reserv_ids = [ reserv.id for line in lines for reserv in line.reservation_ids ] reserv_obj = self.pool.get('stock.reservation') reserv_obj.release(cr, uid, reserv_ids, context=context) return True 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): result = 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 ids: # warn only if we change an existing line return result assert len(ids) == 1, "Expected 1 ID, got %r" % ids line = self.browse(cr, uid, ids[0], context=context) if qty != line.product_uom_qty and line.reservation_ids: msg = _("As you changed the quantity of the line, " "the quantity of the stock reservation will " "be automatically adjusted to %.2f.") % qty msg += "\n\n" result.setdefault('warning', {}) if result['warning'].get('message'): result['warning']['message'] += msg else: result['warning'] = { 'title': _('Configuration Error!'), 'message': msg, } return result def write(self, cr, uid, ids, vals, context=None): block_on_reserve = ('product_id', 'product_uom', 'product_uos', 'type') update_on_reserve = ('price_unit', 'product_uom_qty', 'product_uos_qty') keys = set(vals.keys()) test_block = keys.intersection(block_on_reserve) test_update = keys.intersection(update_on_reserve) if test_block: for line in self.browse(cr, uid, ids, context=context): if not line.reservation_ids: continue raise orm.except_orm( _('Error'), _('You cannot change the product or unit of measure ' 'of lines with a stock reservation. ' 'Release the reservation ' 'before changing the product.')) res = super(sale_order_line, self).write(cr, uid, ids, vals, context=context) if test_update: for line in self.browse(cr, uid, ids, context=context): if not line.reservation_ids: continue if len(line.reservation_ids) > 1: raise orm.except_orm( _('Error'), _('Several stock reservations are linked with the ' 'line. Impossible to adjust their quantity. ' 'Please release the reservation ' 'before changing the quantity.')) line.reservation_ids[0].write({ 'price_unit': line.price_unit, 'product_qty': line.product_uom_qty, 'product_uos_qty': line.product_uos_qty, }) return res
def _setup_analytic_fields(cls, analytic, para, columns, defaults, orm_name, name, bases, nmspc): """Generate analytic and para-analytic fields on the model.""" # If _analytic uses a shortcut, convert it into a prefix-model mapping. if analytic is True: analytic = {"a": orm_name.replace(".", "_")} elif isinstance(analytic, basestring): analytic = {"a": analytic} # Create a field that will be used for replacement in the view if analytic: columns["analytic_dimensions"] = fields.function( lambda self, cr, uid, ids, *a: {i: "" for i in ids}, string=u"Analytic Dimensions", readonly=True, store=False, ) col_pattern = "{pre}{n}_{suf}" size = int(config.get_misc("analytic", "analytic_size", 5)) # Generate the fields directly into the _columns attribute. all_analytic = [] for prefix, model_name in analytic.iteritems(): # Analytic fields all_analytic.append((model_name, prefix, "id")) for n in xrange(1, size + 1): col_name = col_pattern.format(pre=prefix, n=n, suf="id") domain_field = "nd_id.ns{n}_id.model_name".format(n=n) columns[col_name] = fields.many2one( "analytic.code", "Generated Analytic Field", domain=[ (domain_field, "=", model_name), ("view_type", "=", False), ("disabled_per_company", "=", False), ], track_visibility="onchange", ) for key, value in para.iteritems(): # Para-analytic fields prefix, suffix = key model_name = value["model"] all_analytic.append((model_name, prefix, suffix)) if suffix == "id": raise ValueError("Para-analytic suffix cannot be 'id'") field_type = value["type"] args = value["args"] kwargs = value["kwargs"] for n in xrange(1, size + 1): col_name = col_pattern.format(pre=prefix, n=n, suf=suffix) columns[col_name] = field_type(*args, **kwargs) if "default" in value: defaults[col_name] = value["default"] # In order to preserve inheritance, possible overrides, and OEMetaSL's # expected behavior, work on a new class that inherits the given bases, # then make our model class inherit from this class. superclass_name = "_{name}_SuperAnalytic".format(name=name) # Set _register to False in order to prevent its instantiation. superclass = type(superclass_name, bases, {"_register": False}) @AddMethod(superclass) def fields_get(self, cr, uid, allfields=None, context=None, write_access=True): """Override this method to rename analytic fields.""" res = super(superclass, self).fields_get( cr, uid, allfields=allfields, context=context, write_access=write_access ) analytic_osv = self.pool.get("analytic.structure") for model_name, prefix, suffix in all_analytic: res = analytic_osv.analytic_fields_get(cr, uid, model_name, res, prefix, suffix, context=context) return res @AddMethod(superclass) def fields_view_get(self, cr, uid, view_id=None, view_type="form", context=None, toolbar=False, submenu=False): """Override this method to hide unused analytic fields.""" res = super(superclass, self).fields_view_get( cr, uid, view_id=view_id, view_type=view_type, context=context, toolbar=toolbar, submenu=submenu ) analytic_osv = self.pool.get("analytic.structure") for model_name, prefix, suffix in all_analytic: res = analytic_osv.analytic_fields_view_get(cr, uid, model_name, res, prefix, suffix, context=context) return res return (superclass,)
class ir_attachment(osv.osv): _inherit = "ir.attachment" def _website_url_get(self, cr, uid, ids, name, arg, context=None): result = {} for attach in self.browse(cr, uid, ids, context=context): if attach.url: result[attach.id] = attach.url else: result[attach.id] = self.pool['website'].image_url( cr, uid, attach, 'datas') return result def _datas_big(self, cr, uid, ids, name, arg, context=None): result = dict.fromkeys(ids, False) if context and context.get('bin_size'): return result for record in self.browse(cr, uid, ids, context=context): if record.res_model != 'ir.ui.view' or not record.datas: continue try: result[record.id] = openerp.tools.image_resize_image_big( record.datas) except IOError: # apparently the error PIL.Image.open raises pass return result _columns = { 'website_url': fields.function(_website_url_get, string="Attachment URL", type='char'), 'datas_big': fields.function(_datas_big, type='binary', store=True, string="Resized file content"), } def try_remove(self, cr, uid, ids, context=None): """ Removes a web-based image attachment if it is used by no view (template) Returns a dict mapping attachments which would not be removed (if any) mapped to the views preventing their removal """ Views = self.pool['ir.ui.view'] attachments_to_remove = [] # views blocking removal of the attachment removal_blocked_by = {} for attachment in self.browse(cr, uid, ids, context=context): # in-document URLs are html-escaped, a straight search will not # find them url = escape(attachment.website_url) ids = Views.search(cr, uid, [ "|", ('arch_db', 'like', '"%s"' % url), ('arch_db', 'like', "'%s'" % url) ], context=context) if ids: removal_blocked_by[attachment.id] = Views.read(cr, uid, ids, ['name'], context=context) else: attachments_to_remove.append(attachment.id) if attachments_to_remove: self.unlink(cr, uid, attachments_to_remove, context=context) return removal_blocked_by
class website(osv.osv): def _get_menu(self, cr, uid, ids, name, arg, context=None): res = {} menu_obj = self.pool.get('website.menu') for id in ids: menu_ids = menu_obj.search(cr, uid, [('parent_id', '=', False), ('website_id', '=', id)], order='id', context=context) res[id] = menu_ids and menu_ids[0] or False return res _name = "website" # Avoid website.website convention for conciseness (for new api). Got a special authorization from xmo and rco _description = "Website" _columns = { 'name': fields.char('Website Name'), 'domain': fields.char('Website Domain'), 'company_id': fields.many2one('res.company', string="Company"), 'language_ids': fields.many2many('res.lang', 'website_lang_rel', 'website_id', 'lang_id', 'Languages'), 'default_lang_id': fields.many2one('res.lang', string="Default language"), 'default_lang_code': fields.related('default_lang_id', 'code', type="char", string="Default language code", store=True), 'social_twitter': fields.char('Twitter Account'), 'social_facebook': fields.char('Facebook Account'), 'social_github': fields.char('GitHub Account'), 'social_linkedin': fields.char('LinkedIn Account'), 'social_youtube': fields.char('Youtube Account'), 'social_googleplus': fields.char('Google+ Account'), 'google_analytics_key': fields.char('Google Analytics Key'), 'user_id': fields.many2one('res.users', string='Public User'), 'compress_html': fields.boolean('Compress HTML'), 'cdn_activated': fields.boolean('Activate CDN for assets'), 'cdn_url': fields.char('CDN Base URL'), 'cdn_filters': fields.text( 'CDN Filters', help= "URL matching those filters will be rewritten using the CDN Base URL" ), 'partner_id': fields.related('user_id', 'partner_id', type='many2one', relation='res.partner', string='Public Partner'), 'menu_id': fields.function(_get_menu, relation='website.menu', type='many2one', string='Main Menu') } _defaults = { 'user_id': lambda self, cr, uid, c: self.pool['ir.model.data'].xmlid_to_res_id( cr, openerp.SUPERUSER_ID, 'base.public_user'), 'company_id': lambda self, cr, uid, c: self.pool['ir.model.data'].xmlid_to_res_id( cr, openerp.SUPERUSER_ID, 'base.main_company'), 'compress_html': False, 'cdn_activated': False, 'cdn_url': '//localhost:8069/', 'cdn_filters': '\n'.join(DEFAULT_CDN_FILTERS), } # cf. Wizard hack in website_views.xml def noop(self, *args, **kwargs): pass def write(self, cr, uid, ids, vals, context=None): self._get_languages.clear_cache(self) return super(website, self).write(cr, uid, ids, vals, context) def new_page(self, cr, uid, name, template='website.default_page', ispage=True, context=None): context = context or {} imd = self.pool.get('ir.model.data') view = self.pool.get('ir.ui.view') template_module, template_name = template.split('.') # completely arbitrary max_length page_name = slugify(name, max_length=50) page_xmlid = "%s.%s" % (template_module, page_name) # find a free xmlid inc = 0 dom = [('key', '=', page_xmlid), '|', ('website_id', '=', False), ('website_id', '=', context.get('website_id'))] while view.search(cr, openerp.SUPERUSER_ID, dom, context=dict(context or {}, active_test=False)): inc += 1 page_xmlid = "%s.%s" % (template_module, page_name + (inc and "-%s" % inc or "")) page_name += (inc and "-%s" % inc or "") # new page _, template_id = imd.get_object_reference(cr, uid, template_module, template_name) website_id = context.get('website_id') key = template_module + '.' + page_name page_id = view.copy(cr, uid, template_id, { 'website_id': website_id, 'key': key }, context=context) page = view.browse(cr, uid, page_id, context=context) page.write({ 'arch': page.arch.replace(template, page_xmlid), 'name': page_name, 'page': ispage, }) return page_xmlid def delete_page(self, cr, uid, view_id, context=None): if context is None: context = {} View = self.pool.get('ir.ui.view') view_find = View.search( cr, uid, [('id', '=', view_id), "|", ('website_id', '=', context.get('website_id')), ('website_id', '=', False), ('page', '=', True), ('type', '=', 'qweb')], context=context) if view_find: View.unlink(cr, uid, view_find, context=context) def page_search_dependencies(self, cr, uid, view_id=False, context=None): dep = {} if not view_id: return dep # search dependencies just for information. # It will not catch 100% of dependencies and False positive is more than possible # Each module could add dependences in this dict if context is None: context = {} View = self.pool.get('ir.ui.view') Menu = self.pool.get('website.menu') view = View.browse(cr, uid, view_id, context=context) website_id = context.get('website_id') name = view.key.replace("website.", "") fullname = "website.%s" % name if view.page: # search for page with link page_search_dom = [ '|', ('website_id', '=', website_id), ('website_id', '=', False), '|', ('arch_db', 'ilike', '/page/%s' % name), ('arch_db', 'ilike', '/page/%s' % fullname) ] pages = View.search(cr, uid, page_search_dom, context=context) if pages: page_key = _('Page') dep[page_key] = [] for page in View.browse(cr, uid, pages, context=context): if page.page: dep[page_key].append({ 'text': _('Page <b>%s</b> seems to have a link to this page !' % page.key), 'link': '/page/%s' % page.key }) else: dep[page_key].append({ 'text': _('Template <b>%s (id:%s)</b> seems to have a link to this page !' % (page.key, page.id)), 'link': '#' }) # search for menu with link menu_search_dom = [ '|', ('website_id', '=', website_id), ('website_id', '=', False), '|', ('url', 'ilike', '/page/%s' % name), ('url', 'ilike', '/page/%s' % fullname) ] menus = Menu.search(cr, uid, menu_search_dom, context=context) if menus: menu_key = _('Menu') dep[menu_key] = [] for menu in Menu.browse(cr, uid, menus, context=context): dep[menu_key].append({ 'text': _('Menu <b>%s</b> seems to have a link to this page !' % menu.name), 'link': False }) return dep def page_for_name(self, cr, uid, ids, name, module='website', context=None): # whatever return '%s.%s' % (module, slugify(name, max_length=50)) def page_exists(self, cr, uid, ids, name, module='website', context=None): try: name = (name or "").replace("/page/website.", "").replace("/page/", "") if not name: return False return self.pool["ir.model.data"].get_object_reference( cr, uid, module, name) except: return False @openerp.tools.ormcache(skiparg=3) def _get_languages(self, cr, uid, id, context=None): website = self.browse(cr, uid, id) return [(lg.code, lg.name) for lg in website.language_ids] def get_cdn_url(self, cr, uid, uri, context=None): # Currently only usable in a website_enable request context if request and request.website and not request.debug: cdn_url = request.website.cdn_url cdn_filters = (request.website.cdn_filters or '').splitlines() for flt in cdn_filters: if flt and re.match(flt, uri): return urlparse.urljoin(cdn_url, uri) return uri def get_languages(self, cr, uid, ids, context=None): return self._get_languages(cr, uid, ids[0], context=context) def get_alternate_languages(self, cr, uid, ids, req=None, context=None): langs = [] if req is None: req = request.httprequest default = self.get_current_website(cr, uid, context=context).default_lang_code uri = req.path if req.query_string: uri += '?' + req.query_string shorts = [] for code, name in self.get_languages(cr, uid, ids, context=context): lg_path = ('/' + code) if code != default else '' lg = code.split('_') shorts.append(lg[0]) lang = { 'hreflang': ('-'.join(lg)).lower(), 'short': lg[0], 'href': req.url_root[0:-1] + lg_path + uri, } langs.append(lang) for lang in langs: if shorts.count(lang['short']) == 1: lang['hreflang'] = lang['short'] return langs @openerp.tools.ormcache(skiparg=4) def _get_current_website_id(self, cr, uid, domain_name, context=None): ids = self.search(cr, uid, [('name', '=', domain_name)], limit=1, context=context) if ids: return ids[0] else: return self.search(cr, uid, [], limit=1, context=context)[0] def get_current_website(self, cr, uid, context=None): domain_name = request.httprequest.environ.get('HTTP_HOST', '').split(':')[0] website_id = self._get_current_website_id(cr, uid, domain_name, context=context) request.context['website_id'] = website_id return self.browse(cr, uid, website_id, context=context) def is_publisher(self, cr, uid, ids, context=None): Access = self.pool['ir.model.access'] is_website_publisher = Access.check(cr, uid, 'ir.ui.view', 'write', False, context=context) return is_website_publisher def is_user(self, cr, uid, ids, context=None): Access = self.pool['ir.model.access'] return Access.check(cr, uid, 'ir.ui.menu', 'read', False, context=context) def get_template(self, cr, uid, ids, template, context=None): if not isinstance(template, (int, long)) and '.' not in template: template = 'website.%s' % template View = self.pool['ir.ui.view'] view_id = View.get_view_id(cr, uid, template, context=context) if not view_id: raise NotFound return View.browse(cr, uid, view_id, context=context) def _render(self, cr, uid, ids, template, values=None, context=None): # TODO: remove this. (just kept for backward api compatibility for saas-3) return self.pool['ir.ui.view'].render(cr, uid, template, values=values, context=context) def render(self, cr, uid, ids, template, values=None, status_code=None, context=None): # TODO: remove this. (just kept for backward api compatibility for saas-3) return request.render(template, values, uid=uid) def pager(self, cr, uid, ids, url, total, page=1, step=30, scope=5, url_args=None, context=None): # Compute Pager page_count = int(math.ceil(float(total) / step)) page = max(1, min(int(page if str(page).isdigit() else 1), page_count)) scope -= 1 pmin = max(page - int(math.floor(scope / 2)), 1) pmax = min(pmin + scope, page_count) if pmax - pmin < scope: pmin = pmax - scope if pmax - scope > 0 else 1 def get_url(page): _url = "%s/page/%s" % (url, page) if page > 1 else url if url_args: _url = "%s?%s" % (_url, werkzeug.url_encode(url_args)) return _url return { "page_count": page_count, "offset": (page - 1) * step, "page": { 'url': get_url(page), 'num': page }, "page_start": { 'url': get_url(pmin), 'num': pmin }, "page_previous": { 'url': get_url(max(pmin, page - 1)), 'num': max(pmin, page - 1) }, "page_next": { 'url': get_url(min(pmax, page + 1)), 'num': min(pmax, page + 1) }, "page_end": { 'url': get_url(pmax), 'num': pmax }, "pages": [{ 'url': get_url(page), 'num': page } for page in xrange(pmin, pmax + 1)] } def rule_is_enumerable(self, rule): """ Checks that it is possible to generate sensible GET queries for a given rule (if the endpoint matches its own requirements) :type rule: werkzeug.routing.Rule :rtype: bool """ endpoint = rule.endpoint methods = rule.methods or ['GET'] converters = rule._converters.values() if not ('GET' in methods and endpoint.routing['type'] == 'http' and endpoint.routing['auth'] in ('none', 'public') and endpoint.routing.get('website', False) and all( hasattr(converter, 'generate') for converter in converters) and endpoint.routing.get('website')): return False # dont't list routes without argument having no default value or converter spec = inspect.getargspec(endpoint.method.original_func) # remove self and arguments having a default value defaults_count = len(spec.defaults or []) args = spec.args[1:(-defaults_count or None)] # check that all args have a converter return all((arg in rule._converters) for arg in args) def enumerate_pages(self, cr, uid, ids, query_string=None, context=None): """ Available pages in the website/CMS. This is mostly used for links generation and can be overridden by modules setting up new HTML controllers for dynamic pages (e.g. blog). By default, returns template views marked as pages. :param str query_string: a (user-provided) string, fetches pages matching the string :returns: a list of mappings with two keys: ``name`` is the displayable name of the resource (page), ``url`` is the absolute URL of the same. :rtype: list({name: str, url: str}) """ router = request.httprequest.app.get_db_router(request.db) # Force enumeration to be performed as public user url_list = [] for rule in router.iter_rules(): if not self.rule_is_enumerable(rule): continue converters = rule._converters or {} if query_string and not converters and ( query_string not in rule.build([{}], append_unknown=False)[1]): continue values = [{}] convitems = converters.items() # converters with a domain are processed after the other ones gd = lambda x: hasattr(x[1], 'domain') and (x[1].domain <> '[]') convitems.sort(lambda x, y: cmp(gd(x), gd(y))) for (i, (name, converter)) in enumerate(convitems): newval = [] for val in values: query = i == (len(convitems) - 1) and query_string for v in converter.generate(request.cr, uid, query=query, args=val, context=context): newval.append(val.copy()) v[name] = v['loc'] del v['loc'] newval[-1].update(v) values = newval for value in values: domain_part, url = rule.build(value, append_unknown=False) page = {'loc': url} for key, val in value.items(): if key.startswith('__'): page[key[2:]] = val if url in ('/sitemap.xml', ): continue if url in url_list: continue url_list.append(url) yield page def search_pages(self, cr, uid, ids, needle=None, limit=None, context=None): name = re.sub(r"^/p(a(g(e(/(w(e(b(s(i(t(e(\.)?)?)?)?)?)?)?)?)?)?)?)?", "", needle or "") res = [] for page in self.enumerate_pages(cr, uid, ids, query_string=name, context=context): if needle in page['loc']: res.append(page) if len(res) == limit: break return res def kanban(self, cr, uid, ids, model, domain, column, template, step=None, scope=None, orderby=None, context=None): step = step and int(step) or 10 scope = scope and int(scope) or 5 orderby = orderby or "name" get_args = dict(request.httprequest.args or {}) model_obj = self.pool[model] relation = model_obj._columns.get(column)._obj relation_obj = self.pool[relation] get_args.setdefault('kanban', "") kanban = get_args.pop('kanban') kanban_url = "?%s&kanban=" % werkzeug.url_encode(get_args) pages = {} for col in kanban.split(","): if col: col = col.split("-") pages[int(col[0])] = int(col[1]) objects = [] for group in model_obj.read_group(cr, uid, domain, ["id", column], groupby=column): obj = {} # browse column relation_id = group[column][0] obj['column_id'] = relation_obj.browse(cr, uid, relation_id) obj['kanban_url'] = kanban_url for k, v in pages.items(): if k != relation_id: obj['kanban_url'] += "%s-%s" % (k, v) # pager number = model_obj.search(cr, uid, group['__domain'], count=True) obj['page_count'] = int(math.ceil(float(number) / step)) obj['page'] = pages.get(relation_id) or 1 if obj['page'] > obj['page_count']: obj['page'] = obj['page_count'] offset = (obj['page'] - 1) * step obj['page_start'] = max( obj['page'] - int(math.floor((scope - 1) / 2)), 1) obj['page_end'] = min(obj['page_start'] + (scope - 1), obj['page_count']) # view data obj['domain'] = group['__domain'] obj['model'] = model obj['step'] = step obj['orderby'] = orderby # browse objects object_ids = model_obj.search(cr, uid, group['__domain'], limit=step, offset=offset, order=orderby) obj['object_ids'] = model_obj.browse(cr, uid, object_ids) objects.append(obj) values = { 'objects': objects, 'range': range, 'template': template, } return request.website._render("website.kanban_contain", values) def kanban_col(self, cr, uid, ids, model, domain, page, template, step, orderby, context=None): html = "" model_obj = self.pool[model] domain = safe_eval(domain) step = int(step) offset = (int(page) - 1) * step object_ids = model_obj.search(cr, uid, domain, limit=step, offset=offset, order=orderby) object_ids = model_obj.browse(cr, uid, object_ids) for object_id in object_ids: html += request.website._render(template, {'object_id': object_id}) return html def _image_placeholder(self, response): # file_open may return a StringIO. StringIO can be closed but are # not context managers in Python 2 though that is fixed in 3 with contextlib.closing( openerp.tools.misc.file_open(os.path.join( 'web', 'static', 'src', 'img', 'placeholder.png'), mode='rb')) as f: response.data = f.read() return response.make_conditional(request.httprequest) def _image(self, cr, uid, model, id, field, response, max_width=maxint, max_height=maxint, cache=None, context=None): """ Fetches the requested field and ensures it does not go above (max_width, max_height), resizing it if necessary. Resizing is bypassed if the object provides a $field_big, which will be interpreted as a pre-resized version of the base field. If the record is not found or does not have the requested field, returns a placeholder image via :meth:`~._image_placeholder`. Sets and checks conditional response parameters: * :mailheader:`ETag` is always set (and checked) * :mailheader:`Last-Modified is set iif the record has a concurrency field (``__last_update``) The requested field is assumed to be base64-encoded image data in all cases. """ Model = self.pool[model] id = int(id) ids = Model.search(cr, uid, [('id', '=', id)], context=context) if not ids and 'website_published' in Model._fields: ids = Model.search(cr, openerp.SUPERUSER_ID, [('id', '=', id), ('website_published', '=', True)], context=context) if not ids: return self._image_placeholder(response) concurrency = '__last_update' [record] = Model.read(cr, openerp.SUPERUSER_ID, [id], [concurrency, field], context=context) if concurrency in record: server_format = openerp.tools.misc.DEFAULT_SERVER_DATETIME_FORMAT try: response.last_modified = datetime.datetime.strptime( record[concurrency], server_format + '.%f') except ValueError: # just in case we have a timestamp without microseconds response.last_modified = datetime.datetime.strptime( record[concurrency], server_format) # Field does not exist on model or field set to False if not record.get(field): # FIXME: maybe a field which does not exist should be a 404? return self._image_placeholder(response) response.set_etag(hashlib.sha1(record[field]).hexdigest()) response.make_conditional(request.httprequest) if cache: response.cache_control.max_age = cache response.expires = int(time.time() + cache) # conditional request match if response.status_code == 304: return response if model == 'ir.attachment' and field == 'url' and field in record: path = record[field].strip('/') # Check that we serve a file from within the module if os.path.normpath(path).startswith('..'): return self._image_placeholder(response) # Check that the file actually exists path = path.split('/') resource = openerp.modules.get_module_resource(*path) if not resource: return self._image_placeholder(response) data = open(resource, 'rb').read() else: data = record[field].decode('base64') image = Image.open(cStringIO.StringIO(data)) response.mimetype = Image.MIME[image.format] filename = '%s_%s.%s' % (model.replace('.', '_'), id, str( image.format).lower()) response.headers[ 'Content-Disposition'] = 'inline; filename="%s"' % filename if (not max_width) and (not max_height): response.data = data return response w, h = image.size max_w = int(max_width) if max_width else maxint max_h = int(max_height) if max_height else maxint if w < max_w and h < max_h: response.data = data else: size = (max_w, max_h) img = image_resize_and_sharpen(image, size, preserve_aspect_ratio=True) image_save_for_web(img, response.stream, format=image.format) # invalidate content-length computed by make_conditional as # writing to response.stream does not do it (as of werkzeug 0.9.3) del response.headers['Content-Length'] return response def image_url(self, cr, uid, record, field, size=None, context=None): """Returns a local url that points to the image field of a given browse record.""" model = record._name sudo_record = record.sudo() id = '%s_%s' % (record.id, hashlib.sha1(sudo_record.write_date or sudo_record.create_date or '').hexdigest()[0:7]) size = '' if size is None else '/%s' % size return '/website/image/%s/%s/%s%s' % (model, id, field, size)
# ('confirm', 'Waiting Approval'), = deducted in budget # ('accepted', 'Approved'), = deducted in budget # ('done', 'Waiting Payment'), = deducted in budget # ('paid', 'Paid'), = deducted in budget + cash #Totals res[company.id]['smart_cash'] = round(res[company.id]['smart_cash'] - res[company.id]['smart_amount_cash'],0) res[company.id]['smart_budget'] = round(res[company.id]['smart_budget'] - res[company.id]['smart_amount_budget'],0) #res[company.id]['smart_cash'] = 0.0 return res _columns = { 'smart_budget': fields.function(_smart_cash, type="float", digits_compute=dp.get_precision('Account'), string='SMart Budget',multi='all',help="Approved invoiced amount.",), # 'smart_cash': fields.function(smart_cash, type="float", digits_compute=dp.get_precision('Account'), string='SMart Budget', # help="Approved invoiced amount.", # multi='all',), 'smart_cash': fields.function(_smart_cash, type="float", digits_compute=dp.get_precision('Account'), string='SMart Cash', help="Free invoiced amount for salary or expenses.", multi='all',), 'prepayment': fields.boolean('Prepayment',help="SMart User: this virtual company can have prepayment smart_cash, SMart Company: this country applies prepayment"), 'prepayment_days': fields.integer('Prepayment Days',help="Leadtime in days before invoiced amount becomes smart_cash (global)"), 'smart_share': fields.float('SMarts Share',digits_compute=dp.get_precision('Account')), 'sale_order_sum_cash': fields.function(_smart_cash, type="float", digits_compute=dp.get_precision('Account'), string='SMart Order sum cash',multi='all',help="Approved invoiced amount.",), 'sale_order_sum_budget':fields.function(_smart_cash, type="float", digits_compute=dp.get_precision('Account'), string='SMart Order sum budget',multi='all',help="Approved invoiced amount.",), 'smart_amount_cash':fields.function(_smart_cash, type="float", digits_compute=dp.get_precision('Account'), string='SMart Amount cash',multi='all',help="Approved invoiced amount.",), 'smart_amount_budget':fields.function(_smart_cash, type="float", digits_compute=dp.get_precision('Account'), string='SMart Amount budget',multi='all',help="Approved invoiced amount.",), 'activity_amount_cash':fields.function(_smart_cash, type="float", digits_compute=dp.get_precision('Account'), string='SMart activity amount cash',multi='all',help="Approved invoiced amount.",), 'activity_amount_budget':fields.function(_smart_cash, type="float", digits_compute=dp.get_precision('Account'), string='SMart activity amount budget',multi='all',help="Approved invoiced amount.",),
class note_note(osv.osv): """ Note """ _name = 'note.note' _inherit = ['mail.thread'] _description = "Note" #writing method (no modification of values) def name_create(self, cr, uid, name, context=None): rec_id = self.create(cr, uid, {'memo': name}, context=context) return self.name_get(cr, uid, [rec_id], context)[0] #read the first line (convert hml into text) def _get_note_first_line(self, cr, uid, ids, name="", args={}, context=None): res = {} for note in self.browse(cr, uid, ids, context=context): res[note.id] = (note.memo and html2plaintext(note.memo) or "").strip().replace('*','').split("\n")[0] return res def onclick_note_is_done(self, cr, uid, ids, context=None): return self.write(cr, uid, ids, {'open': False, 'date_done': fields.date.today()}, context=context) def onclick_note_not_done(self, cr, uid, ids, context=None): return self.write(cr, uid, ids, {'open': True}, context=context) #return the default stage for the uid user def _get_default_stage_id(self,cr,uid,context=None): ids = self.pool.get('note.stage').search(cr,uid,[('user_id','=',uid)], context=context) return ids and ids[0] or False def _set_stage_per_user(self, cr, uid, id, name, value, args=None, context=None): note = self.browse(cr, uid, id, context=context) if not value: return False stage_ids = [value] + [stage.id for stage in note.stage_ids if stage.user_id.id != uid ] return self.write(cr, uid, [id], {'stage_ids': [(6, 0, set(stage_ids))]}, context=context) def _get_stage_per_user(self, cr, uid, ids, name, args, context=None): result = dict.fromkeys(ids, False) for record in self.browse(cr, uid, ids, context=context): for stage in record.stage_ids: if stage.user_id.id == uid: result[record.id] = stage.id return result _columns = { 'name': fields.function(_get_note_first_line, string='Note Summary', type='text', store=True), 'user_id': fields.many2one('res.users', 'Owner'), 'memo': fields.html('Note Content'), 'sequence': fields.integer('Sequence'), 'stage_id': fields.function(_get_stage_per_user, fnct_inv=_set_stage_per_user, string='Stage', type='many2one', relation='note.stage'), 'stage_ids': fields.many2many('note.stage','note_stage_rel','note_id','stage_id','Stages of Users'), 'open': fields.boolean('Active', track_visibility='onchange'), 'date_done': fields.date('Date done'), 'color': fields.integer('Color Index'), 'tag_ids' : fields.many2many('note.tag','note_tags_rel','note_id','tag_id','Tags'), } _defaults = { 'user_id': lambda self, cr, uid, ctx=None: uid, 'open' : 1, 'stage_id' : _get_default_stage_id, } _order = 'sequence' def read_group(self, cr, uid, domain, fields, groupby, offset=0, limit=None, context=None, orderby=False, lazy=True): if groupby and groupby[0]=="stage_id": #search all stages current_stage_ids = self.pool.get('note.stage').search(cr,uid,[('user_id','=',uid)], context=context) if current_stage_ids: #if the user have some stages #dict of stages: map les ids sur les noms stage_name = dict(self.pool.get('note.stage').name_get(cr, uid, current_stage_ids, context=context)) result = [{ #notes by stage for stages user '__context': {'group_by': groupby[1:]}, '__domain': domain + [('stage_ids.id', '=', current_stage_id)], 'stage_id': (current_stage_id, stage_name[current_stage_id]), 'stage_id_count': self.search(cr,uid, domain+[('stage_ids', '=', current_stage_id)], context=context, count=True) } for current_stage_id in current_stage_ids] #note without user's stage nb_notes_ws = self.search(cr,uid, domain+[('stage_ids', 'not in', current_stage_ids)], context=context, count=True) if nb_notes_ws: # add note to the first column if it's the first stage dom_not_in = ('stage_ids', 'not in', current_stage_ids) if result and result[0]['stage_id'][0] == current_stage_ids[0]: dom_in = result[0]['__domain'].pop() result[0]['__domain'] = domain + ['|', dom_in, dom_not_in] result[0]['stage_id_count'] += nb_notes_ws else: # add the first stage column result = [{ '__context': {'group_by': groupby[1:]}, '__domain': domain + [dom_not_in], 'stage_id': (current_stage_ids[0], stage_name[current_stage_ids[0]]), 'stage_id_count':nb_notes_ws }] + result else: # if stage_ids is empty #note without user's stage nb_notes_ws = self.search(cr,uid, domain, context=context, count=True) if nb_notes_ws: result = [{ #notes for unknown stage '__context': {'group_by': groupby[1:]}, '__domain': domain, 'stage_id': False, 'stage_id_count':nb_notes_ws }] else: result = [] return result else: return super(note_note, self).read_group(self, cr, uid, domain, fields, groupby, offset=offset, limit=limit, context=context, orderby=orderby,lazy=lazy)
def _datas_big(self, cr, uid, ids, name, arg, context=None): result = dict.fromkeys(ids, False) if context and context.get('bin_size'): return result for record in self.browse(cr, uid, ids, context=context): if record.res_model != 'ir.ui.view' or not record.datas: continue try: result[record.id] = openerp.tools.image_resize_image_big(record.datas) except Exception,ex: # ignore any f*****g exceptions pass return result _columns = { 'datas_checksum': fields.function(_datas_checksum, size=40, string="Datas checksum", type='char', store=True, select=True), 'website_url': fields.function(_website_url_get, string="Attachment URL", type='char'), 'datas_big': fields.function (_datas_big, type='binary', store=True, string="Resized file content"), 'mimetype': fields.char('Mime Type', readonly=True), } def _add_mimetype_if_needed(self, values): if values.get('datas_fname'): values['mimetype'] = mimetypes.guess_type(values.get('datas_fname'))[0] or 'application/octet-stream' def create(self, cr, uid, values, context=None): chk = self._compute_checksum(values) if chk: match = self.search(cr, uid, [('datas_checksum', '=', chk)], context=context) if match:
class sale_order(osv.osv): _inherit = "sale.order" def _get_default_warehouse(self, cr, uid, context=None): company_id = self.pool.get('res.users')._get_company(cr, uid, context=context) warehouse_ids = self.pool.get('stock.warehouse').search( cr, uid, [('company_id', '=', company_id)], context=context) if not warehouse_ids: return False return warehouse_ids[0] def _get_shipped(self, cr, uid, ids, name, args, context=None): res = {} for sale in self.browse(cr, uid, ids, context=context): group = sale.procurement_group_id if group: res[sale.id] = all([ proc.state in ['cancel', 'done'] for proc in group.procurement_ids ]) else: res[sale.id] = False return res def _get_orders(self, cr, uid, ids, context=None): res = set() for move in self.browse(cr, uid, ids, context=context): if move.procurement_id and move.procurement_id.sale_line_id: res.add(move.procurement_id.sale_line_id.order_id.id) return list(res) def _get_orders_procurements(self, cr, uid, ids, context=None): res = set() for proc in self.pool.get('procurement.order').browse(cr, uid, ids, context=context): if proc.state == 'done' and proc.sale_line_id: res.add(proc.sale_line_id.order_id.id) return list(res) def _get_picking_ids(self, cr, uid, ids, name, args, context=None): res = {} for sale in self.browse(cr, uid, ids, context=context): if not sale.procurement_group_id: res[sale.id] = [] continue res[sale.id] = self.pool.get('stock.picking').search( cr, uid, [('group_id', '=', sale.procurement_group_id.id)], context=context) return res def _prepare_order_line_procurement(self, cr, uid, order, line, group_id=False, context=None): vals = super(sale_order, self)._prepare_order_line_procurement(cr, uid, order, line, group_id=group_id, context=context) location_id = order.partner_shipping_id.property_stock_customer.id vals['location_id'] = location_id routes = line.route_id and [(4, line.route_id.id)] or [] vals['route_ids'] = routes vals[ 'warehouse_id'] = order.warehouse_id and order.warehouse_id.id or False vals['partner_dest_id'] = order.partner_shipping_id.id return vals _columns = { '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.""" ), 'shipped': fields.function(_get_shipped, string='Delivered', type='boolean', store={ 'procurement.order': (_get_orders_procurements, ['state'], 10) }), 'warehouse_id': fields.many2one('stock.warehouse', 'Warehouse', required=True), 'picking_ids': fields.function(_get_picking_ids, method=True, type='one2many', relation='stock.picking', string='Picking associated to this sale'), } _defaults = { 'warehouse_id': _get_default_warehouse, 'picking_policy': 'direct', 'order_policy': 'manual', } def onchange_warehouse_id(self, cr, uid, ids, warehouse_id, context=None): val = {} if warehouse_id: warehouse = self.pool.get('stock.warehouse').browse( cr, uid, warehouse_id, context=context) if warehouse.company_id: val['company_id'] = warehouse.company_id.id return {'value': val} 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_all') 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_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): move_obj = self.pool.get("stock.move") 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': for picking in order.picking_ids: move_obj.write(cr, uid, [x.id for x in picking.move_lines], {'invoice_state': 'invoiced'}, context=context) return res def action_cancel(self, cr, uid, ids, context=None): if context is None: context = {} sale_order_line_obj = self.pool.get('sale.order.line') proc_obj = self.pool.get('procurement.order') stock_obj = self.pool.get('stock.picking') 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.' )) stock_obj.signal_workflow(cr, uid, [p.id for p in sale.picking_ids], 'button_cancel') 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 _get_date_planned(self, cr, uid, order, line, start_date, context=None): date_planned = super(sale_order, self)._get_date_planned(cr, uid, order, line, start_date, context=context) date_planned = (date_planned - timedelta(days=order.company_id.security_lead) ).strftime(DEFAULT_SERVER_DATETIME_FORMAT) return date_planned def _prepare_procurement_group(self, cr, uid, order, context=None): res = super(sale_order, self)._prepare_procurement_group(cr, uid, order, context=None) res.update({'move_type': order.picking_policy}) return res def action_ship_end(self, cr, uid, ids, context=None): super(sale_order, self).action_ship_end(cr, uid, ids, context=context) 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 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
class hr_employee(orm.Model): _description = "Employee" _inherit = 'hr.employee' def _get_assigned_letters(self, cr, uid, ids, prop, unknow_none, context=None): if not len(ids): return {} model_name = super(hr_employee, self)._name res = [] try: for id in ids: letter_ids = [] ref_ids = self.pool['letter.ref'].search(cr, uid, [('int_ref', '=', model_name + ',' + str(id))], context=context) if ref_ids: for ref in self.pool['letter.ref'].read(cr, uid, ref_ids, context=context): letter_ids.append(ref['letter_id'][0]) res.append((id, letter_ids)) except Exception, e: _logger.error(repr(traceback.extract_tb(sys.exc_traceback))) return dict(res) _columns = { 'letter_ids': fields.function(_get_assigned_letters, method=True, string='Letter', type='one2many', relation="res.letter"), }
class sale_order_line(osv.osv): _inherit = 'sale.order.line' 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 _columns = { 'product_packaging': fields.many2one('product.packaging', 'Packaging'), 'number_packages': fields.function(_number_packages, type='integer', string='Number Packages'), 'route_id': fields.many2one('stock.location.route', 'Route', domain=[('sale_selectable', '=', True)]), } _defaults = { 'product_packaging': False, } 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'].get( 'message', '') or '' products = product_obj.browse(cr, uid, product, context=context) if not products.packaging_ids: packaging = result['product_packaging'] = False 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_with_wh(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, warehouse_id=False, context=None): context = context or {} product_uom_obj = self.pool.get('product.uom') product_obj = self.pool.get('product.product') warning = {} res = 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) # 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 '' if product_obj.type == 'product': #determine if the product is MTO or not (for a further check) isMto = False if warehouse_id: warehouse = self.pool.get('stock.warehouse').browse( cr, uid, warehouse_id, context=context) for product_route in product_obj.route_ids: if warehouse.mto_pull_id and warehouse.mto_pull_id.route_id and warehouse.mto_pull_id.route_id.id == product_route.id: isMto = True break else: try: mto_route_id = self.pool.get('ir.model.data').get_object( cr, uid, 'stock', 'route_warehouse0_mto').id except: # if route MTO not found in ir_model_data, we treat the product as in MTS mto_route_id = False if mto_route_id: for product_route in product_obj.route_ids: if product_route.id == mto_route_id: isMto = True break #check if product is available, and if not: raise a warning, but do this only for products that aren't processed in MTO if not isMto: uom_record = False if uom: uom_record = product_uom_obj.browse(cr, uid, uom, context=context) if product_obj.uom_id.category_id.id != uom_record.category_id.id: uom_record = False if not uom_record: uom_record = product_obj.uom_id compare_qty = float_compare( product_obj.virtual_available, qty, precision_rounding=uom_record.rounding) if compare_qty == -1: warn_msg = _('You plan to sell %.2f %s but you only have %.2f %s available !\nThe real stock is %.2f %s. (without reservations)') % \ (qty, uom_record.name, max(0,product_obj.virtual_available), uom_record.name, max(0,product_obj.qty_available), uom_record.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
'tml_source':fields.selection([ ('database','Database'), ('file','File'), ('parser','Parser'), ],'Template source', select=True), 'parser_def': fields.text('Parser Definition'), 'parser_loc':fields.char('Parser location', size=128, help="Path to the parser location. Beginning of the path must be start with the module name!\nLike this: {module name}/{path to the parser.py file}"), 'parser_state':fields.selection([ ('default',_('Default')), ('def',_('Definition')), ('loc',_('Location')), ],'State of Parser', select=True), 'in_format': fields.selection(_get_in_mimetypes, 'Template Mime-type'), 'out_format':fields.many2one('report.mimetypes', 'Output Mime-type'), 'report_sxw_content': fields.function(_report_content, fnct_inv=_report_content_inv, method=True, type='binary', string='SXW content',), 'active':fields.boolean('Active', help='Disables the report if unchecked.'), 'report_wizard':fields.boolean('Report Wizard'), 'copies': fields.integer('Number of Copies'), 'fallback_false':fields.boolean('Disable Format Fallback'), 'xml_id': fields.function(_get_xml_id, type='char', size=128, string="XML ID", method=True, help="ID of the report defined in xml file"), 'extras': fields.function(_get_extras, method=True, type='char', size='256', string='Extra options'), 'deferred':fields.selection([ ('off',_('Off')), ('adaptive',_('Adaptive')), ],'Deferred', help='Deferred (aka Batch) reporting, for reporting on large amount of data.'), 'deferred_limit': fields.integer('Deferred Records Limit', help='Records limit at which you are invited to start the deferred process.'), 'replace_report_id':fields.many2one('ir.actions.report.xml', 'Replace Report'), 'wizard_id':fields.many2one('ir.actions.act_window', 'Wizard Action'),
class stock_picking(osv.osv): _inherit = "stock.picking" def _get_partner_to_invoice(self, cr, uid, picking, context=None): """ Inherit the original function of the 'stock' module We select the partner of the sales order as the partner of the customer invoice """ saleorder_ids = self.pool['sale.order'].search( cr, uid, [('procurement_group_id', '=', picking.group_id.id)], context=context) saleorders = self.pool['sale.order'].browse(cr, uid, saleorder_ids, context=context) if saleorders and saleorders[0]: saleorder = saleorders[0] return saleorder.partner_invoice_id.id return super(stock_picking, self)._get_partner_to_invoice(cr, uid, picking, context=context) def _get_sale_id(self, cr, uid, ids, name, args, context=None): sale_obj = self.pool.get("sale.order") res = {} for picking in self.browse(cr, uid, ids, context=context): res[picking.id] = False if picking.group_id: sale_ids = sale_obj.search( cr, uid, [('procurement_group_id', '=', picking.group_id.id)], context=context) if sale_ids: res[picking.id] = sale_ids[0] return res _columns = { 'sale_id': fields.function(_get_sale_id, type="many2one", relation="sale.order", string="Sale Order"), } def _create_invoice_from_picking(self, cr, uid, picking, vals, context=None): sale_obj = self.pool.get('sale.order') sale_line_obj = self.pool.get('sale.order.line') invoice_line_obj = self.pool.get('account.invoice.line') invoice_id = super(stock_picking, self)._create_invoice_from_picking(cr, uid, picking, vals, context=context) if picking.group_id: sale_ids = sale_obj.search( cr, uid, [('procurement_group_id', '=', picking.group_id.id)], context=context) if sale_ids: sale_line_ids = sale_line_obj.search( cr, uid, [('order_id', 'in', sale_ids), ('product_id.type', '=', 'service'), ('invoiced', '=', False)], context=context) if sale_line_ids: created_lines = sale_line_obj.invoice_line_create( cr, uid, sale_line_ids, context=context) invoice_line_obj.write(cr, uid, created_lines, {'invoice_id': invoice_id}, context=context) return invoice_id
class HrContract(orm.Model): _inherit = 'hr.contract' def _get_wage_ir(self, cr, uid, ids, fields, arg, context=None): res = {} obj_employee = self.pool.get('hr.employee') employee_ids = obj_employee.search(cr, uid, [('contract_ids.id', '=', ids[0])]) employees = obj_employee.browse(cr, uid, employee_ids, context=context) for employee in employees: for contract in employee.contract_ids: if employee_ids: INSS = (-482.93 if ((contract.wage) >= 4390.25) else -((contract.wage) * 0.11) if ((contract.wage) >= 2195.13) and ((contract.wage) <= 4390.24) else -( (contract.wage) * 0.09) if ((contract.wage) >= 1317.08) and ((contract.wage) <= 2195.12) else -( (contract.wage) * 0.08)) lane = (contract.wage - employee.n_dependent + INSS) first_lane = (-(0.275 * (lane) - 826.15)) l1 = Decimal(str(first_lane)) lane1 = l1.quantize(Decimal('1.10'), rounding=ROUND_DOWN) option_one = float(lane1) second_lane = (-(0.225 * (lane) - 602.96)) l2 = Decimal(str(second_lane)) lane2 = l2.quantize(Decimal('1.10'), rounding=ROUND_DOWN) option_two = float(lane2) third_lane = (-(0.150 * (lane) - 335.03)) l3 = Decimal(str(third_lane)) lane3 = l3.quantize(Decimal('1.10'), rounding=ROUND_DOWN) option_three = float(lane3) fourth_lane = (-(0.075 * (lane) - 134.08)) l4 = Decimal(str(fourth_lane)) lane4 = l4.quantize(Decimal('1.10'), rounding=ROUND_DOWN) option_four = float(lane4) if (lane >= 4463.81): res[ids[0]] = option_one return res elif (lane <= 4463.80) and (lane >= 3572.44): res[ids[0]] = option_two return res elif (lane <= 3572.43) and (lane >= 2679.30): res[ids[0]] = option_three return res elif (lane <= 2679.29) and (lane >= 1787.78): res[ids[0]] = option_four return res else: return 0 def _get_worked_days(self, cr, uid, ids, fields, arg, context=None): res = {} obj_worked_days = self.pool.get('hr.payslip.worked_days') worked_ids = obj_worked_days.search(cr, uid, [('contract_id', '=', ids[0])]) if worked_ids: worked = obj_worked_days.browse(cr, uid, worked_ids[0]) res[ids[0]] = worked.number_of_days return res else: res[ids[0]] = 0 return res def _check_date(self, cr, uid, ids, fields, arg, context=None): res = {} comp_date_from = time.strftime('%Y-04-01') comp_date_to = time.strftime('%Y-02-28') obj_payslip = self.pool.get('hr.payslip') payslip_ids = obj_payslip.search(cr, uid, [('contract_id', '=', ids[0]), ('date_from', '<', comp_date_from), ('date_to', '>', comp_date_to)]) if payslip_ids: res[ids[0]] = True return res else: res[ids[0]] = False return res def _check_voucher(self, cr, uid, ids, context=None): user = self.pool.get('res.users').browse(cr, uid, uid, context=context) for contract in self.browse(cr, uid, ids): if user.company_id.check_benefits: return True else: if contract.value_va == 0 or contract.value_vr == 0: return True else: return False return True _columns = { 'value_va': fields.float('Valley Food', help='Daily Value Benefit'), 'value_vr': fields.float('Meal valley', help='Daily Value Benefit'), 'workeddays': fields.function(_get_worked_days, type='float'), 'transportation_voucher': fields.float('Valley Transportation', help='Percentage of monthly deduction'), 'health_insurance_father': fields.float('Employee Health Plan', help='Health Plan of the Employee'), 'health_insurance_dependent': fields.float('Dependent Health Plan', help='Health Plan for Spouse and Dependents'), 'calc_date': fields.function(_check_date, type='boolean'), 'aditional_benefits': fields.float('Aditional Benefits', help='Others employee benefits'), 'ir_value': fields.function(_get_wage_ir, type="float", digits_compute=dp.get_precision('Payroll')), } _constraints = [[ _check_voucher, u'The company settings do not allow the use of food voucher and simultaneous meal', ['value_va', 'value_vr'] ]] _defaults = {'value_va': 0, 'value_vr': 0}
class account_invoice(osv.osv): def _amount_all(self, cr, uid, ids, name, args, context=None): ''' Calculer les montants : untaxed,tax,total,discount,undiscount et mettre à jour le montant en toute lettre @return:timbre @return:amount_untaxed @return:amount_tax @return:amount_total @return:discount_total @return:undiscount_total ''' res = {} var = 'Timbre' cr.execute('SELECT valeur FROM account_parametre WHERE designation=%s', (var, )) timbre = cr.dictfetchone()['valeur'] for invoice in self.browse(cr, uid, ids, context=context): res[invoice.id] = { 'timbre': 0.0, 'discount_total': 0.0, 'amount_untaxed': 0.0, 'undiscount_total': 0.0, 'amount_tax': 0.0, 'amount_total': 0.0, } for line in invoice.invoice_line: res[invoice.id]['discount_total'] += ( line.quantity * line.price_unit) - line.price_subtotal res[invoice.id]['amount_untaxed'] += line.price_subtotal res[invoice. id]['undiscount_total'] += line.quantity * line.price_unit for line in invoice.tax_line: res[invoice.id]['amount_tax'] += line.amount res[invoice.id]['amount_total'] = res[invoice.id]['amount_tax'] + res[ invoice.id]['amount_untaxed'] if invoice.partner_id.timbre == True and invoice.type == 'out_invoice' or invoice.type == 'in_refund': res[invoice.id]['amount_total'] += timbre res[invoice.id]['timbre'] = timbre if (invoice.partner_id.supplier == True and invoice.type == 'in_invoice'): res[invoice.id]['amount_total'] += timbre res[invoice.id]['timbre'] = timbre amount_word = "" if res[invoice.id]['amount_total'] != 0.0: amount_word = Number_To_Word.Number_To_Word( res[invoice.id]['amount_total'], 'fr', 'Dinars', 'Millimes', 3) cr.execute('UPDATE account_invoice SET amount_word=%s WHERE id=%s', (amount_word, invoice.id)) return res def _get_supplier_id(self, cr, uid): supplier_id = self.pool.get('stock.location').search( cr, uid, [('name', '=', 'Suppliers')])[0] return supplier_id def button_reset_taxes(self, cr, uid, ids, context=None): if context is None: context = {} ctx = context.copy() ait_obj = self.pool.get('account.invoice.tax') for id in ids: cr.execute( "DELETE FROM account_invoice_tax WHERE invoice_id=%s AND manual is False", (id, )) partner = self.browse(cr, uid, id, context=ctx).partner_id if partner.lang: ctx.update({'lang': partner.lang}) for taxe in ait_obj.compute(cr, uid, id, context=ctx).values(): ait_obj.create(cr, uid, taxe) # Update the stored value (fields.function), so we write to trigger recompute self.pool.get('account.invoice').write(cr, uid, ids, {'invoice_line': []}, context=ctx) return True def _amount_residual(self, cr, uid, ids, name, args, context=None): ''' TODO: This fuction is not in use, check the amount_total and residual problem first Ajouter le timbre au montant total lors de l'inirialisation du montant residual @return:residual ''' var = 'Timbre' cr.execute('SELECT valeur FROM account_parametre WHERE designation=%s', (var, )) timbre = cr.dictfetchone()['valeur'] result = {} for invoice in self.browse(cr, uid, ids, context=context): result[invoice.id] = 0.0 if invoice.move_id: for m in invoice.move_id.line_id: if ((m.account_id.type in ('receivable', 'payable')) and (invoice.partner_id.timbre == True)): result[ invoice.id] += m.amount_residual_currency + timbre elif m.account_id.type in ('receivable', 'payable'): result[ invoice.id] += m.amount_residual_currency + timbre return result def onchange_location_dest_id(self, cr, uid, ids, location_dest_id): return { 'domain': { 'cash_id': [('location_id', '=', location_dest_id), ('state', '=', 'open')] } } def action_date_assign(self, cr, uid, ids, *args): ''' Creer les mouvements de stocks pour les lignes de facture au comptant ''' for inv in self.browse(cr, uid, ids): res = self.onchange_payment_term_date_invoice( cr, uid, inv.id, inv.payment_term.id, inv.date_invoice) if res and res['value']: self.write(cr, uid, [inv.id], res['value']) todo_moves = [] for invoice_line in inv.invoice_line: if not invoice_line.product_id: continue if inv.type == 'in_invoice' or inv.type == 'out_refund': # location_id = 8 #Partner locations/Suppliers location_dest_id = 12 #Stock else: location_id = 12 #Stock location_dest_id = 9 #Partner locations/Customers if invoice_line.product_id.product_tmpl_id.type in ('consu'): move = self.pool.get('stock.move').create( cr, uid, { 'name': (invoice_line.name), 'product_id': invoice_line.product_id.id, 'location_id': location_id, 'location_dest_id': location_dest_id, 'partner_id': inv.partner_id.id, 'invoice_id': inv.id, 'product_uom_qty': invoice_line.quantity, 'product_uom': invoice_line.uos_id.id, 'product_uos': invoice_line.uos_id.id, 'state': 'done', 'price_unit': invoice_line.price_unit, 'picking_type_id': 1, }) if invoice_line.move_dest_id: self.pool.get('stock.move').write( cr, uid, [invoice_line.move_dest_id], ) todo_moves.append(move) return True @api.multi def invoice_validate(self): self._cr.execute( "SELECT amount_total FROM account_invoice WHERE id =%s ", (self.id, )) reste_a_payer = self._cr.dictfetchone()['amount_total'] self._cr.execute( "UPDATE account_invoice SET reste_a_payer=%s WHERE id =%s ", ( reste_a_payer, self.id, )) return self.write({'state': 'open'}) def _get_invoice_tax(self, cr, uid, ids, context=None): result = {} for tax in self.pool.get('account.invoice.tax').browse( cr, uid, ids, context=context): result[tax.invoice_id.id] = True return result.keys() def _get_invoice_line(self, cr, uid, ids, context=None): result = {} for line in self.pool.get('account.invoice.line').browse( cr, uid, ids, context=context): result[line.invoice_id.id] = True return result.keys() def _get_invoice_from_line(self, cr, uid, ids, context=None): move = {} for line in self.pool.get('account.move.line').browse(cr, uid, ids, context=context): if line.reconcile_partial_id: for line2 in line.reconcile_partial_id.line_partial_ids: move[line2.move_id.id] = True if line.reconcile_id: for line2 in line.reconcile_id.line_id: move[line2.move_id.id] = True invoice_ids = [] if move: invoice_ids = self.pool.get('account.invoice').search( cr, uid, [('move_id', 'in', move.keys())], context=context) return invoice_ids def _get_invoice_from_reconcile(self, cr, uid, ids, context=None): move = {} for r in self.pool.get('account.move.reconcile').browse( cr, uid, ids, context=context): for line in r.line_partial_ids: move[line.move_id.id] = True for line in r.line_id: move[line.move_id.id] = True invoice_ids = [] if move: invoice_ids = self.pool.get('account.invoice').search( cr, uid, [('move_id', 'in', move.keys())], context=context) return invoice_ids _name = "account.invoice" _order = "id desc" _inherit = 'account.invoice' _columns = { 'amount_word': fields.char('Lettre', size=254, readonly=True), 'timbre': fields.function(_amount_all, digits_compute=dp.get_precision('Account'), string='Timbre', store=True, method=True, multi='all'), #'amount_word': fields.char('Lettre', size=254), 'undiscount_total': fields.function(_amount_all, digits_compute=dp.get_precision('Account'), string='Total sans remise', store=True, method=True, multi='all'), 'discount_total': fields.function(_amount_all, digits_compute=dp.get_precision('Account'), string='Total Remise', store=True, method=True, multi='all'), 'amount_tax': fields.function(_amount_all, digits_compute=dp.get_precision('Account'), string='Total taxe', store=True, method=True, multi='all'), 'amount_untaxed': fields.function(_amount_all, digits_compute=dp.get_precision('Account'), string='Total NHT', store=True, method=True, multi='all'), 'amount_total': fields.function(_amount_all, digits_compute=dp.get_precision('Account'), string='Total', store=True, method=True, multi='all'), 'date_invoice': fields.date('Invoice Date', required=True, readonly=True, states={'draft': [('readonly', False)]}), 'residual': fields.function(_amount_residual, method=True, digits_compute=dp.get_precision('Account'), string='Residual', store={ 'account.invoice': (lambda self, cr, uid, ids, c={}: ids, ['invoice_line', 'move_id', 'amount_total'], 50), 'account.invoice.tax': (_get_invoice_tax, None, 50), 'account.invoice.line': (_get_invoice_line, [ 'price_unit', 'invoice_line_tax_id', 'quantity', 'discount', 'invoice_id' ], 50), 'account.move.line': (_get_invoice_from_line, None, 50), 'account.move.reconcile': (_get_invoice_from_reconcile, None, 50), }, help="Remaining amount due."), 'location_dest_id': fields.many2one( 'stock.location', 'Destination Location', states={'open': [('readonly', True)]}, help="Location where the system will stock the finished products." ), 'location_src_id': fields.many2one('stock.location', 'Source Location', states={'open': [('readonly', True)]}), 'number_invoicing_picking': fields.char('Code Facture', size=32), 'montant_retenue': fields.float('Montant Retenue', digits_compute=dp.get_precision('Account')), 'reste_a_payer': fields.float('Reste à payer', digits_compute=dp.get_precision('Account'), readonly=True), }
fp = None try: fp = tools.file_open(report[name[:-8]], mode='rb') data = report['report_type'] == 'aeroo' and base64.encodestring(fp.read()) or fp.read() except IOError, e: if e.errno == 13: # Permission denied on the template file raise except_orm(_(e.strerror), e.filename) else: _logger.warning('IOERROR!', e) except Exception, e: _logger.warning('Exception!', e) fp = False data = False finally: if fp: fp.close() res[report['id']] = data return res def _report_content_inv(self, cr, uid, rec_id, name, value, arg, context=None): if value: self.write(cr, uid, rec_id, {name + '_data': value}, context=context) _columns = { 'report_sxw_content': old_fields.function(_report_content, fnct_inv=_report_content_inv, method=True, type='binary', string='SXW content'), } # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
class base_price_change_order(osv.osv): def do_change_list_price(self, cr, uid, ids, context=None): if context is None: context = {} context.update({ 'active_ids': ids, }) return { 'view_type': 'form', 'view_mode': 'form', 'res_model': 'okgj.list.price.change.base.price', 'type': 'ir.actions.act_window', 'target': 'new', 'context': context, } def _get_warehouse_id(self, cr, uid, context=None): user_data = self.pool.get('res.users').browse(cr,uid, uid, context=context) warehouse_id = False for one_warehouse in user_data.warehouse_ids: warehouse_id = one_warehouse.id if warehouse_id: break return warehouse_id def _get_purchase_price(self, cr, uid, ids, fields_name, arg, context=None): if context is None: context = {} res = {}.fromkeys(ids, 0.0) purchase_line_obj = self.pool.get('purchase.order.line') for record in self.browse(cr, uid, ids, context=context): purchase_line_ids = purchase_line_obj.search(cr , uid, [ ('product_id','=', record.product_id.id), ('state', 'in', ['confirmed', 'done']) ], order='create_date DESC', context=context, limit=1) if purchase_line_ids: res[record.id] = purchase_line_obj.browse(cr, uid, purchase_line_ids[0], context=context).price_unit return res def _get_approve_state(self, cr, uid, ids, fields_name, arg, context=None): if context is None: context = {} res = {}.fromkeys(ids, False) line_obj = self.pool.get('okgj.base.price.change.line') for record in self.browse(cr, uid, ids, context=context): if record.price_change_line_ids: res[record.id] = 'done' for one_line in record.price_change_line_ids: if one_line.state != 'confirmed': res[record.id] = 'wait_approve' break return res def _approve_state_search(self, cr, uid, obj, name, args, domain=None, context=None): if context is None: context = {} res_ids = self.search(cr, uid, [], context=context) result = self._get_approve_state(cr, uid, res_ids, 'approve_state', '', context) if not args: return [('id', 'in', res_ids)] filter_state = args[0][2] approve_ids = [key for key in result if result[key] == filter_state] if not approve_ids: return [('id', '=', '0')] return [('id', 'in', approve_ids)] _inherit = 'okgj.base.price.change' _description = 'OKGJ Sale Price Change' _order = 'create_date DESC' _columns = { 'create_uid':fields.many2one('res.users', u'创建人', readonly=True), 'create_date':fields.datetime(u'创建日期', readonly=True), 'write_uid':fields.many2one('res.users', u'修改人', readonly=True), 'write_date':fields.datetime(u'修改日期', readonly=True), 'warehouse_id':fields.many2one('stock.warehouse', u'物流中心', required=True, select=True, states={'draft':[('readonly', False)]}, readonly=True), 'product_id':fields.many2one('product.product', u'商品', required=True, select=True, states={'draft':[('readonly', False)]}, readonly=True), 'standard_price':fields.related('product_id', 'standard_price', string=u'成本价', type='float', readonly=True), 'list_price':fields.related('product_id', 'list_price', string=u'会员价', type='float', readonly=True), 'okkg_price':fields.related('product_id', 'okkg_price', string=u'快购价', type='float', readonly=True), 'other_price':fields.related('product_id', 'other_price', string=u'市场价', type='float', readonly=True), 'recent_purchase_price':fields.function(_get_purchase_price, type='float', string=u'最近采购价', readonly=True), ## 'standard_price':fields.float(u'成本价', digits_compute=dp.get_precision('Product Price'), states={'draft':[('readonly', False)],'reedit':[('readonly', False)]}, readonly=True), ## 'okkg_price':fields.float(u'快购价', digits_compute=dp.get_precision('Product Price'), states={'draft':[('readonly', False)],'reedit':[('readonly', False)]}, readonly=True), ## 'other_price':fields.float(u'市场价', digits_compute=dp.get_precision('Product Price'), states={'draft':[('readonly', False)],'reedit':[('readonly', False)]}, readonly=True), ## 'recent_purchase_price':fields.float(u'最近采购价', digits_compute=dp.get_precision('Product Price'), states={'draft':[('readonly', False)],'reedit':[('readonly', False)]}, readonly=True,), 'price_change_line_ids':fields.one2many('okgj.base.price.change.line', 'base_price_change_id', u'价格更改明细', states={'draft':[('readonly', False)],'reedit':[('readonly', False)]}, readonly=True), 'state':fields.selection([('draft', u'草稿'), ('reedit', u'再编辑'),('confirmed', u'已确认')], u'状态', readonly=True), 'approve_state':fields.function(_get_approve_state, fnct_search=_approve_state_search, type='selection', string='审批状态', selection=[('wait_approve', u'待审批'), ('done', u'已审批')]), 'name_template': fields.related('product_id', 'name_template', type='char', size=128, store=True, select=True, string="Template Name"), 'default_code': fields.related('product_id', 'default_code', type='char', size=128, store=True, select=True, string="Product default code"), } _defaults = { 'warehouse_id': _get_warehouse_id, 'state': lambda *a:'draft', } def onchange_product_id(self, cr, uid, ids, product_id, warehouse_id, context=None): if context is None: context = {} res = {} if not (product_id and warehouse_id): return res product_obj = self.pool.get('product.product') purchase_line_obj = self.pool.get('purchase.order.line') change_line_obj = self.pool.get('okgj.base.price.change.line') product_data = product_obj.browse(cr, uid, product_id, context=context) other_price = product_data.other_price okkg_price = product_data.okkg_price standard_price = product_data.standard_price list_price = product_data.list_price ## 多物流中心 ## standard_price = product_obj.get_okgj_product_warehouse_cost(cr, uid, warehouse_id, product_id, context=context)[product_id] #最近采购价 purchase_line_ids = purchase_line_obj.search(cr , uid, [ ('product_id','=', product_id), ('state', 'in', ['confirmed', 'done']) ], order='create_date DESC', context=context, limit=1) recent_purchase_price = 0 if purchase_line_ids: recent_purchase_price = purchase_line_obj.browse(cr, uid, purchase_line_ids[0], context=context).price_unit res = {'value': {'standard_price':standard_price, 'list_price':list_price, 'other_price': other_price, 'okkg_price':okkg_price, 'recent_purchase_price':recent_purchase_price, }} return res ## 上传 def action_upload_all(self, cr, uid, ids, context=None): if context is None: context ={} if isinstance(ids, (int, long)): ids = [ids] line_obj = self.pool.get('okgj.base.price.change.line') for one_order in self.browse(cr, uid, ids, context=context): for one_line in one_order.price_change_line_ids: line_obj.action_upload_line(cr, uid, one_line.id, context=context) self.write(cr, uid, ids, {'state': 'confirmed'}, context=context) return True def action_reedit(self, cr, uid, ids, context=None): if context is None: context ={} if isinstance(ids, (int, long)): ids = [ids] line_obj = self.pool.get('okgj.base.price.change.line') for one_order in self.browse(cr, uid, ids, context=context): for one_line in one_order.price_change_line_ids: line_obj.action_reedit_line(cr, uid, one_line.id, context=context) self.write(cr, uid, ids, {'state': 'reedit'}, context=context) return True
'ActionHelp': menu.action.help, 'ModuleName': data_id.module, 'XmlId': data_id.name}, context=context)) res_mod_dic[ 'doc_on_module'].append(self.title_help(cr, uid, mnames[ data_id.module], data_id.module, context=context)) except KeyError, e: self.__logger.warning( 'Data not found for reference %s[%s:%s.%s]', data_id.model, data_id.res_id, data_id.model, data_id.name, exc_info=True) except Exception, e: self.__logger.warning('Unknown error while browsing %s[%s]', data_id.model, data_id.res_id, exc_info=True) # res_mod_dic['doc_on_module']=list(set(res_mod_dic['doc_on_module'])) for key, value in res.iteritems(): for k, v in res[key].iteritems(): # TODO Make Generic or with regEx # Putting title on the begining. txt = "\n".join(sorted(v[:len(v) - 2])) res[key][k] = txt return res _columns = { 'doc_on_module': fields.function(_get_docs, method=True, string='Documentation', type='text', multi="meta", store=False), }
class base_price_change_line(osv.osv): _name = 'okgj.base.price.change.line' _description = 'OKGJ Sale Price Change Line' _order = 'product_id desc, product_qty asc' def _price_state_search(self, cr, uid, obj, name, args, domain=None, context=None): if context is None: context = {} if not args: return [] res_ids = self.search(cr, uid, [], context=context) price_state = args[0][2] price_data = self._get_price(cr, uid, res_ids, 'price_state', '', context=context) new_ids = [line_id for line_id in price_data if price_data[line_id].get('price_state', '') == price_state] if not new_ids: return [('id', '=', '0')] return [('id', 'in', new_ids)] def _get_price(self, cr, uid, ids, field_names, arg, context=None): if context is None: context = {} result = {}.fromkeys(ids, 0) product_obj = self.pool.get('product.product') for one_line in self.browse(cr, uid, ids, context=context): if one_line.product_id: min_price = one_line.product_id.okgj_cost_price * one_line.product_qty max_price = one_line.product_id.other_price * one_line.product_qty if one_line.product_price < min_price: price_state = '1' elif one_line.product_price > max_price: price_state = '2' else: price_state = '3' result[one_line.id] = { 'min_price':min_price, 'max_price':max_price, 'price_state':price_state, } return result def _get_purchase_price(self, cr, uid, ids, fields_name, arg, context=None): if context is None: context = {} res = {}.fromkeys(ids, 0.0) purchase_line_obj = self.pool.get('purchase.order.line') for record in self.browse(cr, uid, ids, context=context): purchase_line_ids = purchase_line_obj.search(cr , uid, [ ('product_id','=', record.product_id.id), ('state', 'in', ['confirmed', 'done']) ], order='create_date DESC', context=context, limit=1) if purchase_line_ids: res[record.id] = purchase_line_obj.browse(cr, uid, purchase_line_ids[0], context=context).price_unit return res def _get_warehouse_id(self, cr, uid, context=None): """ 依用户ID返回用户的第一个物流中心 """ user_data = self.pool.get('res.users').browse(cr,uid, uid, context=context) warehouse_id = False for one_warehouse in user_data.warehouse_ids: warehouse_id = one_warehouse.id if warehouse_id: break return warehouse_id def verify_list_price(self, cr, uid, product_id, new_list_price, warehouse_id=None, context=None): """ 商品调OK价时验证是否可调 """ product_obj = self.pool.get('product.product') cost_price = product_obj.read(cr, uid, product_id, ['standard_price'], context=context)['standard_price'] ## 多物流中心上线 ## cost_price = product_obj.get_okgj_product_warehouse_cost(cr, uid, warehouse_id, product_id, context=context)[product_id] if warehouse_id: line_ids = self.search(cr, uid, [ ('product_id', '=', product_id), ('warehouse_id', '=', warehouse_id) ], order='product_price_unit ASC', context=context) else: line_ids = self.search(cr, uid, [ ('product_id', '=', product_id), ], order='product_price_unit ASC', context=context) if line_ids: adjust_ratio = self.read(cr, uid, line_ids[0], ['adjust_ratio'], context=context)['adjust_ratio'] lowest_new_unit_price = new_list_price * adjust_ratio if lowest_new_unit_price < cost_price: return False return True def update_list_price(self, cr, uid, product_id, new_list_price, warehouse_id=None, context=None): """ 商品调会员价时自动按比例更新组合价格并上传 """ product_obj = self.pool.get('product.product') if warehouse_id: line_ids = self.search(cr, uid, [ ('product_id', '=', product_id), ('warehouse_id', '=', warehouse_id) ], context=context) else: line_ids = self.search(cr, uid, [ ('product_id', '=', product_id), ], context=context) for one_line in self.browse(cr, uid, line_ids, context=context): adjust_ratio = one_line.adjust_ratio qty = one_line.product_qty new_unit_price = adjust_ratio * new_list_price new_total_price = adjust_ratio * new_list_price * qty self.write(cr, uid, one_line.id, { 'product_price_unit':new_unit_price, 'product_price':new_total_price, }, context=context) if one_line.state in ['confirmed']: self.action_upload_line(cr, uid, one_line.id, context=context) return True _inherit = ['mail.thread', 'ir.needaction_mixin'] _columns = { 'create_uid':fields.many2one('res.users', u'创建人', readonly=True), 'create_date':fields.datetime(u'创建日期', readonly=True), 'base_price_change_id':fields.many2one('okgj.base.price.change', u'价格调整单号', ondelete='cascade', states={'draft':[('readonly', False)]}, readonly=True), 'warehouse_id':fields.many2one('stock.warehouse', u'物流中心', select=True, states={'draft':[('readonly', False)]}, readonly=True), 'product_id':fields.many2one('product.product', u'商品', select=True, required=True, states={'draft':[('readonly', False)]}, readonly=True), 'name_template': fields.related('product_id', 'name_template', type='char', size=128, store=True, select=True, string="Template Name"), 'default_code': fields.related('product_id', 'default_code', type='char', size=128, store=True, select=True, string="Product default code"), 'list_price':fields.related('product_id', 'list_price', string=u'会员价', type='float', readonly=True), 'okkg_price':fields.related('product_id', 'okkg_price', string=u'快购价', type='float', readonly=True), 'other_price':fields.related('product_id', 'other_price', string=u'市场价', type='float', readonly=True), 'recent_purchase_price':fields.function(_get_purchase_price, type='float', string=u'最近采购价', readonly=True), 'product_qty':fields.integer(u'数量', required=True, track_visibility='onchange', states={'draft':[('readonly', False)]}, readonly=True), 'adjust_ratio':fields.float(u'调价比率',digits_compute=dp.get_precision('Product Price'), states={'draft':[('readonly', False)],'reedit':[('readonly', False)]}, readonly=True, required=True), 'product_price_unit':fields.float(u'单位价格', digits_compute=dp.get_precision('Product Price'), required=True, track_visibility='onchange', states={'draft':[('readonly', False)],'reedit':[('readonly', False)]}, readonly=True), 'product_price':fields.float(u'总价', digits_compute=dp.get_precision('Product Price'), required=True, track_visibility='onchange', states={'draft':[('readonly', False)],'reedit':[('readonly', False)]}, readonly=True), 'state': fields.selection([ ('draft', u'草稿'), ('reedit', u'再编辑'), ('confirmed', u'确认'), ('need_reedit', u'驳回'), ], u'状态', required=True, readonly=True, track_visibility='onchange'), 'min_price':fields.function(_get_price, type='float', string=u'最低价', digits_compute=dp.get_precision('Product Price'), multi='get_price'), 'max_price':fields.function(_get_price, type='float', string=u'最高价', digits_compute=dp.get_precision('Product Price'), multi='get_price'), 'price_state':fields.function(_get_price, type='selection', string=u'价格状态', fnct_search=_price_state_search, selection=[('1', u'低于成本价'), ('2',u'高于市场价'), ('3',u'正常')], multi='get_price'), } def _check_repeat(self, cr, uid, ids, context=None): """ 一个物流中心内同商品同数量的记录只能有一条 """ if context is None: context={} for line in self.browse(cr, uid, ids, context=context): has_exist = self.search(cr, uid, [ ('warehouse_id', '=', line.warehouse_id.id), ('product_id', '=', line.product_id.id), ('product_qty', '=', line.product_qty), ], context=context) if len(has_exist) > 1: return False return True _constraints = [(_check_repeat, u'错误,该物流中心已存在同样数量的商品', [u'商品, 数量, 物流中心'])] _defaults = { 'warehouse_id': _get_warehouse_id, 'adjust_ratio': lambda self, cr, uid, context: 1, 'state':lambda self, cr, uid, context:'draft', } def create(self, cr, uid, vals, context=None): base_price_change_id = vals.get('base_price_change_id', False) if base_price_change_id: price_change_obj = self.pool.get('okgj.base.price.change') price_change_data = price_change_obj.browse(cr, uid, base_price_change_id, context=context) vals.update({ 'product_id':price_change_data.product_id.id, 'warehouse_id':price_change_data.warehouse_id.id, }) return super(base_price_change_line, self).create(cr, uid, vals, context=context) def onchange_product_qty_ratio(self, cr, uid, ids, product_id, product_qty, adjust_ratio, context=None): """ 通过变换商品或数量调整价格 """ if context is None: context = {} if not (product_id and product_qty): return {} adjust_ratio = adjust_ratio or 1 list_price = self.pool.get('product.product').read(cr, uid, product_id, ['list_price'])['list_price'] sale_price_unit = list_price * adjust_ratio or 0 sale_price = list_price * product_qty * adjust_ratio or 0 sale_price = sale_price_rounding(sale_price) res = {'value' : { 'product_price_unit': sale_price_unit, 'product_price': sale_price} } return res def onchange_product_price_unit(self, cr, uid, ids, product_id, product_qty, product_price_unit, context=None): """ 通过基础调整比例与总价 """ if context is None: context = {} if not (product_id and product_qty and product_price_unit): return {} list_price = self.pool.get('product.product').read(cr, uid, product_id, ['list_price'])['list_price'] if list_price <= 0: return {} adjust_ratio = product_price_unit / list_price sale_price = product_price_unit * product_qty sale_price = sale_price_rounding(sale_price) res = {'value' : { 'adjust_ratio': adjust_ratio, 'product_price': sale_price} } return res def onchange_product_price(self, cr, uid, ids, product_id, product_qty, product_price, context=None): """ 通过总价调整比率与单价 """ if context is None: context = {} if not (product_id and product_qty and product_price): return {} list_price = self.pool.get('product.product').read(cr, uid, product_id, ['list_price'])['list_price'] if list_price <= 0: return {} adjust_ratio = product_price / (product_qty * list_price) sale_price_unit = product_price / product_qty res = {'value' : { 'adjust_ratio': adjust_ratio, 'product_price_unit': sale_price_unit, } } return res def action_upload_line(self, cr, uid, ids, context=None): self.write(cr, uid, ids, {'state': 'confirmed'}, context=context) return True def action_reedit_line(self, cr, uid, ids, context=None): self.write(cr, uid, ids, {'state': 'reedit'}, context=context) return True def action_need_reedit_line(self, cr, uid, ids, context=None): self.write(cr, uid, ids, {'state': 'need_reedit'}, context=context) return True
# direct access to the m2m table is the less convoluted way to achieve this (and is ok ACL-wise) cr.execute("""SELECT DISTINCT sol.id FROM sale_order_invoice_rel rel JOIN sale_order_line sol ON (sol.order_id = rel.order_id) WHERE rel.invoice_id = ANY(%s)""", (list(ids),)) return [i[0] for i in cr.fetchall()] _name = 'sale.order.line' _description = 'Sales Order Line' _columns = { 'order_id': fields.many2one('sale.order', 'Order Reference', required=True, ondelete='cascade', select=True, readonly=True, states={'draft':[('readonly',False)]}), 'name': fields.text('Description', required=True, readonly=True, states={'draft': [('readonly', False)]}), 'sequence': fields.integer('Sequence', help="Gives the sequence order when displaying a list of sales order lines."), 'product_id': fields.many2one('product.product', 'Product', domain=[('sale_ok', '=', True)], change_default=True), 'invoice_lines': fields.many2many('account.invoice.line', 'sale_order_line_invoice_rel', 'order_line_id', 'invoice_id', 'Invoice Lines', readonly=True), 'invoiced': fields.function(_fnct_line_invoiced, string='Invoiced', type='boolean', store={ 'account.invoice': (_order_lines_from_invoice, ['state'], 10), 'sale.order.line': (lambda self,cr,uid,ids,ctx=None: ids, ['invoice_lines'], 10)}), 'price_unit': fields.float('Unit Price', required=True, digits_compute= dp.get_precision('Product Price'), readonly=True, states={'draft': [('readonly', False)]}), 'type': fields.selection([('make_to_stock', 'from stock'), ('make_to_order', 'on order')], 'Procurement Method', required=True, readonly=True, states={'draft': [('readonly', False)]}, help="From stock: When needed, the product is taken from the stock or we wait for replenishment.\nOn order: When needed, the product is purchased or produced."), 'price_subtotal': fields.function(_amount_line, string='Subtotal', digits_compute= dp.get_precision('Account')), 'tax_id': fields.many2many('account.tax', 'sale_order_tax', 'order_line_id', 'tax_id', 'Taxes', readonly=True, states={'draft': [('readonly', False)]}), 'address_allotment_id': fields.many2one('res.partner', 'Allotment Partner',help="A partner to whom the particular product needs to be allotted."), 'product_uom_qty': fields.float('Quantity', digits_compute= dp.get_precision('Product UoS'), 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'), 'discount': fields.float('Discount (%)', digits_compute= dp.get_precision('Discount'), readonly=True, states={'draft': [('readonly', False)]}), 'th_weight': fields.float('Weight', readonly=True, states={'draft': [('readonly', False)]}), 'state': fields.selection([('cancel', 'Cancelled'),('draft', 'Draft'),('confirmed', 'Confirmed'),('exception', 'Exception'),('done', 'Done')], 'Status', required=True, readonly=True, help='* The \'Draft\' status is set when the related sales order in draft status. \
path = addons.get_module_resource(module.name, 'static', 'src', 'img', '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", size=128, readonly=True, required=True, select=True), 'category_id': fields.many2one('ir.module.category', 'Category', readonly=True, select=True), 'shortdesc': fields.char('Module Name', size=64, readonly=True, translate=True), 'summary': fields.char('Summary', size=64, 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", 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 refer the latest version (the one on disk) # latest_version refer the installed version (the one in database) # published_version refer 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),
def get_counter(self,cr,uid,context=None): myids = self.search(cr, uid, [], context=context) for user in self.browse(cr,uid,myids,context=context): res = user.counter +1; isTrue = self.write(cr, uid, user.id, {'counter': res}, context=context) return isTrue _name = "saas.user.info" _description = "saas.user.info" _columns = { 'name': fields.char('Note', required=False,track_visibility='always', help=""), 'user': fields.many2one('res.partner', 'partner', help=""), 'host_name': fields.char('host_name',required=True, help=""), 'host_type': fields.char('host_type',required=False , help=""), 'server': fields.many2one('saas.server', 'server',required=True, help=""), 'url_addres': fields.function(_get_full_url, type='char',string='url_addres'), 'start_date': fields.datetime('start_date',required=False, help=""), 'end_date': fields.function(_compute_exp_date, type = 'datetime',string='end_date'), 'product_id':fields.many2one('product.product','product_id',required = False,help=''), 'state': fields.function(_get_server_state, type='char', string='state'), 'counter': fields.integer('counter',required=False , help=""), } _defaults = { 'start_date': fields.datetime.now, } _sql_constraints = [ ('host_name_uniq', 'unique (host_name)', 'host_name must be unique !'), ] class saas_server(osv.osv): _inherit = ['mail.thread']
class account_move_line(osv.osv): def _is_payment_schedule(self, cr, uid, ids, fieldnames, args, context=None): result = dict.fromkeys(ids, 0) for record in self.browse(cr, uid, ids, context=context): # Display only record with following conditions if record.account_id.type in ('payable', 'receivable') \ and not record.reconcile_id \ and (record.date_maturity or not record.reconcile_partial_id): result[record.id] = True else: result[record.id] = False return result def _amount_residual2(self, cr, uid, ids, field_names, args, context=None): res = {} cr.execute("select id from account_account where type = 'liquidity'") cash_ids = map(lambda x: x[0], cr.fetchall()) begin_balance = self.pool.get( 'account.account').get_total_account_balance_ex( cr, uid, cash_ids, ['balance']) if context is None: context = {} cur_obj = self.pool.get('res.currency') for move_line in self.browse(cr, uid, ids, context=context): res[move_line.id] = { 'amount_begin_balance': 0.0, 'amount_residual2': 0.0, 'amount_residual_currency2': 0.0, 'amount_end_balance': 0.0, } if move_line.currency_id: move_line_total = move_line.amount_currency else: move_line_total = move_line.debit - move_line.credit line_total_in_company_currency = move_line.debit - move_line.credit context_unreconciled = context.copy() if move_line.reconcile_partial_id: for payment_line in move_line.reconcile_partial_id.line_partial_ids: if payment_line.id == move_line.id: continue if payment_line.currency_id and move_line.currency_id and payment_line.currency_id.id == move_line.currency_id.id: move_line_total += payment_line.amount_currency else: if move_line.currency_id: context_unreconciled.update( {'date': payment_line.date}) amount_in_foreign_currency = cur_obj.compute( cr, uid, move_line.company_id.currency_id.id, move_line.currency_id.id, (payment_line.debit - payment_line.credit), round=False, context=context_unreconciled) move_line_total += amount_in_foreign_currency else: move_line_total += (payment_line.debit - payment_line.credit) line_total_in_company_currency += (payment_line.debit - payment_line.credit) result = move_line_total res[move_line.id]['amount_begin_balance'] = begin_balance res[move_line.id][ 'amount_residual_currency2'] = move_line.currency_id and self.pool.get( 'res.currency').round(cr, uid, move_line.currency_id, result) or result res[move_line. id]['amount_residual2'] = line_total_in_company_currency ending_balance = begin_balance + line_total_in_company_currency res[move_line.id]['amount_end_balance'] = ending_balance begin_balance = ending_balance return res def _get_move_line(self, cr, uid, ids, context=None): """ return all account_move_line for the same partner_id of the updated account_voucher """ move_line_ids = [] for voucher in self.browse(cr, uid, ids, context=context): move_line_ids += self.pool.get('account.move.line').search( cr, uid, [('id', 'in', [line.move_line_id.id for line in voucher.line_ids])], context=context) return move_line_ids _inherit = 'account.move.line' _order = 'date_maturity, id' _columns = { 'is_payment_schedule': fields.function(_is_payment_schedule, type='boolean', string='Is Payment Schedule', store={ 'account.move.line': (lambda self, cr, uid, ids, c={}: ids, None, 10), 'account.voucher': (_get_move_line, ['state'], 10) }), 'amount_begin_balance': fields.function(_amount_residual2, type='float', digits_compute=dp.get_precision('Account'), string='Begin Balance', multi="residual"), 'amount_residual_currency2': fields.function(_amount_residual2, type='float', digits_compute=dp.get_precision('Account'), string='Residual Amount Currency', multi="residual"), 'amount_residual2': fields.function(_amount_residual2, type='float', digits_compute=dp.get_precision('Account'), string='Residual Amount', multi="residual"), 'amount_end_balance': fields.function(_amount_residual2, type='float', digits_compute=dp.get_precision('Account'), string='End Balance', multi="residual"), } def init(self, cr): # Only when first install, update the is_payment_schedule status. cr.execute("update account_move_line m1 \ set is_payment_schedule = \ (select case when type in ('payable','receivable') \ and reconcile_id is null \ and (date_maturity is not null or reconcile_partial_id is null) \ then true else false end \ from account_move_line m2 \ inner join account_account a on m2.account_id = a.id \ where m2.id = m1.id)\ where is_payment_schedule is null")
('cancel', 'Cancelled'), ('waiting_date', 'Waiting Schedule'), ('progress', 'Sales Order'), ('cc_auth', 'Draft Authorized'), ('manual', 'Sale to Invoice'), ('invoice_except', 'Invoice Exception'), ('shipping_except', 'Shipping Exception'), ('done', 'Done') ], 'Status', readonly=True, track_visibility='onchange', help="Gives the status of the quotation or sales order. \nThe exception status is automatically set when a cancel operation occurs in the processing of a document linked to the sales order. \nThe 'Waiting Schedule' status is set when the invoice is confirmed but waiting for the scheduler to run on the order date.", select=True), 'cc_pre_auth':fields.boolean('Creditcard Pre-authorised'), 'rel_account_voucher_id':fields.many2one('account.voucher', 'Related Payment'), 'invoiced': fields.function(_invoiced, method=True, string='Paid', type='boolean', help="It indicates that an invoice has been paid.", store={ 'account.invoice' : (_get_invoice, ['state'], 20), 'sale.order' : (lambda self, cr, uid, ids, c={}: ids, ['state'], 20), 'account.voucher' : (_get_voucher, ['state'], 20), }), 'cc_ship_refund' : fields.boolean('Ship Refunded', readonly=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['rel_account_voucher_id'] = False default['cc_pre_auth'] = False default['cc_ship_refund'] = False
class NewReceiptLineWizard(orm.Model): ''' Wizard for New Receipt Wizard ''' _name = 'new.receipt.line.wizard' _vat_rate = 1.22 # TODO keep in parameter field! _decimal = 2 def onchange_move_prefilter_id(self, cr, uid, ids, pre_filter, context=None): ''' Force domain of product ''' res = { 'domain': {'product_id': []}, 'value': {}, } if pre_filter: res['domain']['product_id'].append( ('default_code', 'ilike', pre_filter)) #res['value']['pre_filter'] = False return res def onchange_product_id(self, cr, uid, ids, product_id, qty, context=None): ''' Change default price from product form ''' decimal = self._decimal res = {'value': {'price': 0.0}} if not product_id: return res product_pool = self.pool.get('product.product') product_proxy = product_pool.browse( cr, uid, product_id, context=context) if not product_id: return res # TODO change price? field_data = product_pool._get_metel_price_data( cr, uid, [product_id], context=context) #res['value']['price'] = product_proxy.lst_price price = round(field_data[product_id].get( 'metel_sale', 0.0), decimal) cost = round(product_proxy.standard_price, decimal) price_vat = price * self._vat_rate try: res['value']['price'] = price # discounted! res['value']['cost'] = cost res['value']['price_vat'] = price_vat res['value']['subtotal'] = price * qty except: pass return res def _get_subtotal_value(self, cr, uid, ids, fields, args, context=None): ''' Fields function for calculate ''' vat_rate = self._vat_rate res = {} for line in self.browse(cr, uid, ids, context=context): price_vat = line.price * vat_rate res[line.id] = { 'price_vat': price_vat, 'cost': line.product_id.standard_price, 'subtotal': price_vat * line.qty, } return res _columns = { 'wizard_id': fields.many2one('new.receipt.wizard', 'Wizard'), 'pre_filter': fields.char('Pre filtro', size=50), 'product_id': fields.many2one('product.product', 'Product'), 'uom_id': fields.related( 'product_id', 'uom_id', type='many2one', relation='product.uom', string='UOM', readonly=True), 'qty': fields.float('Q.', digits=(16, 2), required=True), #'standard_price': fields.float('Price', digits=(16, 4), required=True), 'price': fields.float('Price', digits=(16, 4), required=True), 'cost': fields.function( _get_subtotal_value, method=True, type='float', string='Cost', readonly=True, multi=True), 'price_vat': fields.function( _get_subtotal_value, method=True, type='float', string='Price VAT', readonly=True, multi=True), 'subtotal': fields.function( _get_subtotal_value, method=True, type='float', string='Subtotal', readonly=True, multi=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)]},
class NewReceiptWizard(orm.Model): ''' Wizard for New Receipt Wizard ''' _name = 'new.receipt.wizard' # ------------------------------------------------------------------------- # Wizard button event: # ------------------------------------------------------------------------- def dummy_action(self, cr, uid, ids, context=None): ''' Refresh button ''' return True def action_done(self, cr, uid, ids, context=None): ''' Event for button done ''' if context is None: context = {} name = self.pool.get('ir.sequence').get(cr, uid, 'new.receipt.wizard') self.write(cr, uid, ids, { 'name': name, }, context=context) wiz_proxy = self.browse(cr, uid, ids, context=context)[0] force_date = wiz_proxy.force_date # --------------------------------------------------------------------- # Create new corresponding: # --------------------------------------------------------------------- # Pool used: company_pool = self.pool.get('res.company') picking_pool = self.pool.get('stock.picking') move_pool = self.pool.get('stock.move') quant_pool = self.pool.get('stock.quant') type_pool = self.pool.get('stock.picking.type') now = force_date or ('%s' % datetime.now())[:19] origin = 'CORRISPETTIVO %s' % now[:10] # --------------------------------------------------------------------- # Search or create daily picking: # --------------------------------------------------------------------- picking_ids = picking_pool.search(cr, uid, [ ('corresponding', '=', True), ('origin', '=', origin), ], context=context) if picking_ids: picking_id = picking_ids[0] picking = picking_pool.browse( cr, uid, picking_ids, context=context)[0] # Parameters: picking_type = picking.picking_type_id location_id = picking_type.default_location_src_id.id location_dest_id = picking_type.default_location_dest_id.id company_id = picking.company_id.id else: company_id = company_pool.search(cr, uid, [], context=context)[0] company = company_pool.browse(cr, uid, company_id, context=context) # Type ID: type_ids = type_pool.search(cr, uid, [ ('code', '=', 'outgoing'), ], context=context) if not type_ids: raise osv.except_osv( _('Error'), _('Need setup of outgoing stock.picking.type!'), ) picking_type = \ type_pool.browse(cr, uid, type_ids, context=context)[0] location_id = picking_type.default_location_src_id.id location_dest_id = picking_type.default_location_dest_id.id picking_id = picking_pool.create(cr, uid, { 'partner_id': company.partner_id.id, 'company_id': company_id, 'corresponding': True, #'account_id': account.id, 'date': now, 'min_date': now, 'origin': origin, 'picking_type_id': picking_type.id, 'pick_move': 'out', 'pick_state': 'delivered', #'state': 'delivered', # XXX not real! }, context=context) # --------------------------------------------------------------------- # Add stock movement line: # --------------------------------------------------------------------- receipt = wiz_proxy.name for line in wiz_proxy.line_ids: product = line.product_id price = line.price qty = line.qty # ----------------------------------------------------------------- # Create stock movement: # ----------------------------------------------------------------- move_id = move_pool.create(cr, uid, { 'name': product.name, 'product_uom': product.uom_id.id, 'picking_id': picking_id, 'picking_type_id': picking_type.id, 'origin': 'Scontr: %s' % receipt, 'product_id': product.id, 'product_uom_qty': qty, 'date': now, 'location_id': location_id, 'location_dest_id': location_dest_id, 'state': 'done', 'price_unit': price, }, context=context) # ----------------------------------------------------------------- # Create quants: # ----------------------------------------------------------------- quant_pool.create(cr, uid, { 'stock_move_id': move_id, 'qty': qty, 'cost': price, 'location_id': location_dest_id, 'company_id': company_id, 'product_id': product.id, 'in_date': now, }, context=context) return self.write(cr, uid, ids, { 'state': 'done', }, context=context) def _get_total(self, cr, uid, ids, fields, args, context=None): ''' Fields function for calculate ''' vat = 1.22 res = {} for receipt in self.browse(cr, uid, ids, context=context)[0]: res[receipt.id] = {'total': 0.0} for line in receipt.line_ids: subtotal = line.qty * line.price res[receipt.id]['total'] += subtotal res[receipt.id]['total_vat'] = res[receipt.id]['total'] * vat return res _columns = { 'name': fields.char('# Receipt', size=25), 'force_date': fields.date('Force date', help='Force date instead take today!'), 'total': fields.function(_get_total, method=True, type='float', string='Total', multi=True), 'total_vat': fields.function(_get_total, method=True, type='float', string='Total VAT', multi=True), 'state': fields.selection([ ('draft', 'Draft'), ('done', 'Done'), ], 'State', readonly=True), } _defaults = { # Default value for state: 'name': lambda *x: 'Non confermato...', 'state': lambda *x: 'draft', }
result[rec.id] = rec.mode and rec.mode.type.name or "" return result def _name_get(self, cr, uid, ids, field_name, arg, context=None): result = {} for rec in self.browse(cr, uid, ids, context): result[rec.id] = rec.reference return result _columns = { 'type': fields.selection([ ('payable','Payable'), ('receivable','Receivable'), ],'Type', readonly=True, select=True), # invisible field to filter payment order lines by payment type 'payment_type_name': fields.function(_payment_type_name_get, method=True, type="char", size=64, string="Payment type name"), # The field name is necessary to add attachement documents to payment orders 'name': fields.function(_name_get, method=True, type="char", size=64, string="Name"), 'create_account_moves': fields.selection([('bank-statement','Bank Statement'),('direct-payment','Direct Payment')], 'Create Account Moves', required=True, states={'done':[('readonly',True)]}, help='Indicates when account moves should be created for order payment lines. "Bank Statement" '\ 'will wait until user introduces those payments in bank a bank statement. "Direct Payment" '\ 'will mark all payment lines as payied once the order is done.'), 'period_id': fields.many2one('account.period', 'Period', states={'done':[('readonly',True)]}), } _defaults = { 'type': _get_type, 'reference': _get_reference, 'create_account_moves': lambda *a: 'bank-statement',
class account_invoice(osv.osv): _inherit = 'account.invoice' def render_description(self, cr, uid, description, invoice_id, context=None): if not description: return u"" if context is None: context = {} try: invoice = self.browse(cr, uid, invoice_id, context=context) user = self.pool.get('res.users').browse(cr, uid, uid, context) variables = { 'object': invoice, 'user': user, 'ctx': context, } result = mako_template_env.from_string(description).render( variables) if result == u"False": result = u"" return result except Exception: _logger.exception("failed to render description %r", description) return u"" def _auto_invoice_amount_all(self, cr, uid, ids, name, args, context=None): res = {} tax_obj = self.pool.get('account.tax') for invoice in self.browse(cr, uid, ids, context=context): fp = invoice.fiscal_position res[invoice.id] = { 'auto_invoice_amount_untaxed': 0.0, 'auto_invoice_amount_tax': 0.0, 'auto_invoice_amount_total': 0.0 } for line in invoice.invoice_line: if fp and fp.active_reverse_charge and line.reverse_charge: res[invoice.id][ 'auto_invoice_amount_untaxed'] += line.price_subtotal for t in tax_obj.compute_all( cr, uid, line.invoice_line_tax_id, (line.price_unit * (1 - (line.discount or 0.0) / 100.0)), line.quantity, line.product_id)['taxes']: res[invoice. id]['auto_invoice_amount_tax'] += t['amount'] if (not fp) or (fp and not fp.active_reverse_charge): res[invoice.id][ 'auto_invoice_amount_untaxed'] += line.price_subtotal for t in tax_obj.compute_all( cr, uid, line.invoice_line_tax_id, (line.price_unit * (1 - (line.discount or 0.0) / 100.0)), line.quantity, line.product_id)['taxes']: res[invoice. id]['auto_invoice_amount_tax'] += t['amount'] res[invoice.id]['auto_invoice_amount_total'] = res[ invoice.id]['auto_invoice_amount_tax'] + res[ invoice.id]['auto_invoice_amount_untaxed'] return res _columns = { 'transfer_entry_id': fields.many2one('account.move', 'Transfer Entry', ondelete="set null"), 'auto_invoice_id': fields.many2one('account.invoice', 'Auto Invoice', ondelete="set null"), 'auto_invoice_amount_untaxed': fields.function(_auto_invoice_amount_all, digits_compute=dp.get_precision('Account'), string='Auto Invoice Subtotal', store=False, multi='auto_invoice_all'), 'auto_invoice_amount_tax': fields.function(_auto_invoice_amount_all, digits_compute=dp.get_precision('Account'), string='Auto Invoice Tax', store=False, multi='auto_invoice_all'), 'auto_invoice_amount_total': fields.function(_auto_invoice_amount_all, digits_compute=dp.get_precision('Account'), string='Auto Invoice Total', store=False, multi='auto_invoice_all'), } def voucher_from_invoice(self, cr, uid, invoice_id, amount, journal_id, voucher_type='payment', context=None): context = context or {} voucher_obj = self.pool.get('account.voucher') invoice = self.browse(cr, uid, invoice_id, context) # ----- Voucher Header voucher_id = voucher_obj.create( cr, uid, { 'name': invoice.name, 'partner_id': invoice.partner_id.id, 'amount': amount, 'journal_id': journal_id, 'account_id': invoice.account_id.id, 'type': voucher_type, }) move_line_ids = [] # ----- Extract all the move lines from new invoice for l in invoice.move_id.line_id: if l.date_maturity: move_line_ids.append(l.id) context.update({ 'move_line_ids': move_line_ids, 'invoice_id': invoice.id, }) # ----- Voucher Lines voucher_lines = voucher_obj.recompute_voucher_lines( cr, uid, [voucher_id], invoice.partner_id.id, invoice.journal_id.id, amount, invoice.currency_id.id, voucher_type, invoice.date_invoice, context) voucher_lines_cr = [] voucher_lines_dr = [] for voucher_line in voucher_lines['value']['line_dr_ids']: voucher_lines_dr.append((0, 0, voucher_line)) for voucher_line in voucher_lines['value']['line_cr_ids']: voucher_lines_cr.append((0, 0, voucher_line)) voucher_obj.write( cr, uid, [ voucher_id, ], { 'line_dr_ids': voucher_lines_dr, 'line_cr_ids': voucher_lines_cr, 'pre_line': voucher_lines['value']['pre_line'], 'writeoff_amount': voucher_lines['value']['writeoff_amount'], }, context) # ----- Post Voucher voucher_obj.button_proforma_voucher(cr, uid, [ voucher_id, ], context) return voucher_id def _get_tax_relation(self, cr, uid, invoice_id, context=None): # ----- keep relation between tax and relative intra cee tax tax_relation = {} inv = self.browse(cr, uid, invoice_id) for line in inv.invoice_line: # ----- Check if tax has autoinvoice tax for tax in line.invoice_line_tax_id: tax_relation.update({tax.id: tax.auto_invoice_tax_id.id}) return tax_relation def auto_invoice_vals(self, cr, uid, invoice_id, fiscal_position_id, context=None): context = context or {} invoice = self.browse(cr, uid, invoice_id, context) fp_id = fiscal_position_id or invoice.fiscal_position.id fiscal_position = self.pool.get('account.fiscal.position').browse( cr, uid, fp_id, context) # ----- Get actual invoice copy copy_inv = self.copy_data(cr, uid, invoice_id, {}, context) if not copy_inv: return {} new_inv = copy_inv.copy() # ----- Change some data in new invoice new_inv.update({ 'type': invoice.type.replace('in_', 'out_'), 'origin': invoice.number or '', 'supplier_invoice_number': '', 'internal_number': '', 'number': '', 'state': 'draft', 'move_id': False, 'period_id': invoice.period_id and invoice.period_id.id or False, 'account_id': invoice.partner_id.property_account_receivable.id, 'journal_id': fiscal_position.journal_auto_invoice_id.id, 'date_invoice': invoice.registration_date, 'registration_date': invoice.registration_date, }) new_line = [] tax_relation = self._get_tax_relation(cr, uid, invoice_id, context) for line in new_inv['invoice_line']: vals = line[2].copy() # ----- Change account in new invoice line vals['account_id'] = fiscal_position.account_transient_id.id # ----- Change tax in new invoice line new_tax = [] for tax in vals['invoice_line_tax_id']: new_tax.append((6, 0, [tax_relation[tax[2][0]]])) vals['invoice_line_tax_id'] = new_tax new_line.append((0, 0, vals)) new_inv['invoice_line'] = new_line return new_inv def rc_auto_invoice_vals(self, cr, uid, invoice_id, fiscal_position_id, context=None): # ----- Get complete invoice copy res = self.auto_invoice_vals(cr, uid, invoice_id, fiscal_position_id, context) # ----- Get partner from company for auto invoice company = self.pool.get('res.users').browse(cr, uid, uid, context).company_id res['partner_id'] = company.auto_invoice_partner_id and \ company.auto_invoice_partner_id.id \ or res['partner_id'] # ----- Delete line without reverse charge flag rc_lines = [] for line in res['invoice_line']: if line[2]['reverse_charge']: rc_lines.append(line) res['invoice_line'] = rc_lines return res def extra_ue_auto_invoice_vals(self, cr, uid, invoice_id, fiscal_position_id, context=None): # ----- Get complete invoice copy res = self.auto_invoice_vals(cr, uid, invoice_id, fiscal_position_id, context) # ----- Get partner from company for auto invoice company = self.pool.get('res.users').browse(cr, uid, uid, context).company_id res['partner_id'] = company.auto_invoice_partner_id and \ company.auto_invoice_partner_id.id \ or company.partner_id and company.partner_id.id # ----- Get right lines invoice = self.browse(cr, uid, invoice_id, context) fp_id = fiscal_position_id or invoice.fiscal_position.id fiscal_position = self.pool.get('account.fiscal.position').browse( cr, uid, fp_id, context) product_obj = self.pool.get('product.product') total = 0.0 for line in res['invoice_line']: product = line[2]['product_id'] and product_obj.browse( cr, uid, line[2]['product_id']) or False if product and product.type == 'service' or not product: price_subtotal = line[2]['price_unit'] * ( 1 - (line[2]['discount'] or 0.0) / 100.0) total += price_subtotal * line[2]['quantity'] if not total: return False d = fiscal_position.extra_ue_line_detail res['invoice_line'] = [(0, 0, { 'name': self.render_description(cr, uid, d, invoice_id, context), 'price_unit': total, 'quantity': 1, 'account_id': fiscal_position.account_transient_id.id, 'invoice_line_tax_id': [(6, 0, [fiscal_position.extra_ue_service_tax_id.id])] })] return res def create_auto_invoice(self, cr, uid, ids, context=None): context = context or {} new_invoice_ids = [] move_obj = self.pool.get('account.move') #~ wf_service = netsvc.LocalService("workflow") for inv in self.browse(cr, uid, ids, context): # ----- Apply Auto Invoice only on supplier invoice/refund if not (inv.type == 'in_invoice' or inv.type == 'in_refund'): continue fiscal_position = inv.fiscal_position # ----- Check if fiscal positon is active for intra CEE invoice if not fiscal_position: continue if not (fiscal_position.active_intra_cee or fiscal_position.active_reverse_charge or fiscal_position.active_extra_ue_service): continue # ----- keep relation between tax and relative intra cee tax for line in inv.invoice_line: # ----- Check if taxes exist on each line if not line.invoice_line_tax_id: raise osv.except_osv( _('Error'), _('You must define a tax for each line \ in Intra CEE Invoice')) # ----- Check if tax has autoinvoice tax for tax in line.invoice_line_tax_id: if not tax.auto_invoice_tax_id: raise osv.except_osv( _('Error'), _('Set an Auto Invoice Tax for tax %s') % (tax.name)) # ----- Get actual invoice copy based on fiscal position flag if fiscal_position.active_intra_cee: new_inv = self.auto_invoice_vals(cr, uid, inv.id, fiscal_position.id, context) elif fiscal_position.active_reverse_charge: new_inv = self.rc_auto_invoice_vals(cr, uid, inv.id, fiscal_position.id, context) elif fiscal_position.active_extra_ue_service: new_inv = self.extra_ue_auto_invoice_vals( cr, uid, inv.id, fiscal_position.id, context) if not new_inv: continue # ----- Create Auto Invoice...Yeah!!!!! auto_invoice_id = self.create(cr, uid, new_inv, context) new_invoice_ids.append(auto_invoice_id) # ----- Recompute taxes in new invoice self.button_reset_taxes(cr, uid, [auto_invoice_id], context) # ----- Get new values from auto invoice new_invoice = self.browse(cr, uid, auto_invoice_id, context) # ----- Validate invoice new_invoice.signal_workflow('invoice_open') self.write(cr, uid, [inv.id], {'auto_invoice_id': auto_invoice_id}, context) return new_invoice_ids def action_number(self, cr, uid, ids, context=None): res = super(account_invoice, self).action_number(cr, uid, ids, context) self.create_auto_invoice(cr, uid, ids, context) return res def action_cancel(self, cr, uid, ids, context=None): invoices = self.browse(cr, uid, ids, context) account_move = self.pool.get('account.move') voucher_obj = self.pool.get('account.voucher') #~ wf_service = netsvc.LocalService("workflow") move_ids = [] for inv in invoices: # ----- Delete Auto Invoice if inv.auto_invoice_id: # ----- Delete Payments for suppier invoice if len(inv.payment_ids) > 1: raise osv.except_osv( _('Error!'), _('You cannot cancel an invoice which is partially \ paid. You need to unreconcile related payment entries \ first.')) payment_ids = [] for payment in inv.payment_ids: voucher_ids = voucher_obj.search( cr, uid, [('move_id', '=', payment.move_id.id)]) if not voucher_ids: continue payment_ids = payment_ids + voucher_ids # ----- Delete Payments for auto invoice for payment in inv.auto_invoice_id.payment_ids: voucher_ids = voucher_obj.search( cr, uid, [('move_id', '=', payment.move_id.id)]) if not voucher_ids: continue payment_ids = payment_ids + voucher_ids if payment_ids: voucher_obj.cancel_voucher(cr, uid, payment_ids, context) voucher_obj.unlink(cr, uid, payment_ids, context) # ---- Delete Invoice inv.auto_invoice_id.signal_workflow('invoice_cancel') self.action_cancel_draft(cr, uid, [inv.auto_invoice_id.id]) self.write(cr, uid, inv.auto_invoice_id.id, {'internal_number': ''}, context) self.unlink(cr, uid, [inv.auto_invoice_id.id], context) # ----- Save account move ids if inv.transfer_entry_id: move_ids.append(inv.transfer_entry_id.id) # ----- Reopen and delete account move if move_ids: account_move.button_cancel(cr, uid, move_ids, context) account_move.unlink(cr, uid, move_ids, context) return super(account_invoice, self).action_cancel(cr, uid, ids, context) @api.multi def finalize_invoice_move_lines(self, move_lines): super(account_invoice, self).finalize_invoice_move_lines(move_lines) # modify some data in move lines if (self.type == 'in_invoice' or self.type == 'in_refund'): fiscal_position = self.fiscal_position # ----- Check if fiscal positon is active for intra CEE invoice if not fiscal_position: return move_lines if not (fiscal_position.active_intra_cee or fiscal_position.active_reverse_charge or fiscal_position.active_extra_ue_service): return move_lines if fiscal_position.active_intra_cee: amount_vat = self.amount_tax if fiscal_position.active_reverse_charge: amount_vat = 0.0 for tax in self.tax_line: if not tax.base_code_id.rc: continue amount_vat += tax.amount if fiscal_position.active_extra_ue_service: amount_vat = self.amount_tax cli_account_id = self.partner_id.property_account_receivable.id new_line = { 'name': '/', 'debit': 0.0, 'partner_id': self.partner_id.id, 'account_id': cli_account_id } if self.type == 'in_invoice': new_line.update({'credit': amount_vat}) if self.type == 'in_refund': new_line.update({'debit': amount_vat}) reconcile = self.env['account.move.reconcile'].create( {'type': 'manual'}) if reconcile: new_line.update({'reconcile_id': reconcile.id}) number = 0 for line in move_lines: if 'date_maturity' in line[2] \ and line[2]['date_maturity']: number += 1 for line in move_lines: if 'date_maturity' in line[2] \ and line[2]['date_maturity']: if self.type == 'in_invoice': line[2]['credit'] = line[2]['credit'] - (amount_vat / number) if self.type == 'in_refund': line[2]['debit'] = line[2]['debit'] - (amount_vat / number) move_lines.append((0, 0, new_line)) if (self.type == 'out_invoice' or self.type == 'out_refund'): if not self.origin: return move_lines ref_invoice = self.search([('internal_number', '=', self.origin)]) if not ref_invoice: return move_lines if not ref_invoice.move_id: return move_lines reconcile_id = False for line in ref_invoice.move_id.line_id: if line.reconcile_id: reconcile_id = line.reconcile_id.id break fiscal_position = self.fiscal_position # ----- Check if fiscal positon is active for intra CEE invoice if not fiscal_position: return move_lines if not (fiscal_position.active_intra_cee or fiscal_position.active_reverse_charge or fiscal_position.active_extra_ue_service): return move_lines amount_vat = self.amount_tax cli_account_id = self.partner_id.property_account_receivable.id new_line = { 'name': '/', 'debit': 0.0, 'partner_id': self.partner_id.id, 'account_id': cli_account_id, 'reconcile_id': reconcile_id, } if self.type == 'out_invoice': new_line.update({'debit': amount_vat}) if self.type == 'out_refund': new_line.update({'credit': amount_vat}) number = 0 for line in move_lines: if 'date_maturity' in line[2] \ and line[2]['date_maturity']: number += 1 for line in move_lines: if 'date_maturity' in line[2] \ and line[2]['date_maturity']: line[2][ 'account_id'] = fiscal_position.account_transient_id.id if self.type == 'out_invoice': line[2]['debit'] = line[2]['debit'] - (amount_vat / number) if self.type == 'out_refund': line[2]['credit'] = line[2]['credit'] - (amount_vat / number) move_lines.append((0, 0, new_line)) return move_lines
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" ), "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", ),
'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"
cr, uid, line.taxes_id, line.price, line.qty, line.product_id, line.back_order_id.partner_id ) cur = line.back_order_id.pricelist_id.currency_id res[line.id] = cur_obj.round(cr, uid, cur, taxes["total"]) return res def _get_uom_id(self, cr, uid, context=None): try: proxy = self.pool.get("ir.model.data") result = proxy.get_object_reference(cr, uid, "product", "product_uom_unit") return result[1] except Exception, ex: return False _columns = { # 'location_destination_id': fields.many2one('stock.location', 'Stock Destination Location'), # 'location_id': fields.many2one('stock.location', 'Stock Source Location'), "product_id": fields.many2one("product.product", "Product"), "back_order_id": fields.many2one("back.to.back.order", "Back Order"), "qty": fields.float("Quantity"), "price": fields.float("Unit Price"), "subtotal": fields.function(_amount_line, string="Subtotal", digits_compute=dp.get_precision("Account")), "taxes_id": fields.many2many("account.tax", "purchase_order_taxe", "ord_id", "tax_id", "Taxes"), "product_uom": fields.many2one("product.uom", "Product Unit of Measure", required=True), } _defaults = {"product_uom": _get_uom_id} # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
path = addons.get_module_resource(module.name, 'static', 'src', 'img', '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", size=128, readonly=True, required=True, select=True), 'category_id': fields.many2one('ir.module.category', 'Category', readonly=True, select=True), 'shortdesc': fields.char('Module Name', size=64, readonly=True, translate=True), 'summary': fields.char('Summary', size=64, 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", 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'),
('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, }
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) new_printers = list(set(printers.keys()).difference(set(map(lambda p: p['code'], printers_installed))))
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 product_template(osv.osv): _name = 'product.template' _inherit = 'product.template' def _product_available(self, cr, uid, ids, name, arg, context=None): prod_available = {} product_ids = self.browse(cr, uid, ids, context=context) var_ids = [] for product in product_ids: var_ids += [p.id for p in product.product_variant_ids] variant_available= self.pool['product.product']._product_available(cr, uid, var_ids, context=context) for product in product_ids: qty_available = 0 virtual_available = 0 incoming_qty = 0 outgoing_qty = 0 for p in product.product_variant_ids: qty_available += variant_available[p.id]["qty_available"] virtual_available += variant_available[p.id]["virtual_available"] incoming_qty += variant_available[p.id]["incoming_qty"] outgoing_qty += variant_available[p.id]["outgoing_qty"] prod_available[product.id] = { "qty_available": qty_available, "virtual_available": virtual_available, "incoming_qty": incoming_qty, "outgoing_qty": outgoing_qty, } return prod_available def _search_product_quantity(self, cr, uid, obj, name, domain, context): prod = self.pool.get("product.product") product_variant_ids = prod.search(cr, uid, domain, context=context) return [('product_variant_ids', 'in', product_variant_ids)] def _product_available_text(self, cr, uid, ids, field_names=None, arg=False, context=None): res = {} for product in self.browse(cr, uid, ids, context=context): res[product.id] = str(product.qty_available) + _(" On Hand") return res _columns = { 'type': fields.selection([('product', 'Stockable Product'), ('consu', 'Consumable'), ('service', 'Service')], 'Product Type', required=True, help="Consumable: Will not imply stock management for this product. \nStockable product: Will imply stock management for this product."), 'qty_available_text': fields.function(_product_available_text, type='char'), 'property_stock_procurement': fields.property( type='many2one', relation='stock.location', string="Procurement Location", domain=[('usage','like','procurement')], help="This stock location will be used, instead of the default one, as the source location for stock moves generated by procurements."), 'property_stock_production': fields.property( type='many2one', relation='stock.location', string="Production Location", domain=[('usage','like','production')], help="This stock location will be used, instead of the default one, as the source location for stock moves generated by manufacturing orders."), 'property_stock_inventory': fields.property( type='many2one', relation='stock.location', string="Inventory Location", domain=[('usage','like','inventory')], help="This stock location will be used, instead of the default one, as the source location for stock moves generated when you do an inventory."), 'sale_delay': fields.float('Customer Lead Time', help="The average delay in days between the confirmation of the customer order and the delivery of the finished products. It's the time you promise to your customers."), 'loc_rack': fields.char('Rack', size=16), 'loc_row': fields.char('Row', size=16), 'loc_case': fields.char('Case', size=16), 'track_incoming': fields.boolean('Track Incoming Lots', help="Forces to specify a Serial Number for all moves containing this product and coming from a Supplier Location"), 'track_outgoing': fields.boolean('Track Outgoing Lots', help="Forces to specify a Serial Number for all moves containing this product and going to a Customer Location"), 'track_all': fields.boolean('Full Lots Traceability', help="Forces to specify a Serial Number on each and every operation related to this product"), # sum of product variant qty # 'reception_count': fields.function(_product_available, multi='qty_available', # fnct_search=_search_product_quantity, type='float', string='Quantity On Hand'), # 'delivery_count': fields.function(_product_available, multi='qty_available', # fnct_search=_search_product_quantity, type='float', string='Quantity On Hand'), 'qty_available': fields.function(_product_available, multi='qty_available', digits_compute=dp.get_precision('Product Unit of Measure'), fnct_search=_search_product_quantity, type='float', string='Quantity On Hand'), 'virtual_available': fields.function(_product_available, multi='qty_available', digits_compute=dp.get_precision('Product Unit of Measure'), fnct_search=_search_product_quantity, type='float', string='Quantity Available'), 'incoming_qty': fields.function(_product_available, multi='qty_available', digits_compute=dp.get_precision('Product Unit of Measure'), fnct_search=_search_product_quantity, type='float', string='Incoming'), 'outgoing_qty': fields.function(_product_available, multi='qty_available', digits_compute=dp.get_precision('Product Unit of Measure'), fnct_search=_search_product_quantity, type='float', string='Outgoing'), 'route_ids': fields.many2many('stock.location.route', 'stock_route_product', 'product_id', 'route_id', 'Routes', domain="[('product_selectable', '=', True)]", help="Depending on the modules installed, this will allow you to define the route of the product: whether it will be bought, manufactured, MTO/MTS,..."), } _defaults = { 'sale_delay': 7, } def action_view_routes(self, cr, uid, ids, context=None): route_obj = self.pool.get("stock.location.route") act_obj = self.pool.get('ir.actions.act_window') mod_obj = self.pool.get('ir.model.data') product_route_ids = set() for product in self.browse(cr, uid, ids, context=context): product_route_ids |= set([r.id for r in product.route_ids]) product_route_ids |= set([r.id for r in product.categ_id.total_route_ids]) route_ids = route_obj.search(cr, uid, ['|', ('id', 'in', list(product_route_ids)), ('warehouse_selectable', '=', True)], context=context) result = mod_obj.xmlid_to_res_id(cr, uid, 'stock.action_routes_form', raise_if_not_found=True) result = act_obj.read(cr, uid, [result], context=context)[0] result['domain'] = "[('id','in',[" + ','.join(map(str, route_ids)) + "])]" return result def _get_products(self, cr, uid, ids, context=None): products = [] for prodtmpl in self.browse(cr, uid, ids, context=None): products += [x.id for x in prodtmpl.product_variant_ids] return products def _get_act_window_dict(self, cr, uid, name, context=None): mod_obj = self.pool.get('ir.model.data') act_obj = self.pool.get('ir.actions.act_window') result = mod_obj.xmlid_to_res_id(cr, uid, name, raise_if_not_found=True) result = act_obj.read(cr, uid, [result], context=context)[0] return result def action_open_quants(self, cr, uid, ids, context=None): products = self._get_products(cr, uid, ids, context=context) result = self._get_act_window_dict(cr, uid, 'stock.product_open_quants', context=context) result['domain'] = "[('product_id','in',[" + ','.join(map(str, products)) + "])]" result['context'] = "{'search_default_locationgroup': 1, 'search_default_internal_loc': 1}" return result def action_view_orderpoints(self, cr, uid, ids, context=None): products = self._get_products(cr, uid, ids, context=context) result = self._get_act_window_dict(cr, uid, 'stock.product_open_orderpoint', context=context) if len(ids) == 1 and len(products) == 1: result['context'] = "{'default_product_id': " + str(products[0]) + ", 'search_default_product_id': " + str(products[0]) + "}" else: result['domain'] = "[('product_id','in',[" + ','.join(map(str, products)) + "])]" result['context'] = "{}" return result def action_view_stock_moves(self, cr, uid, ids, context=None): products = self._get_products(cr, uid, ids, context=context) result = self._get_act_window_dict(cr, uid, 'stock.act_product_stock_move_open', context=context) if len(ids) == 1 and len(products) == 1: ctx = "{'tree_view_ref':'stock.view_move_tree', \ 'default_product_id': %s, 'search_default_product_id': %s}" \ % (products[0], products[0]) result['context'] = ctx else: result['domain'] = "[('product_id','in',[" + ','.join(map(str, products)) + "])]" result['context'] = "{'tree_view_ref':'stock.view_move_tree'}" return result
class product_product(orm.Model): ''' Adds a one2many field to the model to the Product which links QC tests for certain triggers.''' _inherit = 'product.product' def _calc_trigger_ids(self, cr, uid, ids, fieldname, args, context=None): # TODO: Eliminar este método, que tampoco aporta mucho prod_trigger_obj = self.pool['product.qc.trigger.test'] res = {} for product_id in ids: res[product_id] = [] trigger_template_ids = prod_trigger_obj.search( cr, uid, [('product_id', '=', product_id)], context=context) for trigger_template in prod_trigger_obj.browse( cr, uid, trigger_template_ids, context=context): if trigger_template.trigger_id.id not in res[product_id]: res[product_id].append(trigger_template.trigger_id.id) return res def _search_trigger_ids(self, cr, uid, obj, name, args, context): trigger_template_proxy = self.pool['product.qc.trigger.test'] res = [] for unused, operator, condition in args: opposite = False if 'in' in operator: if operator == 'not in': operator = 'in' opposite = True else: if operator in ('!=', '<>'): operator = '=' opposite = True template_trigger_ids = trigger_template_proxy.search( cr, uid, [ ('trigger_id', operator, condition), ], context=context) product_ids = [] for template_trigger in trigger_template_proxy.browse( cr, uid, template_trigger_ids, context): product_ids.append(template_trigger.product_id.id) operator = 'in' if opposite: operator = 'not in' res.append(('id', operator, product_ids)) return res _columns = { 'qc_test_trigger_ids': fields.one2many('product.qc.trigger.test', 'product_id', 'QC triggers > tests', help="Defines when a product must to pass a quality " "control test for certain operation.\n"), 'qc_trigger_ids': fields.function(_calc_trigger_ids, method=True, type='many2many', relation='qc.trigger', string='QC triggers', fnct_search=_search_trigger_ids), } def _default_qc_template_trigger_ids(self, cr, uid, context=None): # TODO: Esto no debería añadirse en los nuevos productos, si no cuando # se va a hacer el movimiento, mirar los tests que son de empresa user = self.pool['res.users'].browse(cr, uid, uid, context=context) res = [] return res for company_trigger in user.company_id.qc_test_trigger_ids: res.append({ 'trigger_id': company_trigger.trigger_id.id, 'template_id': company_trigger.template_id.id, 'company_id': user.company_id.id, }) return res _defaults = { 'qc_test_trigger_ids': _default_qc_template_trigger_ids, }
class customer_reconcile(osv.osv): ''' A customer reconcile is the document that associates already made payments with debts of the customer ''' def _get_name(self, cr, uid, context=None): if context is None: context = {} return context.get('name', False) def _get_journal(self, cr, uid, context=None): if context is None: context = {} return context.get('journal_id', False) def _get_narration(self, cr, uid, context=None): if context is None: context = {} return context.get('narration', False) def _get_balance(self, cr, uid, ids, name, args, context=None): if not ids: return {} res = {} amount = 0.0 for dr in self.browse (cr, uid, ids, context=context): u = [] for uac in dr.uac_ids: u.append({'amount': uac.amount}) db = [] for debt in dr.debt_ids: db.append({'amount': debt.amount}) res[dr.id] = self._compute_balance (cr, uid, u, db) return res def _compute_balance(self, cr, uid, uac_ids, debt_ids): currency_obj = self.pool.get('res.currency') balance = 0.0 for uac in uac_ids: balance += uac['amount'] for debt in debt_ids: balance -= debt['amount'] return balance _name = 'numa_ar_base.customer_reconcile' _description = 'Deffered documents receipt' _order = "date desc, id desc" _columns = { 'name':fields.char('Identification', size=256, readonly=True, states={'draft':[('readonly',False)]}), 'date':fields.date('Date', readonly=True, select=True, states={'draft':[('readonly',False)]}, help="Efective operation date"), 'journal_id':fields.many2one('account.journal', 'Journal', required=True, readonly=True, states={'draft':[('readonly',False)]}), 'account_id':fields.many2one('account.account', 'Account', required=True, readonly=True, states={'draft':[('readonly',False)]}), 'uac_ids':fields.one2many('numa_ar_base.customer_reconcile_uac','cr_id','Non reconciled credits', readonly=True, states={'draft':[('readonly',False)]}), 'debt_ids':fields.one2many('numa_ar_base.customer_reconcile_debt','cr_id','Applied debts', readonly=True, states={'draft':[('readonly',False)]}), 'narration':fields.text('Notas', readonly=True, states={'draft':[('readonly',False)]}), 'currency_id': fields.many2one('res.currency', string='Moneda', readonly=True, states={'draft':[('readonly',False)]}), 'company_id': fields.related('journal_id','company_id', type='many2one', relation='res.company', string='Company', store=False, readonly=True), 'state':fields.selection( [('draft','Draft'), ('posted','Posted'), ('cancel','Canceled') ], 'State', readonly=True, size=32, help=' * \'Draft\' state is used on new document entry. \ \n* \'Posted\' is used when the document is registered and account moves are generated \ \n* \'Cancel\' is used for canceled documents.'), 'partner_id':fields.many2one('res.partner', 'Customer', change_default=1, readonly=True, states={'draft':[('readonly',False)]}), 'balance': fields.function(_get_balance, method=True, string='Balance', type='float', readonly=True), 'move_line_ids': fields.many2many('account.move.line', 'customer_reconcile_movements', 'cr_id', 'move_line_id', string='Reconcile', readonly=True, states={'draft':[('readonly',False)]}), } _defaults = { 'name':_get_name, 'journal_id':_get_journal, 'narration':_get_narration, 'state': 'draft', 'name': '', 'date': lambda *a: time.strftime('%Y-%m-%d'), 'company_id': lambda s,cr,uid,c: s.pool.get('res.company')._company_default_get(cr, uid, 'account.account', context=c), } def name_get(self, cr, uid, ids, context=None): if not ids: return [] if context is None: context = {} customer_reconciles = self.browse (cr, uid, ids) return [(dr.id, "%s [%s]" % (dr.name, dr.company_id.name)) for dr in customer_reconciles] def onchange_line_ids(self, cr, uid, ids, uac_ids, debt_ids, context=None): uac_obj = self.pool.get('numa_ar_base.customer_reconcile_uac') debt_obj = self.pool.get('numa_ar_base.customer_reconcile_debt') u = resolve_o2m_operations(cr, uid, uac_obj, uac_ids, ['amount'], context=context) db = resolve_o2m_operations(cr, uid, debt_obj, debt_ids, ['amount'], context=context) return {'value': {'balance': self._compute_balance(cr, uid, u, db)}} def onchange_journal (self, cr, uid, ids, journal_id, partner_id, date, currency_id, context=None): default = { 'value':{}, } if not partner_id and not journal_id: return default cash_obj = self.pool.get('numa_ar_base.customer_reconcile_cash') journal_obj = self.pool.get('account.journal') period_obj = self.pool.get('account.period') journal = journal_obj.browse (cr, uid, journal_id, context=context) default['value']['currency_id'] = journal.currency.id or journal.company_id.currency_id.id default['value']['account_id'] = journal.default_debit_account_id.id default['value']['company_id'] = journal.company_id.id if partner_id: change_set = self.onchange_partner_id(cr, uid, ids, partner_id, journal_id, date, default['value']['currency_id'], context=context) default['value'].update(change_set['value']) return default def onchange_partner_id(self, cr, uid, ids, partner_id, journal_id, date, currency_id, context=None): if context is None: context = {} if not partner_id or not journal_id: return {} currency_pool = self.pool.get('res.currency') move_line_pool = self.pool.get('account.move.line') partner_pool = self.pool.get('res.partner') journal_pool = self.pool.get('account.journal') journal = journal_pool.browse (cr, uid, journal_id) company_id = journal.company_id.id company_currency_id = (journal.currency and journal.currency.id) or journal.company_id.currency_id.id total_debit = 0.0 total_credit = 0.0 default = {'value': {'debt_ids': [], 'uac_ids': []}} domain = [('state','=','valid'), ('account_id.type', '=', 'receivable'), ('reconcile_id', '=', False), ('partner_id', '=', partner_id), ('company_id', '=', company_id)] ids = move_line_pool.search(cr, uid, domain, context=context) moves = move_line_pool.browse(cr, uid, ids, context=context) credits = [] debits = [] for line in moves: original_amount = line.debit or line.credit or 0.0 amount_unreconciled = currency_pool.compute(cr, uid, line.currency_id.id or company_currency_id, currency_id, abs(line.amount_residual)) amount_original = currency_pool.compute(cr, uid, line.currency_id.id or company_currency_id, currency_id, original_amount) rs = { 'name':line.move_id.name, 'move_line_id':line.id, 'account_id':line.account_id.id, 'analytic_account_id':line.analytic_account_id.id, 'amount_original': amount_original, 'date_original':line.date, 'date_due':line.date_maturity, 'amount_unreconciled': amount_unreconciled, 'company_id': journal.company_id.id, } if line.credit: if not (line.reconcile_id or line.reconcile_partial_id): rs['amount'] = amount_unreconciled total_credit += amount_unreconciled credits.append(rs) elif line.debit: rs['amount'] = 0 debits.append(rs) credits.sort(key=lambda line: line['date_original']) debits.sort(key=lambda line: line['date_original']) #Apply credit in order to debts for debt in debits: applied_amount = min(debt['amount_unreconciled'], total_credit) debt['amount'] = applied_amount total_credit -= applied_amount default['value']['uac_ids'] = credits default['value']['debt_ids'] = debits return default def onchange_date(self, cr, uid, ids, date, journal_id, context=None): """ @param date: latest value from user input for field date @param args: other arguments @param context: context arguments, like lang, time zone @return: Returns a dict which contains new values, and context """ if not date: return False if not context: context = {} period_pool = self.pool.get('account.period') journal_pool = self.pool.get('account.journal') res = {'value':{}} if journal_id: journal = journal_pool.browse (cr, uid, journal_id) pids = period_pool.search(cr, uid, [('date_start', '<=', date), ('date_stop', '>=', date), ('company_id', '=', journal.company_id.id)]) else: pids = period_pool.search(cr, uid, [('date_start', '<=', date), ('date_stop', '>=', date)]) if not pids: raise osv.except_osv(_('Error!'), _('No period for receipt date!')) return res def unlink(self, cr, uid, ids, context=None): for t in self.read(cr, uid, ids, ['state'], context=context): if t['state'] not in ('draft', 'canceled'): raise osv.except_osv(_('Error!'), _('Posted documents could not be cancelled!')) return super(customer_reconcile, self).unlink(cr, uid, ids, context=context) def action_post(self, cr, uid, ids, context=None): if context is None: context = {} move_obj = self.pool.get('account.move') move_line_obj = self.pool.get('account.move.line') currency_obj = self.pool.get('res.currency') seq_obj = self.pool.get('ir.sequence') account_obj = self.pool.get('account.account') company_obj = self.pool.get('res.company') partner_obj = self.pool.get('res.partner') property_obj = self.pool.get('ir.property') period_obj = self.pool.get('account.period') for receipt in self.browse(cr, uid, ids, context=context): context_multi_currency = context.copy() context_multi_currency.update({'date': receipt.date}) if receipt.journal_id and receipt.journal_id.sequence_id: name = seq_obj.get_id(cr, uid, receipt.journal_id.sequence_id.id, context={'company_id': receipt.journal_id.company_id.id}) else: raise osv.except_osv(_('Error !'), _('Please define a Journal with sequence!')) pids = period_obj.search(cr, uid, [('date_start', '<=', receipt.date), ('date_stop', '>=', receipt.date), ('company_id', '=', receipt.journal_id.company_id.id)]) if pids: period_id = pids[0] else: raise osv.except_osv(_('Error !'), _('No valid period for the entered date!')) ref = name.replace('/','') self.write (cr, uid, [receipt.id], {'name': name}) company_currency = receipt.journal_id.company_id.currency_id.id current_currency = receipt.currency_id.id debit = 0.0 #Compute the total amount to be payed total_credit = 0.0 for uac in receipt.uac_ids: total_credit += uac.amount if total_credit == 0: raise osv.except_osv(_('Not complete document!'), _('No credit was entered!')) applicable_debts = [] for line in receipt.debt_ids: if line.amount: applicable_debts.append(line) debt_index = 0 if len(applicable_debts): debt = applicable_debts[debt_index] left_to_apply = min (debt.amount_unreconciled, debt.amount) reconcile_lines = [] reconcile_new_lines = [] #Process unassigned credit entries #pdb.set_trace() for uac in receipt.uac_ids: amount_to_apply = uac.amount if amount_to_apply and debt_index < len(applicable_debts): #Apply this amount to debts not yet covered while debt_index < len(applicable_debts) and amount_to_apply > 0: #Taking the amount to apply, try to cover as many docs as possible #we check if the voucher line is fully paid or not and create a move line to balance the payment and initial invoice if needed to_apply = min (amount_to_apply, left_to_apply) if to_apply: old = uac.move_line_id if (uac.amount_original-uac.amount+amount_to_apply) > to_apply: new_line_data = { 'move_id': old.move_id.id, 'account_id': old.account_id.id, 'partner_id': old.partner_id.id, 'name': old.name, 'ref': old.ref, 'date_maturity': old.date_maturity, 'credit': to_apply, 'debit': 0.0, 'state': 'valid', } new_line_id = move_line_obj.create (cr, uid, new_line_data, check=False) reconcile_new_lines.append(new_line_id) if debt.move_line_id.id: rec_ids = [new_line_id, debt.move_line_id.id] reconcile_lines.append(rec_ids) else: move_line_obj.write(cr, uid, [old.id], { 'credit': to_apply, 'debit': 0.0}, check=False, update_check=False) reconcile_new_lines.append(old.id) if debt.move_line_id.id: rec_ids = [old.id, debt.move_line_id.id] reconcile_lines.append(rec_ids) amount_to_apply -= to_apply left_to_apply -= to_apply if not left_to_apply or not to_apply: debt_index += 1 if debt_index < len(applicable_debts): debt = applicable_debts[debt_index] left_to_apply = min (debt.amount_unreconciled, debt.amount) if (uac.amount_original-uac.amount+amount_to_apply) > 0: move_line_obj.write(cr, uid, [uac.move_line_id.id], { 'credit': uac.amount_original-uac.amount+amount_to_apply, 'debit': 0.0}, check=False, update_check=False) #Trigger reconcile on all affected debts self.write (cr, uid, [receipt.id], {'state': 'posted', 'move_line_ids': [(6, 0, reconcile_new_lines)]}) for rec_ids in reconcile_lines: if len(rec_ids) >= 2: move_line_obj.reconcile_partial(cr, uid, rec_ids) return True def copy(self, cr, uid, id, default={}, context=None): default.update({ 'state': 'draft', 'number': False, 'move_id': False, 'qm_ids': False, #'doc_ids': False, 'debt_ids': False, 'reference': False }) if 'date' not in default: default['date'] = time.strftime('%Y-%m-%d') return super(customer_reconcile, self).copy(cr, uid, id, default, context)
'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 account_bank_statement(orm.Model): _inherit = 'account.bank.statement' def _get_statement_years(self, cr, uid, fields, context=None): result = [] first_statement_id = self.search(cr, uid, [('date', '!=', False)], order='date asc', limit=1, context=context) if first_statement_id: first_statement = self.browse(cr, uid, first_statement_id[0], context) first_year = datetime.datetime.strptime(first_statement.date, '%Y-%m-%d').year else: first_year = datetime.date.today().year for year in range(int(first_year), int(datetime.date.today().year) + 1): result.append((str(year), str(year))) return result def _get_statement_year(self, cr, uid, ids, field_name, arg, context): result = {} for statement in self.browse(cr, uid, ids, context): if statement.date_invoice: result[statement.id] = datetime.datetime.strptime( statement.date, '%Y-%m-%d').year else: result[statement.id] = False return result _columns = { 'year': fields.function(_get_statement_year, 'Year', type='selection', selection=_get_statement_years, method=True, help="Select year"), 'date_from': fields.function(lambda *a, **k: {}, method=True, type='date', string="Date from"), 'date_to': fields.function(lambda *a, **k: {}, method=True, type='date', string="Date to"), 'partner_id': fields.related('line_ids', 'partner_id', type='many2one', relation='res.partner', string='Partner'), } def search(self, cr, uid, args, offset=0, limit=0, order=None, context=None, count=False): new_args = [] for arg in args: if arg[0] == 'year': new_args.append( ('date', '>=', '{year}-01-01'.format(year=arg[2]))) new_args.append( ('date', '<=', '{year}-12-31'.format(year=arg[2]))) else: new_args.append(arg) return super(account_bank_statement, self).search(cr, uid, new_args, offset=offset, limit=limit, order=order, context=context, count=count)
) else: return False return self.write(cr, uid, id, {"file_db_store": value}, context=context) _columns = { "name": fields.char("Image Title", size=64), "filename": fields.char("Filename", size=64), "extension": fields.char("file extension", oldname="extention"), "link": fields.boolean( "Link?", help="Images can be linked from files on " "your file system or remote (Preferred)" ), "file_db_store": fields.binary("Image stored in database"), "file": fields.function( _get_image, fnct_inv=_set_image, type="binary", string="File", filters="*.png,*.jpg,*.gif" ), "url": fields.char("File Location"), "url_big": fields.char("File Location Image Size Big"), "url_medium": fields.char("File Location Image Size Medium"), "url_small": fields.char("File Location Image Size Small"), "comments": fields.text("Comments"), "product_id": fields.many2one("product.product", "Product"), } _defaults = {"link": True} _sql_constraints = [ ( "uniq_name_product_id", "UNIQUE(product_id, name)",
class product_product(osv.osv): _inherit = "product.product" def _stock_move_count(self, cr, uid, ids, field_name, arg, context=None): res = dict([(id, {'reception_count': 0, 'delivery_count': 0}) for id in ids]) move_pool=self.pool.get('stock.move') moves = move_pool.read_group(cr, uid, [ ('product_id', 'in', ids), ('location_id.usage', '!=', 'internal'), ('location_dest_id.usage', '=', 'internal'), ('state','in',('confirmed','assigned','pending')) ], ['product_id'], ['product_id']) for move in moves: product_id = move['product_id'][0] res[product_id]['reception_count'] = move['product_id_count'] moves = move_pool.read_group(cr, uid, [ ('product_id', 'in', ids), ('location_id.usage', '=', 'internal'), ('location_dest_id.usage', '!=', 'internal'), ('state','in',('confirmed','assigned','pending')) ], ['product_id'], ['product_id']) for move in moves: product_id = move['product_id'][0] res[product_id]['delivery_count'] = move['product_id_count'] return res def view_header_get(self, cr, user, view_id, view_type, context=None): if context is None: context = {} res = super(product_product, self).view_header_get(cr, user, view_id, view_type, context) if res: return res if (context.get('active_id', False)) and (context.get('active_model') == 'stock.location'): return _('Products: ')+self.pool.get('stock.location').browse(cr, user, context['active_id'], context).name return res def _get_domain_locations(self, cr, uid, ids, context=None): ''' Parses the context and returns a list of location_ids based on it. It will return all stock locations when no parameters are given Possible parameters are shop, warehouse, location, force_company, compute_child ''' context = context or {} location_obj = self.pool.get('stock.location') warehouse_obj = self.pool.get('stock.warehouse') location_ids = [] if context.get('location', False): if type(context['location']) == type(1): location_ids = [context['location']] elif type(context['location']) in (type(''), type(u'')): domain = [('complete_name','ilike',context['location'])] if context.get('force_company', False): domain += [('company_id', '=', context['force_company'])] location_ids = location_obj.search(cr, uid, domain, context=context) else: location_ids = context['location'] else: if context.get('warehouse', False): wids = [context['warehouse']] else: wids = warehouse_obj.search(cr, uid, [], context=context) for w in warehouse_obj.browse(cr, uid, wids, context=context): location_ids.append(w.view_location_id.id) operator = context.get('compute_child', True) and 'child_of' or 'in' domain = context.get('force_company', False) and ['&', ('company_id', '=', context['force_company'])] or [] locations = location_obj.browse(cr, uid, location_ids, context=context) if operator == "child_of" and locations and locations[0].parent_left != 0: loc_domain = [] dest_loc_domain = [] for loc in locations: if loc_domain: loc_domain = ['|'] + loc_domain + ['&', ('location_id.parent_left', '>=', loc.parent_left), ('location_id.parent_left', '<', loc.parent_right)] dest_loc_domain = ['|'] + dest_loc_domain + ['&', ('location_dest_id.parent_left', '>=', loc.parent_left), ('location_dest_id.parent_left', '<', loc.parent_right)] else: loc_domain += ['&', ('location_id.parent_left', '>=', loc.parent_left), ('location_id.parent_left', '<', loc.parent_right)] dest_loc_domain += ['&', ('location_dest_id.parent_left', '>=', loc.parent_left), ('location_dest_id.parent_left', '<', loc.parent_right)] return ( domain + loc_domain, domain + ['&'] + dest_loc_domain + ['!'] + loc_domain, domain + ['&'] + loc_domain + ['!'] + dest_loc_domain ) else: return ( domain + [('location_id', operator, location_ids)], domain + ['&', ('location_dest_id', operator, location_ids), '!', ('location_id', operator, location_ids)], domain + ['&', ('location_id', operator, location_ids), '!', ('location_dest_id', operator, location_ids)] ) def _get_domain_dates(self, cr, uid, ids, context): from_date = context.get('from_date', False) to_date = context.get('to_date', False) domain = [] if from_date: domain.append(('date', '>=', from_date)) if to_date: domain.append(('date', '<=', to_date)) return domain def _product_available(self, cr, uid, ids, field_names=None, arg=False, context=None): context = context or {} field_names = field_names or [] domain_products = [('product_id', 'in', ids)] domain_quant, domain_move_in, domain_move_out = [], [], [] domain_quant_loc, domain_move_in_loc, domain_move_out_loc = self._get_domain_locations(cr, uid, ids, context=context) domain_move_in += self._get_domain_dates(cr, uid, ids, context=context) + [('state', 'not in', ('done', 'cancel', 'draft'))] + domain_products domain_move_out += self._get_domain_dates(cr, uid, ids, context=context) + [('state', 'not in', ('done', 'cancel', 'draft'))] + domain_products domain_quant += domain_products if context.get('lot_id'): domain_quant.append(('lot_id', '=', context['lot_id'])) if context.get('owner_id'): domain_quant.append(('owner_id', '=', context['owner_id'])) owner_domain = ('restrict_partner_id', '=', context['owner_id']) domain_move_in.append(owner_domain) domain_move_out.append(owner_domain) if context.get('package_id'): domain_quant.append(('package_id', '=', context['package_id'])) domain_move_in += domain_move_in_loc domain_move_out += domain_move_out_loc moves_in = self.pool.get('stock.move').read_group(cr, uid, domain_move_in, ['product_id', 'product_qty'], ['product_id'], context=context) moves_out = self.pool.get('stock.move').read_group(cr, uid, domain_move_out, ['product_id', 'product_qty'], ['product_id'], context=context) domain_quant += domain_quant_loc quants = self.pool.get('stock.quant').read_group(cr, uid, domain_quant, ['product_id', 'qty'], ['product_id'], context=context) quants = dict(map(lambda x: (x['product_id'][0], x['qty']), quants)) moves_in = dict(map(lambda x: (x['product_id'][0], x['product_qty']), moves_in)) moves_out = dict(map(lambda x: (x['product_id'][0], x['product_qty']), moves_out)) res = {} for product in self.browse(cr, uid, ids, context=context): id = product.id qty_available = float_round(quants.get(id, 0.0), precision_rounding=product.uom_id.rounding) incoming_qty = float_round(moves_in.get(id, 0.0), precision_rounding=product.uom_id.rounding) outgoing_qty = float_round(moves_out.get(id, 0.0), precision_rounding=product.uom_id.rounding) virtual_available = float_round(quants.get(id, 0.0) + moves_in.get(id, 0.0) - moves_out.get(id, 0.0), precision_rounding=product.uom_id.rounding) res[id] = { 'qty_available': qty_available, 'incoming_qty': incoming_qty, 'outgoing_qty': outgoing_qty, 'virtual_available': virtual_available, } return res def _search_product_quantity(self, cr, uid, obj, name, domain, context): res = [] for field, operator, value in domain: #to prevent sql injections assert field in ('qty_available', 'virtual_available', 'incoming_qty', 'outgoing_qty'), 'Invalid domain left operand' assert operator in ('<', '>', '=', '!=', '<=', '>='), 'Invalid domain operator' assert isinstance(value, (float, int)), 'Invalid domain right operand' if operator == '=': operator = '==' ids = [] if name == 'qty_available' and (value != 0.0 or operator not in ('==', '>=', '<=')): res.append(('id', 'in', self._search_qty_available(cr, uid, operator, value, context))) else: product_ids = self.search(cr, uid, [], context=context) if product_ids: #TODO: Still optimization possible when searching virtual quantities for element in self.browse(cr, uid, product_ids, context=context): if eval(str(element[field]) + operator + str(value)): ids.append(element.id) res.append(('id', 'in', ids)) return res def _search_qty_available(self, cr, uid, operator, value, context): domain_quant = [] if context.get('lot_id'): domain_quant.append(('lot_id', '=', context['lot_id'])) if context.get('owner_id'): domain_quant.append(('owner_id', '=', context['owner_id'])) if context.get('package_id'): domain_quant.append(('package_id', '=', context['package_id'])) domain_quant += self._get_domain_locations(cr, uid, [], context=context)[0] quants = self.pool.get('stock.quant').read_group(cr, uid, domain_quant, ['product_id', 'qty'], ['product_id'], context=context) quants = dict(map(lambda x: (x['product_id'][0], x['qty']), quants)) quants = dict((k, v) for k, v in quants.iteritems() if eval(str(v) + operator + str(value))) return(list(quants)) def _product_available_text(self, cr, uid, ids, field_names=None, arg=False, context=None): res = {} for product in self.browse(cr, uid, ids, context=context): res[product.id] = str(product.qty_available) + _(" On Hand") return res _columns = { 'reception_count': fields.function(_stock_move_count, string="Receipt", type='integer', multi='pickings'), 'delivery_count': fields.function(_stock_move_count, string="Delivery", type='integer', multi='pickings'), 'qty_available_text': fields.function(_product_available_text, type='char'), 'qty_available': fields.function(_product_available, multi='qty_available', type='float', digits_compute=dp.get_precision('Product Unit of Measure'), string='Quantity On Hand', fnct_search=_search_product_quantity, help="Current quantity of products.\n" "In a context with a single Stock Location, this includes " "goods stored at this Location, or any of its children.\n" "In a context with a single Warehouse, this includes " "goods stored in the Stock Location of this Warehouse, or any " "of its children.\n" "stored in the Stock Location of the Warehouse of this Shop, " "or any of its children.\n" "Otherwise, this includes goods stored in any Stock Location " "with 'internal' type."), 'virtual_available': fields.function(_product_available, multi='qty_available', type='float', digits_compute=dp.get_precision('Product Unit of Measure'), string='Forecast Quantity', fnct_search=_search_product_quantity, help="Forecast quantity (computed as Quantity On Hand " "- Outgoing + Incoming)\n" "In a context with a single Stock Location, this includes " "goods stored in this location, or any of its children.\n" "In a context with a single Warehouse, this includes " "goods stored in the Stock Location of this Warehouse, or any " "of its children.\n" "Otherwise, this includes goods stored in any Stock Location " "with 'internal' type."), 'incoming_qty': fields.function(_product_available, multi='qty_available', type='float', digits_compute=dp.get_precision('Product Unit of Measure'), string='Incoming', fnct_search=_search_product_quantity, help="Quantity of products that are planned to arrive.\n" "In a context with a single Stock Location, this includes " "goods arriving to this Location, or any of its children.\n" "In a context with a single Warehouse, this includes " "goods arriving to the Stock Location of this Warehouse, or " "any of its children.\n" "Otherwise, this includes goods arriving to any Stock " "Location with 'internal' type."), 'outgoing_qty': fields.function(_product_available, multi='qty_available', type='float', digits_compute=dp.get_precision('Product Unit of Measure'), string='Outgoing', fnct_search=_search_product_quantity, help="Quantity of products that are planned to leave.\n" "In a context with a single Stock Location, this includes " "goods leaving this Location, or any of its children.\n" "In a context with a single Warehouse, this includes " "goods leaving the Stock Location of this Warehouse, or " "any of its children.\n" "Otherwise, this includes goods leaving any Stock " "Location with 'internal' type."), 'location_id': fields.dummy(string='Location', relation='stock.location', type='many2one'), 'warehouse_id': fields.dummy(string='Warehouse', relation='stock.warehouse', type='many2one'), 'orderpoint_ids': fields.one2many('stock.warehouse.orderpoint', 'product_id', 'Minimum Stock Rules'), } def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False, submenu=False): res = super(product_product,self).fields_view_get(cr, uid, view_id, view_type, context, toolbar=toolbar, submenu=submenu) if context is None: context = {} if ('location' in context) and context['location']: location_info = self.pool.get('stock.location').browse(cr, uid, context['location']) fields=res.get('fields',{}) if fields: if location_info.usage == 'supplier': if fields.get('virtual_available'): res['fields']['virtual_available']['string'] = _('Future Receipts') if fields.get('qty_available'): res['fields']['qty_available']['string'] = _('Received Qty') if location_info.usage == 'internal': if fields.get('virtual_available'): res['fields']['virtual_available']['string'] = _('Future Stock') if location_info.usage == 'customer': if fields.get('virtual_available'): res['fields']['virtual_available']['string'] = _('Future Deliveries') if fields.get('qty_available'): res['fields']['qty_available']['string'] = _('Delivered Qty') if location_info.usage == 'inventory': if fields.get('virtual_available'): res['fields']['virtual_available']['string'] = _('Future P&L') if fields.get('qty_available'): res['fields']['qty_available']['string'] = _('P&L Qty') if location_info.usage == 'procurement': if fields.get('virtual_available'): res['fields']['virtual_available']['string'] = _('Future Qty') if fields.get('qty_available'): res['fields']['qty_available']['string'] = _('Unplanned Qty') if location_info.usage == 'production': if fields.get('virtual_available'): res['fields']['virtual_available']['string'] = _('Future Productions') if fields.get('qty_available'): res['fields']['qty_available']['string'] = _('Produced Qty') return res def action_view_routes(self, cr, uid, ids, context=None): template_obj = self.pool.get("product.template") templ_ids = list(set([x.product_tmpl_id.id for x in self.browse(cr, uid, ids, context=context)])) return template_obj.action_view_routes(cr, uid, templ_ids, context=context)