Merge lp:~altegra/altegra/altegra_dev_carlos_2 into lp:~altegra/+junk/altegra

Status: Merged
Merged at revision: 102
Proposed branch: lp:~altegra/altegra/altegra_dev_carlos_2
Merge into: lp:~altegra/+junk/altegra
Diff against target: 1882 lines (+1587/-50)
25 files modified
account_altegra/__openerp__.py (+1/-0)
account_altegra/account_invoice_view.xml (+16/-0)
crm_altegra/__init__.py (+32/-0)
crm_altegra/__openerp__.py (+57/-0)
crm_altegra/crm_project.py (+586/-0)
crm_altegra/crm_project_view.xml (+442/-0)
crm_altegra/security/groups.xml (+15/-0)
crm_altegra/security/ir.model.access.csv (+4/-0)
crm_altegra/security/sequence.xml (+21/-0)
dollars_altegra/__init__.py (+4/-0)
dollars_altegra/__openerp__.py (+2/-0)
dollars_altegra/account_invoice_view.xml (+45/-3)
dollars_altegra/account_voucher_view.xml (+16/-0)
dollars_altegra/internal_order.py (+44/-0)
dollars_altegra/internal_order_view.xml (+19/-0)
dollars_altegra/purchase.py (+52/-0)
dollars_altegra/purchase_view.xml (+22/-0)
dollars_altegra/sale.py (+10/-0)
dollars_altegra/stock.py (+47/-0)
dollars_altegra/wizard/__init__.py (+32/-0)
dollars_altegra/wizard/create_purchase.py (+62/-0)
internal_order_altegra/purchase.py (+4/-1)
internal_order_altegra/sale.py (+24/-29)
internal_order_altegra/wizard/create_purchase.py (+29/-16)
product_altegra/product.py (+1/-1)
To merge this branch: bzr merge lp:~altegra/altegra/altegra_dev_carlos_2
Reviewer Review Type Date Requested Status
Eric Hernández - http://www.grupoaltegra.com Pending
Review via email: mp+170175@code.launchpad.net

Description of the change

[REF] Purchase_order has product's price in Dollars

To post a comment you must log in.
102. By Eric Hernández - http://www.grupoaltegra.com

