\n"
+" Click to add a new contribution register.\n"
+"
\n"
+" A contribution register is a third party involved in the "
+"salary\n"
+" payment of the employees. It can be the social security, "
+"the\n"
+" estate or anyone that collect or inject money on payslips.\n"
+"
\n"
+" "
+msgstr ""
+
+#. module: hr_payroll
+#: help:hr.payslip.line,condition_range_max:0
+#: help:hr.salary.rule,condition_range_max:0
+msgid "The maximum amount, applied for this rule."
+msgstr ""
+
+#. module: hr_payroll
+#: help:hr.payslip.line,condition_python:0
+#: help:hr.salary.rule,condition_python:0
+msgid ""
+"Applied this rule for calculation if condition is true. You can specify "
+"condition like basic > 1000."
+msgstr ""
+
+#. module: hr_payroll
+#: report:contribution.register.lines:0
+#: report:paylip.details:0
+msgid "Register Name"
+msgstr ""
+
+#. module: hr_payroll
+#: view:hr.payslip.employees:0
+msgid "Payslips by Employees"
+msgstr ""
+
+#. module: hr_payroll
+#: selection:hr.contract,schedule_pay:0
+msgid "Quarterly"
+msgstr ""
+
+#. module: hr_payroll
+#: selection:hr.payslip,state:0
+msgid "Waiting"
+msgstr ""
+
+#. module: hr_payroll
+#: help:hr.salary.rule,quantity:0
+msgid ""
+"It is used in computation for percentage and fixed amount.For e.g. A rule "
+"for Meal Voucher having fixed amount of 1€ per worked day can have its "
+"quantity defined in expression like worked_days.WORK100.number_of_days."
+msgstr ""
+
+#. module: hr_payroll
+#: view:hr.salary.rule:0
+msgid "Search Salary Rule"
+msgstr ""
+
+#. module: hr_payroll
+#: field:hr.payslip,employee_id:0
+#: field:hr.payslip.line,employee_id:0
+#: model:ir.model,name:hr_payroll.model_hr_employee
+msgid "Employee"
+msgstr ""
+
+#. module: hr_payroll
+#: selection:hr.contract,schedule_pay:0
+msgid "Semi-annually"
+msgstr ""
+
+#. module: hr_payroll
+#: report:paylip.details:0
+#: report:payslip:0
+msgid "Email"
+msgstr ""
+
+#. module: hr_payroll
+#: view:hr.payslip.run:0
+msgid "Search Payslip Batches"
+msgstr ""
+
+#. module: hr_payroll
+#: field:hr.payslip.line,amount_percentage_base:0
+#: field:hr.salary.rule,amount_percentage_base:0
+msgid "Percentage based on"
+msgstr ""
+
+#. module: hr_payroll
+#: code:addons/hr_payroll/hr_payroll.py:90
+#, python-format
+msgid "%s (copy)"
+msgstr ""
+
+#. module: hr_payroll
+#: help:hr.config.settings,module_hr_payroll_account:0
+msgid "Create journal entries from payslips"
+msgstr ""
+
+#. module: hr_payroll
+#: field:hr.payslip,paid:0
+msgid "Made Payment Order ? "
+msgstr ""
+
+#. module: hr_payroll
+#: report:contribution.register.lines:0
+msgid "PaySlip Lines by Contribution Register"
+msgstr ""
+
+#. module: hr_payroll
+#: view:hr.payslip:0
+#: field:hr.payslip,line_ids:0
+#: view:hr.payslip.line:0
+#: model:ir.actions.act_window,name:hr_payroll.act_contribution_reg_payslip_lines
+msgid "Payslip Lines"
+msgstr ""
+
+#. module: hr_payroll
+#: view:hr.payslip:0
+msgid "Miscellaneous"
+msgstr ""
+
+#. module: hr_payroll
+#: selection:hr.payslip,state:0
+msgid "Rejected"
+msgstr ""
+
+#. module: hr_payroll
+#: view:hr.payroll.structure:0
+#: field:hr.payroll.structure,rule_ids:0
+#: view:hr.salary.rule:0
+#: model:ir.actions.act_window,name:hr_payroll.action_salary_rule_form
+#: model:ir.ui.menu,name:hr_payroll.menu_action_hr_salary_rule_form
+msgid "Salary Rules"
+msgstr ""
+
+#. module: hr_payroll
+#: code:addons/hr_payroll/hr_payroll.py:341
+#, python-format
+msgid "Refund: "
+msgstr ""
+
+#. module: hr_payroll
+#: model:ir.model,name:hr_payroll.model_payslip_lines_contribution_register
+msgid "PaySlip Lines by Contribution Registers"
+msgstr ""
+
+#. module: hr_payroll
+#: view:hr.payslip:0
+#: selection:hr.payslip,state:0
+#: view:hr.payslip.run:0
+msgid "Done"
+msgstr ""
+
+#. module: hr_payroll
+#: field:hr.payslip.line,appears_on_payslip:0
+#: field:hr.salary.rule,appears_on_payslip:0
+msgid "Appears on Payslip"
+msgstr ""
+
+#. module: hr_payroll
+#: field:hr.payslip.line,amount_fix:0
+#: selection:hr.payslip.line,amount_select:0
+#: field:hr.salary.rule,amount_fix:0
+#: selection:hr.salary.rule,amount_select:0
+msgid "Fixed Amount"
+msgstr ""
+
+#. module: hr_payroll
+#: code:addons/hr_payroll/hr_payroll.py:370
+#, python-format
+msgid "Warning!"
+msgstr ""
+
+#. module: hr_payroll
+#: help:hr.payslip.line,active:0
+#: help:hr.salary.rule,active:0
+msgid ""
+"If the active field is set to false, it will allow you to hide the salary "
+"rule without removing it."
+msgstr ""
+
+#. module: hr_payroll
+#: field:hr.payslip,state:0
+#: field:hr.payslip.run,state:0
+msgid "Status"
+msgstr ""
+
+#. module: hr_payroll
+#: view:hr.payslip:0
+msgid "Worked Days & Inputs"
+msgstr ""
+
+#. module: hr_payroll
+#: field:hr.payslip,details_by_salary_rule_category:0
+msgid "Details by Salary Rule Category"
+msgstr ""
+
+#. module: hr_payroll
+#: model:ir.actions.act_window,name:hr_payroll.action_payslip_lines_contribution_register
+msgid "PaySlip Lines"
+msgstr ""
+
+#. module: hr_payroll
+#: help:hr.payslip.line,register_id:0
+#: help:hr.salary.rule,register_id:0
+msgid "Eventual third party involved in the salary payment of the employees."
+msgstr ""
+
+#. module: hr_payroll
+#: field:hr.payslip.worked_days,number_of_hours:0
+msgid "Number of Hours"
+msgstr ""
+
+#. module: hr_payroll
+#: view:hr.payslip:0
+msgid "PaySlip Batch"
+msgstr ""
+
+#. module: hr_payroll
+#: field:hr.payslip.line,condition_range_min:0
+#: field:hr.salary.rule,condition_range_min:0
+msgid "Minimum Range"
+msgstr ""
+
+#. module: hr_payroll
+#: field:hr.payslip.line,child_ids:0
+#: field:hr.salary.rule,child_ids:0
+msgid "Child Salary Rule"
+msgstr ""
+
+#. module: hr_payroll
+#: report:contribution.register.lines:0
+#: field:hr.payslip,date_to:0
+#: field:hr.payslip.run,date_end:0
+#: report:paylip.details:0
+#: report:payslip:0
+#: field:payslip.lines.contribution.register,date_to:0
+msgid "Date To"
+msgstr ""
+
+#. module: hr_payroll
+#: selection:hr.payslip.line,condition_select:0
+#: selection:hr.salary.rule,condition_select:0
+msgid "Range"
+msgstr ""
+
+#. module: hr_payroll
+#: model:ir.actions.act_window,name:hr_payroll.action_view_hr_payroll_structure_tree
+#: model:ir.ui.menu,name:hr_payroll.menu_hr_payroll_structure_tree
+msgid "Salary Structures Hierarchy"
+msgstr ""
+
+#. module: hr_payroll
+#: help:hr.employee,total_wage:0
+msgid "Sum of all current contract's wage of employee."
+msgstr ""
+
+#. module: hr_payroll
+#: view:hr.payslip:0
+msgid "Payslip"
+msgstr ""
+
+#. module: hr_payroll
+#: field:hr.payslip,credit_note:0
+#: field:hr.payslip.run,credit_note:0
+msgid "Credit Note"
+msgstr ""
+
+#. module: hr_payroll
+#: view:hr.payslip:0
+#: model:ir.actions.act_window,name:hr_payroll.act_payslip_lines
+msgid "Payslip Computation Details"
+msgstr ""
+
+#. module: hr_payroll
+#: help:hr.payslip.line,appears_on_payslip:0
+#: help:hr.salary.rule,appears_on_payslip:0
+msgid "Used to display the salary rule on payslip."
+msgstr ""
+
+#. module: hr_payroll
+#: model:ir.model,name:hr_payroll.model_hr_payslip_input
+msgid "Payslip Input"
+msgstr ""
+
+#. module: hr_payroll
+#: view:hr.salary.rule.category:0
+#: model:ir.actions.act_window,name:hr_payroll.action_hr_salary_rule_category
+#: model:ir.ui.menu,name:hr_payroll.menu_hr_salary_rule_category
+msgid "Salary Rule Categories"
+msgstr ""
+
+#. module: hr_payroll
+#: help:hr.payslip.input,contract_id:0
+#: help:hr.payslip.worked_days,contract_id:0
+msgid "The contract for which applied this input"
+msgstr ""
+
+#. module: hr_payroll
+#: view:hr.salary.rule:0
+msgid "Computation"
+msgstr ""
+
+#. module: hr_payroll
+#: code:addons/hr_payroll/hr_payroll.py:899
+#, python-format
+msgid "Wrong range condition defined for salary rule %s (%s)."
+msgstr ""
+
+#. module: hr_payroll
+#: help:hr.payslip.input,amount:0
+msgid ""
+"It is used in computation. For e.g. A rule for sales having 1% commission of "
+"basic salary for per product can defined in expression like result = "
+"inputs.SALEURO.amount * contract.wage*0.01."
+msgstr ""
+
+#. module: hr_payroll
+#: view:hr.payslip.line:0
+#: field:hr.payslip.line,amount_select:0
+#: field:hr.salary.rule,amount_select:0
+msgid "Amount Type"
+msgstr ""
+
+#. module: hr_payroll
+#: field:hr.payslip.line,category_id:0
+#: view:hr.salary.rule:0
+#: field:hr.salary.rule,category_id:0
+msgid "Category"
+msgstr ""
+
+#. module: hr_payroll
+#: view:hr.salary.rule:0
+msgid "Company Contribution"
+msgstr ""
+
+#. module: hr_payroll
+#: help:hr.payslip.run,credit_note:0
+msgid ""
+"If its checked, indicates that all payslips generated from here are refund "
+"payslips."
+msgstr ""
+
+#. module: hr_payroll
+#: code:addons/hr_payroll/hr_payroll.py:876
+#, python-format
+msgid "Wrong percentage base or quantity defined for salary rule %s (%s)."
+msgstr ""
+
+#. module: hr_payroll
+#: model:ir.actions.act_window,name:hr_payroll.action_view_hr_payroll_structure_list_form
+#: model:ir.ui.menu,name:hr_payroll.menu_hr_payroll_structure_view
+msgid "Salary Structures"
+msgstr ""
+
+#. module: hr_payroll
+#: view:hr.payslip.run:0
+msgid "Draft Payslip Batches"
+msgstr ""
+
+#. module: hr_payroll
+#: view:hr.payslip:0
+#: selection:hr.payslip,state:0
+#: view:hr.payslip.run:0
+#: selection:hr.payslip.run,state:0
+msgid "Draft"
+msgstr ""
+
+#. module: hr_payroll
+#: report:contribution.register.lines:0
+#: field:hr.payslip,date_from:0
+#: field:hr.payslip.run,date_start:0
+#: report:paylip.details:0
+#: report:payslip:0
+#: field:payslip.lines.contribution.register,date_from:0
+msgid "Date From"
+msgstr ""
+
+#. module: hr_payroll
+#: view:hr.payslip.run:0
+msgid "Done Payslip Batches"
+msgstr ""
+
+#. module: hr_payroll
+#: report:paylip.details:0
+msgid "Payslip Lines by Contribution Register:"
+msgstr ""
+
+#. module: hr_payroll
+#: view:hr.salary.rule:0
+msgid "Conditions"
+msgstr ""
+
+#. module: hr_payroll
+#: field:hr.payslip.line,amount_percentage:0
+#: selection:hr.payslip.line,amount_select:0
+#: field:hr.salary.rule,amount_percentage:0
+#: selection:hr.salary.rule,amount_select:0
+msgid "Percentage (%)"
+msgstr ""
+
+#. module: hr_payroll
+#: code:addons/hr_payroll/hr_payroll.py:871
+#, python-format
+msgid "Wrong quantity defined for salary rule %s (%s)."
+msgstr ""
+
+#. module: hr_payroll
+#: view:hr.payslip:0
+msgid "Worked Day"
+msgstr ""
+
+#. module: hr_payroll
+#: view:hr.payroll.structure:0
+msgid "Employee Function"
+msgstr ""
+
+#. module: hr_payroll
+#: model:ir.actions.report.xml,name:hr_payroll.payslip_report
+msgid "Employee PaySlip"
+msgstr ""
+
+#. module: hr_payroll
+#: field:hr.payslip.line,salary_rule_id:0
+msgid "Rule"
+msgstr ""
+
+#. module: hr_payroll
+#: model:ir.actions.report.xml,name:hr_payroll.payslip_details_report
+msgid "PaySlip Details"
+msgstr ""
+
+#. module: hr_payroll
+#: view:hr.payslip:0
+msgid "Compute Sheet"
+msgstr ""
+
+#. module: hr_payroll
+#: field:hr.payslip.line,active:0
+#: field:hr.salary.rule,active:0
+msgid "Active"
+msgstr ""
+
+#. module: hr_payroll
+#: view:hr.salary.rule:0
+msgid "Child Rules"
+msgstr ""
+
+#. module: hr_payroll
+#: help:hr.payslip.line,condition_range_min:0
+#: help:hr.salary.rule,condition_range_min:0
+msgid "The minimum amount, applied for this rule."
+msgstr ""
+
+#. module: hr_payroll
+#: selection:hr.payslip.line,condition_select:0
+#: selection:hr.salary.rule,condition_select:0
+msgid "Python Expression"
+msgstr ""
+
+#. module: hr_payroll
+#: report:paylip.details:0
+#: report:payslip:0
+msgid "Designation"
+msgstr ""
+
+#. module: hr_payroll
+#: view:hr.payslip:0
+msgid "Companies"
+msgstr ""
+
+#. module: hr_payroll
+#: report:paylip.details:0
+#: report:payslip:0
+msgid "Authorized Signature"
+msgstr ""
+
+#. module: hr_payroll
+#: field:hr.payslip,contract_id:0
+#: field:hr.payslip.input,contract_id:0
+#: field:hr.payslip.line,contract_id:0
+#: field:hr.payslip.worked_days,contract_id:0
+#: model:ir.model,name:hr_payroll.model_hr_contract
+msgid "Contract"
+msgstr ""
+
+#. module: hr_payroll
+#: code:addons/hr_payroll/wizard/hr_payroll_payslips_by_employees.py:52
+#, python-format
+msgid "You must select employee(s) to generate payslip(s)."
+msgstr ""
+
+#. module: hr_payroll
+#: report:paylip.details:0
+#: report:payslip:0
+msgid "Credit"
+msgstr ""
+
+#. module: hr_payroll
+#: field:hr.contract,schedule_pay:0
+msgid "Scheduled Pay"
+msgstr ""
+
+#. module: hr_payroll
+#: field:hr.payslip.line,condition_python:0
+#: field:hr.salary.rule,condition_python:0
+msgid "Python Condition"
+msgstr ""
+
+#. module: hr_payroll
+#: view:hr.contribution.register:0
+msgid "Contribution"
+msgstr ""
+
+#. module: hr_payroll
+#: code:addons/hr_payroll/hr_payroll.py:351
+#, python-format
+msgid "Refund Payslip"
+msgstr ""
+
+#. module: hr_payroll
+#: field:hr.rule.input,input_id:0
+#: model:ir.model,name:hr_payroll.model_hr_rule_input
+msgid "Salary Rule Input"
+msgstr ""
+
+#. module: hr_payroll
+#: field:hr.payslip.line,quantity:0
+#: field:hr.salary.rule,quantity:0
+msgid "Quantity"
+msgstr ""
+
+#. module: hr_payroll
+#: view:hr.payslip:0
+msgid "Refund"
+msgstr ""
+
+#. module: hr_payroll
+#: report:contribution.register.lines:0
+#: field:hr.payslip.input,code:0
+#: field:hr.payslip.line,code:0
+#: field:hr.payslip.worked_days,code:0
+#: field:hr.rule.input,code:0
+#: field:hr.salary.rule,code:0
+#: field:hr.salary.rule.category,code:0
+#: report:paylip.details:0
+#: report:payslip:0
+msgid "Code"
+msgstr ""
+
+#. module: hr_payroll
+#: field:hr.payslip.line,amount_python_compute:0
+#: selection:hr.payslip.line,amount_select:0
+#: field:hr.salary.rule,amount_python_compute:0
+#: selection:hr.salary.rule,amount_select:0
+msgid "Python Code"
+msgstr ""
+
+#. module: hr_payroll
+#: field:hr.payslip.input,sequence:0
+#: field:hr.payslip.line,sequence:0
+#: field:hr.payslip.worked_days,sequence:0
+#: field:hr.salary.rule,sequence:0
+msgid "Sequence"
+msgstr ""
+
+#. module: hr_payroll
+#: view:hr.payslip:0
+msgid "Period"
+msgstr ""
+
+#. module: hr_payroll
+#: view:hr.payslip.run:0
+msgid "Period from"
+msgstr ""
+
+#. module: hr_payroll
+#: view:hr.salary.rule:0
+msgid "General"
+msgstr ""
+
+#. module: hr_payroll
+#: code:addons/hr_payroll/hr_payroll.py:674
+#, python-format
+msgid "Salary Slip of %s for %s"
+msgstr ""
+
+#. module: hr_payroll
+#: model:ir.model,name:hr_payroll.model_hr_payslip_employees
+msgid "Generate payslips for all selected employees"
+msgstr ""
+
+#. module: hr_payroll
+#: field:hr.contract,struct_id:0
+#: view:hr.payroll.structure:0
+#: view:hr.payslip:0
+#: view:hr.payslip.line:0
+#: model:ir.model,name:hr_payroll.model_hr_payroll_structure
+msgid "Salary Structure"
+msgstr ""
+
+#. module: hr_payroll
+#: field:hr.contribution.register,register_line_ids:0
+msgid "Register Line"
+msgstr ""
+
+#. module: hr_payroll
+#: view:hr.payslip:0
+msgid "Cancel"
+msgstr ""
+
+#. module: hr_payroll
+#: view:hr.payslip.run:0
+#: selection:hr.payslip.run,state:0
+msgid "Close"
+msgstr ""
+
+#. module: hr_payroll
+#: help:hr.payslip,struct_id:0
+msgid ""
+"Defines the rules that have to be applied to this payslip, accordingly to "
+"the contract chosen. If you let empty the field contract, this field isn't "
+"mandatory anymore and thus the rules applied will be all the rules set on "
+"the structure of all contracts of the employee valid for the chosen period"
+msgstr ""
+
+#. module: hr_payroll
+#: field:hr.payroll.structure,children_ids:0
+#: field:hr.salary.rule.category,children_ids:0
+msgid "Children"
+msgstr ""
+
+#. module: hr_payroll
+#: help:hr.payslip,credit_note:0
+msgid "Indicates this payslip has a refund of another"
+msgstr ""
+
+#. module: hr_payroll
+#: selection:hr.contract,schedule_pay:0
+msgid "Bi-monthly"
+msgstr ""
+
+#. module: hr_payroll
+#: report:paylip.details:0
+msgid "Pay Slip Details"
+msgstr ""
+
+#. module: hr_payroll
+#: model:ir.actions.act_window,name:hr_payroll.action_view_hr_payslip_form
+#: model:ir.ui.menu,name:hr_payroll.menu_department_tree
+msgid "Employee Payslips"
+msgstr ""
+
+#. module: hr_payroll
+#: model:ir.model,name:hr_payroll.model_hr_config_settings
+msgid "hr.config.settings"
+msgstr ""
+
+#. module: hr_payroll
+#: view:hr.payslip.line:0
+#: field:hr.payslip.line,register_id:0
+#: field:hr.salary.rule,register_id:0
+#: model:ir.model,name:hr_payroll.model_hr_contribution_register
+msgid "Contribution Register"
+msgstr ""
+
+#. module: hr_payroll
+#: view:payslip.lines.contribution.register:0
+msgid "Print"
+msgstr ""
+
+#. module: hr_payroll
+#: view:hr.payslip.line:0
+msgid "Calculations"
+msgstr ""
+
+#. module: hr_payroll
+#: view:hr.payslip:0
+msgid "Worked Days"
+msgstr ""
+
+#. module: hr_payroll
+#: view:hr.payslip:0
+msgid "Search Payslips"
+msgstr ""
+
+#. module: hr_payroll
+#: view:hr.payslip.run:0
+#: model:ir.actions.act_window,name:hr_payroll.action_hr_payslip_run_tree
+#: model:ir.ui.menu,name:hr_payroll.menu_hr_payslip_run
+msgid "Payslips Batches"
+msgstr ""
+
+#. module: hr_payroll
+#: view:hr.contribution.register:0
+#: field:hr.contribution.register,note:0
+#: field:hr.payroll.structure,note:0
+#: field:hr.payslip,name:0
+#: field:hr.payslip,note:0
+#: field:hr.payslip.input,name:0
+#: field:hr.payslip.line,note:0
+#: field:hr.payslip.worked_days,name:0
+#: field:hr.rule.input,name:0
+#: view:hr.salary.rule:0
+#: field:hr.salary.rule,note:0
+#: field:hr.salary.rule.category,note:0
+msgid "Description"
+msgstr ""
+
+#. module: hr_payroll
+#: field:hr.employee,total_wage:0
+msgid "Total Basic Salary"
+msgstr ""
+
+#. module: hr_payroll
+#: view:hr.contribution.register:0
+#: model:ir.actions.act_window,name:hr_payroll.action_contribution_register_form
+#: model:ir.ui.menu,name:hr_payroll.menu_action_hr_contribution_register_form
+msgid "Contribution Registers"
+msgstr ""
+
+#. module: hr_payroll
+#: model:ir.ui.menu,name:hr_payroll.menu_hr_payroll_reporting
+#: model:ir.ui.menu,name:hr_payroll.menu_hr_root_payroll
+#: model:ir.ui.menu,name:hr_payroll.payroll_configure
+msgid "Payroll"
+msgstr ""
+
+#. module: hr_payroll
+#: model:ir.actions.report.xml,name:hr_payroll.contribution_register
+msgid "PaySlip Lines By Conribution Register"
+msgstr ""
+
+#. module: hr_payroll
+#: code:addons/hr_payroll/hr_payroll.py:370
+#, python-format
+msgid "You cannot delete a payslip which is not draft or cancelled!"
+msgstr ""
+
+#. module: hr_payroll
+#: report:paylip.details:0
+#: report:payslip:0
+msgid "Address"
+msgstr ""
+
+#. module: hr_payroll
+#: field:hr.payslip,worked_days_line_ids:0
+#: model:ir.model,name:hr_payroll.model_hr_payslip_worked_days
+msgid "Payslip Worked Days"
+msgstr ""
+
+#. module: hr_payroll
+#: view:hr.salary.rule.category:0
+msgid "Salary Categories"
+msgstr ""
+
+#. module: hr_payroll
+#: report:contribution.register.lines:0
+#: field:hr.contribution.register,name:0
+#: field:hr.payroll.structure,name:0
+#: field:hr.payslip.line,name:0
+#: field:hr.payslip.run,name:0
+#: field:hr.salary.rule,name:0
+#: field:hr.salary.rule.category,name:0
+#: report:paylip.details:0
+#: report:payslip:0
+msgid "Name"
+msgstr ""
+
+#. module: hr_payroll
+#: help:hr.payslip.line,amount_percentage:0
+#: help:hr.salary.rule,amount_percentage:0
+msgid "For example, enter 50.0 to apply a percentage of 50%"
+msgstr ""
+
+#. module: hr_payroll
+#: view:hr.payroll.structure:0
+msgid "Payroll Structures"
+msgstr ""
+
+#. module: hr_payroll
+#: view:hr.payslip:0
+#: view:hr.payslip.employees:0
+#: field:hr.payslip.employees,employee_ids:0
+#: view:hr.payslip.line:0
+msgid "Employees"
+msgstr ""
+
+#. module: hr_payroll
+#: report:paylip.details:0
+#: report:payslip:0
+msgid "Bank Account"
+msgstr ""
+
+#. module: hr_payroll
+#: help:hr.payslip.line,sequence:0
+#: help:hr.salary.rule,sequence:0
+msgid "Use to arrange calculation sequence"
+msgstr ""
+
+#. module: hr_payroll
+#: help:hr.payslip,state:0
+msgid ""
+"* When the payslip is created the status is 'Draft'. \n"
+"* If the payslip is under verification, the status is 'Waiting'. "
+"\n"
+"* If the payslip is confirmed then status is set to 'Done'. \n"
+"* When user cancel payslip the status is 'Rejected'."
+msgstr ""
+
+#. module: hr_payroll
+#: help:hr.payslip.line,condition_range:0
+#: help:hr.salary.rule,condition_range:0
+msgid ""
+"This will be used to compute the % fields values; in general it is on basic, "
+"but you can also use categories code fields in lowercase as a variable names "
+"(hra, ma, lta, etc.) and the variable basic."
+msgstr ""
+
+#. module: hr_payroll
+#: selection:hr.contract,schedule_pay:0
+msgid "Annually"
+msgstr ""
+
+#. module: hr_payroll
+#: field:hr.payslip,input_line_ids:0
+msgid "Payslip Inputs"
+msgstr ""
+
+#. module: hr_payroll
+#: view:hr.payslip:0
+msgid "Other Inputs"
+msgstr ""
+
+#. module: hr_payroll
+#: model:ir.actions.act_window,name:hr_payroll.action_hr_salary_rule_category_tree_view
+#: model:ir.ui.menu,name:hr_payroll.menu_hr_salary_rule_category_tree_view
+msgid "Salary Rule Categories Hierarchy"
+msgstr ""
+
+#. module: hr_payroll
+#: code:addons/hr_payroll/hr_payroll.py:882
+#, python-format
+msgid "Wrong python code defined for salary rule %s (%s)."
+msgstr ""
+
+#. module: hr_payroll
+#: report:contribution.register.lines:0
+#: field:hr.payslip.line,total:0
+#: report:paylip.details:0
+#: report:payslip:0
+msgid "Total"
+msgstr ""
+
+#. module: hr_payroll
+#: view:hr.payslip:0
+msgid "Salary Computation"
+msgstr ""
+
+#. module: hr_payroll
+#: view:hr.payslip:0
+msgid "Details By Salary Rule Category"
+msgstr ""
+
+#. module: hr_payroll
+#: help:hr.payslip.input,code:0
+#: help:hr.payslip.worked_days,code:0
+#: help:hr.rule.input,code:0
+msgid "The code that can be used in the salary rules"
+msgstr ""
+
+#. module: hr_payroll
+#: code:addons/hr_payroll/hr_payroll.py:905
+#, python-format
+msgid "Wrong python condition defined for salary rule %s (%s)."
+msgstr ""
+
+#. module: hr_payroll
+#: view:hr.payslip.run:0
+#: model:ir.actions.act_window,name:hr_payroll.action_hr_payslip_by_employees
+msgid "Generate Payslips"
+msgstr ""
+
+#. module: hr_payroll
+#: view:hr.payslip.line:0
+msgid "Search Payslip Lines"
+msgstr ""
+
+#. module: hr_payroll
+#: selection:hr.contract,schedule_pay:0
+msgid "Bi-weekly"
+msgstr ""
+
+#. module: hr_payroll
+#: selection:hr.payslip.line,condition_select:0
+#: selection:hr.salary.rule,condition_select:0
+msgid "Always True"
+msgstr ""
+
+#. module: hr_payroll
+#: report:contribution.register.lines:0
+msgid "PaySlip Name"
+msgstr ""
+
+#. module: hr_payroll
+#: view:hr.payslip:0
+msgid "Accounting"
+msgstr ""
+
+#. module: hr_payroll
+#: field:hr.payslip.line,condition_range:0
+#: field:hr.salary.rule,condition_range:0
+msgid "Range Based on"
+msgstr ""
diff --git a/addons/hr_recruitment/report/hr_recruitment_report_view.xml b/addons/hr_recruitment/report/hr_recruitment_report_view.xml
index c214b2efa75..4d15481070f 100644
--- a/addons/hr_recruitment/report/hr_recruitment_report_view.xml
+++ b/addons/hr_recruitment/report/hr_recruitment_report_view.xml
@@ -8,7 +8,6 @@
-
diff --git a/addons/hr_timesheet_sheet/hr_timesheet_sheet.py b/addons/hr_timesheet_sheet/hr_timesheet_sheet.py
index e8349f68a58..2a79669d61c 100644
--- a/addons/hr_timesheet_sheet/hr_timesheet_sheet.py
+++ b/addons/hr_timesheet_sheet/hr_timesheet_sheet.py
@@ -65,7 +65,7 @@ class hr_timesheet_sheet(osv.osv):
def create(self, cr, uid, vals, *args, **argv):
if 'employee_id' in vals:
if not self.pool.get('hr.employee').browse(cr, uid, vals['employee_id']).user_id:
- raise osv.except_osv(_('Error!'), _('In order to create a timesheet for this employee, you must assign it to a user.'))
+ raise osv.except_osv(_('Error!'), _('In order to create a timesheet for this employee, you must link him/her to a user.'))
if not self.pool.get('hr.employee').browse(cr, uid, vals['employee_id']).product_id:
raise osv.except_osv(_('Error!'), _('In order to create a timesheet for this employee, you must link the employee to a product, like \'Consultant\'.'))
if not self.pool.get('hr.employee').browse(cr, uid, vals['employee_id']).journal_id:
@@ -76,7 +76,7 @@ class hr_timesheet_sheet(osv.osv):
if 'employee_id' in vals:
new_user_id = self.pool.get('hr.employee').browse(cr, uid, vals['employee_id']).user_id.id or False
if not new_user_id:
- raise osv.except_osv(_('Error!'), _('In order to create a timesheet for this employee, you must assign it to a user.'))
+ raise osv.except_osv(_('Error!'), _('In order to create a timesheet for this employee, you must link him/her to a user.'))
if not self._sheet_date(cr, uid, ids, forced_user_id=new_user_id):
raise osv.except_osv(_('Error!'), _('You cannot have 2 timesheets that overlap!\nYou should use the menu \'My Timesheet\' to avoid this problem.'))
if not self.pool.get('hr.employee').browse(cr, uid, vals['employee_id']).product_id:
diff --git a/addons/l10n_fr_rib/bank_view.xml b/addons/l10n_fr_rib/bank_view.xml
index 414ad51954a..4bc697b6173 100644
--- a/addons/l10n_fr_rib/bank_view.xml
+++ b/addons/l10n_fr_rib/bank_view.xml
@@ -21,12 +21,12 @@
res.partner.bank
-
-
-
+
+
+
-
-
+
+
diff --git a/addons/lunch/lunch_view.xml b/addons/lunch/lunch_view.xml
index c5fa52afe29..cb7ad61e928 100644
--- a/addons/lunch/lunch_view.xml
+++ b/addons/lunch/lunch_view.xml
@@ -427,10 +427,14 @@
-
-
-
-
+
+
+
+
+
+
+
+
@@ -461,7 +465,7 @@
-
+
diff --git a/addons/mail/mail_followers.py b/addons/mail/mail_followers.py
index 86246bc2745..33f5f1f8a83 100644
--- a/addons/mail/mail_followers.py
+++ b/addons/mail/mail_followers.py
@@ -109,8 +109,7 @@ class mail_notification(osv.Model):
Administrator
diff --git a/addons/project_gtd/__init__.py b/addons/project_gtd/__init__.py
deleted file mode 100644
index cb17064b6b8..00000000000
--- a/addons/project_gtd/__init__.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-# OpenERP, Open Source Management Solution
-# Copyright (C) 2004-2010 Tiny SPRL ().
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see .
-#
-##############################################################################
-import project_gtd
-import wizard
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
-
diff --git a/addons/project_gtd/__openerp__.py b/addons/project_gtd/__openerp__.py
deleted file mode 100644
index ee14df38101..00000000000
--- a/addons/project_gtd/__openerp__.py
+++ /dev/null
@@ -1,56 +0,0 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-# OpenERP, Open Source Management Solution
-# Copyright (C) 2004-2010 Tiny SPRL ().
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see .
-#
-##############################################################################
-
-
-{
- 'name': 'Todo Lists',
- 'version': '1.0',
- 'category': 'Project Management',
- 'sequence': 100,
- 'summary': 'Personal Tasks, Contexts, Timeboxes',
- 'description': """
-Implement concepts of the "Getting Things Done" methodology
-===========================================================
-
-This module implements a simple personal to-do list based on tasks. It adds an editable list of tasks simplified to the minimum required fields in the project application.
-
-The to-do list is based on the GTD methodology. This world-wide used methodology is used for personal time management improvement.
-
-Getting Things Done (commonly abbreviated as GTD) is an action management method created by David Allen, and described in a book of the same name.
-
-GTD rests on the principle that a person needs to move tasks out of the mind by recording them externally. That way, the mind is freed from the job of remembering everything that needs to be done, and can concentrate on actually performing those tasks.
- """,
- 'author': 'OpenERP SA',
- 'images': ['images/project_gtd.jpeg'],
- 'depends': ['project'],
- 'data': [
- 'project_gtd_data.xml',
- 'project_gtd_view.xml',
- 'security/ir.model.access.csv',
- 'wizard/project_gtd_empty_view.xml',
- 'wizard/project_gtd_fill_view.xml',
- ],
- 'demo': ['project_gtd_demo.xml'],
- 'test':['test/task_timebox.yml'],
- 'installable': True,
- 'auto_install': False,
-}
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/project_gtd/project_gtd.py b/addons/project_gtd/project_gtd.py
deleted file mode 100644
index 47569e863aa..00000000000
--- a/addons/project_gtd/project_gtd.py
+++ /dev/null
@@ -1,122 +0,0 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-# OpenERP, Open Source Management Solution
-# Copyright (C) 2004-2010 Tiny SPRL ().
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see .
-#
-##############################################################################
-
-import sys
-
-from openerp.osv import fields, osv
-from openerp import tools
-from openerp.tools.translate import _
-
-class project_gtd_context(osv.osv):
- _name = "project.gtd.context"
- _description = "Context"
- _columns = {
- 'name': fields.char('Context', size=64, required=True, select=1, translate=1),
- 'sequence': fields.integer('Sequence', help="Gives the sequence order when displaying a list of contexts."),
- }
- _defaults = {
- 'sequence': 1
- }
- _order = "sequence, name"
-
-
-
-class project_gtd_timebox(osv.osv):
- _name = "project.gtd.timebox"
- _order = "sequence"
- _columns = {
- 'name': fields.char('Timebox', size=64, required=True, select=1, translate=1),
- 'sequence': fields.integer('Sequence', help="Gives the sequence order when displaying a list of timebox."),
- 'icon': fields.selection(tools.icons, 'Icon', size=64),
- }
-
-
-class project_task(osv.osv):
- _inherit = "project.task"
- _columns = {
- 'timebox_id': fields.many2one('project.gtd.timebox', "Timebox",help="Time-laps during which task has to be treated"),
- 'context_id': fields.many2one('project.gtd.context', "Context",help="The context place where user has to treat task"),
- }
-
- def copy_data(self, cr, uid, id, default=None, context=None):
- if context is None:
- context = {}
- if not default:
- default = {}
- default['timebox_id'] = False
- default['context_id'] = False
- return super(project_task,self).copy_data(cr, uid, id, default, context)
-
- def _get_context(self, cr, uid, context=None):
- ids = self.pool.get('project.gtd.context').search(cr, uid, [], context=context)
- return ids and ids[0] or False
-
- _defaults = {
- 'context_id': _get_context
- }
- def next_timebox(self, cr, uid, ids, *args):
- timebox_obj = self.pool.get('project.gtd.timebox')
- timebox_ids = timebox_obj.search(cr,uid,[])
- if not timebox_ids: return True
- for task in self.browse(cr,uid,ids):
- timebox = task.timebox_id.id
- if not timebox:
- self.write(cr, uid, task.id, {'timebox_id': timebox_ids[0]})
- elif timebox_ids.index(timebox) != len(timebox_ids)-1:
- index = timebox_ids.index(timebox)
- self.write(cr, uid, task.id, {'timebox_id': timebox_ids[index+1]})
- return True
-
- def prev_timebox(self, cr, uid, ids, *args):
- timebox_obj = self.pool.get('project.gtd.timebox')
- timebox_ids = timebox_obj.search(cr,uid,[])
- for task in self.browse(cr,uid,ids):
- timebox = task.timebox_id.id
- if timebox:
- if timebox_ids.index(timebox):
- index = timebox_ids.index(timebox)
- self.write(cr, uid, task.id, {'timebox_id': timebox_ids[index - 1]})
- else:
- self.write(cr, uid, task.id, {'timebox_id': False})
- return True
-
- def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False, submenu=False):
- if not context: context = {}
- res = super(project_task,self).fields_view_get(cr, uid, view_id, view_type, context, toolbar=toolbar, submenu=submenu)
- search_extended = False
- timebox_obj = self.pool.get('project.gtd.timebox')
- if (res['type'] == 'search') and context.get('gtd', False):
- tt = timebox_obj.browse(cr, uid, timebox_obj.search(cr,uid,[]), context=context)
- search_extended =''
- for time in tt:
- if time.icon:
- icon = time.icon
- else :
- icon=""
- search_extended += '''\n'''
- search_extended +=''''''
-
- res['arch'] = tools.ustr(res['arch']).replace('', search_extended)
-
- return res
-
-
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/project_gtd/project_gtd_data.xml b/addons/project_gtd/project_gtd_data.xml
deleted file mode 100644
index 9d8c99f23ff..00000000000
--- a/addons/project_gtd/project_gtd_data.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-
-
-
-
- Office
- 0
-
-
- Travel
- 2
-
-
-
- Today
- terp-go-today
-
-
- This Week
- terp-go-week
-
-
- Long Term
- terp-project
-
-
-
-
-
-
- mail.group
-
- notification
-
- Todo Lists application installed!
- Add todo items on project tasks, to help you organize your work.
-This application supports the Getting Things Done (GTD) methodology, based on David Allen's book.
-
-
-
-
- Contexts
- project.gtd.context
- Contexts are defined in the "Getting Things Done" methodology. It allows you to categorize your tasks according to the context in which they have to be done: at the office, at home, when I take my car, etc.
-
-
-
-
-
- project.gtd.timebox.tree
- project.gtd.timebox
-
-
-
-
-
-
-
-
-
-
- project.gtd.timebox.form
- project.gtd.timebox
-
-
-
-
-
-
-
-
-
-
-
-
- Timeboxes
- project.gtd.timebox
- form
- tree,form
-
- Timeboxes are defined in the "Getting Things Done" methodology. A timebox defines a period of time in order to categorize your tasks: today, this week, this month, long term.
-
-
-
-
-
- project.task.tree.timebox
- project.task
-
-
-
-
-
-
-
-
-
-
- project.task.form.timebox
- project.task
-
-
-
-
-
-
-
-
-
-
- project.task.gtd.search
- project.task
- 50
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- My Tasks
- project.task
-
- {'set_editable':True,'set_visible':True,'gtd':True,'user_invisible':True, "search_default_open": 1}
- [('user_id','=',uid)]
- form
- kanban,tree,form,calendar,gantt,graph
-
-
-
-
-
-
diff --git a/addons/project_gtd/security/ir.model.access.csv b/addons/project_gtd/security/ir.model.access.csv
deleted file mode 100644
index d85ac8a5d0c..00000000000
--- a/addons/project_gtd/security/ir.model.access.csv
+++ /dev/null
@@ -1,5 +0,0 @@
-id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
-access_project_gtd_context_user,project.gtd.context project user,model_project_gtd_context,project.group_project_user,1,0,0,0
-access_project_gtd_timebox_user,project.gtd.timebox project user,model_project_gtd_timebox,project.group_project_user,1,0,0,0
-access_project_gtd_context_manager,project.gtd.context project manager,model_project_gtd_context,project.group_project_manager,1,1,1,1
-access_project_gtd_timebox_manager,project.gtd.timebox project manager,model_project_gtd_timebox,project.group_project_manager,1,1,1,1
diff --git a/addons/project_gtd/static/description/icon.png b/addons/project_gtd/static/description/icon.png
deleted file mode 100644
index 2f888a90a60..00000000000
Binary files a/addons/project_gtd/static/description/icon.png and /dev/null differ
diff --git a/addons/project_gtd/test/task_timebox.yml b/addons/project_gtd/test/task_timebox.yml
deleted file mode 100644
index 8efa7219b21..00000000000
--- a/addons/project_gtd/test/task_timebox.yml
+++ /dev/null
@@ -1,45 +0,0 @@
--
- In order to test the process of Timebox in Project Management module,
- I set my task from Daily to Weekly Timebox through Plannify Timebox
--
- !record {model: project.timebox.fill.plan, id: plan_id}:
- task_ids: [project.project_task_10]
- timebox_id: timebox_daily
- timebox_to_id: timebox_weekly
--
- I set the task from Daily Timebox to Weekly Timebox
--
- !python {model: project.timebox.fill.plan}: |
- self.process(cr, uid, [ref("plan_id")])
--
- I check task is set to Weekly Timebox
--
- !assert {model: project.task, id: project.project_task_10, string: Task should be set to weekly timebox}:
- - timebox_id.id == ref("timebox_weekly")
--
- I Empty the Weekly Timebox
--
- !python {model: project.timebox.empty}: |
- self._empty(cr, uid, {"active_model": "project.gtd.timebox",
- "active_ids":[ref("timebox_weekly")],
- "active_id": ref("timebox_weekly"),
- })
--
- I check task 'Develop Module in Sale Management' is no more in Weekly Timebox
--
- !assert {model: project.task, id: project.project_task_10 , string: Task is not in Weekly Timebox }:
- - timebox_id.id != ref("timebox_weekly")
--
- I set Previous Timebox on task
--
- !python {model: project.task}: |
- previous_timebox = self.prev_timebox(cr, uid, [ref("project.project_task_10")],
- {'active_ids': [ref("project_gtd.menu_open_gtd_timebox_tree")],})
- assert previous_timebox == True, "I set Previous Timebox on task"
--
- I set Next Timebox on task
--
- !python {model: project.task}: |
- next_timebox = self.next_timebox(cr, uid, [ref("project.project_task_10")],
- {'active_ids': [ref("project_gtd.menu_open_gtd_timebox_tree")],})
- assert next_timebox == True, "I set Next Timebox on task"
\ No newline at end of file
diff --git a/addons/project_gtd/wizard/__init__.py b/addons/project_gtd/wizard/__init__.py
deleted file mode 100644
index aa2bbc22c45..00000000000
--- a/addons/project_gtd/wizard/__init__.py
+++ /dev/null
@@ -1,26 +0,0 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-# OpenERP, Open Source Management Solution
-# Copyright (C) 2004-2010 Tiny SPRL ().
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see .
-#
-##############################################################################
-
-import project_gtd_empty
-import project_gtd_fill
-
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
-
diff --git a/addons/project_gtd/wizard/project_gtd_empty.py b/addons/project_gtd/wizard/project_gtd_empty.py
deleted file mode 100644
index b477c12567a..00000000000
--- a/addons/project_gtd/wizard/project_gtd_empty.py
+++ /dev/null
@@ -1,66 +0,0 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-# OpenERP, Open Source Management Solution
-# Copyright (C) 2004-2010 Tiny SPRL ().
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see .
-#
-##############################################################################
-
-from openerp.osv import fields, osv
-from openerp.tools.translate import _
-
-class project_timebox_empty(osv.osv_memory):
-
- _name = 'project.timebox.empty'
- _description = 'Project Timebox Empty'
- _columns = {
- 'name': fields.char('Name', size=32)
- }
-
- def view_init(self, cr, uid, fields_list, context=None):
- if context is None:
- context = {}
- self._empty(cr, uid, context=context)
- pass
-
- def _empty(self, cr, uid, context=None):
- close = []
- up = []
- obj_tb = self.pool.get('project.gtd.timebox')
- obj_task = self.pool.get('project.task')
-
- if context is None:
- context = {}
- if not 'active_id' in context:
- return {}
-
- ids = obj_tb.search(cr, uid, [], context=context)
- if not len(ids):
- raise osv.except_osv(_('Error!'), _('No timebox child of this one!'))
- tids = obj_task.search(cr, uid, [('timebox_id', '=', context['active_id'])])
- for task in obj_task.browse(cr, uid, tids, context):
- if (task.stage_id and task.stage_id.fold) or (task.user_id.id <> uid):
- close.append(task.id)
- else:
- up.append(task.id)
- if up:
- obj_task.write(cr, uid, up, {'timebox_id':ids[0]})
- if close:
- obj_task.write(cr, uid, close, {'timebox_id':False})
- return {}
-
-
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/project_gtd/wizard/project_gtd_empty_view.xml b/addons/project_gtd/wizard/project_gtd_empty_view.xml
deleted file mode 100644
index 053c0013e73..00000000000
--- a/addons/project_gtd/wizard/project_gtd_empty_view.xml
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
-
- Empty Timebox
- project.timebox.empty
-
-
-
-
-
-
-
-
- Empty Timebox
- ir.actions.act_window
- project.timebox.empty
- form
- form
-
- {'record_id' : active_id}
- new
-
-
-
-
- Empty Timebox
- client_action_multi
-
- action
- project.gtd.timebox
-
-
-
-
-
diff --git a/addons/project_gtd/wizard/project_gtd_fill.py b/addons/project_gtd/wizard/project_gtd_fill.py
deleted file mode 100644
index 121bd7efdac..00000000000
--- a/addons/project_gtd/wizard/project_gtd_fill.py
+++ /dev/null
@@ -1,60 +0,0 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-# OpenERP, Open Source Management Solution
-# Copyright (C) 2004-2010 Tiny SPRL ().
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see .
-#
-##############################################################################
-
-from openerp.osv import fields, osv
-
-class project_timebox_fill(osv.osv_memory):
-
- _name = 'project.timebox.fill.plan'
- _description = 'Project Timebox Fill'
- _columns = {
- 'timebox_id': fields.many2one('project.gtd.timebox', 'Get from Timebox', required=True),
- 'timebox_to_id': fields.many2one('project.gtd.timebox', 'Set to Timebox', required=True),
- 'task_ids': fields.many2many('project.task', 'project_task_rel', 'task_id', 'fill_id', 'Tasks selection')
- }
-
- def _get_from_tb(self, cr, uid, context=None):
- ids = self.pool.get('project.gtd.timebox').search(cr, uid, [], context=context)
- return ids and ids[0] or False
-
- def _get_to_tb(self, cr, uid, context=None):
- if context is None:
- context = {}
- if 'active_id' in context:
- return context['active_id']
- return False
-
- _defaults = {
- 'timebox_id': _get_from_tb,
- 'timebox_to_id': _get_to_tb,
- }
-
- def process(self, cr, uid, ids, context=None):
- if not ids:
- return {}
- data = self.read(cr, uid, ids, [], context=context)
- if not data[0]['task_ids']:
- return {}
- self.pool.get('project.task').write(cr, uid, data[0]['task_ids'], {'timebox_id':data[0]['timebox_to_id'][0]})
- return {'type': 'ir.actions.act_window_close'}
-
-
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/project_gtd/wizard/project_gtd_fill_view.xml b/addons/project_gtd/wizard/project_gtd_fill_view.xml
deleted file mode 100644
index 626dfb699b8..00000000000
--- a/addons/project_gtd/wizard/project_gtd_fill_view.xml
+++ /dev/null
@@ -1,46 +0,0 @@
-
-
-
-
-
- Plannify Timebox
- project.timebox.fill.plan
-
-
-
-
-
-
-
-
-
-
-
-
-
- Plannify Timebox
- ir.actions.act_window
- project.timebox.fill.plan
- form
- form
-
- {'record_id' : active_id}
- new
-
-
-
-
- Plannify Timebox
- client_action_multi
-
- action
- project.gtd.timebox
-
-
-
-
-
diff --git a/addons/project_long_term/__openerp__.py b/addons/project_long_term/__openerp__.py
deleted file mode 100644
index 3a3307d2898..00000000000
--- a/addons/project_long_term/__openerp__.py
+++ /dev/null
@@ -1,63 +0,0 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-# OpenERP, Open Source Management Solution
-# Copyright (C) 2004-2009 Tiny SPRL ().
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see .
-#
-##############################################################################
-
-{
- 'name': 'Long Term Projects',
- 'version': '1.1',
- 'author': 'OpenERP SA',
- 'website': 'http://www.openerp.com',
- 'category': 'Project Management',
- 'images': ['images/project_phase_form.jpeg','images/project_phases.jpeg', 'images/resources_allocation.jpeg'],
- 'depends': ['project'],
- 'description': """
-Long Term Project management module that tracks planning, scheduling, resources allocation.
-===========================================================================================
-
-Features:
----------
- * Manage Big project
- * Define various Phases of Project
- * Compute Phase Scheduling: Compute start date and end date of the phases
- which are in draft, open and pending state of the project given. If no
- project given then all the draft, open and pending state phases will be taken.
- * Compute Task Scheduling: This works same as the scheduler button on
- project.phase. It takes the project as argument and computes all the open,
- draft and pending tasks.
- * Schedule Tasks: All the tasks which are in draft, pending and open state
- are scheduled with taking the phase's start date.
- """,
- 'demo': ['project_long_term_demo.xml'],
- 'test': [
- 'test/phase_process.yml',
- 'test/task_process.yml',
- ],
- 'data': [
- 'security/ir.model.access.csv',
- 'project_long_term_view.xml',
- 'project_long_term_workflow.xml',
- 'wizard/project_compute_phases_view.xml',
- 'wizard/project_compute_tasks_view.xml',
- ],
- 'installable': True,
- 'auto_install': False,
-}
-
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/project_long_term/project_long_term.py b/addons/project_long_term/project_long_term.py
deleted file mode 100644
index 29e94591094..00000000000
--- a/addons/project_long_term/project_long_term.py
+++ /dev/null
@@ -1,296 +0,0 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-# OpenERP, Open Source Management Solution
-# Copyright (C) 2004-2009 Tiny SPRL ().
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see .
-#
-##############################################################################
-
-from datetime import datetime
-from openerp.tools.translate import _
-from openerp.osv import fields, osv
-from openerp.addons.resource.faces import task as Task
-
-class project_phase(osv.osv):
- _name = "project.phase"
- _description = "Project Phase"
-
- def _check_recursion(self, cr, uid, ids, context=None):
- if context is None:
- context = {}
-
- data_phase = self.browse(cr, uid, ids[0], context=context)
- prev_ids = data_phase.previous_phase_ids
- next_ids = data_phase.next_phase_ids
- # it should neither be in prev_ids nor in next_ids
- if (data_phase in prev_ids) or (data_phase in next_ids):
- return False
- ids = [id for id in prev_ids if id in next_ids]
- # both prev_ids and next_ids must be unique
- if ids:
- return False
- # unrelated project
- prev_ids = [rec.id for rec in prev_ids]
- next_ids = [rec.id for rec in next_ids]
- # iter prev_ids
- while prev_ids:
- cr.execute('SELECT distinct prv_phase_id FROM project_phase_rel WHERE next_phase_id IN %s', (tuple(prev_ids),))
- prv_phase_ids = filter(None, map(lambda x: x[0], cr.fetchall()))
- if data_phase.id in prv_phase_ids:
- return False
- ids = [id for id in prv_phase_ids if id in next_ids]
- if ids:
- return False
- prev_ids = prv_phase_ids
- # iter next_ids
- while next_ids:
- cr.execute('SELECT distinct next_phase_id FROM project_phase_rel WHERE prv_phase_id IN %s', (tuple(next_ids),))
- next_phase_ids = filter(None, map(lambda x: x[0], cr.fetchall()))
- if data_phase.id in next_phase_ids:
- return False
- ids = [id for id in next_phase_ids if id in prev_ids]
- if ids:
- return False
- next_ids = next_phase_ids
- return True
-
- def _check_dates(self, cr, uid, ids, context=None):
- for phase in self.read(cr, uid, ids, ['date_start', 'date_end'], context=context):
- if phase['date_start'] and phase['date_end'] and phase['date_start'] > phase['date_end']:
- return False
- return True
-
- def _compute_progress(self, cr, uid, ids, field_name, arg, context=None):
- res = {}
- if not ids:
- return res
- for phase in self.browse(cr, uid, ids, context=context):
- if phase.state=='done':
- res[phase.id] = 100.0
- continue
- elif phase.state=="cancelled":
- res[phase.id] = 0.0
- continue
- elif not phase.task_ids:
- res[phase.id] = 0.0
- continue
-
- tot = done = 0.0
- for task in phase.task_ids:
- tot += task.total_hours
- done += min(task.effective_hours, task.total_hours)
-
- if not tot:
- res[phase.id] = 0.0
- else:
- res[phase.id] = round(100.0 * done / tot, 2)
- return res
-
- _columns = {
- 'name': fields.char("Name", size=64, required=True),
- 'date_start': fields.datetime('Start Date', select=True, help="It's computed by the scheduler according the project date or the end date of the previous phase.", states={'done':[('readonly',True)], 'cancelled':[('readonly',True)]}),
- 'date_end': fields.datetime('End Date', help=" It's computed by the scheduler according to the start date and the duration.", states={'done':[('readonly',True)], 'cancelled':[('readonly',True)]}),
- 'constraint_date_start': fields.datetime('Minimum Start Date', help='force the phase to start after this date', states={'done':[('readonly',True)], 'cancelled':[('readonly',True)]}),
- 'constraint_date_end': fields.datetime('Deadline', help='force the phase to finish before this date', states={'done':[('readonly',True)], 'cancelled':[('readonly',True)]}),
- 'project_id': fields.many2one('project.project', 'Project', required=True, select=True),
- 'next_phase_ids': fields.many2many('project.phase', 'project_phase_rel', 'prv_phase_id', 'next_phase_id', 'Next Phases', states={'cancelled':[('readonly',True)]}),
- 'previous_phase_ids': fields.many2many('project.phase', 'project_phase_rel', 'next_phase_id', 'prv_phase_id', 'Previous Phases', states={'cancelled':[('readonly',True)]}),
- 'sequence': fields.integer('Sequence', select=True, help="Gives the sequence order when displaying a list of phases."),
- 'duration': fields.float('Duration', required=True, help="By default in days", states={'done':[('readonly',True)], 'cancelled':[('readonly',True)]}),
- 'product_uom': fields.many2one('product.uom', 'Duration Unit of Measure', required=True, help="Unit of Measure (Unit of Measure) is the unit of measurement for Duration", states={'done':[('readonly',True)], 'cancelled':[('readonly',True)]}),
- 'task_ids': fields.one2many('project.task', 'phase_id', "Project Tasks", states={'done':[('readonly',True)], 'cancelled':[('readonly',True)]}),
- 'user_force_ids': fields.many2many('res.users', string='Force Assigned Users'),
- 'user_ids': fields.one2many('project.user.allocation', 'phase_id', "Assigned Users",states={'done':[('readonly',True)], 'cancelled':[('readonly',True)]},
- help="The resources on the project can be computed automatically by the scheduler."),
- 'state': fields.selection([('draft', 'New'), ('cancelled', 'Cancelled'),('open', 'In Progress'), ('pending', 'Pending'), ('done', 'Done')], 'Status', readonly=True, required=True,
- help='If the phase is created the status \'Draft\'.\n If the phase is started, the status becomes \'In Progress\'.\n If review is needed the phase is in \'Pending\' status.\
- \n If the phase is over, the status is set to \'Done\'.'),
- 'progress': fields.function(_compute_progress, string='Progress', help="Computed based on related tasks"),
- }
- _defaults = {
- 'state': 'draft',
- 'sequence': 10,
- }
- _order = "project_id, date_start, sequence"
- _constraints = [
- (_check_recursion,'Loops in phases not allowed',['next_phase_ids', 'previous_phase_ids']),
- (_check_dates, 'Phase start-date must be lower than phase end-date.', ['date_start', 'date_end']),
- ]
-
- def onchange_project(self, cr, uid, ids, project, context=None):
- return {}
-
- def copy(self, cr, uid, id, default=None, context=None):
- if default is None:
- default = {}
- if not default.get('name', False):
- default.update(name=_('%s (copy)') % (self.browse(cr, uid, id, context=context).name))
- return super(project_phase, self).copy(cr, uid, id, default, context)
-
- def set_draft(self, cr, uid, ids, *args):
- self.write(cr, uid, ids, {'state': 'draft'})
- return True
-
- def set_open(self, cr, uid, ids, *args):
- self.write(cr, uid, ids, {'state': 'open'})
- return True
-
- def set_pending(self, cr, uid, ids, *args):
- self.write(cr, uid, ids, {'state': 'pending'})
- return True
-
- def set_cancel(self, cr, uid, ids, *args):
- self.write(cr, uid, ids, {'state': 'cancelled'})
- return True
-
- def set_done(self, cr, uid, ids, *args):
- self.write(cr, uid, ids, {'state': 'done'})
- return True
-
- def generate_phase(self, cr, uid, phases, context=None):
- context = context or {}
- result = ""
-
- task_pool = self.pool.get('project.task')
- for phase in phases:
- if phase.state in ('done','cancelled'):
- continue
- # FIXME: brittle and not working if context['lang'] != 'en_US'
- duration_uom = {
- 'day(s)': 'd', 'days': 'd', 'day': 'd', 'd':'d',
- 'month(s)': 'm', 'months': 'm', 'month':'month', 'm':'m',
- 'week(s)': 'w', 'weeks': 'w', 'week': 'w', 'w':'w',
- 'hour(s)': 'H', 'hours': 'H', 'hour': 'H', 'h':'H',
- }.get(phase.product_uom.name.lower(), "H")
- duration = str(phase.duration) + duration_uom
- result += '''
- def Phase_%s():
- effort = \"%s\"''' % (phase.id, duration)
- start = []
- if phase.constraint_date_start:
- start.append('datetime.datetime.strptime("'+str(phase.constraint_date_start)+'", "%Y-%m-%d %H:%M:%S")')
- for previous_phase in phase.previous_phase_ids:
- start.append("up.Phase_%s.end" % (previous_phase.id,))
- if start:
- result += '''
- start = max(%s)
-''' % (','.join(start))
-
- if phase.user_force_ids:
- result += '''
- resource = %s
-''' % '|'.join(map(lambda x: 'User_'+str(x.id), phase.user_force_ids))
-
- result += task_pool._generate_task(cr, uid, phase.task_ids, ident=8, context=context)
- result += "\n"
-
- return result
-
-class project_user_allocation(osv.osv):
- _name = 'project.user.allocation'
- _description = 'Phase User Allocation'
- _rec_name = 'user_id'
- _columns = {
- 'user_id': fields.many2one('res.users', 'User', required=True),
- 'phase_id': fields.many2one('project.phase', 'Project Phase', ondelete='cascade', required=True),
- 'project_id': fields.related('phase_id', 'project_id', type='many2one', relation="project.project", string='Project', store=True),
- 'date_start': fields.datetime('Start Date', help="Starting Date"),
- 'date_end': fields.datetime('End Date', help="Ending Date"),
- }
-
-class project(osv.osv):
- _inherit = "project.project"
-
- def _phase_count(self, cr, uid, ids, field_name, arg, context=None):
- res = dict.fromkeys(ids, 0)
- phase_ids = self.pool.get('project.phase').search(cr, uid, [('project_id', 'in', ids)])
- for phase in self.pool.get('project.phase').browse(cr, uid, phase_ids, context):
- res[phase.project_id.id] += 1
- return res
-
- _columns = {
- 'phase_ids': fields.one2many('project.phase', 'project_id', "Project Phases"),
- 'phase_count': fields.function(_phase_count, type='integer', string="Open Phases"),
- }
-
- def schedule_phases(self, cr, uid, ids, context=None):
- context = context or {}
- if type(ids) in (long, int,):
- ids = [ids]
- projects = self.browse(cr, uid, ids, context=context)
- result = self._schedule_header(cr, uid, ids, context=context)
- for project in projects:
- result += self._schedule_project(cr, uid, project, context=context)
- result += self.pool.get('project.phase').generate_phase(cr, uid, project.phase_ids, context=context)
-
- local_dict = {}
- exec result in local_dict
- projects_gantt = Task.BalancedProject(local_dict['Project'])
-
- for project in projects:
- project_gantt = getattr(projects_gantt, 'Project_%d' % (project.id,))
- for phase in project.phase_ids:
- if phase.state in ('done','cancelled'):
- continue
- # Maybe it's better to update than unlink/create if it already exists ?
- p = getattr(project_gantt, 'Phase_%d' % (phase.id,))
-
- self.pool.get('project.user.allocation').unlink(cr, uid,
- [x.id for x in phase.user_ids],
- context=context
- )
-
- for r in p.booked_resource:
- self.pool.get('project.user.allocation').create(cr, uid, {
- 'user_id': int(r.name[5:]),
- 'phase_id': phase.id,
- 'date_start': p.start.strftime('%Y-%m-%d %H:%M:%S'),
- 'date_end': p.end.strftime('%Y-%m-%d %H:%M:%S')
- }, context=context)
- self.pool.get('project.phase').write(cr, uid, [phase.id], {
- 'date_start': p.start.strftime('%Y-%m-%d %H:%M:%S'),
- 'date_end': p.end.strftime('%Y-%m-%d %H:%M:%S')
- }, context=context)
- return True
-
-class account_analytic_account(osv.osv):
- _inherit = 'account.analytic.account'
- _description = 'Analytic Account'
- _columns = {
- 'use_phases': fields.boolean('Phases', help="Check this field if you plan to use phase-based scheduling"),
- }
-
- def on_change_template(self, cr, uid, ids, template_id, date_start=False, context=None):
- res = super(account_analytic_account, self).on_change_template(cr, uid, ids, template_id, date_start=date_start, context=context)
- if template_id and 'value' in res:
- template = self.browse(cr, uid, template_id, context=context)
- res['value']['use_phases'] = template.use_phases
- return res
-
-
- def _trigger_project_creation(self, cr, uid, vals, context=None):
- if context is None: context = {}
- res = super(account_analytic_account, self)._trigger_project_creation(cr, uid, vals, context=context)
- return res or (vals.get('use_phases') and not 'project_creation_in_progress' in context)
-
-
-class project_task(osv.osv):
- _inherit = "project.task"
- _columns = {
- 'phase_id': fields.many2one('project.phase', 'Project Phase', domain="[('project_id', '=', project_id)]"),
- }
-
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/project_long_term/project_long_term_data.xml b/addons/project_long_term/project_long_term_data.xml
deleted file mode 100644
index ebc084668b7..00000000000
--- a/addons/project_long_term/project_long_term_data.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
diff --git a/addons/project_long_term/project_long_term_demo.xml b/addons/project_long_term/project_long_term_demo.xml
deleted file mode 100644
index fda481d5a11..00000000000
--- a/addons/project_long_term/project_long_term_demo.xml
+++ /dev/null
@@ -1,111 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Collect Requirement and Make SRS
-
-
- 30
-
-
-
-
-
-
-
-
- Design Model
-
-
- 20
-
-
-
-
-
-
- Planning and compute Risk analysis, Time chart
-
-
- 20
-
-
-
-
-
-
- Development and Integration
-
-
- 90
-
-
-
-
-
- Review and Testing
-
-
- 30
-
-
-
-
-
- Deployement and Training
-
-
- 10
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/addons/project_long_term/project_long_term_report.xml b/addons/project_long_term/project_long_term_report.xml
deleted file mode 100644
index d8fe2a4fa6e..00000000000
--- a/addons/project_long_term/project_long_term_report.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
-
-
-
-
diff --git a/addons/project_long_term/project_long_term_view.xml b/addons/project_long_term/project_long_term_view.xml
deleted file mode 100644
index 36fb83000ce..00000000000
--- a/addons/project_long_term/project_long_term_view.xml
+++ /dev/null
@@ -1,387 +0,0 @@
-
-
-
-
-
-
-
-
- project.user.allocation.gantt
- project.user.allocation
-
-
-
-
-
-
-
- project.user.allocation.calendar
- project.user.allocation
-
-
-
-
-
-
-
-
-
-
-
- project.user.allocation.form
- project.user.allocation
-
-
-
-
-
-
- project.phase.list
- project.phase
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- project.phase.calendar
- project.phase
-
-
-
-
-
-
-
-
-
- project.phase.gantt
- project.phase
-
-
-
-
-
-
-
-
- project.phase.search
- project.phase
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Project Phases
- project.phase
- form
- gantt,tree,form,calendar
- {}
-
- A project can be split into the different phases. For each phase, you can define your users allocation, describe different tasks and link your phase to previous and next phases, add date constraints for the automated scheduling. Use the long term planning in order to planify your available users, convert your phases into a series of tasks when you start working on the project.
-
-
-
- Project Phases
- project.phase
- form
- tree,form,calendar
- {}
-
-
-
-
-
-
- phase.task.form2
- project.task
-
-
-
-
-
-
-
-
- phase.task.search.form
- project.task
-
-
-
-
-
-
-
-
-
- phase.task.search.form.group
- project.task
-
-
-
-
-
-
-
-
-
- phase.task.search.form.tree
- project.task
-
-
-
-
-
-
-
-
-
- account.analytic.account.phase.form.inherit
- account.analytic.account
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/addons/project_long_term/project_long_term_workflow.xml b/addons/project_long_term/project_long_term_workflow.xml
deleted file mode 100644
index 317f98d9a35..00000000000
--- a/addons/project_long_term/project_long_term_workflow.xml
+++ /dev/null
@@ -1,110 +0,0 @@
-
-
-
-
-
- project.phase.wkf
- project.phase
- True
-
-
-
-
- True
- set_draft
- function
- set_draft()
-
-
-
-
- set_open
- function
- set_open()
-
-
-
-
- set_cancel
- True
- function
- set_cancel()
-
-
-
-
- set_pending
- function
- set_pending()
-
-
-
-
- set_done
- True
- function
- set_done()
-
-
-
-
-
- set_open
-
-
-
-
-
- set_cancel
-
-
-
-
-
- set_done
-
-
-
-
-
- set_pending
-
-
-
-
-
- set_cancel
-
-
-
-
-
- set_draft
-
-
-
-
-
- set_open
-
-
-
-
-
- set_cancel
-
-
-
-
-
- set_done
-
-
-
-
-
- set_draft
-
-
-
-
diff --git a/addons/project_long_term/security/ir.model.access.csv b/addons/project_long_term/security/ir.model.access.csv
deleted file mode 100644
index 82bfab460cb..00000000000
--- a/addons/project_long_term/security/ir.model.access.csv
+++ /dev/null
@@ -1,9 +0,0 @@
-id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
-access_project_phase,project.phase,model_project_phase,project.group_project_user,1,1,1,0
-access_project_user_allocation,project.user.allocation,model_project_user_allocation,project.group_project_user,1,0,0,0
-access_project_phase_manager,project.phase manager,model_project_phase,project.group_project_manager,1,1,1,1
-access_project_user_allocation_manager,project.user.allocation manager,model_project_user_allocation,project.group_project_manager,1,1,1,1
-access_resource_resource_user,user.user user,resource.model_resource_resource,project.group_project_user,1,0,0,0
-access_resource_resource_manager,user.user manager,resource.model_resource_resource,project.group_project_manager,1,1,1,1
-access_project_user_allocation_manager,project.user.allocation.manager,model_project_user_allocation,project.group_project_manager,1,1,1,1
-access_project_resource_calendar_attendance,resource.calendar.attendance,resource.model_resource_calendar_attendance,project.group_project_manager,1,0,0,0
diff --git a/addons/project_long_term/test/phase_process.yml b/addons/project_long_term/test/phase_process.yml
deleted file mode 100644
index 8738834b103..00000000000
--- a/addons/project_long_term/test/phase_process.yml
+++ /dev/null
@@ -1,79 +0,0 @@
--
- In order to test process of Phases,
--
- I create a record to schedule the phase of project.
--
- !record {model: project.compute.phases, id: project_compute_phases01}:
- target_project: 'one'
- project_id: project.project_project_1
--
- I schedule the phases.
--
- !python {model: project.compute.phases}: |
- self.check_selection(cr, uid, [ref("project_compute_phases01")])
--
- I check the starting date and ending date on the phases after scheduling.
--
- !python {model: project.project}: |
- project = self.browse(cr, uid, ref("project.project_project_1"), context=context)
- def _convert(date):
- import time
- return time.strptime(date, '%Y-%m-%d %H:%M:%S')
- def _check(phase, _convert, _check): #TOFIX: why need to pass function ?
- for next_phase in phase.next_phase_ids:
- assert _convert(next_phase.date_start) >= _convert(phase.date_end), "Phase does not start in proper date."
- _check(next_phase, _convert, _check)
- return True
-
- for phase in project.phase_ids:
-
- assert phase.date_start, "Start date should be computed."
- assert phase.date_end, "End date should be computed."
- if not phase.previous_phase_ids and phase.constraint_date_start:
- assert _convert(phase.date_start) >= _convert(phase.constraint_date_start), "Phase does not start in proper date."
- _check(phase, _convert, _check)
--
- I open phase.
--
- !python {model: project.phase}: |
- self.set_open(cr, uid, [ref("project_phase_1")])
--
- I check state of phase after opened.
--
- !assert {model: project.phase, id: project_phase_1, severity: error, string: Phase should be in open state}:
- - state == "open"
--
- I put phase in pending state.
--
- !python {model: project.phase}: |
- self.set_pending(cr, uid, [ref("project_phase_1")])
--
- I check state of phase after put in pending.
--
- !assert {model: project.phase, id: project_phase_1, severity: error, string: Phase should be in pending state}:
- - state == "pending"
--
- I make Phase in cancel state.
--
- !python {model: project.phase}: |
- self.set_cancel(cr, uid, [ref("project_phase_1")])
--
- I check state of phase after cancelled.
--
- !assert {model: project.phase, id: project_phase_1, severity: error, string: Phase should be in cancel state}:
- - state == "cancelled"
--
- I put again in draft phase.
--
- !python {model: project.phase}: |
- self.set_draft(cr, uid, [ref("project_phase_1")])
--
- I close phase.
--
- !python {model: project.phase}: |
- self.set_done(cr, uid, [ref("project_phase_1")])
--
- I check state of phase after closed.
--
- !assert {model: project.phase, id: project_phase_1, severity: error, string: Phase should be in done state}:
- - state == "done"
diff --git a/addons/project_long_term/test/task_process.yml b/addons/project_long_term/test/task_process.yml
deleted file mode 100644
index 060abcf43f3..00000000000
--- a/addons/project_long_term/test/task_process.yml
+++ /dev/null
@@ -1,19 +0,0 @@
--
- I create a record to compute the tasks of project.
--
- !record {model: project.compute.tasks, id: project_compute_tasks0}:
- project_id: project.project_project_1
--
- I compute and shedule the tasks.
--
- !python {model: project.compute.tasks}: |
- self.compute_date(cr, uid, [ref("project_compute_tasks0")])
--
- Check if tasks scheduled, check that either of task's start_date, end_date and user_id is not null
--
- !python {model: project.project}: |
- prj = self.browse(cr, uid, [ref("project.project_project_1")])[0]
- for task in prj.tasks:
- if task.stage_id and task.stage_id.fold:
- continue
- assert task.user_id and task.date_start and task.date_end, "Project tasks not scheduled"
diff --git a/addons/project_long_term/wizard/project_compute_phases.py b/addons/project_long_term/wizard/project_compute_phases.py
deleted file mode 100644
index 751265d5eba..00000000000
--- a/addons/project_long_term/wizard/project_compute_phases.py
+++ /dev/null
@@ -1,76 +0,0 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-# OpenERP, Open Source Management Solution
-# Copyright (C) 2004-2009 Tiny SPRL ().
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see .
-#
-##############################################################################
-from openerp.tools.translate import _
-from openerp.osv import fields, osv
-
-class project_compute_phases(osv.osv_memory):
- _name = 'project.compute.phases'
- _description = 'Project Compute Phases'
- _columns = {
- 'target_project': fields.selection([
- ('all', 'Compute All My Projects'),
- ('one', 'Compute a Single Project'),
- ], 'Action', required=True),
- 'project_id': fields.many2one('project.project', 'Project')
- }
- _defaults = {
- 'target_project': 'one'
- }
-
- def check_selection(self, cr, uid, ids, context=None):
- return self.compute_date(cr, uid, ids, context=context)
-
- def compute_date(self, cr, uid, ids, context=None):
- """
- Compute the phases for scheduling.
- """
- project_pool = self.pool.get('project.project')
- data = self.read(cr, uid, ids, [], context=context)[0]
- if not data['project_id'] and data['target_project'] == 'one':
- raise osv.except_osv(_('Error!'), _('Please specify a project to schedule.'))
-
- if data['target_project'] == 'one':
- project_ids = [data['project_id'][0]]
- else:
- project_ids = project_pool.search(cr, uid, [('user_id','=',uid)], context=context)
-
- if project_ids:
- project_pool.schedule_phases(cr, uid, project_ids, context=context)
- return self._open_phases_list(cr, uid, data, context=context)
-
- def _open_phases_list(self, cr, uid, data, context=None):
- """
- Return the scheduled phases list.
- """
- if context is None:
- context = {}
- mod_obj = self.pool.get('ir.model.data')
- act_obj = self.pool.get('ir.actions.act_window')
- result = mod_obj._get_id(cr, uid, 'project_long_term', 'act_project_phase')
- id = mod_obj.read(cr, uid, [result], ['res_id'])[0]['res_id']
- result = act_obj.read(cr, uid, [id], context=context)[0]
- result['target'] = 'current'
- project_id = data.get('project_id') and data.get('project_id')[0] or False
- result['context'] = {"search_default_project_id":project_id, "default_project_id":project_id, "search_default_current": 1}
- return result
-
-
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/project_long_term/wizard/project_compute_phases_view.xml b/addons/project_long_term/wizard/project_compute_phases_view.xml
deleted file mode 100644
index c9fcf5aca70..00000000000
--- a/addons/project_long_term/wizard/project_compute_phases_view.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-
-
-
-
-
- Schedule Phases
- project.compute.phases
-
-
-
-
-
-
-
-
-
-
-
-
- Schedule Phases
- ir.actions.act_window
- project.compute.phases
- form
- form
-
- new
- To schedule phases of all or a specified project. It then open a gantt view.
-
-
-
-
-
-
-
diff --git a/addons/project_long_term/wizard/project_compute_tasks.py b/addons/project_long_term/wizard/project_compute_tasks.py
deleted file mode 100644
index d442aee7790..00000000000
--- a/addons/project_long_term/wizard/project_compute_tasks.py
+++ /dev/null
@@ -1,63 +0,0 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-# OpenERP, Open Source Management Solution
-# Copyright (C) 2004-2009 Tiny SPRL ().
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see .
-#
-##############################################################################
-
-from openerp.osv import fields, osv
-
-class project_compute_tasks(osv.osv_memory):
- _name = 'project.compute.tasks'
- _description = 'Project Compute Tasks'
- _columns = {
- 'project_id': fields.many2one('project.project', 'Project', required=True)
- }
-
- def compute_date(self, cr, uid, ids, context=None):
- """
- Schedule the tasks according to users and priority.
- """
- project_pool = self.pool.get('project.project')
- task_pool = self.pool.get('project.task')
- if context is None:
- context = {}
- context['compute_by'] = 'project'
- data = self.read(cr, uid, ids, [])[0]
- project_id = data['project_id'][0]
- project_pool.schedule_tasks(cr, uid, [project_id], context=context)
- return self._open_task_list(cr, uid, data, context=context)
-
- def _open_task_list(self, cr, uid, data, context=None):
- """
- Return the scheduled task list.
- """
- if context is None:
- context = {}
- mod_obj = self.pool.get('ir.model.data')
- act_obj = self.pool.get('ir.actions.act_window')
- result = mod_obj._get_id(cr, uid, 'project_long_term', 'act_resouce_allocation')
- id = mod_obj.read(cr, uid, [result], ['res_id'])[0]['res_id']
- result = {}
- if not id:
- return result
- result = act_obj.read(cr, uid, [id], context=context)[0]
- result['target'] = 'current'
- return result
-
-
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/project_long_term/wizard/project_compute_tasks_view.xml b/addons/project_long_term/wizard/project_compute_tasks_view.xml
deleted file mode 100644
index 8b807806cde..00000000000
--- a/addons/project_long_term/wizard/project_compute_tasks_view.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-
-
-
-
-
- Schedule Tasks
- project.compute.tasks
-
-
-
-
-
-
-
-
-
-
-
- Schedule Tasks
- ir.actions.act_window
- project.compute.tasks
- form
- form
-
- new
-
-
-
-
-
-
diff --git a/addons/purchase/purchase.py b/addons/purchase/purchase.py
index de208f79881..4d05e5fb599 100644
--- a/addons/purchase/purchase.py
+++ b/addons/purchase/purchase.py
@@ -506,7 +506,7 @@ class purchase_order(osv.osv):
if not acc_id:
acc_id = po_line.product_id.categ_id.property_account_expense_categ.id
if not acc_id:
- raise osv.except_osv(_('Error!'), _('Define expense account for this company: "%s" (id:%d).') % (po_line.product_id.name, po_line.product_id.id,))
+ raise osv.except_osv(_('Error!'), _('Define an expense account for this product: "%s" (id:%d).') % (po_line.product_id.name, po_line.product_id.id,))
else:
acc_id = property_obj.get(cr, uid, 'property_account_expense_categ', 'product.category', context=context).id
fpos = po_line.order_id.fiscal_position or False
diff --git a/addons/purchase_requisition/purchase_requisition_view.xml b/addons/purchase_requisition/purchase_requisition_view.xml
index d0171a2ed95..214505219ea 100644
--- a/addons/purchase_requisition/purchase_requisition_view.xml
+++ b/addons/purchase_requisition/purchase_requisition_view.xml
@@ -44,12 +44,19 @@
attrs="{'invisible': ['|', ('state', 'not in', ('open','done')), ('exclusive', '=', 'exclusive')]}" groups="purchase.group_advance_bidding"/>
-
-
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
diff --git a/addons/purchase_requisition/wizard/purchase_requisition_partner.py b/addons/purchase_requisition/wizard/purchase_requisition_partner.py
index 7e2f140caa0..cef4b6be142 100644
--- a/addons/purchase_requisition/wizard/purchase_requisition_partner.py
+++ b/addons/purchase_requisition/wizard/purchase_requisition_partner.py
@@ -36,7 +36,7 @@ class purchase_requisition_partner(osv.osv_memory):
record_id = context and context.get('active_id', False) or False
tender = self.pool.get('purchase.requisition').browse(cr, uid, record_id, context=context)
if not tender.line_ids:
- raise osv.except_osv(_('Error!'), _('No product in call for bids.'))
+ raise osv.except_osv(_('Error!'), _('Define product(s) you want to include in the call for bids.'))
return res
def create_order(self, cr, uid, ids, context=None):
diff --git a/addons/report/tests/test_reports.py b/addons/report/tests/test_reports.py
index b1853489573..d3718df5e63 100644
--- a/addons/report/tests/test_reports.py
+++ b/addons/report/tests/test_reports.py
@@ -19,7 +19,9 @@
#
##############################################################################
import logging
+
import openerp
+import openerp.tests
_logger = logging.getLogger(__name__)
diff --git a/addons/resource/resource_view.xml b/addons/resource/resource_view.xml
index 74f71ecfeea..752026005a3 100644
--- a/addons/resource/resource_view.xml
+++ b/addons/resource/resource_view.xml
@@ -216,7 +216,7 @@
-
+
diff --git a/addons/stock/stock_view.xml b/addons/stock/stock_view.xml
index c13a8635f90..98e6113677d 100644
--- a/addons/stock/stock_view.xml
+++ b/addons/stock/stock_view.xml
@@ -1305,11 +1305,11 @@
stock.incoterms
-
+
-
+
diff --git a/addons/survey/survey.py b/addons/survey/survey.py
index 0569c8ab0d5..590d7ae22c8 100644
--- a/addons/survey/survey.py
+++ b/addons/survey/survey.py
@@ -34,6 +34,27 @@ import uuid
_logger = logging.getLogger(__name__)
+class survey_stage(osv.Model):
+ """Stages for Kanban view of surveys"""
+
+ _name = 'survey.stage'
+ _description = 'Survey Stage'
+ _order = 'sequence asc'
+
+ _columns = {
+ 'name': fields.char(string="Name", required=True, translate=True),
+ 'sequence': fields.integer(string="Sequence"),
+ 'closed': fields.boolean(string="Closed", help="If closed, people won't be able to answer to surveys in this column."),
+ 'fold': fields.boolean(string="Folded in kanban view")
+ }
+ _defaults = {
+ 'sequence': 1,
+ 'closed': False
+ }
+ _sql_constraints = [
+ ('positive_sequence', 'CHECK(sequence >= 0)', 'Sequence number MUST be a natural')
+ ]
+
class survey_survey(osv.Model):
'''Settings for a multi-page/multi-question survey.
@@ -175,9 +196,15 @@ class survey_survey(osv.Model):
'quizz_mode': fields.boolean(string='Quizz mode')
}
+ def _default_stage(self, cr, uid, context=None):
+ ids = self.pool['survey.stage'].search(cr, uid, [], limit=1, context=context)
+ if ids:
+ return ids[0]
+ return False
+
_defaults = {
'color': 0,
- 'stage_id': lambda self, cr, uid, context: self.pool.get('survey.stage').search_read(cr, uid, fields=['id'], order='sequence asc', limit=1, context=context)[0]['id']
+ 'stage_id': lambda self, *a, **kw: self._default_stage(*a, **kw)
}
def _read_group_stage_ids(self, cr, uid, ids, domain, read_group_order=None, access_rights_uid=None, context=None):
@@ -456,26 +483,6 @@ class survey_survey(osv.Model):
}
-class survey_stage(osv.Model):
- """Stages for Kanban view of surveys"""
-
- _name = 'survey.stage'
- _description = 'Survey Stage'
- _order = 'sequence asc'
-
- _columns = {
- 'name': fields.char(string="Name", required=True, translate=True),
- 'sequence': fields.integer(string="Sequence"),
- 'closed': fields.boolean(string="Closed", help="If closed, people won't be able to answer to surveys in this column."),
- 'fold': fields.boolean(string="Folded in kanban view")
- }
- _defaults = {
- 'sequence': 1,
- 'closed': False
- }
- _sql_constraints = [
- ('positive_sequence', 'CHECK(sequence >= 0)', 'Sequence number MUST be a natural')
- ]
class survey_page(osv.Model):
diff --git a/addons/website/static/src/js/website.snippets.editor.js b/addons/website/static/src/js/website.snippets.editor.js
index f59f2cf07ca..0177e8b8b64 100644
--- a/addons/website/static/src/js/website.snippets.editor.js
+++ b/addons/website/static/src/js/website.snippets.editor.js
@@ -130,6 +130,7 @@
*/
+ var dummy = function () {};
var website = openerp.website;
website.add_template_file('/website/static/src/xml/website.snippets.xml');
@@ -361,15 +362,21 @@
},
clean_for_save: function () {
var self = this;
- $(website.snippet.globalSelector).each(function () {
- var $snippet = $(this);
- self.make_active($snippet);
- self.make_active(false);
- var editor = $snippet.data("snippet-editor");
- if (editor) {
- editor.clean_for_save();
+
+ $("*[contentEditable], *[attributeEditable]")
+ .removeAttr('contentEditable')
+ .removeAttr('attributeEditable');
+
+ var options = website.snippet.options;
+ var template = website.snippet.templateOptions;
+ for (var k in options) {
+ if (template[k] && options[k].prototype.clean_for_save !== dummy) {
+ var $snippet = this.dom_filter(template[k].selector);
+ $snippet.each(function () {
+ new options[k](self, null, $(this), k).clean_for_save();
+ });
}
- });
+ }
},
make_active: function ($snippet) {
if ($snippet && this.$active_snipped_id && this.$active_snipped_id.get(0) === $snippet.get(0)) {
@@ -853,8 +860,7 @@
}
},
- clean_for_save: function () {
- }
+ clean_for_save: dummy
});
website.snippet.options.background = website.snippet.Option.extend({
@@ -942,8 +948,7 @@
this.id = this.unique_id();
this.$target.attr("id", this.id);
this.$target.find("[data-slide]").attr("data-cke-saved-href", "#" + this.id);
- this.$target.find("[data-slide-to]").attr("data-target", "#" + this.id);
-
+ this.$target.find("[data-target]").attr("data-target", "#" + this.id);
this.rebind_event();
},
on_clone: function ($clone) {
@@ -963,7 +968,7 @@
},
clean_for_save: function () {
this._super();
- this.$target.find(".item").removeClass("next prev left right");
+ $(".carousel").find(".item").removeClass("next prev left right active");
if(!this.$target.find(".item.active").length) {
this.$target.find(".item:first").addClass("active");
}
@@ -1757,19 +1762,6 @@
}
this.$overlay.removeClass('oe_active');
},
-
- /* clean_for_save
- * function called just before save vue
- */
- clean_for_save: function () {
- for (var i in this.styles){
- this.styles[i].clean_for_save();
- }
- this.$target.removeAttr('contentEditable')
- .find('*').removeAttr('contentEditable');
- this.$target.removeAttr('attributeEditable')
- .find('*').removeAttr('attributeEditable');
- },
});
})();
diff --git a/addons/website_blog/models/website_blog.py b/addons/website_blog/models/website_blog.py
index 031856fff10..ab96cc5b7f8 100644
--- a/addons/website_blog/models/website_blog.py
+++ b/addons/website_blog/models/website_blog.py
@@ -52,7 +52,7 @@ class BlogPost(osv.Model):
'name': fields.char('Title', required=True, translate=True),
'subtitle': fields.char('Sub Title', translate=True),
'author_id': fields.many2one('res.partner', 'Author'),
- 'background_image': fields.binary('Background Image'),
+ 'background_image': fields.binary('Background Image', oldname='content_image'),
'blog_id': fields.many2one(
'blog.blog', 'Blog',
required=True, ondelete='cascade',
diff --git a/addons/project_long_term/__init__.py b/addons/website_certification/__init__.py
similarity index 82%
rename from addons/project_long_term/__init__.py
rename to addons/website_certification/__init__.py
index 6b9b2613f3f..2a6cb8bee84 100644
--- a/addons/project_long_term/__init__.py
+++ b/addons/website_certification/__init__.py
@@ -1,8 +1,8 @@
-# -*- coding: utf-8 -*-
+# -*- encoding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
-# Copyright (C) 2004-2009 Tiny SPRL ().
+# Copyright (C) 2004-TODAY OpenERP S.A.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
@@ -19,7 +19,5 @@
#
##############################################################################
-import project_long_term
-import wizard
-
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+import certification
+import controllers
diff --git a/addons/portal_project_long_term/__openerp__.py b/addons/website_certification/__openerp__.py
similarity index 63%
rename from addons/portal_project_long_term/__openerp__.py
rename to addons/website_certification/__openerp__.py
index 44156afbc06..041014646fe 100644
--- a/addons/portal_project_long_term/__openerp__.py
+++ b/addons/website_certification/__openerp__.py
@@ -1,8 +1,8 @@
-# -*- coding: utf-8 -*-
+# -*- encoding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
-# Copyright (C) 2010-Today OpenERP S.A. ().
+# Copyright (C) 2004-TODAY OpenERP S.A.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
@@ -19,24 +19,20 @@
#
##############################################################################
-
{
- 'name': 'Portal Project Long Term',
+ 'name': 'Certified People',
+ 'category': 'Website',
+ 'summary': 'Display your network of certified people on your website',
'version': '1.0',
- 'category': 'Tools',
- 'complexity': 'easy',
+ 'author': 'OpenERP S.A.',
+ 'depends': ['marketing', 'website'],
'description': """
-This module adds necessary security rules and access rights for project long term and portal.
-=============================================================================================
+ Display your network of certified people on your website
""",
- 'author': 'OpenERP SA',
- 'depends': ['project_long_term', 'portal'],
'data': [
- 'security/portal_security.xml',
'security/ir.model.access.csv',
+ 'views/website_certification_views.xml',
+ 'views/website_certification_templates.xml',
],
'installable': True,
- 'auto_install': True,
- 'category': 'Hidden',
}
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/project_long_term/wizard/__init__.py b/addons/website_certification/certification.py
similarity index 50%
rename from addons/project_long_term/wizard/__init__.py
rename to addons/website_certification/certification.py
index 4536f4a3cbb..48636e027f7 100644
--- a/addons/project_long_term/wizard/__init__.py
+++ b/addons/website_certification/certification.py
@@ -1,8 +1,8 @@
-# -*- coding: utf-8 -*-s
+# -*- encoding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
-# Copyright (C) 2004-2009 Tiny SPRL ().
+# Copyright (C) 2004-TODAY OpenERP S.A.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
@@ -19,7 +19,25 @@
#
##############################################################################
-import project_compute_phases
-import project_compute_tasks
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+from openerp.osv import osv, fields
+
+
+class certification_type(osv.Model):
+ _name = 'certification.type'
+ _order = 'name ASC'
+ _columns = {
+ 'name': fields.char("Certification Type", required=True)
+ }
+
+
+class certification_certification(osv.Model):
+ _name = 'certification.certification'
+ _order = 'certification_date DESC'
+ _columns = {
+ 'partner_id': fields.many2one('res.partner', string="Partner", required=True),
+ 'type_id': fields.many2one('certification.type', string="Certification", required=True),
+ 'certification_date': fields.date("Certification Date", required=True),
+ 'certification_score': fields.char("Certification Score", required=True),
+ 'certification_hidden_score': fields.boolean("Hide score on website?")
+ }
diff --git a/addons/portal_project_long_term/__init__.py b/addons/website_certification/controllers/__init__.py
similarity index 89%
rename from addons/portal_project_long_term/__init__.py
rename to addons/website_certification/controllers/__init__.py
index c8d82ed19bd..672df6ec1f9 100644
--- a/addons/portal_project_long_term/__init__.py
+++ b/addons/website_certification/controllers/__init__.py
@@ -1,8 +1,8 @@
-# -*- coding: utf-8 -*-
+# -*- encoding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
-# Copyright (C) 2010-Today OpenERP S.A. ().
+# Copyright (C) 2004-TODAY OpenERP S.A.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
@@ -18,3 +18,5 @@
# along with this program. If not, see .
#
##############################################################################
+
+import main
diff --git a/addons/website_certification/controllers/main.py b/addons/website_certification/controllers/main.py
new file mode 100644
index 00000000000..ab955bc12dd
--- /dev/null
+++ b/addons/website_certification/controllers/main.py
@@ -0,0 +1,49 @@
+# -*- encoding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-TODAY OpenERP S.A.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+##############################################################################
+
+
+from openerp.addons.web import http
+from openerp.addons.web.http import request
+
+
+class WebsiteCertifiedPartners(http.Controller):
+
+ @http.route(['/certifications',
+ '/certifications/'], type='http', auth='public',
+ website=True, multilang=True)
+ def certified_partners(self, cert_type=None, **post):
+ cr, uid, context = request.cr, request.uid, request.context
+ certification_obj = request.registry['certification.certification']
+ cert_type_obj = request.registry['certification.type']
+
+ domain = []
+ if cert_type:
+ domain.append(('type_id', '=', cert_type.id))
+
+ certifications_ids = certification_obj.search(cr, uid, domain, context=context)
+ certifications = certification_obj.browse(cr, uid, certifications_ids, context=context)
+ types = cert_type_obj.browse(cr, uid, cert_type_obj.search(cr, uid, [], context=context), context=context)
+ data = {
+ 'certifications': certifications,
+ 'types': types
+ }
+
+ return request.website.render("website_certification.certified_partners", data)
diff --git a/addons/website_certification/security/ir.model.access.csv b/addons/website_certification/security/ir.model.access.csv
new file mode 100644
index 00000000000..a297b053d26
--- /dev/null
+++ b/addons/website_certification/security/ir.model.access.csv
@@ -0,0 +1,7 @@
+id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
+access_certifications_public,certification.certification public,model_certification_certification,base.group_public,1,0,0,0
+access_certifications_types_public,certification.type public,model_certification_type,base.group_public,1,0,0,0
+access_certifications_users,certification.certification users,model_certification_certification,base.group_user,1,0,0,0
+access_certifications_types_users,certification.type users,model_certification_type,base.group_user,1,0,0,0
+access_certifications_marketing,certification.certification marketing,model_certification_certification,marketing.group_marketing_user,1,1,1,1
+access_certifications_types_marketing,certification.type marketing,model_certification_type,marketing.group_marketing_user,1,1,1,1
diff --git a/addons/website_certification/views/website_certification_templates.xml b/addons/website_certification/views/website_certification_templates.xml
new file mode 100644
index 00000000000..13fe86a810c
--- /dev/null
+++ b/addons/website_certification/views/website_certification_templates.xml
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
+
+ view.certification.certification.search
+ certification.certification
+
+
+
+
+
+
+
+
+
+
+
+
+ Certifications
+ certification.certification
+ form
+ tree,form
+
+
+
+
+
+
diff --git a/addons/website_forum/controllers/main.py b/addons/website_forum/controllers/main.py
index d6394b069cc..6f5ba3e213c 100644
--- a/addons/website_forum/controllers/main.py
+++ b/addons/website_forum/controllers/main.py
@@ -32,12 +32,21 @@ class WebsiteForum(http.Controller):
return msg
def _prepare_forum_values(self, forum=None, **kwargs):
+ Forum = request.registry['forum.forum']
user = request.registry['res.users'].browse(request.cr, request.uid, request.uid, context=request.context)
public_uid = request.registry['website'].get_public_user(request.cr, request.uid, request.context)
values = {'user': user, 'is_public_user': user.id == public_uid,
'notifications': self._get_notifications(),
'header': kwargs.get('header', dict()),
- 'searches': kwargs.get('searches', dict())}
+ 'searches': kwargs.get('searches', dict()),
+ 'can_edit_own': True,
+ 'can_edit_all': user.karma > Forum._karma_modo_edit_all,
+ 'can_close_own': user.karma > Forum._karma_modo_close_own,
+ 'can_close_all': user.karma > Forum._karma_modo_close_all,
+ 'can_unlink_own': user.karma > Forum._karma_modo_unlink_own,
+ 'can_unlink_all': user.karma > Forum._karma_modo_unlink_all,
+ 'can_unlink_comment': user.karma > Forum._karma_modo_unlink_comment,
+ }
if forum:
values['forum'] = forum
elif kwargs.get('forum_id'):
@@ -45,6 +54,14 @@ class WebsiteForum(http.Controller):
values.update(kwargs)
return values
+ def _has_enough_karma(self, karma_name, uid=None):
+ Forum = request.registry['forum.forum']
+ karma = hasattr(Forum, karma_name) and getattr(Forum, karma_name) or 0
+ user = request.registry['res.users'].browse(request.cr, SUPERUSER_ID, uid or request.uid, context=request.context)
+ if user.karma < karma:
+ return False, {'error': 'not_enough_karma', 'karma': karma}
+ return True, {}
+
# Forum
# --------------------------------------------------
@@ -204,6 +221,10 @@ class WebsiteForum(http.Controller):
@http.route('/forum//question//ask_for_close', type='http', auth="user", multilang=True, website=True)
def question_ask_for_close(self, forum, question, **post):
+ check_res = self._has_enough_karma(question.create_uid.id == request.uid and '_karma_modo_close_own' or '_karma_modo_close_all')
+ if not check_res[0]:
+ return werkzeug.utils.redirect("/forum/%s" % slug(forum))
+
cr, uid, context = request.cr, request.uid, request.context
Reason = request.registry['forum.post.reason']
reason_ids = Reason.search(cr, uid, [], context=context)
@@ -211,7 +232,7 @@ class WebsiteForum(http.Controller):
values = self._prepare_forum_values(**post)
values.update({
- 'post': question,
+ 'question': question,
'question': question,
'forum': forum,
'reasons': reasons,
@@ -228,6 +249,10 @@ class WebsiteForum(http.Controller):
@http.route('/forum//question//close', type='http', auth="user", multilang=True, methods=['POST'], website=True)
def question_close(self, forum, question, **post):
+ check_res = self._has_enough_karma(question.create_uid.id == request.uid and '_karma_modo_close_own' or '_karma_modo_close_all')
+ if not check_res[0]:
+ return werkzeug.utils.redirect("/forum/%s" % slug(forum))
+
request.registry['forum.post'].write(request.cr, request.uid, [question.id], {
'state': 'close',
'closed_uid': request.uid,
@@ -238,17 +263,28 @@ class WebsiteForum(http.Controller):
@http.route('/forum//question//reopen', type='http', auth="user", multilang=True, website=True)
def question_reopen(self, forum, question, **kwarg):
+ check_res = self._has_enough_karma(question.create_uid.id == request.uid and '_karma_modo_close_own' or '_karma_modo_close_all')
+ if not check_res[0]:
+ return werkzeug.utils.redirect("/forum/%s" % slug(forum))
+
request.registry['forum.post'].write(request.cr, request.uid, [question.id], {'state': 'active'}, context=request.context)
return werkzeug.utils.redirect("/forum/%s/question/%s" % (slug(forum), slug(question)))
@http.route('/forum//question//delete', type='http', auth="user", multilang=True, website=True)
def question_delete(self, forum, question, **kwarg):
- #instead of unlink record just change 'active' to false so user can undelete it.
+ check_res = self._has_enough_karma(question.create_uid.id == request.uid and '_karma_modo_unlink_own' or '_karma_modo_unlink_all')
+ if not check_res[0]:
+ return werkzeug.utils.redirect("/forum/%s" % slug(forum))
+
request.registry['forum.post'].write(request.cr, request.uid, [question.id], {'active': False}, context=request.context)
return werkzeug.utils.redirect("/forum/%s/question/%s" % (slug(forum), slug(question)))
@http.route('/forum//question//undelete', type='http', auth="user", multilang=True, website=True)
def question_undelete(self, forum, question, **kwarg):
+ check_res = self._has_enough_karma(question.create_uid.id == request.uid and '_karma_modo_unlink_own' or '_karma_modo_unlink_all')
+ if not check_res[0]:
+ return werkzeug.utils.redirect("/forum/%s" % slug(forum))
+
request.registry['forum.post'].write(request.cr, request.uid, [question.id], {'active': True}, context=request.context)
return werkzeug.utils.redirect("/forum/%s/question/%s" % (slug(forum), slug(question)))
@@ -287,19 +323,27 @@ class WebsiteForum(http.Controller):
@http.route('/forum//post//toggle_correct', type='json', auth="public", website=True)
def post_toggle_correct(self, forum, post, **kwargs):
cr, uid, context = request.cr, request.uid, request.context
+ if post.parent_id is False:
+ return request.redirect('/')
if not request.session.uid:
return {'error': 'anonymous_user'}
- # if user have not access to accept answer then reise warning
- if post.parent_id is False or post.parent_id.create_uid.id != uid:
+ user = request.registry['res.users'].browse(request.cr, SUPERUSER_ID, request.uid, context=request.context)
+ if post.parent_id.create_uid.id != uid:
return {'error': 'own_post'}
+ if post.create_uid.id == user.id and user.karma < request.registry['forum.forum']._karma_answer_accept_own:
+ return {'error': 'not_enough_karma', 'karma': 20}
# set all answers to False, only one can be accepted
request.registry['forum.post'].write(cr, uid, [c.id for c in post.parent_id.child_ids], {'is_correct': False}, context=context)
- request.registry['forum.post'].write(cr, uid, [post.id, post.parent_id.id], {'is_correct': not post.is_correct}, context=context)
+ request.registry['forum.post'].write(cr, uid, [post.id], {'is_correct': not post.is_correct}, context=context)
return not post.is_correct
@http.route('/forum//post//delete', type='http', auth="user", multilang=True, website=True)
def post_delete(self, forum, post, **kwargs):
+ check_res = self._has_enough_karma(post.create_uid.id == request.uid and '_karma_modo_unlink_own' or '_karma_modo_unlink_all')
+ if not check_res[0]:
+ return werkzeug.utils.redirect("/forum/%s" % slug(forum))
+
question = post.parent_id
request.registry['forum.post'].unlink(request.cr, request.uid, [post.id], context=request.context)
if question:
@@ -308,6 +352,10 @@ class WebsiteForum(http.Controller):
@http.route('/forum//post//edit', type='http', auth="user", website=True, multilang=True)
def post_edit(self, forum, post, **kwargs):
+ check_res = self._has_enough_karma(post.create_uid.id == request.uid and '_karma_modo_edit_own' or '_karma_modo_edit_all')
+ if not check_res[0]:
+ return werkzeug.utils.redirect("/forum/%s" % slug(forum))
+
tags = ""
for tag_name in post.tag_ids:
tags += tag_name.name + ","
@@ -345,15 +393,15 @@ class WebsiteForum(http.Controller):
@http.route('/forum//post//upvote', type='json', auth="public", multilang=True, website=True)
def post_upvote(self, forum, post, **kwargs):
- # check for karma and not self vote
if not request.session.uid:
return {'error': 'anonymous_user'}
if request.uid == post.create_uid.id:
return {'error': 'own_post'}
- user = request.registry['res.users'].browse(request.cr, SUPERUSER_ID, request.uid, context=request.context)
- if user.karma <= 5:
- return {'error': 'not_enough_karma', 'karma': 1}
- return request.registry['forum.post'].vote(request.cr, request.uid, [post.id], upvote=True, context=request.context)
+ check_res = self._has_enough_karma('_karma_upvote')
+ if not check_res[0]:
+ return check_res[1]
+ upvote = True if not post.user_vote > 0 else False
+ return request.registry['forum.post'].vote(request.cr, request.uid, [post.id], upvote=upvote, context=request.context)
@http.route('/forum//post//downvote', type='json', auth="public", multilang=True, website=True)
def post_downvote(self, forum, post, **kwargs):
@@ -361,10 +409,11 @@ class WebsiteForum(http.Controller):
return {'error': 'anonymous_user'}
if request.uid == post.create_uid.id:
return {'error': 'own_post'}
- user = request.registry['res.users'].browse(request.cr, SUPERUSER_ID, request.uid, context=request.context)
- if user.karma <= 50:
- return {'error': 'not_enough_karma', 'karma': 50}
- return request.registry['forum.post'].vote(request.cr, request.uid, [post.id], upvote=False, context=request.context)
+ check_res = self._has_enough_karma('_karma_downvote')
+ if not check_res[0]:
+ return check_res[1]
+ upvote = True if post.user_vote < 0 else False
+ return request.registry['forum.post'].vote(request.cr, request.uid, [post.id], upvote=upvote, context=request.context)
# User
# --------------------------------------------------
@@ -392,6 +441,16 @@ class WebsiteForum(http.Controller):
return request.website.render("website_forum.users", values)
+ @http.route(['/forum//partner/'], type='http', auth="public", website=True, multilang=True)
+ def open_partner(self, forum, partner_id=0, **post):
+ cr, uid, context = request.cr, request.uid, request.context
+ pids = request.registry['res.partner'].search(cr, SUPERUSER_ID, [('id', '=', partner_id)], context=context)
+ if pids:
+ partner = request.registry['res.partner'].browse(cr, SUPERUSER_ID, pids[0], context=context)
+ if partner.user_ids:
+ return werkzeug.utils.redirect("/forum/%s/user/%d" % (slug(forum), partner.user_ids[0].id))
+ return werkzeug.utils.redirect("/forum/%s" % slug(forum))
+
@http.route(['/forum//user/'], type='http', auth="public", website=True, multilang=True)
def open_user(self, forum, user_id=0, **post):
cr, uid, context = request.cr, request.uid, request.context
diff --git a/addons/website_forum/data/badges_answer.xml b/addons/website_forum/data/badges_answer.xml
index 4e92600663d..97f184d59f0 100644
--- a/addons/website_forum/data/badges_answer.xml
+++ b/addons/website_forum/data/badges_answer.xml
@@ -1,6 +1,6 @@
-
+
@@ -8,6 +8,7 @@
TeacherReceived at least 3 upvote for an answer for the first timebronze
+ nobodyTeacher
@@ -42,6 +43,7 @@
Nice AnswerAnswer voted up 4 timesbronze
+ nobodyNice Answer (4)
@@ -76,6 +78,7 @@
Good AnswerAnswer voted up 6 timessilver
+ nobodyGood Answer (6)
@@ -110,6 +113,7 @@
Great AnswerAnswer voted up 15 timesgold
+ nobodyGreat Answer (15)
@@ -146,6 +150,7 @@
EnlightenedAnswer was accepted with 3 or more votessilver
+ nobodyEnlightened
@@ -180,6 +185,7 @@
GuruAnswer accepted with 15 or more votessilver
+ nobodyGuru (15)
@@ -256,6 +262,7 @@ for post in Post.browse(cr, uid, user_posts, context=context):
Self-LearnerAnswered own question with at least 4 up votesgold
+ nobodySelf-Learner
diff --git a/addons/website_forum/data/badges_moderation.xml b/addons/website_forum/data/badges_moderation.xml
index d99508bba51..41f3eb7fe41 100644
--- a/addons/website_forum/data/badges_moderation.xml
+++ b/addons/website_forum/data/badges_moderation.xml
@@ -1,6 +1,6 @@
-
+
@@ -15,6 +15,7 @@
CriticFirst downvotebronze
+ nobodyCritic
@@ -50,6 +51,7 @@
DisciplinedDeleted own post with 3 or more upvotesbronze
+ nobodyDisciplined
@@ -85,6 +87,7 @@
EditorFirst editgold
+ nobodyEditor
@@ -223,6 +226,7 @@ result = int(len(data) >= 15)
SupporterFirst upvotegold
+ nobodySupporter
@@ -258,6 +262,7 @@ result = int(len(data) >= 15)
Peer PressureDeleted own post with 3 or more downvotesgold
+ nobodyPeer Pressure
diff --git a/addons/website_forum/data/badges_participation.xml b/addons/website_forum/data/badges_participation.xml
index cf1f79185e1..05c2540d77d 100644
--- a/addons/website_forum/data/badges_participation.xml
+++ b/addons/website_forum/data/badges_participation.xml
@@ -1,12 +1,13 @@
-
+
AutobiographerCompleted own biographybronze
+ nobodyCompleted own biography
@@ -46,6 +47,7 @@
CommentatorPosted 10 commentsbronze
+ nobodyCommentator
@@ -81,6 +83,7 @@
PunditLeft comments with score of 10 or moresilver
+ nobodyPundit
@@ -115,6 +118,7 @@
Chief CommentatorPosted 100 commentssilver
+ nobodyChief Commentator
@@ -177,6 +181,7 @@ result = get_counter(cr, uid, context=context)
TaxonomistCreated a tag used by 15 questionssilver
+ nobodyTaxonomist
diff --git a/addons/website_forum/data/badges_question.xml b/addons/website_forum/data/badges_question.xml
index ab05d8bcf7a..ff2d63c034d 100644
--- a/addons/website_forum/data/badges_question.xml
+++ b/addons/website_forum/data/badges_question.xml
@@ -1,6 +1,6 @@
-
+
@@ -8,6 +8,7 @@
Popular QuestionAsked a question with at least 150 viewsbronze
+ nobodyPopular Question (150)
@@ -43,6 +44,7 @@
Notable QuestionAsked a question with at least 250 viewssilver
+ nobodyPopular Question (250)
@@ -77,6 +79,7 @@
Famous QuestionAsked a question with at least 500 viewsgold
+ nobodyPopular Question (500)
@@ -113,6 +116,7 @@
Credible QuestionQuestion set as favorite by 1 userbronze
+ nobodyFavourite Question (1)
@@ -147,6 +151,7 @@
Favorite QuestionQuestion set as favorite by 5 userssilver
+ nobodyFavourite Question (5)
@@ -181,6 +186,7 @@
Stellar QuestionQuestion set as favorite by 25 usersbronze
+ nobodyFavourite Question (25)
@@ -217,6 +223,7 @@
StudentAsked first question with at least one up votegold
+ nobodyUpvoted question (1)
@@ -251,6 +258,7 @@
Nice QuesiotnQuestion voted up 4 timesbronze
+ nobodyUpvoted question (4)
@@ -285,6 +293,7 @@
Good QuestionQuestion voted up 6 timessilver
+ nobodyUpvoted question (6)
@@ -319,6 +328,7 @@
Great QuestionQuestion voted up 15 timesgold
+ nobodyUpvoted question (15)
@@ -354,6 +364,7 @@
ScholarAsked a question and accepted an answergold
+ nobodyScholar
diff --git a/addons/website_forum/models/forum.py b/addons/website_forum/models/forum.py
index 166fdb809c7..7a8385d1a82 100644
--- a/addons/website_forum/models/forum.py
+++ b/addons/website_forum/models/forum.py
@@ -9,9 +9,38 @@ from openerp.tools.translate import _
class Forum(osv.Model):
+ """TDE TODO: set karma values for actions dynamic for a given forum"""
_name = 'forum.forum'
_description = 'Forums'
_inherit = ['website.seo.metadata']
+ # karma values
+ _karma_upvote = 5 # done
+ _karma_downvote = 50 # done
+ _karma_answer_accept_own = 20 # done
+ _karma_answer_accept_own_now = 50
+ _karma_answer_accept_all = 500
+ _karma_editor_link_files = 30 # done
+ _karma_editor_clickable_link = 50
+ _karma_comment = 1
+ _karma_modo_retag = 75
+ _karma_modo_flag = 100
+ _karma_modo_flag_see_all = 300
+ _karma_modo_unlink_comment = 750
+ _karma_modo_edit_own = 1 # done
+ _karma_modo_edit_all = 300 # done
+ _karma_modo_close_own = 100 # done
+ _karma_modo_close_all = 900 # done
+ _karma_modo_unlink_own = 500 # done
+ _karma_modo_unlink_all = 1000 # done
+ # karma generation
+ _karma_gen_quest_new = 2 # done
+ _karma_gen_upvote_quest = 5 # done
+ _karma_gen_downvote_quest = -2 # done
+ _karma_gen_upvote_ans = 10 # done
+ _karma_gen_downvote_ans = -2 # done
+ _karma_gen_ans_accept = 2 # done
+ _karma_gen_ans_accepted = 15 # done
+ _karma_gen_ans_flagged = -100
_columns = {
'name': fields.char('Name', required=True, translate=True),
@@ -97,6 +126,13 @@ class Post(osv.Model):
res[post.id] = any(answer.create_uid.id == uid for answer in post.child_ids)
return res
+ def _get_has_validated_answer(self, cr, uid, ids, field_name, arg, context=None):
+ res = dict.fromkeys(ids, False)
+ ans_ids = self.search(cr, uid, [('parent_id', 'in', ids), ('is_correct', '=', True)], context=context)
+ for answer in self.browse(cr, uid, ans_ids, context=context):
+ res[answer.parent_id.id] = True
+ return res
+
def _is_self_reply(self, cr, uid, ids, field_name, arg, context=None):
res = dict.fromkeys(ids, False)
for post in self.browse(cr, uid, ids, context=context):
@@ -143,7 +179,8 @@ class Post(osv.Model):
}),
# hierarchy
'parent_id': fields.many2one('forum.post', 'Question', ondelete='cascade'),
- 'self_reply': fields.function(_is_self_reply, 'Reply to own question', type='boolean',
+ 'self_reply': fields.function(
+ _is_self_reply, 'Reply to own question', type='boolean',
store={
'forum.post': (lambda self, cr, uid, ids, c={}: ids, ['parent_id', 'create_uid'], 10),
}),
@@ -156,6 +193,12 @@ class Post(osv.Model):
'uid_has_answered': fields.function(
_get_uid_answered, string='Has Answered', type='boolean',
),
+ 'has_validated_answer': fields.function(
+ _get_has_validated_answer, string='Has a Validated Answered', type='boolean',
+ store={
+ 'forum.post': (_get_post_from_hierarchy, ['parent_id', 'child_ids', 'is_correct'], 10),
+ }
+ ),
# closing
'closed_reason_id': fields.many2one('forum.post.reason', 'Reason'),
'closed_uid': fields.many2one('res.users', 'Closed by', select=1),
@@ -183,10 +226,18 @@ class Post(osv.Model):
self.message_post(cr, uid, parent.id, subject=_('Re: %s') % parent.name, body=body, subtype='website_forum.mt_answer_new', context=context)
else:
self.message_post(cr, uid, post_id, subject=vals.get('name', ''), body=_('New Question Created'), subtype='website_forum.mt_question_new', context=context)
- self.pool['res.users'].add_karma(cr, SUPERUSER_ID, [uid], 2, context=context)
+ self.pool['res.users'].add_karma(cr, SUPERUSER_ID, [uid], self.pool['forum.forum']._karma_gen_quest_new, context=context)
return post_id
def write(self, cr, uid, ids, vals, context=None):
+ Forum = self.pool['forum.forum']
+ # update karma when accepting/rejecting answers
+ if 'is_correct' in vals:
+ mult = 1 if vals['is_correct'] else -1
+ for post in self.browse(cr, uid, ids, context=context):
+ if vals['is_correct'] != post.is_correct:
+ self.pool['res.users'].add_karma(cr, SUPERUSER_ID, [post.create_uid.id], Forum._karma_gen_ans_accepted * mult, context=context)
+ self.pool['res.users'].add_karma(cr, SUPERUSER_ID, [uid], Forum._karma_gen_ans_accept * mult, context=context)
res = super(Post, self).write(cr, uid, ids, vals, context=context)
# if post content modify, notify followers
if 'content' in vals or 'name' in vals:
@@ -198,11 +249,6 @@ class Post(osv.Model):
body, subtype = _('Question Edited'), 'website_forum.mt_question_edit'
obj_id = post.id
self.message_post(cr, uid, obj_id, body=_(body), subtype=subtype, context=context)
- # update karma of related user when any answer accepted
- if 'correct' in vals:
- for post in self.browse(cr, uid, ids, context=context):
- karma_value = 15 if vals.get('correct') else -15
- self.pool['res.users'].add_karma(cr, SUPERUSER_ID, [post.create_uid.id], {'karma': karma_value}, context=context)
return res
def vote(self, cr, uid, ids, upvote=True, context=None):
@@ -252,16 +298,30 @@ class Vote(osv.Model):
def create(self, cr, uid, vals, context=None):
vote_id = super(Vote, self).create(cr, uid, vals, context=context)
- karma_value = int(vals.get('vote', '1')) * 10
- post = self.pool['forum.post'].browse(cr, uid, vals.get('post_id'), context=context)
- self.pool['res.users'].add_karma(cr, SUPERUSER_ID, post.create_uid.id, karma_value, context=context)
+ if vals.get('vote', '1') == '1':
+ karma = self.pool['forum.forum']._karma_upvote
+ elif vals.get('vote', '1') == '-1':
+ karma = self.pool['forum.forum']._karma_downvote
+ post = self.pool['forum.post'].browse(cr, uid, vals['post_id'], context=context)
+ self.pool['res.users'].add_karma(cr, SUPERUSER_ID, [post.create_uid.id], karma, context=context)
return vote_id
def write(self, cr, uid, ids, values, context=None):
+ def _get_karma_value(old_vote, new_vote, up_karma, down_karma):
+ _karma_upd = {
+ '-1': {'-1': 0, '0': -1 * down_karma, '1': -1 * down_karma + up_karma},
+ '0': {'-1': 1 * down_karma, '0': 0, '1': up_karma},
+ '1': {'-1': -1 * up_karma + down_karma, '0': -1 * up_karma, '1': 0}
+ }
+ return _karma_upd[old_vote][new_vote]
if 'vote' in values:
+ Forum = self.pool['forum.forum']
for vote in self.browse(cr, uid, ids, context=context):
- karma_value = (int(values.get('vote')) - int(vote.vote)) * 10
- self.pool['res.users'].add_karma(cr, SUPERUSER_ID, vote.post_id.create_uid.id, karma_value, context=context)
+ if vote.post_id.parent_id:
+ karma_value = _get_karma_value(vote.vote, values['vote'], Forum._karma_gen_upvote_ans, Forum._karma_gen_downvote_ans)
+ else:
+ karma_value = _get_karma_value(vote.vote, values['vote'], Forum._karma_gen_upvote_quest, Forum._karma_gen_downvote_quest)
+ self.pool['res.users'].add_karma(cr, SUPERUSER_ID, [vote.post_id.create_uid.id], karma_value, context=context)
res = super(Vote, self).write(cr, uid, ids, values, context=context)
return res
diff --git a/addons/website_forum/models/res_users.py b/addons/website_forum/models/res_users.py
index 58d43a58191..a9f2dfe0e93 100644
--- a/addons/website_forum/models/res_users.py
+++ b/addons/website_forum/models/res_users.py
@@ -32,8 +32,6 @@ class Users(osv.Model):
}
def add_karma(self, cr, uid, ids, karma, context=None):
- if isinstance(ids, (int, long)):
- ids = [ids]
for user in self.browse(cr, uid, ids, context=context):
self.write(cr, uid, [user.id], {'karma': user.karma + karma}, context=context)
return True
@@ -44,4 +42,4 @@ class Users(osv.Model):
excluded_categories.append('forum')
else:
excluded_categories = ['forum']
- return super(Users, self).get_serialised_gamification_summary(cr, uid, excluded_categories=excluded_categories, context=context)
\ No newline at end of file
+ return super(Users, self).get_serialised_gamification_summary(cr, uid, excluded_categories=excluded_categories, context=context)
diff --git a/addons/website_forum/static/src/js/website_forum.js b/addons/website_forum/static/src/js/website_forum.js
index f483fb98855..9053c573efb 100644
--- a/addons/website_forum/static/src/js/website_forum.js
+++ b/addons/website_forum/static/src/js/website_forum.js
@@ -18,9 +18,9 @@ $(document).ready(function () {
'
');
}
else if (data['error'] == 'not_enough_karma') {
- var $warning = $('
'+
+ var $warning = $('
'+
''+
- 'Sorry, at least ' + data['karma'] + ' karma is required to vote'+
+ 'Sorry, at least ' + data['karma'] + ' karma is required to vote. You can gain karma by answering questions and receiving votes.'+
'
'+
''+
- 'Sorry, the user who asked this question can only accept the answer as correct.'+
+ 'Sorry, only the user who asked this question can accept the answer as correct.'+
+ '
');
+ } else if (data['error'] == 'not_enough_karma') {
+ var $warning = $('
'+
+ ''+
+ 'Sorry, at least ' + data['karma'] + ' karma is required to accept your own answers. You can gain karma by answering questions and receiving votes.'+
'