diff --git a/addons/account/account.py b/addons/account/account.py
index ddb90cc13cc..29ea824f171 100644
--- a/addons/account/account.py
+++ b/addons/account/account.py
@@ -818,6 +818,7 @@ class account_move(osv.osv):
('journal_pur_voucher','Journal Purchase'),
('journal_voucher','Journal Voucher'),
],'Type', readonly=True, select=True, states={'draft':[('readonly',False)]}),
+ 'narration':fields.text('Narration', readonly=True, select=True, states={'draft':[('readonly',False)]}),
'company_id': fields.related('journal_id','company_id',type='many2one',relation='res.company',string='Company',store=True),
}
_defaults = {
diff --git a/addons/account/account_invoice_view.xml b/addons/account/account_invoice_view.xml
index 2034583ed02..a8de84f2cdc 100644
--- a/addons/account/account_invoice_view.xml
+++ b/addons/account/account_invoice_view.xml
@@ -349,6 +349,18 @@
{'type':'out_invoice'}
+
+
+ Panding Invoice
+ account.invoice
+ form
+ tree,form,calendar,graph
+
+ {'type':'out_invoice'}
+ [('state','=','draft')]
+
+
+
tree
diff --git a/addons/account/account_view.xml b/addons/account/account_view.xml
index 82f49d83cae..8be310245ac 100644
--- a/addons/account/account_view.xml
+++ b/addons/account/account_view.xml
@@ -917,7 +917,8 @@
-
+
+
diff --git a/addons/account_analytic_analysis/i18n/nl.po b/addons/account_analytic_analysis/i18n/nl.po
index bfff9f3ec71..c3f12aef08c 100644
--- a/addons/account_analytic_analysis/i18n/nl.po
+++ b/addons/account_analytic_analysis/i18n/nl.po
@@ -7,13 +7,13 @@ msgstr ""
"Project-Id-Version: OpenERP Server 5.0.0_rc3\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2009-08-28 16:01+0000\n"
-"PO-Revision-Date: 2009-12-11 12:37+0000\n"
-"Last-Translator: Pieter J. Kersten (EduSense BV) \n"
+"PO-Revision-Date: 2010-02-01 15:46+0000\n"
+"Last-Translator: Jan Verlaan (Veritos) \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2009-12-16 05:16+0000\n"
+"X-Launchpad-Export-Date: 2010-02-02 04:48+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
#. module: account_analytic_analysis
@@ -191,7 +191,7 @@ msgstr "Berekend met de formule: gefactureerd bedrag - totale kosten."
#: model:ir.actions.act_window,name:account_analytic_analysis.action_account_analytic_managed
#: model:ir.ui.menu,name:account_analytic_analysis.menu_analytic_account_managed
msgid "My Accounts"
-msgstr "Mijn rekeningen"
+msgstr "Mijn kostenplaatsen"
#. module: account_analytic_analysis
#: model:ir.module.module,description:account_analytic_analysis.module_meta_information
@@ -335,7 +335,7 @@ msgstr "Kostenplaats"
#: model:ir.actions.act_window,name:account_analytic_analysis.action_account_analytic_managed_overpassed
#: model:ir.ui.menu,name:account_analytic_analysis.menu_action_account_analytic_managed_overpassed
msgid "Overpassed Accounts"
-msgstr "Overbrugde Kostenplaatsen"
+msgstr "Overgehevelde kostenplaatsen"
#. module: account_analytic_analysis
#: model:ir.actions.act_window,name:account_analytic_analysis.action_hr_tree_invoiced_all
diff --git a/addons/document_caldav/__init__.py b/addons/account_anglo_saxon/__init__.py
similarity index 89%
rename from addons/document_caldav/__init__.py
rename to addons/account_anglo_saxon/__init__.py
index d764dfca72d..dd9a9262710 100644
--- a/addons/document_caldav/__init__.py
+++ b/addons/account_anglo_saxon/__init__.py
@@ -1,8 +1,7 @@
-# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
-# Copyright (C) 2004-2010 Tiny SPRL ().
+# Copyright (C) 2004-2009 Tiny SPRL ().
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
@@ -19,5 +18,8 @@
#
##############################################################################
-import document_caldav
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+import product
+import stock
+import purchase
+import invoice
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
\ No newline at end of file
diff --git a/addons/account_anglo_saxon/__terp__.py b/addons/account_anglo_saxon/__terp__.py
new file mode 100644
index 00000000000..31818e213ef
--- /dev/null
+++ b/addons/account_anglo_saxon/__terp__.py
@@ -0,0 +1,39 @@
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-2009 Tiny SPRL ().
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+##############################################################################
+{
+ "name" : "Stock Account",
+ "version" : "1.1",
+ "author" : "Tiny",
+ "website" : "http://tinyerp.com",
+ "description" : """This module will support the Anglo-Saxons accounting methodology by
+ changing the accounting logic with stock transactions. The difference between the Anglo-Saxon accounting countries
+ and the Rhine or also called Continental accounting countries is the moment of taking the Cost of Goods Sold versus Cost of Sales.
+ Anglo-Saxons accounting does take the cost when sales invoice is created, Continental accounting will take the cost at he moment the goods are shipped.
+ This module will add this functionality by using a interim account, to store the value of shipped goods and will contra book this interim account
+ when the invoice is created to transfer this amount to the debtor or creditor account.""",
+ "depends" : ["product", "account", "sale", "purchase"],
+ "category" : "Generic Modules/Inventory Control",
+ "init_xml" : [],
+ "demo_xml" : [],
+ "update_xml" : ["product_view.xml",],
+ "active": False,
+ "installable": True
+}
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
\ No newline at end of file
diff --git a/addons/account_anglo_saxon/i18n/account_anglo_saxon.pot b/addons/account_anglo_saxon/i18n/account_anglo_saxon.pot
new file mode 100644
index 00000000000..a2d316633a4
--- /dev/null
+++ b/addons/account_anglo_saxon/i18n/account_anglo_saxon.pot
@@ -0,0 +1,54 @@
+# Translation of OpenERP Server.
+# This file contains the translation of the following modules:
+# * account_anglo_saxon
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: OpenERP Server 5.0.6\n"
+"Report-Msgid-Bugs-To: support@openerp.com\n"
+"POT-Creation-Date: 2009-11-24 12:50:50+0000\n"
+"PO-Revision-Date: 2009-11-24 12:50:50+0000\n"
+"Last-Translator: <>\n"
+"Language-Team: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: \n"
+"Plural-Forms: \n"
+
+#. module: account_anglo_saxon
+#: view:product.category:0
+msgid " Accounting Property"
+msgstr ""
+
+#. module: account_anglo_saxon
+#: model:ir.module.module,description:account_anglo_saxon.module_meta_information
+msgid "This module will support the Anglo-Saxons accounting methodology by \n"
+" changing the accounting logic with stock transactions. The difference between the Anglo-Saxon accounting countries \n"
+" and the Rhine or also called Continental accounting countries is the moment of taking the Cost of Goods Sold versus Cost of Sales. \n"
+" Anglo-Saxons accounting does take the cost when sales invoice is created, Continental accounting will take the cost at he moment the goods are shipped.\n"
+" This module will add this functionality by using a interim account, to store the value of shipped goods and will contra book this interim account \n"
+" when the invoice is created to transfer this amount to the debtor or creditor account."
+msgstr ""
+
+#. module: account_anglo_saxon
+#: model:ir.module.module,shortdesc:account_anglo_saxon.module_meta_information
+msgid "Stock Account"
+msgstr ""
+
+#. module: account_anglo_saxon
+#: constraint:ir.ui.view:0
+msgid "Invalid XML for View Architecture!"
+msgstr ""
+
+#. module: account_anglo_saxon
+#: field:product.category,property_account_creditor_price_difference_categ:0
+#: field:product.template,property_account_creditor_price_difference:0
+msgid "Price Difference Account"
+msgstr ""
+
+#. module: account_anglo_saxon
+#: help:product.category,property_account_creditor_price_difference_categ:0
+#: help:product.template,property_account_creditor_price_difference:0
+msgid "This account will be used to value price difference between purchase price and cost price."
+msgstr ""
+
diff --git a/addons/account_anglo_saxon/i18n/fr_BE.po b/addons/account_anglo_saxon/i18n/fr_BE.po
new file mode 100644
index 00000000000..a2d316633a4
--- /dev/null
+++ b/addons/account_anglo_saxon/i18n/fr_BE.po
@@ -0,0 +1,54 @@
+# Translation of OpenERP Server.
+# This file contains the translation of the following modules:
+# * account_anglo_saxon
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: OpenERP Server 5.0.6\n"
+"Report-Msgid-Bugs-To: support@openerp.com\n"
+"POT-Creation-Date: 2009-11-24 12:50:50+0000\n"
+"PO-Revision-Date: 2009-11-24 12:50:50+0000\n"
+"Last-Translator: <>\n"
+"Language-Team: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: \n"
+"Plural-Forms: \n"
+
+#. module: account_anglo_saxon
+#: view:product.category:0
+msgid " Accounting Property"
+msgstr ""
+
+#. module: account_anglo_saxon
+#: model:ir.module.module,description:account_anglo_saxon.module_meta_information
+msgid "This module will support the Anglo-Saxons accounting methodology by \n"
+" changing the accounting logic with stock transactions. The difference between the Anglo-Saxon accounting countries \n"
+" and the Rhine or also called Continental accounting countries is the moment of taking the Cost of Goods Sold versus Cost of Sales. \n"
+" Anglo-Saxons accounting does take the cost when sales invoice is created, Continental accounting will take the cost at he moment the goods are shipped.\n"
+" This module will add this functionality by using a interim account, to store the value of shipped goods and will contra book this interim account \n"
+" when the invoice is created to transfer this amount to the debtor or creditor account."
+msgstr ""
+
+#. module: account_anglo_saxon
+#: model:ir.module.module,shortdesc:account_anglo_saxon.module_meta_information
+msgid "Stock Account"
+msgstr ""
+
+#. module: account_anglo_saxon
+#: constraint:ir.ui.view:0
+msgid "Invalid XML for View Architecture!"
+msgstr ""
+
+#. module: account_anglo_saxon
+#: field:product.category,property_account_creditor_price_difference_categ:0
+#: field:product.template,property_account_creditor_price_difference:0
+msgid "Price Difference Account"
+msgstr ""
+
+#. module: account_anglo_saxon
+#: help:product.category,property_account_creditor_price_difference_categ:0
+#: help:product.template,property_account_creditor_price_difference:0
+msgid "This account will be used to value price difference between purchase price and cost price."
+msgstr ""
+
diff --git a/addons/account_anglo_saxon/i18n/pl.po b/addons/account_anglo_saxon/i18n/pl.po
new file mode 100644
index 00000000000..f23f6949fee
--- /dev/null
+++ b/addons/account_anglo_saxon/i18n/pl.po
@@ -0,0 +1,66 @@
+# Polish translation for openobject-addons
+# Copyright (c) 2010 Rosetta Contributors and Canonical Ltd 2010
+# This file is distributed under the same license as the openobject-addons package.
+# FIRST AUTHOR , 2010.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: openobject-addons\n"
+"Report-Msgid-Bugs-To: FULL NAME \n"
+"POT-Creation-Date: 2009-11-24 12:50+0000\n"
+"PO-Revision-Date: 2010-01-06 01:42+0000\n"
+"Last-Translator: Fabien (Open ERP) \n"
+"Language-Team: Polish \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Launchpad-Export-Date: 2010-01-22 04:42+0000\n"
+"X-Generator: Launchpad (build Unknown)\n"
+
+#. module: account_anglo_saxon
+#: view:product.category:0
+msgid " Accounting Property"
+msgstr ""
+
+#. module: account_anglo_saxon
+#: model:ir.module.module,description:account_anglo_saxon.module_meta_information
+msgid ""
+"This module will support the Anglo-Saxons accounting methodology by \n"
+" changing the accounting logic with stock transactions. The difference "
+"between the Anglo-Saxon accounting countries \n"
+" and the Rhine or also called Continental accounting countries is the "
+"moment of taking the Cost of Goods Sold versus Cost of Sales. \n"
+" Anglo-Saxons accounting does take the cost when sales invoice is "
+"created, Continental accounting will take the cost at he moment the goods "
+"are shipped.\n"
+" This module will add this functionality by using a interim account, to "
+"store the value of shipped goods and will contra book this interim account \n"
+" when the invoice is created to transfer this amount to the debtor or "
+"creditor account."
+msgstr ""
+
+#. module: account_anglo_saxon
+#: model:ir.module.module,shortdesc:account_anglo_saxon.module_meta_information
+msgid "Stock Account"
+msgstr ""
+
+#. module: account_anglo_saxon
+#: constraint:ir.ui.view:0
+msgid "Invalid XML for View Architecture!"
+msgstr "XML niewłaściwy dla tej architektury wyświetlania!"
+
+#. module: account_anglo_saxon
+#: field:product.category,property_account_creditor_price_difference_categ:0
+#: field:product.template,property_account_creditor_price_difference:0
+msgid "Price Difference Account"
+msgstr "Konto różnic cenowych"
+
+#. module: account_anglo_saxon
+#: help:product.category,property_account_creditor_price_difference_categ:0
+#: help:product.template,property_account_creditor_price_difference:0
+msgid ""
+"This account will be used to value price difference between purchase price "
+"and cost price."
+msgstr ""
+"To konto będzie stosowane do rejestrowania różnic cenowych między ceną "
+"zakupu a kosztem."
diff --git a/addons/account_anglo_saxon/invoice.py b/addons/account_anglo_saxon/invoice.py
new file mode 100644
index 00000000000..3904cd6b01e
--- /dev/null
+++ b/addons/account_anglo_saxon/invoice.py
@@ -0,0 +1,158 @@
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-2009 Tiny SPRL ().
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+##############################################################################
+
+from osv import fields, osv
+
+class account_invoice_line(osv.osv):
+ _inherit = "account.invoice.line"
+
+ def move_line_get(self, cr, uid, invoice_id, context=None):
+ res = super(account_invoice_line,self).move_line_get(cr, uid, invoice_id, context)
+ inv = self.pool.get('account.invoice').browse(cr, uid, invoice_id)
+ if inv.type in ('out_invoice','out_refund'):
+ for i_line in inv.invoice_line:
+ if i_line.product_id:
+ if inv.type == 'out_invoice':
+ dacc = i_line.product_id.product_tmpl_id.property_stock_account_output and i_line.product_id.product_tmpl_id.property_stock_account_output.id
+ if not dacc:
+ dacc = i_line.product_id.categ_id.property_stock_account_output_categ and i_line.product_id.categ_id.property_stock_account_output_categ.id
+ else:
+ dacc = i_line.product_id.product_tmpl_id.property_stock_account_input and i_line.product_id.product_tmpl_id.property_stock_account_input.id
+ if not dacc:
+ dacc = i_line.product_id.categ_id.property_stock_account_input_categ and i_line.product_id.categ_id.property_stock_account_input_categ.id
+
+ cacc = i_line.product_id.product_tmpl_id.property_account_expense and i_line.product_id.product_tmpl_id.property_account_expense.id
+ if not cacc:
+ cacc = i_line.product_id.categ_id.property_account_expense_categ and i_line.product_id.categ_id.property_account_expense_categ.id
+ if dacc and cacc:
+ res.append({
+ 'type':'src',
+ 'name': i_line.name[:64],
+ 'price_unit':i_line.product_id.product_tmpl_id.standard_price,
+ 'quantity':i_line.quantity,
+ 'price':i_line.product_id.product_tmpl_id.standard_price * i_line.quantity,
+ 'account_id':dacc,
+ 'product_id':i_line.product_id.id,
+ 'uos_id':i_line.uos_id.id,
+ 'account_analytic_id':i_line.account_analytic_id.id,
+ 'taxes':i_line.invoice_line_tax_id,
+ })
+
+ res.append({
+ 'type':'src',
+ 'name': i_line.name[:64],
+ 'price_unit':i_line.product_id.product_tmpl_id.standard_price,
+ 'quantity':i_line.quantity,
+ 'price': -1 * i_line.product_id.product_tmpl_id.standard_price * i_line.quantity,
+ 'account_id':cacc,
+ 'product_id':i_line.product_id.id,
+ 'uos_id':i_line.uos_id.id,
+ 'account_analytic_id':i_line.account_analytic_id.id,
+ 'taxes':i_line.invoice_line_tax_id,
+ })
+ elif inv.type in ('in_invoice','in_refund'):
+ for i_line in inv.invoice_line:
+ if i_line.product_id:
+ if i_line.product_id.product_tmpl_id.type != 'service':
+ acc = i_line.product_id.product_tmpl_id.property_account_creditor_price_difference and i_line.product_id.product_tmpl_id.property_account_creditor_price_difference.id
+ if not acc:
+ acc = i_line.product_id.categ_id.property_account_creditor_price_difference_categ and i_line.product_id.categ_id.property_account_creditor_price_difference_categ.id
+ a = None
+ if inv.type == 'in_invoice':
+ oa = i_line.product_id.product_tmpl_id.property_stock_account_input and i_line.product_id.product_tmpl_id.property_stock_account_input.id
+ if not oa:
+ oa = i_line.product_id.categ_id.property_stock_account_input_categ and i_line.product_id.categ_id.property_stock_account_input_categ.id
+ else:
+ oa = i_line.product_id.product_tmpl_id.property_stock_account_output and i_line.product_id.product_tmpl_id.property_stock_account_output.id
+ if not oa:
+ oa = i_line.product_id.categ_id.property_stock_account_output_categ and i_line.product_id.categ_id.property_stock_account_output_categ.id
+ if oa:
+ fpos = i_line.invoice_id.fiscal_position or False
+ a = self.pool.get('account.fiscal.position').map_account(cr, uid, fpos, oa)
+ diff_res = []
+ for line in res:
+ if a == line['account_id'] and i_line.product_id.id == line['product_id']:
+ uom = i_line.product_id.uos_id or i_line.product_id.uom_id
+ standard_price = self.pool.get('product.uom')._compute_price(cr, uid, uom.id, i_line.product_id.product_tmpl_id.standard_price, i_line.uos_id.id)
+ if standard_price != i_line.price_unit and line['price'] == i_line.price_unit and acc:
+ price_diff = i_line.price_unit - standard_price
+ line.update({'price':standard_price * line['quantity']})
+ diff_res.append({
+ 'type':'src',
+ 'name': i_line.name[:64],
+ 'price_unit':price_diff,
+ 'quantity':line['quantity'],
+ 'price': price_diff * line['quantity'],
+ 'account_id':acc,
+ 'product_id':line['product_id'],
+ 'uos_id':line['uos_id'],
+ 'account_analytic_id':line['account_analytic_id'],
+ 'taxes':line.get('taxes',[]),
+ })
+ res += diff_res
+ return res
+
+ def product_id_change(self, cr, uid, ids, product, uom, qty=0, name='', type='out_invoice', partner_id=False, fposition_id=False, price_unit=False, address_invoice_id=False, context=None):
+ if not product:
+ return super(account_invoice_line, self).product_id_change(cr, uid, ids, product, uom, qty, name, type, partner_id, fposition_id, price_unit, address_invoice_id, context)
+ else:
+ res = super(account_invoice_line, self).product_id_change(cr, uid, ids, product, uom, qty, name, type, partner_id, fposition_id, price_unit, address_invoice_id, context)
+
+ if type in ('in_invoice','in_refund'):
+ product_obj = self.pool.get('product.product').browse(cr, uid, product, context=context)
+ if type == 'in_invoice':
+ oa = product_obj.product_tmpl_id.property_stock_account_input and product_obj.product_tmpl_id.property_stock_account_input.id
+ if not oa:
+ oa = product_obj.categ_id.property_stock_account_input_categ and product_obj.categ_id.property_stock_account_input_categ.id
+ else:
+ oa = product_obj.product_tmpl_id.property_stock_account_output and product_obj.product_tmpl_id.property_stock_account_output.id
+ if not oa:
+ oa = product_obj.categ_id.property_stock_account_output_categ and product_obj.categ_id.property_stock_account_output_categ.id
+ if oa:
+ fpos = fposition_id and self.pool.get('account.fiscal.position').browse(cr, uid, fposition_id) or False
+ a = self.pool.get('account.fiscal.position').map_account(cr, uid, fpos, oa)
+ res['value'].update({'account_id':a})
+ return res
+
+account_invoice_line()
+
+class account_invoice(osv.osv):
+ _inherit = "account.invoice"
+
+ def _refund_cleanup_lines(self, cr, uid, lines):
+ for line in lines:
+ inv_id = line['invoice_id']
+ inv_obj = self.browse(cr,uid,inv_id[0])
+ if inv_obj.type == 'in_invoice':
+ if line.get('product_id',False):
+ product_obj = self.pool.get('product.product').browse(cr,uid,line['product_id'][0])
+ oa = product_obj.product_tmpl_id.property_stock_account_output and product_obj.product_tmpl_id.property_stock_account_output.id
+ if not oa:
+ oa = product_obj.categ_id.property_stock_account_output_categ and product_obj.categ_id.property_stock_account_output_categ.id
+ if oa:
+ fpos = inv_obj.fiscal_position or False
+ a = self.pool.get('account.fiscal.position').map_account(cr, uid, fpos, oa)
+ account_data = self.pool.get('account.account').read(cr,uid,[a],['name'])[0]
+ line.update({'account_id': (account_data['id'],account_data['name'])})
+ res = super(account_invoice,self)._refund_cleanup_lines(cr, uid, lines)
+ return res
+
+account_invoice()
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
\ No newline at end of file
diff --git a/addons/account_anglo_saxon/product.py b/addons/account_anglo_saxon/product.py
new file mode 100644
index 00000000000..acd6577fbb7
--- /dev/null
+++ b/addons/account_anglo_saxon/product.py
@@ -0,0 +1,55 @@
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-2009 Tiny SPRL ().
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+##############################################################################
+
+from osv import fields, osv
+
+class product_category(osv.osv):
+ _inherit = "product.category"
+ _columns = {
+ 'property_account_creditor_price_difference_categ': fields.property(
+ 'account.account',
+ type='many2one',
+ relation='account.account',
+ string="Price Difference Account",
+ method=True,
+ view_load=True,
+ help="This account will be used to value price difference between purchase price and cost price."),
+
+ }
+product_category()
+
+class product_template(osv.osv):
+ _inherit = "product.template"
+ _columns = {
+ 'property_account_creditor_price_difference': fields.property(
+ 'account.account',
+ type='many2one',
+ relation='account.account',
+ string="Price Difference Account",
+ method=True,
+ view_load=True,
+ help="This account will be used to value price difference between purchase price and cost price."),
+
+ }
+product_template()
+
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+
diff --git a/addons/account_anglo_saxon/product_view.xml b/addons/account_anglo_saxon/product_view.xml
new file mode 100644
index 00000000000..78e51374128
--- /dev/null
+++ b/addons/account_anglo_saxon/product_view.xml
@@ -0,0 +1,53 @@
+
+
+
+
+ product.normal.form.inherit.stock
+ product.product
+ form
+
+
+
+
+
+
+
+
+
+
+
+
+ product.template.product.form.inherit
+ product.template
+ form
+
+
+
+
+
+
+
+
+
+
+
+
+ product.category.property.form.inherit.stock
+ product.category
+ form
+
+
+
+
+
+
+
+
+
diff --git a/addons/account_anglo_saxon/purchase.py b/addons/account_anglo_saxon/purchase.py
new file mode 100644
index 00000000000..98694a3d5dd
--- /dev/null
+++ b/addons/account_anglo_saxon/purchase.py
@@ -0,0 +1,41 @@
+# -*- encoding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-2009 Tiny SPRL ().
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+##############################################################################
+
+from osv import fields, osv
+
+class purchase_order(osv.osv):
+ _name = "purchase.order"
+ _inherit = "purchase.order"
+ _description = "Purchase order"
+
+ def inv_line_create(self, cr, uid, a, ol):
+ line = super(purchase_order, self).inv_line_create(cr, uid, a, ol)
+ if ol.product_id:
+ oa = ol.product_id.product_tmpl_id.property_stock_account_input and ol.product_id.product_tmpl_id.property_stock_account_input.id
+ if not oa:
+ oa = ol.product_id.categ_id.property_stock_account_input_categ and ol.product_id.categ_id.property_stock_account_input_categ.id
+ if oa:
+ fpos = ol.order_id.fiscal_position or False
+ a = self.pool.get('account.fiscal.position').map_account(cr, uid, fpos, oa)
+ line[2].update({'account_id': a})
+ return line
+purchase_order()
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
\ No newline at end of file
diff --git a/addons/account_anglo_saxon/sale.py b/addons/account_anglo_saxon/sale.py
new file mode 100644
index 00000000000..e2cfa7bbb3b
--- /dev/null
+++ b/addons/account_anglo_saxon/sale.py
@@ -0,0 +1,43 @@
+# -*- encoding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-2009 Tiny SPRL ().
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+##############################################################################
+
+from osv import fields, osv
+
+#class sale_order_line(osv.osv):
+# _name = 'sale.order.line'
+# _description = 'Sale Order line'
+# _inherit = 'sale.order.line'
+#
+# def invoice_line_create(self, cr, uid, ids, context={}):
+# line_ids = super('sale_order_line',self).invoice_line_create(cr, uid, ids, context)
+# invoice_line_obj = self.pool.get('account.invoice.line')
+# for line in invoice_line_obj.browse(cr, uid, line_ids):
+# if line.product_id:
+# a = line.product_id.product_tmpl_id.property_stock_account_output and line.product_id.product_tmpl_id.property_stock_account_output.id
+# if not a:
+# a = line.product_id.categ_id.property_stock_account_output_categ and line.product_id.categ_id.property_stock_account_output_categ.id
+# if a:
+# a = self.pool.get('account.fiscal.position').map_account(cr, uid, fpos, a)
+# invoice_line_obj.write(cr, uid, line.id, {'account_id':a})
+#
+#sale_order_line()
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/account_anglo_saxon/stock.py b/addons/account_anglo_saxon/stock.py
new file mode 100644
index 00000000000..ad091364fd8
--- /dev/null
+++ b/addons/account_anglo_saxon/stock.py
@@ -0,0 +1,51 @@
+# -*- encoding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-2009 Tiny SPRL ().
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+##############################################################################
+
+from osv import fields,osv
+
+#----------------------------------------------------------
+# Stock Picking
+#----------------------------------------------------------
+class stock_picking(osv.osv):
+ _inherit = "stock.picking"
+ _description = "Packing List"
+
+ def action_invoice_create(self, cr, uid, ids, journal_id=False,
+ group=False, type='out_invoice', context=None):
+ '''Return ids of created invoices for the pickings'''
+ res = super(stock_picking,self).action_invoice_create(cr, uid, ids, journal_id, group, type, context)
+ if type == 'in_refund':
+ for inv in self.pool.get('account.invoice').browse(cr, uid, res.values(), context=context):
+ for ol in inv.invoice_line:
+ if ol.product_id:
+ oa = ol.product_id.product_tmpl_id.property_stock_account_output and ol.product_id.product_tmpl_id.property_stock_account_output.id
+ if not oa:
+ oa = ol.product_id.categ_id.property_stock_account_output_categ and ol.product_id.categ_id.property_stock_account_output_categ.id
+ if oa:
+ fpos = ol.invoice_id.fiscal_position or False
+ a = self.pool.get('account.fiscal.position').map_account(cr, uid, fpos, oa)
+ self.pool.get('account.invoice.line').write(cr, uid, [ol.id], {'account_id': a})
+ return res
+
+stock_picking()
+
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/account_followup/i18n/nl.po b/addons/account_followup/i18n/nl.po
index 13782599c02..d756121ab3b 100644
--- a/addons/account_followup/i18n/nl.po
+++ b/addons/account_followup/i18n/nl.po
@@ -7,13 +7,13 @@ msgstr ""
"Project-Id-Version: OpenERP Server 5.0.0\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2009-08-28 16:01+0000\n"
-"PO-Revision-Date: 2009-12-11 13:00+0000\n"
-"Last-Translator: Pieter J. Kersten (EduSense BV) \n"
+"PO-Revision-Date: 2010-02-01 15:48+0000\n"
+"Last-Translator: Jan Verlaan (Veritos) \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2009-12-16 05:10+0000\n"
+"X-Launchpad-Export-Date: 2010-02-02 04:48+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
#. module: account_followup
@@ -55,7 +55,7 @@ msgstr "Bedrag in valuta"
#. module: account_followup
#: rml:account_followup.followup.print:0
msgid "Due"
-msgstr "Tot"
+msgstr "Bedrag"
#. module: account_followup
#: view:account.move.line:0
@@ -97,7 +97,7 @@ msgstr "Soort rekening"
#. module: account_followup
#: rml:account_followup.followup.print:0
msgid "Ref"
-msgstr "Ref"
+msgstr "Factuur"
#. module: account_followup
#: wizard_view:account_followup.followup.print.all,next:0
@@ -253,7 +253,7 @@ msgstr ""
msgid ""
"The Object name must start with x_ and not contain any special character !"
msgstr ""
-"De objectnaam moet beginnen met x_ en mag geen speciale karakters bevatten !"
+"De objectnaam moet beginnen met x_ en mag geen speciale tekens bevatten !"
#. module: account_followup
#: wizard_button:account_followup.followup.print.all,summary,end:0
diff --git a/addons/account_voucher/account.py b/addons/account_voucher/account.py
index ec886bef6c6..521767fa410 100644
--- a/addons/account_voucher/account.py
+++ b/addons/account_voucher/account.py
@@ -56,7 +56,6 @@ class account_account(osv.osv):
return ids2
_columns = {
-
'journal_id':fields.many2one('account.journal', 'Journal',domain=[('type','=','situation')]),
'open_bal' : fields.float('Opening Balance',digits=(16,2)),
'level': fields.function(_get_level, string='Level', method=True, store=True, type='integer'),
@@ -219,9 +218,7 @@ class account_move(osv.osv):
_inherit = "account.move"
_columns = {
'name':fields.char('Name', size=256, required=True, readonly=True, states={'draft':[('readonly',False)]}),
- 'narration':fields.text('Narration', readonly=True, select=True, states={'draft':[('readonly',False)]}),
}
-
account_move()
class res_currency(osv.osv):
@@ -245,4 +242,4 @@ class account_account_template(osv.osv):
account_account_template()
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
\ No newline at end of file
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/account_voucher/account_view.xml b/addons/account_voucher/account_view.xml
index b415f1af0b9..62333c56873 100755
--- a/addons/account_voucher/account_view.xml
+++ b/addons/account_voucher/account_view.xml
@@ -1,61 +1,6 @@
-
- account.move.type.form.inherit2
-
- account.move
- form
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- account.form1
diff --git a/addons/auction/i18n/pt_BR.po b/addons/auction/i18n/pt_BR.po
index 9cd95c4bc2e..c6a12f8f1aa 100644
--- a/addons/auction/i18n/pt_BR.po
+++ b/addons/auction/i18n/pt_BR.po
@@ -7,13 +7,13 @@ msgstr ""
"Project-Id-Version: OpenERP Server 5.0.0\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2009-08-28 16:01+0000\n"
-"PO-Revision-Date: 2010-01-23 02:16+0000\n"
+"PO-Revision-Date: 2010-02-01 18:21+0000\n"
"Last-Translator: Holverat Bortolossi \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2010-01-24 04:50+0000\n"
+"X-Launchpad-Export-Date: 2010-02-02 04:48+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
#. module: auction
@@ -150,74 +150,74 @@ msgstr "Antigo/pequeno produto de cobre ou estanho"
#. module: auction
#: field:auction.lots,paid_ach:0
msgid "Buyer invoice reconciled"
-msgstr ""
+msgstr "Fatura do comprador foi reconciliada"
#. module: auction
#: model:ir.actions.wizard,name:auction.auction_wizard_able_taken
msgid "Mark as taken away"
-msgstr ""
+msgstr "Marcar como retirado"
#. module: auction
#: xsl:report.auction.seller.list:0
msgid "Inv."
-msgstr ""
+msgstr "Inv."
#. module: auction
#: field:auction.deposit.cost,amount:0
msgid "Amount"
-msgstr ""
+msgstr "Valor"
#. module: auction
#: model:ir.actions.act_window,name:auction.action_deposit_border
#: model:ir.ui.menu,name:auction.menu_auction_deposit_border
msgid "Deposit border"
-msgstr ""
+msgstr "Limite de Depósito"
#. module: auction
#: xsl:report.auction.deposit:0
msgid "VAT"
-msgstr ""
+msgstr "Imposto sobre Valor Agregado"
#. module: auction
#: view:auction.lots:0
msgid "Statements"
-msgstr ""
+msgstr "Demonstrações"
#. module: auction
#: xsl:flagey.huissier:0
msgid "Adjudication"
-msgstr ""
+msgstr "Conceder"
#. module: auction
#: field:auction.dates,account_analytic_id:0
msgid "Analytic Account"
-msgstr ""
+msgstr "Conta analítica"
#. module: auction
#: selection:auction.lot.category,aie_categ:0
msgid "Unclassifieds"
-msgstr ""
+msgstr "Não classificados"
#. module: auction
#: model:ir.ui.menu,name:auction.menu_auction_dates_next_by_auction
msgid "Objects by Auction"
-msgstr ""
+msgstr "Objetos em leilão"
#. module: auction
#: field:auction.lots,lot_num:0
#: field:report.unclassified.objects,lot_num:0
msgid "List Number"
-msgstr ""
+msgstr "Número de lista"
#. module: auction
#: field:auction.deposit.cost,name:0
msgid "Cost Name"
-msgstr ""
+msgstr "Nome do custo"
#. module: auction
#: selection:auction.lot.category,aie_categ:0
msgid "Antiques"
-msgstr ""
+msgstr "Antiguidades"
#. module: auction
#: view:auction.dates:0
@@ -227,17 +227,17 @@ msgstr ""
#. module: auction
#: field:report.auction.estimation.adj.category,lot_type:0
msgid "Object Type"
-msgstr ""
+msgstr "Tipo de objeto"
#. module: auction
#: wizard_field:auction.lots.sms_send,init,text:0
msgid "SMS Message"
-msgstr ""
+msgstr "Mensagem SMS"
#. module: auction
#: selection:auction.lot.category,aie_categ:0
msgid "Contemporary Art"
-msgstr ""
+msgstr "Arte contemporânea"
#. module: auction
#: view:auction.lots:0
@@ -248,7 +248,7 @@ msgstr ""
#. module: auction
#: field:report.auction.view,nseller:0
msgid "No of sellers"
-msgstr ""
+msgstr "Nenhum vendedor"
#. module: auction
#: selection:auction.lots.send.aie,date_ask,lang:0
@@ -269,7 +269,7 @@ msgstr ""
#. module: auction
#: field:report.auction.view2,obj_margin_procent:0
msgid "Net margin (%)"
-msgstr ""
+msgstr "Margem líquida (%)"
#. module: auction
#: selection:auction.lots,state:0
@@ -277,12 +277,12 @@ msgstr ""
#: selection:report.seller.auction,state:0
#: selection:report.unclassified.objects,state:0
msgid "Unsold"
-msgstr ""
+msgstr "Não vendidos"
#. module: auction
#: view:auction.dates:0
msgid "Dates"
-msgstr ""
+msgstr "Datas"
#. module: auction
#: constraint:product.template:0
@@ -294,13 +294,13 @@ msgstr ""
#. module: auction
#: rml:auction.total.rml:0
msgid "Items"
-msgstr ""
+msgstr "Itens"
#. module: auction
#: model:account.tax,name:auction.auction_tax5
#: field:auction.dates,seller_costs:0
msgid "Seller Costs"
-msgstr ""
+msgstr "Custos do Vendedor"
#. module: auction
#: view:auction.bid:0
@@ -310,22 +310,22 @@ msgstr ""
#: model:ir.actions.report.xml,name:auction.bid_auction
#: model:ir.ui.menu,name:auction.menu_action_bid_open
msgid "Bids"
-msgstr ""
+msgstr "Lances"
#. module: auction
#: model:ir.ui.menu,name:auction.auction_all_objects_menu
msgid "All objects"
-msgstr ""
+msgstr "Todos Objetos"
#. module: auction
#: model:ir.actions.act_window,name:auction.action_auction_buyer_reporting_all2
msgid "Buyer's auction for all months"
-msgstr ""
+msgstr "Leilão do comprador para todos os meses"
#. module: auction
#: field:auction.bid,contact_tel:0
msgid "Contact"
-msgstr ""
+msgstr "Contato"
#. module: auction
#: field:report.auction.view,obj_ret:0
@@ -337,7 +337,7 @@ msgstr ""
#. module: auction
#: wizard_button:auction.lots.sms_send,init,send:0
msgid "Send SMS"
-msgstr ""
+msgstr "Enviar SMS"
#. module: auction
#: selection:auction.lot.category,aie_categ:0
@@ -347,38 +347,38 @@ msgstr ""
#. module: auction
#: field:auction.lots,sel_inv_id:0
msgid "Seller Invoice"
-msgstr ""
+msgstr "Fatura do Vendedor"
#. module: auction
#: view:auction.dates:0
msgid "Commissions"
-msgstr ""
+msgstr "Comissões"
#. module: auction
#: wizard_button:auction.lots.numerotate,search,init:0
msgid "Back"
-msgstr ""
+msgstr "Voltar"
#. module: auction
#: model:ir.actions.act_window,name:auction.action_all_objects_unsold
msgid "Unsold objects"
-msgstr ""
+msgstr "Objetos não vendidos"
#. module: auction
#: model:ir.ui.menu,name:auction.menu_all_objects_sold1
msgid "Sold Objects"
-msgstr ""
+msgstr "Objetos vendidos"
#. module: auction
#: view:report.buyer.auction2:0
#: view:report.seller.auction2:0
msgid "Sum net margin"
-msgstr ""
+msgstr "Somar margem líquida"
#. module: auction
#: view:auction.deposit:0
msgid "Deposit Border Form"
-msgstr ""
+msgstr "Formuálio de Limite de Depósito"
#. module: auction
#: field:auction.bid,bid_lines:0
@@ -386,12 +386,12 @@ msgstr ""
#: rml:bids.lots:0
#: model:ir.model,name:auction.model_auction_bid_line
msgid "Bid"
-msgstr ""
+msgstr "Lance"
#. module: auction
#: wizard_field:auction.lots.send.aie,date_ask,lang:0
msgid "Langage"
-msgstr ""
+msgstr "Idioma"
#. module: auction
#: field:auction.bid_line,lot_id:0
@@ -399,7 +399,7 @@ msgstr ""
#: view:auction.lots:0
#: model:ir.model,name:auction.model_auction_lots
msgid "Object"
-msgstr ""
+msgstr "Objeto"
#. module: auction
#: model:ir.actions.wizard,name:auction.wizard_map_user
@@ -409,7 +409,7 @@ msgstr ""
#. module: auction
#: wizard_field:auction.lots.numerotate,search,lot_num:0
msgid "Inventory Number"
-msgstr ""
+msgstr "Número de inventário"
#. module: auction
#: wizard_button:auction.lots.buyer_map,check,end:0
@@ -417,12 +417,12 @@ msgstr ""
#: wizard_button:auction.lots.numerotate,search,end:0
#: wizard_button:auction.lots.numerotate_cont,init,end:0
msgid "Exit"
-msgstr ""
+msgstr "Sair"
#. module: auction
#: field:report.buyer.auction2,net_revenue:0
msgid "Net Revenue"
-msgstr ""
+msgstr "Receita Líquida"
#. module: auction
#: view:report.buyer.auction:0
@@ -437,17 +437,17 @@ msgstr ""
#: field:report.seller.auction,state:0
#: field:report.unclassified.objects,state:0
msgid "Status"
-msgstr ""
+msgstr "Situação"
#. module: auction
#: model:ir.actions.wizard,name:auction.wizard_sms
msgid "SMS Send"
-msgstr ""
+msgstr "Enviar SMS"
#. module: auction
#: selection:auction.lot.category,aie_categ:0
msgid "Antique/Cartoons"
-msgstr ""
+msgstr "Antigo/Desenhos"
#. module: auction
#: view:auction.lots:0
@@ -455,42 +455,42 @@ msgstr ""
#: selection:report.seller.auction,state:0
#: selection:report.unclassified.objects,state:0
msgid "Sold"
-msgstr ""
+msgstr "Vendido"
#. module: auction
#: constraint:hr.employee:0
msgid "Error ! You cannot create recursive Hierarchy of Employees."
-msgstr ""
+msgstr "Erro! Você não pode criar hierarquia recursiva de funcionários."
#. module: auction
#: field:auction.bid_line,name:0
msgid "Bid date"
-msgstr ""
+msgstr "Data do lance"
#. module: auction
#: field:auction.dates,acc_expense:0
msgid "Expense Account"
-msgstr ""
+msgstr "Conta de despesas"
#. module: auction
#: model:ir.ui.menu,name:auction.menu_wizard_emporte
msgid "Deliveries Management"
-msgstr ""
+msgstr "Gerenciamento de entregas"
#. module: auction
#: field:auction.lots,obj_desc:0
msgid "Object Description"
-msgstr ""
+msgstr "Descrição do objeto"
#. module: auction
#: selection:auction.deposit,method:0
msgid "Contact the Seller"
-msgstr ""
+msgstr "Entre em contato com o vendedor"
#. module: auction
#: view:auction.lots:0
msgid "Auction Objects"
-msgstr ""
+msgstr "Leilão de Objetos"
#. module: auction
#: field:auction.lots,gross_revenue:0
@@ -498,12 +498,12 @@ msgstr ""
#: field:report.object.encoded.manager,gross_revenue:0
#: field:report.seller.auction2,gross_revenue:0
msgid "Gross revenue"
-msgstr ""
+msgstr "Receita bruta"
#. module: auction
#: view:report.seller.auction2:0
msgid "Auction reporting2 form view"
-msgstr ""
+msgstr "Relatório2 de formulário de Leilão"
#. module: auction
#: model:ir.actions.wizard,name:auction.wizard_pay
@@ -513,45 +513,45 @@ msgstr ""
#. module: auction
#: view:report.deposit.border:0
msgid "Depositer's statistics"
-msgstr ""
+msgstr "Estatísticas dos Depositantes"
#. module: auction
#: view:auction.lots:0
msgid "Buyer information"
-msgstr ""
+msgstr "Informações do Comprador"
#. module: auction
#: model:ir.model,name:auction.model_report_seller_auction
msgid "Auction Reporting on seller view"
-msgstr ""
+msgstr "Relatório Leilão na visão do Vendedor"
#. module: auction
#: field:auction.lots,name2:0
msgid "Short Description (2)"
-msgstr ""
+msgstr "Descrição resumida (2)"
#. module: auction
#: model:ir.model,name:auction.model_auction_dates
msgid "auction.dates"
-msgstr ""
+msgstr "leilão.datas"
#. module: auction
#: rml:auction.total.rml:0
#: model:ir.ui.menu,name:auction.auction_buyers_menu
msgid "Buyers"
-msgstr ""
+msgstr "Vendedores"
#. module: auction
#: wizard_field:auction.pay.buy,init,amount:0
#: wizard_field:auction.pay.buy,init,amount2:0
#: wizard_field:auction.pay.buy,init,amount3:0
msgid "Amount paid"
-msgstr ""
+msgstr "Valor pago"
#. module: auction
#: model:ir.ui.menu,name:auction.menu_report_latest_doposit_tree
msgid "My Latest Deposits"
-msgstr ""
+msgstr "Meus Últimos Depósitos"
#. module: auction
#: field:auction.lots,lot_est1:0
@@ -560,32 +560,32 @@ msgstr ""
#: field:report.auction.view,min_est:0
#: field:report.unclassified.objects,lot_est1:0
msgid "Minimum Estimation"
-msgstr ""
+msgstr "Estimativa mínima"
#. module: auction
#: view:auction.dates:0
msgid "Accounting"
-msgstr ""
+msgstr "Contabilidade"
#. module: auction
#: model:ir.ui.menu,name:auction.menu_buyer_allmonth_view2
msgid "Buyer's Revenues"
-msgstr ""
+msgstr "Receitas do comprador"
#. module: auction
#: model:ir.model,name:auction.model_report_auction_adjudication
msgid "report_auction_adjudication"
-msgstr ""
+msgstr "relatório_leilão_concedido"
#. module: auction
#: field:auction.bid_line,price:0
msgid "Maximum Price"
-msgstr ""
+msgstr "Preço máximo"
#. module: auction
#: selection:auction.lots.send.aie,date_ask,lang:0
msgid "eng"
-msgstr ""
+msgstr "Inglês"
#. module: auction
#: view:report.buyer.auction2:0
@@ -595,17 +595,17 @@ msgstr ""
#. module: auction
#: wizard_view:auction.lots.sms_send,init:0
msgid "Bulk SMS send"
-msgstr ""
+msgstr "Enviar SMS em massa"
#. module: auction
#: wizard_view:auction.taken,init:0
msgid "Select lots which are Sold"
-msgstr ""
+msgstr "Selecione lotes que são vendidos"
#. module: auction
#: field:auction.lots,statement_id:0
msgid "Payment"
-msgstr ""
+msgstr "Pagamento"
#. module: auction
#: selection:auction.lots.send.aie,date_ask,lang:0
@@ -615,50 +615,50 @@ msgstr ""
#. module: auction
#: selection:auction.lot.category,aie_categ:0
msgid "Antique/Old weapons and militaria"
-msgstr ""
+msgstr "Antiguidade/Armas antigas e militares"
#. module: auction
#: selection:auction.lot.category,aie_categ:0
msgid "Antique/Oriental Arts/Chineese furnitures"
-msgstr ""
+msgstr "Antiguidade/Arte Orientas/Mobiliário Chinês"
#. module: auction
#: selection:auction.deposit,method:0
msgid "Keep until sold"
-msgstr ""
+msgstr "Manter até vender"
#. module: auction
#: wizard_button:auction.lots.numerotate,init,choice:0
#: wizard_button:auction.lots.send.aie,init,date_ask:0
#: wizard_button:auction.lots.send.aie.results,init,date_ask:0
msgid "Continue"
-msgstr ""
+msgstr "Continuar"
#. module: auction
#: field:report.object.encoded,obj_num:0
#: field:report.object.encoded.manager,obj_num:0
msgid "# of Encoded obj."
-msgstr ""
+msgstr "# do Objeto Codificado"
#. module: auction
#: xsl:report.auction.vnd_bordereau:0
msgid "List N."
-msgstr ""
+msgstr "Lista N."
#. module: auction
#: field:report.deposit.border,moy_est:0
msgid "Avg. Est"
-msgstr ""
+msgstr "Média Estimada"
#. module: auction
#: rml:auction.total.rml:0
msgid "# of sellers:"
-msgstr ""
+msgstr "# dos vendedores:"
#. module: auction
#: constraint:product.product:0
msgid "Error: Invalid ean code"
-msgstr "Error: código EAN invalido"
+msgstr "Erro: Código EAN inválido"
#. module: auction
#: model:ir.module.module,description:auction.module_meta_information
@@ -669,26 +669,31 @@ msgid ""
" Delivery Management. \n"
" "
msgstr ""
+"Este módulo fornece funcionalidade para \n"
+" gerenciar artistas, artigos, vendedores, compradores e leilão.\n"
+" Gerenciar ofertas, registro de objetos vendidos, pagos e não pagos.\n"
+" A administração das entregas. \n"
+" "
#. module: auction
#: rml:auction.total.rml:0
msgid "# of items taken away:"
-msgstr ""
+msgstr "# de itens retirados:"
#. module: auction
#: model:ir.ui.menu,name:auction.menu_auction_allmonth_view1
msgid "Auction's Summary"
-msgstr ""
+msgstr "Resumo do Leilão"
#. module: auction
#: rml:buyer.list:0
msgid "%)"
-msgstr ""
+msgstr "%)"
#. module: auction
#: wizard_view:auction.lots.able,init:0
msgid "Confirmation set taken away"
-msgstr ""
+msgstr "Confirmação marcada como retirada"
#. module: auction
#: wizard_field:auction.lots.make_invoice,init,objects:0
@@ -697,7 +702,7 @@ msgstr ""
#: wizard_field:auction.lots.send.aie.results,date_ask,objects:0
#: field:report.deposit.border,nb_obj:0
msgid "# of objects"
-msgstr ""
+msgstr "# dos Objetos"
#. module: auction
#: field:auction.lots,lot_est2:0
@@ -706,12 +711,12 @@ msgstr ""
#: field:report.auction.view,max_est:0
#: field:report.unclassified.objects,lot_est2:0
msgid "Maximum Estimation"
-msgstr ""
+msgstr "Estimativa Máxima"
#. module: auction
#: field:auction.lots,buyer_price:0
msgid "Buyer price"
-msgstr ""
+msgstr "Preço Comprador"
#. module: auction
#: model:ir.actions.wizard,name:auction.auction_wizard_payer_sel
@@ -721,17 +726,17 @@ msgstr ""
#. module: auction
#: model:ir.actions.report.xml,name:auction.seller_form_id
msgid "Seller List"
-msgstr ""
+msgstr "Lista de Vendedor"
#. module: auction
#: field:auction.lots,is_ok:0
msgid "Buyer's payment"
-msgstr ""
+msgstr "Pagamento do Comprador"
#. module: auction
#: view:auction.dates:0
msgid "Close + Create all invoices"
-msgstr ""
+msgstr "Fechar + Criar todas as Faturas"
#. module: auction
#: model:ir.actions.wizard,name:auction.auction_catalog_flagy
@@ -741,48 +746,48 @@ msgstr ""
#. module: auction
#: field:auction.lot.history,price:0
msgid "Withdrawn price"
-msgstr ""
+msgstr "Preço de retirada"
#. module: auction
#: model:account.tax,name:auction.auction_tax4
msgid "Seller Costs1"
-msgstr ""
+msgstr "Custo1 do Venderor"
#. module: auction
#: selection:auction.lot.category,aie_categ:0
msgid "Antique/Verreries"
-msgstr ""
+msgstr "Antiguidade/Cristais"
#. module: auction
#: selection:auction.lot.category,aie_categ:0
msgid "Antique/Toys"
-msgstr ""
+msgstr "Antiguidade/Briquedos"
#. module: auction
#: field:auction.deposit,create_uid:0
#: field:auction.lots,create_uid:0
msgid "Created by"
-msgstr ""
+msgstr "Criado por"
#. module: auction
#: xsl:report.auction.ach_bordereau:0
msgid "Buyer form"
-msgstr ""
+msgstr "Formulário do comprador"
#. module: auction
#: xsl:report.auction.deposit:0
msgid "Estimate"
-msgstr ""
+msgstr "Estimativa"
#. module: auction
#: rml:auction.total.rml:0
msgid "# of buyers:"
-msgstr ""
+msgstr "# dos compradores:"
#. module: auction
#: field:auction.lots,costs:0
msgid "Indirect costs"
-msgstr ""
+msgstr "Custos indiretos"
#. module: auction
#: xsl:report.auction.ach_bordereau:0
@@ -792,12 +797,12 @@ msgstr ""
#. module: auction
#: constraint:account.tax.code:0
msgid "Error ! You can not create recursive accounts."
-msgstr ""
+msgstr "Erro ! Você não pode criar contas repetidas."
#. module: auction
#: model:ir.ui.menu,name:auction.auction_menu_root
msgid "Auction Management"
-msgstr ""
+msgstr "Gerenciamento de leilão"
#. module: auction
#: field:auction.dates,journal_seller_id:0
@@ -807,23 +812,23 @@ msgstr ""
#. module: auction
#: view:report.buyer.auction:0
msgid "Auction buyer reporting tree view"
-msgstr ""
+msgstr "Relatório de compra do leilão exibição em árvore"
#. module: auction
#: model:ir.ui.menu,name:auction.menu_auction_artist
msgid "Define Artists"
-msgstr ""
+msgstr "Definir artistas"
#. module: auction
#: field:auction.lot.category,name:0
msgid "Category Name"
-msgstr ""
+msgstr "Nome da Categoria"
#. module: auction
#: model:ir.ui.menu,name:auction.menu_report_auction_estimation_adj_category_manager
#: model:ir.ui.menu,name:auction.menu_report_auction_estimation_adj_category_member
msgid "Comparison of estimations"
-msgstr ""
+msgstr "Comparação das estimativas"
#. module: auction
#: model:ir.actions.report.xml,name:auction.v_report_barcode_lot
@@ -833,34 +838,34 @@ msgstr ""
#. module: auction
#: wizard_button:auction.lots.numerotate,not_exist,init:0
msgid "Retry"
-msgstr ""
+msgstr "Repetir"
#. module: auction
#: field:auction.artists,birth_death_dates:0
msgid "Birth / Death dates"
-msgstr ""
+msgstr "Datas de Nascimento / Morte"
#. module: auction
#: selection:auction.lot.category,aie_categ:0
msgid "Antique/Jewelry"
-msgstr ""
+msgstr "Antiguidade/Jóias"
#. module: auction
#: model:ir.model,name:auction.model_report_unclassified_objects
msgid "Unclassified objects "
-msgstr ""
+msgstr "objetos não classificados "
#. module: auction
#: wizard_button:auction.lots.numerotate_cont,init,set_number:0
#: wizard_field:auction.lots.send.aie,date_ask,numerotation:0
#: wizard_field:auction.lots.send.aie,init,numerotation:0
msgid "Numerotation"
-msgstr ""
+msgstr "Numerotation"
#. module: auction
#: model:ir.actions.act_window,name:auction.act_auction_lot_open_deposit
msgid "Bordereau de dépôt"
-msgstr ""
+msgstr "Comprovante de depósito"
#. module: auction
#: xsl:report.auction.deposit:0
diff --git a/addons/base_calendar/DAV/BufferingHTTPServer.py b/addons/base_calendar/DAV/BufferingHTTPServer.py
new file mode 100644
index 00000000000..37520421432
--- /dev/null
+++ b/addons/base_calendar/DAV/BufferingHTTPServer.py
@@ -0,0 +1,99 @@
+#!/usr/bin/env python
+
+"""
+ Buffering HTTP Server
+ Copyright (C) 1999 Christian Scholz (ruebe@aachen.heimat.de)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+"""
+
+
+from utils import VERSION, AUTHOR
+__version__ = VERSION
+__author__ = AUTHOR
+
+from BaseHTTPServer import BaseHTTPRequestHandler
+import os
+class BufferedHTTPRequestHandler(BaseHTTPRequestHandler):
+ """
+ Buffering HTTP Request Handler
+
+ This class is an extension to the BaseHTTPRequestHandler
+ class which buffers the whole output and sends it at once
+ after the processing if the request is finished.
+
+ This makes it possible to work together with some clients
+ which otherwise would break (e.g. cadaver)
+
+ """
+
+
+ def _init_buffer(self):
+ """initialize the buffer.
+
+ If you override the handle() method remember to call
+ this (see below)
+ """
+ self.__buffer=""
+ self.__outfp=os.tmpfile()
+
+ def _append(self,s):
+ """ append a string to the buffer """
+ self.__buffer=self.__buffer+s
+
+ def _flush(self):
+ """ flush the buffer to wfile """
+ self.wfile.write(self.__buffer)
+ self.__outfp.write(self.__buffer)
+ self.__outfp.flush()
+ self.wfile.flush()
+ self.__buffer=""
+
+ def handle(self):
+ """ Handle a HTTP request """
+ self._init_buffer()
+ BaseHTTPRequestHandler.handle(self)
+ self._flush()
+
+ def send_header(self, keyword, value):
+ """Send a MIME header."""
+ if self.request_version != 'HTTP/0.9':
+ self._append("%s: %s\r\n" % (keyword, value))
+
+ def end_headers(self):
+ """Send the blank line ending the MIME headers."""
+ if self.request_version != 'HTTP/0.9':
+ self._append("\r\n")
+
+ def send_response(self, code, message=None):
+ self.log_request(code)
+
+ if message is None:
+ if self.responses.has_key(code):
+ message = self.responses[code][0]
+ else:
+ message = ''
+
+ if self.request_version != 'HTTP/0.9':
+ self._append("%s %s %s\r\n" %
+ (self.protocol_version, str(code), message))
+
+ self.send_header('Server', self.version_string())
+ self.send_header('Connection', 'close')
+ self.send_header('Date', self.date_time_string())
+
+ protocol_version="HTTP/1.1"
+
diff --git a/addons/base_calendar/DAV/WebDAVServer.py b/addons/base_calendar/DAV/WebDAVServer.py
new file mode 100644
index 00000000000..5f409773c18
--- /dev/null
+++ b/addons/base_calendar/DAV/WebDAVServer.py
@@ -0,0 +1,379 @@
+"""
+ Python WebDAV Server.
+ Copyright (C) 1999 Christian Scholz (ruebe@aachen.heimat.de)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+This module builds on AuthServer by implementing the standard DAV
+methods.
+
+Subclass this class and specify an IFACE_CLASS. See example.
+
+"""
+
+DEBUG=None
+
+from utils import VERSION, AUTHOR
+__version__ = VERSION
+__author__ = AUTHOR
+
+
+import os
+import sys
+import time
+import socket
+import string
+import posixpath
+import base64
+import urlparse
+import urllib
+
+from propfind import PROPFIND
+from delete import DELETE
+from davcopy import COPY
+from davmove import MOVE
+
+from string import atoi,split
+from status import STATUS_CODES
+from errors import *
+
+import BaseHTTPServer
+
+class DAVRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
+ """Simple DAV request handler with
+
+ - GET
+ - HEAD
+ - PUT
+ - OPTIONS
+ - PROPFIND
+ - PROPPATCH
+ - MKCOL
+
+ It uses the resource/collection classes for serving and
+ storing content.
+
+ """
+
+ server_version = "DAV/" + __version__
+ protocol_version = 'HTTP/1.1'
+
+ ### utility functions
+ def _log(self, message):
+ pass
+
+ def _append(self,s):
+ """ write the string to wfile """
+ self.wfile.write(s)
+
+ def send_body(self,DATA,code,msg,desc,ctype='application/octet-stream',headers=None):
+ """ send a body in one part """
+
+ if not headers:
+ headers = {}
+ self.send_response(code,message=msg)
+ self.send_header("Connection", "keep-alive")
+ self.send_header("Accept-Ranges", "bytes")
+
+ for a,v in headers.items():
+ self.send_header(a,v)
+
+ if DATA:
+ self.send_header("Content-Length", str(len(DATA)))
+ self.send_header("Content-Type", ctype)
+ else:
+ self.send_header("Content-Length", "0")
+
+ self.end_headers()
+ if DATA:
+ self._append(DATA)
+
+ def send_body_chunks(self,DATA,code,msg,desc,ctype='text/xml; encoding="utf-8"'):
+ """ send a body in chunks """
+
+ self.responses[207]=(msg,desc)
+ self.send_response(code,message=msg)
+ self.send_header("Content-type", ctype)
+ self.send_header("Connection", "keep-alive")
+ self.send_header("Transfer-Encoding", "chunked")
+ self.end_headers()
+ self._append(hex(len(DATA))[2:]+"\r\n")
+ self._append(DATA)
+ self._append("\r\n")
+ self._append("0\r\n")
+ self._append("\r\n")
+
+ ### HTTP METHODS
+
+ def do_OPTIONS(self):
+ """return the list of capabilities """
+ self.send_response(200)
+ self.send_header("Allow", "GET, HEAD, COPY, MOVE, POST, PUT, PROPFIND, PROPPATCH, OPTIONS, MKCOL, DELETE, TRACE")
+ self.send_header("Content-Type", "text/plain")
+ self.send_header("Connection", "keep-alive")
+ self.send_header("DAV", "1")
+ self.end_headers()
+
+ def do_PROPFIND(self):
+
+ dc=self.IFACE_CLASS
+ # read the body
+ body=None
+ if self.headers.has_key("Content-Length"):
+ l=self.headers['Content-Length']
+ body=self.rfile.read(atoi(l))
+ alt_body = """
+
+
+
+
+
+
+
+
+
+ """
+ #self.wfile.write(body)
+
+ # which Depth?
+ if self.headers.has_key('Depth'):
+ d=self.headers['Depth']
+ else:
+ d="infinity"
+
+ uri=self.geturi()
+ pf=PROPFIND(uri,dc,d)
+
+ if body:
+ pf.read_propfind(body)
+
+ try:
+ DATA=pf.createResponse()
+ DATA=DATA+"\n"
+ # print "Data:", DATA
+ except DAV_NotFound,(ec,dd):
+ return self.send_notFound(dd, uri)
+ except DAV_Error, (ec,dd):
+ return self.send_error(ec,dd)
+
+ self.send_body_chunks(DATA,207,"Multi-Status","Multiple responses")
+
+ def geturi(self):
+ buri = self.IFACE_CLASS.baseuri
+ if buri[-1] == '/':
+ return urllib.unquote(buri[:-1]+self.path)
+ else:
+ return urllib.unquote(buri+self.path)
+
+ def do_GET(self):
+ """Serve a GET request."""
+ dc=self.IFACE_CLASS
+ uri=self.geturi()
+
+ # get the last modified date
+ try:
+ lm=dc.get_prop(uri,"DAV:","getlastmodified")
+ except:
+ lm="Sun, 01 Dec 2014 00:00:00 GMT" # dummy!
+ headers={"Last-Modified":lm , "Connection": "keep-alive"}
+
+ # get the content type
+ try:
+ ct=dc.get_prop(uri,"DAV:","getcontenttype")
+ except:
+ ct="application/octet-stream"
+
+ # get the data
+ try:
+ data=dc.get_data(uri)
+ except DAV_Error, (ec,dd):
+ self.send_status(ec)
+ return
+
+ # send the data
+ self.send_body(data,200,"OK","OK",ct,headers)
+
+ def do_HEAD(self):
+ """ Send a HEAD response """
+ dc=self.IFACE_CLASS
+ uri=self.geturi()
+
+ # get the last modified date
+ try:
+ lm=dc.get_prop(uri,"DAV:","getlastmodified")
+ except:
+ lm="Sun, 01 Dec 2014 00:00:00 GMT" # dummy!
+
+ headers={"Last-Modified":lm, "Connection": "keep-alive"}
+
+ # get the content type
+ try:
+ ct=dc.get_prop(uri,"DAV:","getcontenttype")
+ except:
+ ct="application/octet-stream"
+
+ try:
+ data=dc.get_data(uri)
+ headers["Content-Length"]=str(len(data))
+ except DAV_NotFound:
+ self.send_body(None,404,"Not Found","")
+ return
+
+ self.send_body(None,200,"OK","OK",ct,headers)
+
+ def do_POST(self):
+ self.send_error(404,"File not found")
+
+ def do_MKCOL(self):
+ """ create a new collection """
+
+ dc=self.IFACE_CLASS
+ uri=self.geturi()
+ try:
+ res = dc.mkcol(uri)
+ if res:
+ self.send_body(None,201,"Created",'')
+ else:
+ self.send_body(None,415,"Cannot create",'')
+ #self.send_header("Connection", "keep-alive")
+ # Todo: some content, too
+ except DAV_Error, (ec,dd):
+ self.send_body(None,int(ec),dd,dd)
+
+ def do_DELETE(self):
+ """ delete an resource """
+ dc=self.IFACE_CLASS
+ uri=self.geturi()
+ dl=DELETE(uri,dc)
+ if dc.is_collection(uri):
+ res=dl.delcol()
+ else:
+ res=dl.delone()
+
+ if res:
+ self.send_status(207,body=res)
+ else:
+ self.send_status(204)
+
+ def do_PUT(self):
+ dc=self.IFACE_CLASS
+
+ # read the body
+ body=None
+ if self.headers.has_key("Content-Length"):
+ l=self.headers['Content-Length']
+ body=self.rfile.read(atoi(l))
+ uri=self.geturi()
+
+ ct=None
+ if self.headers.has_key("Content-Type"):
+ ct=self.headers['Content-Type']
+ try:
+ dc.put(uri,body,ct)
+ except DAV_Error, (ec,dd):
+ self.send_status(ec)
+ return
+ self.send_status(201)
+
+ def do_COPY(self):
+ """ copy one resource to another """
+ try:
+ self.copymove(COPY)
+ except DAV_Error, (ec,dd):
+ self.send_status(ec)
+
+ def do_MOVE(self):
+ """ move one resource to another """
+ try:
+ self.copymove(MOVE)
+ except DAV_Error, (ec,dd):
+ self.send_status(ec)
+
+ def copymove(self,CLASS):
+ """ common method for copying or moving objects """
+ dc=self.IFACE_CLASS
+
+ # get the source URI
+ source_uri=self.geturi()
+
+ # get the destination URI
+ dest_uri=self.headers['Destination']
+ dest_uri=urllib.unquote(dest_uri)
+
+ # Overwrite?
+ overwrite=1
+ result_code=204
+ if self.headers.has_key("Overwrite"):
+ if self.headers['Overwrite']=="F":
+ overwrite=None
+ result_code=201
+
+ # instanciate ACTION class
+ cp=CLASS(dc,source_uri,dest_uri,overwrite)
+
+ # Depth?
+ d="infinity"
+ if self.headers.has_key("Depth"):
+ d=self.headers['Depth']
+
+ if d!="0" and d!="infinity":
+ self.send_status(400)
+ return
+
+ if d=="0":
+ res=cp.single_action()
+ self.send_status(res)
+ return
+
+ # now it only can be "infinity" but we nevertheless check for a collection
+ if dc.is_collection(source_uri):
+ try:
+ res=cp.tree_action()
+ except DAV_Error, (ec,dd):
+ self.send_status(ec)
+ return
+ else:
+ try:
+ res=cp.single_action()
+ except DAV_Error, (ec,dd):
+ self.send_status(ec)
+ return
+
+ if res:
+ self.send_body_chunks(res,207,STATUS_CODES[207],STATUS_CODES[207],
+ ctype='text/xml; charset="utf-8"')
+ else:
+ self.send_status(result_code)
+
+ def get_userinfo(self,user,pw):
+ """ Dummy method which lets all users in """
+
+ return 1
+
+ def send_status(self,code=200,mediatype='text/xml; charset="utf-8"', \
+ msg=None,body=None):
+
+ if not msg: msg=STATUS_CODES[code]
+ self.send_body(body,code,STATUS_CODES[code],msg,mediatype)
+
+ def send_notFound(self,descr,uri):
+ body = """
+
+ %s
+
+ %s
+
+ """
+ return self.send_status(404,descr, body=body % (uri,descr))
diff --git a/addons/base_calendar/DAV/__init__.py b/addons/base_calendar/DAV/__init__.py
new file mode 100644
index 00000000000..10abdb40014
--- /dev/null
+++ b/addons/base_calendar/DAV/__init__.py
@@ -0,0 +1,20 @@
+"""
+ python davserver
+ Copyright (C) 1999 Christian Scholz (ruebe@aachen.heimat.de)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+"""
+
+
diff --git a/addons/base_calendar/DAV/constants.py b/addons/base_calendar/DAV/constants.py
new file mode 100644
index 00000000000..e858ac519c2
--- /dev/null
+++ b/addons/base_calendar/DAV/constants.py
@@ -0,0 +1,18 @@
+"""
+
+constants definition
+
+
+"""
+
+# definition for resourcetype
+COLLECTION=1
+OBJECT=None
+DAV_PROPS=['creationdate', 'displayname', 'getcontentlanguage', 'getcontentlength', 'getcontenttype', 'getetag', 'getlastmodified', 'lockdiscovery', 'resourcetype', 'source', 'supportedlock']
+
+
+# Request classes in propfind
+
+RT_ALLPROP=1
+RT_PROPNAME=2
+RT_PROP=3
diff --git a/addons/base_calendar/DAV/davcmd.py b/addons/base_calendar/DAV/davcmd.py
new file mode 100644
index 00000000000..5c6be3ff9f7
--- /dev/null
+++ b/addons/base_calendar/DAV/davcmd.py
@@ -0,0 +1,218 @@
+"""
+
+davcmd.py
+---------
+
+containts commands like copy, move, delete for normal
+resources and collections
+
+"""
+
+from string import split,replace,joinfields
+import urlparse
+
+from utils import create_treelist, is_prefix
+from errors import *
+
+def deltree(dc,uri,exclude={}):
+ """ delete a tree of resources
+
+ dc -- dataclass to use
+ uri -- root uri to delete
+ exclude -- an optional list of uri:error_code pairs which should not
+ be deleted.
+
+ returns dict of uri:error_code tuples from which
+ another method can create a multistatus xml element.
+
+ Also note that we only know Depth=infinity thus we don't have
+ to test for it.
+
+ """
+
+ tlist=create_treelist(dc,uri)
+ result={}
+
+ for i in range(len(tlist),0,-1):
+ problem_uris=result.keys()
+ element=tlist[i-1]
+
+ # test here, if an element is a prefix of an uri which
+ # generated an error before.
+ # note that we walk here from childs to parents, thus
+ # we cannot delete a parent if a child made a problem.
+ # (see example in 8.6.2.1)
+ ok=1
+ for p in problem_uris:
+ if is_prefix(element,p):
+ ok=None
+ break
+
+ if not ok: continue
+
+ # here we test for the exclude list which is the other way round!
+ for p in exclude.keys():
+ if is_prefix(p,element):
+ ok=None
+ break
+
+ if not ok: continue
+
+ # now delete stuff
+ try:
+ delone(dc,element)
+ except DAV_Error, (ec,dd):
+ result[element]=ec
+
+ return result
+
+def delone(dc,uri):
+ """ delete a single object """
+ if dc.is_collection(uri):
+ dc.rmcol(uri) # should be empty
+ else:
+ dc.rm(uri)
+
+###
+### COPY
+###
+
+# helper function
+
+def copy(dc,src,dst):
+ """ only copy the element
+
+ This is just a helper method factored out from copy and
+ copytree. It will not handle the overwrite or depth header.
+
+ """
+
+ # destination should have been deleted before
+ if dc.exists(dst): raise DAV_Error, 412
+
+ # source should exist also
+ if not dc.exists(src): raise DAV_NotFound
+
+ if dc.is_collection(src):
+ dc.copycol(src,dst) # an exception will be passed thru
+ else:
+ dc.copy(src,dst) # an exception will be passed thru
+
+
+# the main functions
+
+def copyone(dc,src,dst,overwrite=None):
+ """ copy one resource to a new destination """
+
+ if overwrite and dc.exists(dst):
+ delres=deltree(dc,dst)
+ else:
+ delres={}
+
+ # if we cannot delete everything, then do not copy!
+ if delres: return delres
+
+ try:
+ copy(dc,src,dst) # pass thru exceptions
+ except DAV_Error, (ec,dd):
+ return ec
+
+def copytree(dc,src,dst,overwrite=None):
+ """ copy a tree of resources to another location
+
+ dc -- dataclass to use
+ src -- src uri from where to copy
+ dst -- dst uri
+ overwrite -- if 1 then delete dst uri before
+
+ returns dict of uri:error_code tuples from which
+ another method can create a multistatus xml element.
+
+ """
+
+
+ # first delete the destination resource
+ if overwrite and dc.exists(dst):
+ delres=deltree(dc,dst)
+ else:
+ delres={}
+
+ # if we cannot delete everything, then do not copy!
+ if delres: return delres
+
+ # get the tree we have to copy
+ tlist=create_treelist(dc,src)
+ result={}
+
+ # prepare destination URIs (get the prefix)
+ dpath=urlparse.urlparse(dst)[2]
+
+ for element in tlist:
+ problem_uris=result.keys()
+
+ # now URIs get longer and longer thus we have
+ # to test if we had a parent URI which we were not
+ # able to copy in problem_uris which is the prefix
+ # of the actual element. If it is, then we cannot
+ # copy this as well but do not generate another error.
+ ok=1
+ for p in problem_uris:
+ if is_prefix(p,element):
+ ok=None
+ break
+
+ if not ok: continue
+
+ # now create the destination URI which corresponds to
+ # the actual source URI. -> actual_dst
+ # ("subtract" the base src from the URI and prepend the
+ # dst prefix to it.)
+ esrc=replace(element,src,"")
+ actual_dst=dpath+esrc
+
+ # now copy stuff
+ try:
+ copy(dc,element,actual_dst)
+ except DAV_Error, (ec,dd):
+ result[element]=ec
+
+ return result
+
+
+
+###
+### MOVE
+###
+
+
+def moveone(dc,src,dst,overwrite=None):
+ """ move a single resource
+
+ This is done by first copying it and then deleting
+ the original.
+ """
+
+ # first copy it
+ copyone(dc,src,dst,overwrite)
+
+ # then delete it
+ dc.rm(src)
+
+def movetree(dc,src,dst,overwrite=None):
+ """ move a collection
+
+ This is done by first copying it and then deleting
+ the original.
+
+ PROBLEM: if something did not copy then we have a problem
+ when deleting as the original might get deleted!
+ """
+
+ # first copy it
+ res=copytree(dc,src,dst,overwrite)
+
+ # then delete it
+ res=deltree(dc,src,exclude=res)
+
+ return res
+
diff --git a/addons/base_calendar/DAV/davcopy.py b/addons/base_calendar/DAV/davcopy.py
new file mode 100755
index 00000000000..ec44931b107
--- /dev/null
+++ b/addons/base_calendar/DAV/davcopy.py
@@ -0,0 +1,133 @@
+#!/usr/bin/env python
+
+"""
+ python davserver
+ Copyright (C) 1999 Christian Scholz (ruebe@aachen.heimat.de)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+"""
+
+
+from xml.dom import ext
+from xml.dom.Document import Document
+
+import sys
+import string
+import urlparse
+import urllib
+from StringIO import StringIO
+
+import utils
+from constants import COLLECTION, OBJECT, DAV_PROPS, RT_ALLPROP, RT_PROPNAME, RT_PROP
+from errors import *
+from utils import create_treelist, quote_uri, gen_estring
+
+class COPY:
+ """ copy resources and eventually create multistatus responses
+
+ This module implements the COPY class which is responsible for
+ copying resources. Usually the normal copy work is done in the
+ interface class. This class only creates error messages if error
+ occur.
+
+ """
+
+
+ def __init__(self,dataclass,src_uri,dst_uri,overwrite):
+ self.__dataclass=dataclass
+ self.__src=src_uri
+ self.__dst=dst_uri
+ self.__overwrite=overwrite
+
+
+ def single_action(self):
+ """ copy a normal resources.
+
+ We try to copy it and return the result code.
+ This is for Depth==0
+
+ """
+
+ dc=self.__dataclass
+ base=self.__src
+
+ ### some basic tests
+ # test if dest exists and overwrite is false
+ if dc.exists(self.__dst) and not self.__overwrite: raise DAV_Error, 412
+ # test if src and dst are the same
+ # (we assume that both uris are on the same server!)
+ ps=urlparse.urlparse(self.__src)[2]
+ pd=urlparse.urlparse(self.__dst)[2]
+ if ps==pd: raise DAV_Error, 403
+
+ return dc.copyone(self.__src,self.__dst,self.__overwrite)
+
+ #return copyone(dc,self.__src,self.__dst,self.__overwrite)
+
+ def tree_action(self):
+ """ copy a tree of resources (a collection)
+
+ Here we return a multistatus xml element.
+
+ """
+ dc=self.__dataclass
+ base=self.__src
+
+ ### some basic tests
+ # test if dest exists and overwrite is false
+ if dc.exists(self.__dst) and not self.__overwrite: raise DAV_Error, 412
+ # test if src and dst are the same
+ # (we assume that both uris are on the same server!)
+ ps=urlparse.urlparse(self.__src)[2]
+ pd=urlparse.urlparse(self.__dst)[2]
+ if ps==pd: raise DAV_Error, 403
+
+
+ result=dc.copytree(self.__src,self.__dst,self.__overwrite)
+ #result=copytree(dc,self.__src,self.__dst,self.__overwrite)
+
+ if not result: return None
+
+ ###
+ ### create the multistatus XML element
+ ### (this is also the same as in delete.py.
+ ### we might make a common method out of it)
+ ###
+
+ doc = Document(None)
+ ms=doc.createElement("D:multistatus")
+ ms.setAttribute("xmlns:D","DAV:")
+ doc.appendChild(ms)
+
+ for el,ec in result.items():
+ re=doc.createElement("D:response")
+ hr=doc.createElement("D:href")
+ st=doc.createElement("D:status")
+ huri=doc.createTextNode(quote_uri(el))
+ t=doc.createTextNode(gen_estring(ec))
+ st.appendChild(t)
+ hr.appendChild(huri)
+ re.appendChild(hr)
+ re.appendChild(st)
+ ms.appendChild(re)
+
+ sfile=StringIO()
+ ext.PrettyPrint(doc,stream=sfile)
+ s=sfile.getvalue()
+ sfile.close()
+ return s
+
diff --git a/addons/base_calendar/DAV/davmove.py b/addons/base_calendar/DAV/davmove.py
new file mode 100755
index 00000000000..78c1e649389
--- /dev/null
+++ b/addons/base_calendar/DAV/davmove.py
@@ -0,0 +1,102 @@
+#!/usr/bin/env python
+
+"""
+ python davserver
+ Copyright (C) 1999 Christian Scholz (ruebe@aachen.heimat.de)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+"""
+
+
+import sys
+import string
+import urlparse
+import urllib
+from StringIO import StringIO
+
+import utils
+from constants import COLLECTION, OBJECT, DAV_PROPS
+from constants import RT_ALLPROP, RT_PROPNAME, RT_PROP
+from errors import *
+from utils import create_treelist, quote_uri, gen_estring, make_xmlresponse
+from davcmd import moveone, movetree
+
+class MOVE:
+ """ move resources and eventually create multistatus responses
+
+ This module implements the MOVE class which is responsible for
+ moving resources.
+
+ MOVE is implemented by a COPY followed by a DELETE of the old
+ resource.
+
+ """
+
+
+ def __init__(self,dataclass,src_uri,dst_uri,overwrite):
+ self.__dataclass=dataclass
+ self.__src=src_uri
+ self.__dst=dst_uri
+ self.__overwrite=overwrite
+
+
+ def single_action(self):
+ """ move a normal resources.
+
+ We try to move it and return the result code.
+ This is for Depth==0
+
+ """
+
+ dc=self.__dataclass
+ base=self.__src
+
+ ### some basic tests
+ # test if dest exists and overwrite is false
+ if dc.exists(self.__dst) and not self.__overwrite: raise DAV_Error, 412
+ # test if src and dst are the same
+ # (we assume that both uris are on the same server!)
+ ps=urlparse.urlparse(self.__src)[2]
+ pd=urlparse.urlparse(self.__dst)[2]
+ if ps==pd: raise DAV_Error, 403
+
+ return dc.moveone(self.__src,self.__dst,self.__overwrite)
+
+ def tree_action(self):
+ """ move a tree of resources (a collection)
+
+ Here we return a multistatus xml element.
+
+ """
+ dc=self.__dataclass
+ base=self.__src
+
+ ### some basic tests
+ # test if dest exists and overwrite is false
+ if dc.exists(self.__dst) and not self.__overwrite: raise DAV_Error, 412
+ # test if src and dst are the same
+ # (we assume that both uris are on the same server!)
+ ps=urlparse.urlparse(self.__src)[2]
+ pd=urlparse.urlparse(self.__dst)[2]
+ if ps==pd: raise DAV_Error, 403
+
+ result=dc.movetree(self.__src,self.__dst,self.__overwrite)
+ if not result: return None
+
+ # create the multistatus XML element
+ return make_xmlresponse(result)
+
diff --git a/addons/base_calendar/DAV/delete.py b/addons/base_calendar/DAV/delete.py
new file mode 100755
index 00000000000..ed017e53b6d
--- /dev/null
+++ b/addons/base_calendar/DAV/delete.py
@@ -0,0 +1,63 @@
+#!/usr/bin/env python
+
+"""
+
+ python davserver
+ Copyright (C) 1999 Christian Scholz (ruebe@aachen.heimat.de)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+"""
+import os
+import string
+import urllib
+from StringIO import StringIO
+
+from status import STATUS_CODES
+from utils import gen_estring, quote_uri, make_xmlresponse
+from davcmd import deltree
+
+class DELETE:
+
+ def __init__(self,uri,dataclass):
+ self.__dataclass=dataclass
+ self.__uri=uri
+
+ def delcol(self):
+ """ delete a collection """
+
+ dc=self.__dataclass
+ result=dc.deltree(self.__uri)
+
+ if not len(result.items()):
+ return None # everything ok
+
+ # create the result element
+ return make_xmlresponse(result)
+
+ def delone(self):
+ """ delete a resource """
+
+ dc=self.__dataclass
+ result=dc.delone(self.__uri)
+
+ if not result: return None
+ if not len(result.items()):
+ return None # everything ok
+
+ # create the result element
+ return make_xmlresponse(result)
+
diff --git a/addons/base_calendar/DAV/errors.py b/addons/base_calendar/DAV/errors.py
new file mode 100755
index 00000000000..9c0e7667913
--- /dev/null
+++ b/addons/base_calendar/DAV/errors.py
@@ -0,0 +1,56 @@
+#!/usr/bin/env python
+"""
+
+ Exceptions for the DAVserver implementation
+
+"""
+
+class DAV_Error(Exception):
+ """ in general we can have the following arguments:
+
+ 1. the error code
+ 2. the error result element, e.g. a element
+ """
+
+ def __init__(self,*args):
+ if len(args)==1:
+ self.args=(args[0],"")
+ else:
+ self.args=args
+
+class DAV_Secret(DAV_Error):
+ """ the user is not allowed to know anything about it
+
+ returning this for a property value means to exclude it
+ from the response xml element.
+ """
+
+ def __init__(self):
+ DAV_Error.__init__(self,0)
+ pass
+
+class DAV_NotFound(DAV_Error):
+ """ a requested property was not found for a resource """
+
+ def __init__(self,*args):
+ if len(args):
+ if isinstance(args[0],list):
+ stre = "Path %s not found!"%('/'.join(args[0]))
+ else:
+ stre = args[0]
+ DAV_Error.__init__(self,404,stre)
+ else:
+ DAV_Error.__init__(self,404)
+
+ pass
+
+class DAV_Forbidden(DAV_Error):
+ """ a method on a resource is not allowed """
+
+ def __init__(self,*args):
+ if len(args):
+ DAV_Error.__init__(self,403,args[0])
+ else:
+ DAV_Error.__init__(self,403)
+ pass
+
diff --git a/addons/base_calendar/DAV/iface.py b/addons/base_calendar/DAV/iface.py
new file mode 100644
index 00000000000..c8f5fe2594d
--- /dev/null
+++ b/addons/base_calendar/DAV/iface.py
@@ -0,0 +1,263 @@
+"""
+
+basic interface class
+
+use this for subclassing when writing your own interface
+class.
+
+"""
+
+from errors import *
+
+import time
+from string import lower
+
+class dav_interface:
+ """ interface class for implementing DAV servers """
+
+ ### defined properties (modify this but let the DAV stuff there!)
+ ### the format is namespace: [list of properties]
+
+ PROPS={"DAV:" : ('creationdate',
+ 'displayname',
+ 'getcontentlanguage',
+ 'getcontentlength',
+ 'getcontenttype',
+ 'getetag',
+ 'getlastmodified',
+ 'lockdiscovery',
+ 'resourcetype',
+ 'source',
+ 'supportedlock'),
+ "NS2" : ("p1","p2")
+ }
+
+ # here we define which methods handle which namespace
+ # the first item is the namespace URI and the second one
+ # the method prefix
+ # e.g. for DAV:getcontenttype we call dav_getcontenttype()
+ M_NS={"DAV:" : "_get_dav",
+ "NS2" : "ns2" }
+
+ def get_propnames(self,uri):
+ """ return the property names allowed for the given URI
+
+ In this method we simply return the above defined properties
+ assuming that they are valid for any resource.
+ You can override this in order to return a different set
+ of property names for each resource.
+
+ """
+ return self.PROPS
+
+ def get_prop2(self,uri,ns,pname):
+ """ return the value of a property
+ """
+ if lower(ns)=="dav:": return self.get_dav(uri,pname)
+
+ raise DAV_NotFound
+
+ def get_prop(self,uri,ns,propname):
+ """ return the value of a given property
+
+ uri -- uri of the object to get the property of
+ ns -- namespace of the property
+ pname -- name of the property
+ """
+ if self.M_NS.has_key(ns):
+ prefix=self.M_NS[ns]
+ else:
+ print "No namespace:",ns, "( for prop:", propname,")"
+ raise DAV_NotFound
+ mname=prefix+"_"+propname
+ if not hasattr(self,mname):
+ raise DAV_NotFound
+
+ try:
+ m=getattr(self,mname)
+ r=m(uri)
+ return r
+ except AttributeError, e:
+ print 'Property %s not supported' % propname
+ print "Exception:", e
+ raise DAV_NotFound
+
+ ###
+ ### DATA methods (for GET and PUT)
+ ###
+
+ def get_data(self,uri):
+ """ return the content of an object
+
+ return data or raise an exception
+
+ """
+ raise DAV_NotFound
+
+ def put(self,uri,data):
+ """ write an object to the repository
+
+ return a result code or raise an exception
+ """
+
+ raise DAV_Forbidden
+
+ ###
+ ### Methods for DAV properties
+ ###
+
+ def _get_dav_creationdate(self,uri):
+ """ return the creationdate of a resource """
+ d=self.get_creationdate(uri)
+ # format it
+ if isinstance(d, int) or isinstance(d, float):
+ d = time.localtimetime(d)
+ return time.strftime("%Y-%m-%dT%H:%M:%S%Z",d)
+
+ def _get_dav_getlastmodified(self,uri):
+ """ return the last modified date of a resource """
+ d=self.get_lastmodified(uri)
+ if isinstance(d, int) or isinstance(d, float):
+ d = time.localtime(d)
+ # format it
+ return time.asctime(d)
+
+
+ ###
+ ### OVERRIDE THESE!
+ ###
+
+ def get_creationdate(self,uri):
+ """ return the creationdate of the resource """
+ return time.time()
+
+ def get_lastmodified(self,uri):
+ """ return the last modification date of the resource """
+ return time.time()
+
+
+ ###
+ ### COPY MOVE DELETE
+ ###
+
+ ### methods for deleting a resource
+
+ def rmcol(self,uri):
+ """ delete a collection
+
+ This should not delete any children! This is automatically done
+ before by the DELETE class in DAV/delete.py
+
+ return a success code or raise an exception
+
+ """
+ raise DAV_NotFound
+
+ def rm(self,uri):
+ """ delete a single resource
+
+ return a success code or raise an exception
+
+ """
+ raise DAV_NotFound
+
+ """
+
+ COPY/MOVE HANDLER
+
+ These handler are called when a COPY or MOVE method is invoked by
+ a client. In the default implementation it works as follows:
+
+ - the davserver receives a COPY/MOVE method
+ - the davcopy or davmove module will be loaded and the corresponding
+ class will be initialized
+ - this class parses the query and decides which method of the interface class
+ to call:
+
+ copyone for a single resource to copy
+ copytree for a tree to copy (collection)
+ (the same goes for move of course).
+
+ - the interface class has now two options:
+ 1. to handle the action directly (e.g. cp or mv on filesystems)
+ 2. to let it handle via the copy/move methods in davcmd.
+
+ ad 1) The first approach can be used when we know that no error can
+ happen inside a tree or when the action can exactly tell which
+ element made which error. We have to collect these and return
+ it in a dict of the form {uri: error_code, ...}
+
+ ad 2) The copytree/movetree/... methods of davcmd.py will do the recursion
+ themselves and call for each resource the copy/move method of the
+ interface class. Thus method will then only act on a single resource.
+ (Thus a copycol on a normal unix filesystem actually only needs to do
+ an mkdir as the content will be copied by the davcmd.py function.
+ The davcmd.py method will also automatically collect all errors and
+ return the dictionary described above.
+ When you use 2) you also have to implement the copy() and copycol()
+ methods in your interface class. See the example for details.
+
+ To decide which approach is the best you have to decide if your application
+ is able to generate errors inside a tree. E.g. a function which completely
+ fails on a tree if one of the tree's childs fail is not what we need. Then
+ 2) would be your way of doing it.
+ Actually usually 2) is the better solution and should only be replaced by
+ 1) if you really need it.
+
+ The remaining question is if we should do the same for the DELETE method.
+
+ """
+
+ ### MOVE handlers
+
+ def moveone(self,src,dst,overwrite):
+ """ move one resource with Depth=0 """
+ return moveone(self,src,dst,overwrite)
+
+ def movetree(self,src,dst,overwrite):
+ """ move a collection with Depth=infinity """
+ return movetree(self,src,dst,overwrite)
+
+ ### COPY handlers
+
+ def copyone(self,src,dst,overwrite):
+ """ copy one resource with Depth=0 """
+ return copyone(self,src,dst,overwrite)
+
+ def copytree(self,src,dst,overwrite):
+ """ copy a collection with Depth=infinity """
+ return copytree(self,src,dst,overwrite)
+
+
+ ### low level copy methods (you only need these for method 2)
+ def copy(self,src,dst):
+ """ copy a resource with depth==0
+
+ You don't need to bother about overwrite or not.
+ This has been done already.
+
+ return a success code or raise an exception if something fails
+ """
+ return 201
+
+
+ def copycol(self,src,dst):
+ """ copy a resource with depth==infinity
+
+ You don't need to bother about overwrite or not.
+ This has been done already.
+
+ return a success code or raise an exception if something fails
+ """
+ return 201
+
+ ### some utility functions you need to implement
+
+ def exists(self,uri):
+ """ return 1 or None depending on if a resource exists """
+ return None # no
+
+ def is_collection(self,uri):
+ """ return 1 or None depending on if a resource is a collection """
+ return None # no
+
diff --git a/addons/base_calendar/DAV/propfind.py b/addons/base_calendar/DAV/propfind.py
new file mode 100755
index 00000000000..0fb9c229c03
--- /dev/null
+++ b/addons/base_calendar/DAV/propfind.py
@@ -0,0 +1,372 @@
+#!/usr/bin/env python
+
+"""
+ python davserver
+ Copyright (C) 1999 Christian Scholz (ruebe@aachen.heimat.de)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+"""
+
+
+from xml.dom import ext
+from xml.dom.Document import Document
+
+import sys
+import string
+import urlparse
+import urllib
+from StringIO import StringIO
+
+import utils
+from constants import COLLECTION, OBJECT, DAV_PROPS, RT_ALLPROP, RT_PROPNAME, RT_PROP
+from errors import *
+
+def utf8str(st):
+ if isinstance(st,unicode):
+ return st.encode('utf8')
+ else:
+ return str(st)
+
+class PROPFIND:
+ """ parse a propfind xml element and extract props
+
+ It will set the following instance vars:
+
+ request_class : ALLPROP | PROPNAME | PROP
+ proplist : list of properties
+ nsmap : map of namespaces
+
+ The list of properties will contain tuples of the form
+ (element name, ns_prefix, ns_uri)
+
+
+ """
+
+
+ def __init__(self,uri,dataclass,depth):
+ self.request_type=None
+ self.nsmap={}
+ self.proplist={}
+ self.default_ns=None
+ self.__dataclass=dataclass
+ self.__depth=str(depth)
+ self.__uri=uri
+ self.use_full_urls=True
+ self.__has_body=None # did we parse a body?
+
+ def read_propfind(self,xml_doc):
+ self.request_type,self.proplist,self.namespaces=utils.parse_propfind(xml_doc)
+
+ # a violation of the expected logic: client (korganizer) will ask for DAV:resourcetype
+ # but we also have to return the http://groupdav.org/:resourcetype property!
+ if self.proplist.has_key('DAV:') and 'resourcetype' in self.proplist['DAV:']:
+ if not self.proplist.has_key('http://groupdav.org/'):
+ self.proplist['http://groupdav.org/'] = []
+ self.proplist['http://groupdav.org/'].append('resourcetype')
+ if 'DAV:' in self.namespaces: #TMP
+ self.namespaces.append('http://groupdav.org/')
+
+ def createResponse(self):
+ """ create the multistatus response
+
+ This will be delegated to the specific method
+ depending on which request (allprop, propname, prop)
+ was found.
+
+ If we get a PROPNAME then we simply return the list with empty
+ values which we get from the interface class
+
+ If we get an ALLPROP we first get the list of properties and then
+ we do the same as with a PROP method.
+
+ If the uri doesn't exist, return an xml response with a 404 status
+
+ """
+
+ if not self.__dataclass.exists(self.__uri):
+ raise DAV_NotFound("Path %s doesn't exist" % self.__uri)
+
+ if self.request_type==RT_ALLPROP:
+ return self.create_allprop()
+
+ if self.request_type==RT_PROPNAME:
+ return self.create_propname()
+
+ if self.request_type==RT_PROP:
+ return self.create_prop()
+
+ # no body means ALLPROP!
+ return self.create_allprop()
+
+ def create_propname(self):
+ """ create a multistatus response for the prop names """
+
+ dc=self.__dataclass
+ # create the document generator
+ doc = Document(None)
+ ms=doc.createElement("D:multistatus")
+ ms.setAttribute("xmlns:D","DAV:")
+ doc.appendChild(ms)
+
+ if self.__depth=="0":
+ pnames=dc.get_propnames(self.__uri)
+ re=self.mk_propname_response(self.__uri,pnames,doc)
+ ms.appendChild(re)
+
+ elif self.__depth=="1":
+ pnames=dc.get_propnames(self.__uri)
+ re=self.mk_propname_response(self.__uri,pnames,doc)
+ ms.appendChild(re)
+
+ for newuri in dc.get_childs(self.__uri):
+ pnames=dc.get_propnames(newuri)
+ re=self.mk_propname_response(newuri,pnames,doc)
+ ms.appendChild(re)
+ # *** depth=="infinity"
+
+ sfile=StringIO()
+ ext.PrettyPrint(doc,stream=sfile)
+ s=sfile.getvalue()
+ sfile.close()
+ return s
+
+ def create_allprop(self):
+ """ return a list of all properties """
+ self.proplist={}
+ self.namespaces=[]
+ for ns,plist in self.__dataclass.get_propnames(self.__uri).items():
+ self.proplist[ns]=plist
+ self.namespaces.append(ns)
+
+ return self.create_prop()
+
+ def create_prop(self):
+ """ handle a request
+
+ This will
+
+ 1. set up the -Framework
+
+ 2. read the property values for each URI
+ (which is dependant on the Depth header)
+ This is done by the get_propvalues() method.
+
+ 3. For each URI call the append_result() method
+ to append the actual -Tag to the result
+ document.
+
+ We differ between "good" properties, which have been
+ assigned a value by the interface class and "bad"
+ properties, which resulted in an error, either 404
+ (Not Found) or 403 (Forbidden).
+
+ """
+
+
+ # create the document generator
+ doc = Document(None)
+ ms=doc.createElement("D:multistatus")
+ ms.setAttribute("xmlns:D","DAV:")
+ doc.appendChild(ms)
+
+ if self.__depth=="0":
+ gp,bp=self.get_propvalues(self.__uri)
+ res=self.mk_prop_response(self.__uri,gp,bp,doc)
+ ms.appendChild(res)
+
+ elif self.__depth=="1":
+ gp,bp=self.get_propvalues(self.__uri)
+ res=self.mk_prop_response(self.__uri,gp,bp,doc)
+ ms.appendChild(res)
+
+ try:
+ for newuri in self.__dataclass.get_childs(self.__uri):
+ gp,bp=self.get_propvalues(newuri)
+ res=self.mk_prop_response(newuri,gp,bp,doc)
+ ms.appendChild(res)
+ except DAV_NotFound:
+ # If no children, never mind.
+ pass
+
+ sfile=StringIO()
+ ext.PrettyPrint(doc,stream=sfile)
+ s=sfile.getvalue()
+ sfile.close()
+ return s
+
+
+ def mk_propname_response(self,uri,propnames,doc):
+ """ make a new result element for a PROPNAME request
+
+ This will simply format the propnames list.
+ propnames should have the format {NS1 : [prop1, prop2, ...], NS2: ...}
+
+ """
+ re=doc.createElement("D:response")
+
+ # write href information
+ href=doc.createElement("D:href")
+ if self.use_full_urls:
+ huri=doc.createTextNode(uri)
+ else:
+ uparts=urlparse.urlparse(uri)
+ fileloc=uparts[2]
+ huri=doc.createTextNode(urllib.quote(fileloc.encode('utf8')))
+ href.appendChild(huri)
+ re.appendChild(href)
+
+ ps=doc.createElement("D:propstat")
+ nsnum=0
+
+ for ns,plist in propnames.items():
+ # write prop element
+ pr=doc.createElement("D:prop")
+ nsp="ns"+str(nsnum)
+ pr.setAttribute("xmlns:"+nsp,ns)
+ nsnum=nsnum+1
+
+ # write propertynames
+ for p in plist:
+ pe=doc.createElement(nsp+":"+p)
+ pr.appendChild(pe)
+
+ ps.appendChild(pr)
+
+ re.appendChild(ps)
+
+ return re
+
+ def mk_prop_response(self,uri,good_props,bad_props,doc):
+ """ make a new result element
+
+ We differ between the good props and the bad ones for
+ each generating an extra -Node (for each error
+ one, that means).
+
+ """
+ re=doc.createElement("D:response")
+ # append namespaces to response
+ nsnum=0
+ for nsname in self.namespaces:
+ re.setAttribute("xmlns:ns"+str(nsnum),nsname)
+ nsnum=nsnum+1
+
+ # write href information
+ href=doc.createElement("D:href")
+ if self.use_full_urls:
+ huri=doc.createTextNode(uri)
+ else:
+ uparts=urlparse.urlparse(uri)
+ fileloc=uparts[2]
+ huri=doc.createTextNode(urllib.quote(fileloc.encode('utf8')))
+ href.appendChild(huri)
+ re.appendChild(href)
+
+ # write good properties
+ if good_props and len(good_props.items()):
+ ps=doc.createElement("D:propstat")
+
+ gp=doc.createElement("D:prop")
+ for ns in good_props.keys():
+ ns_prefix="ns"+str(self.namespaces.index(ns))+":"
+ for p,v in good_props[ns].items():
+ pe=doc.createElement(ns_prefix+str(p))
+ if v == None:
+ pass
+ elif ns=='DAV:' and p=="resourcetype":
+ if v == 1:
+ ve=doc.createElement("D:collection")
+ pe.appendChild(ve)
+ elif isinstance(v,tuple) and v[1] == ns:
+ ve=doc.createElement(ns_prefix+v[0])
+ pe.appendChild(ve)
+ else:
+ ve=doc.createTextNode(utf8str(v))
+ pe.appendChild(ve)
+
+ gp.appendChild(pe)
+ if gp.hasChildNodes():
+ re.appendChild(ps)
+ ps.appendChild(gp)
+ s=doc.createElement("D:status")
+ t=doc.createTextNode("HTTP/1.1 200 OK")
+ s.appendChild(t)
+ ps.appendChild(s)
+ re.appendChild(ps)
+
+ # now write the errors!
+ if len(bad_props.items()):
+
+ # write a propstat for each error code
+ for ecode in bad_props.keys():
+ ps=doc.createElement("D:propstat")
+ re.appendChild(ps)
+ bp=doc.createElement("D:prop")
+ ps.appendChild(bp)
+
+ for ns in bad_props[ecode].keys():
+ ns_prefix="ns"+str(self.namespaces.index(ns))+":"
+
+ for p in bad_props[ecode][ns]:
+ pe=doc.createElement(ns_prefix+str(p))
+ bp.appendChild(pe)
+
+ s=doc.createElement("D:status")
+ t=doc.createTextNode(utils.gen_estring(ecode))
+ s.appendChild(t)
+ ps.appendChild(s)
+ re.appendChild(ps)
+
+ # return the new response element
+ return re
+
+ def get_propvalues(self,uri):
+ """ create lists of property values for an URI
+
+ We create two lists for an URI: the properties for
+ which we found a value and the ones for which we
+ only got an error, either because they haven't been
+ found or the user is not allowed to read them.
+
+ """
+ good_props={}
+ bad_props={}
+
+ for (ns,plist) in self.proplist.items():
+ good_props[ns]={}
+ bad_props={}
+ ec = 0
+ for prop in plist:
+ try:
+ ec = 0
+ r=self.__dataclass.get_prop(uri,ns,prop)
+ good_props[ns][prop]=r
+ except DAV_Error, error_code:
+ ec=error_code[0]
+
+ # ignore props with error_code if 0 (invisible)
+ if ec==0: continue
+
+ if bad_props.has_key(ec):
+ if bad_props[ec].has_key(ns):
+ bad_props[ec][ns].append(prop)
+ else:
+ bad_props[ec][ns]=[prop]
+ else:
+ bad_props[ec]={ns:[prop]}
+
+ return good_props, bad_props
+
diff --git a/addons/base_calendar/DAV/status.py b/addons/base_calendar/DAV/status.py
new file mode 100644
index 00000000000..62cb323c4fb
--- /dev/null
+++ b/addons/base_calendar/DAV/status.py
@@ -0,0 +1,31 @@
+"""
+
+status codes for DAV services
+
+
+"""
+
+
+STATUS_CODES={
+ 102: "Processing",
+ 200: "Ok",
+ 201: "Created",
+ 204: "No Content",
+ 207: "Multi-Status",
+ 201: "Created",
+ 400: "Bad Request",
+ 403: "Forbidden",
+ 404: "Not Found",
+ 405: "Method Not Allowed",
+ 409: "Conflict",
+ 412: "Precondition failed",
+ 423: "Locked",
+ 415: "Unsupported Media Type",
+ 507: "Insufficient Storage",
+ 422: "Unprocessable Entity",
+ 423: "Locked",
+ 424: "Failed Dependency",
+ 502: "Bad Gateway",
+ 507: "Insufficient Storage",
+ 999: "Some error in Create Method please check the data of create method"
+}
diff --git a/addons/base_calendar/DAV/utils.py b/addons/base_calendar/DAV/utils.py
new file mode 100755
index 00000000000..c4bb4d1a4c0
--- /dev/null
+++ b/addons/base_calendar/DAV/utils.py
@@ -0,0 +1,160 @@
+#!/usr/bin/env python
+
+"""
+
+UTILITIES
+
+- parse a propfind request body into a list of props
+
+"""
+
+from xml.dom import ext
+from xml.dom.Document import Document
+from xml.dom.ext.reader import PyExpat
+from xml.dom import Node
+from xml.dom import NodeIterator, NodeFilter
+
+from string import lower, split, atoi, joinfields
+import urlparse
+from StringIO import StringIO
+
+from constants import RT_ALLPROP, RT_PROPNAME, RT_PROP
+from status import STATUS_CODES
+
+VERSION = '0.6'
+AUTHOR = 'Simon Pamies '
+
+
+def gen_estring(ecode):
+ """ generate an error string from the given code """
+ ec=atoi(str(ecode))
+ if STATUS_CODES.has_key(ec):
+ return "HTTP/1.1 %s %s" %(ec,STATUS_CODES[ec])
+ else:
+ return "HTTP/1.1 %s" %(ec)
+
+def parse_propfind(xml_doc):
+ """ parse an propfind xml file and return a list of props
+
+ returns:
+
+ request_type -- ALLPROP, PROPNAME, PROP
+ proplist -- list of properties found
+ namespaces -- list of namespaces found
+
+ """
+ doc = PyExpat.Reader().fromString(xml_doc)
+ snit = doc.createNodeIterator(doc, NodeFilter.NodeFilter.SHOW_ELEMENT, None, None)
+
+ request_type=None
+ props={}
+ namespaces=[]
+
+ while 1:
+ curr_elem = snit.nextNode()
+ if not curr_elem: break
+ ename=fname=lower(curr_elem.nodeName)
+ if ":" in fname:
+ ename=split(fname,":")[1]
+ if ename=="prop": request_type=RT_PROP; continue
+ if ename=="propfind": continue
+ if ename=="allprop": request_type=RT_ALLPROP; continue
+ if ename=="propname": request_type=RT_PROPNAME; continue
+
+ # rest should be names of attributes
+
+ ns = curr_elem.namespaceURI
+ if props.has_key(ns):
+ props[ns].append(ename)
+ else:
+ props[ns]=[ename]
+ namespaces.append(ns)
+
+ return request_type,props,namespaces
+
+
+def create_treelist(dataclass,uri):
+ """ create a list of resources out of a tree
+
+ This function is used for the COPY, MOVE and DELETE methods
+
+ uri - the root of the subtree to flatten
+
+ It will return the flattened tree as list
+
+ """
+ queue=[uri]
+ list=[uri]
+ while len(queue):
+ element=queue[-1]
+ if dataclass.is_collection(element):
+ childs=dataclass.get_childs(element)
+ else:
+ childs=[]
+ if len(childs):
+ list=list+childs
+ # update queue
+ del queue[-1]
+ if len(childs):
+ queue=queue+childs
+ return list
+
+def is_prefix(uri1,uri2):
+ """ returns 1 of uri1 is a prefix of uri2 """
+ if uri2[:len(uri1)]==uri1:
+ return 1
+ else:
+ return None
+
+def quote_uri(uri):
+ """ quote an URL but not the protocol part """
+ import urlparse
+ import urllib
+
+ up=urlparse.urlparse(uri)
+ np=urllib.quote(up[2])
+ return urlparse.urlunparse((up[0],up[1],np,up[3],up[4],up[5]))
+
+def get_uriparentpath(uri):
+ """ extract the uri path and remove the last element """
+ up=urlparse.urlparse(uri)
+ return joinfields(split(up[2],"/")[:-1],"/")
+
+def get_urifilename(uri):
+ """ extract the uri path and return the last element """
+ up=urlparse.urlparse(uri)
+ return split(up[2],"/")[-1]
+
+def get_parenturi(uri):
+ """ return the parent of the given resource"""
+ up=urlparse.urlparse(uri)
+ np=joinfields(split(up[2],"/")[:-1],"/")
+ return urlparse.urlunparse((up[0],up[1],np,up[3],up[4],up[5]))
+
+### XML utilities
+
+def make_xmlresponse(result):
+ """ construct a response from a dict of uri:error_code elements """
+ doc = Document(None)
+ ms=doc.createElement("D:multistatus")
+ ms.setAttribute("xmlns:D","DAV:")
+ doc.appendChild(ms)
+
+ for el,ec in result.items():
+ re=doc.createElement("D:response")
+ hr=doc.createElement("D:href")
+ st=doc.createElement("D:status")
+ huri=doc.createTextNode(quote_uri(el))
+ t=doc.createTextNode(gen_estring(ec))
+ st.appendChild(t)
+ hr.appendChild(huri)
+ re.appendChild(hr)
+ re.appendChild(st)
+ ms.appendChild(re)
+
+ sfile=StringIO()
+ ext.PrettyPrint(doc,stream=sfile)
+ s=sfile.getvalue()
+ sfile.close()
+ return s
+
diff --git a/addons/base_calendar/__init__.py b/addons/base_calendar/__init__.py
index c127cc7c124..017a1748449 100644
--- a/addons/base_calendar/__init__.py
+++ b/addons/base_calendar/__init__.py
@@ -21,5 +21,6 @@
import base_calendar
import wizard
-
+import base_calendar_node
+import webdav_server
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/base_calendar/base_calendar.py b/addons/base_calendar/base_calendar.py
index da335fda91c..6cb7e5324fd 100644
--- a/addons/base_calendar/base_calendar.py
+++ b/addons/base_calendar/base_calendar.py
@@ -25,10 +25,13 @@ from dateutil.rrule import *
from osv import osv, fields
from tools.translate import _
import base64
+import math
import pooler
+import pytz
import re
import tools
import vobject
+import time
# O-1 Optional and can come only once
# O-n Optional and can come more than once
@@ -52,11 +55,11 @@ def uid2openobjectid(cr, uidval, oomodel, rdate):
r_id = cr.fetchone()
if r_id:
return (id, r_id[0])
- cr.execute(qry)
+ cr.execute(qry)
ids = map(lambda x: str(x[0]), cr.fetchall())
if id in ids:
return (id, None)
- return False
+ return (False, None)
def openobjectid2uid(cr, uidval, oomodel):
value = 'OpenObject-%s_%s@%s' % (oomodel, uidval, cr.dbname)
@@ -68,7 +71,10 @@ def get_attribute_mapping(cr, uid, calname, context={}):
pool = pooler.get_pool(cr.dbname)
field_obj = pool.get('basic.calendar.fields')
type_obj = pool.get('basic.calendar.lines')
- type_id = type_obj.search(cr, uid, [('object_id.model', '=', context.get('model'))])
+ domain = [('object_id.model', '=', context.get('model'))]
+ if context.get('calendar_id'):
+ domain.append(('calendar_id', '=', context.get('calendar_id')))
+ type_id = type_obj.search(cr, uid, domain)
fids = field_obj.search(cr, uid, [('type_id', '=', type_id[0])])
res = {}
for field in field_obj.browse(cr, uid, fids):
@@ -191,6 +197,8 @@ class CalDAV(object):
self.ical_set(cal_data.name.lower(), vals, 'value')
continue
if cal_data.name.lower() in self.__attribute__:
+ if cal_data.params.get('X-VOBJ-ORIGINAL-TZID'):
+ self.ical_set('vtimezone', cal_data.params.get('X-VOBJ-ORIGINAL-TZID'), 'value')
self.ical_set(cal_data.name.lower(), cal_data.value, 'value')
vals = map_data(cr, uid, self)
return vals
@@ -199,6 +207,7 @@ class CalDAV(object):
if not datas:
return
for data in datas:
+ tzval = None
vevent = ical.add(name)
for field in self.__attribute__.keys():
map_field = self.ical_get(field, 'field')
@@ -236,6 +245,11 @@ class CalDAV(object):
alarm_obj = self.pool.get('basic.calendar.alarm')
vevent = alarm_obj.export_cal(cr, uid, model, \
data[map_field][0], vevent, context=ctx)
+ elif field == 'vtimezone' and data[map_field]:
+ tzval = data[map_field]
+ tz_obj = self.pool.get('basic.calendar.timezone')
+ ical = tz_obj.export_cal(cr, uid, None, \
+ data[map_field], ical, context=context)
elif data[map_field]:
if map_type in ("char", "text"):
vevent.add(field).value = tools.ustr(data[map_field])
@@ -243,7 +257,10 @@ class CalDAV(object):
if field in ('exdate'):
vevent.add(field).value = [parser.parse(data[map_field])]
else:
- vevent.add(field).value = parser.parse(data[map_field])
+ dtfield = vevent.add(field)
+ dtfield.value = parser.parse(data[map_field])
+ if tzval:
+ dtfield.params['TZID'] = [tzval.title()]
elif map_type == "timedelta":
vevent.add(field).value = timedelta(hours=data[map_field])
elif map_type == "many2one":
@@ -295,8 +312,8 @@ class CalDAV(object):
ical_data = base64.decodestring(content)
self.__attribute__ = get_attribute_mapping(cr, uid, self._calname, context)
parsedCal = vobject.readOne(ical_data)
- att_data = []
res = []
+ vals = {}
for child in parsedCal.getChildren():
if child.name.lower() in ('vevent', 'vtodo'):
vals = self.parse_ics(cr, uid, child, context=context)
@@ -307,7 +324,6 @@ class CalDAV(object):
self.ical_reset('value')
return res
-
class Calendar(CalDAV, osv.osv):
_name = 'basic.calendar'
_description = 'Calendar'
@@ -329,28 +345,34 @@ class Calendar(CalDAV, osv.osv):
_columns = {
'name': fields.char("Name", size=64),
'line_ids': fields.one2many('basic.calendar.lines', 'calendar_id', 'Calendar Lines'),
- 'active': fields.boolean('Active'),
+ 'active': fields.boolean('Active'),
+ 'create_date': fields.datetime('Created Date'),
+ 'write_date': fields.datetime('Modifided Date'),
}
_defaults = {
'active': lambda *a: True,
}
- def export_cal(self, cr, uid, datas, vobj='vevent', context={}):
- cal = self.browse(cr, uid, datas[0])
- ical = vobject.iCalendar()
+ def export_cal(self, cr, uid, ids, vobj='vevent', context={}):
+ cal = self.browse(cr, uid, ids[0])
+ ical = vobject.iCalendar()
for line in cal.line_ids:
if line.name in ('valarm', 'attendee'):
continue
mod_obj = self.pool.get(line.object_id.model)
data_ids = mod_obj.search(cr, uid, eval(line.domain), context=context)
datas = mod_obj.read(cr, uid, data_ids, context=context)
- context.update({'model': line.object_id.model})
+ context.update({'model': line.object_id.model,
+ 'calendar_id': cal.id
+ })
self.__attribute__ = get_attribute_mapping(cr, uid, line.name, context)
self.create_ics(cr, uid, datas, line.name, ical, context=context)
return ical.serialize()
def import_cal(self, cr, uid, content, data_id=None, context=None):
+ if not context:
+ context = {}
ical_data = base64.decodestring(content)
parsedCal = vobject.readOne(ical_data)
if not data_id:
@@ -362,7 +384,9 @@ class Calendar(CalDAV, osv.osv):
cal_children[line.name] = line.object_id.model
for child in parsedCal.getChildren():
if child.name.lower() in cal_children:
- context.update({'model': cal_children[child.name.lower()]})
+ context.update({'model': cal_children[child.name.lower()],
+ 'calendar_id': cal.id
+ })
self.__attribute__ = get_attribute_mapping(cr, uid, child.name.lower(), context=context)
val = self.parse_ics(cr, uid, child, cal_children=cal_children, context=context)
obj = self.pool.get(cal_children[child.name.lower()])
@@ -371,7 +395,6 @@ class Calendar(CalDAV, osv.osv):
else:
self.check_import(cr, uid, [val], context=context)
return {}
-
Calendar()
class basic_calendar_line(osv.osv):
@@ -585,15 +608,51 @@ class FreeBusy(CalDAV):
}
-class Timezone(CalDAV):
+class Timezone(CalDAV, osv.osv_memory):
+ _name = 'basic.calendar.timezone'
+ _calname = 'vtimezone'
+
__attribute__ = {
- 'tzid': None, # Use: R-1, Type: Text, Specifies the text value that uniquely identifies the "VTIMEZONE" calendar component.
+ 'tzid': {'field': 'tzid'}, # Use: R-1, Type: Text, Specifies the text value that uniquely identifies the "VTIMEZONE" calendar component.
'last-mod': None, # Use: O-1, Type: DATE-TIME, Specifies the date and time that the information associated with the calendar component was last revised in the calendar store.
'tzurl': None, # Use: O-1, Type: URI, Provides a means for a VTIMEZONE component to point to a network location that can be used to retrieve an up-to-date version of itself.
'standardc': {'tzprop': None}, # Use: R-1,
'daylightc': {'tzprop': None}, # Use: R-1,
'x-prop': None, # Use: O-n, Type: Text,
}
+
+ def get_name_offset(self, cr, uid, tzid, context={}):
+ mytz = pytz.timezone(tzid.title())
+ mydt = datetime.now(tz=mytz)
+ offset = mydt.utcoffset()
+ val = offset.days * 24 + float(offset.seconds) / 3600
+ realoffset = '%02d%02d' % (math.floor(abs(val)), \
+ round(abs(val) % 1 + 0.01, 2) * 60)
+ realoffset = (val < 0 and ('-' + realoffset) or ('+' + realoffset))
+ return (mydt.tzname(), realoffset)
+
+ def export_cal(self, cr, uid, model, tzid, ical, context={}):
+ ctx = context.copy()
+ ctx.update({'model': model})
+ cal_tz = ical.add('vtimezone')
+ cal_tz.add('TZID').value = tzid.title()
+ tz_std = cal_tz.add('STANDARD')
+ tzname, offset = self.get_name_offset(cr, uid, tzid)
+ tz_std.add("TZOFFSETFROM").value = offset
+ tz_std.add("TZOFFSETTO").value = offset
+ tz_std.add("DTSTART").value = datetime.now() # TODO
+ tz_std.add("TZNAME").value = tzname
+ return ical
+
+ def import_cal(self, cr, uid, ical_data, context=None):
+ for child in ical_data.getChildren():
+ if child.name.lower() == 'tzid':
+ tzname = child.value
+ self.ical_set(child.name.lower(), tzname, 'value')
+ vals = map_data(cr, uid, self)
+ return vals
+
+Timezone()
class Alarm(CalDAV, osv.osv_memory):
diff --git a/addons/base_calendar/base_calendar_data.xml b/addons/base_calendar/base_calendar_data.xml
index 0e7250071c8..b15cd72874e 100644
--- a/addons/base_calendar/base_calendar_data.xml
+++ b/addons/base_calendar/base_calendar_data.xml
@@ -1,10 +1,7 @@
-
+
-
- OpenERP
-
diff --git a/addons/base_calendar/base_calendar_node.py b/addons/base_calendar/base_calendar_node.py
new file mode 100644
index 00000000000..1f5a2352b5f
--- /dev/null
+++ b/addons/base_calendar/base_calendar_node.py
@@ -0,0 +1,83 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-2009 Tiny SPRL ().
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+##############################################################################
+
+from osv import osv, fields
+from tools.translate import _
+import pooler
+import tools
+import time
+import base64
+
+class node_calendar(object):
+ def __init__(self, path, context, calendar):
+ self.path = path
+ self.context = context
+ self.calendar_id = calendar.id
+ self.mimetype = 'ics'
+ self.create_date = calendar.create_date
+ self.write_date = calendar.write_date or calendar.create_date
+ self.content_length = 0
+ self.displayname = calendar.name
+
+
+ def get_data(self, cr, uid):
+ calendar_obj = pooler.get_pool(cr.dbname).get('basic.calendar')
+ return calendar_obj.export_cal(cr, uid, [self.calendar_id])
+
+ def get_data_len(self, cr):
+ return self.content_length
+
+ def set_data(self, cr, uid, data):
+ calendar_obj = pooler.get_pool(cr.dbname).get('basic.calendar')
+ return calendar_obj.import_cal(cr, uid, base64.encodestring(data), self.calendar_id)
+
+ def get_etag(self,cr):
+ """ Get a tag, unique per object + modification.
+
+ see. http://tools.ietf.org/html/rfc2616#section-13.3.3 """
+ return self._get_ttag(cr) + ':' + self._get_wtag(cr)
+
+ def _get_wtag(self,cr):
+ """ Return the modification time as a unique, compact string """
+ if self.write_date:
+ wtime = time.mktime(time.strptime(self.write_date,'%Y-%m-%d %H:%M:%S'))
+ else: wtime = time.time()
+ return str(wtime)
+
+ def _get_ttag(self,cr):
+ return 'calendar-%d' % self.calendar_id
+
+class Calendar(osv.osv):
+ _inherit = 'basic.calendar'
+
+ def get_calendar_object(self, cr, uid, uri, context=None):
+ if not uri:
+ return None
+ if len(uri) > 1:
+ return None
+ name, file_type = tuple(uri[0].split('.'))
+ res = self.name_search(cr, uid, name)
+ if not res:
+ return None
+ calendar_id, calendar_name = res[0]
+ calendar = self.browse(cr, uid, calendar_id)
+ return node_calendar(uri, context, calendar)
+Calendar()
diff --git a/addons/base_calendar/cache.py b/addons/base_calendar/cache.py
new file mode 100644
index 00000000000..7f03aa6da13
--- /dev/null
+++ b/addons/base_calendar/cache.py
@@ -0,0 +1,39 @@
+import time
+import heapq
+
+def memoize(maxsize):
+ """decorator to 'memoize' a function - caching its results"""
+ def decorating_function(f):
+ cache = {} # map from key to value
+ heap = [] # list of keys, in LRU heap
+ cursize = 0 # because len() is slow
+ def wrapper(*args):
+ key = repr(args)
+ # performance crap
+ _cache=cache
+ _heap=heap
+ _heappop = heapq.heappop
+ _heappush = heapq.heappush
+ _time = time.time
+ _cursize = cursize
+ _maxsize = maxsize
+ if not _cache.has_key(key):
+ if _cursize == _maxsize:
+ # pop oldest element
+ (_,oldkey) = _heappop(_heap)
+ _cache.pop(oldkey)
+ else:
+ _cursize += 1
+ # insert this element
+ _cache[key] = f(*args)
+ _heappush(_heap,(_time(),key))
+ wrapper.misses += 1
+ else:
+ wrapper.hits += 1
+ return cache[key]
+ wrapper.__doc__ = f.__doc__
+ wrapper.__name__ = f.__name__
+ wrapper.hits = wrapper.misses = 0
+ return wrapper
+ return decorating_function
+
diff --git a/addons/base_calendar/dav_fs.py b/addons/base_calendar/dav_fs.py
new file mode 100644
index 00000000000..e44a41a8e07
--- /dev/null
+++ b/addons/base_calendar/dav_fs.py
@@ -0,0 +1,335 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-2009 Tiny SPRL ().
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+##############################################################################
+
+import pooler
+
+import base64
+import sys
+import os
+import time
+from string import joinfields, split, lower
+
+from service import security
+
+import netsvc
+import urlparse
+
+from DAV.constants import COLLECTION, OBJECT
+from DAV.errors import *
+from DAV.iface import *
+import urllib
+
+from DAV.davcmd import copyone, copytree, moveone, movetree, delone, deltree
+from document.nodes import node_res_dir, node_res_obj
+from cache import memoize
+from tools import misc
+CACHE_SIZE=20000
+
+
+class tinydav_handler(dav_interface):
+ """
+ This class models a Tiny ERP interface for the DAV server
+ """
+ PROPS={'DAV:': dav_interface.PROPS['DAV:'], }
+
+ M_NS={ "DAV:" : dav_interface.M_NS['DAV:'], }
+
+ def __init__(self, parent, verbose=False):
+ self.db_name = False
+ self.parent = parent
+ self.baseuri = parent.baseuri
+
+ def get_propnames(self, uri):
+ props = self.PROPS
+ self.parent.log_message('get propnames: %s' % uri)
+ if uri[-1]=='/':uri=uri[:-1]
+ cr, uid, pool, dbname, uri2 = self.get_cr(uri)
+ if not dbname:
+ cr.close()
+ return props
+ node = self.uri2object(cr,uid,pool, uri2)
+ if node:
+ props.update(node.get_dav_props(cr))
+ cr.close()
+ return props
+
+ def get_prop(self,uri,ns,propname):
+ """ return the value of a given property
+
+ uri -- uri of the object to get the property of
+ ns -- namespace of the property
+ pname -- name of the property
+ """
+ if self.M_NS.has_key(ns):
+ return dav_interface.get_prop(self,uri,ns,propname)
+
+ if uri[-1]=='/':uri=uri[:-1]
+ cr, uid, pool, dbname, uri2 = self.get_cr(uri)
+ if not dbname:
+ cr.close()
+ raise DAV_NotFound
+ node = self.uri2object(cr,uid,pool, uri2)
+ if not node:
+ cr.close()
+ raise DAV_NotFound
+ res = node.get_dav_eprop(cr,ns,propname)
+ cr.close()
+ return res
+
+ def urijoin(self,*ajoin):
+ """ Return the base URI of this request, or even join it with the
+ ajoin path elements
+ """
+ return self.baseuri+ '/'.join(ajoin)
+
+ def uri2local(self, uri):
+ uparts=urlparse.urlparse(uri)
+ reluri=uparts[2]
+ if reluri and reluri[-1]=="/":
+ reluri=reluri[:-1]
+ return reluri
+
+ #
+ # pos: -1 to get the parent of the uri
+ #
+ def get_cr(self, uri):
+ pdb = self.parent.auth_proxy.last_auth
+ reluri = self.uri2local(uri)
+ try:
+ dbname = reluri.split('/')[2]
+ except:
+ dbname = False
+ if not dbname:
+ return None, None, None, False, None
+ if not pdb and dbname:
+ # if dbname was in our uri, we should have authenticated
+ # against that.
+ raise Exception("Programming error")
+ assert pdb == dbname, " %s != %s" %(pdb, dbname)
+ user, passwd, dbn2, uid = self.parent.auth_proxy.auth_creds[pdb]
+ db,pool = pooler.get_db_and_pool(dbname)
+ cr = db.cursor()
+ uri2 = reluri.split('/')[3:]
+ return cr, uid, pool, dbname, uri2
+
+ def uri2object(self, cr, uid, pool, uri):
+ if not uid:
+ return None
+ return pool.get('basic.calendar').get_calendar_object(cr, uid, uri)
+
+ def get_data(self,uri):
+ self.parent.log_message('GET: %s' % uri)
+ if uri[-1]=='/':uri=uri[:-1]
+ cr, uid, pool, dbname, uri2 = self.get_cr(uri)
+ try:
+ if not dbname:
+ raise DAV_Error, 409
+ node = self.uri2object(cr,uid,pool, uri2)
+ if not node:
+ raise DAV_NotFound(uri2)
+ try:
+ datas = node.get_data(cr, uid)
+ except TypeError,e:
+ import traceback
+ self.parent.log_error("GET typeError: %s", str(e))
+ self.parent.log_message("Exc: %s",traceback.format_exc())
+ raise DAV_Forbidden
+ except IndexError,e :
+ self.parent.log_error("GET IndexError: %s", str(e))
+ raise DAV_NotFound(uri2)
+ except Exception,e:
+ import traceback
+ self.parent.log_error("GET exception: %s",str(e))
+ self.parent.log_message("Exc: %s", traceback.format_exc())
+ raise DAV_Error, 409
+ return datas
+ finally:
+ cr.close()
+
+ @memoize(CACHE_SIZE)
+ def _get_dav_resourcetype(self,uri):
+ """ return type of object """
+ self.parent.log_message('get RT: %s' % uri)
+ if uri[-1]=='/':uri=uri[:-1]
+ cr, uid, pool, dbname, uri2 = self.get_cr(uri)
+ try:
+ if not dbname:
+ return COLLECTION
+ node = self.uri2object(cr,uid,pool, uri2)
+ if not node:
+ raise DAV_NotFound(uri2)
+ return OBJECT
+ finally:
+ cr.close()
+
+ def _get_dav_displayname(self,uri):
+ self.parent.log_message('get DN: %s' % uri)
+ if uri[-1]=='/':uri=uri[:-1]
+ cr, uid, pool, dbname, uri2 = self.get_cr(uri)
+ if not dbname:
+ cr.close()
+ return COLLECTION
+ node = self.uri2object(cr,uid,pool, uri2)
+ if not node:
+ cr.close()
+ raise DAV_NotFound(uri2)
+ cr.close()
+ return node.displayname
+
+ @memoize(CACHE_SIZE)
+ def _get_dav_getcontentlength(self,uri):
+ """ return the content length of an object """
+ self.parent.log_message('get length: %s' % uri)
+ if uri[-1]=='/':uri=uri[:-1]
+ result = 0
+ cr, uid, pool, dbname, uri2 = self.get_cr(uri)
+ if not dbname:
+ cr.close()
+ return '0'
+ node = self.uri2object(cr, uid, pool, uri2)
+ if not node:
+ cr.close()
+ raise DAV_NotFound(uri2)
+ result = node.content_length or 0
+ cr.close()
+ return str(result)
+
+ @memoize(CACHE_SIZE)
+ def _get_dav_getetag(self,uri):
+ """ return the ETag of an object """
+ self.parent.log_message('get etag: %s' % uri)
+ if uri[-1]=='/':uri=uri[:-1]
+ result = 0
+ cr, uid, pool, dbname, uri2 = self.get_cr(uri)
+ if not dbname:
+ cr.close()
+ return '0'
+ node = self.uri2object(cr, uid, pool, uri2)
+ if not node:
+ cr.close()
+ raise DAV_NotFound(uri2)
+ result = node.get_etag(cr)
+ cr.close()
+ return str(result)
+
+ @memoize(CACHE_SIZE)
+ def get_lastmodified(self,uri):
+ """ return the last modified date of the object """
+ if uri[-1]=='/':uri=uri[:-1]
+ today = time.time()
+ cr, uid, pool, dbname, uri2 = self.get_cr(uri)
+ try:
+ if not dbname:
+ return today
+ node = self.uri2object(cr,uid,pool, uri2)
+ if not node:
+ raise DAV_NotFound(uri2)
+ if node.write_date:
+ return time.mktime(time.strptime(node.write_date,'%Y-%m-%d %H:%M:%S'))
+ else:
+ return today
+ finally:
+ cr.close()
+
+ @memoize(CACHE_SIZE)
+ def get_creationdate(self,uri):
+ """ return the last modified date of the object """
+
+ if uri[-1]=='/':uri=uri[:-1]
+ cr, uid, pool, dbname, uri2 = self.get_cr(uri)
+ try:
+ if not dbname:
+ raise DAV_Error, 409
+ node = self.uri2object(cr,uid,pool, uri2)
+ if not node:
+ raise DAV_NotFound(uri2)
+ if node.create_date:
+ result = time.strptime(node.create_date,'%Y-%m-%d %H:%M:%S')
+ else:
+ result = time.gmtime()
+ return result
+ finally:
+ cr.close()
+
+ @memoize(CACHE_SIZE)
+ def _get_dav_getcontenttype(self,uri):
+ self.parent.log_message('get contenttype: %s' % uri)
+ if uri[-1]=='/':uri=uri[:-1]
+ cr, uid, pool, dbname, uri2 = self.get_cr(uri)
+ try:
+ if not dbname:
+ return 'httpd/unix-directory'
+ node = self.uri2object(cr,uid,pool, uri2)
+ if not node:
+ raise DAV_NotFound(uri2)
+ result = node.mimetype
+ return result
+ #raise DAV_NotFound, 'Could not find %s' % path
+ finally:
+ cr.close()
+
+
+
+ def put(self, uri, data, content_type=None):
+ """ put the object into the filesystem """
+ self.parent.log_message('Putting %s (%d), %s'%( misc.ustr(uri), len(data), content_type))
+ parent='/'.join(uri.split('/')[:-1])
+ cr, uid, pool,dbname, uri2 = self.get_cr(uri)
+ if not dbname:
+ raise DAV_Forbidden
+ try:
+ node = self.uri2object(cr,uid,pool, uri2[:])
+ except:
+ node = False
+
+ if not node:
+ raise DAV_Forbidden
+ else:
+ try:
+ node.set_data(cr, uid, data)
+ except Exception,e:
+ import traceback
+ self.parent.log_error("Cannot save :%s", str(e))
+ self.parent.log_message("Exc: %s",traceback.format_exc())
+ raise DAV_Forbidden
+
+ cr.commit()
+ cr.close()
+ return 201
+
+
+
+
+ def exists(self,uri):
+ """ test if a resource exists """
+ result = False
+ cr, uid, pool,dbname, uri2 = self.get_cr(uri)
+ if not dbname:
+ cr.close()
+ return True
+ try:
+ node = self.uri2object(cr,uid,pool, uri2)
+ if node:
+ result = True
+ except:
+ pass
+ cr.close()
+ return result
diff --git a/addons/base_calendar/webdav_server.py b/addons/base_calendar/webdav_server.py
new file mode 100644
index 00000000000..9fd6d8bf009
--- /dev/null
+++ b/addons/base_calendar/webdav_server.py
@@ -0,0 +1,79 @@
+# -*- encoding: utf-8 -*-
+
+#
+# Copyright P. Christeas 2008,2009
+#
+#
+# WARNING: This program as such is intended to be used by professional
+# programmers who take the whole responsability of assessing all potential
+# consequences resulting from its eventual inadequacies and bugs
+# End users who are looking for a ready-to-use solution with commercial
+# garantees and support are strongly adviced to contract a Free Software
+# Service Company
+#
+# 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 2
+# 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, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+###############################################################################
+
+
+import netsvc
+from dav_fs import tinydav_handler
+from tools.config import config
+from DAV.WebDAVServer import DAVRequestHandler
+from service.websrv_lib import HTTPDir,FixSendError
+
+class DAVHandler(FixSendError,DAVRequestHandler):
+ verbose = False
+
+ def get_userinfo(self,user,pw):
+ return False
+
+ def _log(self, message):
+ netsvc.Logger().notifyChannel("webdav",netsvc.LOG_DEBUG,message)
+
+ def handle(self):
+ pass
+
+ def finish(self):
+ pass
+
+ def setup(self):
+ davpath = '/calendar/'
+ self.baseuri = "http://%s:%d%s"% (self.server.server_name,self.server.server_port,davpath)
+ self.IFACE_CLASS = tinydav_handler(self)
+ pass
+
+ def log_message(self, format, *args):
+ netsvc.Logger().notifyChannel('webdav',netsvc.LOG_DEBUG_RPC,format % args)
+
+ def log_error(self, format, *args):
+ netsvc.Logger().notifyChannel('webdav',netsvc.LOG_WARNING,format % args)
+
+
+try:
+ from service.http_server import reg_http_service,OpenERPAuthProvider
+ davpath = '/calendar/'
+ handler = DAVHandler
+ handler.verbose = config.get_misc('webdav','verbose',True)
+ handler.debug = config.get_misc('webdav','debug',True)
+ reg_http_service(HTTPDir(davpath,DAVHandler,OpenERPAuthProvider()))
+ netsvc.Logger().notifyChannel('webdav',netsvc.LOG_INFO,"WebDAV service registered at path: %s/ "% davpath)
+except Exception, e:
+ logger = netsvc.Logger()
+ logger.notifyChannel('webdav', netsvc.LOG_ERROR, 'Cannot launch webdav: %s' % e)
+
+#eof
+
+
+
diff --git a/addons/base_contact/i18n/nl.po b/addons/base_contact/i18n/nl.po
index 31eb515e773..21dacd2804b 100644
--- a/addons/base_contact/i18n/nl.po
+++ b/addons/base_contact/i18n/nl.po
@@ -7,13 +7,13 @@ msgstr ""
"Project-Id-Version: OpenERP Server 5.0.0\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2009-08-28 16:01+0000\n"
-"PO-Revision-Date: 2009-12-11 22:28+0000\n"
-"Last-Translator: Pieter J. Kersten (EduSense BV) \n"
+"PO-Revision-Date: 2010-02-01 15:47+0000\n"
+"Last-Translator: Jan Verlaan (Veritos) \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2009-12-16 05:08+0000\n"
+"X-Launchpad-Export-Date: 2010-02-02 04:48+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
#. module: base_contact
@@ -36,7 +36,7 @@ msgstr "res.partner.contact"
msgid ""
"The Object name must start with x_ and not contain any special character !"
msgstr ""
-"De objectnaam moet beginnen met x_ en mag geen speciale karakters bevatten !"
+"De objectnaam moet beginnen met x_ en mag geen speciale tekens bevatten !"
#. module: base_contact
#: field:res.partner.job,function_id:0
diff --git a/addons/base_report_creator/i18n/zh_CN.po b/addons/base_report_creator/i18n/zh_CN.po
index 69e7da8c2f5..cfd7bb92238 100644
--- a/addons/base_report_creator/i18n/zh_CN.po
+++ b/addons/base_report_creator/i18n/zh_CN.po
@@ -7,13 +7,13 @@ msgstr ""
"Project-Id-Version: OpenERP Server 5.0.0\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2009-08-28 16:01+0000\n"
-"PO-Revision-Date: 2009-12-01 15:37+0000\n"
-"Last-Translator: Wei \"oldrev\" Li \n"
+"PO-Revision-Date: 2010-02-01 23:39+0000\n"
+"Last-Translator: mrshelly \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2009-12-16 05:21+0000\n"
+"X-Launchpad-Export-Date: 2010-02-02 04:48+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
#. module: base_report_creator
@@ -22,7 +22,7 @@ msgid ""
"Provide an expression for the field based on which you want to filter the "
"records.\n"
" e.g. res_partner.id=3"
-msgstr ""
+msgstr "可以使用基于字段的Python条件表达式做为过滤条件.(如 res_partner.id=3)"
#. module: base_report_creator
#: field:base_report_creator.report,view_graph_type:0
@@ -406,6 +406,8 @@ msgid ""
"After installing the module, it adds a menu to define custom report in\n"
"the \"Dashboard\" menu.\n"
msgstr ""
+"本模块可以让您使用SQL查询器新建很灵活的对象统计报表.\n"
+"安装此模块后, \"Dashboard(系统面板)\" 上会添加对应的菜单入口.\n"
#. module: base_report_creator
#: selection:base_report_creator.report.fields,calendar_mode:0
diff --git a/addons/caldav/caldav.py b/addons/caldav/caldav.py
index 5741f645b1e..be51f321f9d 100644
--- a/addons/caldav/caldav.py
+++ b/addons/caldav/caldav.py
@@ -19,15 +19,16 @@
#
##############################################################################
+from base_calendar import base_calendar
from datetime import datetime, timedelta
from datetime import datetime, timedelta
from dateutil import parser
from osv import fields, osv
-from base_calendar import base_calendar
from service import web_services
from tools.translate import _
import base64
import pooler
+import pytz
import re
import time
@@ -423,6 +424,9 @@ class calendar_event(osv.osv):
_name = "calendar.event"
_description = "Calendar Event"
__attribute__ = {}
+
+ def _tz_get(self,cr,uid, context={}):
+ return [(x.lower(), x) for x in pytz.all_timezones]
def onchange_rrule_type(self, cr, uid, ids, rtype, *args, **argv):
if rtype == 'none' or not rtype:
@@ -483,7 +487,9 @@ rule or repeating pattern for anexception to a recurrence set"),
'caldav_alarm_id': fields.many2one('calendar.alarm', 'Alarm'),
'recurrent_uid': fields.integer('Recurrent ID'),
'recurrent_id': fields.datetime('Recurrent ID date'),
- }
+ 'vtimezone': fields.selection(_tz_get, 'Timezone', size=64),
+ 'user_id': fields.many2one('res.users', 'Responsible'),
+ }
_defaults = {
'class': lambda *a: 'public',
diff --git a/addons/caldav/caldav_data.xml b/addons/caldav/caldav_data.xml
index 295b05ba540..c8b20ac134b 100644
--- a/addons/caldav/caldav_data.xml
+++ b/addons/caldav/caldav_data.xml
@@ -129,381 +129,5 @@
-
-
- vevent
-
-
-
-
-
- vtodo
-
-
-
-
-
- valarm
-
-
-
-
-
- attendee
-
-
-
-
-
-
-
-
-
-
- field
-
-
-
-
-
-
- field
-
-
-
-
-
-
- field
-
-
-
-
-
-
- field
-
-
-
-
-
-
- field
-
-
-
-
-
-
- field
-
-
-
-
-
-
- field
-
-
-
-
-
-
- field
-
-
-
-
-
-
- field
-
-
-
-
-
-
- field
-
-
-
-
-
-
- field
-
-
-
-
-
-
- field
-
-
-
-
-
-
- field
-
-
-
-
-
-
- field
-
-
-
-
-
-
- field
-
-
-
-
-
-
-
-
- field
-
-
-
-
-
-
- field
-
-
-
-
-
-
- field
-
-
-
-
-
-
- field
-
-
-
-
-
-
- field
-
-
-
-
-
-
- field
-
-
-
-
-
-
- field
-
-
-
-
-
-
- field
-
-
-
-
-
-
- field
-
-
-
-
-
-
- field
-
-
-
-
-
-
- field
-
-
-
-
-
-
- field
-
-
-
-
-
-
-
-
- field
-
-
-
-
-
-
- field
-
-
-
-
-
-
- field
-
-
-
-
-
-
- field
-
-
-
-
-
-
- field
-
-
-
-
-
-
- field
-
-
-
-
-
-
- field
-
-
-
-
-
-
- field
-
-
-
-
-
-
- field
-
-
-
-
-
-
- field
-
-
-
-
-
-
- field
-
-
-
-
-
-
-
- field
-
-
-
-
-
-
- field
-
-
-
-
-
-
- field
-
-
-
-
-
-
- field
-
-
-
-
-
-
- field
-
-
-
-
-
-
- field
-
-
-
-
-
-
- field
-
-
-
-
-
-
- field
-
-
-
-
-
-
- field
-
-
-
-
-
-
- field
-
-
-
-
-
-
- field
-
-
-
diff --git a/addons/caldav/caldav_view.xml b/addons/caldav/caldav_view.xml
index 559c45485cc..4d10b9529f5 100644
--- a/addons/caldav/caldav_view.xml
+++ b/addons/caldav/caldav_view.xml
@@ -65,6 +65,8 @@
+
+
@@ -114,7 +116,7 @@
-
+ calendar.attendee.treecalendar.attendeetree
@@ -126,32 +128,9 @@
-
+
-
- My Invitations
- ir.actions.act_window
- calendar.attendee
- form
- tree,form
-
- [('user_id', '=', uid)]
- {'default_sent_by_uid': uid}
-
-
-
-
- tree
-
-
-
-
-
- form
-
-
- res.alarm.form
@@ -251,7 +230,7 @@
-
+ Custom Ruleir.actions.act_windowcalendar.custom.rrule
@@ -260,9 +239,14 @@
new
-
+
+
+
+
+
+
diff --git a/addons/crm/crm.py b/addons/crm/crm.py
index ed4735a55e8..d9d4c6e6c9d 100644
--- a/addons/crm/crm.py
+++ b/addons/crm/crm.py
@@ -580,7 +580,7 @@ class crm_case(osv.osv):
def __history(self, cr, uid, cases, keyword, history=False, email=False, details=None, context={}):
- model_obj = self.pool.get('ir.model')
+ model_obj = self.pool.get('ir.model')
for case in cases:
model_ids = model_obj.search(cr, uid, [('model','=',case._name)])
data = {
@@ -820,14 +820,7 @@ class crm_case_history(osv.osv):
_name = "crm.case.history"
_description = "Case history"
_order = "id desc"
- _inherits = {'crm.case.log':"log_id"}
-
- def create(self, cr, user, vals, context=None):
- if vals.has_key('res_id') and vals['res_id']:
- case_obj = self.pool.get(vals['model_id'])
- cases = case_obj.browse(cr, user, [vals['res_id']])
- case_obj._action(cr, user, cases, '')
- return super(crm_case_history, self).create(cr, user, vals, context)
+ _inherits = {'crm.case.log':"log_id"}
def _note_get(self, cursor, user, ids, name, arg, context=None):
res = {}
diff --git a/addons/crm/crm_claim.py b/addons/crm/crm_claim.py
index 5e83ce1c367..14921372fad 100644
--- a/addons/crm/crm_claim.py
+++ b/addons/crm/crm_claim.py
@@ -19,16 +19,9 @@
#
##############################################################################
-import tools
from osv import fields, osv
-import os
-import pooler
-import netsvc
-from tools.translate import _
import crm
-
-
class crm_claim(osv.osv):
_name = "crm.claim"
_description = "Claim Cases"
@@ -59,6 +52,7 @@ class crm_claim(osv.osv):
_defaults = {
'priority': lambda *a: crm.AVAILABLE_PRIORITIES[2][0],
}
+
def onchange_categ_id(self, cr, uid, ids, categ, context={}):
if not categ:
return {'value':{}}
diff --git a/addons/crm/crm_claims_view.xml b/addons/crm/crm_claims_view.xml
index 17dd87caa50..5f7e9b07fdc 100644
--- a/addons/crm/crm_claims_view.xml
+++ b/addons/crm/crm_claims_view.xml
@@ -8,24 +8,24 @@
Claim Categoriescrm.case.categform
-
+ [('object_id.model', '=', 'crm.claim')]
- {'object_id':'crm.claim'}
+ {'object_id':'crm.claim'}
# ------------------------------------------------------
# Stages
- # ------------------------------------------------------
+ # ------------------------------------------------------
Claim Stagescrm.case.stageform[('object_id.model', '=', 'crm.claim')]
- {'object_id':'crm.claim'}
+ {'object_id':'crm.claim'}
-
+
CRM - Claims Tree
@@ -169,7 +169,7 @@
-
+
CRM - Claims Searchcrm.claim
@@ -198,12 +198,12 @@
-
+
-
+ />
+
diff --git a/addons/crm/crm_fund_view.xml b/addons/crm/crm_fund_view.xml
index 4fec4afb976..96b0ac51ad9 100644
--- a/addons/crm/crm_fund_view.xml
+++ b/addons/crm/crm_fund_view.xml
@@ -9,9 +9,9 @@
Fundraising Categoriescrm.case.categform
-
- [('object_id.model', '=', 'crm.fundraising')]
- {'object_id':'crm.fundraising'}
+
+ [('object_id.model', '=', 'crm.fundraising')]
+ {'object_id':'crm.fundraising'}
# ------------------------------------------------------
@@ -23,10 +23,10 @@
form[('object_id.model', '=', 'crm.fundraising')]
- {'object_id':'crm.fundraising'}
+ {'object_id':'crm.fundraising'}
-
+
# ------------------------------------------------------
# Fund Raising
# ------------------------------------------------------
@@ -194,12 +194,12 @@
-
+
-
+ />
+
diff --git a/addons/crm/crm_fundraising.py b/addons/crm/crm_fundraising.py
index 046065e61f2..5085f01333f 100644
--- a/addons/crm/crm_fundraising.py
+++ b/addons/crm/crm_fundraising.py
@@ -19,23 +19,9 @@
#
##############################################################################
-import time
-import re
-import os
-
-import mx.DateTime
-import base64
-
-from tools.translate import _
-
-import tools
from osv import fields,osv,orm
-from osv.orm import except_orm
-
import crm
-
-
class crm_fundraising(osv.osv):
_name = "crm.fundraising"
_description = "Fund Raising Cases"
@@ -67,11 +53,11 @@ class crm_fundraising(osv.osv):
_defaults = {
'priority': lambda *a: crm.AVAILABLE_PRIORITIES[2][0],
}
+
def onchange_categ_id(self, cr, uid, ids, categ, context={}):
if not categ:
return {'value':{}}
cat = self.pool.get('crm.case.categ').browse(cr, uid, categ, context).probability
return {'value':{'probability':cat}}
-
crm_fundraising()
diff --git a/addons/crm/crm_helpdesk.py b/addons/crm/crm_helpdesk.py
index ca4bf47006b..13bc13d214c 100644
--- a/addons/crm/crm_helpdesk.py
+++ b/addons/crm/crm_helpdesk.py
@@ -19,23 +19,9 @@
#
##############################################################################
-import time
-import re
-import os
-
-import mx.DateTime
-import base64
-
-from tools.translate import _
-
-import tools
from osv import fields,osv,orm
-from osv.orm import except_orm
-
import crm
-
-
class crm_helpdesk(osv.osv):
_name = "crm.helpdesk"
_description = "Helpdesk Cases"
@@ -57,6 +43,7 @@ class crm_helpdesk(osv.osv):
'categ_id': fields.many2one('crm.case.categ', 'Category', domain="[('section_id','=',section_id),('object_id.model', '=', 'crm.helpdesk')]"),
'duration': fields.float('Duration'),
}
+
def onchange_categ_id(self, cr, uid, ids, categ, context={}):
if not categ:
return {'value':{}}
diff --git a/addons/crm/crm_lead.py b/addons/crm/crm_lead.py
index 9c6ae7bffa7..f346bcf88f7 100644
--- a/addons/crm/crm_lead.py
+++ b/addons/crm/crm_lead.py
@@ -19,22 +19,9 @@
#
##############################################################################
-import time
-import re
-import os
-
-import mx.DateTime
-import base64
-
-from tools.translate import _
-
-import tools
from osv import fields,osv,orm
-from osv.orm import except_orm
-
import crm
-
class crm_opportunity(osv.osv):
_name = "crm.opportunity"
_description = "Opportunity Cases"
@@ -65,9 +52,9 @@ class crm_lead(osv.osv):
'som': fields.many2one('res.partner.som', 'State of Mind', help="The minds states allow to define a value scale which represents" \
"the partner mentality in relation to our services.The scale has" \
"to be created with a factor for each level from 0 (Very dissatisfied) to 10 (Extremely satisfied)."),
-
'opportunity_id': fields.many2one ('crm.opportunity', 'Opportunity'),
}
+
def onchange_categ_id(self, cr, uid, ids, categ, context={}):
if not categ:
return {'value':{}}
diff --git a/addons/crm/crm_lead_view.xml b/addons/crm/crm_lead_view.xml
index 975bb764ce7..2c5024ebd0f 100644
--- a/addons/crm/crm_lead_view.xml
+++ b/addons/crm/crm_lead_view.xml
@@ -2,23 +2,23 @@
-
-
- # ------------------------------------------------------
+
+
+ # ------------------------------------------------------
# Stage
- # ------------------------------------------------------
+ # ------------------------------------------------------
Lead Stagescrm.case.stageform[('object_id.model', '=', 'crm.lead')]
- {'object_id':'crm.lead'}
+ {'object_id':'crm.lead'}
# ------------------------------------------------------
# Leads
- # ------------------------------------------------------
+ # ------------------------------------------------------
CRM - Leads Form
@@ -29,9 +29,9 @@
-
+
-
+
@@ -53,7 +53,7 @@
-
+
-
+
+ />
diff --git a/addons/crm/crm_mailgate.py b/addons/crm/crm_mailgate.py
index 2da93ee3347..e66e2784f2a 100644
--- a/addons/crm/crm_mailgate.py
+++ b/addons/crm/crm_mailgate.py
@@ -49,9 +49,9 @@ class crm_cases(osv.osv):
res = mailgate_obj.partner_get(cr, uid, msg['From'])
if res:
data.update(res)
- res = self.create(cr, uid, data)
+ res = self.create(cr, uid, data)
cases = self.browse(cr, uid, [res])
- self.__history(cr, uid, cases, _('Receive'), history=True, email=msg['From'])
+ self._history(cr, uid, cases, _('Receive'), history=True, email=msg['From'])
return res
def msg_update(self, cr, uid, ids, msg, data={}, default_act='pending'):
@@ -80,7 +80,7 @@ class crm_cases(osv.osv):
res = self.write(cr, uid, ids, data)
cases = self.browse(cr, uid, [res])
- self.__history(cr, uid, cases, _('Receive'), history=True, email=msg['From'])
+ self._history(cr, uid, cases, _('Receive'), history=True, email=msg['From'])
getattr(self,act)(cr, uid, ids)
return res
diff --git a/addons/crm/crm_meeting_data.xml b/addons/crm/crm_meeting_data.xml
index 789708c6a35..09566903d1c 100644
--- a/addons/crm/crm_meeting_data.xml
+++ b/addons/crm/crm_meeting_data.xml
@@ -25,33 +25,101 @@
Case Meetingcrm.meeting
-
+
+
-
+
+
+
+ meeting
+
+
+ vevent
+ [('user_id','=', uid)]
+
+
+
+ valarm
+
+
+
+ attendee
+
+
+
+
+
+
+
+
+
+
+ field
+
-
+
+
+
+
+ field
+
-
+ field
-
+
+
+
+
+
+ field
+
-
+
+
+
+
+ field
+
+
+
+
+
+
+ field
+
+
+ field
-
+
-
+
+
+
+
+
+ field
+
+
+
+
+
+
+ field
+
+
+
@@ -59,5 +127,220 @@
field
+
+
+
+
+ field
+
+
+
+
+
+
+ field
+
+
+
+
+
+
+ field
+
+
+
+
+
+
+ field
+
+
+
+
+
+
+ field
+
+
+
+
+
+
+ field
+
+
+
+
+
+
+ field
+
+
+
+
+
+
+ field
+
+
+
+
+
+
+
+
+ field
+
+
+
+
+
+
+ field
+
+
+
+
+
+
+ field
+
+
+
+
+
+
+ field
+
+
+
+
+
+
+ field
+
+
+
+
+
+
+ field
+
+
+
+
+
+
+ field
+
+
+
+
+
+
+ field
+
+
+
+
+
+
+ field
+
+
+
+
+
+
+ field
+
+
+
+
+
+
+ field
+
+
+
+
+
+
+
+ field
+
+
+
+
+
+
+ field
+
+
+
+
+
+
+ field
+
+
+
+
+
+
+ field
+
+
+
+
+
+
+ field
+
+
+
+
+
+
+ field
+
+
+
+
+
+
+ field
+
+
+
+
+
+
+ field
+
+
+
+
+
+
+ field
+
+
+
+
+
+
+ field
+
+
+
+
+
+
+ field
+
+
+
+
diff --git a/addons/crm/crm_meeting_menu.xml b/addons/crm/crm_meeting_menu.xml
index 678bc72a27d..34d03979897 100644
--- a/addons/crm/crm_meeting_menu.xml
+++ b/addons/crm/crm_meeting_menu.xml
@@ -42,12 +42,6 @@
-
-
-
-
+
+ Meeting Invitations
+ ir.actions.act_window
+ calendar.attendee
+ form
+ tree,form
+
+ [('ref','like','crm.meeting,')]
+ {'default_sent_by_uid': uid}
+
+
+
+
+
Next Meetingscrm.meeting
diff --git a/addons/crm/crm_meeting_view.xml b/addons/crm/crm_meeting_view.xml
index c5231c73752..cd3cce574d5 100644
--- a/addons/crm/crm_meeting_view.xml
+++ b/addons/crm/crm_meeting_view.xml
@@ -9,11 +9,11 @@
Meeting Categoriescrm.case.categform
-
+ [('object_id.model', '=', 'crm.meeting')]
- {'object_id':'crm.meeting'}
+ {'object_id':'crm.meeting'}
-
+
# ------------------------------------------------------
# Meetings
@@ -43,11 +43,11 @@
colspan="1" />
-
+
@@ -88,9 +88,10 @@
-
+
+
@@ -132,10 +133,10 @@
calendar
-
+
-
+
@@ -166,16 +167,16 @@
-
+
-
+ />
+
-
+
diff --git a/addons/crm/crm_opportunity.py b/addons/crm/crm_opportunity.py
index 35a85cad6ee..529bdbf7eb0 100644
--- a/addons/crm/crm_opportunity.py
+++ b/addons/crm/crm_opportunity.py
@@ -19,22 +19,9 @@
#
##############################################################################
-import time
-import re
-import os
-
-import mx.DateTime
-import base64
-
-from tools.translate import _
-
-import tools
from osv import fields,osv,orm
-from osv.orm import except_orm
-
import crm
-
class crm_opportunity(osv.osv):
_name = "crm.opportunity"
_description = "Opportunity Cases"
@@ -58,6 +45,7 @@ class crm_opportunity(osv.osv):
'date_closed': fields.datetime('Closed', readonly=True),
'phonecall_id':fields.many2one ('crm.phonecall', 'Phonecall'),
}
+
def onchange_categ_id(self, cr, uid, ids, categ, context={}):
if not categ:
return {'value':{}}
diff --git a/addons/crm/crm_opportunity_view.xml b/addons/crm/crm_opportunity_view.xml
index a19eb2f3587..0268ffc0b3c 100644
--- a/addons/crm/crm_opportunity_view.xml
+++ b/addons/crm/crm_opportunity_view.xml
@@ -10,14 +10,14 @@
Opportunity Categoriescrm.case.categform
-
+ [('object_id.model', '=', 'crm.opportunity')]
- {'object_id':'crm.opportunity'}
+ {'object_id':'crm.opportunity'}
- # ------------------------------------------------------
+ # ------------------------------------------------------
# Stage
- # ------------------------------------------------------
+ # ------------------------------------------------------
Opportunity Stagescrm.case.stage
@@ -29,7 +29,7 @@
# ------------------------------------------------------
# Opportunities
- # ------------------------------------------------------
+ # ------------------------------------------------------
@@ -52,9 +52,9 @@
-
+
+ name="%(wizard_crm_opportunity_reschedule_phone_call)d" icon="gtk-redo" type="action" />
@@ -172,7 +172,7 @@
-
+
CRM - Opportunities Search
@@ -204,11 +204,11 @@
-
+
-
+ help="My section"/>
+
diff --git a/addons/crm/crm_phonecall.py b/addons/crm/crm_phonecall.py
index 4c548af86e1..5f610860407 100644
--- a/addons/crm/crm_phonecall.py
+++ b/addons/crm/crm_phonecall.py
@@ -19,19 +19,9 @@
#
##############################################################################
-from dateutil.rrule import *
from osv import fields, osv
-import datetime
-import base64
-import re
-import time
-import tools
-
-from tools.translate import _
-
import crm
-
class crm_phonecall(osv.osv):
_name = "crm.phonecall"
_description = "Phonecall Cases"
@@ -53,6 +43,7 @@ class crm_phonecall(osv.osv):
'date_closed': fields.datetime('Closed', readonly=True),
'opportunity_id':fields.many2one ('crm.opportunity', 'Opportunity'),
}
+
def onchange_categ_id(self, cr, uid, ids, categ, context={}):
if not categ:
return {'value':{}}
diff --git a/addons/crm/crm_phonecall_view.xml b/addons/crm/crm_phonecall_view.xml
index 791f0ebeaee..48e6d256924 100644
--- a/addons/crm/crm_phonecall_view.xml
+++ b/addons/crm/crm_phonecall_view.xml
@@ -1,20 +1,20 @@
-
+
# ------------------------------------------------------
# Phonecall Categories
# ------------------------------------------------------
-
+
Phonecall Categoriescrm.case.categform
- [('object_id.model', '=', 'crm.phonecall')]
+ [('object_id.model', '=', 'crm.phonecall')]{'object_id':'crm.phonecall'}
-
+
# ------------------------------------------------------
# Fund Stage
@@ -24,11 +24,11 @@
crm.case.stageform
- [('object_id.model', '=', 'crm.phonecall')]
+ [('object_id.model', '=', 'crm.phonecall')]{'object_id':'crm.phonecall'}
-
+
# ------------------------------------------------------
# Phone Calls
# ------------------------------------------------------
@@ -45,7 +45,7 @@
-
+
@@ -62,12 +62,12 @@
-
+
-
+
-
+
@@ -84,25 +84,25 @@
-
+
-
+
-
-
-
+
+
+
-
+
-
+
@@ -179,11 +179,11 @@
-
+
-
+ help="My section"/>
+
diff --git a/addons/crm/crm_report_view.xml b/addons/crm/crm_report_view.xml
index df76994d9b3..04e4f235988 100644
--- a/addons/crm/crm_report_view.xml
+++ b/addons/crm/crm_report_view.xml
@@ -68,7 +68,7 @@
-
+
diff --git a/addons/crm/crm_view.xml b/addons/crm/crm_view.xml
index 2c8dc9209a9..1c9a7aa2bfd 100644
--- a/addons/crm/crm_view.xml
+++ b/addons/crm/crm_view.xml
@@ -48,9 +48,9 @@
- # ------------------------------------------------------
+ # ------------------------------------------------------
# Stage
- # ------------------------------------------------------
+ # ------------------------------------------------------
crm.case.stage.treecrm.case.stage
@@ -92,7 +92,7 @@
@@ -117,7 +117,7 @@
-
+
@@ -442,11 +442,11 @@
-
+
-
+
Casescrm.case
@@ -507,8 +507,8 @@
-
-
+
+
diff --git a/addons/crm/i18n/es.po b/addons/crm/i18n/es.po
index 2440d434cc2..b03bf59f360 100644
--- a/addons/crm/i18n/es.po
+++ b/addons/crm/i18n/es.po
@@ -7,19 +7,19 @@ msgstr ""
"Project-Id-Version: OpenERP Server 5.0.0\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2010-01-05 05:59+0000\n"
-"PO-Revision-Date: 2010-01-17 17:11+0000\n"
-"Last-Translator: Jaerhigo \n"
+"PO-Revision-Date: 2010-02-02 02:48+0000\n"
+"Last-Translator: Carlos Alberto Ospina \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2010-01-18 04:44+0000\n"
+"X-Launchpad-Export-Date: 2010-02-02 04:48+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
#. module: crm
#: field:crm.email.add.cc,name:0
msgid "Send to"
-msgstr ""
+msgstr "Enviar a"
#. module: crm
#: help:crm.meeting,exdate:0
@@ -33,16 +33,18 @@ msgstr ""
msgid ""
"Check this if you want the rule to send an email to the responsible person."
msgstr ""
+"Revise esto si quiere la regla para enviar un correo a la persona "
+"responsable."
#. module: crm
#: view:crm.meeting:0
msgid "Title"
-msgstr ""
+msgstr "Título"
#. module: crm
#: model:ir.model,name:crm.model_report_crm_case_section_categ2
msgid "Cases by section and category2"
-msgstr "Casos segmentados por sección y categoría 2"
+msgstr "Casos por sección y categoria2"
#. module: crm
#: wizard_field:crm.lead.partner_create,init,close:0
@@ -55,22 +57,22 @@ msgstr ""
#: view:crm.opportunity:0
#: view:crm.phonecall:0
msgid " 7 Days "
-msgstr ""
+msgstr " 7 días "
#. module: crm
#: help:crm.menu.config_wizard,helpdesk:0
msgid "Manages an Helpdesk service."
-msgstr ""
+msgstr "Gestiona un servicio de mesa de ayuda"
#. module: crm
#: view:crm.job:0
msgid "Pending Jobs"
-msgstr ""
+msgstr "Trabajos pendientes"
#. module: crm
#: field:crm.case.rule,trg_state_to:0
msgid "Button Pressed"
-msgstr "Botón presionado"
+msgstr "Botón oprimido"
#. module: crm
#: view:crm.case:0
@@ -85,7 +87,7 @@ msgstr "Requerimiento de trabajo a finalizar"
#. module: crm
#: field:crm.case.stage,name:0
msgid "Stage Name"
-msgstr ""
+msgstr "Nombre de etapa"
#. module: crm
#: view:crm.case:0
@@ -109,12 +111,12 @@ msgstr ""
#. module: crm
#: model:ir.ui.menu,name:crm.menu_hr
msgid "Human Resources"
-msgstr ""
+msgstr "Recursos humanos"
#. module: crm
#: model:ir.ui.menu,name:crm.menu_action_report_crm_case_oppor_categ_categ2
msgid "Cases by Opportunities, Category and Type"
-msgstr ""
+msgstr "Casos por oportunidades, categoria y tipo"
#. module: crm
#: help:crm.menu.config_wizard,claims:0
@@ -122,22 +124,24 @@ msgid ""
"Manages the supplier and customers claims, including your corrective or "
"preventive actions."
msgstr ""
+"Gestiona los reclamos de proveedores y clientes, incluyendon sus acciones "
+"prevenivas ó correctivas."
#. module: crm
#: view:crm.fundraising:0
msgid "Amount"
-msgstr ""
+msgstr "Cantidad"
#. module: crm
#: model:process.transition,note:crm.process_transition_opportunitymeeting0
msgid "Normal or phone meeting for opportunity"
-msgstr ""
+msgstr "Oportunidad de reunion normal ó telefonico."
#. module: crm
#: model:crm.case.stage,name:crm.stage_claim2
#: model:crm.case.stage,name:crm.stage_meet1
msgid "Fixed"
-msgstr ""
+msgstr "Reparado"
#. module: crm
#: code:addons/crm/crm.py:0
@@ -146,35 +150,35 @@ msgstr ""
#: code:addons/crm/wizard/crm_phonecall_wizard.py:0
#, python-format
msgid "Warning !"
-msgstr "¡Atención!"
+msgstr "Advertencia !"
#. module: crm
#: code:addons/crm/wizard/wizard_crm_new_send_email.py:0
#, python-format
msgid "Please specify user's email address !"
-msgstr ""
+msgstr "Por favor especiificar el nombre de usuario de correo"
#. module: crm
#: model:crm.case.categ,name:crm.categ_oppor5
msgid "Campaign"
-msgstr ""
+msgstr "Campaña"
#. module: crm
#: view:crm.opportunity:0
msgid "Search Opportunities"
-msgstr ""
+msgstr "Busqueda de oportunidades"
#. module: crm
#: model:ir.ui.menu,name:crm.menu_crm_case_section_stage_tree
#: view:report.crm.case.section.stage:0
msgid "Cases by Section and Stage"
-msgstr ""
+msgstr "Casos por sección y estados"
#. module: crm
#: wizard_field:crm.job.meeting_set,init,duration:0
#: wizard_field:crm.phonecall.meeting_set,init,duration:0
msgid "Duration (Hours)"
-msgstr ""
+msgstr "Duración (Horas)"
#. module: crm
#: selection:crm.meeting,transparent:0
@@ -194,6 +198,8 @@ msgid ""
"Section to which Case belongs to. Define Responsible user and Email account "
"for mail gateway."
msgstr ""
+"Sección a la cual pertenece el caso. Definir usuario responsable y cuenta de "
+"correo para correo de salida."
#. module: crm
#: view:crm.case:0
@@ -212,7 +218,7 @@ msgstr ""
#: wizard_field:crm.phonecall.opportunity_set,opportunity,partner_id:0
#: model:process.node,name:crm.process_node_partner0
msgid "Partner"
-msgstr "Empresa"
+msgstr "Compañero"
#. module: crm
#: field:crm.case.categ,section_id:0
@@ -227,12 +233,13 @@ msgstr "Sección del caso"
#. module: crm
#: view:crm.job:0
msgid "Proposed Salary"
-msgstr ""
+msgstr "Salario sugerido"
#. module: crm
#: help:crm.case.section,sequence:0
msgid "Gives the sequence order when displaying a list of case sections."
msgstr ""
+"Dar orden de la secuencia cuando se muestre la lista de casos de sección."
#. module: crm
#: code:addons/crm/wizard/crm_job_wizard.py:0
@@ -240,17 +247,17 @@ msgstr ""
#: model:crm.case.categ,name:crm.categ_meet3
#, python-format
msgid "Phone Call"
-msgstr ""
+msgstr "Llamada de telefono"
#. module: crm
#: model:ir.model,name:crm.model_report_crm_case_section_stage
msgid "Cases by section and stage"
-msgstr ""
+msgstr "Casos por secciòn y estado"
#. module: crm
#: field:crm.case.rule,act_mail_to_email:0
msgid "Mail to these emails"
-msgstr "Enviar correo a estos emails"
+msgstr "Correo a estos correos electronicos"
#. module: crm
#: selection:crm.case.rule,trg_date_type:0
@@ -260,7 +267,7 @@ msgstr "Ninguno"
#. module: crm
#: view:crm.case.rule:0
msgid "Special Keywords to Be Used in The Body"
-msgstr "Palabras clave especiales para ser usadas en el mensaje"
+msgstr "Palabras claves especiales para ser usadas en el cuerpo del mensaje."
#. module: crm
#: view:crm.case:0
@@ -270,12 +277,12 @@ msgstr "Palabras clave especiales para ser usadas en el mensaje"
#: view:crm.lead:0
#: view:crm.opportunity:0
msgid "Send New Email"
-msgstr ""
+msgstr "Enviar nuevo correo eléctronico"
#. module: crm
#: view:crm.case.history:0
msgid "My Histories"
-msgstr "Mis historiales"
+msgstr "Mis historias"
#. module: crm
#: field:crm.segmentation,segmentation_line:0
@@ -286,12 +293,13 @@ msgstr "Criterios"
#: model:ir.actions.act_window,name:crm.crm_case_section_act
#: model:ir.ui.menu,name:crm.menu_crm_case_section_act
msgid "Sections"
-msgstr "Secciones"
+msgstr "Secciónes"
#. module: crm
#: help:crm.menu.config_wizard,opportunity:0
msgid "Tracks identified business opportunities for your sales pipeline."
msgstr ""
+"Temas de oportunidades de negocio identificadas para su canal de ventas."
#. module: crm
#: view:crm.meeting:0
@@ -301,12 +309,12 @@ msgstr ""
#. module: crm
#: selection:crm.case.rule,trg_date_type:0
msgid "Last Action Date"
-msgstr "Fecha última acción"
+msgstr "Fechas de ultima acción"
#. module: crm
#: view:crm.job:0
msgid "Appreciation"
-msgstr ""
+msgstr "Reconocimiento"
#. module: crm
#: model:crm.case.stage,name:crm.stage_job3
@@ -316,7 +324,7 @@ msgstr ""
#. module: crm
#: model:ir.actions.wizard,name:crm.wizard_crm_cal_subscribe
msgid "Subscribe to a Remote calendar"
-msgstr ""
+msgstr "Suscribirse a un calendario remoto"
#. module: crm
#: model:ir.actions.act_window,name:crm.crm_case_categ-act
@@ -328,7 +336,7 @@ msgstr "Categorías"
#: code:addons/crm/wizard/wizard_crm_new_send_email.py:0
#, python-format
msgid "Warning!"
-msgstr ""
+msgstr "Advertencia!"
#. module: crm
#: view:crm.case:0
@@ -348,29 +356,29 @@ msgstr "Prueba de segmentación"
#. module: crm
#: model:process.transition,name:crm.process_transition_leadpartner0
msgid "Prospect Partner"
-msgstr ""
+msgstr "Socio prospecto"
#. module: crm
#: view:crm.fundraising:0
#: view:crm.opportunity:0
msgid "Description Information"
-msgstr ""
+msgstr "Información de descripción"
#. module: crm
#: view:crm.lead:0
msgid "Contact Name"
-msgstr ""
+msgstr "Nombre de contacto"
#. module: crm
#: selection:crm.lead.opportunity_set,create_partner,action:0
#: selection:crm.phonecall.opportunity_set,create_partner,action:0
msgid "Link to an existing partner"
-msgstr ""
+msgstr "Enlace al socio existente"
#. module: crm
#: field:crm.case.rule,trg_date_range_type:0
msgid "Delay type"
-msgstr "Tipo de demora"
+msgstr "Tipo de retraso"
#. module: crm
#: view:crm.claim:0
@@ -380,12 +388,12 @@ msgstr "Tipo de demora"
#: view:crm.opportunity:0
#: view:crm.phonecall:0
msgid "Contact"
-msgstr ""
+msgstr "Contacto"
#. module: crm
#: view:crm.job:0
msgid "Next Interview"
-msgstr ""
+msgstr "Próxima entrevista"
#. module: crm
#: field:crm.case.rule,regex_history:0
diff --git a/addons/crm/wizard/crm_lead_wizard.py b/addons/crm/wizard/crm_lead_wizard.py
index a7c24863ee1..95127336a4c 100644
--- a/addons/crm/wizard/crm_lead_wizard.py
+++ b/addons/crm/wizard/crm_lead_wizard.py
@@ -62,6 +62,15 @@ class lead2opportunity(wizard.interface):
'probability': {'type':'float', 'digits':(16,2), 'string': 'Success Probability'},
'partner_id' : {'type':'many2one', 'relation':'res.partner', 'string':'Partner'},
}
+
+ def _check_state(self, cr, uid, data, context):
+ pool = pooler.get_pool(cr.dbname)
+ case_obj = pool.get('crm.lead')
+ for case in case_obj.browse(cr, uid, data['ids']):
+ if case.state != 'open':
+ raise wizard.except_wizard(_('Warning !'),
+ _('Lead should be in \'Open\' state before converting to Opportunity.'))
+ return {}
def _selectopportunity(self, cr, uid, data, context):
pool = pooler.get_pool(cr.dbname)
@@ -105,6 +114,7 @@ class lead2opportunity(wizard.interface):
'partner_id': data['form']['partner_id'],
'section_id':lead.section_id.id,
'description':lead.description,
+ 'date_deadline': lead.date_deadline,
'partner_address_id':lead.partner_address_id.id,
'priority':lead.priority,
})
@@ -170,7 +180,7 @@ class lead2opportunity(wizard.interface):
states = {
'init': {
- 'actions': [],
+ 'actions': [_check_state],
'result': {'type':'choice','next_state':_selectChoice}
},
'create_partner': {
diff --git a/addons/crm/wizard/crm_opportunity_wizard.py b/addons/crm/wizard/crm_opportunity_wizard.py
index 945f92ea688..960baca12ad 100644
--- a/addons/crm/wizard/crm_opportunity_wizard.py
+++ b/addons/crm/wizard/crm_opportunity_wizard.py
@@ -56,6 +56,10 @@ class opportunity2phonecall(wizard.interface):
case_obj = pooler.get_pool(cr.dbname).get('crm.opportunity')
categ_id = pooler.get_pool(cr.dbname).get('crm.case.categ').search(cr, uid, [('name','=','Outbound')])
case = case_obj.browse(cr, uid, data['id'])
+ if case.state != 'open':
+ raise wizard.except_wizard(_('Warning !'),
+ _('Opportunity should be in \'Open\' state before converting to Phone Call.'))
+ return {}
return {
'user_id' : case.user_id and case.user_id.id,
'category_id' : categ_id and categ_id[0] or case.categ_id and case.categ_id.id,
diff --git a/addons/crm/wizard/crm_phonecall_wizard.py b/addons/crm/wizard/crm_phonecall_wizard.py
index e341e46f03e..581c8019d87 100644
--- a/addons/crm/wizard/crm_phonecall_wizard.py
+++ b/addons/crm/wizard/crm_phonecall_wizard.py
@@ -62,6 +62,15 @@ class phonecall2opportunity(wizard.interface):
'probability': {'type':'float', 'digits':(16,2), 'string': 'Success Probability'},
'partner_id' : {'type':'many2one', 'relation':'res.partner', 'string':'Partner'},
}
+
+ def _check_state(self, cr, uid, data, context):
+ pool = pooler.get_pool(cr.dbname)
+ case_obj = pool.get('crm.phonecall')
+ for case in case_obj.browse(cr, uid, data['ids']):
+ if case.state != 'open':
+ raise wizard.except_wizard(_('Warning !'),
+ _('Phone Call state should be \'Open\' before converting to Opportunity.'))
+ return {}
def _selectopportunity(self, cr, uid, data, context):
pool = pooler.get_pool(cr.dbname)
@@ -164,7 +173,7 @@ class phonecall2opportunity(wizard.interface):
states = {
'init': {
- 'actions': [],
+ 'actions': [_check_state],
'result': {'type':'choice','next_state':_selectChoice}
},
'create_partner': {
diff --git a/addons/crm_project/crm_project_bug.py b/addons/crm_project/crm_project_bug.py
index fa408b8a570..6e56e0e3746 100644
--- a/addons/crm_project/crm_project_bug.py
+++ b/addons/crm_project/crm_project_bug.py
@@ -54,20 +54,20 @@ class crm_project_bug(osv.osv):
'categ_id': fields.many2one('crm.case.categ','Category', domain="[('section_id','=',section_id),('object_id.model', '=', 'crm.project.bug')]"),
'priority': fields.selection(crm.AVAILABLE_PRIORITIES, 'Priority'),
'type_id': fields.many2one('crm.case.resource.type', 'Bug Type', domain="[('section_id','=',section_id),('object_id.model', '=', 'crm.project.bug')]"),
-
+
'partner_name': fields.char("Employee's Name", size=64),
'partner_mobile': fields.char('Mobile', size=32),
'partner_phone': fields.char('Phone', size=32),
'stage_id': fields.many2one ('crm.case.stage', 'Stage', domain="[('section_id','=',section_id),('object_id.model', '=', 'crm.project.bug')]"),
'project_id':fields.many2one('project.project', 'Project'),
'duration': fields.float('Duration') ,
- 'probability': fields.float('Probability (%)'),
+ 'probability': fields.float('Probability (%)'),
}
def _get_project(self, cr, uid, context):
user = self.pool.get('res.users').browse(cr,uid,uid, context=context)
if user.context_project_id:
- return user.context_project_id.id
+ return user.context_project_id
return False
_defaults = {
@@ -77,8 +77,8 @@ class crm_project_bug(osv.osv):
if not categ:
return {'value':{}}
cat = self.pool.get('crm.case.categ').browse(cr, uid, categ, context).probability
- return {'value':{'probability':cat}}
-
+ return {'value':{'probability':cat}}
+
crm_project_bug()
diff --git a/addons/crm_project/crm_project_feature.py b/addons/crm_project/crm_project_feature.py
index 18674cda5db..77314ec32de 100644
--- a/addons/crm_project/crm_project_feature.py
+++ b/addons/crm_project/crm_project_feature.py
@@ -38,7 +38,7 @@ class crm_project_future_request(osv.osv):
_name = "crm.project.future"
_description = "Project Future Request"
_order = "id desc"
- _inherit = 'crm.case'
+ _inherit = 'crm.case'
_columns = {
'date_closed': fields.datetime('Closed', readonly=True),
'ref' : fields.reference('Reference', selection=crm._links_get, size=128),
@@ -53,19 +53,19 @@ class crm_project_future_request(osv.osv):
'categ_id': fields.many2one('crm.case.categ','Category', domain="[('section_id','=',section_id),('object_id.model', '=', 'crm.project.future')]"),
'priority': fields.selection(crm.AVAILABLE_PRIORITIES, 'Priority'),
'type_id': fields.many2one('crm.case.resource.type', 'Bug Type', domain="[('section_id','=',section_id),('object_id.model', '=', 'crm.project.future')]"),
-
+
'partner_name': fields.char("Employee's Name", size=64),
'partner_mobile': fields.char('Mobile', size=32),
'partner_phone': fields.char('Phone', size=32),
'stage_id': fields.many2one ('crm.case.stage', 'Stage', domain="[('section_id','=',section_id),('object_id.model', '=', 'crm.project.future')]"),
'project_id':fields.many2one('project.project', 'Project'),
'duration': fields.float('Duration') ,
- 'probability': fields.float('Probability (%)'),
+ 'probability': fields.float('Probability (%)'),
}
def _get_project(self, cr, uid, context):
user = self.pool.get('res.users').browse(cr,uid,uid, context=context)
if user.context_project_id:
- return user.context_project_id.id
+ return user.context_project_id
return False
_defaults = {
@@ -76,7 +76,7 @@ class crm_project_future_request(osv.osv):
return {'value':{}}
cat = self.pool.get('crm.case.categ').browse(cr, uid, categ, context).probability
return {'value':{'probability':cat}}
-
+
crm_project_future_request()
diff --git a/addons/document/i18n/nl.po b/addons/document/i18n/nl.po
index 9f209e78421..5197edaa718 100644
--- a/addons/document/i18n/nl.po
+++ b/addons/document/i18n/nl.po
@@ -7,13 +7,13 @@ msgstr ""
"Project-Id-Version: OpenERP Server 5.0.0\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2009-08-28 16:01+0000\n"
-"PO-Revision-Date: 2009-12-11 13:36+0000\n"
-"Last-Translator: Pieter J. Kersten (EduSense BV) \n"
+"PO-Revision-Date: 2010-02-01 15:45+0000\n"
+"Last-Translator: Jan Verlaan (Veritos) \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2009-12-16 05:25+0000\n"
+"X-Launchpad-Export-Date: 2010-02-02 04:48+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
#. module: document
@@ -29,14 +29,14 @@ msgstr "Bron ID"
#. module: document
#: field:document.directory.content,include_name:0
msgid "Include Record Name"
-msgstr ""
+msgstr "Inclusief naam record"
#. module: document
#: constraint:ir.model:0
msgid ""
"The Object name must start with x_ and not contain any special character !"
msgstr ""
-"De objectnaam moet beginnen met x_ en mag geen speciale karakters bevatten !"
+"De objectnaam moet beginnen met x_ en mag geen speciale tekens bevatten !"
#. module: document
#: field:ir.actions.report.xml,model_id:0
diff --git a/addons/document/i18n/zh_CN.po b/addons/document/i18n/zh_CN.po
index ec7a89be34a..e7c646b4847 100644
--- a/addons/document/i18n/zh_CN.po
+++ b/addons/document/i18n/zh_CN.po
@@ -7,24 +7,24 @@ msgstr ""
"Project-Id-Version: OpenERP Server 5.0.0\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2009-08-28 16:01+0000\n"
-"PO-Revision-Date: 2009-12-28 08:46+0000\n"
-"Last-Translator: Jeroen Vet \n"
+"PO-Revision-Date: 2010-02-01 23:45+0000\n"
+"Last-Translator: mrshelly \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2009-12-29 04:35+0000\n"
+"X-Launchpad-Export-Date: 2010-02-02 04:48+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
#. module: document
#: field:document.directory,create_date:0
msgid "Date Created"
-msgstr "已建立日期"
+msgstr "创建时间"
#. module: document
#: field:document.directory,ressource_id:0
msgid "Resource ID"
-msgstr "资源编码"
+msgstr "资源ID"
#. module: document
#: field:document.directory.content,include_name:0
@@ -40,7 +40,7 @@ msgstr "对象名必须以“x_”开始且不能包含任何特殊字符!"
#. module: document
#: field:ir.actions.report.xml,model_id:0
msgid "Model Id"
-msgstr "模式标识符(ID)"
+msgstr "模块ID"
#. module: document
#: constraint:document.directory:0
diff --git a/addons/document_caldav/__terp__.py b/addons/document_caldav/__terp__.py
deleted file mode 100644
index d7480c734bd..00000000000
--- a/addons/document_caldav/__terp__.py
+++ /dev/null
@@ -1,37 +0,0 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-# OpenERP, Open Source Management Solution
-# Copyright (C) 2004-2010 Tiny SPRL ().
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero 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 Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see .
-#
-##############################################################################
-
-
-{
- 'name': 'Support for caldav based on Document Management System',
- 'version': '1.0',
- 'category': 'Generic Modules/Others',
- 'description': """Allows to synchronise calendars with others applications.""",
- 'author': 'Tiny',
- 'website': 'http://www.openerp.com',
- 'depends': ['caldav','document_webdav', 'crm'],
- 'init_xml': ['document_data.xml'],
- 'update_xml': ['document_view.xml'],
- 'demo_xml': ['document_demo.xml'],
- 'installable': True,
- 'active': False,
-}
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/document_caldav/document_caldav.py b/addons/document_caldav/document_caldav.py
deleted file mode 100644
index 01af5d0d345..00000000000
--- a/addons/document_caldav/document_caldav.py
+++ /dev/null
@@ -1,60 +0,0 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-# OpenERP, Open Source Management Solution
-# Copyright (C) 2004-2010 Tiny SPRL ().
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero 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 Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see .
-#
-##############################################################################
-
-from document.nodes import node_content
-from osv import osv, fields
-from osv.orm import except_orm
-import base64
-import os
-
-class document_directory_content(osv.osv):
- _inherit = 'document.directory.content'
- _columns = {
- 'object_id': fields.many2one('ir.model', 'Object', required=True),
- }
-
- def process_write(self, cr, uid, node, data, context=None):
- if node.extension != '.ics':
- return super(document_directory_content, self).process_write(cr, uid, node, data, context)
- content = self.browse(cr, uid, node.cnt_id, context)
- fobj = self.pool.get(content.object_id.model)
- if not context:
- context = {}
- fobj.import_cal(cr, uid, base64.encodestring(data), context=context)
- return True
-
- def process_read(self, cr, uid, node, context=None):
- ctx = (context or {})
- ctx.update(node.context.context.copy())
- ctx.update(node.dctx)
- content = self.browse(cr, uid, node.cnt_id, ctx)
- obj_class = self.pool.get(content.object_id.model)
- domain = []
- if node.act_id:
- domain.append(('id','=',node.act_id))
- # print "process read clause:",domain
- ids = obj_class.search(cr, uid, domain, context=ctx)
- ctx.update({'model': content.object_id.model})
- s = obj_class.export_cal(cr, uid, ids, context=ctx)
- return s
-document_directory_content()
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
-
diff --git a/addons/document_caldav/document_data.xml b/addons/document_caldav/document_data.xml
deleted file mode 100644
index aa9009aadb1..00000000000
--- a/addons/document_caldav/document_data.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
- .ics
- ICS Calendar
- text/calendar
-
-
-
-
diff --git a/addons/document_caldav/document_demo.xml b/addons/document_caldav/document_demo.xml
deleted file mode 100644
index 6a0e4d10d7b..00000000000
--- a/addons/document_caldav/document_demo.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
- Meeting Calendars
-
-
-
- Meeting Calendars
- meetings
-
- .ics
-
-
-
-
-
-
diff --git a/addons/document_caldav/document_view.xml b/addons/document_caldav/document_view.xml
deleted file mode 100644
index ce937d1e286..00000000000
--- a/addons/document_caldav/document_view.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
-
-
-
- document.directory
- document.directory
- form
-
-
-
-
-
-
-
-
-
-
diff --git a/addons/google_map/i18n/hi.po b/addons/google_map/i18n/hi.po
new file mode 100644
index 00000000000..c7c53978b40
--- /dev/null
+++ b/addons/google_map/i18n/hi.po
@@ -0,0 +1,48 @@
+# Hindi translation for openobject-addons
+# Copyright (c) 2010 Rosetta Contributors and Canonical Ltd 2010
+# This file is distributed under the same license as the openobject-addons package.
+# FIRST AUTHOR , 2010.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: openobject-addons\n"
+"Report-Msgid-Bugs-To: FULL NAME \n"
+"POT-Creation-Date: 2009-08-28 16:01+0000\n"
+"PO-Revision-Date: 2010-02-01 07:18+0000\n"
+"Last-Translator: vir (Open ERP) \n"
+"Language-Team: Hindi \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Launchpad-Export-Date: 2010-02-02 04:48+0000\n"
+"X-Generator: Launchpad (build Unknown)\n"
+
+#. module: google_map
+#: model:ir.actions.wizard,name:google_map.wizard_google_map
+msgid "Launch Google Map"
+msgstr "आरम्भ करना Google Map"
+
+#. module: google_map
+#: constraint:ir.ui.view:0
+msgid "Invalid XML for View Architecture!"
+msgstr ""
+
+#. module: google_map
+#: view:res.partner:0
+#: view:res.partner.address:0
+msgid "Street2 : "
+msgstr "स्ट्रीट 2 "
+
+#. module: google_map
+#: model:ir.module.module,description:google_map.module_meta_information
+msgid ""
+"The module adds google map field in partner address\n"
+"so that we can directly open google map from the\n"
+"url widget."
+msgstr ""
+
+#. module: google_map
+#: view:res.partner:0
+#: view:res.partner.address:0
+msgid "Map"
+msgstr "नक़्शा"
diff --git a/addons/hr/i18n/nl.po b/addons/hr/i18n/nl.po
index 2fce7513ed7..62faff002b0 100644
--- a/addons/hr/i18n/nl.po
+++ b/addons/hr/i18n/nl.po
@@ -7,13 +7,13 @@ msgstr ""
"Project-Id-Version: OpenERP Server 5.0.0\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2009-08-28 16:01+0000\n"
-"PO-Revision-Date: 2009-12-11 13:55+0000\n"
-"Last-Translator: Pieter J. Kersten (EduSense BV) \n"
+"PO-Revision-Date: 2010-02-01 16:11+0000\n"
+"Last-Translator: Jan Verlaan (Veritos) \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2009-12-16 05:21+0000\n"
+"X-Launchpad-Export-Date: 2010-02-02 04:48+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
#. module: hr
@@ -110,7 +110,7 @@ msgstr "Werkt van"
#. module: hr
#: model:ir.actions.act_window,name:hr.action2
msgid "Employee Hierarchy"
-msgstr "Medewerkershiërarchie"
+msgstr "Werknemershiërarchie"
#. module: hr
#: model:ir.ui.menu,name:hr.menu_hr_configuration
@@ -130,7 +130,7 @@ msgstr "Vrouw"
#. module: hr
#: view:hr.timesheet.group:0
msgid "Working Time Category"
-msgstr "Werktijdcategorie"
+msgstr "Werktijd categorie"
#. module: hr
#: model:ir.actions.act_window,name:hr.open_view_employee_tree
@@ -232,7 +232,7 @@ msgstr "Gehuwd"
#. module: hr
#: field:hr.timesheet,tgroup_id:0
msgid "Employee's timesheet group"
-msgstr "Medewerkers urenstaatgroep"
+msgstr "Werknemers urenstaatgroep"
#. module: hr
#: selection:hr.employee,gender:0
@@ -305,7 +305,7 @@ msgstr "Dag van de week"
#. module: hr
#: field:hr.employee,birthday:0
msgid "Birthday"
-msgstr "Verjaardag"
+msgstr "Geboortedatum"
#. module: hr
#: field:hr.employee,active:0
@@ -325,12 +325,12 @@ msgstr "Contractproces werknemer"
#. module: hr
#: model:process.node,note:hr.process_node_openerpuser0
msgid "Create OpenERP User"
-msgstr "Maak een OpenERP gebruiker"
+msgstr "Maak een OpenERP gebruiker aan"
#. module: hr
#: model:process.node,note:hr.process_node_employee0
msgid "Employee Complete Form"
-msgstr "Maak formulier compleet"
+msgstr "Maak werknemersformulier compleet"
#. module: hr
#: view:hr.department:0
@@ -356,7 +356,7 @@ msgstr "Startdatum"
#. module: hr
#: field:res.users,parent_id:0
msgid "Parent Users"
-msgstr "Hoofdgebruikers"
+msgstr "Bovenliggende gebruikers"
#. module: hr
#: field:hr.employee,address_id:0
@@ -383,7 +383,7 @@ msgstr "Persoonlijke gegevens"
msgid ""
"The Object name must start with x_ and not contain any special character !"
msgstr ""
-"De objectnaam moet beginnen met x_ en mag geen speciale karakters bevatten !"
+"De objectnaam moet beginnen met x_ en mag geen speciale tekens bevatten !"
#. module: hr
#: view:hr.timesheet:0
@@ -420,7 +420,7 @@ msgstr "Privé-adres"
#. module: hr
#: view:hr.department:0
msgid "department"
-msgstr "Afdeling"
+msgstr "afdeling"
#. module: hr
#: field:hr.employee,country_id:0
diff --git a/addons/hr_expense/i18n/nl.po b/addons/hr_expense/i18n/nl.po
index e3d4b1ef2d4..98deba3e919 100644
--- a/addons/hr_expense/i18n/nl.po
+++ b/addons/hr_expense/i18n/nl.po
@@ -7,13 +7,13 @@ msgstr ""
"Project-Id-Version: OpenERP Server 5.0.0\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2009-08-28 16:01+0000\n"
-"PO-Revision-Date: 2009-12-11 14:19+0000\n"
-"Last-Translator: Pieter J. Kersten (EduSense BV) \n"
+"PO-Revision-Date: 2010-02-01 16:15+0000\n"
+"Last-Translator: Jan Verlaan (Veritos) \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2009-12-16 05:19+0000\n"
+"X-Launchpad-Export-Date: 2010-02-02 04:48+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
#. module: hr_expense
@@ -326,7 +326,7 @@ msgstr "Declaraties"
#. module: hr_expense
#: field:hr.expense.expense,date_valid:0
msgid "Date Validated"
-msgstr "Datum akkoord:"
+msgstr "Controledatum"
#. module: hr_expense
#: field:hr.expense.expense,account_move_id:0
diff --git a/addons/project/project.py b/addons/project/project.py
index 05a04653d2d..35b6e3840ff 100644
--- a/addons/project/project.py
+++ b/addons/project/project.py
@@ -243,15 +243,15 @@ class task(osv.osv):
for res in self.browse(cr, uid, ids):
if date_start and planned:
resource_id = self.pool.get('resource.resource').search(cr,uid,[('user_id','=',res.user_id.id)])
- resource_obj = self.pool.get('resource.resource').browse(cr,uid,resource_id)[0]
- d = mx.DateTime.strptime(date_start,'%Y-%m-%d %H:%M:%S')
- hrs = (planned)/(occupation_rate)
- work_times = self.pool.get('resource.calendar').interval_get(cr, uid, resource_obj.calendar_id.id or False, d, hrs or 0.0, resource_obj.id)
- result['date_end'] = work_times[-1][1].strftime('%Y-%m-%d %H:%M:%S')
- result['remaining_hours'] = planned-effective
+ if resource_id:
+ resource_obj = self.pool.get('resource.resource').browse(cr,uid,resource_id)[0]
+ d = mx.DateTime.strptime(date_start,'%Y-%m-%d %H:%M:%S')
+ hrs = (planned)/(occupation_rate)
+ work_times = self.pool.get('resource.calendar').interval_get(cr, uid, resource_obj.calendar_id.id or False, d, hrs or 0.0, resource_obj.id)
+ result['date_end'] = work_times[-1][1].strftime('%Y-%m-%d %H:%M:%S')
+ result['remaining_hours'] = planned-effective
return {'value':result}
-
def _default_project(self, cr, uid, context={}):
if 'project_id' in context and context['project_id']:
return context['project_id']
diff --git a/addons/project/project_view.xml b/addons/project/project_view.xml
index cc5f93e2608..51138dcdf0a 100644
--- a/addons/project/project_view.xml
+++ b/addons/project/project_view.xml
@@ -334,6 +334,7 @@
+
@@ -477,11 +478,11 @@
-
+
-
+
diff --git a/addons/project_calendar/project_calendar_data.xml b/addons/project_calendar/project_calendar_data.xml
index e4c333ca6e2..63b5e99333a 100644
--- a/addons/project_calendar/project_calendar_data.xml
+++ b/addons/project_calendar/project_calendar_data.xml
@@ -1,13 +1,17 @@
-
-
- vtodo
-
-
+
+ meeting_todo
+
+ vtodo
+
+
+ [('user_id','=', uid)]
+
+
@@ -15,34 +19,430 @@
{'needs-action': 'draft', 'completed': 'done', 'in-process': 'open', 'cancelled': 'cancelled'}field
-
-
+
+
+
+
+
+ field
+
+
+ field
-
-
+
+
+
+
+
+ field
+
+
+
+
+
+
+ field
+
+
+
+
+
+
+ field
+
+
+
+
+
+
+ field
+
+
+ field
-
-
+
+
+
+
+
+ field
+
+
+ field
-
-
+
+
+
+
+
+ field
+
+
+
+
+
+
+ field
+
+
+ hours
+
+
+
+
+
+ field
+
+
+
+
+
+
+ field
+
+
+
+
+
+
+ field
+
+
+
+
+
+
+ field
+
+
+
+
+ vevent
+
+
+ [('user_id','=', uid)]
+
+
+
+ valarm
+
+
+
+
+
+ attendee
+
+
+
+
+
+
+
+
+
+
+ field
+
+
+
+
+
+
+ field
+
+
+
+
+
+
+ field
+
+
+
+
+
+
+ field
+
+
+
+
+
+
+ field
+
+
+
+
+
+
+ field
+
+
+
+
+
+
+ field
+
+
+
+
+
+
+
+ field
+
+
+
+
+
+
+ field
+
+
+
+
+
+
+ {'tentative': 'draft', 'confirmed': 'open', 'cancelled': 'cancel'}
+ field
+
+
+
+
+
+
+ field
+
+
+
+
+
+
+ field
+
+
+
+
+
+
+ field
+
+
+
+
+
+
+ field
+
+
+
+
+
+
+ field
+
+
+
+
+
+
+ field
+
+
+
+
+
+
+ field
+
+
+
+
+
+
+ field
+
+
+
+
+
+
+
+
+ field
+
+
+
+
+
+
+ field
+
+
+
+
+
+
+ field
+
+
+
+
+
+
+ field
+
+
+
+
+
+
+ field
+
+
+
+
+
+
+ field
+
+
+
+
+
+
+ field
+
+
+
+
+
+
+ field
+
+
+
+
+
+
+ field
+
+
+
+
+
+
+ field
+
+
+
+
+
+
+ field
+
+
+
+
+
+
+
+ field
+
+
+
+
+
+
+ field
+
+
+
+
+
+
+ field
+
+
+
+
+
+
+ field
+
+
+
+
+
+
+ field
+
+
+
+
+
+
+ field
+
+
+
+
+
+
+ field
+
+
+
+
+
+
+ field
+
+
+
+
+
+
+ field
+
+
+
+
+
+
+ field
+
+
+
+
+
+
+ field
+
+
+
+
+
+
-
\ No newline at end of file
+
diff --git a/addons/project_calendar/project_calendar_view.xml b/addons/project_calendar/project_calendar_view.xml
index d331f8614c7..94679161b94 100644
--- a/addons/project_calendar/project_calendar_view.xml
+++ b/addons/project_calendar/project_calendar_view.xml
@@ -66,7 +66,7 @@
form
-
+
diff --git a/addons/purchase/purchase_view.xml b/addons/purchase/purchase_view.xml
index 2f612c159a6..4b6f184ebe2 100644
--- a/addons/purchase/purchase_view.xml
+++ b/addons/purchase/purchase_view.xml
@@ -27,8 +27,8 @@
-
+
-
-
+
+
report.project.task.user.treereport.project.task.user
@@ -41,7 +41,7 @@
-
+
report.project.task.user.searchreport.project.task.user
@@ -55,12 +55,12 @@
-
+
-
+
Tasks Closed by Project and Userreport.project.task.user
@@ -69,9 +69,9 @@
-
+
-
+
report.project.task.formreport.project.task
@@ -106,7 +106,7 @@
-
+
report.project.task.searchreport.project.task
@@ -119,13 +119,13 @@
-
+
-
+
Tasks Closed by Projectreport.project.task
@@ -134,6 +134,6 @@
-
+
diff --git a/addons/scrum/scrum_view.xml b/addons/scrum/scrum_view.xml
index 2ddb8353fec..fb6c3a716d6 100644
--- a/addons/scrum/scrum_view.xml
+++ b/addons/scrum/scrum_view.xml
@@ -1,15 +1,15 @@
-
-
+
+
-
-
+
+
-
+
scrum.project.formscrum.project
@@ -24,7 +24,7 @@
-
+
scrum.project.treescrum.project
@@ -48,7 +48,7 @@
[('parent_id','=',False),('scrum','=',1)]
-
+
Edit Projectsscrum.project
@@ -57,12 +57,12 @@
[('scrum','=',1)]
-
-
+
+
-
+
scrum.product.backlog.treescrum.product.backlog
@@ -80,7 +80,7 @@
-
+
scrum.product.backlog.formscrum.product.backlog
@@ -111,7 +111,7 @@
-
+
scrum.product.backlog.searchscrum.product.backlog
@@ -123,7 +123,7 @@
-
+
@@ -131,7 +131,7 @@
-
+
Backlogsscrum.product.backlog
@@ -139,11 +139,11 @@
-
+
-
+
scrum.sprint.treescrum.sprint
@@ -195,7 +195,7 @@
-
+
scrum.sprint.searchscrum.sprint
@@ -215,7 +215,7 @@
-
+
Sprintsscrum.sprint
@@ -224,12 +224,12 @@
-
+
-
+
scrum.meeting.treescrum.meeting
@@ -276,11 +276,11 @@
-
+
-
+
project.taskView sprint Tasks
@@ -295,7 +295,7 @@
-
+
scrum.product.backlogView sprint backlog
@@ -310,11 +310,11 @@
-
+
-
+
scrum.product.backlogView project's backlog
@@ -343,7 +343,7 @@
-
+
@@ -361,7 +361,7 @@
-
+
scrum.task.searchscrum.task
@@ -382,23 +382,23 @@
[('scrum','=',1)]
-
+
tree
-
+
form
-
+
-
+
Opened tasksscrum.task
@@ -407,6 +407,6 @@
[('state','=','open'),('scrum','=',1)]
-
+
diff --git a/addons/survey/report/survey_analysis_report.py b/addons/survey/report/survey_analysis_report.py
index 79871a63084..069488034d8 100755
--- a/addons/survey/report/survey_analysis_report.py
+++ b/addons/survey/report/survey_analysis_report.py
@@ -257,6 +257,8 @@ class survey_analysis(report_rml):
sqc.question_id = sr.question_id and sra.answer_id = %d and sqc.title ='%s'\
group by sra.answer_id,sqc.rating_weight" % (ans.id,matrix_ans[mat_col]))
col_weight = cr.fetchone()
+ if not col_weight :
+ col_weight= (0,0)
res_count = col_weight[0]
if tot_res:
rating_weight_sum += col_weight[1] * tot_res
diff --git a/addons/survey/report/survey_browse_response.py b/addons/survey/report/survey_browse_response.py
index 26ac0e54103..6e26f21e5b3 100644
--- a/addons/survey/report/survey_browse_response.py
+++ b/addons/survey/report/survey_browse_response.py
@@ -268,7 +268,7 @@ class survey_browse_response(report_rml):
"""
elif que.type in ['matrix_of_choices_only_one_ans','matrix_of_choices_only_multi_ans','rating_scale','matrix_of_drop_down_menus']:
if len(answer) and answer[0].state == "done":
- if que.comment_column:
+ if que.type in ['matrix_of_choices_only_one_ans','rating_scale'] and que.comment_column:
pass
cols_widhts = []
cols_widhts.append(200)
@@ -278,7 +278,7 @@ class survey_browse_response(report_rml):
tmp=0.0
sum = 0.0
i = 0
- if que.comment_column:
+ if que.type in ['matrix_of_choices_only_one_ans','rating_scale'] and que.comment_column:
for col in cols_widhts:
if i==0:
cols_widhts[i] = cols_widhts[i]/2.0
@@ -292,7 +292,7 @@ class survey_browse_response(report_rml):
if col.title not in matrix_ans:
matrix_ans.append(col.title)
len_matrix = len(matrix_ans)
- if que.comment_column:
+ if que.type in ['matrix_of_choices_only_one_ans','rating_scale'] and que.comment_column:
matrix_ans.append(que.column_name)
rml+="""
"""
for mat_col in matrix_ans:
@@ -342,14 +342,14 @@ class survey_browse_response(report_rml):
"""
rml+= """
""" + value + """
"""
- if que.comment_column:
+ if que.type in ['matrix_of_choices_only_one_ans','rating_scale'] and que.comment_column:
if comment_value=='False':
comment_value = ''
rml+= """
"""+ to_xml(tools.ustr(comment_value)) + """
"""
rml+="""
"""
- if que.comment_field_type:
+ if que.is_comment_require:
rml+="""
-
""" + to_xml(tools.ustr(answer[0].comment)) + """
"""
+
""" + to_xml(tools.ustr(answer[0].comment or '')) + """
"""
else:
rml +="""
No Response
diff --git a/addons/survey/survey.py b/addons/survey/survey.py
index c6a4a1daf2b..632f4c768ef 100644
--- a/addons/survey/survey.py
+++ b/addons/survey/survey.py
@@ -331,9 +331,9 @@ class survey_question(osv.osv):
raise osv.except_osv(_('Error !'),_("Maximum Required Answer is greater than Minimum Required Answer"))
if question['type'] == 'matrix_of_drop_down_menus' and vals.has_key('column_heading_ids'):
for col in vals['column_heading_ids']:
- if col[2].has_key('menu_choice') and not col[2]['menu_choice']:
+ if col[2] and col[2].has_key('menu_choice') and not col[2]['menu_choice']:
raise osv.except_osv(_('Error !'),_("You must enter one or more menu choices in column heading"))
- elif col[2].has_key('menu_choice') and col[2]['menu_choice'].strip() == '':
+ elif col[2] and col[2].has_key('menu_choice') and col[2]['menu_choice'].strip() == '':
raise osv.except_osv(_('Error !'),_("You must enter one or more menu choices in column heading (white spaces not allowed)"))
return super(survey_question, self).write(cr, uid, ids, vals, context=context)
@@ -740,24 +740,28 @@ class survey_question_wiz(osv.osv_memory):
fields[tools.ustr(que) + "_commentcolumn_"+tools.ustr(row['id']) + "_field"] = {'type':'char', 'size' : 255, 'string':tools.ustr(que_rec['column_name']), 'views':{}}
etree.SubElement(xml_group, 'field', {'name': tools.ustr(que) + "_commentcolumn_"+tools.ustr(row['id'])+ "_field"})
elif que_rec['type'] == 'matrix_of_choices_only_multi_ans':
- xml_group = etree.SubElement(xml_group, 'group', {'col': '2', 'colspan': '2'})
+ xml_group = etree.SubElement(xml_group, 'group', {'col': str(len(que_rec['column_heading_ids']) + 1), 'colspan': '4'})
+ etree.SubElement(xml_group, 'separator', {'string': '.','colspan': '1'})
+ for col in que_col_head.read(cr, uid, que_rec['column_heading_ids']):
+ etree.SubElement(xml_group, 'separator', {'string': tools.ustr(col['title']),'colspan': '1'})
for row in ans_ids:
etree.SubElement(xml_group, 'label', {'string': to_xml(tools.ustr(row['answer'])) +' :-', 'align': '0.0'})
- etree.SubElement(xml_group, 'newline')
for col in que_col_head.read(cr, uid, que_rec['column_heading_ids']):
- etree.SubElement(xml_group, 'field', {'name': tools.ustr(que) + "_" + tools.ustr(row['id']) + "_" + tools.ustr(col['title'])})
+ etree.SubElement(xml_group, 'field', {'name': tools.ustr(que) + "_" + tools.ustr(row['id']) + "_" + tools.ustr(col['title']), 'nolabel':"1"})
fields[tools.ustr(que) + "_" + tools.ustr(row['id']) + "_" + tools.ustr(col['title'])] = {'type':'boolean', 'string': col['title']}
elif que_rec['type'] == 'matrix_of_drop_down_menus':
- xml_group = etree.SubElement(xml_group, 'group', {'col': '2', 'colspan': '2'})
+ xml_group = etree.SubElement(xml_group, 'group', {'col': str(len(que_rec['column_heading_ids']) + 1), 'colspan': '4'})
+ etree.SubElement(xml_group, 'separator', {'string': '.','colspan': '1'})
+ for col in que_col_head.read(cr, uid, que_rec['column_heading_ids']):
+ etree.SubElement(xml_group, 'separator', {'string': tools.ustr(col['title']),'colspan': '1'})
for row in ans_ids:
etree.SubElement(xml_group, 'label', {'string': to_xml(tools.ustr(row['answer']))+' :-', 'align': '0.0'})
- etree.SubElement(xml_group, 'newline')
for col in que_col_head.read(cr, uid, que_rec['column_heading_ids']):
selection = []
if col['menu_choice']:
for item in col['menu_choice'].split('\n'):
if item and not item.strip() == '': selection.append((item ,item))
- etree.SubElement(xml_group, 'field', {'name': tools.ustr(que) + "_" + tools.ustr(row['id']) + "_" + tools.ustr(col['title'])})
+ etree.SubElement(xml_group, 'field', {'name': tools.ustr(que) + "_" + tools.ustr(row['id']) + "_" + tools.ustr(col['title']),'nolabel':'1'})
fields[tools.ustr(que) + "_" + tools.ustr(row['id']) + "_" + tools.ustr(col['title'])] = {'type':'selection', 'string': col['title'], 'selection':selection}
elif que_rec['type'] == 'multiple_textboxes':
xml_group = etree.SubElement(xml_group, 'group', {'col': '1', 'colspan': '4'})
@@ -1238,7 +1242,7 @@ class survey_question_wiz(osv.osv_memory):
numeric_sum += int(val)
elif val and len(key.split('_')) == 3:
resp_obj.write(cr, uid, update, {'state': 'done'})
- if type(val) == type(''):
+ if type(val) == type('') or type(val) == type(u''):
ans_create_id = res_ans_obj.create(cr, uid, {'response_id':update, 'answer_id':ans_id_len[1], 'answer' : ans_id_len[2], 'value_choice' : val})
sur_name_read['store_ans'][update].update({key:val})
else:
diff --git a/addons/survey/survey_view.xml b/addons/survey/survey_view.xml
index 70b41b589fe..5085ed4986d 100644
--- a/addons/survey/survey_view.xml
+++ b/addons/survey/survey_view.xml
@@ -30,7 +30,7 @@
+ string="Edit Survey" type="action" icon="gtk-edit" context="{'active':True,'edit' : True,'survey_id': active_id}"/>
@@ -93,15 +93,16 @@
-
-
-
-
-
-
+
+
+
+
+
+
+
@@ -351,15 +352,16 @@
-
-
-
-
-
-
+
+
+
+
+
+
+
@@ -544,15 +546,16 @@
-
-
-
-
-
-
+
+
+
+
+
+
+