', [_('Object Name'), _('Field name'), _('Suggestion')])
if not self.error:
for key in dict_obj.keys():
data_list = []
@@ -196,17 +195,18 @@ Test checks for fields, views, security rules, dependancy level
for i in data_list:
count = count + 1
final_dict[key + str(count)] = i
- res += '
', [_('Object Name'), _('Line number'), _('Suggestion')])
if not self.error:
res = str_html + self.format_html_table(header, data_list=dict_obj) + '
'
+ res = res.replace('''
-
-
-
- '''
+ self.result_details += '''%s'''%(self.get_style())
for file_py in list_files:
if file_py.split('.')[-1] == 'py' and not file_py.endswith('__init__.py') and not file_py.endswith('__terp__.py'):
if not flag:
@@ -84,7 +80,19 @@ class quality_test(base_module_quality.abstract_quality_check):
score += 0
#self.result += file + ": "+_("Unable to parse the result. Check the details.")+"\n"
dict_py[file_py] = [file_py, _("Unable to parse the result. Check the details.")]
- self.result_details += res.replace('''
O(1) means that the number of SQL requests to read the object does not depand on the number of objects we are reading. This feature is hardly wished.\n")
for obj, ids in obj_ids.items():
+ code_base_complexity = 0
+ code_half_complexity = 0
+ code_size_complexity = 0
obj_counter += 1
ids = ids[:100]
size = len(ids)
@@ -71,34 +74,38 @@ This test checks the speed of the module. Note that at least 5 demo data is need
if size:
speed_list = []
#we perform the operation twice, and count the number of queries in the second run. This allows to avoid the cache effect. (like translated terms that asks for more queries)
- pool.get(obj).read(cr, uid, [ids[0]])
- cnt = cr.count
- pool.get(obj).read(cr, uid, [ids[0]])
- code_base_complexity = cr.count - cnt
+ try:
+ pool.get(obj).read(cr, uid, [ids[0]])
+ cnt = cr.count
+ pool.get(obj).read(cr, uid, [ids[0]])
+ code_base_complexity = cr.count - cnt
- pool.get(obj).read(cr, uid, ids[:size/2])
- cnt = cr.count
- pool.get(obj).read(cr, uid, ids[:size/2])
- code_half_complexity = cr.count - cnt
+ pool.get(obj).read(cr, uid, ids[:size/2])
+ cnt = cr.count
+ pool.get(obj).read(cr, uid, ids[:size/2])
+ code_half_complexity = cr.count - cnt
- pool.get(obj).read(cr, uid, ids)
- cnt = cr.count
- pool.get(obj).read(cr, uid, ids)
- code_size_complexity = cr.count - cnt
-
- if size < 5:
- speed_list = [obj, size, code_base_complexity, code_half_complexity, code_size_complexity, _("Warning! Not enough demo data")]
- list2 = [obj, _("No enough data")]
+ pool.get(obj).read(cr, uid, ids)
+ cnt = cr.count
+ pool.get(obj).read(cr, uid, ids)
+ code_size_complexity = cr.count - cnt
+ except Exception, e:
+ list2 = [obj, _("Error in Read method")]
+ speed_list = [obj, size, code_base_complexity, code_half_complexity, code_size_complexity, _("Error in Read method:" + str(e))]
else:
- if code_size_complexity <= (code_base_complexity + size):
- complexity = _("O(1)")
- score += 1
- list2 = [obj, _("Efficient")]
+ if size < 5:
+ speed_list = [obj, size, code_base_complexity, code_half_complexity, code_size_complexity, _("Warning! Not enough demo data")]
+ list2 = [obj, _("No enough data")]
else:
- complexity = _("O(n) or worst")
- list2 = [obj, _("Not Efficient")]
+ if code_size_complexity <= (code_base_complexity + size):
+ complexity = _("O(1)")
+ score += 1
+ list2 = [obj, _("Efficient")]
+ else:
+ complexity = _("O(n) or worst")
+ list2 = [obj, _("Not Efficient")]
- speed_list = [obj, size, code_base_complexity, code_half_complexity, code_size_complexity, complexity]
+ speed_list = [obj, size, code_base_complexity, code_half_complexity, code_size_complexity, complexity]
else:
speed_list = [obj, size, "", "", "", _("Warning! Object has no demo data")]
list2 = [obj, _("No data")]
@@ -118,10 +125,11 @@ This test checks the speed of the module. Note that at least 5 demo data is need
return ""
def get_result_details(self, dict_speed):
- str_html = '''
', [_('Object Name'), _('N (Number of Records)'), _('1'), _('N/2'), _('N'), _('Reading Complexity')])
if not self.error:
res = str_html + self.format_html_table(header, data_list=dict_speed) + '
'
+ res = res.replace('''
'''
- header = ('
%s
%s
', [_('File Name'), _('Feedback about structure of module')])
+ str_html = '''%s
'''%(self.get_style())
+ header = ('
%s
%s
', [_('File Name'), _('Feedback about structure of module')])
if not self.error:
res = str_html + self.format_html_table(header, data_list=dict_struct) + '
'
+ res = res.replace('''
'''
- header = ('
%s
%s
', [_('Tag Name'), _('Feed back About terp file of Module')])
+ str_html = '''%s
'''%(self.get_style())
+ header = ('
%s
%s
', [_('Tag Name'), _('Feed back About terp file of Module')])
if not self.error:
res = str_html + self.format_html_table(header, data_list=dict_terp) + '
'
+ res = res.replace('''
'''
- header = ('
%s
%s
', [_('Object Name'), _('Feed back About Workflow of Module')])
+ str_html = '''%s
'''%(self.get_style())
+ header = ('
%s
%s
', [_('Object Name'), _('Feed back About Workflow of Module')])
if not self.error:
res = str_html + self.format_html_table(header, data_list=dict_wf) + '
'
+ res = res.replace('''
Check cases rules
- 1
+ 4hours-1
diff --git a/addons/document/document.py b/addons/document/document.py
index 21aa59661a7..460c52a9698 100644
--- a/addons/document/document.py
+++ b/addons/document/document.py
@@ -125,16 +125,7 @@ class node_class(object):
def get_translation(self,value,lang):
result = value
- pool = pooler.get_pool(self.cr.dbname)
- translation_ids = pool.get('ir.translation').search(self.cr, self.uid, [('value','=',value),('lang','=',lang),('type','=','model')])
- if len(translation_ids):
- tran_id = translation_ids[0]
- translation = pool.get('ir.translation').read(self.cr, self.uid, tran_id, ['res_id','name'])
- res_model,field_name = tuple(translation['name'].split(','))
- res_id = translation['res_id']
- res = pool.get(res_model).read(self.cr, self.uid, res_id, [field_name])
- if res:
- result = res[field_name]
+ #TODO : to get translation term
return result
def directory_list_for_child(self,nodename,parent=False):
@@ -346,12 +337,9 @@ class document_directory(osv.osv):
object: the object.directory or object.directory.content
object2: the other object linked (if object.directory.content)
"""
- def get_object(self, cr, uid, uri, context={}):
- lang = context.get('lang',False)
- if not lang:
- user = self.pool.get('res.users').browse(cr, uid, uid)
- lang = user.context_lang
- context['lang'] = lang
+ def get_object(self, cr, uid, uri, context={}):
+ #TODO : set user's context_lang in context
+ context.update({'lang':False})
if not uri:
return node_class(cr, uid, '', False, context=context, type='database')
turi = tuple(uri)
@@ -667,6 +655,7 @@ class document_file(osv.osv):
vals['res_id']=context.get('default_res_id',False)
if not vals.get('res_model', False) and context.get('default_res_model',False):
vals['res_model']=context.get('default_res_model',False)
+
if vals.get('res_id', False) and vals.get('res_model',False):
obj_model=self.pool.get(vals['res_model'])
result = obj_model.read(cr, uid, [vals['res_id']], context=context)
@@ -705,7 +694,7 @@ class document_file(osv.osv):
try:
res = content_index(base64.decodestring(datas), vals['datas_fname'], vals.get('content_type', None))
super(document_file,self).write(cr, uid, [result], {
- 'index_content': res,
+ 'index_content' : res,
})
cr.commit()
except:
diff --git a/addons/hr_holidays/hr.py b/addons/hr_holidays/hr.py
index 4081f9863e2..733f90f48cd 100644
--- a/addons/hr_holidays/hr.py
+++ b/addons/hr_holidays/hr.py
@@ -207,8 +207,11 @@ class hr_holidays(osv.osv):
'state':'validate',
}
ids2 = self.pool.get('hr.employee').search(cr, uid, [('user_id','=', uid)])
+
if ids2:
vals['manager_id'] = ids2[0]
+ else:
+ raise osv.except_osv(_('Warning !'),_('Either there is no Employee defined, or no User attached with it.'))
self.write(cr, uid, ids, vals)
return True
diff --git a/addons/hr_timesheet_invoice/hr_timesheet_invoice.py b/addons/hr_timesheet_invoice/hr_timesheet_invoice.py
index 6f29c056d34..0c16fb4ffd4 100644
--- a/addons/hr_timesheet_invoice/hr_timesheet_invoice.py
+++ b/addons/hr_timesheet_invoice/hr_timesheet_invoice.py
@@ -44,7 +44,7 @@ class account_analytic_account(osv.osv):
res = {}
for account in self.browse(cr, uid, ids):
invoiced = {}
- cr.execute('select distinct l.invoice_id from hr_analytic_timesheet h left join account_analytic_line l on (h.line_id=l.id) where account_id=1', (account.id,))
+ cr.execute('select distinct(l.invoice_id) from hr_analytic_timesheet h left join account_analytic_line l on (h.line_id=l.id) where account_id=%s', (account.id,))
invoice_ids = filter(None, map(lambda x: x[0], cr.fetchall()))
for invoice in self.pool.get('account.invoice').browse(cr, uid, invoice_ids, context):
res.setdefault(account.id, 0.0)
diff --git a/addons/hr_timesheet_sheet/hr_timesheet_sheet.py b/addons/hr_timesheet_sheet/hr_timesheet_sheet.py
index 3f8ac28dc8f..e700e404c2f 100644
--- a/addons/hr_timesheet_sheet/hr_timesheet_sheet.py
+++ b/addons/hr_timesheet_sheet/hr_timesheet_sheet.py
@@ -587,7 +587,7 @@ class hr_timesheet_sheet_sheet_day(osv.osv):
sheet_id,
total_timesheet,
total_attendance,
- round(cast((total_attendance - total_timesheet) as Numeric),2) AS total_difference
+ cast(round(cast(total_attendance - total_timesheet as Numeric),2) as Double Precision) AS total_difference
FROM
((
SELECT
diff --git a/addons/mrp/report/workcenter_load.py b/addons/mrp/report/workcenter_load.py
index 2bb1572d170..46d0d34628a 100644
--- a/addons/mrp/report/workcenter_load.py
+++ b/addons/mrp/report/workcenter_load.py
@@ -35,7 +35,7 @@ theme.use_color = 1
random.seed(0)
#
-# Pinky: Bad code, seems buggy, TO CHECK !
+# TODO: Bad code, seems buggy, TO CHECK !
#
class external_pdf(render):
@@ -101,7 +101,7 @@ class report_custom(report_int):
colors = choice_colors(len(ids))
ids_str = ','.join(map(str, ids))
cr.execute(
- "SELECT MAX(date_planned) AS stop "\
+ "SELECT MAX(mrp_production.date_planned) AS stop,MIN(mrp_production.date_planned) AS start "\
"FROM mrp_workcenter, mrp_production, mrp_production_workcenter_line "\
"WHERE mrp_production_workcenter_line.production_id=mrp_production.id "\
"AND mrp_production_workcenter_line.workcenter_id=mrp_workcenter.id "\
@@ -109,8 +109,10 @@ class report_custom(report_int):
"AND mrp_workcenter.id IN (%s)" % ids_str)
res = cr.dictfetchone()
if not res['stop']:
- res['stop'] = time.strftime('%Y-%m-%d')
- dates = self._compute_dates(datas['form']['time_unit'], time.strftime('%Y-%m-%d'), res['stop'][:10])
+ res['stop'] = time.strftime('%Y-%m-%d %H:%M:%S')
+ if not res['start']:
+ res['start'] = time.strftime('%Y-%m-%d %H:%M:%S')
+ dates = self._compute_dates(datas['form']['time_unit'], res['start'][:10], res['stop'][:10])
dates_list = dates.keys()
dates_list.sort()
x_index = []
@@ -174,8 +176,8 @@ class report_custom(report_int):
workcenter_num += 1
#plot = bar_plot.T(label=workcenter['name'], data=data, hcol=1, fill_style=fill_style.white, cluster=(color_index,len(ids)))
- if (len(data[0]) <= 1):
- ar = self._empty_graph(data[0][0])
+ if (not data) or (len(data[0]) <= 1):
+ ar = self._empty_graph(time.strftime('%Y-%m-%d'))
ar.draw(can)
# close canvas so that the file is written to "disk"
can.close()
diff --git a/addons/mrp_repair/mrp_repair.py b/addons/mrp_repair/mrp_repair.py
index c5cefd61267..a34f6c844b6 100644
--- a/addons/mrp_repair/mrp_repair.py
+++ b/addons/mrp_repair/mrp_repair.py
@@ -300,7 +300,7 @@ class mrp_repair(osv.osv):
'invoice_id': inv_id,
'name': name,
'origin':repair.name,
- 'account_id': a,
+ 'account_id': operation.product_id and operation.product_id.property_account_income and operation.product_id.property_account_income.id,
'quantity' : operation.product_uom_qty,
'invoice_line_tax_id': [(6,0,[x.id for x in operation.tax_id])],
'uos_id' : operation.product_uom.id,
diff --git a/addons/purchase/purchase_view.xml b/addons/purchase/purchase_view.xml
index 51434162854..f41e6e05cd2 100644
--- a/addons/purchase/purchase_view.xml
+++ b/addons/purchase/purchase_view.xml
@@ -51,7 +51,18 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
@@ -71,7 +82,7 @@
-
+
@@ -197,7 +208,7 @@
form
@@ -226,9 +241,11 @@
purchase.order.linetree
-
+
+
+
-
+
diff --git a/addons/purchase/wizard/wizard_group.py b/addons/purchase/wizard/wizard_group.py
index 597f1bdc5f4..b6ec15fe4c9 100644
--- a/addons/purchase/wizard/wizard_group.py
+++ b/addons/purchase/wizard/wizard_group.py
@@ -102,9 +102,9 @@ def _merge_orders(self, cr, uid, data, context):
else:
#order_infos['name'] += ', %s' % porder.name
if porder.notes:
- order_infos['notes'] += ('\n%s' % (porder.notes,))
+ order_infos['notes'] = (order_infos['notes'] or '') + ('\n%s' % (porder.notes,))
if porder.origin:
- order_infos['origin'] = order_infos['origin'] + ' ' + porder.origin
+ order_infos['origin'] = (order_infos['origin'] or '') + ' ' + porder.origin
for order_line in porder.order_line:
line_key = make_key(order_line, ('name', 'date_planned', 'taxes_id', 'price_unit', 'notes', 'product_id', 'move_dest_id', 'account_analytic_id'))
@@ -161,7 +161,7 @@ class merge_orders(wizard.interface):
states = {
'init': {
'actions': [],
- 'result': {'type': 'form', 'arch' : merge_form, 'fields' : merge_fields, 'state' : [('end', 'Cancel'), ('merge', 'Merge orders') ]}
+ 'result': {'type': 'form', 'arch': merge_form, 'fields' : merge_fields, 'state' : [('end', 'Cancel'), ('merge', 'Merge orders') ]}
},
'merge': {
'actions': [],
diff --git a/addons/purchase_manual/__init__.py b/addons/purchase_manual/__init__.py
new file mode 100644
index 00000000000..c15d258564d
--- /dev/null
+++ b/addons/purchase_manual/__init__.py
@@ -0,0 +1,25 @@
+# -*- encoding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-2009 Tiny SPRL (). All Rights Reserved
+# $Id$
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+##############################################################################
+
+import purchase_manual
+import wizard
+
diff --git a/addons/purchase_manual/__terp__.py b/addons/purchase_manual/__terp__.py
new file mode 100644
index 00000000000..885ac4d9d98
--- /dev/null
+++ b/addons/purchase_manual/__terp__.py
@@ -0,0 +1,42 @@
+# -*- encoding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-2009 Tiny SPRL (). All Rights Reserved
+# $Id$
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+##############################################################################
+
+
+{
+ 'name': 'Purchase Management - Manual Control of Invoice',
+ 'version': '1.1',
+ 'category': 'Generic Modules/Sales & Purchases',
+ 'description': """Module for purchase management, manual control of invoice""",
+ 'author': 'Tiny',
+ 'website': 'http://www.openerp.com',
+ 'depends': ['purchase'],
+ 'init_xml': [],
+ 'update_xml': [
+ 'purchase_manual_view.xml',
+ 'purchase_manual_wizard.xml',
+ ],
+ 'demo_xml': [],
+ 'installable': True,
+ 'active': False,
+# 'certificate': False,
+}
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/purchase_manual/purchase_manual.py b/addons/purchase_manual/purchase_manual.py
new file mode 100644
index 00000000000..e5d32ca49cc
--- /dev/null
+++ b/addons/purchase_manual/purchase_manual.py
@@ -0,0 +1,78 @@
+# -*- encoding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-2009 Tiny SPRL (). All Rights Reserved
+# $Id$
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+##############################################################################
+
+from osv import fields
+from osv import osv
+import netsvc
+
+class purchase_order_line(osv.osv):
+ _inherit='purchase.order.line'
+ _columns = {
+ 'state': fields.selection([('draft', 'Draft'), ('confirmed', 'Confirmed'), ('done', 'Done'), ('cancel', 'Cancelled')], 'Status', required=True, readonly=True),
+ 'invoice_lines': fields.many2many('account.invoice.line', 'purchase_order_line_invoice_rel', 'order_line_id', 'invoice_id', 'Invoice Lines', readonly=True),
+ 'invoiced': fields.boolean('Invoiced', readonly=True),
+ 'partner_id': fields.related('order_id','partner_id',string='Partner',readonly=True,type="many2one", relation="res.partner"),
+ 'date_order': fields.related('order_id','date_order',string='Order Date',readonly=True,type="date")
+ }
+ _defaults = {
+ 'state': lambda *args: 'draft',
+ 'invoiced': lambda *a: 0,
+
+ }
+ def copy_data(self, cr, uid, id, default=None, context={}):
+ print 'copy called'
+ if not default:
+ default = {}
+ default.update({
+ 'state':'draft',
+ 'invoiced':0,
+ 'invoice_lines':[],
+ })
+ return super(purchase_order_line, self).copy_data(cr, uid, id, default, context)
+
+ def action_confirm(self, cr, uid, ids, context={}):
+ self.write(cr, uid, ids, {'state': 'confirmed'}, context)
+ return True
+purchase_order_line()
+
+class purchase_order(osv.osv):
+ _inherit='purchase.order'
+ def action_invoice_create(self, cr, uid, ids, context={}):
+ print 'Invoice Create'
+ res = super(purchase_order, self).action_invoice_create(cr, uid, ids, context)
+ for po in self.browse(cr, uid, ids, context):
+ todo = []
+ for line in po.order_line:
+ todo.append(line.id)
+ self.pool.get('purchase.order.line').write(cr, uid, todo, {'invoiced':True}, context)
+ return res
+
+ def wkf_confirm_order(self, cr, uid, ids, context={}):
+ res = super(purchase_order, self).wkf_confirm_order(cr, uid, ids, context)
+ todo = []
+ for po in self.browse(cr, uid, ids, context):
+ for line in po.order_line:
+ if line.state=='draft':
+ todo.append(line.id)
+ self.pool.get('purchase.order.line').action_confirm(cr, uid, todo, context)
+ return res
+purchase_order()
diff --git a/addons/purchase_manual/purchase_manual_view.xml b/addons/purchase_manual/purchase_manual_view.xml
new file mode 100644
index 00000000000..de424bb17f6
--- /dev/null
+++ b/addons/purchase_manual/purchase_manual_view.xml
@@ -0,0 +1,105 @@
+
+
+
+
+ #
+ # Define PO Line Views
+ #
+
+
+ purchase.order.form
+ purchase.order
+ form
+
+
+
+
+
+
+
+
+
+
+ purchase.order.line.form
+ purchase.order.line
+ form
+
+ 17
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ purchase.order.line.tree
+ purchase.order.line
+ tree
+
+
+
+
+
+
+
+
+
+ #
+ # Inherit PO view to get buttons
+ #
+
+
+ Purchase Order Lines
+ ir.actions.act_window
+ purchase.order.line
+ tree,form
+
+
+
+ tree
+
+
+
+
+
+ form
+
+
+
+
+
+
+ Uninvoiced Purchase Order Lines
+ ir.actions.act_window
+ purchase.order.line
+ [('state','in',('confirmed','done')), ('invoiced','=',False)]
+ form
+ tree,form
+
+
+
+ tree
+
+
+
+
+
+ form
+
+
+
+
+
+
+
diff --git a/addons/purchase_manual/purchase_manual_wizard.xml b/addons/purchase_manual/purchase_manual_wizard.xml
new file mode 100644
index 00000000000..62771cf9fbb
--- /dev/null
+++ b/addons/purchase_manual/purchase_manual_wizard.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
diff --git a/addons/purchase_manual/wizard/__init__.py b/addons/purchase_manual/wizard/__init__.py
new file mode 100644
index 00000000000..616c5c7090c
--- /dev/null
+++ b/addons/purchase_manual/wizard/__init__.py
@@ -0,0 +1 @@
+import wizard_purchase_line_invoice
diff --git a/addons/purchase_manual/wizard/wizard_purchase_line_invoice.py b/addons/purchase_manual/wizard/wizard_purchase_line_invoice.py
new file mode 100644
index 00000000000..89d7d188287
--- /dev/null
+++ b/addons/purchase_manual/wizard/wizard_purchase_line_invoice.py
@@ -0,0 +1,161 @@
+# -*- encoding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-2009 Tiny SPRL (). All Rights Reserved
+# $Id$
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+##############################################################################
+
+import wizard
+import netsvc
+import ir
+import pooler
+
+invoice_form = """
+
+"""
+
+invoice_fields = {
+}
+
+def _makeInvoices(self, cr, uid, data, context):
+ pool = pooler.get_pool(cr.dbname)
+ res = False
+ invoices = {}
+
+ def make_invoice(order, lines):
+ a = order.partner_id.property_account_payable.id
+ if order.partner_id and order.partner_id.property_payment_term.id:
+ pay_term = order.partner_id.property_payment_term.id
+ else:
+ pay_term = False
+ inv = {
+ 'name': order.name,
+ 'origin': order.name,
+ 'type': 'in_invoice',
+ 'reference': "P%dPO%d" % (order.partner_id.id, order.id),
+ 'account_id': a,
+ 'partner_id': order.partner_id.id,
+ 'address_invoice_id': order.partner_address_id.id,
+ 'address_contact_id': order.partner_address_id.id,
+ 'invoice_line': [(6,0,lines)],
+ 'currency_id' : order.pricelist_id.currency_id.id,
+ 'comment': order.notes,
+ 'payment_term': pay_term,
+ 'fiscal_position': order.partner_id.property_account_position.id
+ }
+ inv_id = pool.get('account.invoice').create(cr, uid, inv)
+ return inv_id
+
+ for line in pool.get('purchase.order.line').browse(cr,uid,data['ids']):
+ if (not line.invoiced) and (line.state not in ('draft','cancel')):
+ if not line.order_id.id in invoices:
+ invoices[line.order_id.id] = []
+ if line.product_id:
+ a = line.product_id.product_tmpl_id.property_account_expense.id
+ if not a:
+ a = line.product_id.categ_id.property_account_expense_categ.id
+ if not a:
+ raise osv.except_osv(_('Error !'),
+ _('There is no expense account defined ' \
+ 'for this product: "%s" (id:%d)') % \
+ (line.product_id.name, line.product_id.id,))
+ else:
+ a = pool.get('ir.property').get(cr, uid,
+ 'property_account_expense_categ', 'product.category',
+ context=context)
+ fpos = line.order_id.fiscal_position or False
+ a = pool.get('account.fiscal.position').map_account(cr, uid, fpos, a)
+ inv_id = pool.get('account.invoice.line').create(cr, uid, {
+ 'name': line.name,
+ 'origin': line.order_id.name,
+ 'account_id': a,
+ 'price_unit': line.price_unit,
+ 'quantity': line.product_qty,
+ 'uos_id': line.product_uom.id,
+ 'product_id': line.product_id.id or False,
+ 'invoice_line_tax_id': [(6, 0, [x.id for x in line.taxes_id])],
+ 'note': line.notes,
+ 'account_analytic_id': line.account_analytic_id and line.account_analytic_id.id or False,
+ })
+ cr.execute('insert into purchase_order_line_invoice_rel (order_line_id,invoice_id) values (%s,%s)', (line.id, inv_id))
+ pool.get('purchase.order.line').write(cr, uid, [line.id], {'invoiced': True})
+ invoices[line.order_id.id].append((line,inv_id))
+
+ res = []
+ for result in invoices.values():
+ order = result[0][0].order_id
+ il = map(lambda x: x[1], result)
+ res.append(make_invoice(order, il))
+ return {'invoice_ids': res}
+
+ return {
+ 'domain': "[('id','in', ["+','.join(map(str,res))+"])]",
+ 'name': _('Supplier Invoices'),
+ 'view_type': 'form',
+ 'view_mode': 'tree,form',
+ 'res_model': 'account.invoice',
+ 'view_id': False,
+ 'context': "{'type':'in_invoice'}",
+ 'type': 'ir.actions.act_window'
+ }
+
+class line_make_invoice(wizard.interface):
+ def _open_invoice(self, cr, uid, data, context):
+ pool_obj = pooler.get_pool(cr.dbname)
+ model_data_ids = pool_obj.get('ir.model.data').search(cr,uid,[('model','=','ir.ui.view'),('name','=','invoice_supplier_form')])
+ resource_id = pool_obj.get('ir.model.data').read(cr,uid,model_data_ids,fields=['res_id'])[0]['res_id']
+ return {
+ 'domain': "[('id','in', ["+','.join(map(str,data['form']['invoice_ids']))+"])]",
+ 'name': 'Invoices',
+ 'view_type': 'form',
+ 'view_mode': 'tree,form',
+ 'res_model': 'account.invoice',
+ 'views': [(False,'tree'),(resource_id,'form')],
+ 'context': "{'type':'in_invoice'}",
+ 'type': 'ir.actions.act_window'
+ }
+
+ states = {
+ 'init' : {
+ 'actions': [],
+ 'result': {
+ 'type': 'form',
+ 'arch': invoice_form,
+ 'fields': invoice_fields,
+ 'state': [
+ ('end', 'Cancel'),
+ ('invoice', 'Create invoices')
+ ]
+ }
+ },
+ 'invoice' : {
+ 'actions' : [_makeInvoices],
+ 'result' : {'type': 'state', 'state': 'open'}
+ },
+ 'open': {
+ 'actions': [],
+ 'result': {'type':'action', 'action':_open_invoice, 'state':'end'}
+ }
+ }
+
+line_make_invoice("purchase.order.line.make_invoice")
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+
diff --git a/addons/report_project/report_project.py b/addons/report_project/report_project.py
index b87961e9ee7..933af3e5a46 100644
--- a/addons/report_project/report_project.py
+++ b/addons/report_project/report_project.py
@@ -47,7 +47,7 @@ class report_project_task_user(osv.osv):
t.user_id,
t.project_id,
sum(planned_hours) as hours_planned,
- to_char(avg(date_close::abstime-t.create_date::timestamp), 'DD"d" HH12:MI:SS') as closing_days,
+ to_char(avg(date_close::abstime-t.create_date::timestamp), 'DD"d" HH24:MI:SS') as closing_days,
sum(w.hours) as hours_effective,
((sum(planned_hours)-sum(w.hours))/count(distinct t.id))::decimal(16,2) as hours_delay
from project_task t
diff --git a/addons/sale/report/order.rml b/addons/sale/report/order.rml
index fac75e4f4d9..fa03eb1624b 100644
--- a/addons/sale/report/order.rml
+++ b/addons/sale/report/order.rml
@@ -138,14 +138,16 @@
[[ o.partner_shipping_id.title or '' ]] [[ o.partner_shipping_id.name ]][[ o.partner_shipping_id.street ]][[ o.partner_shipping_id.street2 or '' ]]
- [[ o.partner_shipping_id.city or '' ]] [[ o.partner_shipping_id.zip or '' ]]
+ [[ o.partner_shipping_id.zip or '' ]] [[ o.partner_shipping_id.city or '' ]][[ o.partner_shipping_id.state_id and o.partner_shipping_id.state_id.name or '' ]] [[ o.partner_shipping_id.country_id and o.partner_shipping_id.country_id.name or '' ]]Invoice address :
+ [[ o.partner_invoice_id.title or '' ]] [[ o.partner_invoice_id.name or '' ]] [[ o.partner_invoice_id.street ]] [[ o.partner_invoice_id.street2 and (', %s' % o.partner_invoice_id.street2 or '') ]]
- [[ o.partner_invoice_id.zip or '' ]] [[ o.partner_invoice_id.city or '' ]] [[ o.partner_invoice_id.country_id and (', %s' % (o.partner_invoice_id.country_id and o.partner_invoice_id.country_id.name or '')) ]]
+ [[ o.partner_invoice_id.zip or '' ]] [[ o.partner_invoice_id.city or '' ]]
+ [[ o.partner_invoice_id.state_id and o.partner_invoice_id.state_id.name or '' ]] [[ o.partner_invoice_id.country_id and o.partner_invoice_id.country_id.name or '' ]]
@@ -185,7 +187,7 @@
Your Reference
- Date Ordered
+ [[ o.state=='draft' and 'Quotation Date' or 'Date Ordered' ]]
Our Salesman
diff --git a/addons/sale/sale.py b/addons/sale/sale.py
index c5917c08051..8b026bb3310 100644
--- a/addons/sale/sale.py
+++ b/addons/sale/sale.py
@@ -374,7 +374,7 @@ class sale_order(osv.osv):
'account_id': a,
'partner_id': order.partner_id.id,
'address_invoice_id': order.partner_invoice_id.id,
- 'address_contact_id': order.partner_invoice_id.id,
+ 'address_contact_id': order.partner_order_id.id,
'invoice_line': [(6, 0, lines)],
'currency_id': order.pricelist_id.currency_id.id,
'comment': order.note,
@@ -526,7 +526,7 @@ class sale_order(osv.osv):
pending_deliveries = True
if ((not line.procurement_id) or (line.procurement_id.state=='done')) and not pending_deliveries:
- finished = True
+# finished = True
if line.state != 'done':
write_done_ids.append(line.id)
else:
@@ -560,8 +560,8 @@ class sale_order(osv.osv):
picking_id = False
for line in order.order_line:
proc_id = False
- date_planned = DateTime.now() + DateTime.RelativeDateTime(days=line.delay or 0.0)
- date_planned = (date_planned - DateTime.RelativeDateTime(days=company.security_lead)).strftime('%Y-%m-%d %H:%M:%S')
+ date_planned = DateTime.now() + DateTime.DateTimeDeltaFromDays(line.delay or 0.0)
+ date_planned = (date_planned - DateTime.DateTimeDeltaFromDays(company.security_lead)).strftime('%Y-%m-%d %H:%M:%S')
if line.state == 'done':
continue
if line.product_id and line.product_id.product_tmpl_id.type in ('product', 'consu'):
@@ -835,7 +835,7 @@ class sale_order_line(osv.osv):
'product_id': line.product_id.id or False,
'invoice_line_tax_id': [(6, 0, [x.id for x in line.tax_id])],
'note': line.notes,
- 'account_analytic_id': line.order_id.project_id.id,
+ 'account_analytic_id': line.order_id.project_id and line.order_id.project_id.id or False,
})
cr.execute('insert into sale_order_line_invoice_rel (order_line_id,invoice_id) values (%s,%s)', (line.id, inv_id))
self.write(cr, uid, [line.id], {'invoiced': True})
diff --git a/addons/sale/sale_view.xml b/addons/sale/sale_view.xml
index a2aa31e86c4..ec073a895ba 100644
--- a/addons/sale/sale_view.xml
+++ b/addons/sale/sale_view.xml
@@ -110,7 +110,7 @@
-
+
- [[ o.sale_id and o.sale_id.partner_shipping_id and o.sale_id.partner_shipping_id.partner_id.name or '']]
- [[ o.sale_id and o.sale_id.partner_shipping_id and o.sale_id.partner_shipping_id.name or '']]
- [[ o.sale_id and o.sale_id.partner_shipping_id and o.sale_id.partner_shipping_id.street or '']]
- [[ o.sale_id and o.sale_id.partner_shipping_id and o.sale_id.partner_shipping_id.zip or '']]
- [[ o.sale_id and o.sale_id.partner_shipping_id and o.sale_id.partner_shipping_id.city or '']]
- [[ o.sale_id and o.sale_id.partner_shipping_id and o.sale_id.partner_shipping_id.country_id and o.sale_id.partner_shipping_id.country_id.name or '']]
+ [[ o.address_id and o.address_id.partner_id and o.address_id.partner_id.name or '']]
+ [[ o.address_id and o.address_id.name or '']]
+ [[ o.address_id and o.address_id.street or '']]
+ [[ o.address_id and o.address_id.zip or '']]
+ [[ o.address_id and o.address_id.city or '']]
+ [[ o.address_id and o.address_id.country_id and o.address_id.country_id.name or '']]
diff --git a/addons/stock/stock.py b/addons/stock/stock.py
index 09cbf55b1ed..a2443256d78 100644
--- a/addons/stock/stock.py
+++ b/addons/stock/stock.py
@@ -1293,6 +1293,7 @@ class stock_move(osv.osv):
(0, 0, {
'name': move.name,
'quantity': move.product_qty,
+ 'product_id': move.product_id and move.product_id.id or False,
'credit': amount,
'account_id': acc_src,
'ref': ref,
@@ -1300,6 +1301,7 @@ class stock_move(osv.osv):
'partner_id': partner_id}),
(0, 0, {
'name': move.name,
+ 'product_id': move.product_id and move.product_id.id or False,
'quantity': move.product_qty,
'debit': amount,
'account_id': acc_dest,
diff --git a/addons/stock/stock_view.xml b/addons/stock/stock_view.xml
index 6c606663bbd..c035313462a 100644
--- a/addons/stock/stock_view.xml
+++ b/addons/stock/stock_view.xml
@@ -1287,6 +1287,7 @@
+