orden_servicio.py 15 KB

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