@@ -8,13 +8,13 @@ msgstr ""
|
||||
"Project-Id-Version: openobject-addons\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2009-08-28 16:01+0000\n"
|
||||
"PO-Revision-Date: 2009-12-29 10:14+0000\n"
|
||||
"Last-Translator: NightSpirit <Unknown>\n"
|
||||
"PO-Revision-Date: 2010-01-05 09:22+0000\n"
|
||||
"Last-Translator: pmjt <Unknown>\n"
|
||||
"Language-Team: Finnish <fi@li.org>\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-30 04:47+0000\n"
|
||||
"X-Launchpad-Export-Date: 2010-01-06 04:36+0000\n"
|
||||
"X-Generator: Launchpad (build Unknown)\n"
|
||||
|
||||
#. module: account
|
||||
@@ -692,7 +692,7 @@ msgstr "Analyyttiset merkinnät"
|
||||
#. module: account
|
||||
#: selection:account.subscription,period_type:0
|
||||
msgid "month"
|
||||
msgstr ""
|
||||
msgstr "kuukausi"
|
||||
|
||||
#. module: account
|
||||
#: field:account.analytic.account,partner_id:0
|
||||
|
||||
@@ -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-11-17 09:58+0000\n"
|
||||
"Last-Translator: Fabien (Open ERP) <fp@tinyerp.com>\n"
|
||||
"PO-Revision-Date: 2010-01-06 18:48+0000\n"
|
||||
"Last-Translator: eLBati <elbaddy@gmail.com>\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:11+0000\n"
|
||||
"X-Launchpad-Export-Date: 2010-01-07 04:49+0000\n"
|
||||
"X-Generator: Launchpad (build Unknown)\n"
|
||||
|
||||
#. module: account
|
||||
@@ -24,13 +24,13 @@ msgstr "Nome Interno"
|
||||
#. module: account
|
||||
#: view:account.tax.code:0
|
||||
msgid "Account Tax Code"
|
||||
msgstr "Codice conto tasse"
|
||||
msgstr "Codice conto imposte"
|
||||
|
||||
#. module: account
|
||||
#: model:ir.actions.act_window,name:account.action_invoice_tree9
|
||||
#: model:ir.ui.menu,name:account.menu_action_invoice_tree9
|
||||
msgid "Unpaid Supplier Invoices"
|
||||
msgstr "Non pagate"
|
||||
msgstr "Fatture fornitori non pagate"
|
||||
|
||||
#. module: account
|
||||
#: model:ir.ui.menu,name:account.menu_finance_entries
|
||||
@@ -139,7 +139,7 @@ msgstr "Annulla riconcigliazione voci"
|
||||
#. module: account
|
||||
#: constraint:account.period:0
|
||||
msgid "Error ! The duration of the Period(s) is/are invalid. "
|
||||
msgstr ""
|
||||
msgstr "Errore ! La durata del/dei Periodo/i non è valida "
|
||||
|
||||
#. module: account
|
||||
#: view:account.bank.statement.reconcile:0
|
||||
@@ -1019,7 +1019,7 @@ msgstr "Posizione fiscale"
|
||||
#: field:account.analytic.line,product_uom_id:0
|
||||
#: field:account.move.line,product_uom_id:0
|
||||
msgid "UoM"
|
||||
msgstr "UM"
|
||||
msgstr "Unità di Misura"
|
||||
|
||||
#. module: account
|
||||
#: wizard_field:account.third_party_ledger.report,init,page_split:0
|
||||
|
||||
@@ -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-11-17 09:38+0000\n"
|
||||
"Last-Translator: Idler <idler@pcinhk.com>\n"
|
||||
"PO-Revision-Date: 2010-01-08 03:52+0000\n"
|
||||
"Last-Translator: Wei \"oldrev\" Li <oldrev@gmail.com>\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-01-08 04:38+0000\n"
|
||||
"X-Generator: Launchpad (build Unknown)\n"
|
||||
|
||||
#. module: account_analytic_analysis
|
||||
@@ -26,7 +26,7 @@ msgstr "可开据加已开据的小时数"
|
||||
#. module: account_analytic_analysis
|
||||
#: model:ir.model,name:account_analytic_analysis.model_account_analytic_analysis_summary_user
|
||||
msgid "Hours summary by user"
|
||||
msgstr ""
|
||||
msgstr "按用户汇总小时数"
|
||||
|
||||
#. module: account_analytic_analysis
|
||||
#: field:account.analytic.account,last_invoice_date:0
|
||||
@@ -41,18 +41,18 @@ msgstr "计算公式: 最大开据价格 - 已开据总计"
|
||||
#. module: account_analytic_analysis
|
||||
#: help:account.analytic.account,remaining_hours:0
|
||||
msgid "Computed using the formula: Maximum Quantity - Hours Tot."
|
||||
msgstr ""
|
||||
msgstr "使用以下公式计算: 最大数量 - 总时间"
|
||||
|
||||
#. module: account_analytic_analysis
|
||||
#: model:ir.ui.menu,name:account_analytic_analysis.menu_action_account_analytic_all
|
||||
msgid "All Analytic Accounts"
|
||||
msgstr ""
|
||||
msgstr "所有分析科目列表"
|
||||
|
||||
#. module: account_analytic_analysis
|
||||
#: model:ir.actions.act_window,name:account_analytic_analysis.action_account_analytic_managed_open
|
||||
#: model:ir.ui.menu,name:account_analytic_analysis.menu_analytic_account_to_valid_open
|
||||
msgid "My Current Accounts"
|
||||
msgstr ""
|
||||
msgstr "我的当前科目列表"
|
||||
|
||||
#. module: account_analytic_analysis
|
||||
#: constraint:ir.ui.view:0
|
||||
@@ -72,7 +72,7 @@ msgstr "理论收益"
|
||||
#. module: account_analytic_analysis
|
||||
#: constraint:ir.actions.act_window:0
|
||||
msgid "Invalid model name in the action definition."
|
||||
msgstr ""
|
||||
msgstr "在动作定义中输入的对象名称错误"
|
||||
|
||||
#. module: account_analytic_analysis
|
||||
#: help:account.analytic.account,theorical_margin:0
|
||||
@@ -83,7 +83,7 @@ msgstr ""
|
||||
#: constraint:ir.model:0
|
||||
msgid ""
|
||||
"The Object name must start with x_ and not contain any special character !"
|
||||
msgstr ""
|
||||
msgstr "对象名称必须以“x_”起头且不能包含任何特殊字符!"
|
||||
|
||||
#. module: account_analytic_analysis
|
||||
#: model:ir.actions.act_window,name:account_analytic_analysis.action_account_analytic_new
|
||||
@@ -105,7 +105,7 @@ msgstr ""
|
||||
#: model:ir.actions.act_window,name:account_analytic_analysis.action_account_analytic_all_open
|
||||
#: model:ir.ui.menu,name:account_analytic_analysis.menu_action_account_analytic_all_open
|
||||
msgid "Current Analytic Accounts"
|
||||
msgstr ""
|
||||
msgstr "当前分析科目列表"
|
||||
|
||||
#. module: account_analytic_analysis
|
||||
#: help:account.analytic.account,last_worked_date:0
|
||||
@@ -127,24 +127,24 @@ msgstr ""
|
||||
#. module: account_analytic_analysis
|
||||
#: field:account.analytic.account,last_worked_date:0
|
||||
msgid "Date of Last Cost/Work"
|
||||
msgstr ""
|
||||
msgstr "最后工作日期"
|
||||
|
||||
#. module: account_analytic_analysis
|
||||
#: field:account.analytic.account,total_cost:0
|
||||
msgid "Total Costs"
|
||||
msgstr ""
|
||||
msgstr "总成本"
|
||||
|
||||
#. module: account_analytic_analysis
|
||||
#: help:account.analytic.account,hours_quantity:0
|
||||
msgid ""
|
||||
"Number of hours you spent on the analytic account (from timesheet). It "
|
||||
"computes on all journal of type 'general'."
|
||||
msgstr ""
|
||||
msgstr "在当前核算项目上的工时数。根据类型为总账的凭证计算而来。"
|
||||
|
||||
#. module: account_analytic_analysis
|
||||
#: field:account.analytic.account,remaining_hours:0
|
||||
msgid "Remaining Hours"
|
||||
msgstr ""
|
||||
msgstr "剩余小时数"
|
||||
|
||||
#. module: account_analytic_analysis
|
||||
#: help:account.analytic.account,ca_theorical:0
|
||||
@@ -152,13 +152,13 @@ msgid ""
|
||||
"Based on the costs you had on the project, what would have been the revenue "
|
||||
"if all these costs have been invoiced at the normal sale price provided by "
|
||||
"the pricelist."
|
||||
msgstr ""
|
||||
msgstr "根据项目的当前成本测算出来的利润,这些成本对应的收入是按价格表中的一般销售单价计算出来的。"
|
||||
|
||||
#. module: account_analytic_analysis
|
||||
#: field:account.analytic.account,user_ids:0
|
||||
#: field:account_analytic_analysis.summary.user,user:0
|
||||
msgid "User"
|
||||
msgstr ""
|
||||
msgstr "用户"
|
||||
|
||||
#. module: account_analytic_analysis
|
||||
#: model:ir.actions.act_window,name:account_analytic_analysis.action_account_analytic_managed_pending
|
||||
@@ -170,18 +170,18 @@ msgstr ""
|
||||
#: model:ir.actions.act_window,name:account_analytic_analysis.action_hr_tree_invoiced_my
|
||||
#: model:ir.ui.menu,name:account_analytic_analysis.menu_action_hr_tree_invoiced_my
|
||||
msgid "My Uninvoiced Entries"
|
||||
msgstr ""
|
||||
msgstr "未开发票条目"
|
||||
|
||||
#. module: account_analytic_analysis
|
||||
#: help:account.analytic.account,real_margin:0
|
||||
msgid "Computed using the formula: Invoiced Amount - Total Costs."
|
||||
msgstr ""
|
||||
msgstr "计算公式:发票数量 - 总成本"
|
||||
|
||||
#. module: account_analytic_analysis
|
||||
#: 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 ""
|
||||
msgstr "我的科目列表"
|
||||
|
||||
#. module: account_analytic_analysis
|
||||
#: model:ir.module.module,description:account_analytic_analysis.module_meta_information
|
||||
@@ -194,27 +194,27 @@ msgstr ""
|
||||
#. module: account_analytic_analysis
|
||||
#: field:account.analytic.account,hours_qtt_non_invoiced:0
|
||||
msgid "Uninvoiced Hours"
|
||||
msgstr ""
|
||||
msgstr "未开发票工时"
|
||||
|
||||
#. module: account_analytic_analysis
|
||||
#: field:account.analytic.account,hours_quantity:0
|
||||
msgid "Hours Tot"
|
||||
msgstr ""
|
||||
msgstr "工时总计"
|
||||
|
||||
#. module: account_analytic_analysis
|
||||
#: model:ir.ui.menu,name:account_analytic_analysis.menu_account
|
||||
msgid "Analytic Accounts"
|
||||
msgstr "分析科目"
|
||||
msgstr "核算项目"
|
||||
|
||||
#. module: account_analytic_analysis
|
||||
#: model:ir.module.module,shortdesc:account_analytic_analysis.module_meta_information
|
||||
msgid "report_account_analytic"
|
||||
msgstr ""
|
||||
msgstr "核算项目报表"
|
||||
|
||||
#. module: account_analytic_analysis
|
||||
#: field:account.analytic.account,ca_invoiced:0
|
||||
msgid "Invoiced Amount"
|
||||
msgstr ""
|
||||
msgstr "已开票数量"
|
||||
|
||||
#. module: account_analytic_analysis
|
||||
#: model:ir.ui.menu,name:account_analytic_analysis.next_id_71
|
||||
@@ -224,28 +224,28 @@ msgstr ""
|
||||
#. module: account_analytic_analysis
|
||||
#: field:account.analytic.account,last_worked_invoiced_date:0
|
||||
msgid "Date of Last Invoiced Cost"
|
||||
msgstr ""
|
||||
msgstr "最后开票日期"
|
||||
|
||||
#. module: account_analytic_analysis
|
||||
#: field:account.analytic.account,ca_to_invoice:0
|
||||
msgid "Uninvoiced Amount"
|
||||
msgstr ""
|
||||
msgstr "未开票金额"
|
||||
|
||||
#. module: account_analytic_analysis
|
||||
#: model:ir.actions.act_window,name:account_analytic_analysis.action_account_analytic_all_pending
|
||||
#: model:ir.ui.menu,name:account_analytic_analysis.menu_action_account_analytic_all_pending
|
||||
msgid "Pending Analytic Accounts"
|
||||
msgstr ""
|
||||
msgstr "未决分析科目列表"
|
||||
|
||||
#. module: account_analytic_analysis
|
||||
#: field:account.analytic.account,hours_qtt_invoiced:0
|
||||
msgid "Invoiced Hours"
|
||||
msgstr ""
|
||||
msgstr "已开票小时数"
|
||||
|
||||
#. module: account_analytic_analysis
|
||||
#: field:account.analytic.account,real_margin:0
|
||||
msgid "Real Margin"
|
||||
msgstr ""
|
||||
msgstr "实际利润"
|
||||
|
||||
#. module: account_analytic_analysis
|
||||
#: help:account.analytic.account,ca_invoiced:0
|
||||
@@ -255,12 +255,12 @@ msgstr ""
|
||||
#. module: account_analytic_analysis
|
||||
#: model:ir.model,name:account_analytic_analysis.model_account_analytic_analysis_summary_month
|
||||
msgid "Hours summary by month"
|
||||
msgstr ""
|
||||
msgstr "按月汇总工时数"
|
||||
|
||||
#. module: account_analytic_analysis
|
||||
#: help:account.analytic.account,real_margin_rate:0
|
||||
msgid "Computes using the formula: (Real Margin / Total Costs) * 100."
|
||||
msgstr ""
|
||||
msgstr "计算公式: (实际利润 / 总成本) * 100."
|
||||
|
||||
#. module: account_analytic_analysis
|
||||
#: help:account.analytic.account,hours_qtt_non_invoiced:0
|
||||
@@ -272,7 +272,7 @@ msgstr ""
|
||||
#. module: account_analytic_analysis
|
||||
#: view:account.analytic.account:0
|
||||
msgid "Analytic accounts"
|
||||
msgstr ""
|
||||
msgstr "分析科目"
|
||||
|
||||
#. module: account_analytic_analysis
|
||||
#: field:account.analytic.account,remaining_ca:0
|
||||
@@ -300,7 +300,7 @@ msgstr ""
|
||||
#: field:account_analytic_analysis.summary.month,unit_amount:0
|
||||
#: field:account_analytic_analysis.summary.user,unit_amount:0
|
||||
msgid "Total Time"
|
||||
msgstr ""
|
||||
msgstr "总时间"
|
||||
|
||||
#. module: account_analytic_analysis
|
||||
#: field:account.analytic.account,month_ids:0
|
||||
@@ -312,7 +312,7 @@ msgstr ""
|
||||
#: field:account_analytic_analysis.summary.month,account_id:0
|
||||
#: field:account_analytic_analysis.summary.user,account_id:0
|
||||
msgid "Analytic Account"
|
||||
msgstr ""
|
||||
msgstr "分析科目"
|
||||
|
||||
#. module: account_analytic_analysis
|
||||
#: model:ir.actions.act_window,name:account_analytic_analysis.action_account_analytic_managed_overpassed
|
||||
|
||||
@@ -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: 2009-08-28 16:01+0000\n"
|
||||
"PO-Revision-Date: 2009-09-08 14:27+0000\n"
|
||||
"Last-Translator: xu dong <gnodux@gmail.com>\n"
|
||||
"PO-Revision-Date: 2010-01-08 03:31+0000\n"
|
||||
"Last-Translator: Wei \"oldrev\" Li <oldrev@gmail.com>\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-01-08 04:38+0000\n"
|
||||
"X-Generator: Launchpad (build Unknown)\n"
|
||||
|
||||
#. module: account_budget
|
||||
#: field:crossovered.budget,creating_user_id:0
|
||||
msgid "Responsible User"
|
||||
msgstr ""
|
||||
msgstr "负责用户"
|
||||
|
||||
#. module: account_budget
|
||||
#: rml:account.budget:0
|
||||
@@ -30,23 +30,23 @@ msgstr ""
|
||||
#: model:ir.actions.act_window,name:account_budget.open_budget_post_form
|
||||
#: model:ir.ui.menu,name:account_budget.menu_budget_post_form
|
||||
msgid "Budgetary Positions"
|
||||
msgstr ""
|
||||
msgstr "预算状况"
|
||||
|
||||
#. module: account_budget
|
||||
#: constraint:ir.actions.act_window:0
|
||||
msgid "Invalid model name in the action definition."
|
||||
msgstr ""
|
||||
msgstr "在动作定义使用了无效的模型名称。"
|
||||
|
||||
#. module: account_budget
|
||||
#: rml:account.analytic.account.budget:0
|
||||
#: rml:crossovered.budget.report:0
|
||||
msgid "Printed at:"
|
||||
msgstr ""
|
||||
msgstr "打印于:"
|
||||
|
||||
#. module: account_budget
|
||||
#: view:crossovered.budget:0
|
||||
msgid "Confirm"
|
||||
msgstr ""
|
||||
msgstr "确认"
|
||||
|
||||
#. module: account_budget
|
||||
#: field:crossovered.budget,validating_user_id:0
|
||||
@@ -57,12 +57,12 @@ msgstr ""
|
||||
#: constraint:ir.model:0
|
||||
msgid ""
|
||||
"The Object name must start with x_ and not contain any special character !"
|
||||
msgstr ""
|
||||
msgstr "对象名称必须以“x_”起头且不能包含任何特殊字符!"
|
||||
|
||||
#. module: account_budget
|
||||
#: selection:crossovered.budget,state:0
|
||||
msgid "Confirmed"
|
||||
msgstr ""
|
||||
msgstr "已确认"
|
||||
|
||||
#. module: account_budget
|
||||
#: field:account.budget.post.dotation,period_id:0
|
||||
@@ -80,12 +80,12 @@ msgstr "期末"
|
||||
#. module: account_budget
|
||||
#: rml:account.budget:0
|
||||
msgid "Printing date:"
|
||||
msgstr ""
|
||||
msgstr "打印时间:"
|
||||
|
||||
#. module: account_budget
|
||||
#: selection:crossovered.budget,state:0
|
||||
msgid "Draft"
|
||||
msgstr ""
|
||||
msgstr "草稿"
|
||||
|
||||
#. module: account_budget
|
||||
#: rml:account.analytic.account.budget:0
|
||||
@@ -109,7 +109,7 @@ msgstr ""
|
||||
#: rml:account.budget:0
|
||||
#: rml:crossovered.budget.report:0
|
||||
msgid "Currency:"
|
||||
msgstr ""
|
||||
msgstr "货币:"
|
||||
|
||||
#. module: account_budget
|
||||
#: rml:account.budget:0
|
||||
@@ -203,7 +203,7 @@ msgstr ""
|
||||
#: rml:account.budget:0
|
||||
#: rml:crossovered.budget.report:0
|
||||
msgid "Total :"
|
||||
msgstr ""
|
||||
msgstr "总计:"
|
||||
|
||||
#. module: account_budget
|
||||
#: rml:account.analytic.account.budget:0
|
||||
@@ -256,12 +256,12 @@ msgstr ""
|
||||
#: field:crossovered.budget,date_to:0
|
||||
#: field:crossovered.budget.lines,date_to:0
|
||||
msgid "End Date"
|
||||
msgstr ""
|
||||
msgstr "结束时间"
|
||||
|
||||
#. module: account_budget
|
||||
#: constraint:ir.ui.view:0
|
||||
msgid "Invalid XML for View Architecture!"
|
||||
msgstr ""
|
||||
msgstr "无效的 XML 视图架构!"
|
||||
|
||||
#. module: account_budget
|
||||
#: field:crossovered.budget.lines,theoritical_amount:0
|
||||
|
||||
@@ -7,19 +7,19 @@ msgstr ""
|
||||
"Project-Id-Version: OpenERP Server 5.0.4\n"
|
||||
"Report-Msgid-Bugs-To: support@openerp.com\n"
|
||||
"POT-Creation-Date: 2009-08-28 16:01+0000\n"
|
||||
"PO-Revision-Date: 2009-01-30 12:43+0000\n"
|
||||
"Last-Translator: <>\n"
|
||||
"PO-Revision-Date: 2010-01-08 03:45+0000\n"
|
||||
"Last-Translator: Wei \"oldrev\" Li <oldrev@gmail.com>\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:17+0000\n"
|
||||
"X-Launchpad-Export-Date: 2010-01-08 04:38+0000\n"
|
||||
"X-Generator: Launchpad (build Unknown)\n"
|
||||
|
||||
#. module: account_date_check
|
||||
#: constraint:ir.ui.view:0
|
||||
msgid "Invalid XML for View Architecture!"
|
||||
msgstr ""
|
||||
msgstr "无效的 XML 视图架构!"
|
||||
|
||||
#. module: account_date_check
|
||||
#: field:account.journal,allow_date:0
|
||||
|
||||
@@ -7,13 +7,13 @@ msgstr ""
|
||||
"Project-Id-Version: OpenERP Server 5.0.4\n"
|
||||
"Report-Msgid-Bugs-To: support@openerp.com\n"
|
||||
"POT-Creation-Date: 2009-08-28 16:01+0000\n"
|
||||
"PO-Revision-Date: 2009-01-30 12:49+0000\n"
|
||||
"Last-Translator: Fabien (Open ERP) <fp@tinyerp.com>\n"
|
||||
"PO-Revision-Date: 2010-01-08 04:00+0000\n"
|
||||
"Last-Translator: Wei \"oldrev\" Li <oldrev@gmail.com>\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:17+0000\n"
|
||||
"X-Launchpad-Export-Date: 2010-01-08 04:38+0000\n"
|
||||
"X-Generator: Launchpad (build Unknown)\n"
|
||||
|
||||
#. module: account_payment
|
||||
@@ -29,7 +29,7 @@ msgstr ""
|
||||
#. module: account_payment
|
||||
#: view:payment.order:0
|
||||
msgid "Set to draft"
|
||||
msgstr ""
|
||||
msgstr "设为草稿"
|
||||
|
||||
#. module: account_payment
|
||||
#: help:payment.order,mode:0
|
||||
@@ -39,7 +39,7 @@ msgstr ""
|
||||
#. module: account_payment
|
||||
#: constraint:ir.actions.act_window:0
|
||||
msgid "Invalid model name in the action definition."
|
||||
msgstr ""
|
||||
msgstr "在动作定义使用了无效的模型名称。"
|
||||
|
||||
#. module: account_payment
|
||||
#: view:payment.line:0
|
||||
|
||||
@@ -7,19 +7,19 @@ msgstr ""
|
||||
"Project-Id-Version: OpenERP Server 5.0.4\n"
|
||||
"Report-Msgid-Bugs-To: support@openerp.com\n"
|
||||
"POT-Creation-Date: 2009-08-28 16:01+0000\n"
|
||||
"PO-Revision-Date: 2009-04-10 10:16+0000\n"
|
||||
"Last-Translator: Fabien (Open ERP) <fp@tinyerp.com>\n"
|
||||
"PO-Revision-Date: 2010-01-06 14:14+0000\n"
|
||||
"Last-Translator: Kalle Kniivilä <kalle@kniivila.net>\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:24+0000\n"
|
||||
"X-Launchpad-Export-Date: 2010-01-07 04:49+0000\n"
|
||||
"X-Generator: Launchpad (build Unknown)\n"
|
||||
|
||||
#. module: analytic_journal_billing_rate
|
||||
#: constraint:ir.ui.view:0
|
||||
msgid "Invalid XML for View Architecture!"
|
||||
msgstr ""
|
||||
msgstr "Felaktig XML för Vyarkitektur!"
|
||||
|
||||
#. module: analytic_journal_billing_rate
|
||||
#: field:analytic_journal_rate_grid,journal_id:0
|
||||
|
||||
@@ -7,13 +7,13 @@ msgstr ""
|
||||
"Project-Id-Version: OpenERP Server 5.0.4\n"
|
||||
"Report-Msgid-Bugs-To: support@openerp.com\n"
|
||||
"POT-Creation-Date: 2009-08-28 16:01+0000\n"
|
||||
"PO-Revision-Date: 2009-11-17 09:13+0000\n"
|
||||
"Last-Translator: Kuvaly <kuvaly@seznam.cz>\n"
|
||||
"PO-Revision-Date: 2010-01-04 19:11+0000\n"
|
||||
"Last-Translator: Konki <pavel.konkol@seznam.cz>\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-01-05 04:40+0000\n"
|
||||
"X-Generator: Launchpad (build Unknown)\n"
|
||||
|
||||
#. module: analytic_user_function
|
||||
@@ -24,7 +24,7 @@ msgstr "Invalidní XML pro zobrazení architektury!"
|
||||
#. module: analytic_user_function
|
||||
#: model:ir.model,name:analytic_user_function.model_analytic_user_funct_grid
|
||||
msgid "Relation table between users and products on a analytic account"
|
||||
msgstr ""
|
||||
msgstr "Vztah mezi uživateli a tabulkou produktů na analytickém účtu"
|
||||
|
||||
#. module: analytic_user_function
|
||||
#: field:analytic_user_funct_grid,product_id:0
|
||||
|
||||
@@ -8,13 +8,13 @@ msgstr ""
|
||||
"Project-Id-Version: openobject-addons\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2009-08-28 16:01+0000\n"
|
||||
"PO-Revision-Date: 2009-12-29 10:07+0000\n"
|
||||
"Last-Translator: NightSpirit <Unknown>\n"
|
||||
"PO-Revision-Date: 2010-01-05 09:13+0000\n"
|
||||
"Last-Translator: pmjt <Unknown>\n"
|
||||
"Language-Team: Finnish <fi@li.org>\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-30 04:47+0000\n"
|
||||
"X-Launchpad-Export-Date: 2010-01-06 04:36+0000\n"
|
||||
"X-Generator: Launchpad (build Unknown)\n"
|
||||
|
||||
#. module: base_contact
|
||||
@@ -31,7 +31,7 @@ msgstr ""
|
||||
#: constraint:ir.model:0
|
||||
msgid ""
|
||||
"The Object name must start with x_ and not contain any special character !"
|
||||
msgstr ""
|
||||
msgstr "Objektin nimen tulee alkaa x_ ja se ei saa sisältää erikoismerkkejä!"
|
||||
|
||||
#. module: base_contact
|
||||
#: field:res.partner.job,function_id:0
|
||||
@@ -46,7 +46,7 @@ msgstr ""
|
||||
#: view:res.partner.address:0
|
||||
#: field:res.partner.address,job_ids:0
|
||||
msgid "Contacts"
|
||||
msgstr ""
|
||||
msgstr "Kontaktit"
|
||||
|
||||
#. module: base_contact
|
||||
#: field:res.partner.job,sequence_partner:0
|
||||
@@ -56,7 +56,7 @@ msgstr ""
|
||||
#. module: base_contact
|
||||
#: selection:res.partner.job,state:0
|
||||
msgid "Current"
|
||||
msgstr ""
|
||||
msgstr "Nykyinen"
|
||||
|
||||
#. module: base_contact
|
||||
#: field:res.partner.contact,first_name:0
|
||||
@@ -71,7 +71,7 @@ msgstr ""
|
||||
#. module: base_contact
|
||||
#: field:res.partner.job,other:0
|
||||
msgid "Other"
|
||||
msgstr ""
|
||||
msgstr "Muu"
|
||||
|
||||
#. module: base_contact
|
||||
#: model:process.transition,name:base_contact.process_transition_contacttofunction0
|
||||
@@ -81,7 +81,7 @@ msgstr ""
|
||||
#. module: base_contact
|
||||
#: constraint:ir.actions.act_window:0
|
||||
msgid "Invalid model name in the action definition."
|
||||
msgstr ""
|
||||
msgstr "Virheellinen mallin nimi toimenpiteen määrittelyssä."
|
||||
|
||||
#. module: base_contact
|
||||
#: model:process.transition,name:base_contact.process_transition_partnertoaddress0
|
||||
@@ -101,22 +101,22 @@ msgstr "Lisäpuheliinnumero:"
|
||||
#. module: base_contact
|
||||
#: model:process.node,name:base_contact.process_node_function0
|
||||
msgid "Function"
|
||||
msgstr ""
|
||||
msgstr "Toiminto"
|
||||
|
||||
#. module: base_contact
|
||||
#: field:res.partner.job,fax:0
|
||||
msgid "Fax"
|
||||
msgstr ""
|
||||
msgstr "Faksi"
|
||||
|
||||
#. module: base_contact
|
||||
#: field:res.partner.contact,lang_id:0
|
||||
msgid "Language"
|
||||
msgstr ""
|
||||
msgstr "Kieli"
|
||||
|
||||
#. module: base_contact
|
||||
#: field:res.partner.job,phone:0
|
||||
msgid "Phone"
|
||||
msgstr ""
|
||||
msgstr "Puhelin"
|
||||
|
||||
#. module: base_contact
|
||||
#: model:process.transition,note:base_contact.process_transition_contacttofunction0
|
||||
@@ -149,7 +149,7 @@ msgstr ""
|
||||
#: field:res.partner.contact,email:0
|
||||
#: field:res.partner.job,email:0
|
||||
msgid "E-Mail"
|
||||
msgstr ""
|
||||
msgstr "Sähköposti"
|
||||
|
||||
#. module: base_contact
|
||||
#: field:res.partner.job,date_stop:0
|
||||
@@ -160,7 +160,7 @@ msgstr "Loppupäivämäärä"
|
||||
#: view:res.partner:0
|
||||
#: field:res.partner.job,address_id:0
|
||||
msgid "Address"
|
||||
msgstr ""
|
||||
msgstr "Osoite"
|
||||
|
||||
#. module: base_contact
|
||||
#: model:ir.actions.act_window,name:base_contact.action_res_partner_job
|
||||
@@ -189,7 +189,7 @@ msgstr "Päätyötehtävä"
|
||||
#. module: base_contact
|
||||
#: view:res.partner:0
|
||||
msgid "Categories"
|
||||
msgstr ""
|
||||
msgstr "Kategoriat"
|
||||
|
||||
#. module: base_contact
|
||||
#: field:res.partner.contact,function_id:0
|
||||
@@ -204,7 +204,7 @@ msgstr "Määrittää kumppanit ja heidän osoitteet"
|
||||
#. module: base_contact
|
||||
#: constraint:ir.ui.view:0
|
||||
msgid "Invalid XML for View Architecture!"
|
||||
msgstr ""
|
||||
msgstr "Virheellinen XML näkymä-arkkitehtuurille!"
|
||||
|
||||
#. module: base_contact
|
||||
#: model:process.process,name:base_contact.process_process_basecontactprocess0
|
||||
@@ -219,12 +219,12 @@ msgstr ""
|
||||
#. module: base_contact
|
||||
#: field:res.partner.job,extension:0
|
||||
msgid "Extension"
|
||||
msgstr ""
|
||||
msgstr "Laajennus"
|
||||
|
||||
#. module: base_contact
|
||||
#: field:res.partner.contact,mobile:0
|
||||
msgid "Mobile"
|
||||
msgstr ""
|
||||
msgstr "Matkapuhelin"
|
||||
|
||||
#. module: base_contact
|
||||
#: help:res.partner.job,extension:0
|
||||
@@ -250,12 +250,12 @@ msgstr "Toiminnot ja osoitteet"
|
||||
#. module: base_contact
|
||||
#: field:res.partner.contact,active:0
|
||||
msgid "Active"
|
||||
msgstr ""
|
||||
msgstr "Aktiivinen"
|
||||
|
||||
#. module: base_contact
|
||||
#: field:res.partner.job,contact_id:0
|
||||
msgid "Contact"
|
||||
msgstr ""
|
||||
msgstr "Kontakti"
|
||||
|
||||
#. module: base_contact
|
||||
#: model:process.node,note:base_contact.process_node_partners0
|
||||
@@ -275,23 +275,23 @@ msgstr ""
|
||||
#. module: base_contact
|
||||
#: model:ir.actions.act_window,name:base_contact.act_res_partner_jobs
|
||||
msgid "Partner Contacts"
|
||||
msgstr ""
|
||||
msgstr "Kumppanien yhteishenkilöt"
|
||||
|
||||
#. module: base_contact
|
||||
#: view:res.partner.contact:0
|
||||
msgid "Partner Contact"
|
||||
msgstr ""
|
||||
msgstr "Kumppanin Yhteystiedot"
|
||||
|
||||
#. module: base_contact
|
||||
#: model:process.node,name:base_contact.process_node_partners0
|
||||
msgid "Partners"
|
||||
msgstr ""
|
||||
msgstr "Kumppanit"
|
||||
|
||||
#. module: base_contact
|
||||
#: model:process.node,name:base_contact.process_node_addresses0
|
||||
#: view:res.partner:0
|
||||
msgid "Addresses"
|
||||
msgstr ""
|
||||
msgstr "Osoitteet"
|
||||
|
||||
#. module: base_contact
|
||||
#: model:process.node,note:base_contact.process_node_addresses0
|
||||
@@ -301,7 +301,7 @@ msgstr "Työ -ja yksityisosoitteet"
|
||||
#. module: base_contact
|
||||
#: field:res.partner.contact,name:0
|
||||
msgid "Last Name"
|
||||
msgstr ""
|
||||
msgstr "Sukunimi"
|
||||
|
||||
#. module: base_contact
|
||||
#: field:res.partner.job,state:0
|
||||
@@ -312,7 +312,7 @@ msgstr ""
|
||||
#: view:res.partner.contact:0
|
||||
#: view:res.partner.job:0
|
||||
msgid "General"
|
||||
msgstr ""
|
||||
msgstr "Yleiset"
|
||||
|
||||
#. module: base_contact
|
||||
#: selection:res.partner.job,state:0
|
||||
@@ -322,7 +322,7 @@ msgstr ""
|
||||
#. module: base_contact
|
||||
#: view:res.partner.contact:0
|
||||
msgid "General Information"
|
||||
msgstr ""
|
||||
msgstr "Yleiset Tiedot"
|
||||
|
||||
#. module: base_contact
|
||||
#: model:process.node,note:base_contact.process_node_function0
|
||||
@@ -332,12 +332,12 @@ msgstr ""
|
||||
#. module: base_contact
|
||||
#: field:res.partner.job,name:0
|
||||
msgid "Partner"
|
||||
msgstr ""
|
||||
msgstr "Kumppani"
|
||||
|
||||
#. module: base_contact
|
||||
#: field:res.partner.job,date_start:0
|
||||
msgid "Date Start"
|
||||
msgstr ""
|
||||
msgstr "Aloituspäivämäärä"
|
||||
|
||||
#. module: base_contact
|
||||
#: model:process.transition,note:base_contact.process_transition_functiontoaddress0
|
||||
@@ -347,9 +347,9 @@ msgstr ""
|
||||
#. module: base_contact
|
||||
#: field:res.partner.contact,website:0
|
||||
msgid "Website"
|
||||
msgstr ""
|
||||
msgstr "Websivu"
|
||||
|
||||
#. module: base_contact
|
||||
#: field:res.partner.contact,birthdate:0
|
||||
msgid "Birth Date"
|
||||
msgstr ""
|
||||
msgstr "Syntymäaika"
|
||||
|
||||
@@ -7,13 +7,13 @@ msgstr ""
|
||||
"Project-Id-Version: OpenERP Server 5.0.4\n"
|
||||
"Report-Msgid-Bugs-To: support@openerp.com\n"
|
||||
"POT-Creation-Date: 2009-08-28 16:01+0000\n"
|
||||
"PO-Revision-Date: 2009-12-16 13:06+0000\n"
|
||||
"Last-Translator: Silence <Unknown>\n"
|
||||
"PO-Revision-Date: 2010-01-07 11:24+0000\n"
|
||||
"Last-Translator: Wei \"oldrev\" Li <oldrev@gmail.com>\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-17 04:44+0000\n"
|
||||
"X-Launchpad-Export-Date: 2010-01-08 04:38+0000\n"
|
||||
"X-Generator: Launchpad (build Unknown)\n"
|
||||
|
||||
#. module: base_module_merge
|
||||
@@ -29,7 +29,7 @@ msgstr "信息"
|
||||
#. module: base_module_merge
|
||||
#: wizard_view:base_module_merge.module_merge,init:0
|
||||
msgid "Module Merging"
|
||||
msgstr ""
|
||||
msgstr "模块合并"
|
||||
|
||||
#. module: base_module_merge
|
||||
#: wizard_field:base_module_merge.module_merge,info,author:0
|
||||
@@ -60,12 +60,12 @@ msgstr "版本"
|
||||
#: wizard_view:base_module_merge.module_merge,info:0
|
||||
#: wizard_view:base_module_merge.module_merge,save:0
|
||||
msgid "Module Recording"
|
||||
msgstr ""
|
||||
msgstr "模块记录"
|
||||
|
||||
#. module: base_module_merge
|
||||
#: wizard_view:base_module_merge.module_merge,save:0
|
||||
msgid "Thanks in advance for your contribution."
|
||||
msgstr ""
|
||||
msgstr "感谢您的贡献。"
|
||||
|
||||
#. module: base_module_merge
|
||||
#: wizard_field:base_module_merge.module_merge,info,description:0
|
||||
@@ -81,12 +81,12 @@ msgstr "模块名称"
|
||||
#: model:ir.actions.wizard,name:base_module_merge.wizard_base_module_merger
|
||||
#: model:ir.ui.menu,name:base_module_merge.menu_wizard_base_module_merger
|
||||
msgid "Merge module"
|
||||
msgstr ""
|
||||
msgstr "合并模块"
|
||||
|
||||
#. module: base_module_merge
|
||||
#: wizard_field:base_module_merge.module_merge,save,module_file:0
|
||||
msgid "Module .zip File"
|
||||
msgstr ""
|
||||
msgstr "模块 .zip 文件"
|
||||
|
||||
#. module: base_module_merge
|
||||
#: model:ir.module.module,shortdesc:base_module_merge.module_meta_information
|
||||
@@ -96,7 +96,7 @@ msgstr "模块合并"
|
||||
#. module: base_module_merge
|
||||
#: wizard_view:base_module_merge.module_merge,save:0
|
||||
msgid "Module successfully created !"
|
||||
msgstr ""
|
||||
msgstr "模块已成功创建!"
|
||||
|
||||
#. module: base_module_merge
|
||||
#: wizard_field:base_module_merge.module_merge,info,website:0
|
||||
@@ -117,7 +117,7 @@ msgstr "继续"
|
||||
#. module: base_module_merge
|
||||
#: selection:base_module_merge.module_merge,info,data_kind:0
|
||||
msgid "Normal Data"
|
||||
msgstr ""
|
||||
msgstr "普通数据"
|
||||
|
||||
#. module: base_module_merge
|
||||
#: wizard_view:base_module_merge.module_merge,save:0
|
||||
@@ -126,21 +126,23 @@ msgid ""
|
||||
"publish it on OpenERP.com, in the 'Modules' section. You can do it through "
|
||||
"the website or using features of the 'base_module_publish' module."
|
||||
msgstr ""
|
||||
"如果您认为您的模块其他人也会感兴趣,我们希望您能够把它发布到 OpenERP.com "
|
||||
"的“Modules”部分中。您可以直接通过网站进行发布或者使用“base_module_publish”模块。"
|
||||
|
||||
#. module: base_module_merge
|
||||
#: help:base_module_merge.module_merge,init,modules_list:0
|
||||
msgid "Select Modules which you want to merge in single module"
|
||||
msgstr ""
|
||||
msgstr "选择您希望合并成为单个模块的模块列表"
|
||||
|
||||
#. module: base_module_merge
|
||||
#: wizard_field:base_module_merge.module_merge,info,data_kind:0
|
||||
msgid "Type of Data"
|
||||
msgstr ""
|
||||
msgstr "数据类型"
|
||||
|
||||
#. module: base_module_merge
|
||||
#: wizard_view:base_module_merge.module_merge,info:0
|
||||
msgid "Module Information"
|
||||
msgstr ""
|
||||
msgstr "模块信息"
|
||||
|
||||
#. module: base_module_merge
|
||||
#: wizard_button:base_module_merge.module_merge,info,end:0
|
||||
|
||||
@@ -7,13 +7,13 @@ msgstr ""
|
||||
"Project-Id-Version: OpenERP Server 5.0.4\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:51+0000\n"
|
||||
"PO-Revision-Date: 2010-01-07 11:38+0000\n"
|
||||
"Last-Translator: Wei \"oldrev\" Li <oldrev@gmail.com>\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:09+0000\n"
|
||||
"X-Launchpad-Export-Date: 2010-01-08 04:38+0000\n"
|
||||
"X-Generator: Launchpad (build Unknown)\n"
|
||||
|
||||
#. module: base_module_record
|
||||
@@ -43,7 +43,7 @@ msgstr "对象名必须以“x_”开始且不能包含任何特殊字符!"
|
||||
#. module: base_module_record
|
||||
#: wizard_view:base_module_record.module_record_objects,init:0
|
||||
msgid "Choose objects to record"
|
||||
msgstr ""
|
||||
msgstr "选择要记录的对象列表"
|
||||
|
||||
#. module: base_module_record
|
||||
#: wizard_field:base_module_record.module_record_objects,intro,author:0
|
||||
@@ -83,7 +83,7 @@ msgstr "版本"
|
||||
#. module: base_module_record
|
||||
#: wizard_view:base_module_record.module_record_objects,init:0
|
||||
msgid "Objects Recording"
|
||||
msgstr ""
|
||||
msgstr "对象记录"
|
||||
|
||||
#. module: base_module_record
|
||||
#: wizard_field:base_module_record.module_record_objects,init,check_date:0
|
||||
@@ -94,7 +94,7 @@ msgstr ""
|
||||
#: wizard_view:base_module_record.module_record,stop:0
|
||||
#: wizard_view:base_module_record.module_save,init:0
|
||||
msgid "Recording Information"
|
||||
msgstr ""
|
||||
msgstr "记录信息"
|
||||
|
||||
#. module: base_module_record
|
||||
#: wizard_field:base_module_record.module_save,init,info_status:0
|
||||
@@ -111,24 +111,24 @@ msgstr "状态"
|
||||
#: wizard_view:base_module_record.module_save,init:0
|
||||
#: wizard_view:base_module_record.module_save,save:0
|
||||
msgid "Module Recording"
|
||||
msgstr ""
|
||||
msgstr "模块记录"
|
||||
|
||||
#. module: base_module_record
|
||||
#: model:ir.actions.wizard,name:base_module_record.wizard_base_module_record_objects
|
||||
#: model:ir.ui.menu,name:base_module_record.menu_wizard_base_module_record_objects
|
||||
msgid "Export Customizations As a Module"
|
||||
msgstr ""
|
||||
msgstr "把自定义设置作为模块导出"
|
||||
|
||||
#. module: base_module_record
|
||||
#: wizard_view:base_module_record.module_record_objects,save:0
|
||||
#: wizard_view:base_module_record.module_save,save:0
|
||||
msgid "Thanks in advance for your contribution."
|
||||
msgstr ""
|
||||
msgstr "感谢您的贡献。"
|
||||
|
||||
#. module: base_module_record
|
||||
#: help:base_module_record.module_record_objects,init,objects:0
|
||||
msgid "List of objects to be recorded"
|
||||
msgstr ""
|
||||
msgstr "将被记录的对象列表"
|
||||
|
||||
#. module: base_module_record
|
||||
#: wizard_button:base_module_record.module_record,start,start_confirm:0
|
||||
@@ -139,30 +139,30 @@ msgstr "开始录制"
|
||||
#. module: base_module_record
|
||||
#: selection:base_module_record.module_save,init,info_status:0
|
||||
msgid "Not Recording"
|
||||
msgstr ""
|
||||
msgstr "没有记录"
|
||||
|
||||
#. module: base_module_record
|
||||
#: wizard_field:base_module_record.module_record_objects,intro,description:0
|
||||
#: wizard_field:base_module_record.module_save,info,description:0
|
||||
msgid "Full Description"
|
||||
msgstr ""
|
||||
msgstr "完整描述"
|
||||
|
||||
#. module: base_module_record
|
||||
#: wizard_field:base_module_record.module_record_objects,intro,name:0
|
||||
#: wizard_field:base_module_record.module_save,info,name:0
|
||||
msgid "Module Name"
|
||||
msgstr ""
|
||||
msgstr "模块名称"
|
||||
|
||||
#. module: base_module_record
|
||||
#: wizard_field:base_module_record.module_record_objects,init,objects:0
|
||||
msgid "Objects"
|
||||
msgstr ""
|
||||
msgstr "对象"
|
||||
|
||||
#. module: base_module_record
|
||||
#: wizard_field:base_module_record.module_record_objects,save,module_file:0
|
||||
#: wizard_field:base_module_record.module_save,save,module_file:0
|
||||
msgid "Module .zip File"
|
||||
msgstr ""
|
||||
msgstr "模块 .zip 文件"
|
||||
|
||||
#. module: base_module_record
|
||||
#: wizard_view:base_module_record.module_record,start:0
|
||||
@@ -173,49 +173,49 @@ msgstr ""
|
||||
#: wizard_view:base_module_record.module_record_objects,save:0
|
||||
#: wizard_view:base_module_record.module_save,save:0
|
||||
msgid "Module successfully created !"
|
||||
msgstr ""
|
||||
msgstr "模块已成功创建!"
|
||||
|
||||
#. module: base_module_record
|
||||
#: wizard_view:base_module_record.module_record,start:0
|
||||
msgid "Recording Stopped"
|
||||
msgstr ""
|
||||
msgstr "记录已停止"
|
||||
|
||||
#. module: base_module_record
|
||||
#: selection:base_module_record.module_record_objects,init,filter_cond:0
|
||||
msgid "Created"
|
||||
msgstr ""
|
||||
msgstr "已创建"
|
||||
|
||||
#. module: base_module_record
|
||||
#: wizard_view:base_module_record.module_record_objects,end:0
|
||||
#: wizard_view:base_module_record.module_save,end:0
|
||||
msgid "Thanks For using Module Recorder"
|
||||
msgstr ""
|
||||
msgstr "感谢使用模块记录器"
|
||||
|
||||
#. module: base_module_record
|
||||
#: wizard_field:base_module_record.module_record,start,continue:0
|
||||
msgid "Continue Previous Session"
|
||||
msgstr ""
|
||||
msgstr "继续上次会话"
|
||||
|
||||
#. module: base_module_record
|
||||
#: wizard_field:base_module_record.module_record_objects,intro,website:0
|
||||
#: wizard_field:base_module_record.module_save,info,website:0
|
||||
msgid "Documentation URL"
|
||||
msgstr ""
|
||||
msgstr "文档地址-URL"
|
||||
|
||||
#. module: base_module_record
|
||||
#: selection:base_module_record.module_record_objects,init,filter_cond:0
|
||||
msgid "Modified"
|
||||
msgstr ""
|
||||
msgstr "已修改"
|
||||
|
||||
#. module: base_module_record
|
||||
#: selection:base_module_record.module_save,init,info_status:0
|
||||
msgid "Recording"
|
||||
msgstr ""
|
||||
msgstr "记录中"
|
||||
|
||||
#. module: base_module_record
|
||||
#: wizard_button:base_module_record.module_record_objects,init,record:0
|
||||
msgid "Record"
|
||||
msgstr ""
|
||||
msgstr "记录"
|
||||
|
||||
#. module: base_module_record
|
||||
#: wizard_button:base_module_record.module_record,stop,end:0
|
||||
@@ -223,25 +223,25 @@ msgstr ""
|
||||
#: wizard_button:base_module_record.module_save,info,save:0
|
||||
#: wizard_button:base_module_record.module_save,init,check:0
|
||||
msgid "Continue"
|
||||
msgstr ""
|
||||
msgstr "继续"
|
||||
|
||||
#. module: base_module_record
|
||||
#: model:ir.module.module,shortdesc:base_module_record.module_meta_information
|
||||
#: model:ir.ui.menu,name:base_module_record.menu_wizard_base_mod_rec_rec
|
||||
msgid "Module Recorder"
|
||||
msgstr ""
|
||||
msgstr "模块记录器"
|
||||
|
||||
#. module: base_module_record
|
||||
#: selection:base_module_record.module_record_objects,intro,data_kind:0
|
||||
#: selection:base_module_record.module_save,info,data_kind:0
|
||||
msgid "Normal Data"
|
||||
msgstr ""
|
||||
msgstr "普通数据"
|
||||
|
||||
#. module: base_module_record
|
||||
#: wizard_button:base_module_record.module_record_objects,end,end:0
|
||||
#: wizard_button:base_module_record.module_save,end,end:0
|
||||
msgid "OK"
|
||||
msgstr ""
|
||||
msgstr "确定"
|
||||
|
||||
#. module: base_module_record
|
||||
#: wizard_view:base_module_record.module_record_objects,save:0
|
||||
@@ -251,6 +251,8 @@ msgid ""
|
||||
"publish it on OpenERP.com, in the 'Modules' section. You can do it through "
|
||||
"the website or using features of the 'base_module_publish' module."
|
||||
msgstr ""
|
||||
"如果您认为您的模块其他人也会感兴趣,我们希望您能够把它发布到 OpenERP.com "
|
||||
"的“Modules”部分中。您可以直接通过网站进行发布或者使用“base_module_publish”模块。"
|
||||
|
||||
#. module: base_module_record
|
||||
#: wizard_view:base_module_record.module_record,start:0
|
||||
@@ -281,13 +283,13 @@ msgstr ""
|
||||
#: wizard_field:base_module_record.module_record_objects,intro,data_kind:0
|
||||
#: wizard_field:base_module_record.module_save,info,data_kind:0
|
||||
msgid "Type of Data"
|
||||
msgstr ""
|
||||
msgstr "数据类型"
|
||||
|
||||
#. module: base_module_record
|
||||
#: wizard_view:base_module_record.module_record_objects,intro:0
|
||||
#: wizard_view:base_module_record.module_save,info:0
|
||||
msgid "Module Information"
|
||||
msgstr ""
|
||||
msgstr "模块信息"
|
||||
|
||||
#. module: base_module_record
|
||||
#: model:ir.actions.wizard,name:base_module_record.wizard_base_module_save
|
||||
@@ -308,13 +310,13 @@ msgstr ""
|
||||
#: wizard_button:base_module_record.module_save,info,end:0
|
||||
#: wizard_button:base_module_record.module_save,init,end:0
|
||||
msgid "Cancel"
|
||||
msgstr ""
|
||||
msgstr "取消"
|
||||
|
||||
#. module: base_module_record
|
||||
#: wizard_button:base_module_record.module_record_objects,save,end:0
|
||||
#: wizard_button:base_module_record.module_save,save,end:0
|
||||
msgid "Close"
|
||||
msgstr ""
|
||||
msgstr "关闭"
|
||||
|
||||
#. module: base_module_record
|
||||
#: selection:base_module_record.module_record_objects,init,filter_cond:0
|
||||
@@ -324,4 +326,4 @@ msgstr ""
|
||||
#. module: base_module_record
|
||||
#: model:ir.ui.menu,name:base_module_record.menu_wizard_base_module_record_stop
|
||||
msgid "Stop Recording"
|
||||
msgstr ""
|
||||
msgstr "结束记录"
|
||||
|
||||
@@ -7,13 +7,13 @@ msgstr ""
|
||||
"Project-Id-Version: OpenERP Server 5.0.4\n"
|
||||
"Report-Msgid-Bugs-To: support@openerp.com\n"
|
||||
"POT-Creation-Date: 2009-08-28 16:01+0000\n"
|
||||
"PO-Revision-Date: 2008-11-01 13:18+0000\n"
|
||||
"Last-Translator: Sergei Kostigoff <sergei.kostigoff@gmail.com>\n"
|
||||
"PO-Revision-Date: 2010-01-04 08:52+0000\n"
|
||||
"Last-Translator: Stanislav Terentyev <stas@chinese-russian.com>\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:18+0000\n"
|
||||
"X-Launchpad-Export-Date: 2010-01-05 04:40+0000\n"
|
||||
"X-Generator: Launchpad (build Unknown)\n"
|
||||
|
||||
#. module: base_report_designer
|
||||
@@ -24,7 +24,7 @@ msgstr "Введение"
|
||||
#. module: base_report_designer
|
||||
#: wizard_view:base_report_designer.modify,send_form:0
|
||||
msgid "Upload your modified report"
|
||||
msgstr "Выгрузить ваш измененный отчет"
|
||||
msgstr "Выгрузить измененный вами отчет"
|
||||
|
||||
#. module: base_report_designer
|
||||
#: wizard_button:base_report_designer.modify,get_form_result,send_form:0
|
||||
@@ -54,7 +54,7 @@ msgstr "Ваш отчет был изменен"
|
||||
#. module: base_report_designer
|
||||
#: model:ir.module.module,shortdesc:base_report_designer.module_meta_information
|
||||
msgid "Report designer interface module"
|
||||
msgstr ""
|
||||
msgstr "Модуль интерфейса для оформления отчетов"
|
||||
|
||||
#. module: base_report_designer
|
||||
#: wizard_field:base_report_designer.modify,get_form,report_id:0
|
||||
@@ -99,6 +99,10 @@ msgid ""
|
||||
"to modify it. Once it is modified, re-upload it in Open ERP using this "
|
||||
"wizard."
|
||||
msgstr ""
|
||||
"Это шаблон запрошенного вами отчета. Сохраните его как файл формата .SXW и "
|
||||
"откройте с помощью программы OpenOffice. Не забудьте установить пакет Tiny "
|
||||
"OpenOffice для его изменения. По завершении изменения загрузите его снова в "
|
||||
"Open ERP с помощью этого мастера."
|
||||
|
||||
#. module: base_report_designer
|
||||
#: wizard_button:base_report_designer.modify,send_form,send_form_result:0
|
||||
@@ -108,7 +112,7 @@ msgstr "Обновить отчет"
|
||||
#. module: base_report_designer
|
||||
#: selection:base_report_designer.modify,init,operation:0
|
||||
msgid "Create a new report"
|
||||
msgstr ""
|
||||
msgstr "Создать новый отчет"
|
||||
|
||||
#. module: base_report_designer
|
||||
#: selection:base_report_designer.modify,init,operation:0
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -7,24 +7,24 @@ msgstr ""
|
||||
"Project-Id-Version: OpenERP Server 5.0.4\n"
|
||||
"Report-Msgid-Bugs-To: support@openerp.com\n"
|
||||
"POT-Creation-Date: 2009-08-28 16:01+0000\n"
|
||||
"PO-Revision-Date: 2009-12-15 13:43+0000\n"
|
||||
"Last-Translator: Silence <Unknown>\n"
|
||||
"PO-Revision-Date: 2010-01-08 04:21+0000\n"
|
||||
"Last-Translator: Wei \"oldrev\" Li <oldrev@gmail.com>\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-01-08 04:38+0000\n"
|
||||
"X-Generator: Launchpad (build Unknown)\n"
|
||||
|
||||
#. module: board_account
|
||||
#: view:board.board:0
|
||||
msgid "Analytic accounts to close"
|
||||
msgstr ""
|
||||
msgstr "要关闭的分析科目"
|
||||
|
||||
#. module: board_account
|
||||
#: view:board.board:0
|
||||
msgid "Draft invoices"
|
||||
msgstr ""
|
||||
msgstr "发票草稿"
|
||||
|
||||
#. module: board_account
|
||||
#: constraint:ir.ui.view:0
|
||||
@@ -35,12 +35,12 @@ msgstr "无效的XML视图结构!"
|
||||
#: model:ir.actions.act_window,name:board_account.open_board_account
|
||||
#: model:ir.ui.menu,name:board_account.menu_board_account
|
||||
msgid "Accounting Dashboard"
|
||||
msgstr ""
|
||||
msgstr "会计看板"
|
||||
|
||||
#. module: board_account
|
||||
#: model:ir.actions.act_window,name:board_account.action_aged_receivable
|
||||
msgid "Receivable Accounts"
|
||||
msgstr ""
|
||||
msgstr "应收款科目"
|
||||
|
||||
#. module: board_account
|
||||
#: view:board.board:0
|
||||
@@ -77,7 +77,7 @@ msgstr ""
|
||||
#. module: board_account
|
||||
#: constraint:ir.actions.act_window:0
|
||||
msgid "Invalid model name in the action definition."
|
||||
msgstr ""
|
||||
msgstr "在动作定义使用了无效的模型名称。"
|
||||
|
||||
#. module: board_account
|
||||
#: model:ir.ui.menu,name:board_account.next_id_68
|
||||
@@ -87,7 +87,7 @@ msgstr "会计及账簿"
|
||||
#. module: board_account
|
||||
#: view:board.board:0
|
||||
msgid "Account Board"
|
||||
msgstr ""
|
||||
msgstr "会计看板"
|
||||
|
||||
#. module: board_account
|
||||
#: view:board.board:0
|
||||
|
||||
@@ -7,13 +7,13 @@ msgstr ""
|
||||
"Project-Id-Version: OpenERP Server 5.0.4\n"
|
||||
"Report-Msgid-Bugs-To: support@openerp.com\n"
|
||||
"POT-Creation-Date: 2009-08-28 16:01+0000\n"
|
||||
"PO-Revision-Date: 2008-11-04 11:07+0000\n"
|
||||
"Last-Translator: Sergei Kostigoff <sergei.kostigoff@gmail.com>\n"
|
||||
"PO-Revision-Date: 2010-01-04 08:44+0000\n"
|
||||
"Last-Translator: Stanislav Terentyev <stas@chinese-russian.com>\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:04+0000\n"
|
||||
"X-Launchpad-Export-Date: 2010-01-05 04:40+0000\n"
|
||||
"X-Generator: Launchpad (build Unknown)\n"
|
||||
|
||||
#. module: board_association
|
||||
@@ -24,7 +24,7 @@ msgstr "Ассоциации"
|
||||
#. module: board_association
|
||||
#: model:ir.module.module,shortdesc:board_association.module_meta_information
|
||||
msgid "Dashboard for Associations"
|
||||
msgstr ""
|
||||
msgstr "Панель инструментов для ассоциаций"
|
||||
|
||||
#. module: board_association
|
||||
#: constraint:ir.ui.view:0
|
||||
@@ -55,7 +55,7 @@ msgstr "НЕоплаченные счета"
|
||||
#. module: board_association
|
||||
#: constraint:ir.actions.act_window:0
|
||||
msgid "Invalid model name in the action definition."
|
||||
msgstr ""
|
||||
msgstr "Недопустимое имя модели в определении действия."
|
||||
|
||||
#. module: board_association
|
||||
#: view:board.board:0
|
||||
|
||||
@@ -7,25 +7,25 @@ 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-15 13:24+0000\n"
|
||||
"Last-Translator: Silence <Unknown>\n"
|
||||
"PO-Revision-Date: 2010-01-07 11:12+0000\n"
|
||||
"Last-Translator: Wei \"oldrev\" Li <oldrev@gmail.com>\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:06+0000\n"
|
||||
"X-Launchpad-Export-Date: 2010-01-08 04:38+0000\n"
|
||||
"X-Generator: Launchpad (build Unknown)\n"
|
||||
|
||||
#. module: board_sale
|
||||
#: model:ir.module.module,shortdesc:board_sale.module_meta_information
|
||||
msgid "Dashboard for sales"
|
||||
msgstr ""
|
||||
msgstr "销售情况看板"
|
||||
|
||||
#. module: board_sale
|
||||
#: model:ir.actions.act_window,name:board_sale.open_board_sales_manager
|
||||
#: model:ir.ui.menu,name:board_sale.menu_board_sales_manager
|
||||
msgid "Sale Dashboard"
|
||||
msgstr ""
|
||||
msgstr "销售看板"
|
||||
|
||||
#. module: board_sale
|
||||
#: view:board.board:0
|
||||
|
||||
@@ -37,7 +37,9 @@
|
||||
"author" : "Tiny",
|
||||
'category': 'Generic Modules/Others',
|
||||
'website': 'http://www.openerp.com',
|
||||
"init_xml" : [],
|
||||
"init_xml" : [
|
||||
'caldav_data.xml'
|
||||
],
|
||||
"demo_xml" : [],
|
||||
"update_xml" : [
|
||||
'security/ir.model.access.csv',
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
<?xml version="1.0"?>
|
||||
<openerp>
|
||||
|
||||
<data noupdate="1">
|
||||
<record model="res.alarm" id="alarm1">
|
||||
<field name="name">1 minute before</field>
|
||||
<field name="active" eval="1" />
|
||||
<field name="trigger_duration" eval="1" />
|
||||
<field name="trigger_interval">minutes</field>
|
||||
<field name="trigger_occurs">before</field>
|
||||
<field name="trigger_related">start</field>
|
||||
</record>
|
||||
|
||||
<record model="res.alarm" id="alarm2">
|
||||
<field name="name">5 minutes before</field>
|
||||
<field name="active" eval="1" />
|
||||
<field name="trigger_duration" eval="5" />
|
||||
<field name="trigger_interval">minutes</field>
|
||||
<field name="trigger_occurs">before</field>
|
||||
<field name="trigger_related">start</field>
|
||||
</record>
|
||||
|
||||
<record model="res.alarm" id="alarm3">
|
||||
<field name="name">10 minutes before</field>
|
||||
<field name="active" eval="1" />
|
||||
<field name="trigger_duration" eval="10" />
|
||||
<field name="trigger_interval">minutes</field>
|
||||
<field name="trigger_occurs">before</field>
|
||||
<field name="trigger_related">start</field>
|
||||
</record>
|
||||
|
||||
<record model="res.alarm" id="alarm4">
|
||||
<field name="name">15 minutes before</field>
|
||||
<field name="active" eval="1" />
|
||||
<field name="trigger_duration" eval="15" />
|
||||
<field name="trigger_interval">minutes</field>
|
||||
<field name="trigger_occurs">before</field>
|
||||
<field name="trigger_related">start</field>
|
||||
</record>
|
||||
|
||||
<record model="res.alarm" id="alarm5">
|
||||
<field name="name">30 minutes before</field>
|
||||
<field name="active" eval="1" />
|
||||
<field name="trigger_duration" eval="30" />
|
||||
<field name="trigger_interval">minutes</field>
|
||||
<field name="trigger_occurs">before</field>
|
||||
<field name="trigger_related">start</field>
|
||||
</record>
|
||||
|
||||
<record model="res.alarm" id="alarm6">
|
||||
<field name="name">45 minutes before</field>
|
||||
<field name="active" eval="1" />
|
||||
<field name="trigger_duration" eval="45" />
|
||||
<field name="trigger_interval">minutes</field>
|
||||
<field name="trigger_occurs">before</field>
|
||||
<field name="trigger_related">start</field>
|
||||
</record>
|
||||
|
||||
<record model="res.alarm" id="alarm7">
|
||||
<field name="name">1 hour before</field>
|
||||
<field name="active" eval="1" />
|
||||
<field name="trigger_duration" eval="1" />
|
||||
<field name="trigger_interval">hours</field>
|
||||
<field name="trigger_occurs">before</field>
|
||||
<field name="trigger_related">start</field>
|
||||
</record>
|
||||
|
||||
<record model="res.alarm" id="alarm8">
|
||||
<field name="name">2 hours before</field>
|
||||
<field name="active" eval="1" />
|
||||
<field name="trigger_duration" eval="2" />
|
||||
<field name="trigger_interval">hours</field>
|
||||
<field name="trigger_occurs">before</field>
|
||||
<field name="trigger_related">start</field>
|
||||
</record>
|
||||
|
||||
<record model="res.alarm" id="alarm9">
|
||||
<field name="name">3 hours before</field>
|
||||
|
||||
<field name="active" eval="1" />
|
||||
<field name="trigger_duration" eval="3" />
|
||||
<field name="trigger_interval">hours</field>
|
||||
<field name="trigger_occurs">before</field>
|
||||
<field name="trigger_related">start</field>
|
||||
</record>
|
||||
|
||||
<record model="res.alarm" id="alarm10">
|
||||
<field name="name">4 hours before</field>
|
||||
|
||||
<field name="active" eval="1" />
|
||||
<field name="trigger_duration" eval="4" />
|
||||
<field name="trigger_interval">hours</field>
|
||||
<field name="trigger_occurs">before</field>
|
||||
<field name="trigger_related">start</field>
|
||||
</record>
|
||||
|
||||
<record model="res.alarm" id="alarm11">
|
||||
<field name="name">5 hours before</field>
|
||||
|
||||
<field name="active" eval="1" />
|
||||
<field name="trigger_duration" eval="5" />
|
||||
<field name="trigger_interval">hours</field>
|
||||
<field name="trigger_occurs">before</field>
|
||||
<field name="trigger_related">start</field>
|
||||
</record>
|
||||
|
||||
<record model="res.alarm" id="alarm12">
|
||||
<field name="name">18 hours before</field>
|
||||
|
||||
<field name="active" eval="1" />
|
||||
<field name="trigger_duration" eval="18" />
|
||||
<field name="trigger_interval">hours</field>
|
||||
<field name="trigger_occurs">before</field>
|
||||
<field name="trigger_related">start</field>
|
||||
</record>
|
||||
|
||||
|
||||
<!-- Scheduler for Event Alarm-->
|
||||
<record forcecreate="True" id="ir_cron_scheduler_alarm"
|
||||
model="ir.cron">
|
||||
<field name="name">Run Event Reminder</field>
|
||||
<field eval="True" name="active" />
|
||||
<field name="user_id" ref="base.user_root" />
|
||||
<field name="interval_number">1</field>
|
||||
<field name="interval_type">minutes</field>
|
||||
<field name="numbercall">-1</field>
|
||||
<field eval="False" name="doall" />
|
||||
<field eval="'calendar.alarm'" name="model" />
|
||||
<field eval="'do_run_scheduler'" name="function" />
|
||||
<field eval="'(False,)'" name="args" />
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
+159
-50
@@ -1,86 +1,195 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<!-- Attendee invite wizard-->
|
||||
|
||||
<record id="view_calendar_invite_attendee_wizard" model="ir.ui.view">
|
||||
<field name="name">Invite Attendees</field>
|
||||
<field name="model">caldav.invite.attendee</field>
|
||||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Invite Attendees">
|
||||
<separator string="Select User" colspan="4"/>
|
||||
<newline/>
|
||||
<field name="user_id" select="1" on_change="onchange_user_id(user_id)"/>
|
||||
<field name="email" />
|
||||
<field name="role" select="1" />
|
||||
<field name="rsvp" />
|
||||
<separator string="" colspan="6" />
|
||||
<label string="" colspan="2"/>
|
||||
<button icon='gtk-cancel' special="cancel" string="Cancel"/>
|
||||
<button name="do_invite" string="Invite" type="object" icon="gtk-ok"/>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_view_calendar_invite_attendee_wizard" model="ir.actions.act_window">
|
||||
<field name="name">Invite Attendees</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">caldav.invite.attendee</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
|
||||
<record id="caldav_attendee_form_view" model="ir.ui.view">
|
||||
<field name="name">crm.case.caldav.attendee</field>
|
||||
<field name="model">crm.caldav.attendee</field>
|
||||
<field name="name">calendar.attendee.form</field>
|
||||
<field name="model">calendar.attendee</field>
|
||||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Atendee details">
|
||||
<field name="user_id" on_change="onchange_user_id(user_id)" />
|
||||
<field name="email" select="1"/>
|
||||
<newline />
|
||||
<field name="role" select="1" />
|
||||
<field name="cutype" select="1" />
|
||||
<newline />
|
||||
<field name="rsvp" />
|
||||
<notebook colspan="4">
|
||||
<page string="Basic details">
|
||||
<field name="cn" select="1" colspan="2" />
|
||||
<field name="partstat" />
|
||||
<field name="cutype" select="1" />
|
||||
<field name="role" select="1" />
|
||||
<field name="rsvp" />
|
||||
</page>
|
||||
<page string="Other">
|
||||
<field name="delegated_to" select="1" />
|
||||
<field name="delegated_from" select="1" />
|
||||
<field name="sent_by" />
|
||||
<field name="dir" />
|
||||
<page string="Details">
|
||||
<field name="sent_by_uid" />
|
||||
<field name="dir" widget='url' />
|
||||
<field name="language" />
|
||||
</page>
|
||||
<page string="Delegation Info">
|
||||
<separator string="Delegated to" colspan="4" />
|
||||
<field name="del_to_user_ids" nolabel="1" colspan="4" />
|
||||
<separator string="Delegated from" colspan="4" />
|
||||
<field name="del_from_user_ids" nolabel="1" colspan="4" />
|
||||
</page>
|
||||
</notebook>
|
||||
<group col="6" colspan="4">
|
||||
<field name="state" select="2" />
|
||||
<button name="do_tentative"
|
||||
string="Uncertain"
|
||||
states="needs-action" type="object"
|
||||
icon="terp-crm" />
|
||||
<button name="do_accept"
|
||||
string="Accept"
|
||||
states="needs-action" type="object"
|
||||
icon="gtk-apply" />
|
||||
<button name="do_decline"
|
||||
string="Decline"
|
||||
states="needs-action" type="object"
|
||||
icon="gtk-cancel" />
|
||||
<button
|
||||
name="%(caldav.action_view_calendar_invite_attendee_wizard)d"
|
||||
states="needs-action" string="Delegate"
|
||||
type="action" icon="gtk-sort-descending"
|
||||
context="{'model' : 'calendar.attendee'}" />
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="caldav_attendee_tree_view" model="ir.ui.view">
|
||||
<field name="name">crm.case.caldav.attendee</field>
|
||||
<field name="model">crm.caldav.attendee</field>
|
||||
<field name="name">calendar.attendee.tree</field>
|
||||
<field name="model">calendar.attendee</field>
|
||||
<field name="type">tree</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Atendee details">
|
||||
<field name="cn" select="1" />
|
||||
<field name="partstat" />
|
||||
<field name="state" />
|
||||
<field name="cutype" select="1" />
|
||||
<field name="role" select="1" />
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_view_attendee_form" model="ir.actions.act_window">
|
||||
<field name="name">My Invitations</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">calendar.attendee</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="view_id" ref="caldav_attendee_tree_view" />
|
||||
<field name="domain">[('user_id', '=', uid)]</field>
|
||||
<field name="context">{'default_sent_by_uid': uid}</field>
|
||||
</record>
|
||||
|
||||
<record id="action_invitation_tree_view1" model="ir.actions.act_window.view">
|
||||
<field eval="1" name="sequence" />
|
||||
<field name="view_mode">tree</field>
|
||||
<field name="view_id" ref="caldav_attendee_tree_view" />
|
||||
<field name="act_window_id" ref="action_view_attendee_form" />
|
||||
</record>
|
||||
|
||||
<record id="action_invitation_form_view1" model="ir.actions.act_window.view">
|
||||
<field eval="2" name="sequence" />
|
||||
<field name="view_mode">form</field>
|
||||
<field name="view_id" ref="caldav_attendee_form_view" />
|
||||
<field name="act_window_id" ref="action_view_attendee_form" />
|
||||
</record>
|
||||
|
||||
|
||||
<record id="caldav_attendee_tree_model" model="ir.ui.view">
|
||||
<field name="name">calendar.attendee.tree1</field>
|
||||
<field name="model">calendar.attendee</field>
|
||||
<field name="type">tree</field>
|
||||
<field name="priority">10</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Atendee details">
|
||||
<field name="user_id" select="1" />
|
||||
<field name="email" />
|
||||
<field name="state" />
|
||||
<field name="cutype" select="1" />
|
||||
<field name="role" select="1" />
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="caldav_alarm_form_view" model="ir.ui.view">
|
||||
<field name="name">crm.case.caldav.alarm.form</field>
|
||||
<field name="model">crm.caldav.alarm</field>
|
||||
<record id="caldav_attendee_form_model" model="ir.ui.view">
|
||||
<field name="name">calendar.attendee.form1</field>
|
||||
<field name="model">calendar.attendee</field>
|
||||
<field name="type">form</field>
|
||||
<field name="priority">10</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Atendee details">
|
||||
<field name="user_id" select="1"/>
|
||||
<field name="state" />
|
||||
<field name="cutype" select="1" />
|
||||
<field name="role" select="1" />
|
||||
<newline/>
|
||||
<field name="rsvp" select="1" />
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="res_alarm_form_view" model="ir.ui.view">
|
||||
<field name="name">res.alarm.form</field>
|
||||
<field name="model">res.alarm</field>
|
||||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Alarm details">
|
||||
<field name="action"/>
|
||||
<field name="name" select="1" attrs="{'required' : [('action','in',('EMAIL', 'DISPLAY'))]}"/>
|
||||
<separator string="Description" colspan="4"/>
|
||||
<field name="description" colspan="4" nolabel="1" attrs="{'required' : [('action','in',('EMAIL'))]}"/>
|
||||
<form string="Reminder details">
|
||||
<field name="name" select="1"/>
|
||||
<field name="active"/>
|
||||
<group string="Reminder details" col="4" colspan="4">
|
||||
<field name="trigger_duration" nolabel="1" select="1"/>
|
||||
<field name="trigger_interval" nolabel="1" select="1"/>
|
||||
<field name="trigger_occurs" nolabel="1" select="1"/>
|
||||
<field name="trigger_related" nolabel="1" select="1"/>
|
||||
</group>
|
||||
<field name="duration"/>
|
||||
<field name="repeat"/>
|
||||
<field name="attach" colspan="4" attrs="{'required' : [('action','in',('AUDIO', 'PROCEDURE'))]}"/>
|
||||
</group>
|
||||
<field name="duration"/>
|
||||
<field name="repeat"/>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="caldav_alarm_tree_view" model="ir.ui.view">
|
||||
<field name="name">crm.case.caldav.alarm.tree</field>
|
||||
<field name="model">crm.caldav.alarm</field>
|
||||
<record id="res_tree_view" model="ir.ui.view">
|
||||
<field name="name">res.alarm.tree</field>
|
||||
<field name="model">res.alarm</field>
|
||||
<field name="type">tree</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Alarm details">
|
||||
<field name="name" select="1"/>
|
||||
<field name="action"/>
|
||||
<field name="trigger_interval" select="1"/>
|
||||
<field name="trigger_duration" select="1"/>
|
||||
<field name="trigger_related" select="1"/>
|
||||
<field name="trigger_occurs" select="1"/>
|
||||
<field name="active"/>
|
||||
</tree>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Reminder details">
|
||||
<field name="name" select="1"/>
|
||||
<field name="trigger_interval" select="1"/>
|
||||
<field name="trigger_duration" select="1"/>
|
||||
<field name="trigger_related" select="1"/>
|
||||
<field name="trigger_occurs" select="1"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
</record>
|
||||
|
||||
<record id="view_caldav_set_rrule_wizard" model="ir.ui.view">
|
||||
<field name="name">Add RRule</field>
|
||||
@@ -97,7 +206,7 @@
|
||||
<field name="end_date"
|
||||
attrs="{'required' : [('count','<=',0), ('freq', '!=', 'None')]}"/>
|
||||
<group col="7" colspan="4" name="Select weekdays"
|
||||
attrs="{'invisible' : [('freq','!=','WEEKLY')]}">
|
||||
attrs="{'invisible' : [('freq','!=','weekly')]}">
|
||||
<separator string="" colspan="6" />
|
||||
<newline />
|
||||
<field name="mo" colspan="1" />
|
||||
@@ -109,7 +218,7 @@
|
||||
<field name="su" colspan="1" />
|
||||
<newline />
|
||||
</group>
|
||||
<group col="4" colspan="4" attrs="{'invisible' : [('freq','!=','MONTHLY'), ('freq','!=','YEARLY')]}">
|
||||
<group col="4" colspan="4" attrs="{'invisible' : [('freq','!=','monthly'), ('freq','!=','yearly')]}">
|
||||
<separator string="" colspan="6"/>
|
||||
<group col="2" colspan="4">
|
||||
<field name="select1"/>
|
||||
@@ -127,14 +236,15 @@
|
||||
<label string="of the Month" />
|
||||
<newline />
|
||||
</group>
|
||||
<group col="2" colspan="4" attrs="{'invisible' : [('freq','!=','YEARLY')]}">
|
||||
<group col="2" colspan="4" attrs="{'invisible' : [('freq','!=','yearly')]}">
|
||||
<field name="month_list" string="of" colspan="1"
|
||||
attrs="{'required' : [('freq','=','YEARLY')]}"/>
|
||||
attrs="{'required' : [('freq','=','yearly')]}"/>
|
||||
</group>
|
||||
</group>
|
||||
<separator string="" colspan="6" />
|
||||
<label string="" colspan="3"/>
|
||||
<button name="add_rrule" string="Ok" type="object" icon="gtk-ok"/>
|
||||
<label string="" colspan="2"/>
|
||||
<button icon='gtk-cancel' special="cancel" string="Cancel"/>
|
||||
<button name="do_add" string="Ok" type="object" icon="gtk-ok"/>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
@@ -148,6 +258,5 @@
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
|
||||
+31
-37
@@ -75,14 +75,8 @@ class CalDAV(object):
|
||||
__attribute__ = {
|
||||
}
|
||||
def get_recurrent_dates(self, rrulestring, exdate, startdate=None):
|
||||
def todate(date):
|
||||
val = parser.parse(''.join((re.compile('\d')).findall(date)) + 'Z')
|
||||
return val
|
||||
|
||||
if not startdate:
|
||||
startdate = datetime.now()
|
||||
else:
|
||||
startdate = todate(startdate)
|
||||
startdate = datetime.now()
|
||||
rset1 = rrulestr(rrulestring, dtstart=startdate, forceset=True)
|
||||
|
||||
for date in exdate:
|
||||
@@ -133,10 +127,10 @@ class CalDAV(object):
|
||||
uidval = common.openobjectid2uid(cr, data[map_field], model)
|
||||
vevent.add('uid').value = uidval
|
||||
elif field == 'attendee' and data[map_field]:
|
||||
attendee_obj = self.pool.get('caldav.attendee')
|
||||
attendee_obj = self.pool.get('basic.calendar.attendee')
|
||||
vevent = attendee_obj.export_ical(cr, uid, data[map_field], vevent, context=context)
|
||||
elif field == 'valarm' and data[map_field]:
|
||||
alarm_obj = self.pool.get('caldav.alarm')
|
||||
alarm_obj = self.pool.get('basic.calendar.alarm')
|
||||
vevent = alarm_obj.export_ical(cr, uid, data[map_field][0], vevent, context=context)
|
||||
elif data[map_field]:
|
||||
if map_type == "text":
|
||||
@@ -161,12 +155,12 @@ class CalDAV(object):
|
||||
for child in parsedCal.getChildren():
|
||||
for cal_data in child.getChildren():
|
||||
if cal_data.name.lower() == 'attendee':
|
||||
attendee = self.pool.get('caldav.attendee')
|
||||
attendee = self.pool.get('basic.calendar.attendee')
|
||||
att_data.append(attendee.import_ical(cr, uid, cal_data))
|
||||
self.ical_set(cal_data.name.lower(), att_data, 'value')
|
||||
continue
|
||||
if cal_data.name.lower() == 'valarm':
|
||||
alarm = self.pool.get('caldav.alarm')
|
||||
alarm = self.pool.get('basic.calendar.alarm')
|
||||
vals = alarm.import_ical(cr, uid, cal_data)
|
||||
self.ical_set(cal_data.name.lower(), vals, 'value')
|
||||
continue
|
||||
@@ -183,7 +177,7 @@ class CalDAV(object):
|
||||
|
||||
|
||||
class Calendar(CalDAV, osv.osv_memory):
|
||||
_name = 'caldav.calendar'
|
||||
_name = 'basic.calendar'
|
||||
__attribute__ = {
|
||||
'prodid': None, # Use: R-1, Type: TEXT, Specifies the identifier for the product that created the iCalendar object.
|
||||
'version': None, # Use: R-1, Type: TEXT, Specifies the identifier corresponding to the highest version number
|
||||
@@ -202,7 +196,7 @@ class Calendar(CalDAV, osv.osv_memory):
|
||||
Calendar()
|
||||
|
||||
class Event(CalDAV, osv.osv_memory):
|
||||
_name = 'caldav.event'
|
||||
_name = 'basic.calendar.event'
|
||||
__attribute__ = {
|
||||
'class': None, # Use: O-1, Type: TEXT, Defines the access classification for a calendar component like "PUBLIC" / "PRIVATE" / "CONFIDENTIAL"
|
||||
'created': None, # Use: O-1, Type: DATE-TIME, Specifies the date and time that the calendar information was created by the calendar user agent in the calendar store.
|
||||
@@ -230,7 +224,7 @@ class Event(CalDAV, osv.osv_memory):
|
||||
'exrule': None, # Use: O-n, Type: RECUR, Defines a rule or repeating pattern for an exception to a recurrence set.
|
||||
'rstatus': None,
|
||||
'related': None, # Use: O-n, Specify the relationship of the alarm trigger with respect to the start or end of the calendar component.
|
||||
# like A trigger set 5 minutes after the end of the event or to-do.---> TRIGGER;RELATED=END:PT5M
|
||||
# like A trigger set 5 minutes after the end of the event or to-do.---> TRIGGER;related=END:PT5M
|
||||
'resources': None, # Use: O-n, Type: TEXT, Defines the equipment or resources anticipated for an activity specified by a calendar entity like RESOURCES:EASEL,PROJECTOR,VCR, LANGUAGE=fr:1 raton-laveur
|
||||
'rdate': None, # Use: O-n, Type: DATE-TIME, Defines the list of date/times for a recurrence set.
|
||||
'rrule': None, # Use: O-n, Type: RECUR, Defines a rule or repeating pattern for recurring events, to-dos, or time zone definitions.
|
||||
@@ -244,7 +238,7 @@ class Event(CalDAV, osv.osv_memory):
|
||||
Event()
|
||||
|
||||
class ToDo(CalDAV, osv.osv_memory):
|
||||
_name = 'caldav.todo'
|
||||
_name = 'basic.calendar.todo'
|
||||
|
||||
__attribute__ = {
|
||||
'class': None,
|
||||
@@ -320,13 +314,13 @@ class Timezone(CalDAV):
|
||||
|
||||
|
||||
class Alarm(CalDAV, osv.osv_memory):
|
||||
_name = 'caldav.alarm'
|
||||
_name = 'basic.calendar.alarm'
|
||||
__attribute__ = {
|
||||
'action': None, # Use: R-1, Type: Text, defines the action to be invoked when an alarm is triggered LIKE "AUDIO" / "DISPLAY" / "EMAIL" / "PROCEDURE"
|
||||
'description': None, # Type: Text, Provides a more complete description of the calendar component, than that provided by the "SUMMARY" property. Use:- R-1 for DISPLAY,Use:- R-1 for EMAIL,Use:- R-1 for PROCEDURE
|
||||
'summary': None, # Use: R-1, Type: Text Which contains the text to be used as the message subject. Use for EMAIL
|
||||
'attendee': None, # Use: R-n, Type: CAL-ADDRESS, Contain the email address of attendees to receive the message. It can also include one or more. Use for EMAIL
|
||||
'trigger': None, # Use: R-1, Type: DURATION, The "TRIGGER" property specifies a duration prior to the start of an event or a to-do. The "TRIGGER" edge may be explicitly set to be relative to the "START" or "END" of the event or to-do with the "RELATED" parameter of the "TRIGGER" property. The "TRIGGER" property value type can alternatively be set to an absolute calendar date and time of day value. Use for all action like AUDIO, DISPLAY, EMAIL and PROCEDURE
|
||||
'trigger': None, # Use: R-1, Type: DURATION, The "TRIGGER" property specifies a duration prior to the start of an event or a to-do. The "TRIGGER" edge may be explicitly set to be relative to the "START" or "END" of the event or to-do with the "related" parameter of the "TRIGGER" property. The "TRIGGER" property value type can alternatively be set to an absolute calendar date and time of day value. Use for all action like AUDIO, DISPLAY, EMAIL and PROCEDURE
|
||||
'duration': None, # Type: DURATION, Duration' and 'repeat' are both optional, and MUST NOT occur more than once each, but if one occurs, so MUST the other. Use:- 0-1 for AUDIO, EMAIL and PROCEDURE, Use:- 0-n for DISPLAY
|
||||
'repeat': None, # Type: INTEGER, Duration' and 'repeat' are both optional, and MUST NOT occur more than once each, but if one occurs, so MUST the other. Use:- 0-1 for AUDIO, EMAIL and PROCEDURE, Use:- 0-n for DISPLAY
|
||||
'attach': None, # Use:- O-n: which MUST point to a sound resource, which is rendered when the alarm is triggered for AUDIO, Use:- O-n: which are intended to be sent as message attachments for EMAIL, Use:- R-1:which MUST point to a procedure resource, which is invoked when the alarm is triggered for PROCEDURE.
|
||||
@@ -335,28 +329,28 @@ class Alarm(CalDAV, osv.osv_memory):
|
||||
|
||||
def export_ical(self, cr, uid, alarm_id, vevent, context={}):
|
||||
valarm = vevent.add('valarm')
|
||||
alarm_object = self.pool.get('crm.caldav.alarm')
|
||||
alarm_object = self.pool.get('calendar.alarm')
|
||||
alarm_data = alarm_object.read(cr, uid, alarm_id, [])
|
||||
|
||||
# Compute trigger data
|
||||
interval = alarm_data['trigger_interval']
|
||||
occurs = alarm_data['trigger_occurs']
|
||||
duration = (occurs == 'AFTER' and alarm_data['trigger_duration']) \
|
||||
duration = (occurs == 'after' and alarm_data['trigger_duration']) \
|
||||
or -(alarm_data['trigger_duration'])
|
||||
related = alarm_data['trigger_related']
|
||||
trigger = valarm.add('TRIGGER')
|
||||
trigger.params['RELATED'] = [related.upper()]
|
||||
if interval == 'DAYS':
|
||||
trigger = valarm.add('trigger')
|
||||
trigger.params['related'] = [related.upper()]
|
||||
if interval == 'days':
|
||||
delta = timedelta(days=duration)
|
||||
if interval == 'HOURS':
|
||||
if interval == 'hours':
|
||||
delta = timedelta(hours=duration)
|
||||
if interval == 'MINUTES':
|
||||
if interval == 'minutes':
|
||||
delta = timedelta(minutes=duration)
|
||||
trigger.value = delta
|
||||
|
||||
# Compute other details
|
||||
valarm.add('DESCRIPTION').value = alarm_data['name']
|
||||
valarm.add('ACTION').value = alarm_data['action']
|
||||
valarm.add('description').value = alarm_data['name']
|
||||
valarm.add('action').value = alarm_data['action']
|
||||
return vevent
|
||||
|
||||
def import_ical(self, cr, uid, ical_data):
|
||||
@@ -365,25 +359,25 @@ class Alarm(CalDAV, osv.osv_memory):
|
||||
seconds = child.value.seconds
|
||||
days = child.value.days
|
||||
diff = (days * 86400) + seconds
|
||||
interval = 'DAYS'
|
||||
related = 'BEFORE'
|
||||
interval = 'days'
|
||||
related = 'before'
|
||||
if not seconds:
|
||||
duration = abs(days)
|
||||
related = days>0 and 'AFTER' or 'BEFORE'
|
||||
related = days>0 and 'after' or 'before'
|
||||
elif (abs(diff) / 3600) == 0:
|
||||
duration = abs(diff / 60)
|
||||
interval = 'MINUTES'
|
||||
related = days>=0 and 'AFTER' or 'BEFORE'
|
||||
interval = 'minutes'
|
||||
related = days>=0 and 'after' or 'before'
|
||||
else:
|
||||
duration = abs(diff / 3600)
|
||||
interval = 'HOURS'
|
||||
related = days>=0 and 'AFTER' or 'BEFORE'
|
||||
interval = 'hours'
|
||||
related = days>=0 and 'after' or 'before'
|
||||
self.ical_set('trigger_interval', interval, 'value')
|
||||
self.ical_set('trigger_duration', duration, 'value')
|
||||
self.ical_set('trigger_occurs', related, 'value')
|
||||
if child.params:
|
||||
if child.params.get('RELATED'):
|
||||
self.ical_set('trigger_related', child.params.get('RELATED')[0].lower(), 'value')
|
||||
if child.params.get('related'):
|
||||
self.ical_set('trigger_related', child.params.get('related')[0].lower(), 'value')
|
||||
else:
|
||||
self.ical_set(child.name.lower(), child.value, 'value')
|
||||
vals = map_data(cr, uid, self)
|
||||
@@ -392,7 +386,7 @@ class Alarm(CalDAV, osv.osv_memory):
|
||||
Alarm()
|
||||
|
||||
class Attendee(CalDAV, osv.osv_memory):
|
||||
_name = 'caldav.attendee'
|
||||
_name = 'basic.calendar.attendee'
|
||||
__attribute__ = {
|
||||
'cutype': None, # Use: 0-1 Specify the type of calendar user specified by the property like "INDIVIDUAL"/"GROUP"/"RESOURCE"/"ROOM"/"UNKNOWN".
|
||||
'member': None, # Use: 0-1 Specify the group or list membership of the calendar user specified by the property.
|
||||
@@ -419,7 +413,7 @@ class Attendee(CalDAV, osv.osv_memory):
|
||||
return vals
|
||||
|
||||
def export_ical(self, cr, uid, attendee_id, vevent, context={}):
|
||||
attendee_object = self.pool.get('crm.caldav.attendee')
|
||||
attendee_object = self.pool.get('calendar.attendee')
|
||||
for attendee in attendee_object.read(cr, uid, attendee_id, []):
|
||||
attendee_add = vevent.add('attendee')
|
||||
for a_key, a_val in attendee_object.__attribute__.items():
|
||||
|
||||
+335
-131
@@ -23,22 +23,37 @@ from osv import fields, osv
|
||||
from service import web_services
|
||||
from tools.translate import _
|
||||
import re
|
||||
import time
|
||||
import datetime
|
||||
|
||||
months = {1:"January", 2:"February", 3:"March", 4:"April", 5:"May", 6:"June", \
|
||||
7:"July", 8:"August", 9:"September", 10:"October", 11:"November", \
|
||||
12:"December"}
|
||||
months = {
|
||||
1:"January", 2:"February", 3:"March", 4:"April", \
|
||||
5:"May", 6:"June", 7:"July", 8:"August", 9:"September", \
|
||||
10:"October", 11:"November", 12:"December"}
|
||||
|
||||
def caldevIDs2readIDs(caldev_ID = None):
|
||||
if caldev_ID:
|
||||
if isinstance(caldev_ID, str):
|
||||
return int(caldev_ID.split('-')[0])
|
||||
return caldev_ID
|
||||
def caldav_id2real_id(caldav_id = None, with_date=False):
|
||||
if caldav_id and isinstance(caldav_id, (str, unicode)):
|
||||
res = caldav_id.split('-')
|
||||
if len(res) >= 2:
|
||||
real_id = res[0]
|
||||
if with_date:
|
||||
real_date = time.strftime("%Y-%m-%d %H:%M:%S", \
|
||||
time.strptime(res[1], "%Y%m%d%H%M%S"))
|
||||
return (int(real_id), real_date)
|
||||
return int(real_id)
|
||||
return caldav_id and int(caldav_id) or caldav_id
|
||||
|
||||
def real_id2caldav_id(real_id, recurrent_date):
|
||||
if real_id and recurrent_date:
|
||||
recurrent_date = time.strftime("%Y%m%d%H%M%S", \
|
||||
time.strptime(recurrent_date, "%Y-%m-%d %H:%M:%S"))
|
||||
return '%d-%s'%(real_id, recurrent_date)
|
||||
return real_id
|
||||
|
||||
def uid2openobjectid(cr, uidval, oomodel):
|
||||
__rege = re.compile(r'OpenERP-([\w|\.]+)_([0-9]+)@(\w+)$')
|
||||
__rege = re.compile(r'OpenObject-([\w|\.]+)_([0-9]+)@(\w+)$')
|
||||
wematch = __rege.match(uidval.encode('utf8'))
|
||||
if not wematch:
|
||||
# raise osv.except_osv('Warning!!', "Cannot locate UID in %s" % val['id'])
|
||||
return False
|
||||
else:
|
||||
model, id, dbname = wematch.groups()
|
||||
@@ -51,11 +66,11 @@ def uid2openobjectid(cr, uidval, oomodel):
|
||||
return False
|
||||
|
||||
def openobjectid2uid(cr, uidval, oomodel):
|
||||
value = 'OpenERP-%s_%s@%s' % (oomodel, uidval, cr.dbname)
|
||||
value = 'OpenObject-%s_%s@%s' % (oomodel, uidval, cr.dbname)
|
||||
return value
|
||||
|
||||
class crm_caldav_attendee(osv.osv):
|
||||
_name = 'crm.caldav.attendee'
|
||||
class calendar_attendee(osv.osv):
|
||||
_name = 'calendar.attendee'
|
||||
_description = 'Attendee information'
|
||||
_rec_name = 'cutype'
|
||||
|
||||
@@ -63,53 +78,143 @@ class crm_caldav_attendee(osv.osv):
|
||||
'cutype': {'field':'cutype', 'type':'text'},
|
||||
'member': {'field':'member', 'type':'text'},
|
||||
'role': {'field':'role', 'type':'selection'},
|
||||
'partstat': {'field':'partstat', 'type':'text'},
|
||||
'partstat': {'field':'state', 'type':'text'},
|
||||
'rsvp': {'field':'rsvp', 'type':'boolean'},
|
||||
'delegated-to': {'field':'delegated_to', 'type':'char'},
|
||||
'delegated-from': {'field':'delegated_from', 'type':'char'},
|
||||
'delegated-to': {'field':'delegated_to', 'type':'text'},
|
||||
'delegated-from': {'field':'delegated_from', 'type':'text'},
|
||||
'sent-by': {'field':'sent_by', 'type':'text'},
|
||||
'cn': {'field':'cn', 'type':'text'},
|
||||
'dir': {'field':'dir', 'type':'text'},
|
||||
'language': {'field':'language', 'type':'text'},
|
||||
}
|
||||
|
||||
def _get_address(self, name=None, email=None):
|
||||
if name and email:
|
||||
name += ':'
|
||||
return (name or '') + (email and ('MAILTO:' + email) or '')
|
||||
|
||||
def _compute_data(self, cr, uid, ids, name, arg, context):
|
||||
name = name[0]
|
||||
result = {}
|
||||
|
||||
def get_delegate_data(user):
|
||||
email = user.address_id and user.address_id.email or ''
|
||||
return self._get_address(user.name, email)
|
||||
|
||||
for id in ids:
|
||||
result[id] = {}
|
||||
attdata = self.browse(cr, uid, id, context=context)
|
||||
if name == 'sent_by':
|
||||
if not attdata.sent_by_uid:
|
||||
result[id][name] = ''
|
||||
continue
|
||||
else:
|
||||
result[id][name] = self._get_address(attdata.sent_by_uid.name, \
|
||||
attdata.sent_by_uid.address_id.email)
|
||||
if name == 'cn':
|
||||
result[id][name] = self._get_address(attdata.user_id.name, attdata.email)
|
||||
if name == 'delegated_to':
|
||||
user_obj = self.pool.get('res.users')
|
||||
todata = map(get_delegate_data, attdata.del_to_user_ids)
|
||||
result[id][name] = ', '.join(todata)
|
||||
if name == 'delegated_from':
|
||||
dstring = []
|
||||
user_obj = self.pool.get('res.users')
|
||||
fromdata = map(get_delegate_data, attdata.del_from_user_ids)
|
||||
result[id][name] = ', '.join(fromdata)
|
||||
return result
|
||||
|
||||
_columns = {
|
||||
'cutype': fields.selection([('INDIVIDUAL', 'INDIVIDUAL'), ('GROUP', 'GROUP'), \
|
||||
('RESOURCE', 'RESOURCE'), ('ROOM', 'ROOM'), \
|
||||
('UNKNOWN', 'UNKNOWN') ], 'CUTYPE', \
|
||||
help="Specify the type of calendar user"),
|
||||
'member': fields.char('Member', size=124, help="Indicate the groups that the attendee belongs to"),
|
||||
'role': fields.selection([ ('REQ-PARTICIPANT', 'REQ-PARTICIPANT'), \
|
||||
('CHAIR', 'CHAIR'), ('OPT-PARTICIPANT', 'OPT-PARTICIPANT'), \
|
||||
('NON-PARTICIPANT', 'NON-PARTICIPANT')], 'ROLE', \
|
||||
help='Participation role for the calendar user'),
|
||||
'partstat': fields.selection([('TENTATIVE', 'TENTATIVE'),
|
||||
('NEEDS-ACTION', 'NEEDS-ACTION'),
|
||||
('ACCEPTED', 'ACCEPTED'),
|
||||
('DECLINED', 'DECLINED'),
|
||||
('DELEGATED', 'DELEGATED')], 'PARTSTAT', \
|
||||
help="Status of the attendee's participation"),
|
||||
'rsvp': fields.boolean('RSVP', help="Indicats whether the favor of a reply is requested"),
|
||||
'delegated_to': fields.char('DELEGATED-TO', size=124, \
|
||||
help="The calendar users that the original request was delegated to"),
|
||||
'delegated_from': fields.char('DELEGATED-FROM', size=124, \
|
||||
help="Indicates whom the request was delegated from"),
|
||||
'sent_by': fields.char('SENT-BY', size=124, \
|
||||
help="Specify the calendar user that is acting on behalf of the calendar user"),
|
||||
'cn': fields.char('CN', size=124, help="The common or displayable name to be associated with the calendar user"),
|
||||
'dir': fields.char('DIR', size=124, help="Reference to the URI that points to the directory information corresponding to the attendee."),
|
||||
'language': fields.char('LANGUAGE', size=124, help="To specify the language for text values in a property or property parameter."),
|
||||
'cutype': fields.selection([('individual', 'Individual'), \
|
||||
('group', 'Group'), ('resource', 'Resource'), \
|
||||
('room', 'Room'), ('unknown', 'Unknown') ], \
|
||||
'User Type', help="Specify the type of calendar user"),
|
||||
'member': fields.char('Member', size=124, help="Indicate the groups \
|
||||
that the attendee belongs to"),
|
||||
'role': fields.selection([ ('req-participant', 'req-participant'), \
|
||||
('chair', 'chair'), ('opt-participant', 'opt-participant'), \
|
||||
('non-participant', 'non-participant')], 'User\'s Role', \
|
||||
help='Participation role for the calendar user'),
|
||||
'state': fields.selection([('tentative', 'Tentative'),
|
||||
('needs-action', 'Needs Action'),
|
||||
('accepted', 'Accepted'),
|
||||
('declined', 'Declined'),
|
||||
('delegated', 'Delegated')], 'Status', readonly=True,
|
||||
help="Status of the attendee's participation"),
|
||||
'rsvp': fields.boolean('Required Reply?', help="Indicats whether the \
|
||||
favor of a reply is requested"),
|
||||
'delegated_to': fields.function(_compute_data, method=True, \
|
||||
string='Delegated To', type="char", size=124, store=True, \
|
||||
multi='delegated_to', help="The users that the original request \
|
||||
was delegated to"),
|
||||
'del_to_user_ids': fields.many2many('res.users', 'att_del_to_user_rel',
|
||||
'attendee_id', 'user_id', 'Users'),
|
||||
'delegated_from': fields.function(_compute_data, method=True, string=\
|
||||
'Delegated From', type="char", store=True, size=124, multi='delegated_from'),
|
||||
'del_from_user_ids': fields.many2many('res.users', 'att_del_from_user_rel', \
|
||||
'attendee_id', 'user_id', 'Users'),
|
||||
'sent_by': fields.function(_compute_data, method=True, string='Sent By', type="char", multi='sent_by', store=True, size=124, help="Specify the user that is acting on behalf of the calendar user"),
|
||||
'sent_by_uid': fields.many2one('res.users', 'Sent by User'),
|
||||
'cn': fields.function(_compute_data, method=True, string='Common name', type="char", size=124, multi='cn', store=True),
|
||||
'dir': fields.char('URI Reference', size=124, help="Reference to the URI that points to the directory information corresponding to the attendee."),
|
||||
'language': fields.char('Language', size=124, help="To specify the language for text values in a property or property parameter."),
|
||||
'user_id': fields.many2one('res.users', 'User'),
|
||||
'email': fields.char('Email', size=124),
|
||||
}
|
||||
_defaults = {
|
||||
'cn': lambda *x: 'MAILTO:',
|
||||
'state': lambda *x: 'needs-action',
|
||||
}
|
||||
|
||||
crm_caldav_attendee()
|
||||
|
||||
class crm_caldav_alarm(osv.osv):
|
||||
_name = 'crm.caldav.alarm'
|
||||
def onchange_user_id(self, cr, uid, ids, user_id, *args, **argv):
|
||||
if not user_id:
|
||||
return {'value': {'email': ''}}
|
||||
user = self.pool.get('res.users').browse(cr, uid, user_id, *args)
|
||||
return {'value': {'email': user.address_id.email}}
|
||||
|
||||
def do_tentative(self, cr, uid, ids, context=None, *args):
|
||||
self.write(cr, uid, ids, {'state': 'tentative'}, context)
|
||||
|
||||
def do_accept(self, cr, uid, ids, context=None, *args):
|
||||
self.write(cr, uid, ids, {'state': 'accepted'}, context)
|
||||
|
||||
def do_decline(self, cr, uid, ids, context=None, *args):
|
||||
self.write(cr, uid, ids, {'state': 'declined'}, context)
|
||||
|
||||
calendar_attendee()
|
||||
|
||||
class res_alarm(osv.osv):
|
||||
_name = 'res.alarm'
|
||||
_description = 'basic alarm information'
|
||||
_columns = {
|
||||
'name':fields.char('Name', size=256, required=True),
|
||||
'trigger_occurs': fields.selection([('before', 'Before'), ('after', 'After')], \
|
||||
'Trigger time', required=True),
|
||||
'trigger_interval': fields.selection([('minutes', 'Minutes'), ('hours', 'Hours'), \
|
||||
('days', 'Days')], 'Trigger duration', required=True),
|
||||
'trigger_duration': fields.integer('Time', required=True),
|
||||
'trigger_related': fields.selection([('start', 'The event starts'), ('end', \
|
||||
'The event ends')], 'Trigger Occures at', required=True),
|
||||
'duration': fields.integer('Duration', help="""Duration' and 'Repeat' \
|
||||
are both optional, but if one occurs, so MUST the other"""),
|
||||
'repeat': fields.integer('Repeat'),
|
||||
'active': fields.boolean('Active', help="If the active field is set to true, it will allow you to hide the event alarm information without removing it."),
|
||||
|
||||
|
||||
}
|
||||
_defaults = {
|
||||
'trigger_interval': lambda *x: 'minutes',
|
||||
'trigger_duration': lambda *x: 5,
|
||||
'trigger_occurs': lambda *x: 'before',
|
||||
'trigger_related': lambda *x: 'start',
|
||||
'active': lambda *x: 1,
|
||||
}
|
||||
|
||||
res_alarm()
|
||||
|
||||
class calendar_alarm(osv.osv):
|
||||
_name = 'calendar.alarm'
|
||||
_description = 'Event alarm information'
|
||||
|
||||
_inherits = {'res.alarm': "alarm_id"}
|
||||
__attribute__ = {
|
||||
'action': {'field': 'action', 'type': 'text'},
|
||||
'description': {'field': 'name', 'type': 'text'},
|
||||
@@ -122,43 +227,111 @@ class crm_caldav_alarm(osv.osv):
|
||||
'duration': {'field': 'duration', 'type': 'text'},
|
||||
'repeat': {'field': 'repeat', 'type': 'text'},
|
||||
'attach': {'field': 'attach', 'type': 'text'},
|
||||
}
|
||||
|
||||
_columns = {
|
||||
'name': fields.char('Summary', size=124, help="""Contains the text to be used as the message subject for EMAIL
|
||||
or contains the text to be used for DISPLAY"""),
|
||||
'action': fields.selection([('AUDIO', 'AUDIO'), ('DISPLAY', 'DISPLAY'), \
|
||||
('PROCEDURE', 'PROCEDURE'), ('EMAIL', 'EMAIL') ], 'Action', \
|
||||
}
|
||||
|
||||
_columns = {
|
||||
'alarm_id': fields.many2one('res.alarm', 'Basic Alarm', ondelete='cascade'),
|
||||
'name': fields.char('Summary', size=124, help="""Contains the text to be used as the message subject for email
|
||||
or contains the text to be used for display"""),
|
||||
'action': fields.selection([('audio', 'Audio'), ('display', 'Display'), \
|
||||
('procedure', 'Procedure'), ('email', 'Email') ], 'Action', \
|
||||
required=True, help="Defines the action to be invoked when an alarm is triggered"),
|
||||
'description': fields.text('Description', help='Provides a more complete description of the calendar component, than that provided by the "SUMMARY" property'),
|
||||
'attendee_ids': fields.many2many('crm.caldav.attendee', 'alarm_attendee_rel', \
|
||||
'alarm_id', 'attendee_id', 'Attendees'),
|
||||
'trigger_occurs': fields.selection([('BEFORE', 'BEFORE'), ('AFTER', 'AFTER')], \
|
||||
'Trigger time', required=True),
|
||||
'trigger_interval': fields.selection([('MINUTES', 'MINUTES'), ('HOURS', 'HOURS'), \
|
||||
('DAYS', 'DAYS')], 'Trigger duration', required=True),
|
||||
'trigger_duration': fields.integer('TIme', required=True),
|
||||
'trigger_related': fields.selection([('start', 'The event starts'), ('end', \
|
||||
'The event ends')], 'Trigger Occures at', required=True),
|
||||
'duration': fields.integer('Duration', help="""Duration' and 'Repeat' \
|
||||
are both optional, but if one occurs, so MUST the other"""),
|
||||
'repeat': fields.integer('Repeat'), # TODO
|
||||
'attach': fields.binary('Attachment', help="""* Points to a sound resource, which is rendered when the alarm is triggered for AUDIO,
|
||||
* File which is intended to be sent as message attachments for EMAIL,
|
||||
* Points to a procedure resource, which is invoked when the alarm is triggered for PROCEDURE.
|
||||
"""),
|
||||
'active': fields.boolean('Active', help="If the active field is set to true, it will allow you to hide the event alarm information without removing it."),
|
||||
}
|
||||
'attendee_ids': fields.many2many('calendar.attendee', 'alarm_attendee_rel', \
|
||||
'alarm_id', 'attendee_id', 'Attendees', readonly=True),
|
||||
'attach': fields.binary('Attachment', help="""* Points to a sound resource, which is rendered when the alarm is triggered for audio,
|
||||
* File which is intended to be sent as message attachments for email,
|
||||
* Points to a procedure resource, which is invoked when the alarm is triggered for procedure."""),
|
||||
'res_id' : fields.integer('Resource ID'),
|
||||
'model_id': fields.many2one('ir.model', 'Model'),
|
||||
'user_id': fields.many2one('res.users', 'Owner'),
|
||||
'event_date' : fields.datetime('Event Date'),
|
||||
'trigger_date' : fields.datetime('Trigger Date', readonly="True"),
|
||||
'state':fields.selection([
|
||||
('draft','Draft'),
|
||||
('run','Run'),
|
||||
('stop','Stop'),
|
||||
('done','Done'),
|
||||
],'State', select=True, readonly=True),
|
||||
}
|
||||
|
||||
_defaults = {
|
||||
'action': lambda *x: 'EMAIL',
|
||||
'trigger_interval': lambda *x: 'MINUTES',
|
||||
'trigger_duration': lambda *x: 5,
|
||||
'trigger_occurs': lambda *x: 'BEFORE',
|
||||
'trigger_related': lambda *x: 'start',
|
||||
}
|
||||
|
||||
crm_caldav_alarm()
|
||||
'action': lambda *x: 'email',
|
||||
'state' : lambda *x: 'run',
|
||||
}
|
||||
|
||||
def create(self, cr, uid, vals, context={}):
|
||||
event_date = vals.get('event_date', False)
|
||||
if event_date:
|
||||
dtstart = datetime.datetime.strptime(vals['event_date'], "%Y-%m-%d %H:%M:%S")
|
||||
if vals['trigger_interval'] == 'days':
|
||||
delta = datetime.timedelta(days=vals['trigger_duration'])
|
||||
if vals['trigger_interval'] == 'hours':
|
||||
delta = datetime.timedelta(hours=vals['trigger_duration'])
|
||||
if vals['trigger_interval'] == 'minutes':
|
||||
delta = datetime.timedelta(minutes=vals['trigger_duration'])
|
||||
trigger_date = dtstart + (vals['trigger_occurs'] == 'after' and delta or -delta)
|
||||
vals['trigger_date'] = trigger_date
|
||||
res = super(calendar_alarm, self).create(cr, uid, vals, context)
|
||||
return res
|
||||
|
||||
def do_run_scheduler(self, cr, uid, automatic=False, use_new_cursor=False, \
|
||||
context=None):
|
||||
if not context:
|
||||
context = {}
|
||||
current_datetime = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
||||
cr.execute("select alarm.id as id \
|
||||
from calendar_alarm alarm \
|
||||
where alarm.state = %s and alarm.trigger_date <= %s", ('run', current_datetime))
|
||||
res = cr.dictfetchall()
|
||||
alarm_ids = map(lambda x: x['id'], res)
|
||||
attendee_obj = self.pool.get('calendar.attendee')
|
||||
request_obj = self.pool.get('res.request')
|
||||
mail_to = []
|
||||
for alarm in self.browse(cr, uid, alarm_ids):
|
||||
if alarm.action == 'display':
|
||||
value = {
|
||||
'name': alarm.name,
|
||||
'act_from': alarm.user_id.id,
|
||||
'act_to': alarm.user_id.id,
|
||||
'body': alarm.description,
|
||||
'trigger_date': alarm.trigger_date,
|
||||
'ref_doc1' : '%s,%s' %(alarm.model_id.model, alarm.res_id)
|
||||
}
|
||||
request_id = request_obj.create(cr, uid, value)
|
||||
request_ids = [request_id]
|
||||
for attendee in alarm.attendee_ids:
|
||||
value['act_to'] = attendee.act_to.id
|
||||
request_id = request_obj.create(cr, uid, value)
|
||||
request_ids.append(request_id)
|
||||
request_obj.request_send(cr, uid, request_ids)
|
||||
|
||||
if alarm.action == 'email':
|
||||
sub = '[Openobject Remainder] %s' %(alarm.name)
|
||||
body = """
|
||||
Name : %s
|
||||
Date : %s
|
||||
Description : %s
|
||||
|
||||
From :
|
||||
%s
|
||||
%s
|
||||
|
||||
""" %(alarm.name, alarm.trigger_date, alarm.description, alarm.user_id.name, alarm.user_id.sign)
|
||||
mail_to = [alarm.user_id.address_id.email]
|
||||
for att in alarm.attendee_ids:
|
||||
mail_to.append(att.act_to.address_id.email)
|
||||
|
||||
tools.email_send(
|
||||
tools.confirm['from_mail'],
|
||||
mail_to,
|
||||
sub,
|
||||
body
|
||||
)
|
||||
self.write(cr, uid, [alarm.id], {'state':'done'})
|
||||
return True
|
||||
|
||||
calendar_alarm()
|
||||
|
||||
class ir_attachment(osv.osv):
|
||||
_name = 'ir.attachment'
|
||||
@@ -175,7 +348,7 @@ class ir_attachment(osv.osv):
|
||||
new_args = args
|
||||
for i, arg in enumerate(new_args):
|
||||
if arg[0] == 'res_id':
|
||||
new_args[i] = (arg[0], arg[1], caldevIDs2readIDs(arg[2]))
|
||||
new_args[i] = (arg[0], arg[1], caldav_id2real_id(arg[2]))
|
||||
return super(ir_attachment, self).search(cr, uid, new_args, offset=offset,
|
||||
limit=limit, order=order,
|
||||
context=context, count=False)
|
||||
@@ -189,7 +362,7 @@ class ir_values(osv.osv):
|
||||
new_model = []
|
||||
for data in models:
|
||||
if type(data) in (list, tuple):
|
||||
new_model.append((data[0], caldevIDs2readIDs(data[1])))
|
||||
new_model.append((data[0], caldav_id2real_id(data[1])))
|
||||
else:
|
||||
new_model.append(data)
|
||||
return super(ir_values, self).set(cr, uid, key, key2, name, new_model, value, \
|
||||
@@ -200,7 +373,7 @@ class ir_values(osv.osv):
|
||||
new_model = []
|
||||
for data in models:
|
||||
if type(data) in (list, tuple):
|
||||
new_model.append((data[0], caldevIDs2readIDs(data[1])))
|
||||
new_model.append((data[0], caldav_id2real_id(data[1])))
|
||||
else:
|
||||
new_model.append(data)
|
||||
return super(ir_values, self).get(cr, uid, key, key2, new_model, meta, context, \
|
||||
@@ -217,7 +390,7 @@ class ir_model(osv.osv):
|
||||
data = super(ir_model, self).read(cr, uid, ids, fields=fields, context=context, load=load)
|
||||
if data:
|
||||
for val in data:
|
||||
val['id'] = caldevIDs2readIDs(val['id'])
|
||||
val['id'] = caldav_id2real_id(val['id'])
|
||||
return data
|
||||
|
||||
ir_model()
|
||||
@@ -229,47 +402,26 @@ class virtual_report_spool(web_services.report_spool):
|
||||
return super(virtual_report_spool, self).exp_report(db, uid, object, ids, datas, context)
|
||||
new_ids = []
|
||||
for id in ids:
|
||||
new_ids.append(caldevIDs2readIDs(id))
|
||||
datas['id'] = caldevIDs2readIDs(datas['id'])
|
||||
new_ids.append(caldav_id2real_id(id))
|
||||
datas['id'] = caldav_id2real_id(datas['id'])
|
||||
super(virtual_report_spool, self).exp_report(db, uid, object, new_ids, datas, context)
|
||||
return super(virtual_report_spool, self).exp_report(db, uid, object, new_ids, datas, context)
|
||||
|
||||
virtual_report_spool()
|
||||
|
||||
class virtual_wizard(web_services.wizard):
|
||||
def exp_execute(self, db, uid, wiz_id, datas, action='init', context=None):
|
||||
#if wiz_id not in self.wiz_uid:
|
||||
# # TODO: To Check why need it
|
||||
# if wiz_id == 1:
|
||||
# wiz_name ='base_setup.base_setup'
|
||||
# if wiz_id == 2:
|
||||
# wiz_name ='module.upgrade'
|
||||
# super(virtual_wizard,self).exp_create(db, uid, wiz_name, datas)
|
||||
new_ids = []
|
||||
if 'id' in datas:
|
||||
datas['id'] = caldevIDs2readIDs(datas['id'])
|
||||
for id in datas['ids']:
|
||||
new_ids.append(caldevIDs2readIDs(id))
|
||||
datas['ids'] = new_ids
|
||||
res=super(virtual_wizard, self).exp_execute(db, uid, wiz_id, datas, action, context)
|
||||
return res
|
||||
|
||||
virtual_wizard()
|
||||
|
||||
|
||||
class set_rrule_wizard(osv.osv_memory):
|
||||
_name = "caldav.set.rrule"
|
||||
_description = "Set RRULE"
|
||||
|
||||
_columns = {
|
||||
'freq': fields.selection([('None', 'No Repeat'), \
|
||||
('SECONDLY', 'SECONDLY'), \
|
||||
('MINUTELY', 'MINUTELY'), \
|
||||
('HOURLY', 'HOURLY'), \
|
||||
('DAILY', 'DAILY'), \
|
||||
('WEEKLY', 'WEEKLY'), \
|
||||
('MONTHLY', 'MONTHLY'), \
|
||||
('YEARLY', 'YEARLY')], 'Frequency', required=True),
|
||||
('secondly', 'Secondly'), \
|
||||
('minutely', 'Minutely'), \
|
||||
('hourly', 'Hourly'), \
|
||||
('daily', 'Daily'), \
|
||||
('weekly', 'Weekly'), \
|
||||
('monthly', 'Monthly'), \
|
||||
('yearly', 'Yearly')], 'Frequency', required=True),
|
||||
'interval': fields.integer('Interval'),
|
||||
'count': fields.integer('Count'),
|
||||
'mo': fields.boolean('Mon'),
|
||||
@@ -294,19 +446,12 @@ class set_rrule_wizard(osv.osv_memory):
|
||||
}
|
||||
|
||||
_defaults = {
|
||||
'freq': lambda *x: 'DAILY',
|
||||
'freq': lambda *x: 'daily',
|
||||
'select1': lambda *x: 'date',
|
||||
'interval': lambda *x: 1,
|
||||
}
|
||||
|
||||
def add_rrule(self, cr, uid, ids, context={}):
|
||||
datas = self.read(cr, uid, ids)[0]
|
||||
if not context or not context.get('model'):
|
||||
return {}
|
||||
else:
|
||||
model = context.get('model')
|
||||
obj = self.pool.get(model)
|
||||
res_obj = obj.browse(cr, uid, context['active_id'])
|
||||
def compute_rule_string(self, cr, uid, datas, context=None, *args):
|
||||
weekdays = ['mo', 'tu', 'we', 'th', 'fr', 'sa', 'su']
|
||||
weekstring = ''
|
||||
monthstring = ''
|
||||
@@ -318,14 +463,13 @@ class set_rrule_wizard(osv.osv_memory):
|
||||
if freq == 'None':
|
||||
obj.write(cr, uid, [res_obj.id], {'rrule' : ''})
|
||||
return {}
|
||||
if datas.get('interval') <= 0:
|
||||
raise osv.except_osv(_('Error!'), ("Please select proper Interval"))
|
||||
|
||||
if freq == 'WEEKLY':
|
||||
byday = map(lambda x: x.upper(), filter(lambda x: datas.get(x) and x in weekdays, datas))
|
||||
weekstring = ';BYDAY=' + ','.join(byday)
|
||||
|
||||
elif freq == 'MONTHLY':
|
||||
if freq == 'weekly':
|
||||
byday = map(lambda x: x.upper(), filter(lambda x: datas.get(x) and x in weekdays, datas))
|
||||
if byday:
|
||||
weekstring = ';BYDAY=' + ','.join(byday)
|
||||
|
||||
elif freq == 'monthly':
|
||||
byday = ''
|
||||
if datas.get('select1')=='date' and (datas.get('day') < 1 or datas.get('day') > 31):
|
||||
raise osv.except_osv(_('Error!'), ("Please select proper Day of month"))
|
||||
@@ -333,7 +477,7 @@ class set_rrule_wizard(osv.osv_memory):
|
||||
byday = ';BYDAY=' + datas.get('byday') + datas.get('week_list')
|
||||
monthstring = byday or (';BYMONTHDAY=' + str(datas.get('day')))
|
||||
|
||||
elif freq == 'YEARLY':
|
||||
elif freq == 'yearly':
|
||||
bymonth = ''
|
||||
byday = ''
|
||||
if datas.get('select1')=='date' and (datas.get('day') < 1 or datas.get('day') > 31):
|
||||
@@ -354,9 +498,69 @@ class set_rrule_wizard(osv.osv_memory):
|
||||
str(datas.get('interval')) + enddate + monthstring + yearstring
|
||||
|
||||
# End logic
|
||||
return rrule_string
|
||||
|
||||
def do_add(self, cr, uid, ids, context={}):
|
||||
datas = self.read(cr, uid, ids)[0]
|
||||
if datas.get('interval') <= 0:
|
||||
raise osv.except_osv(_('Error!'), ("Please select proper Interval"))
|
||||
|
||||
|
||||
if not context or not context.get('model'):
|
||||
return {}
|
||||
else:
|
||||
model = context.get('model')
|
||||
obj = self.pool.get(model)
|
||||
res_obj = obj.browse(cr, uid, context['active_id'])
|
||||
|
||||
rrule_string = self.compute_rule_string(cr, uid, datas)
|
||||
obj.write(cr, uid, [res_obj.id], {'rrule' : rrule_string})
|
||||
return {}
|
||||
|
||||
set_rrule_wizard()
|
||||
|
||||
class invite_attendee_wizard(osv.osv_memory):
|
||||
_name = "caldav.invite.attendee"
|
||||
_description = "Invite Attendees"
|
||||
|
||||
_columns = {
|
||||
'user_id': fields.many2one('res.users', 'User'),
|
||||
'email': fields.char('Email', size=124),
|
||||
'role': fields.selection([ ('REQ-PARTICIPANT', 'REQ-PARTICIPANT'), \
|
||||
('CHAIR', 'CHAIR'), ('OPT-PARTICIPANT', 'OPT-PARTICIPANT'), \
|
||||
('NON-PARTICIPANT', 'NON-PARTICIPANT')], 'User\'s Role', \
|
||||
help='Participation role for the calendar user'),
|
||||
'rsvp': fields.boolean('Required Reply?', help="Indicats whether the \
|
||||
favor of a reply is requested"),
|
||||
}
|
||||
|
||||
def do_invite(self, cr, uid, ids, context={}):
|
||||
datas = self.read(cr, uid, ids)[0]
|
||||
if not context or not context.get('model') or not datas.get('user_id'):
|
||||
return {}
|
||||
else:
|
||||
model = context.get('model')
|
||||
obj = self.pool.get(model)
|
||||
res_obj = obj.browse(cr, uid, context['active_id'])
|
||||
user_obj = self.pool.get('res.users')
|
||||
attendee_obj = self.pool.get('calendar.attendee')
|
||||
for user_id in datas.get('users', []):
|
||||
user = user_obj.browse(cr, uid, user_id)
|
||||
if not user.address_id.email:
|
||||
raise osv.except_osv(_('Error!'), \
|
||||
("User does not have an email Address"))
|
||||
attendee_id = attendee_obj.create(cr, uid, {'user_id': user_id,\
|
||||
'cn': user.name + ':MAILTO:' + user.address_id.email})
|
||||
obj.write(cr, uid, res_obj.id, {'attendee_ids': [(6, 0, [attendee_id])]})
|
||||
return {}
|
||||
|
||||
|
||||
def onchange_user_id(self, cr, uid, ids, user_id, *args, **argv):
|
||||
if not user_id:
|
||||
return {'value': {'email': ''}}
|
||||
user = self.pool.get('res.users').browse(cr, uid, user_id, *args)
|
||||
return {'value': {'email': user.address_id.email}}
|
||||
|
||||
invite_attendee_wizard()
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
|
||||
"caldav_calendar_all","caldav.calendar","model_caldav_calendar",,1,1,1,1
|
||||
"caldav_event_all","caldav.event","model_caldav_event",,1,1,1,1
|
||||
"caldav_attendee_all","caldav.attendee","model_caldav_attendee",,1,1,1,1
|
||||
"access_crm_caldav_attendee","crm.caldav.attendee","model_crm_caldav_attendee",,1,1,1,1
|
||||
"access_crm_caldav_alarm","crm.caldav.alarm","model_crm_caldav_alarm",,1,1,1,1
|
||||
"basic_calendar_all","basic.calendar","model_basic_calendar",,1,1,1,1
|
||||
"basic_calendar_event_all","basic.calendar.event","model_basic_calendar_event",,1,1,1,1
|
||||
"basic_calendar_attendee_all","basic.calendar.attendee","model_basic_calendar_attendee",,1,1,1,1
|
||||
"access_basic_calendar_attendee","calendar.attendee","model_basic_calendar_attendee",,1,1,1,1
|
||||
"access_basic_calendar_alarm","calendar.alarm","model_basic_calendar_alarm",,1,1,1,1
|
||||
|
||||
|
+58
-59
@@ -21,9 +21,9 @@
|
||||
|
||||
|
||||
{
|
||||
'name': 'Customer & Supplier Relationship Management',
|
||||
'version': '1.0',
|
||||
'category': 'Generic Modules/CRM & SRM',
|
||||
'name': 'Customer & Supplier Relationship Management',
|
||||
'version': '1.0',
|
||||
'category': 'Generic Modules/CRM & SRM',
|
||||
'description': """The generic Open ERP Customer Relationship Management
|
||||
system enables a group of people to intelligently and efficiently manage
|
||||
leads, opportunities, tasks, issues, requests, bugs, campaign, claims, etc.
|
||||
@@ -41,68 +41,67 @@ appropriate staff, and making sure all future correspondence gets to the right
|
||||
place.
|
||||
|
||||
The CRM module has a email gateway for the synchronisation interface
|
||||
between mails and Open ERP.""",
|
||||
'author': 'Tiny',
|
||||
'website': 'http://www.openerp.com',
|
||||
'depends': ['base',
|
||||
'caldav',
|
||||
'process',
|
||||
'mail_gateway',
|
||||
],
|
||||
between mails and Open ERP.""",
|
||||
'author': 'Tiny',
|
||||
'website': 'http://www.openerp.com',
|
||||
'depends': ['base',
|
||||
'caldav',
|
||||
'process',
|
||||
'mail_gateway',
|
||||
],
|
||||
'init_xml': ['crm_data.xml',
|
||||
'crm_meeting_data.xml',
|
||||
'crm_claims_data.xml',
|
||||
'crm_fund_data.xml',
|
||||
'crm_helpdesk_data.xml',
|
||||
'crm_jobs_data.xml',
|
||||
'crm_lead_data.xml',
|
||||
'crm_meeting_data.xml',
|
||||
'crm_claims_data.xml',
|
||||
'crm_fund_data.xml',
|
||||
'crm_helpdesk_data.xml',
|
||||
'crm_jobs_data.xml',
|
||||
'crm_lead_data.xml',
|
||||
'crm_meeting_data.xml',
|
||||
'crm_opportunity_data.xml',
|
||||
'crm_phonecall_data.xml',
|
||||
],
|
||||
'crm_opportunity_data.xml',
|
||||
'crm_phonecall_data.xml',
|
||||
],
|
||||
'update_xml': [
|
||||
'crm_wizard.xml',
|
||||
'crm_view.xml',
|
||||
'crm_config_view.xml',
|
||||
'crm_job_wizard.xml',
|
||||
'crm_jobs_view.xml',
|
||||
'crm_jobs_menu.xml',
|
||||
'crm_lead_wizard.xml',
|
||||
'crm_lead_view.xml',
|
||||
'crm_lead_menu.xml',
|
||||
'crm_meeting_wizard.xml',
|
||||
'crm_meeting_view.xml',
|
||||
'crm_meeting_menu.xml',
|
||||
'crm_opportunity_wizard.xml',
|
||||
'crm_opportunity_view.xml',
|
||||
'crm_opportunity_menu.xml',
|
||||
'crm_fund_view.xml',
|
||||
'crm_fund_menu.xml',
|
||||
'crm_claims_view.xml',
|
||||
'crm_claims_menu.xml',
|
||||
'crm_phonecall_wizard.xml',
|
||||
'crm_phonecall_view.xml',
|
||||
'crm_phonecall_menu.xml',
|
||||
'crm_report_view.xml',
|
||||
'crm_helpdesk_view.xml',
|
||||
'crm_report.xml',
|
||||
'security/crm_security.xml',
|
||||
'security/ir.model.access.csv',
|
||||
'crm_wizard.xml',
|
||||
'crm_view.xml',
|
||||
'crm_config_view.xml',
|
||||
'crm_job_wizard.xml',
|
||||
'crm_jobs_view.xml',
|
||||
'crm_jobs_menu.xml',
|
||||
'crm_lead_wizard.xml',
|
||||
'crm_lead_view.xml',
|
||||
'crm_lead_menu.xml',
|
||||
'crm_meeting_wizard.xml',
|
||||
'crm_meeting_view.xml',
|
||||
'crm_meeting_menu.xml',
|
||||
'crm_opportunity_wizard.xml',
|
||||
'crm_opportunity_view.xml',
|
||||
'crm_opportunity_menu.xml',
|
||||
'crm_fund_view.xml',
|
||||
'crm_fund_menu.xml',
|
||||
'crm_claims_view.xml',
|
||||
'crm_claims_menu.xml',
|
||||
'crm_phonecall_wizard.xml',
|
||||
'crm_phonecall_view.xml',
|
||||
'crm_phonecall_menu.xml',
|
||||
'crm_report_view.xml',
|
||||
'crm_helpdesk_view.xml',
|
||||
'crm_report.xml',
|
||||
'security/crm_security.xml',
|
||||
'security/ir.model.access.csv',
|
||||
'process/crm_configuration_process.xml'
|
||||
],
|
||||
],
|
||||
'demo_xml': [
|
||||
'crm_demo.xml',
|
||||
'crm_meeting_demo.xml',
|
||||
'crm_claims_demo.xml',
|
||||
'crm_fund_demo.xml',
|
||||
'crm_helpdesk_demo.xml',
|
||||
'crm_jobs_demo.xml',
|
||||
'crm_lead_demo.xml',
|
||||
'crm_claims_demo.xml',
|
||||
'crm_fund_demo.xml',
|
||||
'crm_helpdesk_demo.xml',
|
||||
'crm_jobs_demo.xml',
|
||||
'crm_lead_demo.xml',
|
||||
'crm_meeting_demo.xml',
|
||||
'crm_opportunity_demo.xml',
|
||||
'crm_phonecall_demo.xml'],
|
||||
'installable': True,
|
||||
'active': False,
|
||||
'certificate': '0079056041421',
|
||||
'crm_opportunity_demo.xml',
|
||||
'crm_phonecall_demo.xml'],
|
||||
'installable': True,
|
||||
'active': False,
|
||||
'certificate': '0079056041421',
|
||||
}
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
@@ -52,7 +52,7 @@ class crm_cases(osv.osv):
|
||||
data.update(res)
|
||||
return self.create(cr, uid, data)
|
||||
|
||||
def msg_update(self, cr, uid, id, msg, data={}, default_act='pending'):
|
||||
def msg_update(self, cr, uid, ids, msg, data={}, default_act='pending'):
|
||||
mailgate_obj = self.pool.get('mail.gateway')
|
||||
msg_actions, body_data = mailgate_obj.msg_act_get(msg)
|
||||
data.update({
|
||||
@@ -77,9 +77,9 @@ class crm_cases(osv.osv):
|
||||
if 'partner' in msg_actions:
|
||||
data['email_from'] = msg_actions['partner'][:128]
|
||||
|
||||
self.write(cr, uid, [id], data)
|
||||
getattr(self,act)(cr, uid, [id])
|
||||
return True
|
||||
res = self.write(cr, uid, ids, data)
|
||||
getattr(self,act)(cr, uid, ids)
|
||||
return res
|
||||
|
||||
def emails_get(self, cr, uid, ids, context={}):
|
||||
res = []
|
||||
|
||||
+397
-224
@@ -1,6 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
@@ -15,144 +15,189 @@
|
||||
# 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 <http://www.gnu.org/licenses/>.
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
from caldav import common
|
||||
from dateutil.rrule import *
|
||||
from osv import fields, osv
|
||||
import datetime
|
||||
import datetime
|
||||
import base64
|
||||
import re
|
||||
import time
|
||||
import tools
|
||||
from tools.translate import _
|
||||
from dateutil import parser
|
||||
|
||||
class crm_meeting(osv.osv):
|
||||
_name = 'crm.meeting'
|
||||
_name = 'crm.meeting'
|
||||
_description = "Meeting Cases"
|
||||
_order = "id desc"
|
||||
_inherits = {'crm.case':"inherit_case_id"}
|
||||
_inherits = {'crm.case': "inherit_case_id"}
|
||||
__attribute__ = {
|
||||
'class' : {'field':'class', 'type':'text'},
|
||||
'created' : {'field':'create_date', 'type':'datetime'}, # keep none for now
|
||||
'description' : {'field':'description', 'type':'text'},
|
||||
'dtstart' : {'field':'date', 'type':'datetime'},
|
||||
#'last-mod' : {'field':'write_date', 'type':'datetime'},
|
||||
'location' : {'field':'location', 'type':'text'},
|
||||
# 'organizer' : {'field':'partner_id', 'sub-field':'name', 'type':'many2one'},
|
||||
'priority' : {'field':'priority', 'type':'int'},
|
||||
'dtstamp' : {'field':'date', 'type':'datetime'},
|
||||
'seq' : None,
|
||||
'status' : {'field':'state', 'type':'selection', 'mapping' : {'TENTATIVE' : 'draft', \
|
||||
'CONFIRMED' : 'open' , 'CANCELLED' : 'cancel'}},
|
||||
'summary' : {'field':'name', 'type':'text'},
|
||||
'transp' : {'field':'transparent', 'type':'text'},
|
||||
'uid' : {'field':'id', 'type':'text'},
|
||||
'url' : {'field':'caldav_url', 'type':'text'},
|
||||
'recurid' : None,
|
||||
# 'attach' : {'field':'attachment_ids', 'sub-field':'datas', 'type':'list'},
|
||||
'attendee' : {'field':'attendees', 'type':'many2many', 'object' : 'crm.caldav.attendee'},
|
||||
# 'categories' : {'field':'categ_id', 'sub-field':'name'},
|
||||
# 'categories' : {'field':None , 'sub-field':'name', 'type':'text'},
|
||||
'comment' : None,
|
||||
'contact' : None,
|
||||
'exdate' : {'field':'exdate', 'type':'datetime'},
|
||||
'exrule' : {'field':'exrule', 'type':'text'},
|
||||
'rstatus' : None,
|
||||
'related' : None,
|
||||
'resources' : None,
|
||||
'rdate' : None,
|
||||
'rrule' : {'field':'rrule', 'type':'text'},
|
||||
'x-openobject-model' : {'value':_name, 'type':'text'},
|
||||
# 'duration' : {'field':'duration'},
|
||||
'dtend' : {'field':'date_closed', 'type':'datetime'},
|
||||
'valarm' : {'field':'alarm_id', 'type':'many2one', 'object' : 'crm.caldav.alarm'},
|
||||
}
|
||||
'class': {'field': 'class', 'type': 'text'},
|
||||
'created': {'field': 'create_date', 'type': 'datetime'}, # keep none for now
|
||||
'description': {'field': 'description', 'type': 'text'},
|
||||
'dtstart': {'field': 'date', 'type': 'datetime'},
|
||||
'location': {'field': 'location', 'type': 'text'},
|
||||
#'organizer': {'field': 'partner_id', 'sub-field': 'name', 'type': 'many2one'},
|
||||
'priority': {'field': 'priority', 'type': 'int'},
|
||||
'dtstamp' : {'field': 'date', 'type': 'datetime'},
|
||||
'seq': None,
|
||||
'status': {'field': 'state', 'type': 'selection', 'mapping': {'TENTATIVE': 'draft', \
|
||||
'CONFIRMED': 'open' , 'CANCELLED': 'cancel'}},
|
||||
'summary': {'field': 'name', 'type': 'text'},
|
||||
'transp': {'field': 'transparent', 'type': 'text'},
|
||||
'uid': {'field': 'id', 'type': 'text'},
|
||||
'url': {'field': 'caldav_url', 'type': 'text'},
|
||||
'recurid': None,
|
||||
# 'attach': {'field': 'attachment_ids', 'sub-field': 'datas', 'type': 'list'},
|
||||
'attendee': {'field': 'attendee_ids', 'type': 'many2many', 'object': 'calendar.attendee'},
|
||||
# 'categories': {'field': 'categ_id', 'sub-field': 'name'},
|
||||
# 'categories': {'field':None , 'sub-field': 'name', 'type': 'text'},
|
||||
'comment': None,
|
||||
'contact': None,
|
||||
'exdate' : {'field': 'exdate', 'type': 'datetime'},
|
||||
'exrule' : {'field': 'exrule', 'type': 'text'},
|
||||
'rstatus': None,
|
||||
'related': None,
|
||||
'resources': None,
|
||||
'rdate': None,
|
||||
'rrule': {'field': 'rrule', 'type': 'text'},
|
||||
'x-openobject-model': {'value': _name, 'type': 'text'},
|
||||
# 'duration': {'field': 'duration'},
|
||||
'dtend': {'field': 'date_closed', 'type': 'datetime'},
|
||||
'valarm': {'field': 'caldav_alarm_id', 'type': 'many2one', 'object': 'calendar.alarm'},
|
||||
}
|
||||
|
||||
def _get_attendee_data(self, cr, uid, ids, name, arg, context):
|
||||
result = {}
|
||||
for id in ids:
|
||||
eventdata = self.browse(cr, uid, id, context=context)
|
||||
if not eventdata.attendee_ids:
|
||||
return result
|
||||
att_data = map(lambda x: x.cn or '', eventdata.attendee_ids)
|
||||
result[id] = ', '.join(att_data)
|
||||
return result
|
||||
|
||||
def _set_attendee_data(self, cr, uid, id, name, value, arg, context):
|
||||
if not value:
|
||||
return
|
||||
eventdata = self.browse(cr, uid, id, context=context)
|
||||
att_len = len(eventdata.attendee_ids)
|
||||
if att_len == len(value.split(',')):
|
||||
return
|
||||
if att_len > len(value.split(',')):
|
||||
for attendee in eventdata.attendee_ids[len(value.split(',')):]:
|
||||
self.write(cr, uid, id, {'attendee_ids': [(3, attendee.id)]})
|
||||
return
|
||||
attendee_obj = self.pool.get('calendar.attendee')
|
||||
for val in value.split(',')[att_len:]:
|
||||
attendee_id = attendee_obj.create(cr, uid, {'cn': val.strip()})
|
||||
self.write(cr, uid, id, {'attendee_ids': [(4, attendee_id)]})
|
||||
return
|
||||
|
||||
_columns = {
|
||||
'inherit_case_id': fields.many2one('crm.case','Case',ondelete='cascade'),
|
||||
'class' : fields.selection([('PUBLIC', 'PUBLIC'), ('PRIVATE', 'PRIVATE'), \
|
||||
('CONFIDENTIAL', 'CONFIDENTIAL')], 'Privacy'),
|
||||
'location' : fields.char('Location', size=264, help="Gives Location of Meeting"),
|
||||
'freebusy' : fields.text('FreeBusy'),
|
||||
'transparent' : fields.selection([('TRANSPARENT', 'TRANSPARENT'), \
|
||||
('OPAQUE', 'OPAQUE')], 'Trensparent'),
|
||||
'caldav_url' : fields.char('Caldav URL', size=264),
|
||||
'exdate' : fields.text('Exception Date/Times', help="This property defines the list\
|
||||
'inherit_case_id': fields.many2one('crm.case', 'Case', ondelete='cascade'),
|
||||
'date_deadline': fields.datetime('Deadline', help="Deadline Date is automatically computed from Start Date + Duration"),
|
||||
'class': fields.selection([('public', 'Public'), ('private', 'Private'), \
|
||||
('confidential', 'Confidential')], 'Privacy'),
|
||||
'location': fields.char('Location', size=264, help="Gives Location of Meeting"),
|
||||
'freebusy': fields.text('FreeBusy'),
|
||||
'show_as': fields.selection([('free', 'Free'), \
|
||||
('busy', 'Busy')],
|
||||
'show_as'),
|
||||
'caldav_url': fields.char('Caldav URL', size=264),
|
||||
'exdate': fields.text('Exception Date/Times', help="This property defines the list\
|
||||
of date/time exceptions for arecurring calendar component."),
|
||||
'exrule' : fields.char('Exception Rule', size=352, help="defines a rule or repeating pattern\
|
||||
'exrule': fields.char('Exception Rule', size=352, help="defines a rule or repeating pattern\
|
||||
for anexception to a recurrence set"),
|
||||
'rrule' : fields.char('Recurrent Rule', size=352),
|
||||
'attendees': fields.many2many('crm.caldav.attendee', 'crm_attendee_rel', 'case_id', \
|
||||
'rrule': fields.char('Recurrent Rule', size=352, invisible="True"),
|
||||
'rrule_type' : fields.selection([('none', 'None'), ('daily', 'Daily'), \
|
||||
('weekly', 'Weekly'), ('monthly', 'Monthly'), ('yearly', 'Yearly'), ('custom','Custom')], 'Recurrency'),
|
||||
'attendees': fields.function(_get_attendee_data, method=True,\
|
||||
fnct_inv=_set_attendee_data, string='Attendees', type="text"),
|
||||
'alarm_id': fields.many2one('res.alarm', 'Alarm'),
|
||||
'caldav_alarm_id': fields.many2one('calendar.alarm', 'Alarm'),
|
||||
'attendee_ids': fields.many2many('calendar.attendee', 'crm_attendee_rel', 'case_id', \
|
||||
'attendee_id', 'Attendees'),
|
||||
'alarm_id' : fields.many2one('crm.caldav.alarm', 'Alarm'),
|
||||
}
|
||||
|
||||
_defaults = {
|
||||
'class': lambda *a: 'PUBLIC',
|
||||
'transparent': lambda *a: 'OPAQUE',
|
||||
_defaults = {
|
||||
'class': lambda *a: 'public',
|
||||
}
|
||||
|
||||
def do_alarm_create(self, cr, uid, ids, context={}):
|
||||
alarm_obj = self.pool.get('calendar.alarm')
|
||||
model_obj = self.pool.get('ir.model')
|
||||
model_id = model_obj.search(cr, uid, [('model','=',self._name)])[0]
|
||||
|
||||
for meeting in self.browse(cr, uid, ids):
|
||||
self.do_alarm_unlink(cr, uid, [meeting.id])
|
||||
basic_alarm = meeting.alarm_id
|
||||
if basic_alarm and meeting.state in ('open'):
|
||||
vals = {
|
||||
'action': 'display',
|
||||
'description': meeting.description,
|
||||
'name': meeting.name,
|
||||
'attendee_ids': [(6,0, map(lambda x:x.id, meeting.attendee_ids))],
|
||||
'trigger_related': basic_alarm.trigger_related,
|
||||
'trigger_duration': basic_alarm.trigger_duration,
|
||||
'trigger_occurs': basic_alarm.trigger_occurs,
|
||||
'trigger_interval': basic_alarm.trigger_interval,
|
||||
'duration': basic_alarm.duration,
|
||||
'repeat': basic_alarm.repeat,
|
||||
'state' : 'run',
|
||||
'event_date' : meeting.date,
|
||||
'res_id' : meeting.id,
|
||||
'model_id' : model_id,
|
||||
'user_id' : uid
|
||||
}
|
||||
alarm_id = alarm_obj.create(cr, uid, vals)
|
||||
cr.execute('Update crm_meeting set caldav_alarm_id=%s where id=%s' % (alarm_id, meeting.id))
|
||||
cr.commit()
|
||||
return True
|
||||
|
||||
|
||||
def run_scheduler(self, cr, uid, automatic=False, use_new_cursor=False, \
|
||||
context=None):
|
||||
if not context:
|
||||
context = {}
|
||||
cr.execute('select c.id as id, crm_case.date as date, alarm.id as alarm_id, alarm.name as name,\
|
||||
alarm.trigger_interval, alarm.trigger_duration, alarm.trigger_related, \
|
||||
alarm.trigger_occurs from crm_meeting c \
|
||||
join crm_case on c.inherit_case_id = crm_case.id \
|
||||
join crm_caldav_alarm alarm on (alarm.id=c.alarm_id) \
|
||||
where alarm_id is not null and alarm.active=True')
|
||||
case_with_alarm = cr.dictfetchall()
|
||||
case_obj = self.pool.get('crm.meeting')
|
||||
attendee_obj = self.pool.get('crm.caldav.attendee')
|
||||
mail_to = []
|
||||
for alarmdata in case_with_alarm:
|
||||
dtstart = datetime.datetime.strptime(alarmdata['date'], "%Y-%m-%d %H:%M:%S")
|
||||
if alarmdata['trigger_interval'] == 'DAYS':
|
||||
delta = datetime.timedelta(days=alarmdata['trigger_duration'])
|
||||
if alarmdata['trigger_interval'] == 'HOURS':
|
||||
delta = datetime.timedelta(hours=alarmdata['trigger_duration'])
|
||||
if alarmdata['trigger_interval'] == 'MINUTES':
|
||||
delta = datetime.timedelta(minutes=alarmdata['trigger_duration'])
|
||||
alarm_time = dtstart + (alarmdata['trigger_occurs']== 'AFTER' and delta or -delta)
|
||||
if datetime.datetime.now() >= alarm_time:
|
||||
case_val = case_obj.browse(cr, uid, alarmdata.get('id'), context)[0]
|
||||
for att in case_val.attendees:
|
||||
if att.cn.rsplit(':')[-1]:
|
||||
mail_to.append(att.cn.rsplit(':')[-1])
|
||||
if mail_to:
|
||||
sub = 'Event Reminder for ' + case_val.name or ''
|
||||
body = (case_val.name or '')+ '\n\t' + (case_val.description or '') + '\n\nEvent time: ' \
|
||||
+(case_val.date) + '\n\nLocation: ' + (case_val.location or '') + \
|
||||
'\n\nMembers Details: ' + '\n'.join(mail_to)
|
||||
tools.email_send(
|
||||
case_val.user_id.address_id.email,
|
||||
mail_to,
|
||||
sub,
|
||||
body
|
||||
)
|
||||
cr.execute('update crm_caldav_alarm set active=False\
|
||||
where id = %s' % alarmdata['alarm_id'])
|
||||
cr.commit()
|
||||
def do_alarm_unlink(self, cr, uid, ids, context={}):
|
||||
alarm_obj = self.pool.get('calendar.alarm')
|
||||
model_obj = self.pool.get('ir.model')
|
||||
model_id = model_obj.search(cr, uid, [('model','=',self._name)])[0]
|
||||
for meeting in self.browse(cr, uid, ids):
|
||||
alarm_ids = alarm_obj.search(cr, uid, [('model_id','=',model_id), ('res_id','=',meeting.id)])
|
||||
if alarm_ids and len(alarm_ids):
|
||||
alarm_obj.unlink(cr, uid, alarm_ids)
|
||||
cr.execute('Update crm_meeting set caldav_alarm_id=NULL where id=%s' % (meeting.id))
|
||||
cr.commit()
|
||||
return True
|
||||
|
||||
def on_change_duration(self, cr, uid, id, date, duration):
|
||||
if not date:
|
||||
return {}
|
||||
start_date = datetime.datetime.fromtimestamp(time.mktime(time.strptime(date, "%Y-%m-%d %H:%M:%S")))
|
||||
if duration >= 0 :
|
||||
end = start_date + datetime.timedelta(hours=duration)
|
||||
if duration < 0:
|
||||
raise osv.except_osv(_('Warning !'),
|
||||
_('You can not set negative Duration.'))
|
||||
|
||||
res = {'value' : {'date_deadline' : end.strftime('%Y-%m-%d %H:%M:%S')}}
|
||||
return res
|
||||
|
||||
|
||||
|
||||
def export_cal(self, cr, uid, ids, context={}):
|
||||
crm_data = self.read(cr, uid, ids, [], context ={'read' :True})
|
||||
event_obj = self.pool.get('caldav.event')
|
||||
crm_data = self.read(cr, uid, ids, [], context ={'read':True})
|
||||
event_obj = self.pool.get('basic.calendar.event')
|
||||
event_obj.__attribute__.update(self.__attribute__)
|
||||
|
||||
attendee_obj = self.pool.get('caldav.attendee')
|
||||
crm_attendee = self.pool.get('crm.caldav.attendee')
|
||||
|
||||
attendee_obj = self.pool.get('basic.calendar.attendee')
|
||||
crm_attendee = self.pool.get('calendar.attendee')
|
||||
attendee_obj.__attribute__.update(crm_attendee.__attribute__)
|
||||
|
||||
alarm_obj = self.pool.get('caldav.alarm')
|
||||
crm_alarm = self.pool.get('crm.caldav.alarm')
|
||||
|
||||
alarm_obj = self.pool.get('basic.calendar.alarm')
|
||||
crm_alarm = self.pool.get('calendar.alarm')
|
||||
alarm_obj.__attribute__.update(crm_alarm.__attribute__)
|
||||
|
||||
|
||||
ical = event_obj.export_ical(cr, uid, crm_data, {'model': 'crm.meeting'})
|
||||
caendar_val = ical.serialize()
|
||||
caendar_val = caendar_val.replace('"', '').strip()
|
||||
@@ -160,36 +205,107 @@ class crm_meeting(osv.osv):
|
||||
|
||||
def import_cal(self, cr, uid, data, context={}):
|
||||
file_content = base64.decodestring(data)
|
||||
event_obj = self.pool.get('caldav.event')
|
||||
event_obj = self.pool.get('basic.calendar.event')
|
||||
event_obj.__attribute__.update(self.__attribute__)
|
||||
|
||||
attendee_obj = self.pool.get('caldav.attendee')
|
||||
crm_attendee = self.pool.get('crm.caldav.attendee')
|
||||
attendee_obj = self.pool.get('basic.calendar.attendee')
|
||||
crm_attendee = self.pool.get('calendar.attendee')
|
||||
attendee_obj.__attribute__.update(crm_attendee.__attribute__)
|
||||
|
||||
alarm_obj = self.pool.get('caldav.alarm')
|
||||
crm_alarm = self.pool.get('crm.caldav.alarm')
|
||||
|
||||
alarm_obj = self.pool.get('basic.calendar.alarm')
|
||||
crm_alarm = self.pool.get('calendar.alarm')
|
||||
alarm_obj.__attribute__.update(crm_alarm.__attribute__)
|
||||
vals = event_obj.import_ical(cr, uid, file_content)
|
||||
for val in vals:
|
||||
section_id = self.pool.get('crm.case.section').search(cr, uid, \
|
||||
[('name', 'like', 'Meeting%')])[0]
|
||||
val.update({'section_id' : section_id})
|
||||
is_exists = common.uid2openobjectid(cr, val['id'], self._name )
|
||||
for val in vals:
|
||||
is_exists = common.uid2openobjectid(cr, val['id'], self._name)
|
||||
val.pop('id')
|
||||
if val.has_key('create_date'): val.pop('create_date')
|
||||
val['caldav_url'] = context.get('url') or ''
|
||||
caldav_alarm_id = val['caldav_alarm_id']
|
||||
if caldav_alarm_id:
|
||||
caldav_alarm = self.browse(cr, uid, caldav_alarm_id)
|
||||
val['alarm_id'] = caldav_alarm.alarm_id
|
||||
if is_exists:
|
||||
self.write(cr, uid, [is_exists], val)
|
||||
else:
|
||||
case_id = self.create(cr, uid, val)
|
||||
return {'count': len(vals)}
|
||||
|
||||
def search(self, cr, uid, args, offset=0, limit=None, order=None,
|
||||
def get_recurrent_ids(self, cr, uid, ids, start_date, until_date, limit=100):
|
||||
if not limit:
|
||||
limit = 100
|
||||
if ids and (start_date or until_date):
|
||||
cr.execute("select m.id, m.rrule, c.date, m.exdate from crm_meeting m\
|
||||
join crm_case c on (c.id=m.inherit_case_id) \
|
||||
where m.id in ("+ ','.join(map(lambda x: str(x), ids))+")")
|
||||
result = []
|
||||
count = 0
|
||||
start_date = start_date and datetime.datetime.strptime(start_date, "%Y-%m-%d") or False
|
||||
until_date = until_date and datetime.datetime.strptime(until_date, "%Y-%m-%d") or False
|
||||
for data in cr.dictfetchall():
|
||||
if count > limit:
|
||||
break
|
||||
event_date = datetime.datetime.strptime(data['date'], "%Y-%m-%d %H:%M:%S")
|
||||
if start_date and start_date <= event_date:
|
||||
start_date = event_date
|
||||
if not data['rrule']:
|
||||
idval = common.real_id2caldav_id(data['id'], data['date'])
|
||||
result.append(idval)
|
||||
count += 1
|
||||
else:
|
||||
exdate = data['exdate'] and data['exdate'].split(',') or []
|
||||
event_obj = self.pool.get('basic.calendar.event')
|
||||
rrule_str = data['rrule']
|
||||
new_rrule_str = []
|
||||
rrule_until_date = False
|
||||
is_until = False
|
||||
for rule in rrule_str.split(';'):
|
||||
name, value = rule.split('=')
|
||||
if name == "UNTIL":
|
||||
is_until = True
|
||||
value = parser.parse(value)
|
||||
rrule_until_date = parser.parse(value.strftime("%Y-%m-%d"))
|
||||
if until_date and until_date >= rrule_until_date:
|
||||
until_date = rrule_until_date
|
||||
if until_date:
|
||||
until_date = until_date.strftime("%Y%m%d%H%M%S")
|
||||
value = until_date
|
||||
new_rule = '%s=%s' % (name, value)
|
||||
new_rrule_str.append(new_rule)
|
||||
if not is_until and until_date:
|
||||
until_date = until_date.strftime("%Y%m%d%H%M%S")
|
||||
value = until_date
|
||||
name = "UNTIL"
|
||||
new_rule = '%s=%s' % (name, value)
|
||||
new_rrule_str.append(new_rule)
|
||||
new_rrule_str = ';'.join(new_rrule_str)
|
||||
start_date = datetime.datetime.strptime(data['date'], "%Y-%m-%d %H:%M:%S")
|
||||
rdates = event_obj.get_recurrent_dates(str(new_rrule_str), exdate, start_date)
|
||||
for rdate in rdates:
|
||||
idval = common.real_id2caldav_id(data['id'], rdate)
|
||||
result.append(idval)
|
||||
count += 1
|
||||
ids = result
|
||||
return ids
|
||||
|
||||
def search(self, cr, uid, args, offset=0, limit=100, order=None,
|
||||
context=None, count=False):
|
||||
res = super(crm_meeting, self).search(cr, uid, args, offset,
|
||||
args_without_date = []
|
||||
start_date = False
|
||||
until_date = False
|
||||
for arg in args:
|
||||
if arg[0] not in ('date', unicode('date')):
|
||||
args_without_date.append(arg)
|
||||
else:
|
||||
if arg[1] in ('>', '>='):
|
||||
start_date = arg[2]
|
||||
elif arg[1] in ('<', '<='):
|
||||
until_date = arg[2]
|
||||
|
||||
res = super(crm_meeting, self).search(cr, uid, args_without_date, offset,
|
||||
limit, order, context, count)
|
||||
return res
|
||||
return self.get_recurrent_ids(cr, uid, res, start_date, until_date, limit)
|
||||
|
||||
|
||||
def write(self, cr, uid, ids, vals, context=None, check=True, update_check=True):
|
||||
if isinstance(ids, (str, int, long)):
|
||||
@@ -198,152 +314,150 @@ class crm_meeting(osv.osv):
|
||||
select = ids
|
||||
new_ids = []
|
||||
for id in select:
|
||||
id = common.caldevIDs2readIDs(id)
|
||||
id = common.caldav_id2real_id(id)
|
||||
if not id in new_ids:
|
||||
new_ids.append(id)
|
||||
if 'case_id' in vals :
|
||||
vals['case_id'] = common.caldevIDs2readIDs(vals['case_id'])
|
||||
if 'case_id' in vals:
|
||||
vals['case_id'] = common.caldav_id2real_id(vals['case_id'])
|
||||
res = super(crm_meeting, self).write(cr, uid, new_ids, vals, context=context)
|
||||
self.do_alarm_create(cr, uid, ids)
|
||||
return res
|
||||
|
||||
def browse(self, cr, uid, ids, context=None, list_class=None, fields_process={}):
|
||||
if isinstance(ids, (str, int, long)):
|
||||
select = [ids]
|
||||
else:
|
||||
select = ids
|
||||
select = map(lambda x:common.caldevIDs2readIDs(x), select)
|
||||
res = super(crm_meeting, self).browse(cr, uid, select, context, list_class, fields_process)
|
||||
select = ids
|
||||
select = map(lambda x: common.caldav_id2real_id(x), select)
|
||||
res = super(crm_meeting, self).browse(cr, uid, select, context, list_class, fields_process)
|
||||
if isinstance(ids, (str, int, long)):
|
||||
return res and res[0] or False
|
||||
return res
|
||||
|
||||
def read(self, cr, uid, ids, fields=None, context={}, load='_classic_read'):
|
||||
""" logic for recurrent event
|
||||
example : 123-20091111170822"""
|
||||
if context and context.has_key('read'):
|
||||
return super(crm_meeting, self).read(cr, uid, ids, fields=fields, context=context, \
|
||||
load=load)
|
||||
if not type(ids) == list :
|
||||
# Called from code
|
||||
return super(crm_meeting, self).read(cr, uid, common.caldevIDs2readIDs(ids), \
|
||||
fields=fields, context=context, load=load)
|
||||
def read(self, cr, uid, ids, fields=None, context={}, load='_classic_read'):
|
||||
if isinstance(ids, (str, int, long)):
|
||||
select = [ids]
|
||||
else:
|
||||
ids = map(lambda x:common.caldevIDs2readIDs(x), ids)
|
||||
|
||||
select = ids
|
||||
select = map(lambda x: (x, common.caldav_id2real_id(x)), select)
|
||||
result = []
|
||||
if fields and 'date' not in fields:
|
||||
fields.append('date')
|
||||
if not ids:
|
||||
return []
|
||||
result = []
|
||||
for read_id in ids:
|
||||
res = super(crm_meeting, self).read(cr, uid, read_id, fields=fields, context=context, load=load)
|
||||
cr.execute("""select m.id, m.rrule, c.date, m.exdate from crm_meeting m\
|
||||
join crm_case c on (c.id=m.inherit_case_id) \
|
||||
where m.id = %s""" % read_id)
|
||||
data = cr.dictfetchall()[0]
|
||||
if not data['rrule']:
|
||||
strdate = ''.join((re.compile('\d')).findall(data['date']))
|
||||
idval = str(common.caldevIDs2readIDs(data['id'])) + '-' + strdate
|
||||
data['id'] = idval
|
||||
res.update(data)
|
||||
result.append(res)
|
||||
else:
|
||||
exdate = data['exdate'] and data['exdate'].split(',') or []
|
||||
event_obj = self.pool.get('caldav.event')
|
||||
rdates = event_obj.get_recurrent_dates(str(data['rrule']), exdate, data['date'])[:10]
|
||||
for rdate in rdates:
|
||||
val = res.copy()
|
||||
idval = (re.compile('\d')).findall(rdate)
|
||||
val['date'] = rdate
|
||||
id = str(res['id']).split('-')[0]
|
||||
val['id'] = id + '-' + ''.join(idval)
|
||||
val1 = val.copy()
|
||||
result.append(val1)
|
||||
for caldav_id, real_id in select:
|
||||
res = super(crm_meeting, self).read(cr, uid, real_id, fields=fields, context=context, \
|
||||
load=load)
|
||||
ls = common.caldav_id2real_id(caldav_id, with_date=True)
|
||||
if not isinstance(ls, (str, int, long)) and len(ls) >= 2:
|
||||
res['date'] = ls[1]
|
||||
res['id'] = caldav_id
|
||||
|
||||
result.append(res)
|
||||
if isinstance(ids, (str, int, long)):
|
||||
return result and result[0] or False
|
||||
return result
|
||||
|
||||
def copy(self, cr, uid, id, default=None, context={}):
|
||||
return super(crm_meeting, self).copy(cr, uid, common.caldevIDs2readIDs(id), \
|
||||
def copy(self, cr, uid, id, default=None, context={}):
|
||||
res = super(crm_meeting, self).copy(cr, uid, common.caldav_id2real_id(id), \
|
||||
default, context)
|
||||
self.do_alarm_create(cr, uid, [res])
|
||||
return res
|
||||
|
||||
def unlink(self, cr, uid, ids, context=None):
|
||||
res = False
|
||||
for id in ids:
|
||||
if len(str(id).split('-')) > 1:
|
||||
date_new = time.strftime("%Y-%m-%d %H:%M:%S", \
|
||||
time.strptime(str(str(id).split('-')[1]), "%Y%m%d%H%M%S"))
|
||||
for record in self.read(cr, uid, [common.caldevIDs2readIDs(id)], \
|
||||
ls = common.caldav_id2real_id(id)
|
||||
if not isinstance(ls, (str, int, long)) and len(ls) >= 2:
|
||||
date_new = ls[1]
|
||||
for record in self.read(cr, uid, [common.caldav_id2real_id(id)], \
|
||||
['date', 'rrule', 'exdate']):
|
||||
if record['rrule']:
|
||||
exdate = (record['exdate'] and (record['exdate'] + ',' ) or '') + \
|
||||
exdate = (record['exdate'] and (record['exdate'] + ',') or '') + \
|
||||
''.join((re.compile('\d')).findall(date_new)) + 'Z'
|
||||
if record['date'] == date_new:
|
||||
self.write(cr, uid, [common.caldevIDs2readIDs(id)], {'exdate' : exdate})
|
||||
res = self.write(cr, uid, [common.caldav_id2real_id(id)], {'exdate': exdate})
|
||||
else:
|
||||
ids = map(lambda x:common.caldevIDs2readIDs(x), ids)
|
||||
return super(crm_meeting, self).unlink(cr, uid, common.caldevIDs2readIDs(ids))
|
||||
ids = map(lambda x: common.caldav_id2real_id(x), ids)
|
||||
res = super(crm_meeting, self).unlink(cr, uid, common.caldav_id2real_id(ids))
|
||||
self.do_alarm_unlink(cr, uid, ids)
|
||||
else:
|
||||
return super(crm_meeting, self).unlink(cr, uid, ids)
|
||||
res = super(crm_meeting, self).unlink(cr, uid, ids)
|
||||
self.do_alarm_unlink(cr, uid, ids)
|
||||
return res
|
||||
|
||||
def create(self, cr, uid, vals, context={}):
|
||||
if 'case_id' in vals:
|
||||
vals['case_id'] = common.caldevIDs2readIDs(vals['case_id'])
|
||||
return super(crm_meeting, self).create(cr, uid, vals, context)
|
||||
vals['case_id'] = common.caldav_id2real_id(vals['case_id'])
|
||||
res = super(crm_meeting, self).create(cr, uid, vals, context)
|
||||
self.do_alarm_create(cr, uid, [res])
|
||||
return res
|
||||
|
||||
|
||||
def _map_ids(self, method, cr, uid, ids, *args, **argv):
|
||||
if isinstance(ids, (str, int, long)):
|
||||
select = [ids]
|
||||
else:
|
||||
select = ids
|
||||
select = ids
|
||||
case_data = self.browse(cr, uid, select)
|
||||
new_ids = []
|
||||
for case in case_data:
|
||||
if case.inherit_case_id:
|
||||
new_ids.append(case.inherit_case_id.id)
|
||||
res = getattr(self.pool.get('crm.case'),method)(cr, uid, new_ids, *args, **argv)
|
||||
res = getattr(self.pool.get('crm.case'), method)(cr, uid, new_ids, *args, **argv)
|
||||
if isinstance(ids, (str, int, long)) and isinstance(res, list):
|
||||
return res and res[0] or False
|
||||
return res
|
||||
|
||||
|
||||
def onchange_rrule_type(self, cr, uid, ids, type, *args, **argv):
|
||||
if type == 'none':
|
||||
return {'value': {'rrule': ''}}
|
||||
if type == 'custom':
|
||||
return {}
|
||||
rrule = self.pool.get('caldav.set.rrule')
|
||||
rrulestr = rrule.compute_rule_string(cr, uid, {'freq': type.upper(),\
|
||||
'interval': 1})
|
||||
return {'value': {'rrule': rrulestr}}
|
||||
|
||||
|
||||
def onchange_case_id(self, cr, uid, ids, *args, **argv):
|
||||
return self._map_ids('onchange_case_id',cr,uid,ids,*args,**argv)
|
||||
return self._map_ids('onchange_case_id', cr, uid, ids, *args, **argv)
|
||||
def onchange_partner_id(self, cr, uid, ids, *args, **argv):
|
||||
return self._map_ids('onchange_partner_id',cr,uid,ids,*args,**argv)
|
||||
return self._map_ids('onchange_partner_id', cr, uid, ids, *args, **argv)
|
||||
def onchange_partner_address_id(self, cr, uid, ids, *args, **argv):
|
||||
return self._map_ids('onchange_partner_address_id',cr,uid,ids,*args,**argv)
|
||||
return self._map_ids('onchange_partner_address_id', cr, uid, ids, *args, **argv)
|
||||
def onchange_categ_id(self, cr, uid, ids, *args, **argv):
|
||||
return self._map_ids('onchange_categ_id',cr,uid,ids,*args,**argv)
|
||||
def case_close(self,cr, uid, ids, *args, **argv):
|
||||
return self._map_ids('case_close',cr,uid,ids,*args,**argv)
|
||||
def case_open(self,cr, uid, ids, *args, **argv):
|
||||
return self._map_ids('case_open',cr,uid,ids,*args,**argv)
|
||||
def case_cancel(self,cr, uid, ids, *args, **argv):
|
||||
return self._map_ids('case_cancel',cr,uid,ids,*args,**argv)
|
||||
def case_reset(self,cr, uid, ids, *args, **argv):
|
||||
return self._map_ids('case_reset',cr,uid,ids,*args,**argv)
|
||||
return self._map_ids('onchange_categ_id', cr, uid, ids, *args, **argv)
|
||||
def case_close(self, cr, uid, ids, *args, **argv):
|
||||
return self._map_ids('case_close', cr, uid, ids, *args, **argv)
|
||||
def case_open(self, cr, uid, ids, *args, **argv):
|
||||
return self._map_ids('case_open', cr, uid, ids, *args, **argv)
|
||||
def case_cancel(self, cr, uid, ids, *args, **argv):
|
||||
return self._map_ids('case_cancel', cr, uid, ids, *args, **argv)
|
||||
def case_reset(self, cr, uid, ids, *args, **argv):
|
||||
return self._map_ids('case_reset', cr, uid, ids, *args, **argv)
|
||||
|
||||
def msg_new(self, cr, uid, msg):
|
||||
def msg_new(self, cr, uid, msg):
|
||||
mailgate_obj = self.pool.get('mail.gateway')
|
||||
msg_body = mailgate_obj.msg_body_get(msg)
|
||||
data = {
|
||||
'name': msg['Subject'],
|
||||
'email_from': msg['From'],
|
||||
'email_cc': msg['Cc'],
|
||||
'user_id': False,
|
||||
'description': msg_body['body'],
|
||||
'history_line': [(0, 0, {'description': msg_body['body'], 'email': msg['From'] })],
|
||||
'name': msg['Subject'],
|
||||
'email_from': msg['From'],
|
||||
'email_cc': msg['Cc'],
|
||||
'user_id': False,
|
||||
'description': msg_body['body'],
|
||||
'history_line': [(0, 0, {'description': msg_body['body'], 'email': msg['From'] })],
|
||||
}
|
||||
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)
|
||||
return res
|
||||
|
||||
def msg_update(self, cr, uid, ids, *args, **argv):
|
||||
return self._map_ids('msg_update',cr, uid, ids, *args, **argv)
|
||||
return self._map_ids('msg_update', cr, uid, ids, *args, **argv)
|
||||
def emails_get(self, cr, uid, ids, *args, **argv):
|
||||
return self._map_ids('emails_get',cr, uid, ids, *args, **argv)
|
||||
def msg_send(self, cr, uid, ids, *args, **argv):
|
||||
return self._map_ids('msg_send',cr, uid, ids, *args, **argv)
|
||||
return self._map_ids('emails_get', cr, uid, ids, *args, **argv)
|
||||
def msg_send(self, cr, uid, ids, *args, **argv):
|
||||
return self._map_ids('msg_send', cr, uid, ids, *args, **argv)
|
||||
|
||||
crm_meeting()
|
||||
|
||||
@@ -352,16 +466,16 @@ class crm_meeting_generic_wizard(osv.osv_memory):
|
||||
_name = 'crm.meeting.generic_wizard'
|
||||
|
||||
_columns = {
|
||||
'section_id': fields.many2one('crm.case.section', 'Section', required=True),
|
||||
'user_id': fields.many2one('res.users', 'Responsible'),
|
||||
'section_id': fields.many2one('crm.case.section', 'Section', required=True),
|
||||
'user_id': fields.many2one('res.users', 'Responsible'),
|
||||
}
|
||||
|
||||
def _get_default_section(self, cr, uid, context):
|
||||
case_id = context.get('active_id',False)
|
||||
case_id = context.get('active_id', False)
|
||||
if not case_id:
|
||||
return False
|
||||
case_obj = self.pool.get('crm.meeting')
|
||||
case = case_obj.read(cr, uid, case_id, ['state','section_id'])
|
||||
case = case_obj.read(cr, uid, case_id, ['state', 'section_id'])
|
||||
if case['state'] in ('done'):
|
||||
raise osv.except_osv(_('Error !'), _('You can not assign Closed Case.'))
|
||||
return case['section_id']
|
||||
@@ -372,32 +486,91 @@ class crm_meeting_generic_wizard(osv.osv_memory):
|
||||
}
|
||||
def action_create(self, cr, uid, ids, context=None):
|
||||
case_obj = self.pool.get('crm.meeting')
|
||||
case_id = context.get('active_id',[])
|
||||
case_id = context.get('active_id', [])
|
||||
res = self.read(cr, uid, ids)[0]
|
||||
case = case_obj.browse(cr, uid, case_id)
|
||||
if case.state in ('done'):
|
||||
raise osv.except_osv(_('Error !'), _('You can not assign Closed Case.'))
|
||||
new_case_id = case_obj.copy(cr, uid, case_id, default=
|
||||
{
|
||||
'section_id':res.get('section_id',False),
|
||||
'user_id':res.get('user_id',False),
|
||||
'case_id' : case.inherit_case_id.id
|
||||
}, context=context)
|
||||
'section_id': res.get('section_id', False),
|
||||
'user_id': res.get('user_id', False),
|
||||
'case_id': case.inherit_case_id.id
|
||||
}, context=context)
|
||||
case_obj.case_close(cr, uid, [case_id])
|
||||
data_obj = self.pool.get('ir.model.data')
|
||||
result = data_obj._get_id(cr, uid, 'crm', 'view_crm_case_meetings_filter')
|
||||
search_view = data_obj.read(cr, uid, result, ['res_id'])
|
||||
new_case = case_obj.read(cr, uid, new_case_id, ['id'])
|
||||
value = {
|
||||
'name': _('Meetings'),
|
||||
'view_type': 'form',
|
||||
'view_mode': 'calendar, tree, form',
|
||||
'res_model': 'crm.meeting',
|
||||
'type': 'ir.actions.act_window',
|
||||
new_case = case_obj.read(cr, uid, new_case_id, ['id'])
|
||||
value = {
|
||||
'name': _('Meetings'),
|
||||
'view_type': 'form',
|
||||
'view_mode': 'calendar, tree, form',
|
||||
'res_model': 'crm.meeting',
|
||||
'type': 'ir.actions.act_window',
|
||||
'search_view_id': search_view['res_id']
|
||||
}
|
||||
return value
|
||||
|
||||
crm_meeting_generic_wizard()
|
||||
|
||||
class res_users(osv.osv):
|
||||
_inherit = 'res.users'
|
||||
|
||||
def _get_user_avail(self, cr, uid, ids, name, args, context=None):
|
||||
res={}
|
||||
if not context or not context.get('model'):
|
||||
return {}
|
||||
else:
|
||||
model = context.get('model')
|
||||
obj = self.pool.get(model)
|
||||
event_obj = obj.browse(cr, uid, context['active_id'])
|
||||
event_start = event_obj.date
|
||||
event_end = datetime.datetime.strptime(event_obj.date, "%Y-%m-%d %H:%M:%S") \
|
||||
+ datetime.timedelta(hours=event_obj.duration)
|
||||
for id in ids:
|
||||
datas = self.browse(cr, uid, id)
|
||||
cr.execute("""SELECT c.date as start, (c.date::timestamp \
|
||||
+ c.duration * interval '1 hour') as end \
|
||||
from crm_meeting m \
|
||||
join crm_case c on (c.id=m.inherit_case_id)\
|
||||
where c.user_id = %s
|
||||
and m.id not in (""" % (datas['id']) + str(context['active_id']) +")")
|
||||
dates = cr.dictfetchall()
|
||||
overlaps = False
|
||||
# check event time
|
||||
for date in dates:
|
||||
start = date['start']
|
||||
end = date['end']
|
||||
cr.execute("SELECT (timestamp '%s', timestamp '%s') OVERLAPS\
|
||||
(timestamp '%s', timestamp '%s')" % (event_start, event_end, start, end))
|
||||
over = cr.fetchone()[0]
|
||||
if over:
|
||||
overlaps = True
|
||||
|
||||
# check for attendee added already
|
||||
cr.execute("""select att.user_id , c.id
|
||||
from calendar_attendee att
|
||||
inner join crm_attendee_rel rel on (rel.attendee_id=att.id)
|
||||
join crm_meeting m on (rel.case_id=m.id)
|
||||
join crm_case c on (m.inherit_case_id = c.id )
|
||||
where (c.date, c.date::timestamp + c.duration * interval '1 hour') overlaps\
|
||||
(timestamp '%s', timestamp '%s')""" % (event_start, event_end))
|
||||
added_data = filter(lambda x: x.get('user_id')==id, cr.dictfetchall())
|
||||
if added_data:
|
||||
overlaps = True
|
||||
if overlaps:
|
||||
res[id] = 'busy'
|
||||
else:
|
||||
res[id] = 'free'
|
||||
return res
|
||||
|
||||
_columns = {
|
||||
'availability': fields.function(_get_user_avail, type='selection', \
|
||||
selection=[('free', 'Free'), ('busy', 'Busy')], \
|
||||
string='Free/Busy', method=True),
|
||||
}
|
||||
|
||||
res_users()
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
@@ -58,21 +58,12 @@
|
||||
<record model="crm.case.stage" id="stage_meet5">
|
||||
<field name="name">Future</field>
|
||||
<field name="section_id" ref="section_support1"/>
|
||||
</record>
|
||||
|
||||
<record model="res.request.link" id="request_link_meeting">
|
||||
<field name="name">Case Meeting</field>
|
||||
<field name="object">crm.meeting</field>
|
||||
</record>
|
||||
<!-- Scheduler for Event Alarm-->
|
||||
<record forcecreate="True" id="ir_cron_scheduler_alarm"
|
||||
model="ir.cron">
|
||||
<field name="name">Run Event Reminder</field>
|
||||
<field eval="True" name="active" />
|
||||
<field name="user_id" ref="base.user_root" />
|
||||
<field name="interval_number">1</field>
|
||||
<field name="interval_type">days</field>
|
||||
<field name="numbercall">-1</field>
|
||||
<field eval="False" name="doall" />
|
||||
<field eval="'crm.meeting'" name="model" />
|
||||
<field eval="'run_scheduler'" name="function" />
|
||||
<field eval="'(False,)'" name="args" />
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
|
||||
@@ -86,7 +86,6 @@
|
||||
<field name="view_id" ref="crm_case_calendar_view_meet"/>
|
||||
<field name="context" eval="{'default_state':'open'}"/>
|
||||
<field name="search_view_id" ref="view_crm_case_meetings_filter"/>
|
||||
<field name="domain" eval="[('section_id.calendar','=',1)]"/>
|
||||
</record>
|
||||
<record model="ir.actions.act_window.view" id="action_crm_tag_calendar_meet">
|
||||
<field name="sequence" eval="1"/>
|
||||
@@ -113,6 +112,10 @@
|
||||
<field name="act_window_id" ref="crm_case_categ_meet"/>
|
||||
</record>
|
||||
<menuitem parent="crm.menu_crm" name="Calendar" id="menu_crm_case_category_act_meetings"/>
|
||||
|
||||
<menuitem parent="crm.menu_crm_case_category_act_meetings"
|
||||
name="My Invitations" id="menu_crm_meetings_invitation"
|
||||
action="caldav.action_view_attendee_form" />
|
||||
|
||||
<!--
|
||||
ALL MEETINGS
|
||||
|
||||
@@ -33,47 +33,70 @@
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="crm_case_form_view_meet">
|
||||
<record model="ir.ui.view" id="view_users_form_crm">
|
||||
<field name="name">caldav.res.users.form</field>
|
||||
<field name="type">form</field>
|
||||
<field name="priority">10</field>
|
||||
<field name="model">res.users</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="User">
|
||||
<field name="name" />
|
||||
<field name="availability" />
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="view_users_tree_crm">
|
||||
<field name="name">caldav.res.users.tree</field>
|
||||
<field name="type">tree</field>
|
||||
<field name="priority">10</field>
|
||||
<field name="model">res.users</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Userss">
|
||||
<field name="name" />
|
||||
<field name="availability" />
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="crm_case_form_view_meet">
|
||||
<field name="name">CRM - Meetings Form</field>
|
||||
<field name="model">crm.meeting</field>
|
||||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Meetings Form">
|
||||
<field name="name" select="1" string="Title"/>
|
||||
<field name="section_id" widget="selection"
|
||||
string="Calendar" domain="[('calendar','=',True)]"/>
|
||||
<field name="location" />
|
||||
<field name="categ_id" select="2" on_change="onchange_categ_id(categ_id)"/>
|
||||
|
||||
<group colspan="4" col="6">
|
||||
<field name="name" select="1" string="Title"/>
|
||||
<field name="section_id" widget="selection"
|
||||
string="Calendar" domain="[('calendar','=',True)]"/>
|
||||
<field name="user_id" select="2" string="Responsible" required="1"/>
|
||||
<newline/>
|
||||
<field name="date" string="Meeting Date" required="1"/>
|
||||
<field name="duration" colspan="1" widget="float_time" required="1"/>
|
||||
<group colspan="2">
|
||||
<field name="case_id" on_change="onchange_case_id(case_id, name, partner_id)"/>
|
||||
<button string="Assign" name="%(crm_meeting_generic_wizard_act)d" type="action" />
|
||||
</group>
|
||||
<field name="date" string="Start Date" on_change="on_change_duration(date, duration)" required="1"/>
|
||||
<field name="duration" string="Duration(In Hour)" on_change="on_change_duration(date, duration)" widget="float_time"/>
|
||||
<field name="date_deadline" string="End Date" required="1"/>
|
||||
|
||||
</group>
|
||||
<notebook colspan="4">
|
||||
<page string="Meeting">
|
||||
<field name="partner_id" on_change="onchange_partner_id(partner_id, email_from)" />
|
||||
<field name="partner_address_id" on_change="onchange_partner_address_id(partner_address_id, email_from)"/>
|
||||
<field name="email_from"/>
|
||||
<newline/>
|
||||
<field name="categ_id" select="2" on_change="onchange_categ_id(categ_id)"/>
|
||||
<field name="location" />
|
||||
<field name="alarm_id" colspan="4" string="Reminder"/>
|
||||
<group colspan="4">
|
||||
<field name="rrule" string="Recurrency Rule"/>
|
||||
<button string="Change RRule"
|
||||
<page string="Meeting">
|
||||
<field name="alarm_id" colspan="1" string="Alarm"/>
|
||||
<group colspan="2" col="3">
|
||||
<field name="rrule_type" string="Recurrency"
|
||||
on_change="onchange_rrule_type(rrule_type)"
|
||||
colspan="1" />
|
||||
<button string="Custom"
|
||||
name="%(caldav.action_view_caldav_set_rrule_wizard)d"
|
||||
icon="gtk-save-as" type="action" context="{'model' : 'crm.meeting'}"/>
|
||||
icon="gtk-save-as" type="action" context="{'model' : 'crm.meeting'}"
|
||||
attrs="{'readonly':[('rrule_type','!=','custom')]}"
|
||||
/>
|
||||
</group>
|
||||
<separator string="Description" colspan="4"/>
|
||||
<field name="description" nolabel="1" colspan="4"/>
|
||||
<separator colspan="4"/>
|
||||
<field name="class"/>
|
||||
<field name="transparent"/>
|
||||
<separator colspan="4"/>
|
||||
<separator string="Description" colspan="4"/>
|
||||
<field name="description" nolabel="1" colspan="4"/>
|
||||
<separator string="Attendees" colspan="4"/>
|
||||
<field name="attendees" nolabel="1" colspan="4"/>
|
||||
<field name="show_as" string="Show as"/>
|
||||
<field name="class" string="Mark as"/>
|
||||
<separator string="" colspan="4"/>
|
||||
<group col="8" colspan="4">
|
||||
<field name="state" select="2"/>
|
||||
<button name="case_open" string="Confirm Meeting" states="draft,cancel,pending" type="object" icon="terp-crm"/>
|
||||
@@ -82,15 +105,29 @@
|
||||
</group>
|
||||
</page>
|
||||
<page string="Attendee Detail">
|
||||
<separator string="Attendee" colspan="4"/>
|
||||
<field name="attendees" colspan="4" nolabel="1"/>
|
||||
</page>
|
||||
<separator string="Attendees" colspan="4"/>
|
||||
<field name="attendee_ids" colspan="4" nolabel="1"/>
|
||||
<button string="Invite Attendees"
|
||||
name="%(caldav.action_view_calendar_invite_attendee_wizard)d"
|
||||
icon="terp-partner" type="action"
|
||||
context="{'model' : 'crm.meeting'}" />
|
||||
</page>
|
||||
<page string="Partner Info">
|
||||
<field name="partner_id" on_change="onchange_partner_id(partner_id, email_from)" />
|
||||
<field name="partner_address_id" on_change="onchange_partner_address_id(partner_address_id, email_from)"/>
|
||||
<field name="email_from"/>
|
||||
</page>
|
||||
<page string="Other Info">
|
||||
<field name="caldav_url" widget="url" readonly="True"/>
|
||||
<newline/>
|
||||
<field name="user_id" select="2" string="Responsible" required="1"/>
|
||||
<group colspan="2">
|
||||
<field name="case_id" on_change="onchange_case_id(case_id, name, partner_id)"/>
|
||||
<button string="Assign" name="%(crm_meeting_generic_wizard_act)d" type="action" />
|
||||
</group>
|
||||
<field name="rrule" string="Recurrent Rules" colspan="4"/>
|
||||
<field name="exrule" string="Exception Rules" colspan="4"/>
|
||||
<separator string="Exception Dates" colspan="4"/>
|
||||
<field name="exdate" nolabel="1" colspan="4" />
|
||||
<field name="exdate" nolabel="1" colspan="4" />
|
||||
|
||||
</page>
|
||||
</notebook>
|
||||
</form>
|
||||
@@ -123,10 +160,10 @@
|
||||
<field name="type">calendar</field>
|
||||
<field name="priority" eval="2"/>
|
||||
<field name="arch" type="xml">
|
||||
<calendar string="Meetings" date_start="date" color="user_id" date_delay="duration">
|
||||
<calendar string="Meetings" date_start="date" color="section_id" date_delay="duration">
|
||||
<field name="name"/>
|
||||
<field name="partner_id"/>
|
||||
<field name="section_id" widget="selection"/>
|
||||
<field name="user_id" widget="selection"/>
|
||||
</calendar>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
+3253
-1025
File diff suppressed because it is too large
Load Diff
+3256
-1028
File diff suppressed because it is too large
Load Diff
@@ -6,8 +6,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: OpenERP Server 5.0.4\n"
|
||||
"Report-Msgid-Bugs-To: support@openerp.com\n"
|
||||
"POT-Creation-Date: 2009-08-28 16:01+0000\n"
|
||||
"PO-Revision-Date: 2009-02-03 09:18+0000\n"
|
||||
"POT-Creation-Date: 2010-01-05 16:01+0000\n"
|
||||
"PO-Revision-Date: 2010-01-05 09:18+0000\n"
|
||||
"Last-Translator: Fabien (Open ERP) <fp@tinyerp.com>\n"
|
||||
"Language-Team: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
|
||||
+3485
-1154
File diff suppressed because it is too large
Load Diff
+3324
-953
File diff suppressed because it is too large
Load Diff
+3267
-1033
File diff suppressed because it is too large
Load Diff
+3532
-1202
File diff suppressed because it is too large
Load Diff
+3472
-1193
File diff suppressed because it is too large
Load Diff
+3485
-1156
File diff suppressed because it is too large
Load Diff
+3458
-1181
File diff suppressed because it is too large
Load Diff
+3439
-1135
File diff suppressed because it is too large
Load Diff
+3321
-1030
File diff suppressed because it is too large
Load Diff
+3704
-1136
File diff suppressed because it is too large
Load Diff
+3459
-1196
File diff suppressed because it is too large
Load Diff
+3253
-1025
File diff suppressed because it is too large
Load Diff
+3255
-1027
File diff suppressed because it is too large
Load Diff
+3253
-1025
File diff suppressed because it is too large
Load Diff
+3484
-1156
File diff suppressed because it is too large
Load Diff
+3253
-1025
File diff suppressed because it is too large
Load Diff
+3441
-1175
File diff suppressed because it is too large
Load Diff
+3512
-1105
File diff suppressed because it is too large
Load Diff
+3253
-1025
File diff suppressed because it is too large
Load Diff
+3490
-1155
File diff suppressed because it is too large
Load Diff
+3254
-1026
File diff suppressed because it is too large
Load Diff
+3381
-1099
File diff suppressed because it is too large
Load Diff
+3449
-1131
File diff suppressed because it is too large
Load Diff
+3481
-1152
File diff suppressed because it is too large
Load Diff
+3267
-1039
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user