Odoo中文社区可以通过以下三个域名访问:shine-it.net , odoocn.org,odoo.net.cn

原论坛用户的基本信息和发帖这里都予以保留,请注意:原论坛用户无需重新注册新用户,但是您的密码需要重置

开发人员可以登录gitter讨论组: http://gitter.im/odoo-china/Talk, 需要github账号

如果您登录系统碰到问题,请在微信公众号留言:

源码阅读注解: sale.py 中 product_id_change 函数



  • 今天读了一下 sale.py 中 product_id_change 函数,<br /><br />水平不高, 读得累, 花了2小时<br /><br />笔记如下, 一起学习 :<br /><br />===  视图中调用的定义  == <br /><br />    <field name="product_id"<br /> context="{'partner_id':parent.partner_id, 'quantity':product_uom_qty, 'pricelist':parent.pricelist_id, 'shop':parent.shop_id, 'uom':product_uom}"<br /> groups="base.group_user"<br /> on_change="product_id_change(parent.pricelist_id, product_id, product_uom_qty, product_uom, product_uos_qty, product_uos, name, <br /> <br /> parent.partner_id, False, True, parent.date_order, False, parent.fiscal_position, False, context)"/><br /><br />parent.partner_id<br />parent.date_order<br /><br />这种用法, 我估计是 取 得当前 的 one2many 字段所在 form的 其它字段 的值<br />    <br />= 以下为  py 中的对应函数  ===============================================================================================================<br /><br />    def product_id_change(self, cr, uid, ids, pricelist, product, qty=0,<br />            uom=False, qty_uos=0, uos=False, name='', partner_id=False,<br />            lang=False, update_tax=True, date_order=False, packaging=False, fiscal_position=False, flag=False, context=None):<br />        context = context or {}<br />        lang = lang or context.get('lang',False)<br />        <br /> # 判断, 选择产品前,必须先选择  客户<br /> if not  partner_id:<br />            raise osv.except_osv(_('No Customer Defined !'), _('Before choosing a product,\n select a customer in the sales form.'))<br /><br /> <br /> warning = {}<br />        product_uom_obj = self.pool.get('product.uom')<br />        partner_obj = self.pool.get('res.partner')<br />        product_obj = self.pool.get('product.product')<br /><br /><br /> # 准备好 context , 包括 语言 和 客户ID<br /> context = {'lang': lang, 'partner_id': partner_id}<br /> if partner_id:<br />            lang = partner_obj.browse(cr, uid, partner_id).lang<br /> # 准备第二个 context, 语言 改为 客户的 lang<br />        context_partner = {'lang': lang, 'partner_id': partner_id}<br /><br /><br /><br /> # 如果将 产品选中为 空(即 清空产品后), 重量 置0 , 产品销售单位数量 设为 qyt ,  产品单位, 产品小数单位 的 domain 清空, 返回<br />        if not product:<br />            return {'value': {'th_weight': 0,<br />                'product_uos_qty': qty}, 'domain': {'product_uom': [],<br />                  'product_uos': []}}<br /><br /> # 如果订单尚未指定 订单日期, 则 取得默认的 日期, 字串类型str<br />        if not date_order:<br />            date_order = time.strftime(DEFAULT_SERVER_DATE_FORMAT)<br /><br />        result = {}<br />        warning_msgs = {}<br /><br />        # 如果传入的 product(=product_id) 有值, 则打开该 ID 对应的对象<br /> product_obj = product_obj.browse(cr, uid, product, context=context_partner)<br /><br />        <br /> ######### 下面开始处理单位<br /> <br /> uom2 = False<br />        if uom:<br />     # 根据 uom 取得单位的 对象<br />            uom2 = product_uom_obj.browse(cr, uid, uom)<br /><br />     # 如果 产品默认的 计量单位的类别和 输入参数中单位的 类别不一致, <br />            if product_obj.uom_id.category_id.id != uom2.category_id.id:<br /> uom = False  # 将 传入的单位设置为 空<br /><br /><br /><br />        if uos:<br />            if product_obj.uos_id:<br />                uos2 = product_uom_obj.browse(cr, uid, uos)<br />                if product_obj.uos_id.category_id.id != uos2.category_id.id:<br />                    uos = False # 如果产品的销售单位 跟 输入参数的销售单位 类别不一致, , 也将 传入的 销售单位置空<br />            else:<br />                uos = False # 如果 产品的 销售单位 未指定, 此处的销售单位也必须为空<br /><br /><br /> # fiscal_position 财务替换规则<br /> # 根据 ID 取得 财务替换规格的 对象<br />        fpos = fiscal_position and self.pool.get('account.fiscal.position').browse(cr, uid, fiscal_position) or False<br /><br /> # 根据 财务替换规则 和 产品的 税务设定 进行 映射<br /> if update_tax: #The quantity only have changed<br />            result['tax_id'] = self.pool.get('account.fiscal.position').map_tax(cr, uid, fpos, product_obj.taxes_id)<br /><br /><br /><br /> # flag 是个标识 ,因为 本函数 是多个字段 定义为对应的 onchange 函数, 某些 字段的 onchange 会输入参数  flag = True<br />        if not flag:<br />            result['name'] = self.pool.get('product.product').name_get(cr, uid, [product_obj.id], context=context_partner)[0][1]    # 这里的  context_partner 已经包含了客户的语言 , 取得输入产品的 名称(根据客户的语言翻译好)<br />            if product_obj.description_sale:    # 如果产品里设置了 销售说明字段 , 则添加上 <br />                result['name'] += '\n'+product_obj.description_sale      #  等价于  result['name'] =  result['name'] + '\n'+product_obj.description_sale <br /><br />        domain = {}<br /><br />        <br /> <br /> #  根据前面的单位 计算  销售单位的数量  以及  单位字段的 domain<br /><br /><br /><br /> if (not uom) and (not uos): # 如果 计量单位和销售单位 都 无效 (可能是 没输入,也可能 是被前面 检查后置空了)<br />            result['product_uom'] = product_obj.uom_id.id<br /><br />     if product_obj.uos_id: # 产品中指定了销售单位<br />                result['product_uos'] = product_obj.uos_id.id # 从产品取 销售单位<br />                result['product_uos_qty'] = qty * product_obj.uos_coeff # 根据 转换系数 和 输入的 数量 计算 销售单位对应数量<br />                uos_category_id = product_obj.uos_id.category_id.id # 销售单位的类别 ID, 用于 后面的 对 销售单位设置 domain<br />            else:<br />                result['product_uos'] = False # 产品中没有 销售单位, 则销售单位置空<br />                result['product_uos_qty'] = qty # 销售单位数量 = 输入的数量(计量单位对应数量)<br />                uos_category_id = False # 销售单位的类别 ID, 用于 设置 domain, 设为 false 将导致 销售单位 无法选择<br /><br />            result['th_weight'] = qty * product_obj.weight # 计算本行产品的重量 =  数量 * 单个重量<br />            domain = {'product_uom':<br />                        [('category_id', '=', product_obj.uom_id.category_id.id)], # 修改 计量单位的 product_uom 的 domain , 仅允许同类单位可选<br />                        'product_uos':<br />                        [('category_id', '=', uos_category_id)]} # 同上<br /><br /><br /><br />        elif uos and not uom: # only happens if uom is False # 销售单位有效,  计量单位无效<br />            result['product_uom'] = product_obj.uom_id and product_obj.uom_id.id # 取得产品中设置的  计量单位<br />            result['product_uom_qty'] = qty_uos / product_obj.uos_coeff # 根据 销售单位数量 / 系数  , 倒算出 计量单位数量<br />            result['th_weight'] = result['product_uom_qty'] * product_obj.weight # 计算重量 计量单位数量 * 单个产品重量<br /><br /><br /><br />        elif uom: # whether uos is set or not # 计量单位有效 , 销售单位 不确定<br /><br />            default_uom = product_obj.uom_id and product_obj.uom_id.id # 默认计量单位 从 产品中取得<br />            q = product_uom_obj._compute_qty(cr, uid, uom, qty, default_uom) # 根据输入单位 , 输入的数量 以及 产品的默认计量单位 , 计算数量(根据单位的比例关系进行转换)<br />            result['product_uom'] = default_uom # 返回默认单位<br /><br />            if product_obj.uos_id:<br />                result['product_uos'] = product_obj.uos_id.id # 如果产品设置了  销售单位 , 则从产品 取得 销售单位<br />                result['product_uos_qty'] = qty * product_obj.uos_coeff # 根据输入数量和 转换系数计算出 产品的销售单位 数量<br />            else:<br />                result['product_uos'] = False # 产品 没有设置 销售单位<br />                result['product_uos_qty'] = qty # 销售单位数量 直接 设为 输入数量<br />            result['th_weight'] = q * product_obj.weight        # Round the quantity up # 重量 为 折算的单个产品数量 * 单个产品的重量  ( 产品设置的默认计量单位和 产品行的输入的计量单位不一致时, 前面已经折算)<br /><br />        if not uom2: # uom2 是前面 检查 uom 时 取得的 uom 对应的 对象, <br />            uom2 = product_obj.uom_id # 如果前面 uom 尚未取得值, 这里就直接取得 产品对象中 所属 的 uom 对象<br /><br /><br /><br />        # get unit price<br /> # 下面 开始 取得单价 <br /><br />        if not pricelist:  <br />            warn_msg = _('You have to select a pricelist or a customer in the sales form !\n' #  没有指定 价格表, 抛错<br />                    'Please set one before choosing a product.')<br />            warning_msgs += _("No Pricelist ! : ") + warn_msg +"\n\n"<br />        else:<br />            price = self.pool.get('product.pricelist').price_get(cr, uid, [pricelist], # 根据产品, 数量, 客户 , 计量单位, 订单日期 等信息 ( price_get 待 进一步 解读)<br />                    product, qty or 1.0, partner_id, {<br />                        'uom': uom or result.get('product_uom'),<br />                        'date': date_order,<br />                        })[pricelist] # price_get 返回一个以 pricelist 为 key 的 字典, 包含价格<br /><br />            if price is False:<br />                warn_msg = _("Cannot find a pricelist line matching this product and quantity.\n" # 如果 取得的 price 失败, 抛错<br />                        "You have to change either the product, the quantity or the pricelist.")<br /><br />                warning_msgs += _("No valid pricelist line found ! :") + warn_msg +"\n\n"<br />            else:<br />                result.update({'price_unit': price}) #  取得 单价<br /><br />        if warning_msgs: # 如果前面的 计算过程 包括 了警告信息,这 构造一个 字典予以返回<br />            warning = {<br />                      'title': _('Configuration Error!'),<br />                      'message' : warning_msgs<br />                    }<br />        return {'value': result, 'domain': domain, 'warning': warning} # onchang 函数 返回 三个字典: <br /> # 'value': result, 修改的字段值, 以字段名为 key<br /> # 'domain': domain, 也是以 字段名为key<br /> # 'warning': warning



  • 今天读了一下 sale.py 中 product_id_change 函数,<br /><br />水平不高, 读得累, 花了2小时<br /><br />笔记如下, 一起学习 :<br /><br />===  视图中调用的定义  == <br /><br />    <field name="product_id"<br /> context="{'partner_id':parent.partner_id, 'quantity':product_uom_qty, 'pricelist':parent.pricelist_id, 'shop':parent.shop_id, 'uom':product_uom}"<br /> groups="base.group_user"<br /> on_change="product_id_change(parent.pricelist_id, product_id, product_uom_qty, product_uom, product_uos_qty, product_uos, name, <br /> <br /> parent.partner_id, False, True, parent.date_order, False, parent.fiscal_position, False, context)"/><br /><br />parent.partner_id<br />parent.date_order<br /><br />这种用法, 我估计是 取 得当前 的 one2many 字段所在 form的 其它字段 的值<br />    <br />= 以下为  py 中的对应函数  ===============================================================================================================<br /><br />    def product_id_change(self, cr, uid, ids, pricelist, product, qty=0,<br />            uom=False, qty_uos=0, uos=False, name='', partner_id=False,<br />            lang=False, update_tax=True, date_order=False, packaging=False, fiscal_position=False, flag=False, context=None):<br />        context = context or {}<br />        lang = lang or context.get('lang',False)<br />        <br /> # 判断, 选择产品前,必须先选择  客户<br /> if not  partner_id:<br />            raise osv.except_osv(_('No Customer Defined !'), _('Before choosing a product,\n select a customer in the sales form.'))<br /><br /> <br /> warning = {}<br />        product_uom_obj = self.pool.get('product.uom')<br />        partner_obj = self.pool.get('res.partner')<br />        product_obj = self.pool.get('product.product')<br /><br /><br /> # 准备好 context , 包括 语言 和 客户ID<br /> context = {'lang': lang, 'partner_id': partner_id}<br /> if partner_id:<br />            lang = partner_obj.browse(cr, uid, partner_id).lang<br /> # 准备第二个 context, 语言 改为 客户的 lang<br />        context_partner = {'lang': lang, 'partner_id': partner_id}<br /><br /><br /><br /> # 如果将 产品选中为 空(即 清空产品后), 重量 置0 , 产品销售单位数量 设为 qyt ,  产品单位, 产品小数单位 的 domain 清空, 返回<br />        if not product:<br />            return {'value': {'th_weight': 0,<br />                'product_uos_qty': qty}, 'domain': {'product_uom': [],<br />                  'product_uos': []}}<br /><br /> # 如果订单尚未指定 订单日期, 则 取得默认的 日期, 字串类型str<br />        if not date_order:<br />            date_order = time.strftime(DEFAULT_SERVER_DATE_FORMAT)<br /><br />        result = {}<br />        warning_msgs = {}<br /><br />        # 如果传入的 product(=product_id) 有值, 则打开该 ID 对应的对象<br /> product_obj = product_obj.browse(cr, uid, product, context=context_partner)<br /><br />        <br /> ######### 下面开始处理单位<br /> <br /> uom2 = False<br />        if uom:<br />     # 根据 uom 取得单位的 对象<br />            uom2 = product_uom_obj.browse(cr, uid, uom)<br /><br />     # 如果 产品默认的 计量单位的类别和 输入参数中单位的 类别不一致, <br />            if product_obj.uom_id.category_id.id != uom2.category_id.id:<br /> uom = False  # 将 传入的单位设置为 空<br /><br /><br /><br />        if uos:<br />            if product_obj.uos_id:<br />                uos2 = product_uom_obj.browse(cr, uid, uos)<br />                if product_obj.uos_id.category_id.id != uos2.category_id.id:<br />                    uos = False # 如果产品的销售单位 跟 输入参数的销售单位 类别不一致, , 也将 传入的 销售单位置空<br />            else:<br />                uos = False # 如果 产品的 销售单位 未指定, 此处的销售单位也必须为空<br /><br /><br /> # fiscal_position 财务替换规则<br /> # 根据 ID 取得 财务替换规格的 对象<br />        fpos = fiscal_position and self.pool.get('account.fiscal.position').browse(cr, uid, fiscal_position) or False<br /><br /> # 根据 财务替换规则 和 产品的 税务设定 进行 映射<br /> if update_tax: #The quantity only have changed<br />            result['tax_id'] = self.pool.get('account.fiscal.position').map_tax(cr, uid, fpos, product_obj.taxes_id)<br /><br /><br /><br /> # flag 是个标识 ,因为 本函数 是多个字段 定义为对应的 onchange 函数, 某些 字段的 onchange 会输入参数  flag = True<br />        if not flag:<br />            result['name'] = self.pool.get('product.product').name_get(cr, uid, [product_obj.id], context=context_partner)[0][1]    # 这里的  context_partner 已经包含了客户的语言 , 取得输入产品的 名称(根据客户的语言翻译好)<br />            if product_obj.description_sale:    # 如果产品里设置了 销售说明字段 , 则添加上 <br />                result['name'] += '\n'+product_obj.description_sale      #  等价于  result['name'] =  result['name'] + '\n'+product_obj.description_sale <br /><br />        domain = {}<br /><br />        <br /> <br /> #  根据前面的单位 计算  销售单位的数量  以及  单位字段的 domain<br /><br /><br /><br /> if (not uom) and (not uos): # 如果 计量单位和销售单位 都 无效 (可能是 没输入,也可能 是被前面 检查后置空了)<br />            result['product_uom'] = product_obj.uom_id.id<br /><br />     if product_obj.uos_id: # 产品中指定了销售单位<br />                result['product_uos'] = product_obj.uos_id.id # 从产品取 销售单位<br />                result['product_uos_qty'] = qty * product_obj.uos_coeff # 根据 转换系数 和 输入的 数量 计算 销售单位对应数量<br />                uos_category_id = product_obj.uos_id.category_id.id # 销售单位的类别 ID, 用于 后面的 对 销售单位设置 domain<br />            else:<br />                result['product_uos'] = False # 产品中没有 销售单位, 则销售单位置空<br />                result['product_uos_qty'] = qty # 销售单位数量 = 输入的数量(计量单位对应数量)<br />                uos_category_id = False # 销售单位的类别 ID, 用于 设置 domain, 设为 false 将导致 销售单位 无法选择<br /><br />            result['th_weight'] = qty * product_obj.weight # 计算本行产品的重量 =  数量 * 单个重量<br />            domain = {'product_uom':<br />                        [('category_id', '=', product_obj.uom_id.category_id.id)], # 修改 计量单位的 product_uom 的 domain , 仅允许同类单位可选<br />                        'product_uos':<br />                        [('category_id', '=', uos_category_id)]} # 同上<br /><br /><br /><br />        elif uos and not uom: # only happens if uom is False # 销售单位有效,  计量单位无效<br />            result['product_uom'] = product_obj.uom_id and product_obj.uom_id.id # 取得产品中设置的  计量单位<br />            result['product_uom_qty'] = qty_uos / product_obj.uos_coeff # 根据 销售单位数量 / 系数  , 倒算出 计量单位数量<br />            result['th_weight'] = result['product_uom_qty'] * product_obj.weight # 计算重量 计量单位数量 * 单个产品重量<br /><br /><br /><br />        elif uom: # whether uos is set or not # 计量单位有效 , 销售单位 不确定<br /><br />            default_uom = product_obj.uom_id and product_obj.uom_id.id # 默认计量单位 从 产品中取得<br />            q = product_uom_obj._compute_qty(cr, uid, uom, qty, default_uom) # 根据输入单位 , 输入的数量 以及 产品的默认计量单位 , 计算数量(根据单位的比例关系进行转换)<br />            result['product_uom'] = default_uom # 返回默认单位<br /><br />            if product_obj.uos_id:<br />                result['product_uos'] = product_obj.uos_id.id # 如果产品设置了  销售单位 , 则从产品 取得 销售单位<br />                result['product_uos_qty'] = qty * product_obj.uos_coeff # 根据输入数量和 转换系数计算出 产品的销售单位 数量<br />            else:<br />                result['product_uos'] = False # 产品 没有设置 销售单位<br />                result['product_uos_qty'] = qty # 销售单位数量 直接 设为 输入数量<br />            result['th_weight'] = q * product_obj.weight        # Round the quantity up # 重量 为 折算的单个产品数量 * 单个产品的重量  ( 产品设置的默认计量单位和 产品行的输入的计量单位不一致时, 前面已经折算)<br /><br />        if not uom2: # uom2 是前面 检查 uom 时 取得的 uom 对应的 对象, <br />            uom2 = product_obj.uom_id # 如果前面 uom 尚未取得值, 这里就直接取得 产品对象中 所属 的 uom 对象<br /><br /><br /><br />        # get unit price<br /> # 下面 开始 取得单价 <br /><br />        if not pricelist:  <br />            warn_msg = _('You have to select a pricelist or a customer in the sales form !\n' #  没有指定 价格表, 抛错<br />                    'Please set one before choosing a product.')<br />            warning_msgs += _("No Pricelist ! : ") + warn_msg +"\n\n"<br />        else:<br />            price = self.pool.get('product.pricelist').price_get(cr, uid, [pricelist], # 根据产品, 数量, 客户 , 计量单位, 订单日期 等信息 ( price_get 待 进一步 解读)<br />                    product, qty or 1.0, partner_id, {<br />                        'uom': uom or result.get('product_uom'),<br />                        'date': date_order,<br />                        })[pricelist] # price_get 返回一个以 pricelist 为 key 的 字典, 包含价格<br /><br />            if price is False:<br />                warn_msg = _("Cannot find a pricelist line matching this product and quantity.\n" # 如果 取得的 price 失败, 抛错<br />                        "You have to change either the product, the quantity or the pricelist.")<br /><br />                warning_msgs += _("No valid pricelist line found ! :") + warn_msg +"\n\n"<br />            else:<br />                result.update({'price_unit': price}) #  取得 单价<br /><br />        if warning_msgs: # 如果前面的 计算过程 包括 了警告信息,这 构造一个 字典予以返回<br />            warning = {<br />                      'title': _('Configuration Error!'),<br />                      'message' : warning_msgs<br />                    }<br />        return {'value': result, 'domain': domain, 'warning': warning} # onchang 函数 返回 三个字典: <br /> # 'value': result, 修改的字段值, 以字段名为 key<br /> # 'domain': domain, 也是以 字段名为key<br /> # 'warning': warning


  • 管理员

    兄弟干得漂亮,赞一个



  • 请教一个问题:<br />要实现图中所示的,如何实现:在改变产品ID后,显示产品在手库存数?是否修改product_id_change,如何改?请指教。<br />-------------<br />已在sale.order.line模块中添加了字段x_qty_available (标签Quantity On Hand)。



  • 楼上的需求需要写 python代码的



  • 能帮助写代码吗?



  • mark,学习一下



  • 学习!



  • 学习,很有帮助,谢谢


登录后回复
 

与 Odoo 中文社区 的连接断开,我们正在尝试重连,请耐心等待