GoodERP
Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.

227 lines
8.1KB

  1. # -*- coding: utf-8 -*-
  2. # Copyright 2016 上海开阖软件有限公司 (http://www.osbzr.com)
  3. # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
  4. from odoo import _
  5. from odoo import models, fields, api
  6. from odoo.exceptions import UserError
  7. class Goods(models.Model):
  8. """
  9. 继承了core里面定义的goods 模块,并定义了视图和添加字段。
  10. """
  11. _inherit = 'goods'
  12. def get_parent_tax_rate(self, parent_id):
  13. # 逐级取商品分类上的税率
  14. tax_rate = parent_id.tax_rate
  15. if not tax_rate and parent_id.parent_id:
  16. tax_rate = self.get_parent_tax_rate(parent_id.parent_id)
  17. return tax_rate
  18. def get_tax_rate(self, goods, partner, type):
  19. """
  20. 获得税率
  21. 如果商品上没有税率,则逐级取商品分类上的税率;
  22. 商品税率和业务伙伴税率做比较:如果都存在,取小的;其中一个存在取该值;都不存在取公司上的进/销项税
  23. """
  24. if not goods:
  25. return
  26. goods_tax_rate, partner_tax_rate = False, False
  27. # 如果商品上没有税率,则取商品分类上的税率
  28. if goods.tax_rate:
  29. goods_tax_rate = goods.tax_rate
  30. elif goods.goods_class_id.tax_rate:
  31. goods_tax_rate = goods.goods_class_id.tax_rate
  32. elif goods.goods_class_id.parent_id: # 逐级取商品分类上的税率
  33. goods_tax_rate = self.get_parent_tax_rate(
  34. goods.goods_class_id.parent_id)
  35. # 取业务伙伴税率
  36. if partner:
  37. partner_tax_rate = partner.tax_rate
  38. # 商品税率和业务伙伴税率做比较,并根据情况返回
  39. if goods_tax_rate and partner_tax_rate:
  40. if goods_tax_rate >= partner_tax_rate:
  41. return partner_tax_rate
  42. else:
  43. return goods_tax_rate
  44. elif goods_tax_rate and not partner_tax_rate:
  45. return goods_tax_rate
  46. elif not goods_tax_rate and partner_tax_rate:
  47. return partner_tax_rate
  48. else:
  49. if type == 'buy':
  50. return self.env.user.company_id.import_tax_rate
  51. elif type == 'sell':
  52. return self.env.user.company_id.output_tax_rate
  53. no_stock = fields.Boolean('虚拟商品')
  54. using_batch = fields.Boolean('管理批号')
  55. force_batch_one = fields.Boolean('管理序列号')
  56. attribute_ids = fields.One2many('attribute', 'goods_id', string='属性')
  57. image = fields.Binary('图片', attachment=True)
  58. supplier_id = fields.Many2one('partner',
  59. '默认供应商',
  60. ondelete='restrict',
  61. domain=[('s_category_id', '!=', False)])
  62. get_way = fields.Selection([
  63. ('self', '自制'),
  64. ('ous', '委外'),
  65. ('po', '采购'),
  66. ], default='po', string='获取方式')
  67. price = fields.Float('售价(不含税)')
  68. gpm = fields.Float('毛利率')
  69. barcode = fields.Char('条形码')
  70. note = fields.Text('备注')
  71. goods_class_id = fields.Many2one(
  72. 'goods.class', string='商品分类',
  73. domain=[('type', '=', 'normal')])
  74. _sql_constraints = [
  75. ('barcode_uniq', 'unique(barcode)', '条形码不能重复'),
  76. ]
  77. @api.onchange('uom_id')
  78. def onchange_uom(self):
  79. """
  80. :return: 当选取单位时辅助单位默认和 单位相等。
  81. """
  82. self.uos_id = self.uom_id
  83. @api.onchange('gpm', 'cost')
  84. def onchange_gpm(self):
  85. """
  86. 根据毛利率计算零售价
  87. """
  88. if self.gpm >= 1 or self.gpm < 0:
  89. raise UserError(_('毛利率请输入0%-100%之间的数值.'))
  90. self.price = self.cost / (1 - self.gpm)
  91. @api.onchange('price', 'cost')
  92. def onchange_price(self):
  93. """
  94. 根据零售价计算毛利率
  95. """
  96. if self.price > 0 and self.cost > 0:
  97. self.gpm = 1 - self.cost / self.price
  98. @api.onchange('using_batch')
  99. def onchange_using_batch(self):
  100. """
  101. :return: 当将管理批号的勾去掉后,自动将管理序列号的勾去掉
  102. """
  103. if not self.using_batch:
  104. self.force_batch_one = False
  105. def conversion_unit(self, qty):
  106. """ 数量 × 转化率 = 辅助数量
  107. :param qty: 传进来数量计算出辅助数量
  108. :return: 返回辅助数量
  109. """
  110. self.ensure_one()
  111. return self.conversion * qty
  112. def anti_conversion_unit(self, qty):
  113. """ 数量 = 辅助数量 / 转化率
  114. :param qty: 传入值为辅助数量
  115. :return: 数量
  116. """
  117. self.ensure_one()
  118. return self.conversion and qty / self.conversion or 0
  119. class Attribute(models.Model):
  120. _name = 'attribute'
  121. _description = '属性'
  122. @api.depends('value_ids')
  123. def _compute_name(self):
  124. for a in self:
  125. a.name = ' '.join(
  126. [value.category_id.name + ':' + value.value_id.name for value in a.value_ids])
  127. @api.model
  128. def name_search(self, name='', args=None, operator='ilike', limit=100):
  129. '''在many2one字段中支持按条形码搜索'''
  130. args = args or []
  131. if name:
  132. attribute_ids = self.search([('ean', '=', name)])
  133. if attribute_ids:
  134. return [(attribute.id, attribute.display_name) for attribute in attribute_ids]
  135. return super(Attribute, self).name_search(
  136. name=name, args=args, operator=operator, limit=limit)
  137. ean = fields.Char('条码')
  138. name = fields.Char('属性', compute='_compute_name',
  139. store=True, readonly=True)
  140. goods_id = fields.Many2one('goods', '商品', ondelete='cascade')
  141. value_ids = fields.One2many(
  142. 'attribute.value', 'attribute_id', string='属性值')
  143. company_id = fields.Many2one(
  144. 'res.company',
  145. string='公司',
  146. change_default=True,
  147. default=lambda self: self.env.company)
  148. _sql_constraints = [
  149. ('ean_uniq', 'unique (ean)', '该条码已存在'),
  150. ('goods_attribute_uniq', 'unique (goods_id, name)', '该SKU已存在'),
  151. ]
  152. @api.constrains('value_ids')
  153. def check_value_ids(self):
  154. for a in self:
  155. att_dict = {}
  156. for line in a.value_ids:
  157. if line.category_id not in att_dict:
  158. att_dict[line.category_id] = line.category_id
  159. else:
  160. raise UserError(_('属性值的类别不能相同'))
  161. class AttributeValue(models.Model):
  162. _name = 'attribute.value'
  163. _rec_name = 'value_id'
  164. _description = '属性明细'
  165. attribute_id = fields.Many2one('attribute', '商品属性', ondelete='cascade')
  166. category_id = fields.Many2one('core.category', '属性',
  167. ondelete='cascade',
  168. domain=[('type', '=', 'attribute')],
  169. required=True)
  170. value_id = fields.Many2one('attribute.value.value', '值',
  171. ondelete='restrict',
  172. domain="[('category_id','=',category_id)]",
  173. default=lambda self: self.env.context.get(
  174. 'default_category_id'),
  175. required=True)
  176. company_id = fields.Many2one(
  177. 'res.company',
  178. string='公司',
  179. change_default=True,
  180. default=lambda self: self.env.company)
  181. class AttributeValueValue(models.Model):
  182. _name = 'attribute.value.value'
  183. _description = '属性值'
  184. category_id = fields.Many2one('core.category', '属性',
  185. ondelete='cascade',
  186. domain=[('type', '=', 'attribute')],
  187. required=True)
  188. name = fields.Char('值', required=True)
  189. company_id = fields.Many2one(
  190. 'res.company',
  191. string='公司',
  192. change_default=True,
  193. default=lambda self: self.env.company)
  194. _sql_constraints = [
  195. ('name_category_uniq', 'unique(category_id,name)', '同一属性的值不能重复')
  196. ]
上海开阖软件有限公司 沪ICP备12045867号-1