orden_servicio.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440
  1. # -*- coding: utf-8 -*-
  2. # License, author and contributors information in:
  3. # __openerp__.py file at the root folder of this module.
  4. from openerp import api, models, fields, _
  5. from openerp.exceptions import ValidationError, except_orm, Warning, RedirectWarning
  6. from openerp.tools import DEFAULT_SERVER_TIME_FORMAT
  7. from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT
  8. from datetime import datetime
  9. import logging
  10. _log = logging.getLogger(__name__)
  11. class OrdenServicio(models.Model):
  12. _name = 'orden.servicio'
  13. _description = 'Orden de servicio'
  14. _inherit = ['mail.thread', 'ir.needaction_mixin']
  15. def _get_user(self):
  16. return self.env.uid
  17. def _get_number(self):
  18. return self.env['ir.sequence'].get('orden.servicio') or '*'
  19. name = fields.Char(
  20. string=u'Referencia',
  21. default=_get_number
  22. )
  23. user_id = fields.Many2one(
  24. comodel_name='res.users',
  25. string='Usuario',
  26. default=_get_user
  27. )
  28. partner_id = fields.Many2one(
  29. comodel_name='res.partner',
  30. string='Cliente'
  31. )
  32. celular_partner = fields.Char(related='partner_id.mobile', string='Móvil', store=True)
  33. telefono_partner = fields.Char(related='partner_id.phone', string='Teléfono', store=True)
  34. ubicacion_google_link = fields.Char(string='Ubicación Google Link')
  35. currency_id = fields.Many2one('res.currency', string='Moneda Base')
  36. company_id = fields.Many2one('res.company', string='Empresa')
  37. name_obra = fields.Char(string='Obra', required=True)
  38. name_local = fields.Char(string='Local', required=True)
  39. order_date = fields.Datetime(
  40. string='Fecha de pedido de servicio', required=True,
  41. default=fields.Datetime.now
  42. )
  43. planned_start_date = fields.Datetime(
  44. string='Fecha y hora inicio de obra', required=True
  45. )
  46. planned_end_date = fields.Datetime(
  47. string='Fecha y hora fin de obra', required=True
  48. )
  49. contacto_obra = fields.Char(
  50. string='Persona de contacto de la obra', required=True
  51. )
  52. responsable = fields.Char(
  53. string='Técnico Responsable', required=True
  54. )
  55. celular_obra = fields.Char(
  56. string='Celular/Tel. de la Obra'
  57. )
  58. nro_factura = fields.Char(
  59. string='N° de factura'
  60. )
  61. distancia_obra = fields.Float(
  62. string='Distancia en km', required=True
  63. )
  64. croquis = fields.Char(
  65. string='Croquis de la obra/Ubicación', required=True
  66. )
  67. hrs_total = fields.Char(
  68. string='Hora total del trabajo', required=True
  69. )
  70. zona_obra = fields.Text(string='Zona obra de trabajo', required=True)
  71. obs_obra = fields.Text(
  72. string='Obs.'
  73. )
  74. fotos_obras = fields.Many2many(comodel_name='ir.attachment', relation='obra_attachment_rel', column1='obra_id', column2='attachment_id', string='Fotos del trabajo')
  75. horarios_dia = fields.One2many('horario.dia', 'servicio_id', 'Horarios por día')
  76. sale_order_id = fields.Many2one('sale.order', string='Orden de venta')
  77. product_ids = fields.One2many(
  78. comodel_name='servicio.producto',
  79. inverse_name='servicio_id',
  80. string='Productos a utilizar'
  81. )
  82. insumos_ids = fields.One2many(
  83. comodel_name='servicio.insumo',
  84. inverse_name='servicio_id',
  85. string='Insumos a utilizar'
  86. )
  87. logistica_ids = fields.One2many(
  88. comodel_name='servicio.logistica',
  89. inverse_name='servicio_id',
  90. string='Gastos de lógistica'
  91. )
  92. devolucion_ids = fields.One2many(
  93. comodel_name='devolucion.insumo',
  94. inverse_name='servicio_id',
  95. string='Devolución de productos e insumos'
  96. )
  97. recepcion_ids = fields.One2many(
  98. comodel_name='recepcion.fabrica',
  99. inverse_name='servicio_id',
  100. string='Recepción en fábrica'
  101. )
  102. invoice_ids = fields.One2many('account.invoice', 'servicio_invoice_id')
  103. invoice_count = fields.Integer(
  104. string='Facturas',
  105. compute='_get_invoice_count',
  106. )
  107. state = fields.Selection([
  108. ('draft', 'Pendiente'),
  109. ('in_progress', 'En progreso'),
  110. ('done', 'Realizado'),
  111. ('canceled', 'Cancelado')],
  112. string='Estado',
  113. default='draft'
  114. )
  115. @api.multi
  116. @api.depends('product_ids.subtotal')
  117. def _compute_total_producto(self):
  118. for record in self:
  119. record.total_producto = sum(record.product_ids.mapped('subtotal'))
  120. @api.multi
  121. @api.depends('insumos_ids.subtotal')
  122. def _compute_total_insumo(self):
  123. for record in self:
  124. record.total_insumo = sum(record.insumos_ids.mapped('subtotal'))
  125. @api.multi
  126. @api.depends('product_ids.subtotal')
  127. def _compute_total_logistica(self):
  128. for record in self:
  129. record.total_logistica = sum(record.logistica_ids.mapped('subtotal'))
  130. @api.multi
  131. @api.depends('insumos_ids.subtotal')
  132. def _compute_total_devolucion(self):
  133. for record in self:
  134. record.total_devolucion = sum(record.devolucion_ids.mapped('subtotal'))
  135. @api.multi
  136. @api.depends('insumos_ids.subtotal')
  137. def _compute_total_fabrica(self):
  138. for record in self:
  139. record.total_fabrica = sum(record.recepcion_ids.mapped('subtotal'))
  140. @api.depends('total_producto', 'total_insumo', 'total_logistica')
  141. def _compute_total_obra(self):
  142. for record in self:
  143. record.total_obra = record.total_producto + record.total_insumo + record.total_logistica
  144. total_producto = fields.Float(compute='_compute_total_producto', string='Total Producto', store=True)
  145. total_insumo = fields.Float(compute='_compute_total_insumo', string='Total Insumo', store=True)
  146. total_logistica = fields.Float(compute='_compute_total_logistica', string='Total Logística', store=True)
  147. total_devolucion = fields.Float(compute='_compute_total_devolucion', string='Total Devolución', store=True)
  148. total_fabrica = fields.Float(compute='_compute_total_fabrica', string='Total Recepción', store=True)
  149. total_obra = fields.Float(compute='_compute_total_obra', string='Total Obra', store=True)
  150. @api.model
  151. def defaults(self):
  152. res = super(OrderServicio, self).defaults()
  153. company_id = self.env['res.company']._company_default_get('order.servicio')
  154. currency_id = company_id.currency_id.id if company_id.currency_id else False
  155. res.update({
  156. 'currency_id': currency_id,
  157. 'company_id': company_id.id,
  158. })
  159. return res
  160. @api.one
  161. @api.depends('invoice_ids')
  162. def _get_invoice_count(self):
  163. self.invoice_count = len(self.invoice_ids)
  164. @api.one
  165. def button_in_progress(self):
  166. self.state = 'in_progress'
  167. @api.one
  168. def button_in_progress_back(self):
  169. self.state = 'draft'
  170. @api.one
  171. def button_done_back(self):
  172. self.state = 'in_progress'
  173. @api.one
  174. def button_done(self):
  175. self.state = 'done'
  176. @api.one
  177. def button_cancel(self):
  178. self.state = 'canceled'
  179. @api.one
  180. def onchange_partner_id(self, partner_id):
  181. _log.info('-'*100)
  182. _log.info(partner_id)
  183. @api.onchange('ubicacion_google_link')
  184. def on_ubicacion_google_link_change(self):
  185. for record in self:
  186. if record.ubicacion_google_link:
  187. # Abrir la ubicación en otra pestaña
  188. # Esto puede requerir personalización adicional dependiendo de tu requisito exacto
  189. url = record.ubicacion_google_link
  190. class ProductoServicio(models.Model):
  191. _name = 'servicio.producto'
  192. servicio_id = fields.Many2one(
  193. comodel_name='orden.servicio',
  194. string='Orden de servicio'
  195. )
  196. product_id = fields.Many2one('product.product', 'Producto', domain=[('type', '=', 'product')])
  197. categ_id = fields.Char('Categoría de producto')
  198. quantity = fields.Float(
  199. string='Cantidad',
  200. default=1,
  201. digits=(5, 3)
  202. )
  203. price_unit = fields.Float('Precio de costo')
  204. subtotal = fields.Float('Subtotal', compute='compute_subtotal', store=True, digits=(10, 0))
  205. @api.one
  206. @api.depends('quantity', 'price_unit')
  207. def compute_subtotal(self):
  208. self.subtotal = self.quantity * self.price_unit
  209. @api.onchange('product_id')
  210. def onchange_product_id(self):
  211. if self.product_id:
  212. self.description = self.product_id.name
  213. self.categ_id = self.product_id.categ_id.name
  214. self.type = 'product' if self.product_id.type == 'product' \
  215. else 'service'
  216. # @ TODO impuestos??
  217. # Obtener el precio del producto a partir de la tarifa del cliente
  218. self.price_unit = self.product_id.standard_price
  219. class ServicioInsumo(models.Model):
  220. _name = 'servicio.insumo'
  221. _description = 'Lista de Materiales proveidos'
  222. _inherit = ['mail.thread', 'ir.needaction_mixin']
  223. servicio_id = fields.Many2one(
  224. comodel_name='orden.servicio',
  225. string='Orden de servicio'
  226. )
  227. product_id = fields.Many2one('product.product', 'Producto', domain=[('type', '=', 'product')])
  228. descripcion = fields.Char(
  229. string='Descripcion',
  230. required=True
  231. )
  232. quantity = fields.Float(
  233. string='Cantidad',
  234. default=1,
  235. digits=(5, 3)
  236. )
  237. price_unit = fields.Float(
  238. string='Precio Unit.'
  239. )
  240. subtotal = fields.Float(
  241. string='Subtotal',
  242. compute='compute_subtotal',
  243. digits=(10, 0)
  244. )
  245. @api.one
  246. @api.depends('quantity', 'price_unit')
  247. def compute_subtotal(self):
  248. self.subtotal = self.quantity * self.price_unit
  249. @api.onchange('product_id')
  250. def onchange_product_id(self):
  251. if self.product_id:
  252. self.descripcion = self.product_id.name
  253. self.price_unit = self.product_id.standard_price
  254. class ServicioLogistica(models.Model):
  255. _name = 'servicio.logistica'
  256. _description = 'Gastos de logística'
  257. _inherit = ['mail.thread', 'ir.needaction_mixin']
  258. servicio_id = fields.Many2one(
  259. comodel_name='orden.servicio',
  260. string='Orden de servicio'
  261. )
  262. fecha = fields.Date(
  263. string='Fecha',
  264. required=True
  265. )
  266. product_id = fields.Many2one('product.product', 'Servicio', domain=[('type', '=', 'service')])
  267. descripcion = fields.Char(
  268. string='Descripcion',
  269. required=True
  270. )
  271. quantity = fields.Float(
  272. string='Km recorrido',
  273. default=1
  274. )
  275. price_unit = fields.Float(
  276. string='Precio Unit.'
  277. )
  278. subtotal = fields.Float(
  279. string='Subtotal',
  280. compute='compute_subtotal',
  281. digits=(10, 0)
  282. )
  283. @api.one
  284. @api.depends('quantity', 'price_unit')
  285. def compute_subtotal(self):
  286. self.subtotal = self.quantity * self.price_unit
  287. @api.onchange('product_id')
  288. def onchange_product_id(self):
  289. if self.product_id:
  290. self.descripcion = self.product_id.name
  291. self.price_unit = self.product_id.standard_price
  292. class DevolucionInsumo(models.Model):
  293. _name = 'devolucion.insumo'
  294. _description = 'Devolución de productos e insumos'
  295. _inherit = ['mail.thread', 'ir.needaction_mixin']
  296. servicio_id = fields.Many2one(
  297. comodel_name='orden.servicio',
  298. string='Orden de servicio'
  299. )
  300. product_id = fields.Many2one('product.product', 'Producto', domain=[('type', '=', 'product')])
  301. descripcion = fields.Char(
  302. string='Descripcion',
  303. required=True
  304. )
  305. quantity = fields.Float(
  306. string='Cantidad',
  307. default=1,
  308. digits=(5, 3)
  309. )
  310. price_unit = fields.Float(
  311. string='Precio Unit.'
  312. )
  313. subtotal = fields.Float(
  314. string='Subtotal',
  315. compute='compute_subtotal',
  316. digits=(10, 0)
  317. )
  318. @api.one
  319. @api.depends('quantity', 'price_unit')
  320. def compute_subtotal(self):
  321. self.subtotal = self.quantity * self.price_unit
  322. @api.onchange('product_id')
  323. def onchange_product_id(self):
  324. if self.product_id:
  325. self.descripcion = self.product_id.name
  326. self.price_unit = self.product_id.standard_price
  327. class RecepcionFabrica(models.Model):
  328. _name = 'recepcion.fabrica'
  329. _description = 'Recepción en fábrica '
  330. _inherit = ['mail.thread', 'ir.needaction_mixin']
  331. servicio_id = fields.Many2one(
  332. comodel_name='orden.servicio',
  333. string='Orden de servicio'
  334. )
  335. fecha = fields.Date(
  336. string='Fecha',
  337. required=True
  338. )
  339. product_id = fields.Many2one(
  340. comodel_name='product.product',
  341. string='Productos'
  342. )
  343. descripcion = fields.Char(
  344. string='Descripcion',
  345. required=True
  346. )
  347. quantity = fields.Float(
  348. string='Cantidad',
  349. default=1
  350. )
  351. price_unit = fields.Float(
  352. string='Precio Unit.'
  353. )
  354. subtotal = fields.Float(
  355. string='Subtotal',
  356. compute='compute_subtotal',
  357. digits=(10, 0)
  358. )
  359. employee_id = fields.Many2one(
  360. 'hr.employee',
  361. string='Empleado'
  362. )
  363. @api.one
  364. @api.depends('quantity', 'price_unit')
  365. def compute_subtotal(self):
  366. self.subtotal = self.quantity * self.price_unit
  367. @api.onchange('product_id')
  368. def onchange_product_id(self):
  369. if self.product_id:
  370. self.descripcion = self.product_id.name
  371. self.price_unit = self.product_id.standard_price
  372. class AccountInvoice(models.Model):
  373. _inherit = 'account.invoice'
  374. servicio_invoice_id = fields.Many2one('orden.servicio')