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