我遇到了一个奇怪的问题,将某个产品成本计算方法设置为平均成本,根据采购合同,入库操作均正常,但尝试了一下取消订单,系统
总是报“不能取消这个采购订单,首先取消这个采购订单相关的入库单”,可我已经对相关的入库做了退库处理,并确认了返回供应商的
的发货单,不知各位有无遇到这个问题?
bluesthink
-
将产品成本计算方法设置为平均成本时,为何无法取消采购合同。 -
Openerp BOM成本计算错误问题的解决。[quote author=digitalsatori link=topic=10066.msg21809#msg21809 date=1377742995]
@bluethink 解决方法很简单啊 ;D 。 如果这符合贵公司的要求也未尝不可。 但是,要知道这种成本的计算是很不准确的,对于一个产品有多个BOM的情况,你无法选择参与成本运算的BOM,你也无法选择或指定BOM property,希望你可以继续改进。
另外, 你的成本运算只考虑材料成本而没有考虑制造费用,理论上也是不合理的。 这里有一个模块: [检测到链接无效,已移除]
他定义了一个cost_price的函数字段,如果产品有BOM,则会计算组成该产品的物料的Standard Price之和再加上根据routing计算出的制造费用。
[b]注:[/b]如果将这个模块中计算子产品的standar_price改成新定义的cost_price, 就可以循环递归运算所有的下级bom的物料成本和相应的制造费用了。
[/quote]
1、目前我公司暂时没有用到多属性,而且老板关心的是物料成本,所以这样的改动目前能够满足要求。
2、对于制造费用分摊,有两种方式,一种是按照工时分摊,一种是按照产品成本(含新产品试制成本)分摊,我理解openerp支持的是前一种。而且对于第一种来说,由于_bom_explode2对于routing和workcenter信息是有返回的,那么report/price.py还是会做这部分的计算的。(不知理解是否正确)
3、product_cost_incl_bom这个模块我用过,是有一定的改善,但还是存在有的半成品没有展开计算以及数量不对的情况(当设置参数为小数点的时,比如将一个外购的大尺寸PVC板切割加工成小尺寸的PVC板,就需要设置类似A<-0.2B之类的BOM定义。这个时候这个模块的计算会出现错误,可以设置3级以上BOM试验一下,一定会出问题) -
Openerp BOM成本计算错误问题的解决。昨天想了一下,问题的根本在于_bom_explode函数要同时支持生产和成本计算,对于生产来说,mrp投料是一级一级的计算,不能一下子直接算出所有的原材料,否则库存中已有的半成品就消耗不掉了。而对于成本构成来说,是需要算出产品所有的原材料的。满足了生产的需求,就无法满足成本计算了。
因此解决的方法:
1、在addons/mrp/mrp.py中新建一个_bom_explode2函数
def _bom_explode2(self, cr, uid, bom, factor, properties=None, addthis=False, level=0, routing_id=False):
""" Finds Products and Work Centers for related BoM for manufacturing order.
@param bom: BoM of particular product.
@param factor: Factor of product UoM.
@param properties: A List of properties Ids.
@param addthis: If BoM found then True else False.
@param level: Depth level to find BoM lines starts from 10.
@return: result: List of dictionaries containing product details.
result2: List of dictionaries containing Work Center details.
"""
routing_obj = self.pool.get('mrp.routing')
factor = factor / (bom.product_efficiency or 1.0)
factor = rounding(factor, bom.product_rounding)
if factor < bom.product_rounding:
factor = bom.product_rounding
result = []
result2 = []
phantom = False
if bom.type == 'phantom' and not bom.bom_lines:
newbom = self._bom_find(cr, uid, bom.product_id.id, bom.product_uom.id, properties)
if newbom:
[color=blue] res = self._bom_explode2(cr, uid, self.browse(cr, uid, [newbom])[0], factorbom.product_qty, properties, addthis=True, level=level+10)[/color]
result = result + res[0]
result2 = result2 + res[1]
phantom = True
else:
phantom = False
if not phantom:
#下面三行为新增和修改,修正成本计算时bom_lines计算错误问题。
[color=blue] bom_id = self._bom_find(cr, uid, bom.product_id.id, bom.product_uom.id, properties)
bom_lines = self.browse(cr, uid, bom_id).bom_lines
if addthis and not bom_lines:[/color]
result.append(
{
'name': bom.product_id.name,
'product_id': bom.product_id.id,
'product_qty': bom.product_qty * factor,
'product_uom': bom.product_uom.id,
'product_uos_qty': bom.product_uos and bom.product_uos_qty * factor or False,
'product_uos': bom.product_uos and bom.product_uos.id or False,
})
routing = (routing_id and routing_obj.browse(cr, uid, routing_id)) or bom.routing_id or False
if routing:
for wc_use in routing.workcenter_lines:
wc = wc_use.workcenter_id
d, m = divmod(factor, wc_use.workcenter_id.capacity_per_cycle)
mult = (d + (m and 1.0 or 0.0))
cycle = mult * wc_use.cycle_nbr
result2.append({
'name': tools.ustr(wc_use.name) + ' - ' + tools.ustr(bom.product_id.name),
'workcenter_id': wc.id,
'sequence': level+(wc_use.sequence or 0),
'cycle': cycle,
'hour': float(wc_use.hour_nbrmult + ((wc.time_start or 0.0)+(wc.time_stop or 0.0)+cycle*(wc.time_cycle or 0.0)) * (wc.time_efficiency or 1.0)),
})
#从正确的bom_lines中取数据
[color=blue] for bom2 in bom_lines:[/color]
# for bom2 in bom.bom_lines:
#修改RES的计算,解决成本计算中原材料数量不对问题
[color=blue] res = self._bom_explode2(cr, uid, bom2, factor*bom.product_qty, properties, addthis=True, level=level+10)[/color]
# res = self._bom_explode(cr, uid, bom2, factor, properties, addthis=True, level=level+10)
result = result + res[0]
result2 = result2 + res[1]
return result, result2
2、修改addons/mrp/report/price.py
[color=blue] sub_boms = bom_pool._bom_explode2(cr, uid, bom, factor / bom.product_qty)[/color]
# sub_boms = bom_pool._bom_explode(cr, uid, bom, factor / bom.product_qty) -
Openerp BOM成本计算错误问题的解决。感谢指导,可是在这种情况下打印BOM成本结构,确实有问题啊,到半成品就结束了,而且半成品的成本显示为0.应该如何修改呢?
-
Openerp BOM成本计算错误问题的解决。1、对于一个产品多BOM的情况,应该是用到了properties,
bom_id = self._bom_find(cr, uid, bom.product_id.id, bom.product_uom.id, properties)
bom_id是按照propertiers查询的,能够支持一个产品多个属性的情况。若查询不到,那就用最接近的。
2、为什么要这样修改,可能我没有说清楚。
这样修改的原因是:原有bom.bom_lines的值有错误,为什么呢,和openerp BOM数据存放方式有关系
若有产品 X2,bom结构定义如下:
x2 1.000 Unit(s)
- a2 0.700 Unit(s)
- x1 3.000 Unit(s)
... - a1 0.200 Unit(s)
那么在mrp_bom表中的数据如下:(为便于理解,仅列出主要的几个字段)
id product_uom product_qty product_efficiency name product_id bom_id type
6 1 1 1 x3 7 normal
7 1 2 1 x2 5 6 normal
1 1 1 1 x1 3 normal
2 1 0.2 1 a1 2 1 normal
3 1 1 1 x2 5 normal
5 1 0.7 1 a2 6 3 normal
8 1 3 1 x1 3 3 normal
从表中数据可以看到x2,x1有两条记录,一条记录描述了本级别的BOM项,一条记录描述了和上级BOM之间的关系。 a1只被X1引用,没有下级,故只有
一条记录,a2只被x2引用,没有下级,故只有一条记录。
x2本身的id是3,那么从X2获取的子bom_lines数据,分别对应id为5和8的记录,其中8和X1相关,注意问题就出在这个地方,如果按照Bom_id为8去
获取Bom_line子项,是无法的到数据的,这就是为何BOM成本计算时计算到半成品就结束的原因。
bom_id = self._bom_find(cr, uid, bom.product_id.id, bom.product_uom.id, properties)的目的是找到X1本级别的BOM项,也就是id为1的那条记录
数据,通过bom_id=1做关联,恰好找到id为2的Bom子项目,也就是说bom_lines = self.browse(cr, uid, bom_id).bom_lines获取的子项才是正确的。
3、第三个问题,看了一下,确实_bom_explode函数在别的地方也可能有调用。这是我的失误。 -
Openerp BOM成本计算错误问题的解决。已经上报了官方的bug,但没有响应,只好自己解决了。呵呵。
-
Openerp BOM成本计算错误问题的解决。我所在的公司是一家以制造为主的企业,在成品生产的过程中,会先生产出低级别的半成品,再一级一级组装,生产出最终的成品。其中,有一些半成品是委托其他公司生产的(原材料由我们提供),库房对半成品单独管理,为了应对市场需求,有的半成品会预先生产好。 因此在做BOM定义的时候,半成品的BOM类型只能定义为Normal,不能定义为phantom。
这样就发现了一个问题(此问题在openerp6.1和openerp7.0均存在),打印产品成本构成时,成本计算到半成品就结束了,有时候原材料的数量计算也有问题。但是打印BOM结构又完全正确,当时百思不得期间,一个偶然的机会,把所有的半成品的BOM类型都改为phantom,一切OK。但这不是我想要的,于是跟踪调测mrp部分的代码,比较部件BOM类型为Normal和phantom的成本计算代码,终于解决了这个问题,需要修改addons/mrp/mrp.py中的_bom_explpde函数,
(以openerp 7.0为例,见蓝色字体),经过分析此函数仅在打印BOM成本构成时被调用,不会影响其他功能。
def _bom_explode(self, cr, uid, bom, factor, properties=None, addthis=False, level=0, routing_id=False):
""" Finds Products and Work Centers for related BoM for manufacturing order.
@param bom: BoM of particular product.
@param factor: Factor of product UoM.
@param properties: A List of properties Ids.
@param addthis: If BoM found then True else False.
@param level: Depth level to find BoM lines starts from 10.
@return: result: List of dictionaries containing product details.
result2: List of dictionaries containing Work Center details.
"""
routing_obj = self.pool.get('mrp.routing')
factor = factor / (bom.product_efficiency or 1.0)
factor = rounding(factor, bom.product_rounding)
if factor < bom.product_rounding:
factor = bom.product_rounding
result = []
result2 = []
phantom = False
if bom.type == 'phantom' and not bom.bom_lines:
newbom = self._bom_find(cr, uid, bom.product_id.id, bom.product_uom.id, properties)
if newbom:
res = self._bom_explode(cr, uid, self.browse(cr, uid, [newbom])[0], factorbom.product_qty, properties, addthis=True, level=level+10)
result = result + res[0]
result2 = result2 + res[1]
phantom = True
else:
phantom = False
if not phantom:
#下面两行为新增,修正bom_lines计算错误问题。
[color=blue] bom_id = self._bom_find(cr, uid, bom.product_id.id, bom.product_uom.id, properties)
bom_lines = self.browse(cr, uid, bom_id).bom_lines[/color]
if addthis and not bom_lines:
result.append(
{
'name': bom.product_id.name,
'product_id': bom.product_id.id,
'product_qty': bom.product_qty * factor,
'product_uom': bom.product_uom.id,
'product_uos_qty': bom.product_uos and bom.product_uos_qty * factor or False,
'product_uos': bom.product_uos and bom.product_uos.id or False,
})
routing = (routing_id and routing_obj.browse(cr, uid, routing_id)) or bom.routing_id or False
if routing:
for wc_use in routing.workcenter_lines:
wc = wc_use.workcenter_id
d, m = divmod(factor, wc_use.workcenter_id.capacity_per_cycle)
mult = (d + (m and 1.0 or 0.0))
cycle = mult * wc_use.cycle_nbr
result2.append({
'name': tools.ustr(wc_use.name) + ' - ' + tools.ustr(bom.product_id.name),
'workcenter_id': wc.id,
'sequence': level+(wc_use.sequence or 0),
'cycle': cycle,
'hour': float(wc_use.hour_nbrmult + ((wc.time_start or 0.0)+(wc.time_stop or 0.0)+cycle*(wc.time_cycle or 0.0)) * (wc.time_efficiency or 1.0)),
})
#从正确的bom_lines中取数据
[color=blue] for bom2 in bom_lines:[/color]
# for bom2 in bom.bom_lines:
#修改RES的计算,解决成本计算中原材料数量不对问题
[color=blue]res = self._bom_explode(cr, uid, bom2, factor*bom.product_qty, properties, addthis=True, level=level+10)[/color]
# res = self._bom_explode(cr, uid, bom2, factor, properties, addthis=True, level=level+10)
result = result + res[0]
result2 = result2 + res[1]
return result, result2 -
关于7.0中把原料的库存核算设为“实时(自动进行)后,原料内部调拨到生产库位投产都自动生产会计分录问题的解决经过分析跟踪原代码,发现问题出在做出入库条件判断的时候没有考虑判断生产库位,没有考虑虚拟库位的特殊性:openerp默认的虚拟库位对应Company_id是null值。生成会计分录的代码就不详细解释了,记得论坛以前有人解释过。
原代码:addons/stock/stock.py
2299 if move.product_id.valuation == 'real_time': # FIXME: product valuation should perhaps be a property?
2300 if context is None:
2301 context = {}
2302 src_company_ctx = dict(context,force_company=move.location_id.company_id.id)
2303 dest_company_ctx = dict(context,force_company=move.location_dest_id.company_id.id)
2304 account_moves = []
2305 # Outgoing moves (or cross-company output part)
2306 if move.location_id.company_id <br />2307 and (move.location_id.usage == 'internal' and move.location_dest_id.usage != 'internal'<br />2308 or move.location_id.company_id != move.location_dest_id.company_id):
2309 journal_id, acc_src, acc_dest, acc_valuation = self._get_accounting_data_for_valuation(cr, uid, move, src_company_ctx)
2310 reference_amount, reference_currency_id = self._get_reference_accounting_values_for_valuation(cr, uid, move, src_company_ctx)
2311 #returning goods to supplier
2312 if move.location_dest_id.usage == 'supplier':
2313 account_moves += [(journal_id, self._create_account_move_line(cr, uid, move, acc_valuation, acc_src, reference_amount, reference_currency_id, c ontext))]
2314 else:
2315 account_moves += [(journal_id, self._create_account_move_line(cr, uid, move, acc_valuation, acc_dest, reference_amount, reference_currency_id, context))]
2316
2317 # Incoming moves (or cross-company input part)
2318 if move.location_dest_id.company_id <br />2319 and (move.location_id.usage != 'internal' and move.location_dest_id.usage == 'internal'<br />2320 or move.location_id.company_id != move.location_dest_id.company_id):
2321 journal_id, acc_src, acc_dest, acc_valuation = self._get_accounting_data_for_valuation(cr, uid, move, dest_company_ctx)
2322 reference_amount, reference_currency_id = self._get_reference_accounting_values_for_valuation(cr, uid, move, src_company_ctx)
2323 #goods return from customer
2324 if move.location_id.usage == 'customer':
2325 account_moves += [(journal_id, self._create_account_move_line(cr, uid, move, acc_dest, acc_valuation, reference_amount, reference_currency_id, context))]
代码做如下修改:
在2306行前面加入:
company_id = self.pool.get('res.users').browse(cr, uid, uid).company_id #获得用户当前公司ID
2306行改为:
if move.location_id.company_id == company_id and (move.location_id.usage == 'internal' and move.location_dest_id.usage != 'internal' and move.location_dest_id.usage != 'production' or move.location_id.company_id != move.location_dest_id.company_id and move.location_dest_id.company_id): #注意句中无换行符号
2318行改为:
if move.location_dest_id.company_id == company_id and (move.location_id.usage != 'internal' and move.location_id.usage != 'production' and move.location_dest_id.usage == 'internal' or move.location_id.company_id != move.location_dest_id.company_id and move.location_id.company_id): #注意句中无换行符号 -
Openerp支持中文报表及模版设计的一点心得是在看英文的文档,努力中,不至于会掉到河里的。只是想分享一下而已。
-
Openerp支持中文报表及模版设计的一点心得这个星期,在研究openerp支持中文报表的问题。遇到的几个障碍基本上解决了,
网上这方面的资料很少,只好自己琢磨,今天总算是解决了,和大家分享一下,少走弯路。
1、openerp支持中文字体模块的安装
目前有两个模块可以用base_report_cn,ocen_base_fonts。
(1)安装了base_report_cn后,RML和XML报表可以显示中文,但发现webkit报表无法显示中文。
(2)安装了ocen_base_fonts,RML、XML报表和webkit报表均无法显示汉字。
今天在研究webkit报表的时候,尝试安装了CJK中文支持包(我在安装ubantu的时候选的是服务器纯英文方式)
sudo apt-get install latex-cjk-chinese*
(1)和(2)中遇到的问题均解决了。
2、报表模版的编辑
(1)尝试用base_report_designer插件在openoffice上做模版的编辑,但发现其有诸多的问题,可以修改已有的报表模版,但是无法新建模版,哪怕只用英文也不行,插件表现也不稳定,经常异常退出。(不知在英文版本的操作系统上有无这个问题)
难道一定要学习RML语言,完全手工编辑报表模版吗。
--->于是尝试(2)
(2)webkit报表
使用webkit报表时,若报错,最好下一个最新版本的wkhtmltopdf,见我另外一个帖子。问题可以解决。
下面讲如何做模版设计,可以按照这个思路来做,目前看已经是最便捷的方法了。
1、打开openoffice的文档编辑器writer,选一个最通用的英文字体。然后设计报表,比如插入一个表格。。。。
2、在需要填写公式和标题的地方,用T1,T2,T3标记。
3、将文档保存为html格式,这个时候已经有一个mako模版的半成品了。
4、用notepad++之类的工具再次打开这个文件,将刚才标记的T1、T2...依次替换为对应的公式或者汉字。
5、再次全局检查一下这个文件头部和尾部的内容,删除文件头出现GB2312、openoffice的行。将文件以utf8格式
再次保存,大功告成。 -
关于数据导入不仅仅是windows版本有这样的问题,linux版本也是这样的。openerp的导入功能做得不是一般的烂,基本上不可用。最好的数据导入方法还是直接操作数据库导入。根据模块的命名和源码很容易就可以推测出相关表的名字,再安装一个pgadm工具,就可以导入了。
可以先通过openerp界面手工输入1-2条个记录,只输入必须要输的字段,然后通过pgadm/pg_dump将其导出, 转换成CSV格式,根据输入的值可以推断出各字段的含义,然后通过exel批量的编辑,在编辑时要注意id等serial型的值是否正确。导入完毕后需要将相关的触发器值设置正确。 -
Webkit 报表打印报错
我用的操作系统版本是ubantu11.04,前2天曾经怀疑是wkhtmltopdf的问题,安装webkit_report模块的说明,检查了一下是0.9.9版本符合要求。而且用apt-get install提示已经是最新版本,就没有往这个方向考虑了。
这两日还是无解,只好到http://code.google.com/p/wkhtmltopdf上再看看,发现版本0.11.0才是最新的版本,同时看到说在ubantu上务必用静态链接库生成的wkhtmltopdf,否则可能会有页眉、页脚打印方面的问题。就尝试了一下,问题得到解决。
步骤:
1、从http://code.google.com/p/wkhtmltopdf下载文件wkhtmltopdf-0.11.0_rc1-static-amd64.tar.bz2。
2、解压得到文件wkhtmltopdf-amd64,将其改名twkhtmltopdf放到/usr/bin目录下。
3、增加执行权限: chmod 755 htmltopdf
请注意若是64位操作系统,请下载wkhtmltopdf-amd64(不论你的CPU是amd的还是intel的)。另外,研究了一下,当前
版本的webkit_report模块不需要再配置wkhtmltopdf路径了,模块会自动找到这个文件的。 -
为何base_report_designer插件可以修改报表,但不能新建报表?不准备用英文操作系统,后续准备研究一下webkit报表,如果可行,也是可以在openoffice上编辑报表模版的,这样报表模版设计更为方便。
-
Webkit 报表打印报错安装了report_webkit和report_webkit_sample模块。一打印就报错,错误如下,从日志上看是PDF文件没有生成,不知何故?
难道需要配置wkhtmltopdf的路径吗?但我在公司->webkit标签上找不到设置路径的地方啊?
2013-02-05 05:08:15,151 29967 ERROR ? openerp.service.web_services: Exception: [Errno 2] No such file or directory: '/tmp/webkit.tmp.cxwjlj.pdf'
Traceback (most recent call last):
File "/usr/lib/pymodules/python2.7/openerp/service/web_services.py", line 727, in go
(result, format) = obj.create(cr, uid, ids, datas, context)
File "/usr/lib/pymodules/python2.7/openerp/addons/report_webkit/webkit_report.py", line 325, in create
result = self.create_source_pdf(cursor, uid, ids, data, report_xml, context)
File "/usr/lib/pymodules/python2.7/openerp/report/report_sxw.py", line 509, in create_source_pdf
return self.create_single_pdf(cr, uid, ids, data, report_xml, context)
File "/usr/lib/pymodules/python2.7/openerp/addons/report_webkit/webkit_report.py", line 299, in create_single_pdf
pdf = self.generate_pdf(bin, report_xml, head, foot, htmls)
File "/usr/lib/pymodules/python2.7/openerp/addons/report_webkit/webkit_report.py", line 174, in generate_pdf
pdf = file(out_filename, 'rb').read()
IOError: [Errno 2] No such file or directory: '/tmp/webkit.tmp.cxwjlj.pdf'
2013-02-05 05:08:15,301 29967 ERROR ? openerp.netsvc: 2
No such file or directory -
为何base_report_designer插件可以修改报表,但不能新建报表?看了一下,这样转出的RML文件格式是有问题的,难道RML只能手工编辑吗?另外,我在做测试样例的时候,只用了英文。
-
报表打印时出错重启openerp,问题解决。
-
报表打印时出错另外,如何打开openerp的详细日志?
-
为何base_report_designer插件可以修改报表,但不能新建报表?找到一个变通的方法,随便从openerp的addons找到一个sxw文件,在此基础上编辑,就可以转成RML文件了。
如果在oppenoffice上新建一个空的sxw文件,则无法转RML文件。
我猜想还是SXW文件的格式问题,可能最新的oppenoffice版本和以前有不兼容的地方。 -
报表打印时出错在oecn_training_classroom的demo上做了一个最简单的报表,只打印oecn.training.lesson的name字段,可一执行打印就报错:
report.oecn.training.lesson_report
<type 'exceptions.KeyError'>,
KeyError(u'report.oecn.training.lesson_report',),
<traceback object at 0x7f05311fd320>
对代码检查了很多次,自己发现不了问题。谁能告诉我这是什么原因导致的? -
为何base_report_designer插件可以修改报表,但不能新建报表?安装了base_report_designer模块和openoffice插件,可以修改已有的报表,修改后显示也是正常的。
目前遇到的问题是新建报表有问题:新建后发送服务器后,一切显示都OK,没有报错,但在服务器上找不到相应的sxw和RML文件,同时在本地也无法生成RML文件。不知何故?
我的服务器用的是ubantu10.04,OE版本为6.1,客户端为64位 win7。