mirror of
https://gitlab.com/flectra-hq/flectra.git
synced 2026-11-02 20:30:20 -06:00
[PATCH] Upstream patch - 27052023
This commit is contained in:
1 parent
50acfc7a79
commit
2a5f774eb0
14 files changed
+125
-63
No files matched your search
@@ -5,6 +5,7 @@ from collections import defaultdict
|
|||||||
|
|
||||||
from flectra import api, fields, models, _
|
from flectra import api, fields, models, _
|
||||||
from flectra.exceptions import UserError
|
from flectra.exceptions import UserError
|
||||||
|
from flectra.tools import frozendict
|
||||||
|
|
||||||
|
|
||||||
class AccountMove(models.Model):
|
class AccountMove(models.Model):
|
||||||
@@ -162,9 +163,6 @@ class AccountMove(models.Model):
|
|||||||
'''
|
'''
|
||||||
self.ensure_one()
|
self.ensure_one()
|
||||||
|
|
||||||
def _serialize_python_dictionary(vals):
|
|
||||||
return '-'.join(str(vals[k]) for k in sorted(vals.keys()))
|
|
||||||
|
|
||||||
def default_grouping_key_generator(tax_values):
|
def default_grouping_key_generator(tax_values):
|
||||||
return {'tax': tax_values['tax_id']}
|
return {'tax': tax_values['tax_id']}
|
||||||
|
|
||||||
@@ -250,7 +248,7 @@ class AccountMove(models.Model):
|
|||||||
|
|
||||||
for tax_values in tax_values_list:
|
for tax_values in tax_values_list:
|
||||||
grouping_key = grouping_key_generator(tax_values)
|
grouping_key = grouping_key_generator(tax_values)
|
||||||
serialized_grouping_key = _serialize_python_dictionary(grouping_key)
|
serialized_grouping_key = frozendict(grouping_key)
|
||||||
|
|
||||||
# Add to invoice line global tax amounts.
|
# Add to invoice line global tax amounts.
|
||||||
if serialized_grouping_key not in invoice_global_tax_details['invoice_line_tax_details'][invoice_line]:
|
if serialized_grouping_key not in invoice_global_tax_details['invoice_line_tax_details'][invoice_line]:
|
||||||
|
|||||||
@@ -72,11 +72,6 @@ class GoogleGmailMixin(models.AbstractModel):
|
|||||||
if not self.google_gmail_uri:
|
if not self.google_gmail_uri:
|
||||||
raise UserError(_('Please configure your Gmail credentials.'))
|
raise UserError(_('Please configure your Gmail credentials.'))
|
||||||
|
|
||||||
if not self.smtp_user:
|
|
||||||
raise UserError(_(
|
|
||||||
'Please fill the "Username" field with your Gmail username (your email address). '
|
|
||||||
'This should be the same account as the one used for the Gmail OAuthentication Token.'))
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'type': 'ir.actions.act_url',
|
'type': 'ir.actions.act_url',
|
||||||
'url': self.google_gmail_uri,
|
'url': self.google_gmail_uri,
|
||||||
|
|||||||
@@ -3,7 +3,8 @@
|
|||||||
|
|
||||||
import base64
|
import base64
|
||||||
|
|
||||||
from flectra import models, api
|
from flectra import _, models, api
|
||||||
|
from flectra.exceptions import UserError
|
||||||
|
|
||||||
|
|
||||||
class IrMailServer(models.Model):
|
class IrMailServer(models.Model):
|
||||||
@@ -12,6 +13,13 @@ class IrMailServer(models.Model):
|
|||||||
_name = 'ir.mail_server'
|
_name = 'ir.mail_server'
|
||||||
_inherit = ['ir.mail_server', 'google.gmail.mixin']
|
_inherit = ['ir.mail_server', 'google.gmail.mixin']
|
||||||
|
|
||||||
|
@api.constrains('use_google_gmail_service')
|
||||||
|
def _check_use_google_gmail_service(self):
|
||||||
|
if self.filtered(lambda server: server.use_google_gmail_service and not server.smtp_user):
|
||||||
|
raise UserError(_(
|
||||||
|
'Please fill the "Username" field with your Gmail username (your email address). '
|
||||||
|
'This should be the same account as the one used for the Gmail OAuthentication Token.'))
|
||||||
|
|
||||||
@api.onchange('smtp_encryption')
|
@api.onchange('smtp_encryption')
|
||||||
def _onchange_encryption(self):
|
def _onchange_encryption(self):
|
||||||
"""Do not change the SMTP configuration if it's a Gmail server
|
"""Do not change the SMTP configuration if it's a Gmail server
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
|
# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
|
||||||
|
|
||||||
|
from collections import defaultdict
|
||||||
|
|
||||||
from flectra import _, api, exceptions, fields, models, modules
|
from flectra import _, api, exceptions, fields, models, modules
|
||||||
from flectra.addons.base.models.res_users import is_selection_groups
|
from flectra.addons.base.models.res_users import is_selection_groups
|
||||||
|
|
||||||
@@ -115,45 +117,43 @@ GROUP BY channel_moderator.res_users_id""", [tuple(self.ids)])
|
|||||||
|
|
||||||
@api.model
|
@api.model
|
||||||
def systray_get_activities(self):
|
def systray_get_activities(self):
|
||||||
query = """SELECT m.id, count(*), act.res_model as model,
|
activities = self.env["mail.activity"].search([("user_id", "=", self.env.uid)])
|
||||||
CASE
|
activities_by_record_by_model_name = defaultdict(lambda: defaultdict(lambda: self.env["mail.activity"]))
|
||||||
WHEN %(today)s::date - act.date_deadline::date = 0 Then 'today'
|
for activity in activities:
|
||||||
WHEN %(today)s::date - act.date_deadline::date > 0 Then 'overdue'
|
record = self.env[activity.res_model].browse(activity.res_id)
|
||||||
WHEN %(today)s::date - act.date_deadline::date < 0 Then 'planned'
|
activities_by_record_by_model_name[activity.res_model][record] += activity
|
||||||
END AS states
|
model_ids = list({self.env["ir.model"]._get(name).id for name in activities_by_record_by_model_name.keys()})
|
||||||
FROM mail_activity AS act
|
|
||||||
JOIN ir_model AS m ON act.res_model_id = m.id
|
|
||||||
WHERE user_id = %(user_id)s
|
|
||||||
GROUP BY m.id, states, act.res_model;
|
|
||||||
"""
|
|
||||||
self.env.cr.execute(query, {
|
|
||||||
'today': fields.Date.context_today(self),
|
|
||||||
'user_id': self.env.uid,
|
|
||||||
})
|
|
||||||
activity_data = self.env.cr.dictfetchall()
|
|
||||||
model_ids = [a['id'] for a in activity_data]
|
|
||||||
model_names = {n[0]: n[1] for n in self.env['ir.model'].browse(model_ids).name_get()}
|
|
||||||
|
|
||||||
user_activities = {}
|
user_activities = {}
|
||||||
for activity in activity_data:
|
for model_name, activities_by_record in activities_by_record_by_model_name.items():
|
||||||
if not user_activities.get(activity['model']):
|
domain = [("id", "in", list({r.id for r in activities_by_record.keys()}))]
|
||||||
module = self.env[activity['model']]._original_module
|
allowed_records = self.env[model_name].search(domain)
|
||||||
icon = module and modules.module.get_module_icon(module)
|
if not allowed_records:
|
||||||
user_activities[activity['model']] = {
|
continue
|
||||||
'name': model_names[activity['id']],
|
module = self.env[model_name]._original_module
|
||||||
'model': activity['model'],
|
icon = module and modules.module.get_module_icon(module)
|
||||||
'type': 'activity',
|
user_activities[model_name] = {
|
||||||
'icon': icon,
|
"name": self.env["ir.model"]._get(model_name).with_prefetch(model_ids).name,
|
||||||
'total_count': 0, 'today_count': 0, 'overdue_count': 0, 'planned_count': 0,
|
"model": model_name,
|
||||||
}
|
"type": "activity",
|
||||||
user_activities[activity['model']]['%s_count' % activity['states']] += activity['count']
|
"icon": icon,
|
||||||
if activity['states'] in ('today', 'overdue'):
|
"total_count": 0,
|
||||||
user_activities[activity['model']]['total_count'] += activity['count']
|
"today_count": 0,
|
||||||
|
"overdue_count": 0,
|
||||||
user_activities[activity['model']]['actions'] = [{
|
"planned_count": 0,
|
||||||
'icon': 'fa-clock-o',
|
"actions": [
|
||||||
'name': 'Summary',
|
{
|
||||||
}]
|
"icon": "fa-clock-o",
|
||||||
|
"name": "Summary",
|
||||||
|
}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
for record, activities in activities_by_record.items():
|
||||||
|
if record not in allowed_records:
|
||||||
|
continue
|
||||||
|
for activity in activities:
|
||||||
|
user_activities[model_name]["%s_count" % activity.state] += 1
|
||||||
|
if activity.state in ("today", "overdue"):
|
||||||
|
user_activities[model_name]["total_count"] += 1
|
||||||
return list(user_activities.values())
|
return list(user_activities.values())
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -33,6 +33,11 @@ class IrMailServer(models.Model):
|
|||||||
'Please set it to "TLS (STARTTLS)".')
|
'Please set it to "TLS (STARTTLS)".')
|
||||||
% server.name)
|
% server.name)
|
||||||
|
|
||||||
|
if not server.smtp_user:
|
||||||
|
raise UserError(_(
|
||||||
|
'Please fill the "Username" field with your Outlook/Office365 username (your email address). '
|
||||||
|
'This should be the same account as the one used for the Outlook OAuthentication Token.'))
|
||||||
|
|
||||||
@api.onchange('smtp_encryption')
|
@api.onchange('smtp_encryption')
|
||||||
def _onchange_encryption(self):
|
def _onchange_encryption(self):
|
||||||
"""Do not change the SMTP configuration if it's a Outlook server
|
"""Do not change the SMTP configuration if it's a Outlook server
|
||||||
|
|||||||
@@ -81,11 +81,6 @@ class MicrosoftOutlookMixin(models.AbstractModel):
|
|||||||
if not self.use_microsoft_outlook_service or not self.is_microsoft_outlook_configured:
|
if not self.use_microsoft_outlook_service or not self.is_microsoft_outlook_configured:
|
||||||
raise UserError(_('Please configure your Outlook credentials.'))
|
raise UserError(_('Please configure your Outlook credentials.'))
|
||||||
|
|
||||||
if not self.smtp_user:
|
|
||||||
raise UserError(_(
|
|
||||||
'Please fill the "Username" field with your Outlook/Office365 username (your email address). '
|
|
||||||
'This should be the same account as the one used for the Outlook OAuthentication Token.'))
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'type': 'ir.actions.act_url',
|
'type': 'ir.actions.act_url',
|
||||||
'url': self.microsoft_outlook_uri,
|
'url': self.microsoft_outlook_uri,
|
||||||
|
|||||||
@@ -120,12 +120,6 @@ class StockMove(models.Model):
|
|||||||
for move in self:
|
for move in self:
|
||||||
move.order_finished_lot_ids = move.raw_material_production_id.lot_producing_id
|
move.order_finished_lot_ids = move.raw_material_production_id.lot_producing_id
|
||||||
|
|
||||||
@api.model
|
|
||||||
def _prepare_merge_moves_distinct_fields(self):
|
|
||||||
distinct_fields = super()._prepare_merge_moves_distinct_fields()
|
|
||||||
distinct_fields.append('bom_line_id')
|
|
||||||
return distinct_fields
|
|
||||||
|
|
||||||
@api.depends('raw_material_production_id.bom_id')
|
@api.depends('raw_material_production_id.bom_id')
|
||||||
def _compute_allowed_operation_ids(self):
|
def _compute_allowed_operation_ids(self):
|
||||||
for move in self:
|
for move in self:
|
||||||
@@ -380,7 +374,8 @@ class StockMove(models.Model):
|
|||||||
def _prepare_merge_moves_distinct_fields(self):
|
def _prepare_merge_moves_distinct_fields(self):
|
||||||
distinct_fields = super()._prepare_merge_moves_distinct_fields()
|
distinct_fields = super()._prepare_merge_moves_distinct_fields()
|
||||||
distinct_fields.append('created_production_id')
|
distinct_fields.append('created_production_id')
|
||||||
distinct_fields.append('bom_line_id')
|
if self.bom_line_id and ("phantom" in self.bom_line_id.bom_id.mapped('type')):
|
||||||
|
distinct_fields.append('bom_line_id')
|
||||||
return distinct_fields
|
return distinct_fields
|
||||||
|
|
||||||
@api.model
|
@api.model
|
||||||
|
|||||||
@@ -1433,3 +1433,6 @@ class Picking(models.Model):
|
|||||||
body=message,
|
body=message,
|
||||||
)
|
)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def _get_report_lang(self):
|
||||||
|
return self.move_lines and self.move_lines[0].partner_id.lang or self.partner_id.lang or self.env.lang
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
<template id="report_delivery_document">
|
<template id="report_delivery_document">
|
||||||
<t t-call="web.html_container">
|
<t t-call="web.html_container">
|
||||||
<t t-call="web.external_layout">
|
<t t-call="web.external_layout">
|
||||||
<t t-set="o" t-value="o.with_context(lang=o.partner_id.lang or o.env.lang)" />
|
<t t-set="o" t-value="o.with_context(lang=o._get_report_lang())" />
|
||||||
<t t-set="partner" t-value="o.partner_id or (o.move_lines and o.move_lines[0].partner_id) or False"/>
|
<t t-set="partner" t-value="o.partner_id or (o.move_lines and o.move_lines[0].partner_id) or False"/>
|
||||||
<t t-if="partner" name="partner_header">
|
<t t-if="partner" name="partner_header">
|
||||||
<t t-set="address">
|
<t t-set="address">
|
||||||
@@ -229,7 +229,7 @@
|
|||||||
|
|
||||||
<template id="report_deliveryslip">
|
<template id="report_deliveryslip">
|
||||||
<t t-foreach="docs" t-as="o">
|
<t t-foreach="docs" t-as="o">
|
||||||
<t t-call="stock.report_delivery_document" t-lang="o.partner_id.lang or o.env.lang"/>
|
<t t-call="stock.report_delivery_document" t-lang="o._get_report_lang()"/>
|
||||||
</t>
|
</t>
|
||||||
</template>
|
</template>
|
||||||
</flectra>
|
</flectra>
|
||||||
@@ -74,6 +74,15 @@ class MailTestMultiCompany(models.Model):
|
|||||||
name = fields.Char()
|
name = fields.Char()
|
||||||
company_id = fields.Many2one('res.company')
|
company_id = fields.Many2one('res.company')
|
||||||
|
|
||||||
|
class MailTestMultiCompanyWithActivity(models.Model):
|
||||||
|
""" This model can be used in multi company tests with activity"""
|
||||||
|
_name = "mail.test.multi.company.with.activity"
|
||||||
|
_description = "Test Multi Company Mail With Activity"
|
||||||
|
_inherit = ["mail.thread", "mail.activity.mixin"]
|
||||||
|
|
||||||
|
name = fields.Char()
|
||||||
|
company_id = fields.Many2one("res.company")
|
||||||
|
|
||||||
|
|
||||||
class MailTestSelectionTracking(models.Model):
|
class MailTestSelectionTracking(models.Model):
|
||||||
""" Test tracking for selection fields """
|
""" Test tracking for selection fields """
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ access_mail_test_cc_portal,mail.test.cc.portal,model_mail_test_cc,base.group_por
|
|||||||
access_mail_test_cc_user,mail.test.cc.user,model_mail_test_cc,base.group_user,1,1,1,1
|
access_mail_test_cc_user,mail.test.cc.user,model_mail_test_cc,base.group_user,1,1,1,1
|
||||||
access_mail_test_multi_company_user,mail.test.multi.company.user,model_mail_test_multi_company,base.group_user,1,1,1,1
|
access_mail_test_multi_company_user,mail.test.multi.company.user,model_mail_test_multi_company,base.group_user,1,1,1,1
|
||||||
access_mail_test_multi_company_portal,mail.test.multi.company.portal,model_mail_test_multi_company,base.group_portal,1,0,0,0
|
access_mail_test_multi_company_portal,mail.test.multi.company.portal,model_mail_test_multi_company,base.group_portal,1,0,0,0
|
||||||
|
access_mail_test_multi_company_with_activity_user,mail.test.multi.company.with.activity.user,model_mail_test_multi_company_with_activity,base.group_user,1,1,1,1
|
||||||
|
access_mail_test_multi_company_with_activity_portal,mail.test.multi.company.with.activity.portal,model_mail_test_multi_company_with_activity,base.group_portal,1,0,0,0
|
||||||
access_mail_test_track_compute,mail.test.track.compute,model_mail_test_track_compute,base.group_user,1,1,1,1
|
access_mail_test_track_compute,mail.test.track.compute,model_mail_test_track_compute,base.group_user,1,1,1,1
|
||||||
access_mail_test_track_selection_portal,mail.test.track.selection.portal,model_mail_test_track_selection,base.group_portal,0,0,0,0
|
access_mail_test_track_selection_portal,mail.test.track.selection.portal,model_mail_test_track_selection,base.group_portal,0,0,0,0
|
||||||
access_mail_test_track_selection_user,mail.test.track.selection.user,model_mail_test_track_selection,base.group_user,1,1,1,1
|
access_mail_test_track_selection_user,mail.test.track.selection.user,model_mail_test_track_selection,base.group_user,1,1,1,1
|
||||||
|
@@ -8,4 +8,11 @@
|
|||||||
<field name="domain_force">['|', ('company_id', '=', False), ('company_id', 'in', company_ids)]</field>
|
<field name="domain_force">['|', ('company_id', '=', False), ('company_id', 'in', company_ids)]</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
|
<record id="mail_test_multi_company_with_activity_rule" model="ir.rule">
|
||||||
|
<field name="name">Mail Test Multi Company With Activity</field>
|
||||||
|
<field name="model_id" ref="test_mail.model_mail_test_multi_company_with_activity"/>
|
||||||
|
<field eval="True" name="global"/>
|
||||||
|
<field name="domain_force">['|', ('company_id', '=', False), ('company_id', 'in', company_ids)]</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
</flectra>
|
</flectra>
|
||||||
@@ -108,3 +108,45 @@ class TestMultiCompanySetup(TestMailCommon, TestRecipients):
|
|||||||
"%s %s" % (company_3.name, test_record.name),
|
"%s %s" % (company_3.name, test_record.name),
|
||||||
"%s@%s" % (self.alias_catchall, self.alias_domain)))
|
"%s@%s" % (self.alias_catchall, self.alias_domain)))
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_systray_get_activities(self):
|
||||||
|
self.env["mail.activity"].search([]).unlink()
|
||||||
|
user_admin = self.user_admin.with_user(self.user_admin)
|
||||||
|
test_records = self.env["mail.test.multi.company.with.activity"].create(
|
||||||
|
[
|
||||||
|
{"name": "Test1", "company_id": user_admin.company_id.id},
|
||||||
|
{"name": "Test2", "company_id": self.company_2.id},
|
||||||
|
]
|
||||||
|
)
|
||||||
|
test_records[0].activity_schedule("test_mail.mail_act_test_todo", user_id=user_admin.id)
|
||||||
|
test_records[1].activity_schedule("test_mail.mail_act_test_todo", user_id=user_admin.id)
|
||||||
|
res_all = user_admin.systray_get_activities()
|
||||||
|
self.assertEqual(
|
||||||
|
res_all[0],
|
||||||
|
{
|
||||||
|
"actions": [{"icon": "fa-clock-o", "name": "Summary"}],
|
||||||
|
"icon": "/base/static/description/icon.png",
|
||||||
|
"model": "mail.test.multi.company.with.activity",
|
||||||
|
"name": "Test Multi Company Mail With Activity",
|
||||||
|
"overdue_count": 0,
|
||||||
|
"planned_count": 0,
|
||||||
|
"today_count": 2,
|
||||||
|
"total_count": 2,
|
||||||
|
"type": "activity",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
res_c2 = user_admin.with_context(allowed_company_ids=[self.company_2.id]).systray_get_activities()
|
||||||
|
self.assertEqual(
|
||||||
|
res_c2[0],
|
||||||
|
{
|
||||||
|
"actions": [{"icon": "fa-clock-o", "name": "Summary"}],
|
||||||
|
"icon": "/base/static/description/icon.png",
|
||||||
|
"model": "mail.test.multi.company.with.activity",
|
||||||
|
"name": "Test Multi Company Mail With Activity",
|
||||||
|
"overdue_count": 0,
|
||||||
|
"planned_count": 0,
|
||||||
|
"today_count": 1,
|
||||||
|
"total_count": 1,
|
||||||
|
"type": "activity",
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -205,7 +205,10 @@ class WebsiteForm(http.Controller):
|
|||||||
model_name = model.sudo().model
|
model_name = model.sudo().model
|
||||||
if model_name == 'mail.mail':
|
if model_name == 'mail.mail':
|
||||||
values.update({'reply_to': values.get('email_from')})
|
values.update({'reply_to': values.get('email_from')})
|
||||||
record = request.env[model_name].with_user(SUPERUSER_ID).with_context(mail_create_nosubscribe=True).create(values)
|
record = request.env[model_name].with_user(SUPERUSER_ID).with_context(
|
||||||
|
mail_create_nosubscribe=True,
|
||||||
|
commit_assetsbundle=False,
|
||||||
|
).create(values)
|
||||||
|
|
||||||
if custom or meta:
|
if custom or meta:
|
||||||
_custom_label = "%s\n___________\n\n" % _("Other Information:") # Title for custom fields
|
_custom_label = "%s\n___________\n\n" % _("Other Information:") # Title for custom fields
|
||||||
|
|||||||
Reference in new issue
Block a user