orden_servicio.py 15 KB

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