orden_servicio.py 13 KB

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