[MERGE] Carlos

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'account_altegra/__openerp__.py'
2--- account_altegra/__openerp__.py 2013-02-19 00:22:16 +0000
3+++ account_altegra/__openerp__.py 2013-07-03 23:03:28 +0000
4@@ -38,6 +38,7 @@
5 "description": "Account customization altegra",
6 "data" :[
7 #~ "account_invoice_view.xml",
8+ "account_invoice_view.xml",
9 ],
10 'demo': [],
11 'test': [],
12
13=== added file 'account_altegra/account_invoice_view.xml'
14--- account_altegra/account_invoice_view.xml 1970-01-01 00:00:00 +0000
15+++ account_altegra/account_invoice_view.xml 2013-07-03 23:03:28 +0000
16@@ -0,0 +1,16 @@
17+<?xml version="1.0" encoding="utf-8"?>
18+<openerp>
19+ <data>
20+ <record model="ir.ui.view" id="view_invoice_line_form_inherit">
21+ <field name="name">view.invoice.line.form.inherit</field>
22+ <field name="type">form</field>
23+ <field name="model">account.invoice.line</field>
24+ <field name="inherit_id" ref="account.view_invoice_line_form" />
25+ <field name="arch" type="xml">
26+ <field name="uos_id" position="replace">
27+ <field name="uos_id" nolabel="1"/>
28+ </field>
29+ </field>
30+ </record>
31+ </data>
32+</openerp>
33
34=== added directory 'crm_altegra'
35=== added file 'crm_altegra/__init__.py'
36--- crm_altegra/__init__.py 1970-01-01 00:00:00 +0000
37+++ crm_altegra/__init__.py 2013-07-03 23:03:28 +0000
38@@ -0,0 +1,32 @@
39+#!/usr/bin/env python
40+#-*- coding:utf-8 -*-
41+
42+#############################################################################
43+# Module Writen to OpenERP, Open Source Management Solution
44+# CopyLeft 2012 - http://www.grupoaltegra.com
45+# You are free to share, copy, distribute, transmit, adapt and use for commercial purpose
46+# More information about license: http://www.gnu.org/licenses/agpl.html
47+# info Grupo Altegra (openerp@grupoaltegra.com)
48+#
49+#############################################################################
50+#
51+# Coded by: Carlos Blanco (carlos.blanco@grupoaltegra.com)
52+#
53+#############################################################################
54+#
55+# This program is free software: you can redistribute it and/or modify
56+# it under the terms of the GNU Affero General Public License as
57+# published by the Free Software Foundation, either version 3 of the
58+# License, or (at your option) any later version.
59+#
60+# This program is distributed in the hope that it will be useful,
61+# but WITHOUT ANY WARRANTY; without even the implied warranty of
62+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
63+# GNU Affero General Public License for more details.
64+#
65+# You should have received a copy of the GNU Affero General Public License
66+# along with this program. If not, see <http://www.gnu.org/licenses/>.
67+#
68+#############################################################################
69+
70+import crm_project
71
72=== added file 'crm_altegra/__openerp__.py'
73--- crm_altegra/__openerp__.py 1970-01-01 00:00:00 +0000
74+++ crm_altegra/__openerp__.py 2013-07-03 23:03:28 +0000
75@@ -0,0 +1,57 @@
76+#!/usr/bin/env python
77+#-*- coding:utf-8 -*-
78+
79+#############################################################################
80+# Module Writen to OpenERP, Open Source Management Solution
81+# CopyLeft 2012 - http://www.grupoaltegra.com
82+# You are free to share, copy, distribute, transmit, adapt and use for commercial purpose
83+# More information about license: http://www.gnu.org/licenses/agpl.html
84+# info Grupo Altegra (openerp@grupoaltegra.com)
85+#
86+#############################################################################
87+#
88+# Coded by: Carlos Blanco (carlos.blanco@grupoaltegra.com)
89+#
90+#############################################################################
91+#
92+# This program is free software: you can redistribute it and/or modify
93+# it under the terms of the GNU Affero General Public License as
94+# published by the Free Software Foundation, either version 3 of the
95+# License, or (at your option) any later version.
96+#
97+# This program is distributed in the hope that it will be useful,
98+# but WITHOUT ANY WARRANTY; without even the implied warranty of
99+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
100+# GNU Affero General Public License for more details.
101+#
102+# You should have received a copy of the GNU Affero General Public License
103+# along with this program. If not, see <http://www.gnu.org/licenses/>.
104+#
105+#############################################################################
106+
107+{
108+
109+ "name": "CRM Altegra",
110+ "version": "0.1",
111+ "depends": ["base","sale_altegra"],
112+ "author": "Grupo Altegra",
113+ "description": """
114+ This module allows you to manage projects that are entered
115+ """,
116+ "website" : "http://www.grupoaltegra.com",
117+ "category": "Custom Modules",
118+
119+ "data" :[
120+ 'security/ir.model.access.csv',
121+ 'security/groups.xml',
122+ 'security/sequence.xml',
123+ 'crm_project_view.xml',
124+ ],
125+
126+ 'demo': [
127+ ],
128+
129+ "active": False,
130+ "images": [],
131+ "installable": True,
132+}
133
134=== added file 'crm_altegra/crm_project.py'
135--- crm_altegra/crm_project.py 1970-01-01 00:00:00 +0000
136+++ crm_altegra/crm_project.py 2013-07-03 23:03:28 +0000
137@@ -0,0 +1,586 @@
138+#!/usr/bin/env python
139+#-*- coding:utf-8 -*-
140+
141+#############################################################################
142+# Module Writen to OpenERP, Open Source Management Solution
143+# CopyLeft 2012 - http://www.grupoaltegra.com
144+# You are free to share, copy, distribute, transmit, adapt and use for commercial purpose
145+# More information about license: http://www.gnu.org/licenses/agpl.html
146+# info Grupo Altegra (openerp@grupoaltegra.com)
147+#
148+#############################################################################
149+#
150+# Coded by: Carlos Blanco (carlos.blanco@grupoaltegra.com)
151+#
152+#############################################################################
153+#
154+# This program is free software: you can redistribute it and/or modify
155+# it under the terms of the GNU Affero General Public License as
156+# published by the Free Software Foundation, either version 3 of the
157+# License, or (at your option) any later version.
158+#
159+# This program is distributed in the hope that it will be useful,
160+# but WITHOUT ANY WARRANTY; without even the implied warranty of
161+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
162+# GNU Affero General Public License for more details.
163+#
164+# You should have received a copy of the GNU Affero General Public License
165+# along with this program. If not, see <http://www.gnu.org/licenses/>.
166+#
167+#############################################################################
168+
169+from osv import osv, fields
170+import datetime
171+import time
172+from tools.translate import _
173+
174+class crm_project(osv.Model):
175+ _name = "crm.project"
176+
177+ def _get_task_date(self, cr, uid, ids, field_names=None, arg=False, context=None):
178+ """
179+ Metodo para obtener la fecha menor de todas las tareas agregadas al proyecto
180+ """
181+ res = {}
182+ # Para cada projecto buscamos la fecha menor de todas sus tareas
183+ for project_row in self.browse(cr, uid, ids, context):
184+ # Si es el campo "task_warning_date" buscamos el campo "warning_date"
185+ if field_names == 'task_warning_date':
186+ field = "warning_date"
187+ else:
188+ field = "date_limit"
189+ # Query donde obtenemos la fehca menor
190+ query = "SELECT "+str(field)+" FROM crm_task WHERE state = 'open' AND type = '"+str(project_row.type)+"' AND project_id = '"+str(project_row.id)+"' order by date_limit ASC limit 1 "
191+ cr.execute(query)
192+ date_min = cr.fetchall()
193+ # Si se tiene una fecha
194+ if date_min:
195+ # Obtenemos la fecha
196+ date_min = date_min[0][0]
197+ # Separams la fecha y la hora
198+ date_min = date_min.split(' ')
199+ # Obtenemos solo la fecha
200+ date2 = date_min[0]
201+ # Se la asiganamos al campo
202+ res[project_row.id] = str(date2)
203+ else:
204+ res[project_row.id] = False
205+ return res
206+
207+ _columns = {
208+ 'name': fields.char('Nombre',size= 64, help="Nombre del proyecto", required=True, readonly=True, states={'draft': [('readonly', False)]}),
209+ 'reference': fields.char('Referencia',size=64, readonly=True,states={'draft': [('readonly', False)]}),
210+ 'user_id': fields.many2one('res.users','Responsable', required=True, readonly=True, states={'draft': [('readonly', False)]}, help = "Usuario que debe estar encargado del proyecto"),
211+ 'estimated_amount': fields.float('Ingreso estimado', states={'done': [('readonly', True)],'cancel': [('readonly', True)]}, help = "Ingreso que podria dar este proyecto si se gana"),
212+ 'date':fields.datetime('Fecha de creación', readonly=True, states={'draft': [('readonly', False)]}, help = "Fecha en que se creo el proyecto "),
213+ 'customer_id': fields.many2one('res.partner','Cliente', readonly=True, states={'draft': [('readonly', False)]}, help = "Cliente que se esta trabajando si es que existe en la base"),
214+ 'company': fields.char('Empresa', size= 64, readonly=True, required=True, states={'draft': [('readonly', False)]}, help = " Nombre de la empresa que tiene el proyecto"),
215+ 'contact_name': fields.char('Nombre de contacto', states={'done': [('readonly', True)],'cancel': [('readonly', True)]}, size=64, help="Nombre con quien se debe contactar para información del proyecto"),
216+ 'phone': fields.char('Teléfono', size= 64, states={'done': [('readonly', True)],'cancel': [('readonly', True)]}),
217+ 'mail': fields.char('e-mail',size= 64, states={'done': [('readonly', True)],'cancel': [('readonly', True)]}),
218+ 'type': fields.selection([
219+ ('opportunity', 'Oportunidad'),
220+ ('implementation', 'Implementación')
221+ ], 'Tipo', help="Tipo del proyecto.", readonly=True, states={'draft': [('readonly', False)]}),
222+ 'state': fields.selection([
223+ ('draft', 'Borrador'),
224+ ('opportunity', 'Oportunidad'),
225+ ('implementation', 'Implementación'),
226+ ('done', 'Finalizado'),
227+ ('cancel', 'Cancelada')
228+ ], 'Estado', readonly=True, help="Estado en el que se encuentra el proyecto.", select=True),
229+ #~ 'task_ids': fields.one2many('crm.task','project_id', 'Tareas', states={'done': [('readonly', True)],'draft': [('readonly', True)],'cancel': [('readonly', True)]}, help="Tareas que deben realizarse para el proyecto"),
230+ 'task_opportunity_ids': fields.one2many('crm.task','project_id', 'Tareas Oportunidades', domain=[('type','=','opportunity')], readonly=True,states={'opportunity': [('readonly', False)]}, help="Tareas que deben realizarse para el proyecto"),
231+ 'task_implementation_ids': fields.one2many('crm.task','project_id', 'Tareas Implementaciones', domain=[('type','=','implementation')], readonly=True,states={'implementation': [('readonly', False)]}, help="Tareas que deben realizarse para el proyecto"),
232+ 'activity_ids': fields.one2many('crm.activities','project_id', 'Actividades', states={'done': [('readonly', True)],'draft': [('readonly', True)],'cancel': [('readonly', True)]}, help="Actividades que deben realizarse para el proyecto"),
233+ 'task_min_date':fields.function(_get_task_date,type='date',string="Fecha menor", help="Fecha menor de todos las tareas agregadas al proyecto"),
234+ 'task_warning_date':fields.function(_get_task_date,type='date',string="Fecha menor", help="Fecha menor de todos las tareas agregadas al proyecto"),
235+ 'change_date':fields.boolean('Cambio Fecha', help ="Indica que se cambio la fecha de alguna tarea"),
236+ 'pending_project': fields.boolean('Proyecto Pendiente', states={'done': [('readonly', True)],'draft': [('readonly', True)],'cancel': [('readonly', True)]}, help="Se marca esta opcion para indicar que éste proyecto tendra un seguimiento a largo plazo."),
237+ 'UEE': fields.many2one('account.analytic.account', 'UEE', required=True, help="Unidad de negocios a las que pertenece el usuario."),
238+ }
239+
240+ _defaults = {
241+ 'state': 'draft',
242+ 'date': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'),
243+ 'user_id': lambda obj, cr, uid, context: uid,
244+ 'type': 'opportunity',
245+ 'pending_project': False,
246+ 'reference': lambda obj, cr, uid, context: obj.pool.get('ir.sequence').get(cr, uid, 'crm.project'),
247+ }
248+
249+ def acction_done(self, cr, uid, ids, context=None):
250+ """
251+ Función para finalizar el proyecto y cambiarlos a estado Done
252+ """
253+ for project_row in self.browse(cr, uid ,ids, context):
254+ # Validamos que se hayan realizado todas las tareas
255+ #~ self.validate_task_done(cr, uid, project_row.task_ids, context)
256+ self.validate_task_done(cr, uid, project_row.task_implementation_ids, context)
257+ self.write(cr, uid, ids, {'state':'done'})
258+ return True
259+
260+ def review_task_change_date(self, cr, uid, ids, context=None):
261+ """
262+ función para revisar si a otra tarea se le han cambiado la fecha
263+ """
264+ for projetc_row in self.browse(cr, uid, ids, context):
265+ change_date = False
266+ if projetc_row.type == 'opportunity':
267+ for task_row in projetc_row.task_opportunity_ids:
268+ if task_row.change_date and task_row.state == 'open':
269+ change_date = True
270+ break
271+ self.write(cr, uid, ids, {'change_date':change_date})
272+ elif projetc_row.type == 'implementation':
273+ for task_row in projetc_row.task_implementation_ids:
274+ if task_row.change_date and task_row.state == 'open':
275+ change_date = True
276+ break
277+ self.write(cr, uid, [projetc_row.id], {'change_date':change_date})
278+ return True
279+
280+ def acction_cancel(self, cr, uid, ids, context=None):
281+ """
282+ Función para cancelar los projectos y cambiarlas a estado Cancelodo
283+ """
284+ for project_row in self.browse(cr, uid, ids, context):
285+ task_opportunity_ids = [task_row.id for task_row in project_row.task_opportunity_ids]
286+ task_implementation_ids = [task_row.id for task_row in project_row.task_implementation_ids]
287+ activities_ids = [activity_row.id for activity_row in project_row.activity_ids]
288+ if task_opportunity_ids:
289+ self.pool.get('crm.task').acction_cancel(cr, uid, task_opportunity_ids, context)
290+ if task_implementation_ids:
291+ self.pool.get('crm.task').acction_cancel(cr, uid, task_implementation_ids, context)
292+ #~ task_ids = [task_row.id for task_row in project_row.task_ids]
293+ #~ if task_ids:
294+ #~ self.pool.get('crm.task').acction_cancel(cr, uid, task_ids, context)
295+ self.write(cr, uid, ids, {'state':'cancel'})
296+ return True
297+
298+ def on_change_customer_id(self, cr, uid, ids, partner_id, context = None):
299+ """
300+ Método para obtener todos los datos del cliente que se esta seleccionando
301+ """
302+ val = {}
303+ if partner_id:
304+ partner_row = self.pool.get('res.partner').browse(cr, uid, partner_id)
305+ val.update({'company':partner_row.name})
306+ if partner_row.address:
307+ address_row = partner_row.address[0]
308+ val.update({'contact_name':address_row.name, 'phone':address_row.phone, 'mail':address_row.email})
309+ return { 'value' : val}
310+
311+ def validate_task_done(self, cr, uid, task_rows, context=None):
312+ """
313+ Función que evalua si todas las tareas ya fueron terminadas
314+ """
315+ done = False
316+ if not task_rows:
317+ raise osv.except_osv(_('Error !'),_('No tienes asignada ninguna tarea al proyecto.'))
318+ for task_row in task_rows:
319+ if task_row.state in ('draft','open'):
320+ raise osv.except_osv(_('Error !'),_('Aun falta terminar la tarea '+str(task_row.name)+'.'))
321+ if task_row.state == 'done':
322+ done = True
323+ if not done:
324+ raise osv.except_osv(_('Error !'),_('No se realizo ninguna tarea.'))
325+ return True
326+
327+ def acction_confirm(self, cr, uid, ids, context=None):
328+ """
329+ Función para confirmar el proyecto y pasarlo a estado oportunidad
330+ """
331+ self.write(cr, uid, ids, {'state': 'opportunity','type':'opportunity'})
332+ return True
333+
334+ def acction_implementation(self, cr, uid, ids, context=None):
335+ """
336+ Función para confirmar el proyecto y pasarlo a estado implementación
337+ """
338+ for project_row in self.browse(cr, uid, ids, context):
339+ if not project_row.type == 'implementation':
340+ self.validate_task_done(cr, uid, project_row.task_opportunity_ids, context)
341+ #~ self.validate_task_done(cr, uid, project_row.task_ids, context)
342+ self.write(cr, uid, ids, {'state': 'implementation', 'type':'implementation'})
343+ return True
344+
345+ def unlink(self, cr, uid, ids, context=None):
346+ """
347+ Función que redefine la función unlink para evitar que eliminen proyectos que no esten en estado draft
348+ """
349+ for project_row in self.browse(cr, uid, ids, context):
350+ task_ids = []
351+ if project_row.state != 'draft':
352+ raise osv.except_osv(_('Error !'),_('Solo puedes eliminar proyectos en estao Borrador.'))
353+ task_opportunity_ids = [task_row.id for task_row in project_row.task_opportunity_ids]
354+ task_implementation_ids = [task_row.id for task_row in project_row.task_implementation_ids]
355+ if task_opportunity_ids:
356+ self.pool.get('crm.task').unlink(cr, uid, task_opportunity_ids)
357+ if task_implementation_ids:
358+ self.pool.get('crm.task').unlink(cr, uid, task_implementation_ids)
359+ #~ task_ids = [task_row.id for task_row in project_row.task_ids]
360+ #~ if task_ids:
361+ #~ self.pool.get('crm.task').unlink(cr, uid, task_ids)
362+ return super(crm_project, self).unlink(cr, uid, ids, context)
363+
364+ def search_task_expired(self, cr, uid, ids=None, context=None):
365+ if not context:
366+ context = {}
367+ self.pool.get('crm.task').search_task_expired(cr, uid, ids=None, context=None)
368+ return True
369+
370+class crm_task(osv.Model):
371+ _name = "crm.task"
372+
373+ _columns = {
374+ 'name': fields.char('Nombre Tarea', size=64, required=True,readonly=True, states={'draft': [('readonly', False)]}),
375+ 'date_limit': fields.datetime('Fecha Limite', required=True, states={'cancel': [('readonly', True)]}, help="Fecha limite en la cual debe realizarse la tarea"),
376+ 'user_id': fields.many2one('res.users','Responsable', required=True, select=True,readonly=True, states={'draft': [('readonly', False)]}),
377+ 'note': fields.text('Notas',states={'cancel': [('readonly', True)]}),
378+ 'project_id': fields.many2one('crm.project', 'Proyecto', domain="[('state','in',('opportunity','implementation'))]", required = True, select=True,readonly=True, states={'draft': [('readonly', False)]}),
379+ 'type': fields.selection([
380+ ('opportunity', 'Oportunidad'),
381+ ('implementation', 'Implementación')
382+ ], 'Tipo', help="Tipo de la tarea.", readonly=True, states={'draft': [('readonly', False)]},select=True),
383+ 'state': fields.selection([
384+ ('draft', 'Borrador'),
385+ ('open', 'Abierta'),
386+ ('done', 'Finalizado'),
387+ ('cancel', 'Cancelada')
388+ ], 'Estado', readonly=True, help="Estado en el que se encuentra la tarea.", select=True),
389+ 'warning_date': fields.date('Fecha para aviso', help="Fecha en que se avisara que la tarea esta por vencerse"),
390+ 'change_date':fields.boolean('Cambio Fecha', readonly=True, help ="Indica que se cambio la fecha de la tarea"),
391+ 'activity_id': fields.many2one('crm.activities','Actividad', required=True, readonly=True, states={'draft': [('readonly', False)]}, help="Actividad a la que pertenece esta tarea"),
392+ }
393+
394+ _defaults = {
395+ 'state': 'draft',
396+ 'change_date': False,
397+ 'user_id': lambda obj, cr, uid, context: uid,
398+ 'type': 'opportunity',
399+ }
400+
401+ def onchange_activity(self, cr, uid, ids, activity_id,context=None):
402+ """Función para ontener el proyecto al que pertenece el sprint seleccionado"""
403+ val = {}
404+ if not activity_id:
405+ val['project_id'] = False
406+ return {'value': val}
407+ # Obtenemos el registro de la actividad
408+ activity_row = self.pool.get('crm.activities').browse(cr, uid, activity_id)
409+ # Asignamos al proyecto que tiene asigando
410+ val['project_id'] = activity_row.project_id.id
411+ return {'value': val}
412+
413+ def get_email_vals(self, cr, uid, task_ids, subject, message, context=None):
414+ """
415+ Funcion para obtener los datos para crear el correo
416+ """
417+ list_vals = []
418+ notifications_obj = self.pool.get('email.notifications')
419+ user_obj = self.pool.get('res.users')
420+ # Buscamos las notificaciones
421+ notifications_ids = notifications_obj.search(cr, uid, [], limit = 1)
422+ if not notifications_ids:
423+ raise osv.except_osv(_('Error'), _("No existen correos de destinatario en las notificaciones!"))
424+ notifications_row = notifications_obj.browse(cr,uid, notifications_ids, context)[0]
425+ # Validamos si existen correos para productos recibidos
426+ if not notifications_row.authorization_discount:
427+ raise osv.except_osv(_('Error'), _("No existen correos de destinatario !"))
428+ for task_row in self.browse(cr, uid, task_ids, context):
429+ # Validamos que el usuario tenga correo
430+ if not task_row.user_id.user_email:
431+ raise osv.except_osv(_('Error'), _("No tiene correo el usuario "+str(task_row.user_id.name)+" !"))
432+ date = str(task_row.date_limit)
433+ task_name = task_row.name.encode('utf-8')
434+ project_name = task_row.project_id.name.encode('utf-8')
435+ # concatenamos el asunto y el mensaje con los datos de la tarea
436+ subject_new = subject % (str(task_name), date)
437+ message_new = message % (str(task_name),str(project_name),date,task_row.user_id.name.encode('utf-8'))
438+ # Obtenemos los destinatarios que es el del responsable de la tarea y al director
439+ email_to = notifications_row.authorization_discount.encode('utf-8') +","+task_row.user_id.user_email.encode('utf-8')
440+ # Obtenemos todos los valores para crear el correo
441+ vals = {
442+ 'email_from': "moyblanco22@gmail.com",
443+ 'email_to': email_to,
444+ 'subject': subject_new,
445+ 'body_text' :message_new,
446+ }
447+ list_vals.append(vals)
448+ return list_vals
449+
450+ def search_task_expired(self, cr, uid, ids=None, context=None):
451+ if not context:
452+ context = {}
453+ # Obtenemos la fecha de hoy
454+ today = datetime.date.today()
455+ # Obtenemos las tareas que esten abiertas y que su fecha de expiracion es
456+ expiring_task_ids = self.search(cr, uid, [('state','=','open'),('warning_date','=',today)])
457+ # Obtenemos las tareas que estan abiertas pero la fecha limite de realizacion esta pasada
458+ expired_task_ids = self.search(cr, uid, [('state','=','open'),('date_limit','<',str(today))])
459+ # Creamos los correos para las tareas que apenas expiraran
460+ if expiring_task_ids:
461+ # Creamos el asunto y el mensaje
462+ subject = "La tarea '%s' esta por expirar el dia %s "
463+ msj = "La tarea '%s' del proyecto '%s' tiene fecha limite de realizacion el dia %s \n Responsable: %s"
464+ # Obtenemos los diccionarios para las tareas que van a expirar
465+ vals_expiring_task_ids = self.get_email_vals(cr, uid, expiring_task_ids, subject, msj.encode('utf-8'), context)
466+ # Enviamos los correos de las tareas que apenas van a expirar
467+ self.send_email(cr, uid, ids, vals_expiring_task_ids, context)
468+ # Creamos los correos para las tareas que ya estan expiradass
469+ if expired_task_ids:
470+ # Creamos el asunto y mensaje
471+ subject = "La tarea '%s' ya expiro el dia %s"
472+ msj = "La tarea '%s' del proyecto '%s' tiene fecha limite de realizacion el dia %s \n Responsable: %s"
473+ # Obtenemos los diccionarios para las tareas que van a expirar
474+ vals_expired_task_ids = self.get_email_vals(cr, uid, expired_task_ids, subject, msj.encode('utf-8'), context)
475+ # Enviamos correos con las tareas ya expiradas
476+ self.send_email(cr, uid, ids, vals_expired_task_ids, context)
477+ return True
478+
479+ def send_email(self, cr, uid, ids, list_vals, context=None):
480+ """
481+ Método que envia correo por el picking que se recibio
482+ ids: ids de task_row
483+ vals: diccionario con todos los elementos que se necesitan para crear el correo "email_from, email_to, subject, body_text"
484+ """
485+ if not context:
486+ context = {}
487+ # Objetos
488+ mail_message_obj = self.pool.get('mail.message')
489+ for vals in list_vals:
490+ # Creamos el correo
491+ msg_id = mail_message_obj.schedule_with_attach(cr, uid, vals['email_from'], [vals['email_to']], vals['subject'], vals['body_text'],
492+ model='mail.campaign', email_cc=False, email_bcc=False, reply_to=False,
493+ attachments={}, references=False, res_id=1,
494+ subtype='html', headers=False, context=context)
495+ # Enviamos el Correo
496+ mail_message_obj.send(cr,uid,[msg_id],context)
497+ return True
498+
499+ def acction_confirm(self, cr, uid, ids, context=None):
500+ """
501+ Funcion para aprobar las tareas y cambiarlas a estado aprobada
502+ """
503+ self.write(cr, uid, ids, {'state':'open'})
504+ activities_ids = [task_row.activity_id.id for task_row in self.browse(cr, uid, ids, context)]
505+ if activities_ids:
506+ self.pool.get('crm.activities').update_state_activities(cr, uid, activities_ids, context)
507+ return True
508+
509+ def acction_done(self, cr, uid, ids, context=None):
510+ """
511+ Funcion para Terminar las tareas y cambiarlas a estado Finalizado
512+ """
513+ activities_ids = []
514+ # Para cada tarea que se quiere finalizar se obtiene su actividad y se revisa si no tiene revisiones pendientes
515+ for task_row in self.browse(cr, uid, ids, context):
516+ activities_ids.append(task_row.activity_id.id)
517+ # Si aun no se revisa esa tarea se marca un error
518+ if task_row.change_date:
519+ raise osv.except_osv(_('Error !'),_('No se puede finalizar una tarea que no se ha revisado.'))
520+ # Se actualiza el estado de las tareas a realizado si todas estan bien
521+ self.write(cr, uid, ids, {'state':'done'})
522+ # Se actualizan las actividades de las tareas que se acaban de finalizar
523+ if activities_ids:
524+ self.pool.get('crm.activities').update_state_activities(cr, uid, activities_ids, context)
525+ return True
526+
527+ def acction_cancel(self, cr, uid, ids, context=None):
528+ """
529+ Funcion para cancelar las tareas y cambiarlas a estado Finalizado
530+ """
531+ project_ids = []
532+ activities_ids = []
533+ # Se obtienen los proyectos relacionados a las tareas a cancelar
534+ for task_row in self.browse(cr, uid, ids, context):
535+ if task_row.change_date:
536+ project_ids.append(task_row.project_id.id)
537+ activities_ids.append(task_row.activity_id.id)
538+ # Se actualiza el proyecto a revisado puesto que se cancelo la tarea que se cambio la fecha
539+ if project_ids:
540+ # Se actualiza el proyecto indicando que ya se reviso la tarea con fecha cambiada
541+ self.pool.get('crm.project').review_task_change_date(cr, uid, project_ids, context)
542+ self.write(cr, uid, ids, {'state':'cancel'})
543+ if activities_ids:
544+ self.pool.get('crm.activities').update_state_activities(cr, uid, activities_ids, context)
545+ return True
546+
547+ def action_review(self, cr, uid, ids, context=None):
548+ """
549+ Funcion para indicar que esta tarea ya fue revisada
550+ """
551+ project_ids = []
552+ # Se buscan los proyectos relacionados con la tarea
553+ for task_row in self.browse(cr, uid, ids, context):
554+ project_ids.append(task_row.project_id.id)
555+ # Se actualiza la tarea indicando que ya se reviso
556+ self.write(cr, uid, ids, {'change_date':False})
557+ if project_ids:
558+ # Se actualiza el proyecto indicando que ya se reviso
559+ self.pool.get('crm.project').review_task_change_date(cr, uid, project_ids, context)
560+ return True
561+
562+ def get_warning_date(self, cr, uid, vals, context=None):
563+ """
564+ Función que obtiene la fecha para aviso si es que se agrega la fecha limite
565+ """
566+ if vals.get('date_limit'):
567+ # Obtenemos solo la fecha sin tiempo
568+ date = vals.get('date_limit').split(' ')
569+ # La convertimos a datetime
570+ date = datetime.datetime.strptime(date[0] ,'%Y-%m-%d')
571+ warning_date = date - datetime.timedelta(days = 1)
572+ # Actualizamos la fecha para aviso
573+ vals.update({'warning_date':warning_date})
574+ if context.get('write'):
575+ vals.update({'change_date': True})
576+ return vals
577+
578+ def create(self, cr, uid, vals, context=None):
579+ """
580+ Función que redefine el metodo create para obtener la fecha limite y las fechas para dar avisos
581+ """
582+ vals = self.get_warning_date(cr, uid, vals, context)
583+ if vals.get('activity_id'):
584+ # Obtenemos el registro del spint
585+ activity_row = self.pool.get('crm.activities').browse(cr, uid, vals.get('activity_id'))
586+ # Asignamos al proyecto que tiene asigando
587+ vals.update({'project_id':activity_row.project_id.id,'type':activity_row.project_id.type})
588+ vals.update({'change_date': False})
589+ # Creamos la nueva tarea
590+ task_id = super(crm_task, self).create(cr, uid, vals, context)
591+ return task_id
592+
593+ def write(self, cr, uid, ids, vals, context=None):
594+ """
595+ Función que redefine el metodo write para saber si se esta modificando la fecha limite
596+ """
597+ if context is None:
598+ context = {}
599+ # Actualizamos el context por si se actualiza la fech alimite se actualize tambien el campo change_date
600+ context.update({'write':True})
601+ # Obtenemos la fecha de aviso
602+ vals = self.get_warning_date(cr, uid, vals, context)
603+ # Realizamos el write de la funcion original
604+ res = super(crm_task, self).write(cr, uid, ids, vals, context)
605+ project_ids = []
606+ task_ids = []
607+ # Obtenemos los ids de los projectos
608+ for task_row in self.browse(cr, uid, ids):
609+ if task_row.state == 'draft' and task_row.change_date:
610+ task_ids.append(task_row.id)
611+ elif task_row.change_date:
612+ project_ids.append(task_row.project_id.id)
613+ # se actualiza el proyecto indicando que se cambio la fecha
614+ if project_ids:
615+ self.pool.get('crm.project').write(cr, uid, project_ids, {'change_date':True})
616+ if task_ids:
617+ self.write(cr, uid, task_ids, {'change_date':False})
618+ return res
619+
620+ def unlink(self, cr, uid, ids, context=None):
621+ """
622+ Función que redefine la función unlink para evitar que eliminen tarea que no esten en estado draft
623+ """
624+ activities_ids = []
625+ for task_row in self.browse(cr, uid, ids, context):
626+ if task_row.state != 'draft':
627+ raise osv.except_osv(_('Error !'),_('Solo puedes eliminar tareas en estao Borrador.'))
628+ activities_ids.append(task_row.activity_id.id)
629+ res = super(crm_task, self).unlink(cr, uid, ids, context)
630+ if activities_ids:
631+ self.pool.get('crm.activities').update_state_activities(cr, uid, activities_ids, context)
632+ return res
633+
634+
635+class crm_activities(osv.Model):
636+
637+ _name = "crm.activities"
638+
639+ _columns = {
640+ 'name': fields.char('Nombre', size=64, required=True,readonly=True, states={'draft': [('readonly', False)]}),
641+ 'task_ids': fields.one2many('crm.task', 'activity_id', 'Tareas', readonly=True, states={'open': [('readonly', False)]}, help="Tareas de la actividad"),
642+ 'project_id': fields.many2one('crm.project', 'Proyecto', required=True, readonly=True, states={'draft': [('readonly', False)]}, domain="[('state','in',('opportunity','implementation'))]", help="Proyecto al que pertenece la actividad"),
643+ 'user_id': fields.many2one('res.users','Responsable', required=True, readonly=True, states={'draft': [('readonly', False)]}, help = "Usuario que debe estar encargado de la actividad"),
644+ 'type': fields.selection([
645+ ('opportunity', 'Oportunidad'),
646+ ('implementation', 'Implementación')
647+ ], 'Tipo', help="Tipo de la actividad.", readonly=True),
648+ 'state': fields.selection([
649+ ('draft', 'Borrador'),
650+ ('open', 'Abierta'),
651+ ('done', 'Finalizado'),
652+ ('cancel', 'Cancelada')
653+ ], 'Estado', readonly=True, help="Estado en el que se encuentra la actividad.", select=True),
654+ 'date_limit': fields.date('Fecha limite', readonly=True, states={'draft': [('readonly', False)]}, help=" Fecha limite en que se debe cumplir la actividad"),
655+ }
656+
657+ _defaults = {
658+ 'state': 'draft',
659+ 'user_id': lambda obj, cr, uid, context: uid,
660+ }
661+
662+ def create(self, cr, uid, vals, context=None):
663+ """
664+ Función para actualizar el tipo de la actividad segun el tipo del proyecto seleccionado
665+ """
666+ if vals.get('project_id'):
667+ project_row = self.pool.get('crm.project').browse(cr, uid, vals.get('project_id'))
668+ vals.update({'type':project_row.type})
669+ return super(crm_activities, self).create(cr, uid, vals, context)
670+
671+ def action_confirm_activity(self, cr, uid, ids, context=None):
672+ """
673+ Función para cambiar el estado de la actividd a confirmada
674+ """
675+ self.write(cr, uid, ids, {'state':'open'})
676+ return True
677+
678+ def unlink(self, cr, uid, ids, context=None):
679+ """
680+ Se redefine el método unlink para no permitir eliminar actividades que no esten en estado draft
681+ """
682+ for activity_row in self.browse(cr, uid, ids):
683+ if activity_row.state != 'draft':
684+ raise osv.except_osv(_('Error !'),_('No se puede eliminar una actividad que no esta en estado draft.'))
685+ super(crm_activities, self).unlink(cr, uid, ids, context)
686+ return True
687+
688+ def update_state_activities(self, cr, uid, ids, context=None):
689+ """
690+ Funcion para cambiar el estado de la actividad en base a sus tareas
691+ """
692+ # Se recorren todas las actividades
693+ for activity_row in self.browse(cr, uid, ids, context):
694+ done = 0
695+ cancel = 0
696+ state =False
697+ # Se recorren todas las tareas de la actividad para revisar sus estados si tienen tareas
698+ if activity_row.task_ids:
699+ for task_row in activity_row.task_ids:
700+ # Si tiene alguntatarea en estado draft u open se marca la actividad como abierta
701+ if task_row.state == 'draft' or task_row.state == 'open':
702+ state = 'open'
703+ break
704+ # Si tiene tareas en estado done se aumenta el contador
705+ elif task_row.state == 'done':
706+ done += 1
707+ # Si tiene tareas en estado cancel se aumenta el contador
708+ elif task_row.state == 'cancel':
709+ cancel += 1
710+ # Si no se tiene estado aun comparamos los contadores de done y cancel
711+ if not state:
712+ # si existen cantidades en done y cancel o si el contador done es igual al total de actividades se pone en estado done
713+ if (done and cancel) or done == len(activity_row.task_ids):
714+ state = 'done'
715+ # Si el contador de cancel es igual al total de tareas el estado es cancel
716+ elif cancel == len(activity_row.task_ids):
717+ state = 'cancel'
718+ else:
719+ state='draft'
720+ self.write(cr, uid, [activity_row.id], {'state':state})
721+ return True
722+
723+
724
725=== added file 'crm_altegra/crm_project_view.xml'
726--- crm_altegra/crm_project_view.xml 1970-01-01 00:00:00 +0000
727+++ crm_altegra/crm_project_view.xml 2013-07-03 23:03:28 +0000
728@@ -0,0 +1,442 @@
729+<?xml version="1.0" encoding="utf-8"?>
730+<openerp>
731+ <data>
732+ <!-- crm_project_main_menu -->
733+ <menuitem icon="terp-stock" id="crm_project_main_menu" name="CRM" sequence="0" groups="crm_altegra.group_crm_user"
734+ web_icon="images/icon.png"
735+ web_icon_hover="images/icon.png"/>
736+
737+ <!-- crm_project_menu -->
738+ <menuitem id="crm_project_menu" name="CRM" parent="crm_project_main_menu" sequence="1"/>
739+
740+ <!-- crm_task_menu -->
741+ <menuitem id="crm_activities_menu" name="Actividades" parent="crm_project_main_menu" sequence="1"/>
742+
743+ <!-- crm_task_menu -->
744+ <menuitem id="crm_task_menu" name="Tareas" parent="crm_project_main_menu" sequence="2"/>
745+
746+ <record id="view_crm_project_filter" model="ir.ui.view">
747+ <field name="name">view.crm.project.filter</field>
748+ <field name="model">crm.project</field>
749+ <field name="type">search</field>
750+ <field name="arch" type="xml">
751+ <search string="Buscar">
752+ <group>
753+ <filter icon="terp-check" name="pending_project_false" string="Proyectos Actuales" domain="[('pending_project','=',False),('state','in',('opportunity','implementation','draft'))]" help="Proyectos que estan marcados como pendientes"/>
754+ <filter icon="terp-gtk-media-pause" name="pending_project_true" string="Proyectos Pendientes" domain="[('pending_project','=',True),('state','in',('opportunity','implementation','draft'))]" help="Proyectos que estan marcados como pendientes"/>
755+ </group>
756+ <field name="name" filter_domain="[('name','ilike',self)]" string="Proyecto"/>
757+ <field name="company" filter_domain="[('company','ilike',self)]"/>
758+ <field name="user_id">
759+ <filter domain="[('user_id','=',uid)]" help="Encargado" icon="terp-personal"/>
760+ </field>
761+ <field name="state"/>
762+ <field name="UEE"/>
763+ <newline/>
764+ <group expand="0" string="Group By..." groups="base.group_extended">
765+ <filter string="Responsable" icon="terp-personal" domain="[]" context="{'group_by':'user_id'}"/>
766+ <filter string="Cliente" icon="terp-personal" domain="[]" context="{'group_by':'company'}"/>
767+ <separator orientation="vertical"/>
768+ <filter string="State" icon="terp-stock_effects-object-colorize" domain="[]" context="{'group_by':'state'}"/>
769+ </group>
770+ </search>
771+ </field>
772+ </record>
773+
774+ <!-- view_crm_project_tree -->
775+ <record id="view_crm_project_tree" model="ir.ui.view">
776+ <field name="name">view.crm.project.tree</field>
777+ <field name="model">crm.project</field>
778+ <field name="type">tree</field>
779+ <field name="priority" eval="17"/>
780+ <field name="arch" type="xml">
781+ <tree string="Proyectos" colors="black: state == 'done';grey: state == 'cancel';blue: change_date == True;red: task_min_date &lt; current_date and state in ('implementation','opportunity');orange: task_warning_date &lt;= current_date and state in ('implementation','opportunity')">
782+ <field name="reference"/>
783+ <field name="name"/>
784+ <field name="company"/>
785+ <field name="user_id"/>
786+ <field name="estimated_amount" sum="Sum amount"/>
787+ <field name="state"/>
788+ <field name="task_min_date" invisible="1"/>
789+ <field name="task_warning_date" invisible="1"/>
790+ <field name="change_date" invisible="1"/>
791+ <field name="pending_project" invisible="1"/>
792+ <field name="UEE" invisible="1"/>
793+ </tree>
794+ </field>
795+ </record>
796+
797+ <!-- view_crm_project_form -->
798+ <record id="view_crm_project_form" model="ir.ui.view">
799+ <field name="name">view.crm.project.form</field>
800+ <field name="model">crm.project</field>
801+ <field name="type">form</field>
802+ <field name="priority" eval="17"/>
803+ <field name="arch" type="xml">
804+ <form string="Proyecto" >
805+ <group colspan="4" col = "8">
806+ <field name="name" colspan="6"/>
807+ <field name="reference" invisible="1"/>
808+ <field name="pending_project" colspan="2"/>
809+ <field name="user_id" colspan="2"/>
810+ <field name="UEE" colspan="4"/>
811+ <field name="date" colspan="2"/>
812+ <field name="estimated_amount" colspan="2"/>
813+ <field name="type" invisible="1"/>
814+ </group>
815+ <group string ="Cliente" colspan="4">
816+ <field name="customer_id" on_change="on_change_customer_id(customer_id)"/>
817+ <field name="company"/>
818+ <field name="contact_name"/>
819+ <field name="phone"/>
820+ <field name="mail"/>
821+ </group>
822+ <notebook colspan="4">
823+ <page string="Actividades">
824+ <field name="activity_ids" nolabel="1">
825+ <form string="Actividad" >
826+ <group colspan="4" col = "6">
827+ <field name="name" />
828+ <field name="date_limit"/>
829+ </group>
830+ <group string="Tareas" colspan="4">
831+ <field name="task_ids" nolabel="1"/>
832+ </group>
833+ <group>
834+ <field name="state" widget="statusbar"/>
835+ </group>
836+ <group>
837+ <button name="action_confirm_activity" type="object" states="draft" string="Aprobar" icon="gtk-go-forward" />
838+ </group>
839+ </form>
840+ </field>
841+ </page>
842+ <page string="Tareas Oportunidad">
843+ <group colspan="4">
844+ <field name="task_opportunity_ids" nolabel="1">
845+ <form string="Tarea" >
846+ <group colspan="4" col = "6">
847+ <field name="name" colspan="6"/>
848+ <field name="user_id"/>
849+ <field name="date_limit"/>
850+ <field name="change_date" invisible="1"/>
851+ <field name="activity_id" domain="[('project_id','=',parent.id),('state','=','open')]"/>
852+ </group>
853+ <group string ="Notas" colspan="4">
854+ <field name="note" nolabel="1"/>
855+ </group>
856+ <group>
857+ <field name="state" widget="statusbar"/>
858+ </group>
859+ <group>
860+ <button name="action_review" type="object" string="Revisado" icon="terp-stock_zoom" attrs="{'invisible':['|',('change_date','=',False),('state','in',('draft','cancel','done'))]}" groups="crm_altegra.group_crm_admin"/>
861+ <button name="acction_confirm" type="object" states="draft" string="Aprobar" icon="STOCK_NEW" />
862+ <button name="acction_done" type="object" states="open" string="Finalizada" icon="terp-camera_test" />
863+ <button name="acction_cancel" type="object" string="Cancelar" icon="gtk-cancel" attrs="{'invisible':['|',('state','in',('cancel','done'))]}" groups="crm_altegra.group_crm_admin"/>
864+ </group>
865+ </form>
866+ </field>
867+ </group>
868+ </page>
869+ <page string="Tareas implementacion">
870+ <group colspan="4">
871+ <field name="task_implementation_ids" nolabel="1">
872+ <form string="Tarea" >
873+ <group colspan="4" col = "6">
874+ <field name="name" colspan="6"/>
875+ <field name="user_id"/>
876+ <field name="date_limit"/>
877+ <field name="change_date" invisible="1"/>
878+ <field name="activity_id" domain="[('project_id','=',parent.id),('state','=','open')]"/>
879+ </group>
880+ <group string ="Notas" colspan="4">
881+ <field name="note" nolabel="1"/>
882+ </group>
883+ <group>
884+ <field name="state" widget="statusbar"/>
885+ </group>
886+ <group>
887+ <button name="action_review" type="object" string="Revisado" icon="terp-stock_zoom" attrs="{'invisible':['|',('change_date','=',False),('state','in',('draft','cancel','done'))]}" groups="crm_altegra.group_crm_admin"/>
888+ <button name="acction_confirm" type="object" states="draft" string="Aprobar" icon="STOCK_NEW" />
889+ <button name="acction_done" type="object" states="open" string="Finalizada" icon="terp-camera_test" />
890+ <button name="acction_cancel" type="object" string="Cancelar" icon="gtk-cancel" attrs="{'invisible':['|',('state','in',('cancel','done'))]}" groups="crm_altegra.group_crm_admin"/>
891+ </group>
892+ </form>
893+ </field>
894+ </group>
895+ </page>
896+ </notebook>
897+ <group col="16">
898+ <group>
899+ <field name="state" widget="statusbar"/>
900+ </group>
901+ <group col="10">
902+<!--
903+ <button name="search_task_expired" type="object" string="Correos" icon="gtk-go-forward" groups="crm_altegra.group_crm_admin"/>
904+-->
905+ <button name="acction_confirm" type="object" string="Oportunidad" icon="gtk-go-forward" attrs="{'invisible':['|',('state','!=','draft'),('type','=','implementation')]}"/>
906+ <button name="acction_implementation" type="object" string="Implementación" icon="gtk-go-forward" attrs="{'invisible':['|',('state','!=','draft'),('type','=','opportunity')]}"/>
907+ <button name="acction_implementation" states ="opportunity" type="object" string="Implementación" icon="gtk-go-forward" />
908+ <button name="acction_done" states ="implementation" type="object" string="Finalizar" icon="gtk-go-forward" />
909+ <button name="acction_cancel" type="object" string="Cancelar" icon="gtk-cancel" groups="crm_altegra.group_crm_admin" attrs="{'invisible':[('state','in',('cancel','done'))]}"/>
910+ </group>
911+ </group>
912+ </form>
913+ </field>
914+ </record>
915+
916+ <!-- crm_project_opportunity_action -->
917+ <record id="crm_project_opportunity_action" model="ir.actions.act_window">
918+ <field name="name">Proyectos Oportunidades</field>
919+ <field name="res_model">crm.project</field>
920+ <field name="view_type">form</field>
921+ <field name="view_mode">tree,form</field>
922+ <field name="context">{'default_type': 'opportunity',"search_default_pending_project_false":1}</field>
923+ <field name="domain">[('type','=','opportunity')]</field>
924+ <field name="view_id" ref="view_crm_project_tree"/>
925+ </record>
926+
927+ <record id="crm_project_implementation_action" model="ir.actions.act_window">
928+ <field name="name">Proyectos Implementación</field>
929+ <field name="res_model">crm.project</field>
930+ <field name="view_type">form</field>
931+ <field name="view_mode">tree,form</field>
932+ <field name="context">{'default_type': 'implementation',"search_default_pending_project_false":1}</field>
933+ <field name="domain">[('type','=','implementation')]</field>
934+ <field name="search_view_id" ref="view_crm_project_filter"/>
935+ <field name="view_id" ref="view_crm_project_tree"/>
936+ </record>
937+
938+ <!-- crm_project_menu_action -->
939+ <menuitem id="crm_project_opportunity_menu_action"
940+ parent="crm_project_menu"
941+ name="Oportunidades"
942+ action="crm_project_opportunity_action"
943+ sequence="1"/>
944+
945+ <menuitem id="crm_project_implementation_menu_action"
946+ parent="crm_project_menu"
947+ name="Implementación"
948+ action="crm_project_implementation_action"
949+ sequence="1"/>
950+
951+ <record id="view_crm_task_filter" model="ir.ui.view">
952+ <field name="name">view.crm.task.filter</field>
953+ <field name="model">crm.task</field>
954+ <field name="type">search</field>
955+ <field name="arch" type="xml">
956+ <search string="Buscar">
957+ <field name="name" filter_domain="[('name','ilike',self)]" string="Tarea"/>
958+ <field name="project_id"/>
959+ <field name="user_id">
960+ <filter domain="[('user_id','=',uid)]" help="Encargado" icon="terp-personal"/>
961+ </field>
962+ <field name="type"/>
963+ <field name="state"/>
964+ <newline/>
965+ <group expand="0" string="Group By..." groups="base.group_extended">
966+ <filter string="Proyecto" icon="gtk-open" domain="[]" context="{'group_by':'project_id'}"/>
967+ <filter string="Actividad" icon="gtk-find-and-replace" domain="[]" context="{'group_by':'activity_id'}"/>
968+ <filter string="Responsable" icon="terp-personal+" domain="[]" context="{'group_by':'user_id'}"/>
969+ <separator orientation="vertical"/>
970+ <filter string="State" icon="terp-stock_effects-object-colorize" domain="[]" context="{'group_by':'state'}"/>
971+ </group>
972+ </search>
973+ </field>
974+ </record>
975+
976+ <!-- view_crm_task_tree -->
977+ <record id="view_crm_task_tree" model="ir.ui.view">
978+ <field name="name">view.crm.task.tree</field>
979+ <field name="model">crm.task</field>
980+ <field name="type">tree</field>
981+ <field name="priority" eval="17"/>
982+ <field name="arch" type="xml">
983+ <tree string="Tareas" colors="black: state == 'done';grey: state == 'cancel';blue: change_date == True;red: date_limit &lt;= current_date and state == 'open';orange: warning_date &lt;= current_date and state == 'open';green: date_limit &gt; current_date and state == 'open'" >
984+ <field name="name"/>
985+ <field name="project_id"/>
986+ <field name="activity_id"/>
987+ <field name="user_id"/>
988+ <field name="date_limit"/>
989+ <field name="type" invisible="1"/>
990+ <field name="warning_date" invisible="1"/>
991+ <field name="change_date" invisible="1"/>
992+ <field name="state"/>
993+ <field name="type" invisible="1"/>
994+ <button name="acction_confirm" type="object" states="draft" string="Aprobar" icon="STOCK_NEW" />
995+ <button name="acction_done" type="object" states="open" string="Finalizada" icon="terp-camera_test" />
996+ </tree>
997+ </field>
998+ </record>
999+
1000+
1001+ <!-- view_crm_task_form -->
1002+ <record id="view_crm_task_form" model="ir.ui.view">
1003+ <field name="name">view.crm.task.form</field>
1004+ <field name="model">crm.task</field>
1005+ <field name="type">form</field>
1006+ <field name="priority" eval="17"/>
1007+ <field name="arch" type="xml">
1008+ <form string="Tarea" >
1009+ <group colspan="4" col = "6">
1010+ <field name="name" colspan="6"/>
1011+ <field name="user_id"/>
1012+ <field name="date_limit"/>
1013+ </group>
1014+ <notebook colspan="4">
1015+ <page string ="Notas">
1016+ <group colspan="4">
1017+ <field name="note" nolabel="1"/>
1018+ </group>
1019+ </page>
1020+ <page string="Otra información">
1021+ <field name="project_id" />
1022+ <field name="activity_id" domain="[('project_id','=',project_id),('state','=','open')]"/>
1023+ <field name="type" readonly="1"/>
1024+ <field name="change_date" readonly="1"/>
1025+ </page>
1026+ </notebook>
1027+ <group>
1028+ <field name="state" widget="statusbar"/>
1029+ </group>
1030+ <group>
1031+ <button name="action_review" type="object" string="Revisado" icon="terp-stock_zoom" attrs="{'invisible':['|',('change_date','=',False),('state','in',('draft','cancel','done'))]}" groups="crm_altegra.group_crm_admin"/>
1032+ <button name="acction_confirm" type="object" states="draft" string="Aprobar" icon="STOCK_NEW" />
1033+ <button name="acction_done" type="object" states="open" string="Finalizada" icon="terp-camera_test" />
1034+ <button name="acction_cancel" type="object" string="Cancelar" icon="gtk-cancel" attrs="{'invisible':['|',('state','in',('cancel','done'))]}" groups="crm_altegra.group_crm_admin"/>
1035+ </group>
1036+ </form>
1037+ </field>
1038+ </record>
1039+
1040+ <record id="crm_task_action" model="ir.actions.act_window">
1041+ <field name="name">Tareas</field>
1042+ <field name="res_model">crm.task</field>
1043+ <field name="view_type">form</field>
1044+ <field name="view_mode">tree,form</field>
1045+ <field name="search_view_id" ref="view_crm_task_filter"/>
1046+ <field name="view_id" ref="view_crm_task_tree"/>
1047+ </record>
1048+
1049+ <!-- crm_project_menu_action -->
1050+ <menuitem id="crm_task_menu_action"
1051+ parent="crm_task_menu"
1052+ name="Tareas"
1053+ action="crm_task_action"
1054+ groups="crm_altegra.group_crm_admin"
1055+ sequence="1"/>
1056+
1057+
1058+ <record id="view_crm_activities_filter" model="ir.ui.view">
1059+ <field name="name">view.crm.activities.filter</field>
1060+ <field name="model">crm.activities</field>
1061+ <field name="type">search</field>
1062+ <field name="arch" type="xml">
1063+ <search string="Buscar">
1064+ <field name="name" filter_domain="[('name','ilike',self)]" string="Actividad"/>
1065+ <field name="project_id"/>
1066+ <field name="user_id">
1067+ <filter domain="[('user_id','=',uid)]" help="Encargado" icon="terp-personal"/>
1068+ </field>
1069+ <field name="state"/>
1070+ <newline/>
1071+ <group expand="0" string="Group By..." groups="base.group_extended">
1072+ <filter string="Proyecto" icon="gtk-open" domain="[]" context="{'group_by':'project_id'}"/>
1073+ <filter string="Responsable" icon="terp-personal+" domain="[]" context="{'group_by':'user_id'}"/>
1074+ <separator orientation="vertical"/>
1075+ <filter string="State" icon="terp-stock_effects-object-colorize" domain="[]" context="{'group_by':'state'}"/>
1076+ </group>
1077+ </search>
1078+ </field>
1079+ </record>
1080+
1081+
1082+ <!-- view_crm_activities_tree -->
1083+ <record id="view_crm_activities_tree" model="ir.ui.view">
1084+ <field name="name">view.crm.activities.tree</field>
1085+ <field name="model">crm.activities</field>
1086+ <field name="type">tree</field>
1087+ <field name="priority" eval="17"/>
1088+ <field name="arch" type="xml">
1089+ <tree string="Actividades">
1090+ <field name="name"/>
1091+ <field name="project_id"/>
1092+ <field name="user_id"/>
1093+ <field name="type"/>
1094+ <field name="state"/>
1095+ <button name="action_confirm_activity" type="object" states="draft" string="Aprobar" icon="gtk-go-forward" />
1096+ </tree>
1097+ </field>
1098+ </record>
1099+
1100+ <!-- view_crm_activities_form -->
1101+ <record id="view_crm_activities_form" model="ir.ui.view">
1102+ <field name="name">view.crm.activities.form</field>
1103+ <field name="model">crm.activities</field>
1104+ <field name="type">form</field>
1105+ <field name="priority" eval="17"/>
1106+ <field name="arch" type="xml">
1107+ <form string="Actividad" >
1108+ <group colspan="4" >
1109+ <field name="name" />
1110+ <field name="project_id"/>
1111+ <field name="user_id"/>
1112+ <field name="date_limit"/>
1113+ </group>
1114+ <group string="Tareas" colspan="4">
1115+ <field name="task_ids" nolabel="1">
1116+ <form string="Tarea" >
1117+ <group colspan="4" col = "6">
1118+ <field name="name" colspan="6"/>
1119+ <field name="user_id"/>
1120+ <field name="date_limit"/>
1121+ <field name="change_date" invisible="1"/>
1122+ </group>
1123+ <group string ="Notas" colspan="4">
1124+ <field name="note" nolabel="1"/>
1125+ </group>
1126+ <group>
1127+ <field name="state" widget="statusbar"/>
1128+ </group>
1129+ <group>
1130+ <button name="action_review" type="object" string="Revisado" icon="terp-stock_zoom" attrs="{'invisible':['|',('change_date','=',False),('state','in',('draft','cancel','done'))]}" groups="crm_altegra.group_crm_admin"/>
1131+ <button name="acction_confirm" type="object" states="draft" string="Aprobar" icon="STOCK_NEW" />
1132+ <button name="acction_done" type="object" states="open" string="Finalizada" icon="terp-camera_test" />
1133+ <button name="acction_cancel" type="object" string="Cancelar" icon="gtk-cancel" attrs="{'invisible':['|',('state','in',('cancel','done'))]}" groups="crm_altegra.group_crm_admin"/>
1134+ </group>
1135+ </form>
1136+ </field>
1137+ </group>
1138+ <group>
1139+ <field name="state" widget="statusbar"/>
1140+ </group>
1141+ <group>
1142+ <button name="action_confirm_activity" type="object" states="draft" string="Aprobar" icon="gtk-go-forward" />
1143+<!--
1144+ <button name="update_state_activities" type="object" string="UPDATE" icon="gtk-go-forward" />
1145+-->
1146+ </group>
1147+ </form>
1148+ </field>
1149+ </record>
1150+
1151+ <record id="crm_activities_action" model="ir.actions.act_window">
1152+ <field name="name">Actividades</field>
1153+ <field name="res_model">crm.activities</field>
1154+ <field name="view_type">form</field>
1155+ <field name="view_mode">tree,form</field>
1156+ <field name="search_view_id" ref="view_crm_activities_filter"/>
1157+ <field name="view_id" ref="view_crm_activities_tree"/>
1158+ </record>
1159+
1160+ <!-- crm_project_menu_action -->
1161+ <menuitem id="crm_activities_menu_action"
1162+ parent="crm_activities_menu"
1163+ name="Actividades"
1164+ action="crm_activities_action"
1165+ groups="crm_altegra.group_crm_admin"
1166+ sequence="1"/>
1167+
1168+
1169+ </data>
1170+</openerp>
1171
1172=== added directory 'crm_altegra/images'
1173=== added file 'crm_altegra/images/icon.png'
1174Binary files crm_altegra/images/icon.png 1970-01-01 00:00:00 +0000 and crm_altegra/images/icon.png 2013-07-03 23:03:28 +0000 differ
1175=== added directory 'crm_altegra/security'
1176=== added file 'crm_altegra/security/groups.xml'
1177--- crm_altegra/security/groups.xml 1970-01-01 00:00:00 +0000
1178+++ crm_altegra/security/groups.xml 2013-07-03 23:03:28 +0000
1179@@ -0,0 +1,15 @@
1180+<?xml version="1.0"?>
1181+<openerp>
1182+ <data>
1183+ <record model="res.groups" id="group_crm_admin">
1184+ <field name="name">Administrador de CRM</field>
1185+ <field name="category_id" ref="base.module_category_usability"/>
1186+ </record>
1187+
1188+ <record model="res.groups" id="group_crm_user">
1189+ <field name="name">Usuario de CRM</field>
1190+ <field name="category_id" ref="base.module_category_usability"/>
1191+ </record>
1192+
1193+ </data>
1194+</openerp>
1195
1196=== added file 'crm_altegra/security/ir.model.access.csv'
1197--- crm_altegra/security/ir.model.access.csv 1970-01-01 00:00:00 +0000
1198+++ crm_altegra/security/ir.model.access.csv 2013-07-03 23:03:28 +0000
1199@@ -0,0 +1,4 @@
1200+id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
1201+access_crm_project,crm.project,model_crm_project,,1,1,1,1
1202+access_crm_task,crm.task,model_crm_task,,1,1,1,1
1203+access_crm_activities,crm.activities,model_crm_activities,,1,1,1,1
1204
1205=== added file 'crm_altegra/security/sequence.xml'
1206--- crm_altegra/security/sequence.xml 1970-01-01 00:00:00 +0000
1207+++ crm_altegra/security/sequence.xml 2013-07-03 23:03:28 +0000
1208@@ -0,0 +1,21 @@
1209+<?xml version="1.0"?>
1210+<openerp>
1211+ <data>
1212+ <record model="ir.sequence.type" id="sequence_crm_project">
1213+ <field name="code">crm.project</field>
1214+ <field name="name">Seguimiento</field>
1215+ </record>
1216+
1217+ <record model="ir.sequence" id="sequence_tracing">
1218+ <field name="code">crm.project</field>
1219+ <field name="name">Seguimiento</field>
1220+ <field name="number_next">1</field>
1221+ <field name="implementation">standard</field>
1222+ <field name="padding">4</field>
1223+ <field name="number_increment">1</field>
1224+ <field name="prefix">SEG</field>
1225+ <field name="active">True</field>
1226+ </record>
1227+
1228+ </data>
1229+</openerp>
1230
1231=== added directory 'crm_altegra/static'
1232=== added directory 'crm_altegra/static/src'
1233=== added directory 'crm_altegra/static/src/img'
1234=== added file 'crm_altegra/static/src/img/icon.png'
1235Binary files crm_altegra/static/src/img/icon.png 1970-01-01 00:00:00 +0000 and crm_altegra/static/src/img/icon.png 2013-07-03 23:03:28 +0000 differ
1236=== modified file 'dollars_altegra/__init__.py'
1237--- dollars_altegra/__init__.py 2013-03-28 22:40:30 +0000
1238+++ dollars_altegra/__init__.py 2013-07-03 23:03:28 +0000
1239@@ -34,3 +34,7 @@
1240 import account_invoice
1241 import account_change_currency
1242 import account_voucher
1243+import internal_order
1244+import purchase
1245+import wizard
1246+import stock
1247
1248=== modified file 'dollars_altegra/__openerp__.py'
1249--- dollars_altegra/__openerp__.py 2013-04-15 22:22:45 +0000
1250+++ dollars_altegra/__openerp__.py 2013-07-03 23:03:28 +0000
1251@@ -40,6 +40,8 @@
1252 "sale_view.xml",
1253 "account_invoice_view.xml",
1254 "account_voucher_view.xml",
1255+ "internal_order_view.xml",
1256+ "purchase_view.xml",
1257 ],
1258 'demo': [],
1259 'test': [],
1260
1261=== modified file 'dollars_altegra/account_invoice_view.xml'
1262--- dollars_altegra/account_invoice_view.xml 2013-05-07 06:18:54 +0000
1263+++ dollars_altegra/account_invoice_view.xml 2013-07-03 23:03:28 +0000
1264@@ -3,6 +3,43 @@
1265 <data>
1266
1267 <!-- account_invoice_form_inh -->
1268+ <record model="ir.ui.view" id="invoice_supplier_form_inh">
1269+ <field name="name">invoice.supplier.form.inh</field>
1270+ <field name="model">account.invoice</field>
1271+ <field name="inherit_id" ref="account.invoice_supplier_form" />
1272+ <field name="type">form</field>
1273+ <field name="arch" type="xml" >
1274+
1275+ <field name="currency_id" position="replace"/>
1276+ <field name="period_id" position="replace">
1277+ <field name="period_id" domain="[('state', '=', 'draft')]" groups="account.group_account_user" widget="selection" invisible="1"/>
1278+ </field>
1279+ <field name="reference_type" position="replace">
1280+ <field name="reference_type" nolabel="1" size="0" invisible="1"/>
1281+ </field>
1282+ <field name="fiscal_position" position="replace">
1283+ <field name="fiscal_position" groups="base.group_extended" widget="selection" invisible="1"/>
1284+ </field>
1285+ <button name="239" string="Change" position="replace">
1286+ <button name="239" type="action" icon="terp-stock_effects-object-colorize" string="Change" attrs="{'invisible':[('state','!=','draft')]}" colspan="2" invisible="1"/>
1287+ </button>
1288+ <field name="date_due" position="after">
1289+ <newline/>
1290+ <group string="Dolares" colspan="4" col="10">
1291+ <field name="currency_id" width="50" colspan="2"/>
1292+ <button name="239" type="action" icon="terp-stock_effects-object-colorize" string="Change" attrs="{'invisible':[('state','!=','draft')]}" colspan="2"/>
1293+ <field name="exchange_rate" attrs="{'readonly':[('state','!=','draft')]}" colspan="2"/>
1294+ <field name="system_rate" colspan="2"/>
1295+ <field name="dollar_invoice" readonly="1" colspan="2"/>
1296+ </group>
1297+ </field>
1298+ <button name="invoice_open" position="replace">
1299+ <button name="invoice_open" states="draft,proforma2" string="Approve" icon="terp-camera_test" attrs="{'readonly':[('exchange_rate','=', False),('dollar_invoice','=', True)]}"/>
1300+ </button>
1301+ </field>
1302+ </record>
1303+
1304+ <!-- account_invoice_form_inh -->
1305 <record model="ir.ui.view" id="account_invoice_form_inh">
1306 <field name="name">account.invoice.form.inh</field>
1307 <field name="model">account.invoice</field>
1308@@ -17,15 +54,20 @@
1309 <button name="%(account.action_account_change_currency)d" type="action" icon="terp-stock_effects-object-colorize" string="Change" attrs="{'invisible':[('state','!=','draft')]}" groups="account.group_account_user"/>
1310 </group>
1311 <group colspan="2" col="6">
1312- <field name="exchange_rate" attrs="{'readonly':[('state','!=','draft')]}"/>
1313- <field name="system_rate"/>
1314- <field name="dollar_invoice" readonly="1"/>
1315+ <field name="exchange_rate" attrs="{'readonly':[('state','!=','draft')]}" />
1316+ <field name="system_rate" />
1317+ <field name="dollar_invoice" readonly="1" />
1318 </group>
1319 </field>
1320+ <button string="Validate" position="replace">
1321+ <button name="invoice_open" string="Validate" icon="gtk-go-forward" attrs="{'invisible':['|',('state','not in',('draft')),'|',('origin','=','')], 'readonly':[('exchange_rate','=', '0'),('dollar_invoice','=', True)]}"/>
1322+ </button>
1323+<!--
1324 <button string="Validate" position="replace"/>
1325 <button string="IMPRIMIR REMISION" position="after">
1326 <button name="invoice_open" string="Validate" icon="gtk-go-forward" attrs="{'invisible':['|',('state','not in',('draft')),'|',('origin','=','')], 'readonly':[('exchange_rate','=', '0'),('dollar_invoice','=', True)]}"/>
1327 </button>
1328+-->
1329 <field name="origin" position="replace">
1330 <field name="origin" attrs="{'readonly':[('manual_invoice','!=',True)]}"/>
1331 <field name="manual_invoice" groups="base.group_system"/>
1332
1333=== modified file 'dollars_altegra/account_voucher_view.xml'
1334--- dollars_altegra/account_voucher_view.xml 2013-04-15 20:39:28 +0000
1335+++ dollars_altegra/account_voucher_view.xml 2013-07-03 23:03:28 +0000
1336@@ -24,6 +24,22 @@
1337 <button name="proforma_voucher" string="Validate" states="draft" icon="gtk-go-forward" invisible="context.get('line_type', False)"
1338 attrs="{'readonly':[('payment_rate_currency_id','=','2'),('validate_rate','=', False)]}"/>
1339 </button>
1340+ <xpath expr="//field[@name='line_cr_ids']/tree//field[@name='date_due']" position="after">
1341+ <field name="currency_id" string="Divisa"/>
1342+ </xpath>
1343+ </field>
1344+ </record>
1345+
1346+ <!-- view_vendor_payment_form_inherit -->
1347+ <record model="ir.ui.view" id="view_vendor_payment_form_inherit">
1348+ <field name="name">view.vendor.payment.form.inherit</field>
1349+ <field name="model">account.voucher</field>
1350+ <field name="inherit_id" ref="account_voucher.view_vendor_payment_form"/>
1351+ <field name="type">form</field>
1352+ <field name="arch" type="xml">
1353+ <xpath expr="//field[@name='line_dr_ids']/tree//field[@name='date_due']" position="after">
1354+ <field name="currency_id" string="Divisa"/>
1355+ </xpath>
1356 </field>
1357 </record>
1358
1359
1360=== added file 'dollars_altegra/internal_order.py'
1361--- dollars_altegra/internal_order.py 1970-01-01 00:00:00 +0000
1362+++ dollars_altegra/internal_order.py 2013-07-03 23:03:28 +0000
1363@@ -0,0 +1,44 @@
1364+#!/usr/bin/env python
1365+#-*- coding:utf-8 -*-
1366+
1367+#############################################################################
1368+# Module Writen to OpenERP, Open Source Management Solution
1369+# CopyLeft 2012 - http://www.grupoaltegra.com
1370+# You are free to share, copy, distribute, transmit, adapt and use for commercial purpose
1371+# More information about license: http://www.gnu.org/licenses/agpl.html
1372+# info Grupo Altegra (openerp@grupoaltegra.com)
1373+#
1374+#############################################################################
1375+#
1376+# Coded by: Carlos Blanco (carlos.blanco@grupoaltegra.com)
1377+# Coded by: Edgar Romero (edgar.romero@grupoaltegra.com)
1378+#
1379+#############################################################################
1380+#
1381+# This program is free software: you can redistribute it and/or modify
1382+# it under the terms of the GNU Affero General Public License as
1383+# published by the Free Software Foundation, either version 3 of the
1384+# License, or (at your option) any later version.
1385+#
1386+# This program is distributed in the hope that it will be useful,
1387+# but WITHOUT ANY WARRANTY; without even the implied warranty of
1388+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1389+# GNU Affero General Public License for more details.
1390+#
1391+# You should have received a copy of the GNU Affero General Public License
1392+# along with this program. If not, see <http://www.gnu.org/licenses/>.
1393+#
1394+#############################################################################
1395+
1396+from osv import osv, fields
1397+
1398+class internal_order(osv.Model):
1399+ _inherit = "internal.order"
1400+
1401+ _columns = {
1402+ 'currency_id': fields.many2one('res.currency', 'Moneda', help="Tipo de moneda en que se realizo la cotización"),
1403+ }
1404+
1405+ _defaults = {
1406+ 'currency_id': 34,
1407+ }
1408
1409=== added file 'dollars_altegra/internal_order_view.xml'
1410--- dollars_altegra/internal_order_view.xml 1970-01-01 00:00:00 +0000
1411+++ dollars_altegra/internal_order_view.xml 2013-07-03 23:03:28 +0000
1412@@ -0,0 +1,19 @@
1413+<?xml version="1.0" encoding="utf-8"?>
1414+<openerp>
1415+ <data>
1416+
1417+ <!-- sale_view_order_form_dollars_inh -->
1418+ <record model="ir.ui.view" id="view_internal_order_tree_inherit">
1419+ <field name="name">view.internal.order.tree.inherit</field>
1420+ <field name="model">internal.order</field>
1421+ <field name="inherit_id" ref="internal_order_altegra.view_internal_order_tree" />
1422+ <field name="type">tree</field>
1423+ <field name="arch" type="xml" >
1424+ <field name="part_number" position="replace">
1425+ <field name="currency_id" />
1426+ </field>
1427+ </field>
1428+ </record>
1429+
1430+ </data>
1431+</openerp>
1432
1433=== added file 'dollars_altegra/purchase.py'
1434--- dollars_altegra/purchase.py 1970-01-01 00:00:00 +0000
1435+++ dollars_altegra/purchase.py 2013-07-03 23:03:28 +0000
1436@@ -0,0 +1,52 @@
1437+#!/usr/bin/env python
1438+#-*- coding:utf-8 -*-
1439+
1440+#############################################################################
1441+# Module Writen to OpenERP, Open Source Management Solution
1442+# CopyLeft 2012 - http://www.grupoaltegra.com
1443+# You are free to share, copy, distribute, transmit, adapt and use for commercial purpose
1444+# More information about license: http://www.gnu.org/licenses/agpl.html
1445+# info Grupo Altegra (openerp@grupoaltegra.com)
1446+#
1447+#############################################################################
1448+#
1449+# Coded by: Carlos Blanco (carlos.blanco@grupoaltegra.com)
1450+#
1451+#############################################################################
1452+#
1453+# This program is free software: you can redistribute it and/or modify
1454+# it under the terms of the GNU Affero General Public License as
1455+# published by the Free Software Foundation, either version 3 of the
1456+# License, or (at your option) any later version.
1457+#
1458+# This program is distributed in the hope that it will be useful,
1459+# but WITHOUT ANY WARRANTY; without even the implied warranty of
1460+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1461+# GNU Affero General Public License for more details.
1462+#
1463+# You should have received a copy of the GNU Affero General Public License
1464+# along with this program. If not, see <http://www.gnu.org/licenses/>.
1465+#
1466+#############################################################################
1467+
1468+from osv import osv, fields
1469+
1470+class purchase_order(osv.Model):
1471+ _inherit = 'purchase.order'
1472+
1473+ _columns = {
1474+ 'dollar_purchase': fields.boolean('Compra en dólares', readonly=True, states={'draft': [('readonly', False)]},help = "Selecciona esta opción si la compra será en dólares"),
1475+ 'exchange_rate': fields.float('Tipo de cambio', readonly=True, states={'draft': [('readonly', False)]}, help = "Ingresa el tipo de cambio del dólar a pesos"),
1476+ }
1477+
1478+ _defaults = {
1479+ 'dollar_purchase': False,
1480+ }
1481+
1482+ def action_invoice_create(self, cr, uid, ids, context=None):
1483+ invoice_id = super(purchase_order, self).action_invoice_create(cr, uid, ids, context)
1484+ purchase_row = self.browse(cr, uid, ids, context)[0]
1485+ if purchase_row.dollar_purchase:
1486+ self.pool.get('account.invoice').write(cr, uid, [invoice_id], {'dollar_invoice': True, 'exchange_rate':purchase_row.exchange_rate, 'currency_id':2})
1487+ return invoice_id
1488+
1489
1490=== added file 'dollars_altegra/purchase_view.xml'
1491--- dollars_altegra/purchase_view.xml 1970-01-01 00:00:00 +0000
1492+++ dollars_altegra/purchase_view.xml 2013-07-03 23:03:28 +0000
1493@@ -0,0 +1,22 @@
1494+<?xml version="1.0" encoding="utf-8"?>
1495+<openerp>
1496+ <data>
1497+
1498+ <!-- sale_view_order_form_dollars_inh -->
1499+ <record model="ir.ui.view" id="purchase_order_form_inh">
1500+ <field name="name">purchase.order.form.inh</field>
1501+ <field name="model">purchase.order</field>
1502+ <field name="inherit_id" ref="purchase.purchase_order_form" />
1503+ <field name="type">form</field>
1504+ <field name="arch" type="xml" >
1505+ <field name="shipped" position="after">
1506+ <field name="dollar_purchase" />
1507+ </field>
1508+ <field name="origin" position="after">
1509+ <field name="exchange_rate" attrs="{'invisible': [('dollar_purchase','!=',True)], 'required': [('dollar_purchase','=',True)]}"/>
1510+ </field>
1511+ </field>
1512+ </record>
1513+
1514+ </data>
1515+</openerp>
1516
1517=== modified file 'dollars_altegra/sale.py'
1518--- dollars_altegra/sale.py 2013-03-28 22:40:30 +0000
1519+++ dollars_altegra/sale.py 2013-07-03 23:03:28 +0000
1520@@ -44,6 +44,16 @@
1521 _defaults = {
1522 'dollar_sale': False,
1523 }
1524+
1525+ def get_internal_order_vals(self, cr, uid, ids, line, context=None):
1526+ internal_order_line = super(sale_order, self).get_internal_order_vals(cr, uid, ids, line, context)
1527+ # Si es venta en dólares
1528+ if line.order_id.dollar_sale:
1529+ if line.order_id.exchange_rate <= 0:
1530+ raise osv.except_osv(_('¡Tu cotización es en dólares'),_('Ingresa un tipo de cambio mayor a cero'))
1531+ else:
1532+ internal_order_line.update({'currency_id':2})
1533+ return internal_order_line
1534
1535 def action_wait(self, cr, uid, ids, context=None):
1536 """
1537
1538=== added file 'dollars_altegra/stock.py'
1539--- dollars_altegra/stock.py 1970-01-01 00:00:00 +0000
1540+++ dollars_altegra/stock.py 2013-07-03 23:03:28 +0000
1541@@ -0,0 +1,47 @@
1542+#!/usr/bin/env python
1543+#-*- coding:utf-8 -*-
1544+
1545+#############################################################################
1546+# Module Writen to OpenERP, Open Source Management Solution
1547+# CopyLeft 2012 - http://www.grupoaltegra.com
1548+# You are free to share, copy, distribute, transmit, adapt and use for commercial purpose
1549+# More information about license: http://www.gnu.org/licenses/agpl.html
1550+# info Grupo Altegra (openerp@grupoaltegra.com)
1551+#
1552+#############################################################################
1553+#
1554+# Coded by: Carlos Blanco (carlos.blanco@grupoaltegra.com)
1555+#
1556+#############################################################################
1557+#
1558+# This program is free software: you can redistribute it and/or modify
1559+# it under the terms of the GNU Affero General Public License as
1560+# published by the Free Software Foundation, either version 3 of the
1561+# License, or (at your option) any later version.
1562+#
1563+# This program is distributed in the hope that it will be useful,
1564+# but WITHOUT ANY WARRANTY; without even the implied warranty of
1565+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1566+# GNU Affero General Public License for more details.
1567+#
1568+# You should have received a copy of the GNU Affero General Public License
1569+# along with this program. If not, see <http://www.gnu.org/licenses/>.
1570+#
1571+#############################################################################
1572+
1573+from osv import osv, fields
1574+
1575+class stock_picking(osv.Model):
1576+
1577+ _inherit = "stock.picking"
1578+
1579+ def _prepare_invoice(self, cr, uid, picking, partner, inv_type, journal_id, context=None):
1580+ """ Se redefine el método para sabes si la compra se cotizo en dolares """
1581+ invoice_vals = super(stock_picking, self)._prepare_invoice(cr, uid, picking, partner, inv_type, journal_id, context)
1582+ # Validamos si el picking tiene compra
1583+ if picking.purchase_id:
1584+ # Validamos si la compra fue cotizada en Dolares
1585+ if picking.purchase_id.dollar_purchase:
1586+ # Si fue cotizada en dolares actualizamos el diccionario para agregarle la moneda y ponerle el tipo de cambio de la compra
1587+ invoice_vals.update({'dollar_invoice': True, 'exchange_rate':picking.purchase_id.exchange_rate, 'currency_id':2})
1588+ return invoice_vals
1589
1590=== added directory 'dollars_altegra/wizard'
1591=== added file 'dollars_altegra/wizard/__init__.py'
1592--- dollars_altegra/wizard/__init__.py 1970-01-01 00:00:00 +0000
1593+++ dollars_altegra/wizard/__init__.py 2013-07-03 23:03:28 +0000
1594@@ -0,0 +1,32 @@
1595+#!/usr/bin/env python
1596+#-*- coding:utf-8 -*-
1597+
1598+#############################################################################
1599+# Module Writen to OpenERP, Open Source Management Solution
1600+# CopyLeft 2012 - http://www.grupoaltegra.com
1601+# You are free to share, copy, distribute, transmit, adapt and use for commercial purpose
1602+# More information about license: http://www.gnu.org/licenses/agpl.html
1603+# info Grupo Altegra (openerp@grupoaltegra.com)
1604+#
1605+#############################################################################
1606+#
1607+# Coded by: Carlos Blanco (carlos.blanco@grupoaltegra.com)
1608+#
1609+#############################################################################
1610+#
1611+# This program is free software: you can redistribute it and/or modify
1612+# it under the terms of the GNU Affero General Public License as
1613+# published by the Free Software Foundation, either version 3 of the
1614+# License, or (at your option) any later version.
1615+#
1616+# This program is distributed in the hope that it will be useful,
1617+# but WITHOUT ANY WARRANTY; without even the implied warranty of
1618+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1619+# GNU Affero General Public License for more details.
1620+#
1621+# You should have received a copy of the GNU Affero General Public License
1622+# along with this program. If not, see <http://www.gnu.org/licenses/>.
1623+#
1624+############################################################################
1625+
1626+import create_purchase
1627
1628=== added file 'dollars_altegra/wizard/create_purchase.py'
1629--- dollars_altegra/wizard/create_purchase.py 1970-01-01 00:00:00 +0000
1630+++ dollars_altegra/wizard/create_purchase.py 2013-07-03 23:03:28 +0000
1631@@ -0,0 +1,62 @@
1632+#!/usr/bin/env python
1633+#-*- coding:utf-8 -*-
1634+
1635+#############################################################################
1636+# Module Writen to OpenERP, Open Source Management Solution
1637+# CopyLeft 2012 - http://www.grupoaltegra.com
1638+# You are free to share, copy, distribute, transmit, adapt and use for commercial purpose
1639+# More information about license: http://www.gnu.org/licenses/agpl.html
1640+# info Grupo Altegra (openerp@grupoaltegra.com)
1641+#
1642+#############################################################################
1643+#
1644+# Coded by: Carlos Blanco (carlos.blanco@grupoaltegra.com)
1645+#
1646+#############################################################################
1647+#
1648+# This program is free software: you can redistribute it and/or modify
1649+# it under the terms of the GNU Affero General Public License as
1650+# published by the Free Software Foundation, either version 3 of the
1651+# License, or (at your option) any later version.
1652+#
1653+# This program is distributed in the hope that it will be useful,
1654+# but WITHOUT ANY WARRANTY; without even the implied warranty of
1655+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1656+# GNU Affero General Public License for more details.
1657+#
1658+# You should have received a copy of the GNU Affero General Public License
1659+# along with this program. If not, see <http://www.gnu.org/licenses/>.
1660+#
1661+#############################################################################
1662+
1663+from osv import osv ,fields
1664+from tools.translate import _
1665+
1666+class create_purchase(osv.TransientModel):
1667+ _inherit = 'create.purchase'
1668+
1669+ def get_io_by_supplier(self, cr, uid, ids, supplier_ids, internal_order_rows, context=None):
1670+ """ Método que crea un diccionario con las internal orders por proveedor """
1671+ vals = {}
1672+ # Clasificamos las lineas por proveedor
1673+ for supplier_id in supplier_ids:
1674+ aux = []
1675+ currency_id = False
1676+ for index in range(len(internal_order_rows)):
1677+ # Si es del proveedor se agrega a una lista auxiliar
1678+ if supplier_id == internal_order_rows[index].supplier_id.id:
1679+ if not currency_id:
1680+ currency_id = internal_order_rows[index].currency_id.id
1681+ elif currency_id != internal_order_rows[index].currency_id.id:
1682+ raise osv.except_osv(_('¡Error!'),_('No puedes seleccionar compras con diferentes monedas y el mismo proveedor'))
1683+ aux.append(internal_order_rows[index])
1684+ # Se agrega las lineas por proveedor
1685+ vals.update({supplier_id:aux})
1686+ return vals
1687+
1688+ def get_purchase_vals(self, cr, uid, ids, supplier_id, internal_row, context=None):
1689+ """ Método para obtener el diccionario para crear la compra """
1690+ purchase_vals = super(create_purchase, self).get_purchase_vals(cr, uid, ids, supplier_id, internal_row, context)
1691+ if internal_row.currency_id.id == 2:
1692+ purchase_vals.update({'dollar_purchase':True})
1693+ return purchase_vals
1694
1695=== modified file 'internal_order_altegra/purchase.py'
1696--- internal_order_altegra/purchase.py 2013-04-23 00:23:24 +0000
1697+++ internal_order_altegra/purchase.py 2013-07-03 23:03:28 +0000
1698@@ -120,14 +120,17 @@
1699 - Se redefine la función para agregar la fecha de entrega y la paquetería al picking de entrada
1700 proveniente de purchase_order.
1701 """
1702+ customer_id = False
1703 picking_id = super(purchase_order, self)._create_pickings(cr, uid, order, order_lines, picking_id=False, context=None)
1704 if picking_id:
1705 # Actualizamos fecha de llegada y paqueteria en orden de entrada
1706 self.pool.get('stock.picking').write(cr, uid, picking_id, {'date_arrival': order.date_arrival or False, 'package_id': order.package_id.id or False,'min_date':order.date_arrival})
1707 picking_row = self.pool.get('stock.picking').browse(cr,uid,picking_id)[0]
1708 for stock_move_row in picking_row.move_lines:
1709+ if stock_move_row.purchase_line_id.internal_order_id:
1710+ customer_id = stock_move_row.purchase_line_id.internal_order_id.customer_id and stock_move_row.purchase_line_id.internal_order_id.customer_id.id or False
1711 # Actualizamos fecha de llegada y cliente del movimiento
1712- self.pool.get('stock.move').write(cr, uid, [stock_move_row.id], {'date_arrival':order.date_arrival, 'customer_id': stock_move_row.purchase_line_id.internal_order_id.customer_id.id or False})
1713+ self.pool.get('stock.move').write(cr, uid, [stock_move_row.id], {'date_arrival':order.date_arrival, 'customer_id': customer_id})
1714 return picking_id
1715
1716 class purchase_order_line(osv.Model):
1717
1718=== modified file 'internal_order_altegra/sale.py'
1719--- internal_order_altegra/sale.py 2013-04-22 23:17:45 +0000
1720+++ internal_order_altegra/sale.py 2013-07-03 23:03:28 +0000
1721@@ -62,6 +62,26 @@
1722 'name': self.pool.get('ir.sequence').get(cr, uid, 'sale.order'),
1723 })
1724 return super(sale_order, self).copy(cr, uid, id, default, context=context)
1725+
1726+ def get_internal_order_vals(self, cr, uid, ids, line, context=None):
1727+ """ Método que genera el diccionario para crear las lineas internas """
1728+ internal_order_line = {
1729+ 'sale_id' : ids[0],
1730+ 'special_price' : line.special_price,
1731+ 'qty_order' : line.product_uom_qty,
1732+ 'qty_buy': line.product_uom_qty,
1733+ 'product_id' : line.product_id.id,
1734+ 'part_number' : line.product_id.default_code,
1735+ 'price_unit' : line.price_unit,
1736+ 'customer_id': line.order_id.partner_id.id,
1737+ 'user_id': line.order_id.user_id.id,
1738+ 'brand_id' : line.product_id.categ_id.id,
1739+ 'delivery_date' : line.order_id.delivery or False,
1740+ 'supplier_id' : line.supplier_id.id,
1741+ 'price_buy': line.supplier_price,
1742+ 'note': line.order_id.note,
1743+ }
1744+ return internal_order_line
1745
1746 def create_internal_lines(self, cr, uid, ids, context=None):
1747 """
1748@@ -70,7 +90,7 @@
1749 """
1750 # Sale order row
1751 sale_order_row = self.browse(cr, uid, ids, context=None)[0]
1752-
1753+ internal_order_ids = []
1754 # Verificamos que haya sido ingresada la fecha de entrega
1755 if sale_order_row.delivery:
1756 if sale_order_row:
1757@@ -87,40 +107,15 @@
1758 # Si todas las líneas son servicio se cambia el método de facturación
1759 if types[0][0] == 'service':
1760 self.pool.get('sale.order').write(cr, uid, ids, {'order_policy': 'manual'}, context=None)
1761-
1762- # Si es venta en dólares
1763- if sale_order_row.dollar_sale:
1764- if sale_order_row.exchange_rate <= 0:
1765- raise osv.except_osv(_('¡Tu cotización es en dólares'),_('Ingresa un tipo de cambio mayor a cero'))
1766- else:
1767- conversion_factor = float(round(sale_order_row.exchange_rate, 2))
1768- else:
1769- conversion_factor = 1
1770-
1771 # Recorremos líneas de sale_order
1772 for line in self.pool.get('sale.order.line').browse(cr, uid, sale_order_lines, context=None):
1773 # Se crean líneas de pedido interno únicamente de productos que no son servicios
1774 if line.product_id.type != 'service':
1775- # Creamos líneas de pedido interno
1776- internal_order_line = {
1777- 'sale_id' : ids[0],
1778- 'special_price' : line.special_price,
1779- 'qty_order' : line.product_uom_qty,
1780- 'qty_buy': line.product_uom_qty,
1781- 'product_id' : line.product_id.id,
1782- 'part_number' : line.product_id.default_code,
1783- 'price_unit' : line.price_unit * conversion_factor,
1784- 'customer_id': sale_order_row.partner_id.id,
1785- 'user_id': sale_order_row.user_id.id,
1786- 'brand_id' : line.product_id.categ_id.id,
1787- 'delivery_date' : sale_order_row.delivery or False,
1788- 'supplier_id' : line.supplier_id.id,
1789- 'price_buy': line.supplier_price * conversion_factor,
1790- 'note': sale_order_row.note,
1791- }
1792+ internal_order_line = self.get_internal_order_vals(cr, uid, ids, line, context)
1793 # Creamos línea
1794 internal_order_line_id = self.pool.get('internal.order').create(cr, uid, internal_order_line, context=None)
1795+ internal_order_ids.append(internal_order_line_id)
1796 else:
1797 raise osv.except_osv(_('¡Verifica los datos!'),_('Debes ingresar Tiempo de entrega'))
1798
1799- return True
1800+ return internal_order_ids
1801
1802=== modified file 'internal_order_altegra/wizard/create_purchase.py'
1803--- internal_order_altegra/wizard/create_purchase.py 2013-04-23 00:23:24 +0000
1804+++ internal_order_altegra/wizard/create_purchase.py 2013-07-03 23:03:28 +0000
1805@@ -35,6 +35,33 @@
1806 class create_purchase(osv.TransientModel):
1807 _name = 'create.purchase'
1808
1809+
1810+ def get_io_by_supplier(self, cr, uid, ids, supplier_ids, internal_order_rows, context=None):
1811+ """ Método que crea un diccionario con las internal orders por proveedor """
1812+ vals = {}
1813+ # Clasificamos las lineas por proveedor
1814+ for supplier_id in supplier_ids:
1815+ aux = []
1816+ for index in range(len(internal_order_rows)):
1817+ # Si es del proveedor se agrega a una lista auxiliar
1818+ if supplier_id == internal_order_rows[index].supplier_id.id:
1819+ aux.append(internal_order_rows[index])
1820+ # Se agrega las lineas por proveedor
1821+ vals.update({supplier_id:aux})
1822+ return vals
1823+
1824+ def get_purchase_vals(self, cr, uid, ids, supplier_id, internal_row, context=None):
1825+ """ Método para obtener el diccionario para crear la compra """
1826+ purchase_vals = {
1827+ 'partner_id':supplier_id,
1828+ 'partner_address_id': self.pool.get('res.partner').address_get(cr, uid, [supplier_id], ['default'])['default'],
1829+ 'pricelist_id': self.pool.get('res.partner').browse(cr, uid, supplier_id).property_product_pricelist_purchase.id,
1830+ 'company_id': internal_row.sale_id.company_id.id,
1831+ 'warehouse_id':internal_row.sale_id.shop_id.warehouse_id.id,
1832+ 'location_id':internal_row.sale_id.shop_id.warehouse_id.lot_stock_id.id,
1833+ }
1834+ return purchase_vals
1835+
1836 def action_create_purchase(self,cr,uid,ids,context=None):
1837 """ Crea las ordenes de compra de los internal orders seleccionadas """
1838 # Objetos
1839@@ -57,28 +84,14 @@
1840 if not internal_order_row.supplier_id.id in supplier_ids:
1841 supplier_ids.append(internal_order_row.supplier_id.id)
1842 # Clasificamos las lineas por proveedor
1843- for supplier_id in supplier_ids:
1844- aux = []
1845- for index in range(len(internal_order_rows)):
1846- # Si es del proveedor se agrega a una lista auxiliar
1847- if supplier_id == internal_order_rows[index].supplier_id.id:
1848- aux.append(internal_order_rows[index])
1849- # Se agrega las lineas por proveedor
1850- vals.update({supplier_id:aux})
1851+ vals = self.get_io_by_supplier(cr, uid, ids, supplier_ids, internal_order_rows, context)
1852 # Creamos las compras
1853 for supplier_id in supplier_ids:
1854 # Obtenemos el primer registro del proveedor
1855 internal_row = vals[supplier_id][0]
1856 origin = internal_row.sale_id.name
1857 # Obtenemos los valores para crear la compra
1858- purchase_vals = {
1859- 'partner_id':supplier_id,
1860- 'partner_address_id': self.pool.get('res.partner').address_get(cr, uid, [supplier_id], ['default'])['default'],
1861- 'pricelist_id': self.pool.get('res.partner').browse(cr, uid, supplier_id).property_product_pricelist_purchase.id,
1862- 'company_id': internal_row.sale_id.company_id.id,
1863- 'warehouse_id':internal_row.sale_id.shop_id.warehouse_id.id,
1864- 'location_id':internal_row.sale_id.shop_id.warehouse_id.lot_stock_id.id,
1865- }
1866+ purchase_vals = self.get_purchase_vals(cr, uid, ids, supplier_id, internal_row, context)
1867 # Creamos la compra
1868 fiscal_position_id = False
1869 purchase_id = purchase_obj.create(cr,uid,purchase_vals)
1870
1871=== modified file 'product_altegra/product.py'
1872--- product_altegra/product.py 2013-04-23 17:36:34 +0000
1873+++ product_altegra/product.py 2013-07-03 23:03:28 +0000
1874@@ -76,7 +76,7 @@
1875 return res
1876
1877 _columns = {
1878- 'model' : fields.char('Modelo', size=20),
1879+ 'model' : fields.char('Modelo', size=64),
1880 'government_description': fields.text('Descripción Gobierno', help="Descripción utilizada en cotizaciones y facturas de la UEE Gobierno", translate=True),
1881 'qty_zero_stock': fields.function(_get_qty_stock, type='float', string='Costo Cero', store=False, multi='all', digits_compute=dp.get_precision('Product UoM')),
1882 }

Subscribers

People subscribed via source and target branches