stock_warehouse_transfer.py 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. # -*- encoding: utf-8 -*-
  2. ##############################################################################
  3. #
  4. # Copyright (C) 2015 ICTSTUDIO (<http://www.ictstudio.eu>).
  5. #
  6. # This program is free software: you can redistribute it and/or modify
  7. # it under the terms of the GNU Affero General Public License as
  8. # published by the Free Software Foundation, either version 3 of the
  9. # License, or (at your option) any later version.
  10. #
  11. # This program is distributed in the hope that it will be useful,
  12. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. # GNU Affero General Public License for more details.
  15. #
  16. # You should have received a copy of the GNU Affero General Public License
  17. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. #
  19. ##############################################################################
  20. from openerp import models, fields, api, _
  21. from openerp.exceptions import Warning
  22. from openerp.tools import float_compare
  23. import logging
  24. _logger = logging.getLogger(__name__)
  25. class StockWarehouseTransfer(models.Model):
  26. _name = 'stock.warehouse.transfer'
  27. _description = 'Stock Warehouse Transfer'
  28. _inherit = ['mail.thread', 'ir.needaction_mixin']
  29. @api.model
  30. def _get_default_name(self):
  31. return self.env['ir.sequence'].get('stock.warehouse.transfer')
  32. @api.model
  33. def _get_default_date(self):
  34. return fields.Date.context_today(self)
  35. @api.model
  36. def _get_default_state(self):
  37. return 'draft'
  38. @api.multi
  39. @api.depends('pickings.state')
  40. def _calc_transfer_state(self):
  41. for rec in self:
  42. if rec.pickings:
  43. picking_states = [p.state for p in rec.pickings]
  44. if 'done' in picking_states:
  45. rec.state = 'done'
  46. else:
  47. rec.state = 'draft'
  48. name = fields.Char(
  49. string='Referencia',
  50. default=_get_default_name)
  51. date = fields.Date(
  52. string='Fecha',
  53. default=_get_default_date)
  54. source_warehouse = fields.Many2one(
  55. comodel_name='stock.warehouse',
  56. string='Déposito de Origen')
  57. dest_warehouse = fields.Many2one(
  58. comodel_name='stock.warehouse',
  59. string='Déposito de Destino')
  60. state = fields.Selection(
  61. selection=[
  62. ('draft', 'Borrador'),
  63. ('done', 'Hecho')],
  64. string='Status',
  65. default=_get_default_state,
  66. store=True,
  67. compute=_calc_transfer_state)
  68. lines = fields.One2many(
  69. comodel_name='stock.warehouse.transfer.line',
  70. inverse_name='transfer',
  71. string='Lineas de Transferencia')
  72. pickings = fields.One2many(
  73. comodel_name='stock.picking',
  74. inverse_name='transfer',
  75. string='Transferencia Relacionada')
  76. company_id = fields.Many2one(
  77. comodel_name='res.company', string='Compania', required=True,
  78. default=lambda self: self.env['res.company']._company_default_get(
  79. 'stock.warehouse.transfer'))
  80. def get_transfer_picking_type(self):
  81. self.ensure_one()
  82. picking_types = self.env['stock.picking.type'].search(
  83. [
  84. ('default_location_src_id', '=', self.source_warehouse.lot_stock_id.id),
  85. ('code', '=', 'outgoing')
  86. ]
  87. )
  88. if not picking_types:
  89. _logger.error("No picking type found")
  90. #TODO: Exception Raise
  91. return picking_types and picking_types[0]
  92. @api.multi
  93. def get_picking_vals(self):
  94. self.ensure_one()
  95. picking_type = self.get_transfer_picking_type()
  96. picking_vals = {
  97. 'picking_type_id' : picking_type.id,
  98. 'transfer' : self.id,
  99. 'origin': self.name
  100. }
  101. return picking_vals
  102. @api.multi
  103. def action_create_picking(self):
  104. for rec in self:
  105. picking_vals = rec.get_picking_vals()
  106. _logger.debug("Picking Vals: %s", picking_vals)
  107. picking = rec.pickings.create(picking_vals)
  108. if not picking:
  109. _logger.error("Error Creating Picking")
  110. #TODO: Add Exception
  111. pc_group = rec._get_procurement_group()
  112. for line in rec.lines:
  113. move_vals = line.get_move_vals(picking, pc_group)
  114. if move_vals:
  115. _logger.debug("Move Vals: %s", move_vals)
  116. product = self.env['product.product'].browse(move_vals['product_id'])
  117. location = self.env['stock.location'].browse(move_vals['location_id'])
  118. uom = self.env['stock.location'].browse(move_vals['location_id'])
  119. if product.type == 'product':
  120. uom_record = product.uom_id
  121. qty_available = self.get_location_qty(product.id, move_vals['location_id'])
  122. compare_qty = float_compare(qty_available, move_vals['product_uom_qty'], precision_rounding=uom_record.rounding)
  123. if compare_qty == -1:
  124. warn_msg = _('Estas intentando transferir %.2f %s de %s pero el déposito de origen posee %.2f %s disponible!') % \
  125. (move_vals['product_uom_qty'], uom_record.name,
  126. product.name,
  127. max(0,qty_available), uom_record.name)
  128. raise Warning(_("No hay stock suficiente: "),_(warn_msg))
  129. move_id = self.env['stock.move'].create(move_vals)
  130. move_id.action_done()
  131. @api.multi
  132. def get_location_qty(self, product_id, location_id):
  133. location_ids = self.env['stock.location'].search([('active','=',True),('usage','=','internal')])
  134. for id in location_ids:
  135. suma = 0
  136. quant_ids = self.env['stock.quant'].search([('product_id','=', product_id),('location_id','=',location_id)])
  137. if quant_ids:
  138. for quant_id in quant_ids:
  139. suma = suma + quant_id.qty
  140. return suma
  141. @api.model
  142. def _prepare_procurement_group(self):
  143. return {'name': self.name}
  144. @api.model
  145. def _get_procurement_group(self):
  146. pc_groups = self.env['procurement.group'].search(
  147. [
  148. ('name', '=', self.name)
  149. ]
  150. )
  151. if pc_groups:
  152. pc_group = pc_groups[0]
  153. else:
  154. pc_vals = self._prepare_procurement_group()
  155. pc_group = self.env['procurement.group'].create(pc_vals)
  156. return pc_group or False