product.py 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. # -*- encoding: utf-8 -*-
  2. ##############################################################################
  3. # For copyright and license notices, see __openerp__.py file in root directory
  4. ##############################################################################
  5. from openerp import fields, models, api, _
  6. from openerp.osv import fields as old_fields
  7. from openerp.exceptions import Warning
  8. import math
  9. class product_product(models.Model):
  10. _inherit = 'product.product'
  11. pack_line_ids = fields.One2many(
  12. 'product.pack.line',
  13. 'parent_product_id',
  14. 'Pack Products',
  15. help='List of products that are part of this pack.'
  16. )
  17. used_pack_line_ids = fields.One2many(
  18. 'product.pack.line',
  19. 'product_id',
  20. 'On Packs',
  21. help='List of packs where product is used.'
  22. )
  23. def _product_available(
  24. self, cr, uid, ids, field_names=None, arg=False, context=None):
  25. """
  26. For product packs we get availability in a different way
  27. """
  28. pack_product_ids = self.search(cr, uid, [
  29. ('pack', '=', True),
  30. ('id', 'in', ids),
  31. ])
  32. res = super(product_product, self)._product_available(
  33. cr, uid, list(set(ids) - set(pack_product_ids)),
  34. field_names, arg, context)
  35. for product in self.browse(cr, uid, pack_product_ids, context=context):
  36. pack_qty_available = []
  37. pack_virtual_available = []
  38. for subproduct in product.pack_line_ids:
  39. subproduct_stock = self._product_available(
  40. cr, uid, [subproduct.product_id.id], field_names, arg,
  41. context)[subproduct.product_id.id]
  42. sub_qty = subproduct.quantity
  43. if sub_qty:
  44. pack_qty_available.append(math.floor(
  45. subproduct_stock['qty_available'] / sub_qty))
  46. pack_virtual_available.append(math.floor(
  47. subproduct_stock['virtual_available'] / sub_qty))
  48. # TODO calcular correctamente pack virtual available para negativos
  49. res[product.id] = {
  50. 'qty_available': (
  51. pack_qty_available and min(pack_qty_available) or False),
  52. 'incoming_qty': 0,
  53. 'outgoing_qty': 0,
  54. 'virtual_available': (
  55. pack_virtual_available and
  56. max(min(pack_virtual_available), 0) or False),
  57. }
  58. return res
  59. def _search_product_quantity(self, cr, uid, obj, name, domain, context):
  60. """
  61. We use original search function
  62. """
  63. return super(product_product, self)._search_product_quantity(
  64. cr, uid, obj, name, domain, context)
  65. # overwrite ot this fields so that we can modify _product_available
  66. # function to support packs
  67. _columns = {
  68. 'qty_available': old_fields.function(
  69. _product_available, multi='qty_available',
  70. fnct_search=_search_product_quantity),
  71. 'virtual_available': old_fields.function(
  72. _product_available, multi='qty_available',
  73. fnct_search=_search_product_quantity),
  74. 'incoming_qty': old_fields.function(
  75. _product_available, multi='qty_available',
  76. fnct_search=_search_product_quantity),
  77. 'outgoing_qty': old_fields.function(
  78. _product_available, multi='qty_available',
  79. fnct_search=_search_product_quantity),
  80. }
  81. @api.one
  82. @api.constrains('pack_line_ids')
  83. def check_recursion(self):
  84. """
  85. Check recursion on packs
  86. """
  87. pack_lines = self.pack_line_ids
  88. while pack_lines:
  89. if self in pack_lines.mapped('product_id'):
  90. raise Warning(_(
  91. 'Error! You cannot create recursive packs.\n'
  92. 'Product id: %s') % self.id)
  93. pack_lines = pack_lines.mapped('product_id.pack_line_ids')
  94. class product_template(models.Model):
  95. _inherit = 'product.template'
  96. # TODO rename a pack_type
  97. pack_price_type = fields.Selection([
  98. ('components_price', 'Detailed - Components Prices'),
  99. ('totalice_price', 'Detailed - Totaliced Price'),
  100. ('fixed_price', 'Detailed - Fixed Price'),
  101. ('none_detailed_assited_price', 'None Detailed - Assisted Price'),
  102. ('none_detailed_totaliced_price', 'None Detailed - Totaliced Price'),
  103. ],
  104. 'Pack Type',
  105. help="* Detailed - Components Prices: Detail lines with prices on "
  106. "sales order.\n"
  107. "* Detailed - Totaliced Price: Detail lines on sales order totalicing "
  108. "lines prices on pack (don't show component prices).\n"
  109. "* Detailed - Fixed Price: Detail lines on sales order and use product"
  110. " pack price (ignore line prices).\n"
  111. "* None Detailed - Assisted Price: Do not detail lines on sales "
  112. "order. Assist to get pack price using pack lines."
  113. )
  114. pack = fields.Boolean(
  115. 'Pack?',
  116. help='Is a Product Pack?',
  117. )
  118. pack_line_ids = fields.One2many(
  119. related='product_variant_ids.pack_line_ids'
  120. )
  121. used_pack_line_ids = fields.One2many(
  122. related='product_variant_ids.used_pack_line_ids'
  123. )
  124. @api.constrains(
  125. 'product_variant_ids', 'pack_price_type')
  126. def check_relations(self):
  127. """
  128. Check assited packs dont have packs a childs
  129. """
  130. # check assited price has no packs child of them
  131. if self.pack_price_type == 'none_detailed_assited_price':
  132. child_packs = self.mapped(
  133. 'pack_line_ids.product_id').filtered('pack')
  134. if child_packs:
  135. raise Warning(_(
  136. 'A "None Detailed - Assisted Price Pack" can not have a '
  137. 'pack as a child!'))
  138. # TODO we also should check this
  139. # check if we are configuring a pack for a product that is partof a
  140. # assited pack
  141. # if self.pack:
  142. # for product in self.product_variant_ids
  143. # parent_assited_packs = self.env['product.pack.line'].search([
  144. # ('product_id', '=', self.id),
  145. # ('parent_product_id.pack_price_type', '=',
  146. # 'none_detailed_assited_price'),
  147. # ])
  148. # print 'parent_assited_packs', parent_assited_packs
  149. # if parent_assited_packs:
  150. # raise Warning(_(
  151. # 'You can not set this product as pack because it is part'
  152. # ' of a "None Detailed - Assisted Price Pack"'))
  153. @api.one
  154. @api.constrains('company_id', 'product_variant_ids', 'used_pack_line_ids')
  155. def check_pack_line_company(self):
  156. """
  157. Check packs are related to packs of same company
  158. """
  159. for line in self.pack_line_ids:
  160. if line.product_id.company_id != self.company_id:
  161. raise Warning(_(
  162. 'Pack lines products company must be the same as the\
  163. parent product company'))
  164. for line in self.used_pack_line_ids:
  165. if line.parent_product_id.company_id != self.company_id:
  166. raise Warning(_(
  167. 'Pack lines products company must be the same as the\
  168. parent product company'))
  169. @api.multi
  170. def write(self, vals):
  171. """
  172. We remove from prod.prod to avoid error
  173. """
  174. if vals.get('pack_line_ids', False):
  175. self.product_variant_ids.write(
  176. {'pack_line_ids': vals.pop('pack_line_ids')})
  177. return super(product_template, self).write(vals)
  178. @api.model
  179. def _price_get(self, products, ptype='list_price'):
  180. res = super(product_template, self)._price_get(
  181. products, ptype=ptype)
  182. for product in products:
  183. if (
  184. product.pack and
  185. product.pack_price_type in [
  186. 'totalice_price',
  187. 'none_detailed_assited_price',
  188. 'none_detailed_totaliced_price']):
  189. pack_price = 0.0
  190. for pack_line in product.pack_line_ids:
  191. product_line_price = pack_line.product_id.price_get()[
  192. pack_line.product_id.id] * (
  193. 1 - (pack_line.discount or 0.0) / 100.0)
  194. product_line_price
  195. pack_price += (product_line_price * pack_line.quantity)
  196. res[product.id] = pack_price
  197. return res