diff options
| -rw-r--r-- | addons/hr_timesheet/data/hr_timesheet_data.xml | 6 | ||||
| -rw-r--r-- | addons/hr_timesheet/views/project_views.xml | 2 | ||||
| -rw-r--r-- | addons/project/__init__.py | 1 | ||||
| -rw-r--r-- | addons/project/__manifest__.py | 1 | ||||
| -rw-r--r-- | addons/project/data/project_data.xml | 135 | ||||
| -rw-r--r-- | addons/project/models/project.py | 33 | ||||
| -rw-r--r-- | addons/project/security/ir.model.access.csv | 1 | ||||
| -rw-r--r-- | addons/project/static/src/css/project.css | 5 | ||||
| -rw-r--r-- | addons/project/views/project_views.xml | 24 | ||||
| -rw-r--r-- | addons/project/views/res_config_settings_views.xml | 4 | ||||
| -rw-r--r-- | addons/project/wizard/__init__.py | 4 | ||||
| -rw-r--r-- | addons/project/wizard/project_delete_wizard.py | 24 | ||||
| -rw-r--r-- | addons/project/wizard/project_delete_wizard_views.xml | 28 | ||||
| -rw-r--r-- | addons/sale_project/views/project_task_views.xml | 2 | ||||
| -rw-r--r-- | addons/sale_timesheet/views/project_task_views.xml | 2 | ||||
| -rw-r--r-- | addons/web/static/src/js/views/kanban/kanban_record.js | 11 |
16 files changed, 208 insertions, 75 deletions
diff --git a/addons/hr_timesheet/data/hr_timesheet_data.xml b/addons/hr_timesheet/data/hr_timesheet_data.xml index 8fb4eb76cf6..0bb3c0dd642 100644 --- a/addons/hr_timesheet/data/hr_timesheet_data.xml +++ b/addons/hr_timesheet/data/hr_timesheet_data.xml @@ -23,4 +23,10 @@ <field name="key">hr_timesheet.timesheet_min_duration</field> <field name="value">15</field> </record> + + <!-- Sample project --> + <record forcecreate="False" id="project.project_project_data" model="project.project"> + <field name="allow_timesheets" eval="False" /> + <field name="allow_timesheet_timer" eval="False" /> + </record> </odoo> diff --git a/addons/hr_timesheet/views/project_views.xml b/addons/hr_timesheet/views/project_views.xml index 9385d4ac042..dd51e1f8d57 100644 --- a/addons/hr_timesheet/views/project_views.xml +++ b/addons/hr_timesheet/views/project_views.xml @@ -117,7 +117,7 @@ </group> <group name="timesheet_error" attrs="{'invisible': [('analytic_account_active', '!=', False)]}"> <div class="alert alert-warning" role="alert"> - You can not log timesheets on this project since is linked to an inactive analytic account. Please change it, or reactivate the current one to timesheet on the project. + You cannot log timesheets on this project since it is linked to an inactive analytic account. Please change this account, or reactivate the current one to timesheet on the project. </div> </group> <field name="timesheet_ids" mode="tree,kanban" attrs="{'invisible': [('analytic_account_active', '=', False)]}" context="{'default_project_id': project_id, 'default_name':''}"> diff --git a/addons/project/__init__.py b/addons/project/__init__.py index 5905766d867..4e9b019bd7a 100644 --- a/addons/project/__init__.py +++ b/addons/project/__init__.py @@ -4,3 +4,4 @@ from . import controllers from . import models from . import report +from . import wizard diff --git a/addons/project/__manifest__.py b/addons/project/__manifest__.py index 490da2229a9..ef03cb8f296 100644 --- a/addons/project/__manifest__.py +++ b/addons/project/__manifest__.py @@ -37,6 +37,7 @@ 'data/digest_data.xml', 'data/project_mail_template_data.xml', 'data/project_data.xml', + 'wizard/project_delete_wizard_views.xml', ], 'demo': ['data/project_demo.xml'], 'test': [ diff --git a/addons/project/data/project_data.xml b/addons/project/data/project_data.xml index b2b6d043752..d78834cfad2 100644 --- a/addons/project/data/project_data.xml +++ b/addons/project/data/project_data.xml @@ -99,19 +99,19 @@ <record forcecreate="False" id="project_stage_data_0" model="project.task.type"> <field name="sequence">1</field> - <field name="name">Basic</field> + <field name="name">First Steps</field> <field name="project_ids" eval="[(4, ref('project_project_data'))]"/> </record> <record forcecreate="False" id="project_stage_data_1" model="project.task.type"> <field name="sequence">2</field> - <field name="name">Advanced</field> + <field name="name">Getting Better</field> <field name="project_ids" eval="[(4, ref('project_project_data'))]"/> </record> <record forcecreate="False" id="project_stage_data_2" model="project.task.type"> <field name="sequence">3</field> - <field name="name">Expert</field> + <field name="name">Wow... You're Amazing!</field> <field name="project_ids" eval="[(4, ref('project_project_data'))]"/> </record> @@ -122,52 +122,56 @@ <field name="project_id" ref="project.project_project_data"/> <field name="active" eval="False"/> <field name="name">Welcome to Odoo</field> - <field name="description">Welcome! This project has the objective to show you all the main feature in the project app. Each card will help you to manage your projects easily in a few minutes.</field> + <field name="description" type="xml"> + <p>Welcome!</p> + <p>This project has the objective to show you all the main features from the project app.</p> + <p>Each card will teach you tips and tricks to easily manage your projects and tasks.</p> + </field> <field name="color">2</field> <field name="stage_id" ref="project_stage_data_0"/> </record> <record forcecreate="False" id="project_task_data_1" model="project.task"> - <field name="sequence">2</field> + <field name="sequence">5</field> <field name="user_id" ref="base.user_admin"/> <field name="priority">0</field> <field name="project_id" ref="project.project_project_data"/> - <field name="active" eval="False"/> - <field name="name">Try to play with the search bar. Use the filters</field> - <field name="description">Come back to the tasks view to play with the filters. They are up to the form</field> - <field name="stage_id" ref="project_stage_data_0"/> + <field name="name">Try to play with the filters</field> + <field name="description" type="xml"> + <p>Go back to the tasks view to play with the filters. Try to identify unassigned tasks or tasks that are overdue, for instance.</p> + <p>Hint: the filters and the search bar are available in the top right corner of your screen.</p> + </field> + <field name="stage_id" ref="project_stage_data_1"/> </record> <record forcecreate="False" id="project_task_data_5" model="project.task"> - <field name="sequence">3</field> + <field name="sequence">2</field> <field name="user_id" ref="base.user_admin"/> <field name="priority">0</field> <field name="project_id" ref="project.project_project_data"/> - <field name="active" eval="False"/> - <field name="name">Try to drag a task wherever your want</field> + <field name="name">Try to drag & drop this task wherever your want</field> + <field name="description">... or try changing the status of your task from here.</field> <field name="kanban_state">done</field> <field name="stage_id" ref="project_stage_data_0"/> </record> <record forcecreate="False" id="project_task_data_2" model="project.task"> - <field name="sequence">4</field> + <field name="sequence">3</field> <field name="user_id" ref="base.user_admin"/> <field name="priority">0</field> <field name="project_id" ref="project.project_project_data"/> - <field name="active" eval="False"/> - <field name="name">Guess what happens if you set this task as favorite?</field> - <field name="description">Click on the top left star to change the priority and come back in the tasks view. You task is now at the top of the column.</field> + <field name="name">Star this task to prioritize it</field> + <field name="description" type="xml"><p>Click on the top left icon to prioritize this task and go back to the kanban view.</p> <p>Your task is now at the top of the stage.</p></field> <field name="stage_id" ref="project_stage_data_0"/> </record> <record forcecreate="False" id="project_task_data_4" model="project.task"> + <field name="sequence">3</field> <field name="user_id" ref="base.user_admin"/> <field name="priority">0</field> <field name="project_id" ref="project.project_project_data"/> - <field name="active" eval="False"/> - <field name="name">Use the chatter to collaborate with your members</field> - <field name="description">The chatter is right below</field> - <field name="stage_id" ref="project_stage_data_2"/> + <field name="name">Use the chatter to collaborate with your team</field> + <field name="stage_id" ref="project_stage_data_1"/> </record> <record forcecreate="False" id="msg_task_4" model="mail.message"> @@ -175,90 +179,109 @@ <field name="model">project.task</field> <field name="author_id" ref="base.partner_root"/> <field name="res_id" ref="project_task_data_4"/> - <field name="body">Use this chatter to send emails. Add new people in the followers list, to make them aware about the main changes about this task!</field> + <field name="body">Use this chatter to send emails. Add new people in the followers list to make them aware about the main changes about this task.</field> <field name="message_type">email</field> <field name="subtype_id" ref="mail.mt_comment"/> </record> + <record forcecreate="False" id="msg_task_4_1" model="mail.message"> + <field name="subject">Converse with your customers and colleagues</field> + <field name="model">project.task</field> + <field name="author_id" ref="base.partner_root"/> + <field name="res_id" ref="project_task_data_4"/> + <field name="body">Use @ mentions to ping a colleague or # mentions to contact an entire team. The people following this task won't be notified of the note you are logging unless you specifically tag them.</field> + <field name="message_type">comment</field> + <field name="subtype_id" ref="mail.mt_note"/> + </record> + + <record forcecreate="False" id="project_task_data_10" model="project.task"> + <field name="sequence">4</field> + <field name="user_id" ref="base.user_admin"/> + <field name="priority">0</field> + <field name="project_id" ref="project.project_project_data"/> + <field name="name">Organize your work by using activities.</field> + <field name="stage_id" ref="project_stage_data_1"/> + </record> + + <record forcecreate="False" id="mail_activity_task_4" model="mail.activity"> + <field name="res_id" ref="project_task_data_10"/> + <field name="res_model_id" ref="model_project_task"/> + <field name="activity_type_id" ref="mail.mail_activity_data_todo" /> + <field name="date_deadline" eval="datetime.now()+timedelta(days=5)"/> + <field name="summary">Use activities to organize your work. Try marking this activity as done.</field> + <field name="create_uid" ref="base.user_root"/> + <field name="user_id" ref="base.user_root"/> + </record> + <record forcecreate="False" id="project_tag_data" model="project.tags"> <field name="name">Need Assistance</field> <field name="color" eval="5"/> </record> <record forcecreate="False" id="project_task_data_6" model="project.task"> - <field name="sequence">3</field> + <field name="sequence">1</field> <field name="user_id" ref="base.user_admin"/> <field name="priority">0</field> <field name="project_id" ref="project.project_project_data"/> - <field name="active" eval="False"/> - <field name="name">Use tags to organize your tasks</field> + <field name="name">Use tags to categorize your tasks</field> <field name="kanban_state">blocked</field> <field name="stage_id" ref="project_stage_data_1"/> - <field name="description">Tags will be represented by colored bars on the card</field> + <field name="description" type="xml"><p>Tags will be represented by colored dots on your task's card.</p> + <p>Click on a tag to define its color.</p> + <p>Tip: you can also define a color for your task from the tasks view.</p></field> <field name="tag_ids" eval="[(6,0,[ref('project.project_tag_data')])]"/> </record> <record forcecreate="False" id="project_task_data_12" model="project.task"> - <field name="sequence">4</field> + <field name="sequence">1</field> <field name="user_id" ref="base.user_admin"/> <field name="priority">0</field> <field name="project_id" ref="project.project_project_data"/> - <field name="active" eval="False"/> <field name="color">3</field> <field name="name">Try to customize this card. Change its background.</field> - <field name="description">Use the edit icon on the card to customize the background.</field> - <field name="stage_id" ref="project_stage_data_1"/> + <field name="description">Use the edit icon on the card from the tasks view to customize its background.</field> + <field name="stage_id" ref="project_stage_data_2"/> </record> <record forcecreate="False" id="project_task_data_13" model="project.task"> - <field name="sequence">5</field> - <field name="user_id" ref="base.user_admin"/> - <field name="priority">0</field> - <field name="project_id" ref="project.project_project_data"/> - <field name="active" eval="False"/> - <field name="name">Set this task as 'Ready for next stage' to proceed further in the process</field> - <field name="description">You can change its state by clicking on the small circle on the card, or here, next to the task title.</field> - <field name="stage_id" ref="project_stage_data_1"/> - </record> - - <record forcecreate="False" id="project_task_data_7" model="project.task"> + <field name="sequence">4</field> <field name="user_id" ref="base.user_admin"/> <field name="priority">0</field> <field name="project_id" ref="project.project_project_data"/> - <field name="active" eval="False"/> - <field name="name">Finished with this stage? Archive it !</field> - <field name="stage_id" ref="project_stage_data_2"/> - <field name="description">Click on the gear icon on the column, to archive the stage, with all the tasks in it. You can also archive one card only, by clicking on the button in the task form view.</field> + <field name="name">Set this task as being 'Ready for next stage'</field> + <field name="description" type="xml"><p>You can change this task's state by clicking on the small circle on the card, or here, next to the task's title.</p> + <p>Kanban states are perfect to let your colleagues know that your task is ready to be proceeded or that you need help on something.</p></field> + <field name="stage_id" ref="project_stage_data_0"/> </record> <record forcecreate="False" id="project_task_data_9" model="project.task"> + <field name="sequence">2</field> <field name="user_id" ref="base.user_admin"/> <field name="priority">0</field> <field name="project_id" ref="project.project_project_data"/> - <field name="active" eval="False"/> - <field name="name">You want to add a stage? Add a new column !</field> + <field name="name">You want to add a stage? Add a new column!</field> <field name="stage_id" ref="project_stage_data_2"/> - <field name="description">Click on the last column to create a stage. The name depends on the process. For example, in a customer service process, a stage name may be 'Backlog', 'Waiting Customer Feedback' or 'Done'.</field> + <field name="description" type="xml"><p>Click on the last column of your tasks view to create a stage.</p><p>Feel free to adapt the steps to your business workflow by drag & dropping your stages in the right places.</p> <p>Tip: You can also fold the stages you don't need to see permanently.</p></field> </record> - <record forcecreate="False" id="project_task_data_11" model="project.task"> + <record forcecreate="false" id="project_task_data_11" model="project.task"> + <field name="sequence">2</field> <field name="user_id" ref="base.user_admin"/> <field name="priority">0</field> <field name="project_id" ref="project.project_project_data"/> - <field name="active" eval="False"/> <field name="name">You can set a deadline on a task</field> + <field name="description" type="xml"><p>Deadlines are useful to get things done on time.</p><p>You will get visual clues when the due date is close or due.</p></field> <field name="stage_id" ref="project_stage_data_1"/> - <field name="date_deadline" eval="datetime.now()+timedelta(days=30)"/> + <field name="date_deadline" eval="datetime.now()-timedelta(days=7)"/> </record> - <record forcecreate="False" id="project_task_data_14" model="project.task"> - <field name="user_id" ref="base.user_admin"/> + <record forcecreate="false" id="project_task_data_15" model="project.task"> + <field name="sequence">5</field> <field name="priority">0</field> + <field name="user_id" eval="False" /> <field name="project_id" ref="project.project_project_data"/> - <field name="active" eval="False"/> - <field name="name">Send a message with a picture as attachment, and see what happens!</field> - <field name="stage_id" ref="project_stage_data_2"/> - <field name="description">In the chatter, sending an email with an attachment will display the picture on the card. When there are several image attachments, you can choose which one you want to display.</field> + <field name="name">Assign yourself to this task</field> + <field name="stage_id" ref="project_stage_data_0"/> </record> </odoo> diff --git a/addons/project/models/project.py b/addons/project/models/project.py index 09fef75a8a7..dea89f2c05e 100644 --- a/addons/project/models/project.py +++ b/addons/project/models/project.py @@ -5,7 +5,7 @@ import ast from datetime import timedelta from odoo import api, fields, models, tools, SUPERUSER_ID, _ -from odoo.exceptions import UserError, AccessError, ValidationError +from odoo.exceptions import UserError, AccessError, ValidationError, RedirectWarning from odoo.tools.misc import format_date @@ -132,6 +132,10 @@ class Project(models.Model): Create a new project</p>''') }) action_data = action.read()[0] + + action_config = self.env.ref('project.open_view_project_all_config', False) + if action_config: + action_config.sudo().write({'help': action.help}) # Reload the dashboard return action_data @@ -352,6 +356,22 @@ class Project(models.Model): return res + def action_unlink(self): + wizard = self.env['project.delete.wizard'].create({ + 'project_ids': self.ids + }) + + return { + 'name': _('Confirmation'), + 'view_mode': 'form', + 'res_model': 'project.delete.wizard', + 'views': [(self.env.ref('project.project_delete_wizard_form').id, 'form')], + 'type': 'ir.actions.act_window', + 'res_id': wizard.id, + 'target': 'new', + 'context': self.env.context, + } + def unlink(self): # Check project is empty for project in self.with_context(active_test=False): @@ -507,9 +527,9 @@ class Task(models.Model): domain="[('project_ids', '=', project_id)]", copy=False) tag_ids = fields.Many2many('project.tags', string='Tags') kanban_state = fields.Selection([ - ('normal', 'Grey'), - ('done', 'Green'), - ('blocked', 'Red')], string='Kanban State', + ('normal', 'In Progress'), + ('done', 'Ready'), + ('blocked', 'Blocked')], string='Kanban State', copy=False, default='normal', required=True) kanban_state_label = fields.Char(compute='_compute_kanban_state_label', string='Kanban State Label', tracking=True) create_date = fields.Datetime("Created On", readonly=True, index=True) @@ -943,6 +963,11 @@ class Task(models.Model): return headers def _message_post_after_hook(self, message, msg_vals): + if message.attachment_ids and not self.displayed_image_id: + image_attachments = message.attachment_ids.filtered(lambda a: a.mimetype == 'image') + if image_attachments: + self.displayed_image_id = image_attachments[0] + if self.email_from and not self.partner_id: # we consider that posting a message with a specified recipient (not a follower, a specific one) # on a document without customer means that it was created through the chatter using diff --git a/addons/project/security/ir.model.access.csv b/addons/project/security/ir.model.access.csv index c6e0fc445d9..ad520ea8b56 100644 --- a/addons/project/security/ir.model.access.csv +++ b/addons/project/security/ir.model.access.csv @@ -23,3 +23,4 @@ access_mail_activity_type_project_manager,mail.activity.type.project.manager,mai access_account_analytic_account_user,account.analytic.account,analytic.model_account_analytic_account,project.group_project_user,1,0,0,0 access_account_analytic_account_manager,account.analytic.account,analytic.model_account_analytic_account,project.group_project_manager,1,1,1,1 access_account_analytic_line_project,account.analytic.line project,analytic.model_account_analytic_line,project.group_project_manager,1,1,1,1 +access_project_delete_wizard,access_project_delete_wizard,model_project_delete_wizard,project.group_project_manager,1,1,1,1 diff --git a/addons/project/static/src/css/project.css b/addons/project/static/src/css/project.css index f1599a7b21d..19f265cd2c6 100644 --- a/addons/project/static/src/css/project.css +++ b/addons/project/static/src/css/project.css @@ -65,3 +65,8 @@ .o_kanban_project_tasks .badge-danger { border-color: var(--danger); } + +.o_form_project_tasks .ribbon:not(.o_invisible_modifier) + div > h1 > div[name="kanban_state"] { + margin-right: 150px; + padding-left: 1rem; +} diff --git a/addons/project/views/project_views.xml b/addons/project/views/project_views.xml index d0b8b214754..40231d1d83e 100644 --- a/addons/project/views/project_views.xml +++ b/addons/project/views/project_views.xml @@ -94,7 +94,7 @@ <field name="name">project.project.form</field> <field name="model">project.project</field> <field name="arch" type="xml"> - <form string="Project"> + <form string="Project" delete="0"> <header> <button name="%(portal.portal_share_action)d" string="Share" type="action" class="oe_highlight oe_read_only"/> </header> @@ -242,7 +242,7 @@ <field name="name">project.project.tree</field> <field name="model">project.project</field> <field name="arch" type="xml"> - <tree decoration-bf="message_needaction==True" decoration-muted="active == False" string="Projects"> + <tree decoration-bf="message_needaction==True" decoration-muted="active == False" string="Projects" delete="0"> <field name="sequence" optional="show" widget="handle"/> <field name="message_needaction" invisible="1"/> <field name="active" invisible="1"/> @@ -458,7 +458,7 @@ <p class="o_view_nocontent_empty_folder"> Create a new project </p><p> - Organize your activities (plan tasks, track issues, invoice timesheets) for internal, personal or customer projects. + Or <a type="action" name="%(project.ir_actions_server_project_sample)d" tabindex="-1">activate a sample project</a> to play with. </p> </field> </record> @@ -514,10 +514,6 @@ domain="[('parent_id', '=', False)]" attrs="{'invisible' : [('allow_subtasks', '=', False)]}" /> - </group> - <!-- YTI FIXME: Clean these fake groups --> - <group name="sales_order_group"/> - <group name="dates"> <field name="date_deadline"/> <field name="tag_ids" widget="many2many_tags" options="{'color_field': 'color', 'no_create_edit': True}"/> </group> @@ -575,6 +571,15 @@ target="new" /> + <record id="unlink_project_action" model="ir.actions.server"> + <field name="name">Delete</field> + <field name="model_id" ref="project.model_project_project"/> + <field name="binding_model_id" ref="project.model_project_project"/> + <field name="binding_view_types">form,list</field> + <field name="state">code</field> + <field name="code">action = records.action_unlink()</field> + </record> + <record id="quick_create_task_form" model="ir.ui.view"> <field name="name">project.task.form.quick_create</field> <field name="model">project.task</field> @@ -642,7 +647,7 @@ <span class="fa fa-ellipsis-v"/> </a> <div class="dropdown-menu" role="menu"> - <a t-if="widget.editable" role="menuitem" type="set_cover" class="dropdown-item" data-field="displayed_image_id">Set Cover Image</a> + <a t-if="widget.editable" role="menuitem" type="set_cover" data-auto-open="1" class="dropdown-item" data-field="displayed_image_id">Set Cover Image</a> <a name="%(portal.portal_share_action)d" role="menuitem" type="action" class="dropdown-item">Share</a> <a t-if="widget.editable" role="menuitem" type="edit" class="dropdown-item">Edit Task</a> <a t-if="widget.deletable" role="menuitem" type="delete" class="dropdown-item">Delete</a> @@ -1035,6 +1040,9 @@ <p class="o_view_nocontent_smiling_face"> Create a new tag </p> + <p> + Tags are perfect to categorize your tasks. + </p> </field> </record> <menuitem action="project_tags_action" id="menu_project_tags_act" parent="menu_project_config"/> diff --git a/addons/project/views/res_config_settings_views.xml b/addons/project/views/res_config_settings_views.xml index 711edcd627f..759291fc286 100644 --- a/addons/project/views/res_config_settings_views.xml +++ b/addons/project/views/res_config_settings_views.xml @@ -10,7 +10,7 @@ <div class="app_settings_block" data-string="Project" string="Project" data-key="project" groups="project.group_project_manager"> <h2>Tasks Management</h2> <div class="row mt16 o_settings_container" id="tasks_management"> - <div id="use_collaborative_pad" class="col-12 col-lg-6 o_setting_box" title="Lets the company customize which Pad installation should be used to link to new pads (for example: http://etherpad.com/)."> + <div id="use_collaborative_pad" class="col-12 col-lg-6 o_setting_box"> <div class="o_setting_left_pane"> <field name="module_pad"/> </div> @@ -70,7 +70,7 @@ <div class="o_setting_right_pane"> <label for="module_hr_timesheet"/> <div class="text-muted"> - Log time on tasks + Track time spent on tasks. </div> </div> </div> diff --git a/addons/project/wizard/__init__.py b/addons/project/wizard/__init__.py new file mode 100644 index 00000000000..fc073c12452 --- /dev/null +++ b/addons/project/wizard/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from . import project_delete_wizard diff --git a/addons/project/wizard/project_delete_wizard.py b/addons/project/wizard/project_delete_wizard.py new file mode 100644 index 00000000000..3dcc512a843 --- /dev/null +++ b/addons/project/wizard/project_delete_wizard.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import fields, models + + +class ProjectDelete(models.TransientModel): + _name = 'project.delete.wizard' + _description = 'Project Delete Wizard' + + project_ids = fields.Many2many('project.project', string='Projects') + task_count = fields.Integer(compute='_compute_task_count') + + def _compute_task_count(self): + for wizard in self: + wizard.task_count = sum(wizard.with_context(active_test=False).project_ids.mapped('task_count')) + + def action_archive(self): + self.project_ids.write({'active': False}) + return self.env.ref('project.open_view_project_all').read()[0] + + def confirm_delete(self): + self.with_context(active_test=False).project_ids.unlink() + return self.env.ref('project.open_view_project_all').read()[0] diff --git a/addons/project/wizard/project_delete_wizard_views.xml b/addons/project/wizard/project_delete_wizard_views.xml new file mode 100644 index 00000000000..5947b26ab60 --- /dev/null +++ b/addons/project/wizard/project_delete_wizard_views.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<odoo> + <data> + <record id="project_delete_wizard_form" model="ir.ui.view"> + <field name="name">Delete Project</field> + <field name="model">project.delete.wizard</field> + <field name="arch" type="xml"> + <form string="Delete Project"> + <field name="task_count" invisible="1" /> + <group attrs="{'invisible': [('task_count', '=', 0)]}"> + <span>You cannot delete a project containing tasks. You can either archive it or first delete all of its tasks.</span> + </group> + <group attrs="{'invisible': [('task_count', '>', 0)]}"> + <span>Are you sure you want to delete this project ?</span> + </group> + <footer attrs="{'invisible': [('task_count', '=', 0)]}"> + <button string="Archive project" type="object" name="action_archive" class="btn btn-primary" /> + <button string="Discard" special="cancel" /> + </footer> + <footer attrs="{'invisible': [('task_count', '>', 0)]}"> + <button string="Ok" type="object" name="confirm_delete" class="btn btn-primary" /> + <button string="Cancel" special="cancel" /> + </footer> + </form> + </field> + </record> + </data> +</odoo> diff --git a/addons/sale_project/views/project_task_views.xml b/addons/sale_project/views/project_task_views.xml index d45fdd10d26..0a02c40b85f 100644 --- a/addons/sale_project/views/project_task_views.xml +++ b/addons/sale_project/views/project_task_views.xml @@ -26,7 +26,7 @@ string="Sales Order" groups="sales_team.group_sale_salesman"/> </div> - <xpath expr="//group[@name='sales_order_group']" position="inside"> + <xpath expr="//field[@name='partner_email']" position="after"> <field name="sale_line_id" string="Sales Order Item" attrs="{'invisible': ['|', ('partner_id', '=', False), '&', ('sale_order_id', '!=', False), ('sale_line_id', '=', False)]}" options='{"no_open": True}' readonly="1" context="{'create': False, 'edit': False, 'delete': False}" groups="sales_team.group_sale_salesman"/> <field name="sale_order_id" attrs="{'invisible': [('project_id', '!=', False)]}" groups="sales_team.group_sale_salesman"/> <field name="commercial_partner_id" invisible="1" /> diff --git a/addons/sale_timesheet/views/project_task_views.xml b/addons/sale_timesheet/views/project_task_views.xml index a2a4b09a0ad..51e83ea5969 100644 --- a/addons/sale_timesheet/views/project_task_views.xml +++ b/addons/sale_timesheet/views/project_task_views.xml @@ -86,7 +86,7 @@ <field name="display_create_order" invisible="1"/> <button name="action_make_billable" string="Create Sales Order" type="object" attrs="{'invisible': [('display_create_order', '=', False)]}" groups="sales_team.group_sale_salesman"/> </xpath> - <xpath expr="//group[@name='sales_order_group']" position="inside"> + <xpath expr="//field[@name='date_deadline']" position="before"> <field name="billable_type" invisible="1"/> </xpath> <xpath expr="//field[@name='email_cc']" position="after"> diff --git a/addons/web/static/src/js/views/kanban/kanban_record.js b/addons/web/static/src/js/views/kanban/kanban_record.js index f199a286db6..7b02d7317df 100644 --- a/addons/web/static/src/js/views/kanban/kanban_record.js +++ b/addons/web/static/src/js/views/kanban/kanban_record.js @@ -380,8 +380,9 @@ var KanbanRecord = Widget.extend({ * * @private * @param {string} fieldName field used to set cover image + * @param {boolean} autoOpen automatically open the file choser if there are no attachments */ - _setCoverImage: function (fieldName) { + _setCoverImage: function (fieldName, autoOpen) { var self = this; this._rpc({ model: 'ir.attachment', @@ -395,6 +396,7 @@ var KanbanRecord = Widget.extend({ }).then(function (attachmentIds) { self.imageUploadID = _.uniqueId('o_cover_image_upload'); self.accepted_file_extensions = 'image/*'; // prevent uploading of other file types + self.attachment_count = attachmentIds.length; var coverId = self.record[fieldName] && self.record[fieldName].raw_value; var $content = $(QWeb.render('KanbanView.SetCoverModal', { coverId: coverId, @@ -442,6 +444,10 @@ var KanbanRecord = Widget.extend({ }); dialog.opened().then(function () { var $selectBtn = dialog.$footer.find('.btn-primary'); + if (autoOpen && !self.attachment_count) { + $selectBtn.click(); + } + $content.on('click', '.o_kanban_cover_image', function (ev) { $imgs.not(ev.currentTarget).removeClass('o_selected'); $selectBtn.prop('disabled', !$(ev.currentTarget).toggleClass('o_selected').hasClass('o_selected')); @@ -687,10 +693,11 @@ var KanbanRecord = Widget.extend({ break; case 'set_cover': var fieldName = $action.data('field'); + var autoOpen = $action.data('auto-open'); if (this.fields[fieldName].type === 'many2one' && this.fields[fieldName].relation === 'ir.attachment' && this.fieldsInfo[fieldName].widget === 'attachment_image') { - this._setCoverImage(fieldName); + this._setCoverImage(fieldName, autoOpen); } else { var warning = _.str.sprintf(_t('Could not set the cover image: incorrect field ("%s") is provided in the view.'), fieldName); this.do_warn(warning); |
