1、销售与运作规划(S&OP);
2、需求管理;
3、主生产计划(MPS)及最后总装计划(FAS);
4、物料需求计划(MRP);
5、物流清单子系统(BOM);
6、库存事务处理子系统;
7、计划接收量子系统;
8、车间作业排产、派工及控制;
9、能力需求计划(CRP);
10、投入/产出工作量控制;
11、供应商计划及采购作业;
12、分销资源计划(DRP);
13、工具计划及管理;
14、财务计划及管理;
15、模拟;
16、业绩评价;
qdfulee
-
MRP II 应该涵盖的16个子功能 -
库存明细报表的实现后台代码在附件中。说明下,前台显示的二级表头不是我做的,不能上传,见谅。
目前这个版本的效率不高,希望高手能优化下。
模块设计思路:
1、库存明细表是通过 fields_view_get 动态生成的。
2、不同库位的库存根据系统stock里product.product 中的字段 qty_available,virtual_available 读出。这两个字段的值是依据context里不同库位读出。我是通过这个功能循环产品id和库位id读出的。(这个方法挺笨的)
3、功能入口通过向导进入。向导生成的菜单如下图:
[attachimg=2]
如果安装出错,可能需要把 product.py里 fields_view_get()中下几句代码:
etree.SubElement(view, 'field', {'name': tools.ustr(location.id)+'-real', 'th_string':location.name, 'colspan':'2'})
etree.SubElement(view, 'field', {'name': tools.ustr(location.id)+'-virtual','colspan':'1'})
etree.SubElement(view, 'field', {'name': 'qty_available', 'string': u'实际库存', 'th_string': u'汇总', 'colspan':'2'})
etree.SubElement(view, 'field', {'name': 'virtual_available', 'string': u'账面库存', 'colspan':'1'})
中的'th_string' 和'colspan' 标签去掉。 -
OE 之搜索效率问题先看一段search的代码
<br /><record model="ir.ui.view" id="dispatch_work_order_filter"><br /><field name="name">dispatch.work_order.filter</field><br /><field name="model">dispatch.work_order</field><br /><field name="type">search</field><br /><field name="arch" type="xml"><br /><search string="工单"><br /><field name="name"/><br /><field name="customer"/><br /><field name="mobile"/><br /><field name="phone"/><br /><field name="address"/><br /><field name="service_card"/><br /><field name="brand"/><br /><field name="series_number"/><br /><field name="area"/><br /><field name="client_source"/><br /><field name="buy_address"/><br /><field name="engineer"/><br /><field name="department"/><br /><field name="note"/><br /><field name="check_result"/><br /><field name="measure"/><br /><field name="description_of_fault"/><br /><field name="bill_date" string="开单日期等于" filter_domain="[('bill_date','=',self)]"/><br /><field name="bill_date" string="开单日期大于" filter_domain="[('bill_date','>',self)]"/><br /><separator/><br /><field name="bill_date" string="开单日期小于" filter_domain="[('bill_date','<',self)]"/><br /><field name="appointment_date" string="预约日期等于" filter_domain="[('appointment_date','=',self)]"/><br /><field name="appointment_date" string="预约日期大于" filter_domain="[('appointment_date','>',self)]"/><br /><separator/><br /><field name="appointment_date" string="预约日期小于" filter_domain="[('appointment_date','<',self)]"/><br /><field name="visit_time" string="回访日期等于" filter_domain="[('appointment_date','=',self)]"/><br /><field name="visit_time" string="回访日期大于" filter_domain="[('appointment_date','>',self)]"/><br /><separator/><br /><field name="visit_time" string="回访日期小于" filter_domain="[('appointment_date','<',self)]"/><br /><field name="done_date" string="完工日期等于" filter_domain="[('done_date','=',self)]"/><br /><field name="done_date" string="完工日期大于" filter_domain="[('done_date','>',self)]"/><br /><separator/><br /><field name="done_date" string="完工日期小于" filter_domain="[('done_date','<',self)]"/><br /><field name="bill_month"/><br /><field name="create_uid"/><br /><field name="done_month"/><br /><separator/><br /><filter icon="terp-check" domain="[('state','=','draft')]" string="待派工" name="done0"/><br /><filter icon="ter-check" domain="[('state','=','dealing')]" string="待报工" name="dealing0"/><br /><filter icon="terp-check" domain="[('state','=','done')]" string="待交单" name="reply0"/><br /><filter icon="terp-check" domain="[('state','=','reply')]" string="待回访" name="visit0"/><br /><separator/><br /><filter icon="terp-check" domain="[('state_use_card','=','0')]" string="不扣卡" name="state_use_card0"/><br /><filter icon="terp-check" domain="[('state_use_card','=','1')]" string="需扣卡" name="state_use_card1"/><br /><separator/><br /><filter icon="terp-check" domain="[('state','=','draft')]" string="草稿" name="draft"/><br /><filter icon="terp-check" domain="[('state','=','dealing')]" string="已派工" name="dealing"/><br /><filter icon="terp-check" domain="[('state','=','done')]" string="已完工" name="done"/><br /><filter icon="terp-check" domain="[('state','=','reply')]" string="已交单" name="reply"/><br /><filter icon="terp-check" domain="[('state','=','visit')]" string="已回访" name="visit"/><br /><separator/><br /><filter icon="terp-check" domain="[('evaluate','=','very_satisfied')]" string="非常满意" name="very_satisfied"/><br /><filter icon="terp-check" domain="[('evaluate','=','satisfied')]" string="满意" name="satisfied"/><br /><filter icon="terp-check" domain="[('evaluate','=','discontent')]" string="不满" name="discontent"/><br /><filter icon="terp-check" domain="[('evaluate','=','visit')]" string="非常不满" name="very_discontent"/><br /><separator/><br /><group expand="0" string="分组"><br /><filter string="按月" icon="terp-personal" domain="[]" context="{'group_by':'bill_month'}"/><br /><filter string="客户" icon="terp-personal" domain="[]" context="{'group_by':'customer'}"/><br /><filter string="服务卡" icon="terp-personal" domain="[]" context="{'group_by':'service_card'}"/><br /><filter string="品牌型号" icon="terp-personal+" domain="[]" context="{'group_by':'brand'}"/><br /><filter string="工程师" icon="terp-personal" domain="[]" context="{'group_by':'engineer'}"/><br /><filter string="部门" icon="terp-personal+" domain="[]" context="{'group_by':'department'}"/><br /><filter string="区域" icon="terp-personal+" domain="[]" context="{'group_by':'area'}"/><br /><filter string="客户来源" icon="terp-personal+" domain="[]" context="{'group_by':'client_source'}"/><br /><filter string="购机地点" icon="terp-personal+" domain="[]" context="{'group_by':'buy_address'}"/><br /><filter string="维修类型" icon="terp-personal+" domain="[]" context="{'group_by':'warranty_type'}"/><br /><filter string="维修方式" icon="terp-personal+" domain="[]" context="{'group_by':'repair_method'}"/><br /><filter string="客户评价" icon="terp-personal+" domain="[]" context="{'group_by':'evaluate'}"/><br /><filter string="状态" icon="terp-stock_effects-object-colorize" domain="[]" context="{'group_by':'state'}"/><br /></group><br /></search><br /></field><br /></record><br />
要说明什么问题呢?
当用户数据量比较多的时候,这样的搜索视图效率就会越来越低。
原因是OE是根据输入不断的向服务器请求数据。如果用户输入速度慢,同时匹配的数据项由比较多,那么原先出于人体工学考虑的搜索就会出现卡顿现象。
有两个方法可以解决,一是search不要太复杂,二是用wizard做精准的搜索条件然后一次提交。 -
库存明细报表的实现OE当前的功能里,查询库存要么是所有产品所有库位一张表,要么是一个产品在不同库位的数量分布,无法在一张表上实现多个产品多个库位的明细。
于是就有了如下的代码:# -*- coding: utf-8 -*-<br />from openerp.osv import osv,fields<br />from lxml import etree<br />from openerp import tools<br /><br /><br />class product_product(osv.osv):<br /> _inherit = "product.product"<br /><br /> def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False, submenu=False):<br /> res = super(product_product, self).fields_view_get(cr, uid, view_id, view_type, context, toolbar=toolbar, submenu=submenu)<br /> if context.get('inventory_list') == True and view_type == 'tree':<br /> loc_obj = self.pool.get('stock.location')<br /> locations = loc_obj.browse(cr, uid, loc_obj.search(cr, uid, [('child_ids', '=', False), ('usage', '=', 'internal')]))<br /> view = etree.fromstring(res['arch'])<br /> fields_list = res['fields']<br /> for location in locations:<br /> fields_list[tools.ustr(location.id)+'-real'] = {'type': 'float', 'string': location.name+'-实际库存'}<br /> fields_list[tools.ustr(location.id)+'-virtual'] = {'type': 'float', 'string': location.name+'-账面库存'}<br /> etree.SubElement(view, 'field', {'name': tools.ustr(location.id)+'-real'})<br /> etree.SubElement(view, 'field', {'name': tools.ustr(location.id)+'-virtual'})<br /> res['arch'] = etree.tostring(view)<br /> return res<br /><br /> def read(self, cr, uid, ids, fields=None, context=None, load='_classic_read'):<br /> result = super(product_product, self).read(cr, uid, ids, fields=fields, context=context)<br /> if context.get('inventory_list') == True:<br /> locations = []<br /> for field in fields:<br /> s = field.split('-')<br /> if len(s) == 2:<br /> if s[1] == 'real':<br /> locations.append(int(s[0]))<br /> i = 0<br /> for id in ids:<br /> for location in locations:<br /> context['location'] = location<br /> val = super(product_product, self).read(cr, uid, id, ['qty_available', 'virtual_available'], context, )<br /> result[i][tools.ustr(location)+'-real'] = val['qty_available']<br /> result[i][tools.ustr(location)+'-virtual'] = val['virtual_available']<br /> i += 1<br /> return result
实现的效果附件 -
OPENERP CRM应该拓展的报表正式阐释CRM拓展前,首先说下客户对信息化系统的潜在需求.所谓潜在需求是指客户大多数时候不会直接提出来,但需要实施公司满足的需求.
信息系统必须体现管理思想,满足企业三个层面的潜在需求.
第一个层面 战略层(企业决策层):
战略项目和企业关键业绩点的多维统计功能.该项功能最好能够达到抽丝剥茧后体现出相关业绩点的关联关系.
第二个层面 战术层(企业各业务单元负责人):
1、需要在流程中体现相关业务单元的制约、协作关系,且流程要简洁高效。
2、业务单元数据分析,需要实时跟踪其关键业绩指标的变化,以满足其及时调整战术的需要。
第三个层面 战斗层(系统的数据采集点):
这个层面的工作相对单一、工作量大,所以数据采集要尽量简单、明了、易懂。
下面切入正题
OPENERP的CRM在战术层上的功能略显单薄,管理思想没有体现出来。个人认为需要关注如下几个点内容:
1、营销渠道的绩效。
2、不同客户类别的绩效。
3、新增客户的绩效。
4、老客户的绩效。
如上几点可以通过几类报表实现
1、营销渠道下新增客户的分布、成交分布、客户类别分布。
2、新增客户 、客户成交总额、首次和二次成交 随时间的动态分布报表。
3、商机各阶段平均时间报表。
如上报表应该可以和产品及其分类关联 -
OPENERP 构建动态视图在openerp展示界面通常是通过定义class的view(xml文件)来实现的。
有时这种方法不能支持用户自定义字段的需求,于是就可以通过重写fields_view_get()、 read()来实现。
实例代码<br /><br /># -*- coding: utf-8 -*-<br />from openerp.osv import osv,fields<br />from lxml import etree<br />from openerp import tools<br />from openerp.tools import to_xml<br /><br /><br /><br /><br />class AnalysisQuestionnaireType(osv.osv):<br /> _name = 'analysis.questionnaire.type'<br /> _description = '问卷类型'<br /> _columns = {<br /> 'name': fields.char('名称', size=125, required=True),<br /> 'analysis_set': fields.many2many('analysis.title.set', id1='analysis_questionnaire_type_id',<br /> id2='analysis_title_set_id', string='主题'),<br /> }<br /><br /><br /><br /><br />class AnalysisTitleSet(osv.osv):<br /> _name = "analysis.title.set"<br /> _description = "主题"<br /> _columns = {<br /> "name": fields.char(string="名称", size=125, required=True,),<br /> 'analysis_questionnaire_type': fields.many2many('analysis.questionnaire.type',<br /> id1='analysis_title_set_id',<br /> id2='analysis_questionnaire_type_id',<br /> string='问卷类型'),<br /> "analysis_title": fields.one2many('analysis.title', 'set', '题目'),<br /> }<br /><br /><br /><br /><br />class AnalysisTitle(osv.osv):<br /> _name = "analysis.title"<br /> _description = "题目"<br /> _columns = {<br /> "name": fields.char(string="名称", size=125, required=True),<br /> "note": fields.text("描述"),<br /> "set": fields.many2one("analysis.title.set", string="主题", required=True),<br /> 'type': fields.selection([('multiple_choice_only_one_ans', '单项选择'),<br /> ('multiple_choice_multiple_ans', '多项选择'),<br /> ('matrix_of_choices_only_one_ans', '单选组合'),<br /> ('single_textbox', '单行文本框'),<br /> ('multiple_textbox', '多个单行文本框'),<br /> ('comment', '多行文本框'),<br /> ('date', '日期框'),<br /> ('date_and_time', '日期时间框'),<br /> ('descriptive_text', '描述性文本'),<br /> ('attachment', '附件'),<br /> ('image', '图片'),<br /> ], '题目类型', required=1,),<br /> 'is_require_answer': fields.boolean('必填项'),<br /> 'option_id': fields.one2many('analysis.title.option', 'title_id', '备选答案'),<br /> 'column_heading_ids': fields.one2many('analysis.title.column.heading', 'title_id', '标题'),<br /> 'descriptive_text': fields.text('描述文本'),<br /> }<br /><br /><br /><br /><br />class AnalysisTitleOption(osv.osv):<br /> _name = 'analysis.title.option'<br /> _description = '答案选项'<br /> _columns = {<br /> 'title_id': fields.many2one('analysis.title', '题目', ondelete='cascade'),<br /> 'option': fields.char('答案选项', size=128, required=True),<br /> 'type': fields.selection([('char', '字符型'),<br /> ('date', '日期'),<br /> ('datetime', '日期时间型'),<br /> ('integer', '整数型'),<br /> ('float', '小数型'),<br /> ('selection', '选择型')],<br /> '答案类型',<br /> required=True),<br /><br /><br /> }<br /><br /><br /><br /><br />class AnalysisTitleColumnHeading(osv.osv):<br /> _name = 'analysis.title.column.heading'<br /> _description = '选项标题'<br /> _columns = {<br /> 'name': fields.char('选项标题', size=128, required=True),<br /> 'title_id': fields.many2one('analysis.title', '题目', ondelete='cascade'),<br /> }<br /><br /><br /><br /><br />class AnalysisAnswer(osv.osv):<br /> _name = 'analysis.answer'<br /> _description = '答案'<br /> _columns = {<br /> 'analysis_questionnaire': fields.many2one('analysis.questionnaire', '问卷'),<br /> 'value': fields.text('值')<br /> }<br /><br /><br /><br /><br />class AnalysisQuestionnaire(osv.osv):<br /> _name = 'analysis.questionnaire'<br /> _description = '分析问卷'<br /><br /><br /> _columns = {<br /> "name": fields.char(string='名称', size=125, required=True),<br /> 'type': fields.many2one('analysis.questionnaire.type', string='类型', required=True),<br /> 'title': fields.one2many('analysis.answer', "analysis_questionnaire", "答案"),<br /> }<br /><br /><br /> def default_get(self, cr, uid, fields_list, context=None):<br /> default = super(AnalysisQuestionnaire, self).default_get(cr, uid, fields_list, context=context)<br /> con = context.get('type')<br /> default['type'] = con<br /> return default<br /><br /><br /> def view_init(self, cr, uid, fields_list, context=None):<br /> pass<br /><br /><br /> def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False, submenu=False,):<br /> if context is None:<br /> context = {}<br /> result = super(AnalysisQuestionnaire, self).fields_view_get(cr, uid, view_id,<br /> view_type=view_type, context=context,<br /> toolbar=toolbar, submenu=submenu)<br /> if view_type == 'form' and context.has_key('type'):<br /> view = etree.fromstring(result['arch'])<br /> fields = result['fields']<br /> print etree.tostring(view)<br /> notebook = etree.SubElement(view, 'notebook')<br /> sets = self.pool.get('analysis.questionnaire.type').browse(cr, uid, context['type']).analysis_set<br /> q_no = 0<br /> for set in sets:<br /> page = etree.SubElement(notebook, 'page', string=set.name)<br /> for title in set.analysis_title:<br /> q_no += 1<br /> etree.SubElement(page, 'newline')<br /> if title.is_require_answer:<br /> etree.SubElement(page, 'separator', {'string': '*'+tools.ustr(q_no)+'.'+tools.ustr(title.name)})<br /> else:<br /> etree.SubElement(page, 'separator', {'string': tools.ustr(q_no)+'.'+tools.ustr(title.name)})<br /><br /><br /> if title.type == 'multiple_choice_only_one_ans':<br /> parent = etree.SubElement(page, 'group')<br /> selection = []<br /> for option in title.option_id:<br /> selection.append((tools.ustr(option.id), option.option))<br /> fields['title'+'_'+tools.ustr(title.id)+'_selection'] = {'type': 'selection',<br /> 'selection': selection,<br /> 'name': title.name}<br /> etree.SubElement(parent, 'field', {'name': 'title'+'_'+tools.ustr(title.id)+'_selection'})<br /> elif title.type == 'multiple_choice_multiple_ans':<br /> parent = etree.SubElement(page, 'group', {'col': '4', 'colspan': '4'})<br /> for option in title.option_id:<br /> etree.SubElement(parent, 'field', {'name': 'title'+'_'+tools.ustr(title.id)+'-'+'option'+'_'<br /> + tools.ustr(option.id)})<br /> fields['title'+'_'+tools.ustr(title.id)+'-'+'option'+'_'<br /> + tools.ustr(option.id)] = {'type': 'boolean', 'string': option.option}<br /> elif title.type == 'matrix_of_choices_only_one_ans':<br /> parent = etree.SubElement(page, 'group', {'col': '2', 'colspan': '2'})<br /> selection = []<br /> for option in title.option_id:<br /> selection.append((tools.ustr(option.id), option.option))<br /> for col in title.column_heading_ids:<br /> etree.SubElement(parent, 'newline')<br /> etree.SubElement(parent, 'field', {'name': 'title'+'_'+tools.ustr(title.id)+'-'+'col'+'_'<br /> + tools.ustr(col.id),<br /> })<br /> fields['title'+'_'+tools.ustr(title.id)+'-'+'col'+'_'<br /> + tools.ustr(col.id)] = {'type': 'selection', 'selection': selection}<br /> elif title.type == 'single_textbox':<br /> parent = etree.SubElement(page, 'group',)<br /> etree.SubElement(parent, 'field', {'name': 'title'+'_'+tools.ustr(title.id) + "_single",<br /> 'nolabel': "1",<br /> 'colspan': "4"})<br /> fields['title'+'_'+tools.ustr(title.id) + "_single"] = {'type': 'char', 'size': 255}<br /> elif title.type == 'multiple_textbox':<br /> parent = etree.SubElement(page, 'group', {'col': '4', 'colspan': '4'})<br /> for col in title.column_heading_ids:<br /> fields['title'+'_'+tools.ustr(title.id)+'-'+'col'+'_'+tools.ustr(col.id)] = {'type': 'char',<br /> 'size': 255}<br /> etree.SubElement(parent, 'field', {'width': '300',<br /> 'colspan': '1',<br /> 'name': 'title'+'_'+tools.ustr(title.id)+'-'+'col'+'_'<br /> + tools.ustr(col.id)})<br /> elif title.type == 'comment':<br /> parent = etree.SubElement(page, 'group')<br /> etree.SubElement(parent, 'field', {'name': 'title'+'_'+tools.ustr(title.id) + "_comment",<br /> 'nolabel': "1",<br /> 'colspan': "4"})<br /> fields['title'+'_'+tools.ustr(title.id) + "_comment"] = {'type': 'text'}<br /> elif title.type == 'date':<br /> parent = etree.SubElement(page, 'group', {'col': '4', 'colspan': '4'})<br /> for col in title.column_heading_ids:<br /> fields['title'+'_'+tools.ustr(title.id)+'-'+'col'+'_'+tools.ustr(col.id)] = {'type': 'date'}<br /> etree.SubElement(parent, 'field', {'name': 'title'+'_'+tools.ustr(title.id)+'-'+'col'+'_'<br /> + tools.ustr(col.id)})<br /> elif title.type == 'date_and_time':<br /> parent = etree.SubElement(page, 'group', {'col': '4', 'colspan': '4'})<br /> for col in title.column_heading_ids:<br /> fields['title'+'_'+tools.ustr(title.id)+'-'<br /> + 'col'+'_'+tools.ustr(col.id)] = {'type': 'datetime'}<br /> etree.SubElement(parent, 'field', {'name': 'title'+'_'+tools.ustr(title.id)+'-'+'col'+'_'<br /> + tools.ustr(col.id)})<br /> elif title.type == 'attachment':<br /> parent = etree.SubElement(page, 'group',)<br /> fields['title'+'_'+tools.ustr(title.id)+'_attachment'] = {'type': 'binary'}<br /> etree.SubElement(parent, 'field', {'name': 'title'+'_'+tools.ustr(title.id)+'_attachment'})<br /> elif title.type == 'descriptive_text':<br /> parent = etree.SubElement(page, 'group')<br /> if title.descriptive_text:<br /> for que_test in title.descriptive_text.split('\n'):<br /> etree.SubElement(parent, 'label', {'string': to_xml(tools.ustr(que_test)),<br /> 'align': "0.0"})<br /> elif title.type == 'image':<br /> parent = etree.SubElement(page, 'group',)<br /> fields['title'+'_'+tools.ustr(title.id)+'_image'] = {'type': 'binary'}<br /> etree.SubElement(parent, 'field', {'name': 'title'+'_'+tools.ustr(title.id)+'_image',<br /> 'widget': 'image'})<br /> result['arch'] = etree.tostring(view)<br /> return result<br /><br /><br /> def create(self, cr, uid, vals, context=None):<br /> answer_obj = self.pool.get("analysis.answer")<br /> questionnaire_vals = {'name': vals.get('name'), 'type': vals.get('type')}<br /> vals.pop('name', "not name")<br /> vals.pop('type', 'not type')<br /> answer_vals = {}<br /> questionnaire_id = super(AnalysisQuestionnaire, self).create(cr, uid, questionnaire_vals, context=context)<br /> answer_vals['analysis_questionnaire'] = questionnaire_id<br /> answer_vals['value'] = vals<br /> answer_obj.create(cr, uid, answer_vals, context=context)<br /> return questionnaire_id<br /><br /><br /> def read(self, cr, user, ids, fields=None, context=None, load='_classic_read'):<br /> result = super(AnalysisQuestionnaire, self).read(cr, user, ids, fields=fields, context=context, load=load)<br /> answer_obj = self.pool.get('analysis.answer')<br /> i = 0<br /> while i < len(result):<br /> answer_list = answer_obj.search(cr, user, [('analysis_questionnaire', '=', result['id'])])<br /> if answer_list:<br /> val = eval(answer_obj.read(cr, user, answer_list, ['value'], context=context)[0]['value'])<br /> result.update(val)<br /> i += 1<br /> return result<br />
[i]
[color=rgb(69, 69, 69)][font=tahoma][size=14px]上述代码用户可以自己定义问卷题目及题目类型。通过fields_view_get()画出view,然后把动态构建的字段及其值通过重写create()把数据存储到另外一个表里。这里用的是一个text字段把create返回的值直接存储起来的。当需要查看保存过的数据时,通过重写read()整理成需要的数据格式返回。[/size][/font][/color][/i] -
解决Document上传中文docx\pptx\xlsx\doc无法获得正确内容索引的问题[quote author=佛山-姜 link=topic=11888.msg21802#msg21802 date=1377701845]
是指中文文件名称吗???
[/quote]
是中文文本的doc,docx等文件,在文档模块中内容索引为乱码。 -
解决Document上传中文docx\pptx\xlsx\doc无法获得正确内容索引的问题[quote author=mrshelly link=topic=11888.msg21811#msg21811 date=1377747427]
了解.... 能给贴子加点 Tag 吗. 这样会更便于检索..
[/quote]
加了,不长写帖子,见谅。 -
解决Document上传中文docx\pptx\xlsx\doc无法获得正确内容索引的问题主题如题,不多描述。解决方法:
1、openerp\addons\document\std_index.py中修改类似“res = toString().encode('ascii','replace')”的代码为“res = toString().encode('utf-8','replace')”
这个修改解决pptx\docx\xlsx
2、linux下安装antiword,这个解决doc的问题。 -
OE开发中错误信息的调用直接代码
def dispatch_work_order_reduce_card_times(self,cr,uid,ids,context=None):<br /> <br /> service_card_id=self.read(cr,uid,ids,["service_card"],context)[0]["service_card"][0]<br /> if service_card_id:<br /> obj=self.pool.get("dispatch.service_card").read(cr,uid,service_card_id,["due_date","remaining_times"],context)<br /> if obj["remaining_times"]<1:<br /> raise osv.except_osv(_('Error!'), _('服务卡剩余次数为:0.'))
-
Fields.function中的fnct为什么要返回字典类型初学者的浅薄的领悟,高手飘过吧。
写一个小练习的时候出现的问题,幸亏总监指点。
fnct之所以返回字典类型,可能考虑form和tree处理不同数量记录的通用性。 这样设计是不是同样因为oe数据处理的基本单位是整张表呢? -
Openerp 中的 domainoe中的domain多用于自定义搜索条件。
domain中的单个条件是一个三个元素组成的元组。第一个是对象的一个column,也就是字段名;第二个是比较运算符=, !=, >, >=, <, <=, like, ilike, in, not in, child_of, parent_left, parent_right
;第三个就是用来比较的值了。多个条件用“|”(or),“&”(and),“!”(no)逻辑运算符链接。逻辑运算符作为前缀放置于条件前面。“|”与“&”必须两个条件链接,“!”对一个条件取反。默认逻辑运算符为“&”。
举个例子:
['|','|',('group_ids','in',[g.id for g in user.groups_id]), ('user_id', '=', user.id), '&', ('user_id', '=', False), ('group_ids','=',False), '|','|', ('company_id','=',False), ('company_id','child_of',[user.company_id.id]),('company_id.child_ids','child_of',[user.company_id.id])]
这个例子的意思是:
['|',
'|',('group_ids','in',[g.id for g in user.groups_id]), ('user_id', '=', user.id),
'&', ('user_id', '=', False), ('group_ids','=',False),
'|',
'|', ('company_id','=',False), ('company_id','child_of',[user.company_id.id]),
('company_id.child_ids','child_of',[user.company_id.id])]
写个容易看的方式:
(('group_ids','in',[g.id for g in user.groups_id]) or ('user_id', '=', user.id)) or (('user_id', '=', False) and ('group_ids','=',False)) or (('company_id','=',False) or ('company_id','child_of',[user.company_id.id])) or ('company_id.child_ids','child_of',[user.company_id.id])