stock.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. # -*- coding: utf-8 -*-
  2. # @authors: Alexander Ezquevo <alexander@acysos.com>
  3. # Copyright (C) 2015 Acysos S.L.
  4. # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
  5. from openerp import models, fields, api, _
  6. from openerp.exceptions import Warning
  7. ANIMAL_TYPE = [(None, 'No animal'), ('male', 'Male)'), ('female', 'Female'),
  8. ('individual', 'Individual'), ('group', 'Group'), ]
  9. class stock_move(models.Model):
  10. _inherit = 'stock.move'
  11. @api.model
  12. def _get_invoice_line_vals(self, move, inv_type, contetx=None):
  13. res = super(stock_move, self)._get_invoice_line_vals(move,
  14. inv_type, contetx)
  15. specie = self.env['farm.specie'].search([
  16. (True, '=', True)])[0]
  17. if len(specie.sale_product) != 0:
  18. alter_prod = specie.sale_product
  19. if res['product_id'] == specie.group_product.id or \
  20. res['product_id'] == specie.female_product.id or \
  21. res['product_id'] == specie.male_product.id:
  22. res['animal_qty'] = res['quantity']
  23. res['product_id'] = alter_prod.id
  24. res['uos_id'] = alter_prod.uos_id.id
  25. res['quantity'] = 1
  26. farm = move.location_id.get_farm_warehouse().id
  27. res['farm'] = farm
  28. return res
  29. @api.multi
  30. def action_done(self):
  31. super(stock_move, self).action_done()
  32. customer_location = self.env['stock.location'].search([
  33. ('usage', '=', 'customer')])
  34. for line in self:
  35. if customer_location.id == line.location_dest_id.id:
  36. lots = []
  37. for lot in line.quant_ids:
  38. lots.append(lot.lot_id.name)
  39. animals_obj = self.env['farm.animal.group']
  40. partys = animals_obj.search([
  41. ('state', '!=', 'sold'),
  42. ('location', 'child_of', line.location_id.id)])
  43. sale_animal = []
  44. for party in partys:
  45. for lot in lots:
  46. if party.number == lot and party not in sale_animal:
  47. sale_animal.append(party)
  48. if len(sale_animal) > 0:
  49. self.sale_group(sale_animal)
  50. else:
  51. species_obj = self.env['farm.specie'].search(
  52. [(True, '=', True)])
  53. for specie in species_obj:
  54. if line.product_id.id == specie.group_product.id:
  55. raise Warning(_('group sold not found'))
  56. @api.one
  57. def sale_group(self, groups):
  58. for group in groups:
  59. for lot in self.quant_ids:
  60. if lot.lot_id.name == group.number:
  61. if lot.qty == group.quantity:
  62. self.totalSale(group, lot.qty)
  63. elif lot.qty < group.quantity and group.state != 'sold':
  64. group.quantity = group.quantity - lot.qty
  65. farm_mov_obj = self.env['farm.move.event']
  66. farm_mov_obj.create({
  67. 'animal_type': 'group',
  68. 'specie': group.specie.id,
  69. 'farm': group.farm.id,
  70. 'animal_group': group.id,
  71. 'timestamp': self.picking_id.date,
  72. 'from_location': group.location.id,
  73. 'to_location': self.location_dest_id.id,
  74. 'quantity': lot.qty,
  75. 'unit_price': 1,
  76. 'move': self.id,
  77. })
  78. else:
  79. raise Warning(
  80. _('there are insufficient nº of animals'))
  81. @api.one
  82. def totalSale(self, group, qty):
  83. group.state = 'sold'
  84. group.removal_date = self.date
  85. farm_mov_obj = self.env['farm.move.event']
  86. group.quantity = 0
  87. farm_mov_obj.create({
  88. 'animal_type': 'group',
  89. 'specie': group.specie.id,
  90. 'farm': group.farm.id,
  91. 'animal_group': group.id,
  92. 'timestamp': self.picking_id.date,
  93. 'from_location': group.location.id,
  94. 'to_location': self.location_dest_id.id,
  95. 'quantity': qty,
  96. 'unit_price': 1,
  97. 'move': self.id,
  98. })
  99. tags_obj = self.env['farm.tags']
  100. new_tag = tags_obj.search([
  101. ('name', '=', group.farm.name + '-Sold')])
  102. if len(new_tag) == 0:
  103. new_tag = tags_obj.create(
  104. {'name': group.farm.name + '-Sold', })
  105. group.tags = [(6, 0, [new_tag.id, ])]
  106. class Lot(models.Model):
  107. _inherit = 'stock.production.lot'
  108. animal_type = fields.Selection(selection=ANIMAL_TYPE)
  109. animal_group = fields.One2many(comodel_name='stock.lot_farm.animal.group',
  110. inverse_name='animal_group', string='Group')
  111. semen_breed = fields.Many2one(comodel_name='farm.specie.breed',
  112. string='Raza')
  113. class LotAnimal(models.Model):
  114. _name = 'stock.lot_farm.animal'
  115. _rec_name = 'lot'
  116. lot = fields.Many2one(comodel_name='stock.production.lot',
  117. string='Lot')
  118. animal = fields.Many2one(comodel_name='farm.animal', string='Animal',
  119. ondelete='RESTRICT', select=True)
  120. class LotAnimalGroup(models.Model):
  121. _name = 'stock.lot_farm.animal.group'
  122. _rec_name = 'lot'
  123. lot = fields.Many2one(comodel_name='stock.production.lot',
  124. string='Lot', required=True,
  125. ondelete='RESTRICT', select=True)
  126. animal_group = fields.Many2one(
  127. comodel_name='farm.animal.group',
  128. string='Animal Group', required=True,
  129. ondelete='RESTRICT', select=True)
  130. class Warehouse(models.Model):
  131. _inherit = 'stock.warehouse'
  132. external = fields.Boolean(String='External Farm')
  133. holding_number = fields.Char(string='holding number')
  134. radius = fields.Float(string='Radius', help='is used for calculating '
  135. 'transport costs, you can use absolute or relative'
  136. ' values', default=1)
  137. animal_max = fields.Integer(string='Max num of animals')
  138. class Location(models.Model):
  139. _inherit = 'stock.location'
  140. silo = fields.Boolean(string='Silo', select=True, default=False,
  141. help='Indicates that the location is a silo.')
  142. factory = fields.Boolean(string='Factory', default=False)
  143. transport = fields.Boolean(string='Transport', default=False)
  144. farm_yard = fields.Boolean(string='Farm Yard', select=True, default=False)
  145. locations_to_fed = fields.One2many(
  146. comodel_name='stock.location.silo_stock.location',
  147. inverse_name='silo', string='Location to fed',
  148. help='Indicates the locations the silo feeds. Note that this will '
  149. 'only be a default value.')
  150. animal_max = fields.Integer(string='Max num of animals')
  151. @api.multi
  152. def get_farm_warehouse(self):
  153. for res in self:
  154. view_loc = res
  155. while view_loc.usage != 'view':
  156. view_loc = view_loc.location_id
  157. warehouse = self.env['stock.warehouse'].search([
  158. ('view_location_id', '=', view_loc.id)])
  159. return warehouse
  160. class LocationSiloLocation(models.Model):
  161. _name = 'stock.location.silo_stock.location'
  162. silo = fields.Many2one(comodel_name='stock.location', string='silo',
  163. ondelete='CASCADE', required=True, select=True)
  164. location = fields.Many2one(comodel_name='stock.location',
  165. string='Location',
  166. ondelete='CASCADE', required=True, select=True)
  167. class Foster_location_stock(models.Model):
  168. _name = 'farm.foster.locations'
  169. _rec_name = 'location'
  170. specie = fields.Many2one(comodel_name='farm.specie', string='specie')
  171. location = fields.Many2one(comodel_name='stock.location',
  172. string='Location',
  173. domain=[('usage', '=', 'transit')])
  174. class Transit_location_stock(models.Model):
  175. _name = 'farm.transit.locations'
  176. _rec_name = 'location'
  177. specie = fields.Many2one(comodel_name='farm.specie', string='specie')
  178. location = fields.Many2one(comodel_name='stock.location',
  179. string='Location',
  180. domain=[('usage', '=', 'transit')])
  181. class Future_maders_location_stock(models.Model):
  182. _name = 'farm.future_maders.locations'
  183. _rec_name = 'location'
  184. specie = fields.Many2one(comodel_name='farm.specie', string='specie')
  185. location = fields.Many2one(comodel_name='stock.location',
  186. string='Location',
  187. domain=[('usage', '=', 'transit')])
  188. class StockInventory(models.Model):
  189. _inherit = 'stock.inventory'
  190. feed_analitic = fields.Boolean('Set Feed Analitic', default=False)
  191. class StockInventoryLine(models.Model):
  192. _inherit = 'stock.inventory.line'
  193. @api.model
  194. def _resolve_inventory_line(self, inventory_line):
  195. res = super(
  196. StockInventoryLine, self)._resolve_inventory_line(
  197. inventory_line)
  198. if res:
  199. move = self.env['stock.move'].search([('id', '=', res)])
  200. diff = inventory_line.theoretical_qty - inventory_line.product_qty
  201. if inventory_line.inventory_id.feed_analitic:
  202. if diff < 0:
  203. self.set_analitics(move, False)
  204. else:
  205. self.set_analitics(move, True)
  206. return res
  207. @api.multi
  208. def set_analitics(self, move, lost):
  209. analitic_remain_ob = self.env['purchase.analitic.remain']
  210. if lost:
  211. location = move.location_id
  212. else:
  213. location = move.location_dest_id
  214. factory = location
  215. while(factory.location_id.id != 1):
  216. factory = factory.location_id
  217. analitic_remain = analitic_remain_ob.search([
  218. ('farm', '=', factory.id)])
  219. lot_cost = move.restrict_lot_id.unit_cost
  220. qty = move.product_uom_qty
  221. cost = 0
  222. if lot_cost and lot_cost > 0:
  223. cost = lot_cost * qty
  224. else:
  225. quants_obj = self.env['stock.quant']
  226. quants = quants_obj.search([
  227. ('lot_id', '=', move.restrict_lot_id.id)])
  228. ids = []
  229. for q in quants:
  230. ids.append(q.id)
  231. moves = self.env['stock.move'].with_context({}).search([
  232. ('quant_ids', 'in', ids),
  233. ('picking_id', '!=', False)])
  234. amount = 0.0
  235. raw_qty = 0
  236. for mov in moves:
  237. if mov.price_unit > 0:
  238. amount += mov.price_unit * mov.product_qty
  239. raw_qty = raw_qty + mov.product_qty
  240. if raw_qty > 0:
  241. unit_price = amount/raw_qty
  242. cost += qty * unit_price
  243. if cost == 0:
  244. prod_tmpl = move.product_id.product_tmpl_id
  245. cost = prod_tmpl.standard_price * qty
  246. if not lost:
  247. cost = cost * -1
  248. if len(analitic_remain) == 0:
  249. analitic_remain_ob.create({
  250. 'farm': factory.id,
  251. 'quantity': cost})
  252. else:
  253. analitic_remain.quantity = \
  254. analitic_remain.quantity + cost