animal_group.py 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  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. from datetime import datetime
  8. DFORMAT = "%Y-%m-%d %H:%M:%S"
  9. DFORMAT2 = "%Y-%m-%d"
  10. class AnimalGroup(models.Model):
  11. _name = 'farm.animal.group'
  12. _order = 'arrival_date desc'
  13. mother = fields.Char(string='Mother', compute='get_mother')
  14. specie = fields.Many2one(comodel_name='farm.specie', string='Specie',
  15. required=True)
  16. breed = fields.Many2one(comodel_name='farm.specie.breed', string='Breed')
  17. lot = fields.One2many(comodel_name='stock.lot_farm.animal.group',
  18. inverse_name='animal_group', column1='lot',
  19. string='Lot')
  20. number = fields.Char(string='Number', compute='get_number', store=True)
  21. location = fields.Many2one(comodel_name='stock.location',
  22. string='Current location',
  23. domain=[('usage', '!=', 'view'), ])
  24. farm = fields.Many2one(comodel_name='stock.location',
  25. string='Current Farm',
  26. domain=[('usage', '=', 'view')])
  27. quantity = fields.Integer(string='Quantity')
  28. origin = fields.Selection([('purchased', 'Purchased'),
  29. ('raised', 'Raised'), ], string='Origin',
  30. required=True,
  31. default='purchased',
  32. help='Raised means that this group was born in'
  33. 'the farm. Otherwise, it was purchased.')
  34. arrival_date = fields.Date(string='Arrival Date',
  35. default=fields.Date.today(),
  36. help="The date this group arrived (if it was"
  37. "purchased) or when it was born.")
  38. """
  39. purchase_shipment = fields.Many2one(comodel_name='stock.shipment.in',
  40. string='Purchase Shipment',
  41. readonly=True)
  42. """
  43. initial_location = fields.Many2one(comodel_name='stock.location',
  44. string='Initial location',
  45. required=True,
  46. domain=[('usage', '=', 'internal'),
  47. ('silo', '=', False), ],
  48. help="The Location where the group was"
  49. "reached or where it was allocated when"
  50. "it was purchased.\nIt is used as"
  51. "historical information and to get"
  52. "Serial Number.")
  53. initial_quantity = fields.Integer(string='Initial quantity', required=True,
  54. help="The number of animals in group"
  55. "when it was reached or purchased.\nIt"
  56. "is used as historical information and"
  57. "to create the initial move.")
  58. removal_date = fields.Date(string='Removal date', readonly=True)
  59. weights = fields.One2many(comodel_name='farm.animal.group.weight',
  60. inverse_name='party', column1='tag',
  61. string='Weights')
  62. current_weight = fields.Many2one(comodel_name='farm.animal.group.weight',
  63. string='Current weight',
  64. compute='on_change_with_current_weight')
  65. tags = fields.Many2many(comodel_name='farm.tags',
  66. inverse_name='animal_group', string='Tag')
  67. notes = fields.Text(string='Notes')
  68. active = fields.Boolean(string='Active', default=True)
  69. feed_quantity = fields.Float(string='cumulative consumed feed')
  70. consumed_feed = fields.Float(string='Consumed Feed per Animal (kg)',
  71. compute='get_consumed_feed')
  72. state = fields.Selection(selection=[
  73. ('lactating', 'Lactating'), ('transition', 'Transition'),
  74. ('fatten', 'Faten up'), ('sold', 'Sold')],
  75. readonly=True, default='fatten')
  76. transition_days = fields.Integer(string='Days in Transition',
  77. compute='get_transit_days')
  78. fattening_days = fields.Integer(string='Days in fatening',
  79. compute='get_fattenig_days')
  80. account = fields.Many2one(comodel_name='account.analytic.account',
  81. string='Analytic Account')
  82. fatten_date = fields.Date(string='fatten day', compute='_get_fatten_day',
  83. store=True)
  84. weaning_day = fields.Datetime(string='weaning_day', compute='get_weaning_day')
  85. @api.multi
  86. def get_transformations(self):
  87. tranform_obj = self.env['farm.trasformation.event']
  88. for res in self:
  89. for lot in res.lot:
  90. transforms = tranform_obj.search([
  91. '|', ('animal_group', '=', res.id),
  92. ('to_animal_group', '=', )])
  93. @api.multi
  94. def show_feed_event_from_group(self):
  95. feed_ev_obj = self.env['farm.feed.event']
  96. ids = []
  97. for res in self:
  98. for lot in res.lot:
  99. print res.lot
  100. feed_evts = feed_ev_obj.search([
  101. ('lot', '=', lot.lot.id)])
  102. for event in feed_evts:
  103. ids.append(event.id)
  104. res = {'view_mode': 'tree,form',
  105. 'res_model': 'farm.feed.event',
  106. 'view_id': False,
  107. 'type': 'ir.actions.act_window',
  108. 'view_type': 'form',
  109. 'domain': [('id', 'in', ids)]}
  110. return res
  111. @api.multi
  112. def get_mother(self):
  113. farrow = self.env['farm.farrowing.event_group']
  114. for res in self:
  115. group_farrow = farrow.search([
  116. ('animal_group', '=', res.id)])
  117. if len(group_farrow)!= 0:
  118. res.mother = group_farrow.event.animal.number
  119. else:
  120. res.mother = '*'
  121. @api.one
  122. def get_weaning_day(self):
  123. if self.state != 'lactating':
  124. weaning_obj = self.env['farm.weaning.event']
  125. wean = weaning_obj.search([
  126. ('farrowing_group', '=', self.id)])
  127. if len(wean) != 0:
  128. self.weaning_day = datetime.strptime(wean.timestamp, DFORMAT)
  129. @api.multi
  130. @api.depends('location', 'state')
  131. def _get_fatten_day(self):
  132. for res in self:
  133. if res.state not in ('lactating', 'transition'):
  134. transformation_obj = self.env['farm.transformation.event']
  135. transition_location = []
  136. for loc in res.specie.lost_found_location:
  137. transition_location.append(loc.location.id)
  138. transition = transformation_obj.search([
  139. ('animal_group', '=', res.id),
  140. ('from_location.id', 'in', transition_location),
  141. ('to_location.id', 'not in', transition_location)])
  142. if transition:
  143. res.fatten_date = transition[-1].timestamp
  144. else:
  145. res.fatten_date = res.arrival_date
  146. @api.one
  147. def get_transit_days(self):
  148. if self.state == 'lactating':
  149. self.transition_days = 0
  150. elif self.state == 'transition':
  151. weaning_obj = self.env['farm.weaning.event']
  152. wean = weaning_obj.search([
  153. ('farrowing_group', '=', self.id)])
  154. if wean:
  155. wean_day = datetime.strptime(wean.timestamp, DFORMAT)
  156. self.transition_days = (datetime.today() - wean_day).days
  157. else:
  158. ref_day = datetime.strptime(self.arrival_date, DFORMAT2)
  159. self.transition_days = (datetime.today() - ref_day).days
  160. else:
  161. weaning_obj = self.env['farm.weaning.event']
  162. transformation_obj = self.env['farm.transformation.event']
  163. wean = weaning_obj.search([
  164. ('farrowing_group', '=', self.id)])
  165. if len(wean) != 0:
  166. wean_day = datetime.strptime(wean.timestamp, DFORMAT)
  167. else:
  168. wean_day = datetime.strptime(self.arrival_date, DFORMAT2)
  169. transition_location = []
  170. for loc in self.specie.lost_found_location:
  171. transition_location.append(loc.location.id)
  172. transition = transformation_obj.search([
  173. ('animal_group', '=', self.id),
  174. ('from_location.id', 'in', transition_location),
  175. ('to_location.id', 'not in', transition_location)])
  176. if transition:
  177. transition_finish = datetime.strptime(
  178. transition[-1].timestamp, DFORMAT)
  179. self.transition_days = (transition_finish - wean_day).days
  180. else:
  181. self.transition_days = 0
  182. @api.one
  183. def get_fattenig_days(self):
  184. if self.state == 'lactating' or self.state == 'transition':
  185. self.fattening_days = 0
  186. else:
  187. transformation_obj = self.env['farm.transformation.event']
  188. transition_location = []
  189. for loc in self.specie.lost_found_location:
  190. transition_location.append(loc.location.id)
  191. transition = transformation_obj.search([
  192. ('animal_group', '=', self.id),
  193. ('from_location.id', 'in', transition_location),
  194. ('to_location.id', 'not in', transition_location)])
  195. if len(transition) == 0:
  196. transition_finish = datetime.strptime(
  197. self.arrival_date, '%Y-%m-%d')
  198. else:
  199. transition_finish = datetime.strptime(
  200. transition[-1].timestamp, DFORMAT)
  201. if self.state == 'fatten':
  202. self.fattening_days = (
  203. datetime.today() - transition_finish).days
  204. else:
  205. moves_obj = self.env['farm.move.event']
  206. sale_move = moves_obj.search([
  207. ('animal_group', '=', self.id)])
  208. sale_day = datetime.strptime(
  209. sale_move[-1].timestamp, DFORMAT)
  210. self.fattening_days = (sale_day - transition_finish).days
  211. @api.multi
  212. def create_first_move(self, res):
  213. moves_obj = self.env['stock.move']
  214. quant_obj = self.env['stock.quant']
  215. for record in res:
  216. if not record.lot:
  217. production_lot_obj = self.env['stock.production.lot']
  218. animal_group_lot_obj = \
  219. self.env['stock.lot_farm.animal.group']
  220. new_lot = production_lot_obj.create({
  221. 'product_id': res.specie.group_product.id,
  222. 'animal_type': 'group',
  223. })
  224. animal_group_lot_obj.create({
  225. 'lot': new_lot.id,
  226. 'animal_group': res.id})
  227. quant = quant_obj.search([
  228. ('lot_id', '=', record.lot[0].lot.id),
  229. ('location_id', '=', record.initial_location.id)
  230. ])
  231. record.location = record.initial_location
  232. if len(record.lot) > 1:
  233. raise Warning(
  234. _('lots can not be mixed in an initial group, create a'
  235. ' group for each lot and then group them into the'
  236. ' desired group'))
  237. elif record.origin == 'raised':
  238. if not quant:
  239. raise_location = self.env['stock.location'].search(
  240. [('usage', '=', 'production')])
  241. uom = record.lot.lot.product_id.product_tmpl_id.uom_id.id
  242. new_move = moves_obj.create({
  243. 'name': 'raise-' + record.lot[0].lot.name,
  244. 'create_date': fields.Date.today(),
  245. 'date': record.arrival_date,
  246. 'product_id': record.lot[0].lot.product_id.id,
  247. 'product_uom_qty': record.initial_quantity,
  248. 'product_uom': uom,
  249. 'location_id': raise_location.id,
  250. 'location_dest_id': record.initial_location.id,
  251. 'company_id': record.initial_location.company_id.id,
  252. })
  253. new_move.action_done()
  254. new_move.quant_ids.lot_id = record.lot[0].lot.id
  255. else:
  256. raise Warning(
  257. _('this lot iis in use, please create new lot'))
  258. else:
  259. if not quant:
  260. raise Warning(
  261. _('no product in farms for this lot'))
  262. target_quant = False
  263. for q in quant:
  264. if q.location_id == record.initial_location:
  265. if q.qty >= record.initial_quantity:
  266. target_quant = q
  267. if not target_quant:
  268. raise Warning(
  269. _('group intial quantity and product quantity '
  270. 'are diferent'))
  271. an_group = self.env['farm.animal.group'].search([
  272. ('lot.lot.id', '=', record.lot.lot.id),
  273. ('id', '!=', record.id)])
  274. if len(an_group) > 0:
  275. raise Warning(
  276. _('this lot is in use from oder group'))
  277. @api.model
  278. @api.returns('self', lambda value: value.id)
  279. def create(self, vals):
  280. res = super(AnimalGroup, self).create(vals)
  281. self.create_first_move(res)
  282. res.quantity = res.initial_quantity
  283. analy_ac_obj = self.env['account.analytic.account']
  284. top_account = analy_ac_obj.search([
  285. ('name', '=', res.farm.name)])
  286. if not top_account:
  287. gen_account = analy_ac_obj.search([
  288. ('name', '=', 'General Account')])
  289. if not gen_account:
  290. gen_account = analy_ac_obj.create({'name': 'General Account'})
  291. top_account = analy_ac_obj.create({'name': res.farm.name,
  292. 'parent_id': gen_account.id})
  293. new_account = analy_ac_obj.create({
  294. 'name': 'AA-group-'+res.number,
  295. 'parent_id': top_account.id})
  296. res.account = new_account
  297. return res
  298. @api.multi
  299. def name_get(self):
  300. result = ''
  301. displayName = []
  302. for group in self:
  303. if group.tags:
  304. displayName.append(
  305. (group.id, group.number + '-' +group.tags[0].name))
  306. else:
  307. displayName.append((group.id, group.number))
  308. return displayName
  309. @api.multi
  310. @api.depends('lot')
  311. def get_number(self):
  312. for group in self:
  313. result = '*'
  314. if len(group.lot) > 2:
  315. result = group.lot[2].lot.name
  316. elif len(group.lot) > 0:
  317. result = group.lot[0].lot.name
  318. group.number = result
  319. def get_locations(self):
  320. return False
  321. @api.one
  322. def on_change_with_current_weight(self):
  323. if self.weights:
  324. self.current_weight = self.weights[0].id
  325. @api.one
  326. def get_consumed_feed(self):
  327. if self.quantity == 0:
  328. self.consumed_feed = self.feed_quantity/self.initial_quantity
  329. else:
  330. self.consumed_feed = self.feed_quantity/self.quantity
  331. class AnimalGroupWeight(models.Model):
  332. _name = 'farm.animal.group.weight'
  333. _order = 'timestamp DESC'
  334. rec_name = 'weight'
  335. party = fields.Many2one(comodel_name='farm.animal.group',
  336. string='Group', ondelete='CASCADE',
  337. required=True)
  338. timestamp = fields.Datetime(string='Date & time',
  339. default=fields.Datetime.now())
  340. quantity = fields.Integer(string='Number of individuals', required=True)
  341. uom = fields.Many2one(comodel_name='product.uom', string='Uom')
  342. weight = fields.Float(string='Weihht', digits=(3, 2), required=True)
  343. @api.onchange('timestamp')
  344. def get_defaults(self):
  345. if self.party is not False:
  346. self.quantity = self.party.quantity