diff --git a/addons/account/data/account_data.xml b/addons/account/data/account_data.xml
index 4381b3b14f9..a8c1d83daef 100644
--- a/addons/account/data/account_data.xml
+++ b/addons/account/data/account_data.xml
@@ -195,6 +195,7 @@
\n"
+" Apreciat ${object.partner_id.name}\n"
+" % if object.partner_id.parent_id:\n"
+" (${object.partner_id.parent_id.name})\n"
+" % endif\n"
+"
\n"
+" Li fem arribar la seva \n"
+" % if object.number:\n"
+" factura ${object.number}\n"
+" % else:\n"
+" factura\n"
+" %endif\n"
+" % if object.origin:\n"
+" (amb referència: ${object.origin})\n"
+" % endif\n"
+" per valor de ${format_amount(object.amount_total, object.currency_id)}\n"
+" de ${object.company_id.name}.\n"
+" % if object.state=='paid':\n"
+" Aquesta factura ja està pagada.\n"
+" % else:\n"
+" Si us plau, feu aquest pagament amb la major brevetat possible.\n"
+" % endif\n"
+"
\n"
+" No dubti en contactar amb nosaltres si té qualsevol dubte.\n"
+"
\n"
" Уважаемый ${object.partner_id.name} How do account types affect your reports? Profit & Loss Income Minus Cost of Revenue GROSS PROFIT Plus Other Income Minus Expenses Expenses Depreciation NET PROFIT Balance Sheet Current Assets Receivable Accounts Prepayments Plus Bank Plus Fixed Assets Plus Non-Current Assets TOTAL ASSETS Minus Current Liabilities Minus Credit Card Accounts Minus Payable Accounts Minus Non-Current Liabilities NET ASSETS Equity Plus Net Profit TOTAL EQUITY
\n"
" Спасибо за оплату.\n"
-" Вот ваш платеж ${(object.name or '').replace('/','-')} на сумму\n"
+" Вот ваш платёж ${(object.name or '').replace('/','-')} на сумму\n"
" ${format_amount(object.amount, object.currency_id)} от ${object.company_id.name}.\n"
"
\n"
-" Не стесняйтесь обращаться к нам, если у вас есть какие-либо вопросы..\n"
+" Не стесняйтесь обращаться к нам, если у вас возникли какие-либо вопросы.\n"
"
\n"
" С наилучшими пожеланиями,
\n"
" % if user and user.signature:\n"
@@ -580,22 +581,22 @@ msgstr "Журнал:"
#. module: account
#: model_terms:ir.ui.view,arch_db:account.report_payment_receipt_document
msgid "Memo: "
-msgstr "Заметка."
+msgstr "Заметка:"
#. module: account
#: model_terms:ir.ui.view,arch_db:account.report_payment_receipt_document
msgid "Payment Amount: "
-msgstr "Сумма платежа"
+msgstr "Сумма платежа:"
#. module: account
#: model_terms:ir.ui.view,arch_db:account.report_payment_receipt_document
msgid "Payment Date: "
-msgstr "Дата платежа"
+msgstr "Дата платежа:"
#. module: account
#: model_terms:ir.ui.view,arch_db:account.report_payment_receipt_document
msgid "Payment Method: "
-msgstr "Метода платежа"
+msgstr "Метод платежа:"
#. module: account
#: model_terms:ir.ui.view,arch_db:account.report_invoice_document
@@ -610,7 +611,7 @@ msgstr "Источник:"
#. module: account
#: model_terms:ir.ui.view,arch_db:account.report_invoice_document
msgid "Subtotal"
-msgstr "Подытог"
+msgstr "Промежуточный итог"
#. module: account
#: model_terms:ir.ui.view,arch_db:account.report_journal
@@ -716,23 +717,21 @@ msgid ""
"the sum of line subtotals equals the total with taxes."
msgstr ""
"Округление по строкам рекомендуется использовать, если ваши цены включают "
-"налоги. В этом случае, сумма подитогов по строке будет эквивалентна итогу, "
-"включающему налоги."
+"налоги. В этом случае, сумма промежуточных итогов по строке будет "
+"эквивалентна итогу, включающему налоги."
#. module: account
#: code:addons/account/models/account_bank_statement.py:527
#: code:addons/account/models/account_bank_statement.py:530
#, python-format
msgid "A selected move line was already reconciled."
-msgstr "Выбранная строка была уже сверена"
+msgstr "Выбранная строка была уже сверена."
#. module: account
#: code:addons/account/models/account_bank_statement.py:538
#, python-format
msgid "A selected statement line was already reconciled with an account move."
-msgstr ""
-"Выбранная строка оператора уже была согласована с перемещением учетной "
-"записи."
+msgstr "Выбранная строка уже была согласована с перемещением учётной записи."
#. module: account
#: sql_constraint:account.fiscal.position.tax:0
@@ -827,13 +826,13 @@ msgstr ""
#. module: account
#: model:ir.actions.act_window,name:account.action_account_group_tree
msgid "Account Groups"
-msgstr "Группы Счетов"
+msgstr "Группы счетов"
#. module: account
#: model:ir.model.fields,field_description:account.field_account_journal__company_partner_id
#: model:ir.model.fields,field_description:account.field_account_setup_bank_manual_config__partner_id
msgid "Account Holder"
-msgstr "Владелец счета"
+msgstr "Владелец счёта"
#. module: account
#: model:ir.model.fields,field_description:account.field_account_setup_bank_manual_config__acc_holder_name
@@ -924,7 +923,7 @@ msgstr "Тег счёта"
#. module: account
#: model:ir.actions.act_window,name:account.account_tag_action
msgid "Account Tags"
-msgstr "Тэги Счетов"
+msgstr "Теги счетов"
#. module: account
#: model_terms:ir.ui.view,arch_db:account.account_tax_view_tree
@@ -937,7 +936,7 @@ msgstr "Счёт налога"
#: model_terms:ir.ui.view,arch_db:account.view_account_tax_template_form
#: model_terms:ir.ui.view,arch_db:account.view_account_tax_template_tree
msgid "Account Tax Template"
-msgstr "Шаблон налогового счета"
+msgstr "Шаблон налогового счёта"
#. module: account
#: model:ir.model.fields,field_description:account.field_res_config_settings__module_account_taxcloud
@@ -950,7 +949,7 @@ msgstr ""
#: model_terms:ir.ui.view,arch_db:account.view_account_template_search
#: model_terms:ir.ui.view,arch_db:account.view_account_template_tree
msgid "Account Template"
-msgstr "Шаблон счета"
+msgstr "Шаблон счёта"
#. module: account
#: model:ir.model.fields,field_description:account.field_account_chart_template__property_stock_valuation_account_id
@@ -984,7 +983,7 @@ msgid ""
" entries."
msgstr ""
"Тип счёта используется в информационных целях, при создании официальных "
-"отчетов для конкретной страны, определении правил закрытия финансового года "
+"отчётов для конкретной страны, определении правил закрытия финансового года "
"и проводок открытия."
#. module: account
@@ -1049,7 +1048,7 @@ msgid ""
"Account that will be set on invoice tax lines for invoices. Leave empty to "
"use the expense account."
msgstr ""
-"Банковский счёт который будет указан в строках, соответствующих налогам в "
+"Банковский счёт, который будет указан в строках, соответствующих налогам в "
"счёте на оплату. Если оставить это поле пустым, будет использоваться "
"расходный счёт."
@@ -1059,7 +1058,7 @@ msgid ""
"Account that will be set on invoice tax lines for refunds. Leave empty to "
"use the expense account."
msgstr ""
-"Банковский счёт который будет указан как счёт для возврата в строках, "
+"Банковский счёт, который будет указан как счёт для возврата в строках, "
"соответствующих налогам в счёте на оплату. Если оставить это поле пустым, "
"будет использоваться расходный счёт."
@@ -1305,7 +1304,7 @@ msgstr "Дополнительная информация"
#. module: account
#: model_terms:ir.ui.view,arch_db:account.invoice_supplier_form
msgid "Additional notes..."
-msgstr "Дополнительные заметки ..."
+msgstr "Дополнительные заметки..."
#. module: account
#: selection:account.tax,type_tax_use:0
@@ -1450,7 +1449,7 @@ msgstr "Разрешить печать чеков и депозиты"
#. module: account
#: model:res.groups,name:account.group_cash_rounding
msgid "Allow the cash rounding management"
-msgstr "Разрешает управление округлением наличности"
+msgstr "Разрешить управление округлением наличности"
#. module: account
#: model_terms:ir.ui.view,arch_db:account.res_config_settings_view_form
@@ -1805,13 +1804,13 @@ msgstr ""
#: model:ir.model.fields,help:account.field_account_fiscal_position__country_id
#: model:ir.model.fields,help:account.field_account_fiscal_position_template__country_id
msgid "Apply only if delivery or invoicing country match."
-msgstr "Применить только если страна доставки или счёта совпадают."
+msgstr "Применить, только если страна доставки или счёта совпадают."
#. module: account
#: model:ir.model.fields,help:account.field_account_fiscal_position__vat_required
#: model:ir.model.fields,help:account.field_account_fiscal_position_template__vat_required
msgid "Apply only if partner has a VAT number."
-msgstr "Применить если партнеру указано значение НДС."
+msgstr "Применить, если партнёру указано значение НДС."
#. module: account
#: model_terms:ir.ui.view,arch_db:account.res_config_settings_view_form
@@ -1853,7 +1852,7 @@ msgstr "Управление активами"
#. module: account
#: model:ir.model.fields,field_description:account.field_account_chart_template__account_ids
msgid "Associated Account Templates"
-msgstr "Связанные шаблоны счета"
+msgstr "Связанные шаблоны счёта"
#. module: account
#: model:ir.model.fields,field_description:account.field_account_journal__at_least_one_inbound
@@ -1908,7 +1907,7 @@ msgid ""
" did not match any partner."
msgstr ""
"Автор сообщения. Если не установлен, email_from может содержать адрес почты,"
-" который не соответствует ни одному партнеру."
+" который не соответствует ни одному партнёру."
#. module: account
#: model:ir.model.fields,field_description:account.field_account_invoice_send__author_avatar
@@ -2018,7 +2017,7 @@ msgstr "Балансовая ведомость"
#. module: account
#: model:ir.model.fields,help:account.field_account_bank_statement__balance_end
msgid "Balance as calculated based on Opening Balance and transaction lines"
-msgstr "Баланс вычисляется основываясь на начальном балансе и операциях"
+msgstr "Баланс вычисляется, основываясь на начальном балансе и операциях"
#. module: account
#: selection:account.journal,type:0
@@ -2055,7 +2054,7 @@ msgstr ""
#. module: account
#: model:ir.model.fields,field_description:account.field_account_bank_statement_line__account_number
msgid "Bank Account Number"
-msgstr "Номер банковского счета"
+msgstr "Номер банковского счёта"
#. module: account
#: model:ir.model.fields,help:account.field_account_invoice__partner_bank_id
@@ -2271,7 +2270,7 @@ msgstr "Дата выставления счёта"
#. module: account
#: model_terms:ir.ui.view,arch_db:account.invoice_supplier_form
msgid "Bill lines"
-msgstr "Строки счета"
+msgstr "Строки счёта"
#. module: account
#: model:res.groups,name:account.group_account_invoice
@@ -2319,7 +2318,7 @@ msgstr "Блокирующее сообщение"
#. module: account
#: model:ir.model.fields,field_description:account.field_account_account_type__include_initial_balance
msgid "Bring Accounts Balance Forward"
-msgstr "Перенос баланса счетов вперёд."
+msgstr "Перенос баланса счетов вперёд"
#. module: account
#: model_terms:ir.actions.act_window,help:account.open_account_journal_dashboard_kanban
@@ -2367,7 +2366,8 @@ msgstr "По продавцу"
msgid ""
"By unchecking the active field, you may hide a fiscal position without "
"deleting it."
-msgstr "Вы можете скрыть позицию системы налогов без её удаления сняв флажок."
+msgstr ""
+"Вы можете скрыть позицию системы налогов без её удаления, сняв флажок."
#. module: account
#: model:ir.model.fields,help:account.field_account_incoterms__active
@@ -2476,7 +2476,7 @@ msgstr ""
#: code:addons/account/models/account_move.py:358
#, python-format
msgid "Cannot create moves for different companies."
-msgstr "Нельзя создать операцию для различных компаний"
+msgstr "Нельзя создать операцию для различных компаний."
#. module: account
#: code:addons/account/models/account_move.py:390
@@ -2491,7 +2491,7 @@ msgid ""
"Cannot find a chart of accounts for this company, You should configure it. \n"
"Please go to Account Configuration."
msgstr ""
-"Не могу найти план счетов для этой компании, Вы следует настроить его. \n"
+"Не могу найти план счетов для этой компании, Вам следует настроить его. \n"
"Пожалуйста, перейдите в настройки счёта."
#. module: account
@@ -2581,7 +2581,7 @@ msgstr "Округления наличности"
#: code:addons/account/models/account_bank_statement.py:187
#, python-format
msgid "Cash difference observed during the counting (%s)"
-msgstr "Денежная разница наблюдается при подсчете (%s)"
+msgstr "Денежная разница наблюдается при подсчёте (%s)"
#. module: account
#: code:addons/account/models/account_journal_dashboard.py:34
@@ -2706,7 +2706,7 @@ msgstr "Проверьте итоговый баланс"
#. module: account
#: model:ir.model.fields,help:account.field_account_bank_statement__is_difference_zero
msgid "Check if difference is zero."
-msgstr "Проверять если разница нулевая."
+msgstr "Проверять, если разница нулевая."
#. module: account
#: model:ir.model.fields,help:account.field_account_account__reconcile
@@ -2714,8 +2714,8 @@ msgid ""
"Check this box if this account allows invoices & payments matching of "
"journal items."
msgstr ""
-"Поставьте тут флажок, если данный счёт допускает сверку позиций журнала со "
-"счетами-фактурами и оплатами."
+"Установите этот флажок, если данный счёт допускает сверку позиций журнала со"
+" счетами-фактурами и оплатами."
#. module: account
#: model:ir.model.fields,help:account.field_account_journal__refund_sequence
@@ -2723,8 +2723,8 @@ msgid ""
"Check this box if you don't want to share the same sequence for invoices and"
" credit notes made from this journal"
msgstr ""
-"Установите это, если не хотите сквозную нумерацию счетов и кредитных авизо, "
-"относящихся к этому журналу "
+"Установите этот флажок, если не хотите сквозную нумерацию счетов и кредитных"
+" авизо, относящихся к этому журналу "
#. module: account
#: model:ir.model.fields,help:account.field_account_journal__update_posted
@@ -2732,8 +2732,8 @@ msgid ""
"Check this box if you want to allow the cancellation the entries related to "
"this journal or of the invoice related to this journal"
msgstr ""
-"Отметьте, если вы хотите включить возможность отмены проводок, связанных с "
-"этим журналом, или позиций из счетов, связанных с этим журналом"
+"Установите этот флажок, если вы хотите включить возможность отмены проводок,"
+" связанных с этим журналом, или позиций из счетов, связанных с этим журналом"
#. module: account
#: model:ir.model.fields,help:account.field_account_tax__price_include
@@ -2741,14 +2741,16 @@ msgstr ""
msgid ""
"Check this if the price you use on the product and invoices includes this "
"tax."
-msgstr "Отметьте, если цена продукта и счёта включают этот налог."
+msgstr ""
+"Установите этот флажок, если цена продукта и счёта включают этот налог."
#. module: account
#: model:ir.model.fields,help:account.field_account_account_template__reconcile
msgid ""
"Check this option if you want the user to reconcile entries in this account."
msgstr ""
-"Отметьте, если вы хотите, чтобы пользователь сверял проводки по этому счету."
+"Установите этот флажок, если вы хотите, чтобы пользователь сверял проводки "
+"по этому счёту."
#. module: account
#: model_terms:ir.ui.view,arch_db:account.res_config_settings_view_form
@@ -2804,14 +2806,14 @@ msgstr ""
#: code:addons/account/static/src/js/tour.js:19
#, python-format
msgid "Click to send the invoice by email."
-msgstr "Кликните, чтобы отослать счет по эл.почте."
+msgstr "Нажмите, чтобы отослать счёт по эл. почте."
#. module: account
#. openerp-web
#: code:addons/account/static/src/js/tour.js:23
#, python-format
msgid "Click to send the invoice."
-msgstr "Кликните, чтобы послать счет."
+msgstr "Нажмите, чтобы отослать счёт."
#. module: account
#. openerp-web
@@ -2821,7 +2823,7 @@ msgid ""
"Click to validate your invoice. A reference will be assigned to this "
"invoice and you will not be able to modify it anymore."
msgstr ""
-"Нажмите, чтобы подтвердить свой счет. Счет получит номер и вы не "
+"Нажмите, чтобы подтвердить свой счёт. Счёт получит номер и вы не "
"сможете больше его менять."
#. module: account
@@ -2917,7 +2919,7 @@ msgstr ""
#. module: account
#: model:ir.actions.act_window,name:account.action_account_common_menu
msgid "Common Report"
-msgstr "Общий отчет"
+msgstr "Общий отчёт"
#. module: account
#: model:ir.model.fields,field_description:account.field_res_config_settings__invoice_reference_type
diff --git a/addons/account/i18n/uk.po b/addons/account/i18n/uk.po
index ef6a4522a7b..cfc5c971788 100644
--- a/addons/account/i18n/uk.po
+++ b/addons/account/i18n/uk.po
@@ -476,7 +476,7 @@ msgstr ""
#. module: account
#: model_terms:ir.ui.view,arch_db:account.report_invoice_document
msgid "Quantity"
-msgstr ""
+msgstr "Кількість"
#. module: account
#: model_terms:ir.ui.view,arch_db:account.account_journal_dashboard_kanban_view
diff --git a/addons/account/i18n/zh_CN.po b/addons/account/i18n/zh_CN.po
index 39ae8e9db22..c2a7c9ec935 100644
--- a/addons/account/i18n/zh_CN.po
+++ b/addons/account/i18n/zh_CN.po
@@ -71,7 +71,7 @@ msgstr "# 数字"
#. module: account
#: model:mail.template,report_name:account.mail_template_data_payment_receipt
msgid "${(object.name or '').replace('/','-')}"
-msgstr "${(object.name or '').取代('/','-')}"
+msgstr "${(object.name or '').replace('/','-')}"
#. module: account
#: model:mail.template,subject:account.email_template_edi_invoice
@@ -4274,7 +4274,7 @@ msgstr "发现重复的供应商。你可能重复记录了同一供应商的账
#. module: account
#: model:ir.model.fields,field_description:account.field_res_config_settings__module_account_reports
msgid "Dynamic Reports"
-msgstr "动态报表"
+msgstr "动态报告"
#. module: account
#: model:ir.model.fields,field_description:account.field_res_config_settings__module_l10n_eu_service
diff --git a/addons/account/models/account_bank_statement.py b/addons/account/models/account_bank_statement.py
index 4a2b0824d24..d57fb164ee4 100644
--- a/addons/account/models/account_bank_statement.py
+++ b/addons/account/models/account_bank_statement.py
@@ -324,6 +324,16 @@ class AccountBankStatementLine(models.Model):
if self.amount_currency != 0 and self.amount == 0:
raise ValidationError(_('If "Amount Currency" is specified, then "Amount" must be as well.'))
+ @api.constrains('currency_id', 'journal_id')
+ def _check_currency_id(self):
+ for line in self:
+ if not line.currency_id:
+ continue
+
+ statement_currency = line.journal_id.currency_id or line.company_id.currency_id
+ if line.currency_id == statement_currency:
+ raise ValidationError(_('The currency of the bank statement line must be different than the statement currency.'))
+
@api.model
def create(self, vals):
line = super(AccountBankStatementLine, self).create(vals)
@@ -657,7 +667,13 @@ class AccountBankStatementLine(models.Model):
#create the res.partner.bank if needed
if self.account_number and self.partner_id and not self.bank_account_id:
- self.bank_account_id = self.env['res.partner.bank'].create({'acc_number': self.account_number, 'partner_id': self.partner_id.id}).id
+ bank_account = self.env['res.partner.bank'].search(
+ [('acc_number', '=', self.account_number), ('partner_id', '=', self.partner_id.id)])
+ if not bank_account:
+ bank_account = self.env['res.partner.bank'].create({
+ 'acc_number': self.account_number, 'partner_id': self.partner_id.id
+ })
+ self.bank_account_id = bank_account
counterpart_moves.assert_balanced()
return counterpart_moves
diff --git a/addons/account/models/account_invoice.py b/addons/account/models/account_invoice.py
index 391a151e2c7..465fab791e0 100644
--- a/addons/account/models/account_invoice.py
+++ b/addons/account/models/account_invoice.py
@@ -1578,6 +1578,7 @@ class AccountInvoiceLine(models.Model):
help="Gives the sequence of this line when displaying the invoice.")
invoice_id = fields.Many2one('account.invoice', string='Invoice Reference',
ondelete='cascade', index=True)
+ invoice_type = fields.Selection(related='invoice_id.type', readonly=True)
uom_id = fields.Many2one('uom.uom', string='Unit of Measure',
ondelete='set null', index=True, oldname='uos_id')
product_id = fields.Many2one('product.product', string='Product',
diff --git a/addons/account/models/account_reconcile_model.py b/addons/account/models/account_reconcile_model.py
index bd89394733d..0941a34fb2f 100644
--- a/addons/account/models/account_reconcile_model.py
+++ b/addons/account/models/account_reconcile_model.py
@@ -392,14 +392,17 @@ class AccountReconcileModel(models.Model):
aml.date_maturity AS aml_date_maturity,
aml.amount_residual AS aml_amount_residual,
aml.amount_residual_currency AS aml_amount_residual_currency,
- CASE WHEN
- REGEXP_REPLACE(st_line.name, '[^0-9]', '', 'g') ~ REGEXP_REPLACE(move.name, '[^0-9]', '', 'g')
- OR (
- move.ref IS NOT NULL
- AND
- REGEXP_REPLACE(st_line.name, '[^0-9]', '', 'g') ~ REGEXP_REPLACE(move.ref, '[^0-9]', '', 'g')
- )
- THEN TRUE ELSE FALSE END AS communication_flag
+ CASE WHEN TRIM(REGEXP_REPLACE(move.name, '[^0-9]', '', 'g')) = '' THEN FALSE
+ ELSE
+ TRIM(REGEXP_REPLACE(move.name, '[^0-9]', '', 'g'))
+ = ANY(regexp_split_to_array(REGEXP_REPLACE(st_line.name, '[^(0-9|\s)]', '', 'g'), '\s+'))
+ OR (
+ move.ref IS NOT NULL
+ AND TRIM(REGEXP_REPLACE(move.ref, '[^0-9]', '', 'g')) != ''
+ AND TRIM(REGEXP_REPLACE(move.ref, '[^0-9]', '', 'g'))
+ = ANY(regexp_split_to_array(REGEXP_REPLACE(st_line.name, '[^(0-9|\s)]', '', 'g'), '\s+'))
+ )
+ END AS communication_flag
FROM account_bank_statement_line st_line
LEFT JOIN account_journal journal ON journal.id = st_line.journal_id
LEFT JOIN jnl_precision ON jnl_precision.journal_id = journal.id
@@ -427,13 +430,18 @@ class AccountReconcileModel(models.Model):
AND CASE WHEN line_partner.partner_id != 0 THEN
aml.partner_id = line_partner.partner_id
ELSE
- (
- REGEXP_REPLACE(st_line.name, '[^0-9]', '', 'g') ~ REGEXP_REPLACE(move.name, '[^0-9]', '', 'g')
- OR (
- move.ref IS NOT NULL
- AND
- REGEXP_REPLACE(st_line.name, '[^0-9]', '', 'g') ~ REGEXP_REPLACE(move.ref, '[^0-9]', '', 'g')
- )
+ (
+ CASE WHEN TRIM(REGEXP_REPLACE(move.name, '[^0-9]', '', 'g')) = '' THEN FALSE
+ ELSE
+ TRIM(REGEXP_REPLACE(move.name, '[^0-9]', '', 'g'))
+ = ANY(regexp_split_to_array(REGEXP_REPLACE(st_line.name, '[^(0-9|\s)]', '', 'g'), '\s+'))
+ OR (
+ move.ref IS NOT NULL
+ AND TRIM(REGEXP_REPLACE(move.ref, '[^0-9]', '', 'g')) != ''
+ AND TRIM(REGEXP_REPLACE(move.ref, '[^0-9]', '', 'g'))
+ = ANY(regexp_split_to_array(REGEXP_REPLACE(st_line.name, '[^(0-9|\s)]', '', 'g'), '\s+'))
+ )
+ END
)
END
@@ -676,6 +684,8 @@ class AccountReconcileModel(models.Model):
new_aml_dicts = reconciliation_results['new_aml_dicts']
if reconciliation_results['open_balance_dict']:
new_aml_dicts.append(reconciliation_results['open_balance_dict'])
+ if not line.partner_id and partner:
+ line.partner_id = partner
counterpart_moves = line.process_reconciliation(
counterpart_aml_dicts=reconciliation_results['counterpart_aml_dicts'],
payment_aml_rec=reconciliation_results['payment_aml_rec'],
@@ -707,6 +717,8 @@ class AccountReconcileModel(models.Model):
new_aml_dicts = reconciliation_results['new_aml_dicts']
if reconciliation_results['open_balance_dict']:
new_aml_dicts.append(reconciliation_results['open_balance_dict'])
+ if not line.partner_id and partner:
+ line.partner_id = partner
counterpart_moves = line.process_reconciliation(
counterpart_aml_dicts=reconciliation_results['counterpart_aml_dicts'],
payment_aml_rec=reconciliation_results['payment_aml_rec'],
diff --git a/addons/account/models/reconciliation_widget.py b/addons/account/models/reconciliation_widget.py
index 65f3992c3ba..950cfd60110 100644
--- a/addons/account/models/reconciliation_widget.py
+++ b/addons/account/models/reconciliation_widget.py
@@ -142,12 +142,19 @@ class AccountReconciliation(models.AbstractModel):
bank_statements_left += line.statement_id
amls = aml_ids and self.env['account.move.line'].browse(aml_ids)
- results['lines'].append({
+ line_vals = {
'st_line': self._get_statement_line(line),
'reconciliation_proposition': aml_ids and self._prepare_move_lines(amls) or [],
'model_id': matching_amls[line.id].get('model') and matching_amls[line.id]['model'].id,
'write_off': matching_amls[line.id].get('status') == 'write_off',
- })
+ }
+ if not line.partner_id and partner_map.get(line.id):
+ partner = self.env['res.partner'].browse(partner_map[line.id])
+ line_vals.update({
+ 'partner_id': partner.id,
+ 'partner_name': partner.name,
+ })
+ results['lines'].append(line_vals)
return results
@@ -331,7 +338,11 @@ class AccountReconciliation(models.AbstractModel):
rec_prop = aml_ids and self.env['account.move.line'].browse(aml_ids) or self._get_move_line_reconciliation_proposition(account.id, partner_id)
row['reconciliation_proposition'] = self._prepare_move_lines(rec_prop, target_currency=currency)
row['company_id'] = account.company_id.id
- return rows
+
+ # Return the partners with a reconciliation proposition first, since they are most likely to
+ # be reconciled.
+ return [r for r in rows if r['reconciliation_proposition']] + [r for r in rows if not r['reconciliation_proposition']]
+
@api.model
def process_move_lines(self, data):
diff --git a/addons/account/static/src/js/reconciliation/reconciliation_model.js b/addons/account/static/src/js/reconciliation/reconciliation_model.js
index b3e6d56c2f4..c76768103a9 100644
--- a/addons/account/static/src/js/reconciliation/reconciliation_model.js
+++ b/addons/account/static/src/js/reconciliation/reconciliation_model.js
@@ -365,6 +365,7 @@ var StatementModel = BasicModel.extend({
var handle = _.uniqueId('rline');
self.lines[handle] = {
id: res.st_line.id,
+ partner_id: res.st_line.partner_id,
handle: handle,
reconciled: false,
mode: 'inactive',
@@ -1008,6 +1009,11 @@ var StatementModel = BasicModel.extend({
'display_name': line.reconciliation_proposition[0].partner_name,
}, true);
}
+ }else if(!line.st_line.partner_id && line.partner_id && line.partner_name){
+ return self.changePartner(line.handle, {
+ 'id': line.partner_id,
+ 'display_name': line.partner_name,
+ }, true);
}
return true;
})
@@ -1386,7 +1392,6 @@ var ManualModel = StatementModel.extend({
}
line.reconciliation_proposition = [];
});
-
if (process_reconciliations.length) {
def = self._rpc({
model: 'account.reconciliation.widget',
diff --git a/addons/account/views/account_invoice_view.xml b/addons/account/views/account_invoice_view.xml
index 1e09d4b6935..2617974de75 100644
--- a/addons/account/views/account_invoice_view.xml
+++ b/addons/account/views/account_invoice_view.xml
@@ -77,8 +77,11 @@
"
#. module: auth_signup
#: model:mail.template,body_html:auth_signup.reset_password_email
@@ -226,6 +313,86 @@ msgid ""
"\n"
" "
msgstr ""
+" \n"
+"\n"
+"\n"
+" \n"
+"\n"
+" \n"
+"
\n"
+"\n"
+" \n"
+" \n"
+" \n"
+" \n"
+" \n"
+"
\n"
+" \n"
+" \n"
+" Velkommen til Odoo
\n"
+" \n"
+" ${object.name}\n"
+" \n"
+" \n"
+"
\n"
+" \n"
+" \n"
+"
\n"
+" \n"
+" \n"
+" \n"
+" \n"
+" \n"
+" \n"
+"
\n"
+" \n"
+" \n"
+"
\n"
+" Du er inviteret af ${object.create_uid.name} fra ${object.company_id.name} til at oprette forbindelse til Odoo.\n"
+"
\n"
+" Din registrerings e-mail er: ${object.email}
\n"
+" Har du aldrig hørt om Odoo? Det er et alt-i-et-ERP system, der er har +3 millioner brugere. Det vil forbedre din oplevelse på arbejdspladsen betydeligt og øge produktiviteten.\n"
+"
\n"
+" Prøv at se her Odoo Tour for at opleve systemet\n"
+"
\n"
+" God fornøjelse med Odoo!
\n"
+" --
Hilsen ${object.company_id.name} \n"
+" \n"
+" \n"
+"
\n"
+" \n"
+" \n"
+"\n"
+"\n"
+" \n"
+" \n"
+"
\n"
+" \n"
+" \n"
+" ${object.company_id.name}\n"
+" \n"
+" \n"
+" ${object.company_id.phone}\n"
+" % if object.company_id.email\n"
+" | ${object.company_id.email}\n"
+" % endif\n"
+" % if object.company_id.website\n"
+" | \n"
+" ${object.company_id.website}\n"
+" \n"
+" % endif\n"
+" \n"
+"\n"
+" \n"
+"
\n"
+" \n"
+" \n"
+" Powered by Odoo\n"
+"
\n"
+" "
#. module: auth_signup
#: model:mail.template,body_html:auth_signup.mail_template_user_signup_account_created
@@ -310,11 +477,90 @@ msgid ""
"\n"
""
msgstr ""
+" \n"
+"\n"
+"\n"
+" \n"
+"\n"
+" \n"
+"
\n"
+"\n"
+" \n"
+" \n"
+" \n"
+" \n"
+" \n"
+"
\n"
+" \n"
+" \n"
+" Din konto
\n"
+" \n"
+" ${object.name}\n"
+" \n"
+" \n"
+"
\n"
+" \n"
+" \n"
+"
\n"
+" \n"
+" \n"
+" \n"
+" \n"
+" \n"
+" \n"
+"
\n"
+" \n"
+" \n"
+"
\n"
+" Der blev anmodet om en nulstilling af adgangskoden til den Odoo konto, der var knyttet til denne e-mail.\n"
+" Du kan ændre dit kodeord ved at følge dette link, som forbliver gyldigt i de næste 24 timer:
\n"
+"
\n"
+" Tak,
\n"
+" ${user.signature | safe}
\n"
+" \n"
+" \n"
+"
\n"
+" \n"
+" \n"
+"\n"
+"\n"
+" \n"
+" \n"
+"
\n"
+" \n"
+" \n"
+" ${object.company_id.name}\n"
+" \n"
+" \n"
+" ${object.company_id.phone}\n"
+" % if object.company_id.email\n"
+" | ${object.company_id.email}\n"
+" % endif\n"
+" % if object.company_id.website\n"
+" | \n"
+" ${object.company_id.website}\n"
+" \n"
+" % endif\n"
+" \n"
+"\n"
+" \n"
+"
\n"
+" \n"
+" \n"
+" Powered by Odoo\n"
+"
"
#. module: auth_signup
#: model_terms:ir.ui.view,arch_db:auth_signup.signup
msgid "Already have an account?"
-msgstr ""
+msgstr "Har du allerede en konto?"
#. module: auth_signup
#: code:addons/auth_signup/controllers/main.py:80
@@ -340,7 +586,7 @@ msgstr "Godkendelse mislykkedes."
#. module: auth_signup
#: model_terms:ir.ui.view,arch_db:auth_signup.reset_password
msgid "Back to Login"
-msgstr "Tilbage til log ind"
+msgstr "Tilbage til login"
#. module: auth_signup
#: code:addons/auth_signup/models/res_users.py:199
@@ -356,7 +602,7 @@ msgstr "Luk"
#. module: auth_signup
#: model:ir.model,name:auth_signup.model_res_config_settings
msgid "Config Settings"
-msgstr ""
+msgstr "Konfigurer opsætning"
#. module: auth_signup
#: model_terms:ir.ui.view,arch_db:auth_signup.reset_password
@@ -393,12 +639,12 @@ msgstr "Kunne ikke nulstille din adgangskode"
#. module: auth_signup
#: model:ir.model.fields,field_description:auth_signup.field_res_config_settings__auth_signup_uninvited
msgid "Customer Account"
-msgstr ""
+msgstr "Konto"
#. module: auth_signup
#: model_terms:ir.ui.view,arch_db:auth_signup.res_config_settings_view_form
msgid "Default Access Rights"
-msgstr "Standard Adgangsrettigheder"
+msgstr "Standard adgangsrettigheder"
#. module: auth_signup
#: model_terms:ir.ui.view,arch_db:auth_signup.login
@@ -409,18 +655,18 @@ msgstr "Har ikke en konto?"
#: model:ir.model.fields,field_description:auth_signup.field_res_config_settings__auth_signup_reset_password
#: model_terms:ir.ui.view,arch_db:auth_signup.res_config_settings_view_form
msgid "Enable password reset from Login page"
-msgstr "Tillad nulstilling af adgangskode fra log ind siden."
+msgstr "Tillad nulstilling af adgangskode fra login siden."
#. module: auth_signup
#: model:ir.model,name:auth_signup.model_ir_http
msgid "HTTP Routing"
-msgstr ""
+msgstr "HTTP Routing"
#. module: auth_signup
#: code:addons/auth_signup/controllers/main.py:115
#, python-format
msgid "Invalid signup token"
-msgstr "Ugyldigt tilmeldings token"
+msgstr "Ugyldigt tilmeldingstoken"
#. module: auth_signup
#: model_terms:ir.ui.view,arch_db:auth_signup.res_config_settings_view_form
@@ -436,7 +682,7 @@ msgstr "Aldrig forbundet"
#: code:addons/auth_signup/controllers/main.py:75
#, python-format
msgid "No login provided."
-msgstr ""
+msgstr "Ingen login angivet."
#. module: auth_signup
#: model_terms:ir.ui.view,arch_db:auth_signup.fields
@@ -446,7 +692,7 @@ msgstr "Adgangskode"
#. module: auth_signup
#: model_terms:ir.ui.view,arch_db:auth_signup.res_config_settings_view_form
msgid "Password Reset"
-msgstr ""
+msgstr "Nulstil adgangskode"
#. module: auth_signup
#: model:mail.template,subject:auth_signup.reset_password_email
@@ -457,7 +703,7 @@ msgstr "Nulstilling af adgangskode"
#: code:addons/auth_signup/controllers/main.py:125
#, python-format
msgid "Passwords do not match; please retype them."
-msgstr "Passwordsene matcher ikke; prøv venligst igen."
+msgstr "Adgangskoderne matcher ikke; prøv venligst igen."
#. module: auth_signup
#: model_terms:ir.ui.view,arch_db:auth_signup.login
@@ -468,7 +714,7 @@ msgstr "Nulstil adgangskode"
#: code:addons/auth_signup/models/res_users.py:163
#, python-format
msgid "Reset password: invalid username or email"
-msgstr "Nulstil adgangskode: ugyldigt brugernavn eller email"
+msgstr "Nulstil adgangskode: ugyldigt brugernavn eller e-mail"
#. module: auth_signup
#: model_terms:ir.ui.view,arch_db:auth_signup.res_users_view_form
@@ -478,7 +724,7 @@ msgstr "Send instruktioner til at nulstille adgangskode "
#. module: auth_signup
#: model_terms:ir.ui.view,arch_db:auth_signup.res_users_view_form
msgid "Send an Invitation Email"
-msgstr "Send en invitations email"
+msgstr "Send en invitations e-mail"
#. module: auth_signup
#: model_terms:ir.ui.view,arch_db:auth_signup.signup
@@ -489,67 +735,67 @@ msgstr "Tilmeld dig"
#: model:ir.model.fields,field_description:auth_signup.field_res_partner__signup_expiration
#: model:ir.model.fields,field_description:auth_signup.field_res_users__signup_expiration
msgid "Signup Expiration"
-msgstr ""
+msgstr "Tilmelding er udløb"
#. module: auth_signup
#: model:ir.model.fields,field_description:auth_signup.field_res_partner__signup_token
#: model:ir.model.fields,field_description:auth_signup.field_res_users__signup_token
msgid "Signup Token"
-msgstr ""
+msgstr "Tilmeldingstoken"
#. module: auth_signup
#: model:ir.model.fields,field_description:auth_signup.field_res_partner__signup_type
#: model:ir.model.fields,field_description:auth_signup.field_res_users__signup_type
msgid "Signup Token Type"
-msgstr ""
+msgstr "Type på tilmeldingstoken"
#. module: auth_signup
#: model:ir.model.fields,field_description:auth_signup.field_res_partner__signup_valid
#: model:ir.model.fields,field_description:auth_signup.field_res_users__signup_valid
msgid "Signup Token is Valid"
-msgstr ""
+msgstr "Tilmeldingstoken er gyldig"
#. module: auth_signup
#: model:ir.model.fields,field_description:auth_signup.field_res_partner__signup_url
#: model:ir.model.fields,field_description:auth_signup.field_res_users__signup_url
msgid "Signup URL"
-msgstr ""
+msgstr "Tilmeldings URL"
#. module: auth_signup
#: code:addons/auth_signup/models/res_users.py:117
#, python-format
msgid "Signup is not allowed for uninvited users"
-msgstr ""
+msgstr "Tilmelding er ikke tilladt for ikke inviterede brugere"
#. module: auth_signup
#: code:addons/auth_signup/models/res_partner.py:149
#, python-format
msgid "Signup token '%s' is no longer valid"
-msgstr ""
+msgstr "Tilmeldingstoken '%s' er ikke længere gyldig"
#. module: auth_signup
#: code:addons/auth_signup/models/res_partner.py:145
#, python-format
msgid "Signup token '%s' is not valid"
-msgstr ""
+msgstr "Tilmeldingstoken '%s' er ikke gyldig"
#. module: auth_signup
#: code:addons/auth_signup/models/res_users.py:138
#, python-format
msgid "Signup: invalid template user"
-msgstr ""
+msgstr "Tilmelding: ugyldig skabelonbruger"
#. module: auth_signup
#: code:addons/auth_signup/models/res_users.py:141
#, python-format
msgid "Signup: no login given for new user"
-msgstr ""
+msgstr "Tilmelding: Ingen login er givet til ny bruger"
#. module: auth_signup
#: code:addons/auth_signup/models/res_users.py:143
#, python-format
msgid "Signup: no name or partner given for new user"
-msgstr ""
+msgstr "Tilmelding: Intet navn eller partner er givet til ny bruger"
#. module: auth_signup
#: model:ir.model.fields,field_description:auth_signup.field_res_users__state
@@ -565,13 +811,13 @@ msgstr "\"Skabelonbruger\" for nye brugere, som oprettes gennem tilmelding"
#: code:addons/auth_signup/controllers/main.py:123
#, python-format
msgid "The form was not properly filled in."
-msgstr ""
+msgstr "Formularen blev ikke korrekt udfyldt."
#. module: auth_signup
#: code:addons/auth_signup/models/res_users.py:127
#, python-format
msgid "This is his first connection. Wish him welcome"
-msgstr ""
+msgstr "Dette er hans første forbindelse. Ønsk ham velkommen"
#. module: auth_signup
#: model_terms:ir.ui.view,arch_db:auth_signup.res_config_settings_view_form
@@ -580,6 +826,9 @@ msgid ""
"list view and click on 'Portal Access Management' option in the dropdown "
"menu *Action*."
msgstr ""
+"Hvis du vil sende invitationer i B2B-tilstand, skal du åbne en kontakt eller"
+" vælge flere i listevisning og klikke på 'Portal Access Management' i "
+"rullemenuen *Handling*."
#. module: auth_signup
#: model:ir.model,name:auth_signup.model_res_users
@@ -605,4 +854,4 @@ msgstr "Dit navn"
#. module: auth_signup
#: model_terms:ir.ui.view,arch_db:auth_signup.fields
msgid "e.g. John Doe"
-msgstr ""
+msgstr "e.g. John Doe"
diff --git a/addons/auth_signup/i18n/zh_CN.po b/addons/auth_signup/i18n/zh_CN.po
index 70528de42d9..b17f8d686a4 100644
--- a/addons/auth_signup/i18n/zh_CN.po
+++ b/addons/auth_signup/i18n/zh_CN.po
@@ -5,8 +5,9 @@
# Translators:
# Martin Trigaux, 2018
# ChinaMaker \n"
+"\n"
+"\n"
+" \n"
+"\n"
+" \n"
+"
\n"
+"\n"
+" \n"
+" \n"
+" \n"
+" \n"
+" \n"
+"
\n"
+" \n"
+" \n"
+" Din konto
\n"
+" \n"
+" ${object.name}\n"
+" \n"
+" \n"
+"
\n"
+" \n"
+" \n"
+"
\n"
+" \n"
+" \n"
+" \n"
+" \n"
+" \n"
+" \n"
+"
\n"
+" \n"
+" \n"
+"
\n"
+" Din konto er blevet oprettet!
\n"
+" Dit login er ${object.email}
\n"
+" For at få adgang til din konto, kan du bruge følgende link:\n"
+"
\n"
+" ${user.signature | safe}
\n"
+" \n"
+" \n"
+"
\n"
+" \n"
+" \n"
+"\n"
+"\n"
+" \n"
+" \n"
+"
\n"
+" \n"
+" \n"
+" ${object.company_id.name}\n"
+" \n"
+" \n"
+" ${object.company_id.phone}\n"
+" % if object.company_id.email\n"
+" | ${object.company_id.email}\n"
+" % endif\n"
+" % if object.company_id.website\n"
+" | \n"
+" ${object.company_id.website}\n"
+" \n"
+" % endif\n"
+" \n"
+"\n"
+" \n"
+"
\n"
+" \n"
+" \n"
+" Powered by Odoo\n"
+"
Tilføj nye salgsmuligheder
\n" +" Det ser ud som om du ikke er tilknyttet en salgsgruppe. Du skal tilføje dig selv\n" +" som medlem af et af salgsgrupperne.\n" +"
" #. module: crm #. openerp-web @@ -94,9 +103,10 @@ msgid "" "attached to this opportunity.Type '@' to mention" " people - it's like cc-ing on emails.
" msgstr "" -"Send beskeder til dine muligheder og modtag svar der automatisk " -"vedhæftes denne salgsmulighed.
Tast '@' for at " -"stile direkte til folk - virker som cc/ på e-mails.
" +"Send beskeder til dine salgsmuligheder og modtag svar der " +"automatisk vedhæftes denne salgsmulighed.
Tast " +"'@' for at sende besked direkte til en person - virker som cc/ på " +"e-mails.
" #. module: crm #. openerp-web @@ -108,6 +118,10 @@ msgid "" "afterSelect a standard activity for now.
" msgstr "" +"Du vil kunne tilpasse dine opfølgningsaktiviteter. " +"F.eks.:
Vælg " +"en standard aktivitet for nu.
" #. module: crm #: model_terms:ir.ui.view,arch_db:crm.crm_case_form_view_oppor @@ -164,7 +178,7 @@ msgstr "Mål for udførte aktiviteter" #. module: crm #: model_terms:ir.ui.view,arch_db:crm.view_crm_case_opportunities_filter msgid "Activities Todo" -msgstr "" +msgstr "Aktiviteter der mangler" #. module: crm #: model:ir.model.fields,field_description:crm.field_crm_lead__activity_state @@ -185,7 +199,7 @@ msgstr "Aktivitetstyper" #: code:addons/crm/models/crm_lead.py:933 #, python-format msgid "Add a new lead" -msgstr "" +msgstr "Tilføj nyt kundeemne" #. module: crm #: model_terms:ir.ui.view,arch_db:crm.res_config_settings_view_form @@ -232,7 +246,7 @@ msgstr "Tildel denne salgsmulighed til" #. module: crm #: model:ir.model.fields,field_description:crm.field_crm_lead__date_open msgid "Assignation Date" -msgstr "Tilknytnings dato" +msgstr "Tildelingsdato" #. module: crm #: model:ir.model.fields,field_description:crm.field_crm_lead__message_attachment_count @@ -247,7 +261,7 @@ msgstr "Gennemsnitlig sandsynlighed" #. module: crm #: model:ir.model.fields,field_description:crm.field_crm_lead__is_blacklisted msgid "Blacklist" -msgstr "" +msgstr "Blacklist" #. module: crm #: code:addons/crm/models/crm_lead.py:400 @@ -258,7 +272,7 @@ msgstr "Boom! Team rekord for de sidste 30 dage." #. module: crm #: model:ir.model.fields,field_description:crm.field_crm_lead__message_bounce msgid "Bounce" -msgstr "Spring" +msgstr "Afvisning" #. module: crm #: model:ir.ui.menu,name:crm.crm_menu_root @@ -275,7 +289,7 @@ msgstr "CRM aktivitetsanalyse" #. module: crm #: model:ir.model,name:crm.model_crm_stage msgid "CRM Stages" -msgstr "" +msgstr "CRM faser" #. module: crm #: model:mail.activity.type,name:crm.mail_activity_demo_call_demo @@ -300,7 +314,7 @@ msgstr "Annuller" #. module: crm #: model:ir.actions.act_window,name:crm.crm_team_act_tree msgid "Cases by Sales Team" -msgstr "Sager efter salgs teams" +msgstr "Sager efter salgsteams" #. module: crm #: model:ir.model.fields,field_description:crm.field_crm_stage__on_change @@ -322,7 +336,7 @@ msgstr "" #. module: crm #: model:ir.model.fields,help:crm.field_crm_team__use_opportunities msgid "Check this box to manage a presales process with opportunities." -msgstr "" +msgstr "Marker denne boks for at styre en salgsproces med salgsmuligheder." #. module: crm #: model:ir.model.fields,field_description:crm.field_crm_lead__city @@ -348,7 +362,7 @@ msgstr "" #: code:addons/crm/static/src/js/tour.js:32 #, python-format msgid "Click here to add your opportunity." -msgstr "" +msgstr "Klik her for at tilføje din salgsmulighed." #. module: crm #. openerp-web @@ -366,7 +380,7 @@ msgstr "" #: code:addons/crm/static/src/js/tour.js:60 #, python-format msgid "Click on the opportunity to zoom in." -msgstr "" +msgstr "Klik på salgsmuligheden for at zoome ind." #. module: crm #: model:ir.model.fields,field_description:crm.field_crm_lead__date_closed @@ -406,7 +420,7 @@ msgstr "Virksomhedsnavn" #. module: crm #: model:ir.model,name:crm.model_res_config_settings msgid "Config Settings" -msgstr "" +msgstr "Konfigurer opsætning" #. module: crm #: model:ir.ui.menu,name:crm.crm_menu_config @@ -473,12 +487,12 @@ msgstr "Konverteringsmuligheder" #. module: crm #: model:ir.model,name:crm.model_crm_lead2opportunity_partner_mass msgid "Convert Lead to Opportunity (in mass)" -msgstr "" +msgstr "Konverter kundeemne til salgsmulighed (i en masse)" #. module: crm #: model:ir.model,name:crm.model_crm_lead2opportunity_partner msgid "Convert Lead to Opportunity (not in mass)" -msgstr "" +msgstr "Konverter kundeemne til salgsmulighed (ikke i en masse)" #. module: crm #: model_terms:ir.ui.view,arch_db:crm.view_crm_lead2opportunity_partner_mass @@ -538,12 +552,12 @@ msgstr "Opret" #. module: crm #: model_terms:ir.ui.view,arch_db:crm.view_create_opportunity_simplified msgid "Create & Edit" -msgstr "Opret & Redigér" +msgstr "Opret & redigér" #. module: crm #: model:ir.model.fields,field_description:crm.field_res_config_settings__module_crm_reveal msgid "Create Leads/Opportunities from your website's traffic" -msgstr "" +msgstr "Opret kundeemner / salgsmuligheder fra din hjemmeside" #. module: crm #: model_terms:ir.ui.view,arch_db:crm.view_crm_lead2opportunity_partner @@ -560,12 +574,12 @@ msgstr "Opret ny kunde" #: model_terms:ir.actions.act_window,help:crm.crm_case_form_view_salesteams_lead #: model_terms:ir.actions.act_window,help:crm.crm_case_form_view_salesteams_opportunity msgid "Create a new lead" -msgstr "" +msgstr "Opret nyt kundeemne" #. module: crm #: model_terms:ir.actions.act_window,help:crm.crm_lead_tag_action msgid "Create a new tag for your opportunities" -msgstr "" +msgstr "Opret et nyt tag for dine salgsmuligheder" #. module: crm #: model:ir.actions.act_window,name:crm.create_opportunity_simplified @@ -576,13 +590,13 @@ msgstr "Opret en salgsmulighed" #. module: crm #: model_terms:ir.actions.act_window,help:crm.relate_partner_opportunities msgid "Create an new opportunity related to this customer" -msgstr "" +msgstr "Opret en ny salgsmulighed relateret til denne kunde" #. module: crm #: code:addons/crm/models/crm_lead.py:935 #, python-format msgid "Create an opportunity in your pipeline" -msgstr "" +msgstr "Opret en salgsmulighed i din pipeline" #. module: crm #: model_terms:ir.actions.act_window,help:crm.crm_lead_tag_action @@ -628,7 +642,7 @@ msgstr "Oprettet den" #: model_terms:ir.ui.view,arch_db:crm.view_crm_case_leads_filter #: model_terms:ir.ui.view,arch_db:crm.view_crm_case_opportunities_filter msgid "Creation Date" -msgstr "Oprettelses dato" +msgstr "Oprettelsesdato" #. module: crm #: model:ir.actions.server,name:crm.action_your_pipeline @@ -682,7 +696,7 @@ msgstr "Dato" #. module: crm #: model_terms:ir.ui.view,arch_db:crm.crm_opportunity_report_view_search msgid "Date Closed" -msgstr "" +msgstr "Lukket dato" #. module: crm #: model:ir.model.fields,field_description:crm.field_crm_lead__day_open @@ -702,7 +716,7 @@ msgstr "Standard alias navn for leads" #. module: crm #: model_terms:ir.actions.act_window,help:crm.crm_lost_reason_action msgid "Define a new lost reason" -msgstr "" +msgstr "Definer en ny årsag for en tabt salgsmulighed" #. module: crm #: model_terms:ir.ui.view,arch_db:crm.crm_case_kanban_view_leads @@ -722,7 +736,7 @@ msgstr "Design" #. module: crm #: model:ir.model,name:crm.model_digest_digest msgid "Digest" -msgstr "" +msgstr "Digest" #. module: crm #: model_terms:ir.ui.view,arch_db:crm.view_create_opportunity_simplified @@ -748,6 +762,7 @@ msgstr "Vis navn" #, python-format msgid "Do not have access, skip this data for user's digest email" msgstr "" +"Har ikke adgang, spring over disse data til brugerens opsummerings e-mail" #. module: crm #: selection:crm.lead2opportunity.partner,action:0 @@ -759,7 +774,7 @@ msgstr "Link ikke til en kunde" #. module: crm #: model_terms:ir.ui.view,arch_db:crm.crm_case_kanban_view_leads msgid "Dropdown menu" -msgstr "" +msgstr "Dropdown menu" #. module: crm #: model_terms:ir.ui.view,arch_db:crm.crm_case_kanban_view_leads @@ -789,6 +804,8 @@ msgid "" "Email sent to ${email} generate opportunities in your " "pipeline.I have checked this application but It's not match with our requirement. so no need to process further and we should refuse this application.
+I have checked this application but it does not match with our requirements. We don't need to proceed further and we should refuse this application.
Kind regards,
]]>We should move further for this application as early as possible..
+We should move further for this application as early as possible.
Kind regards,
]]>For website built with Odoo CMS, please install the website_livechat module. Then go to Website Admin > Configuration > Settings and select the Website Live Chat Channel you want to add on your website.
+For websites built with the Odoo CMS, please install the website_livechat module. Then go to Website > Configuration > Settings and select the Website Live Chat Channel you want to add on your website.
--
%s
Channels make it easy to organize information across different topics and groups.
Try to create your first channel (e.g. sales, marketing, product XYZ, after work party, etc).
"), position: 'bottom', +}, { + trigger: '.o_mail_discuss .o_mail_discuss_sidebar .o_mail_add_thread[data-type="public"]', + content: _t("Create a channel here.
"), + position: 'right', + run: function (actions) { + var t = new Date().getTime(); + actions.text("SomeChannel_" + t, this.$anchor.find("input")); + }, +}, { + trigger: ".ui-menu-item > a", + auto: true, + in_modal: false, }, { trigger: '.o_mail_discuss .o_composer_text_field', content: _t("Write a message to the members of the channel here.
You can notify someone with '@' or link another channel with '#'. Start your message with '/' to get the list of possible commands.
"), position: "top", width: 350, + run: function (actions) { + var t = new Date().getTime(); + actions.text("SomeText_" + t, this.$anchor); + }, }, { - trigger: ".o_mail_discuss .o_mail_thread .o_thread_message_star", + trigger: '.o_mail_discuss .o_thread_composer .o_composer_button_send', + content: _t("Post your message on the thread"), + position: "top", +}, { + trigger: '.o_mail_discuss .o_mail_thread .o_thread_message_star', content: _t("Messages can be starred to remind you to check back later."), position: "right", }, { - trigger: '.o_mail_discuss .o_mail_item_item[data-thread-id="mailbox_starred"]', + trigger: '.o_mail_discuss .o_mail_discuss_item[data-thread-id="mailbox_starred"]', content: _t("Once a message has been starred, you can come back and review it at any time here."), position: "bottom", }, { diff --git a/addons/mail/static/src/xml/thread.xml b/addons/mail/static/src/xml/thread.xml index e5db4a72524..f28e071b2f3 100644 --- a/addons/mail/static/src/xml/thread.xml +++ b/addons/mail/static/src/xml/thread.xml @@ -338,7 +338,7 @@ - \"`' \u30C4", "should have correct mention link in the message content"); + $input.val("@"); + $input.trigger('keyup'); + var $mention = discuss.$('.o_mention_proposition'); + assert.strictEqual($mention.find('.o_mention_name').text(), + '\u0405pëciãlUser<&>"`\' \u30C4', + "first partner mention should still display the correct partner name"); discuss.destroy(); done(); }); @@ -513,6 +519,85 @@ QUnit.test('@ mention with special chars', function (assert) { }); }); +QUnit.test('@ mention in mailing channel', function (assert) { + assert.expect(8); + var done = assert.async(); + + var fetchListenersDef = $.Deferred(); + + this.data.initMessaging = { + channel_slots: { + channel_channel: [{ + id: 1, + channel_type: "channel", + name: "general", + mass_mailing: true, + }], + }, + }; + + createDiscuss({ + id: 1, + context: {}, + params: {}, + data: this.data, + services: this.services, + mockRPC: function (route, args) { + if (args.method === 'channel_fetch_listeners') { + fetchListenersDef.resolve(); + return $.when([ + {id: 1, name: 'Admin'}, + ]); + } + return this._super.apply(this, arguments); + }, + }) + .then(function (discuss) { + var $general = discuss.$('.o_mail_discuss_sidebar') + .find('.o_mail_discuss_item[data-thread-id=1]'); + + // click on general + $general.click(); + // 1st composer: basic composer (hidden), 2nd composer: extended (shown) + var $input = discuss.$('textarea.o_composer_text_field').eq(1); + assert.ok($input.length, "should display a composer input"); + + // Simulate '@' typed by user with mocked Window.getSelection + // Note: focus is needed in order to trigger rpc 'channel_fetch_listeners' + $input.focus(); + $input.val("@"); + $input.trigger('keyup'); + + fetchListenersDef + .then(concurrency.delay.bind(concurrency, 0)) + .then(function () { + assert.strictEqual(discuss.$('.dropup.o_composer_mention_dropdown.show').length, 1, + "dropup menu for partner mentions should be open"); + + var $mention = discuss.$('.o_mention_proposition'); + assert.strictEqual($mention.length, 1, + "should display 1 partner mention proposition"); + + // correct mention proposition + assert.ok($mention.hasClass('active'), + "partner mention should be active"); + assert.strictEqual($mention.data('id'), 1, + "partner mention should link to the correct partner id"); + assert.strictEqual($mention.find('.o_mention_name').text(), "Admin", + "partner mention should display the correct partner name"); + + // equivalent to $mentionPropositions.find('active').click(); + $input.trigger($.Event('keyup', {which: $.ui.keyCode.ENTER})); + + assert.ok($input.is(':focus'), "composer body should have focus"); + assert.notOk(discuss.$('.o_composer_subject').is(':focus')); + + discuss.destroy(); + done(); + }); + }); +}); + QUnit.test('no crash focusout emoji button', function (assert) { assert.expect(3); var done = assert.async(); @@ -1055,5 +1140,84 @@ QUnit.test('drag and drop file in composer', function (assert) { }); }); +QUnit.test('reply to message from inbox', function (assert) { + var done = assert.async(); + assert.expect(11); + + var self = this; + this.data['mail.message'].records = [{ + author_id: [5, 'Demo User'], + body: 'test 1
', + id: 1, + needaction: true, + needaction_partner_ids: [3], + res_id: 100, + model: 'some.document', + record_name: 'SomeDocument', + }]; + this.data.initMessaging = { + needaction_inbox_counter: 1, + }; + + createDiscuss({ + id: 1, + context: {}, + params: {}, + data: this.data, + services: this.services, + session: { partner_id: 3 }, + mockRPC: function (route, args) { + if (args.method === 'message_post') { + assert.step(args.method); + assert.strictEqual(args.model, 'some.document', + "should post message to correct document model"); + assert.strictEqual(args.args[0], 100, + "should post message to correct document ID"); + + self.data['mail.message'].records.push({ + author_id: [3, 'Me'], + body: args.kwargs.body, + id: 2, + res_id: 100, + model: 'some.document', + record_name: 'SomeDocument', + }); + return $.when(2); + } + return this._super.apply(this, arguments); + }, + }) + .then(function (discuss) { + assert.strictEqual(discuss.$('.o_mail_discuss_item.o_active').data('thread-id'), + 'mailbox_inbox', + "Inbox should be selected by default"); + assert.containsOnce(discuss, '.o_thread_message', + "should display a single message in inbox"); + assert.strictEqual(discuss.$('.o_thread_message').data('message-id'), 1, + "message should be linked to correct message"); + assert.containsOnce(discuss.$('.o_thread_message'), '.o_thread_message_reply', + "should display the reply icon for message linked to a document"); + + testUtils.dom.click(discuss.$('.o_thread_message_reply')); + var $composer = discuss.$('.o_thread_composer_extended'); + assert.isVisible($composer, + "extended composer should become visible"); + assert.strictEqual($composer.find('.o_composer_subject input').val(), + 'Re: SomeDocument', + "composer should have copied document name as subject of message"); + + var $textarea = $composer.find('.o_composer_input textarea').first(); + testUtils.fields.editInput($textarea, 'someContent'); + assert.containsOnce($composer, '.o_composer_button_send', + "should have button to send reply message"); + testUtils.dom.click($composer.find('.o_composer_button_send')); + + assert.verifySteps(['message_post']); + + discuss.destroy(); + done(); + }); +}); + }); }); diff --git a/addons/mail/static/tests/systray/systray_messaging_menu_tests.js b/addons/mail/static/tests/systray/systray_messaging_menu_tests.js index d020cf81151..44651a70523 100644 --- a/addons/mail/static/tests/systray/systray_messaging_menu_tests.js +++ b/addons/mail/static/tests/systray/systray_messaging_menu_tests.js @@ -625,5 +625,161 @@ QUnit.test("messaging menu widget: channel seen notification", function ( assert messagingMenu.destroy(); }); +QUnit.test("messaging menu widget: preview with no message should be undated", function ( assert ) { + assert.expect(2); + + // remove any message on the channel + this.data['mail.channel'].records[0].channel_message_ids = []; + this.data['mail.message'].records[0].channel_ids = []; + + var messagingMenu = new MessagingMenu(); + testUtils.addMockEnvironment(messagingMenu, { + services: this.services, + data: this.data, + }); + + messagingMenu.appendTo($('#qunit-fixture')); + + messagingMenu.$('.dropdown-toggle').click(); + + assert.strictEqual(messagingMenu.$('.o_mail_preview').length, 1, + "should have two previews in messaging menu"); + + assert.ok(_.isEmpty(messagingMenu.$('.o_mail_preview .o_last_message_date').text().trim()), + "should have preview as undated"); + + messagingMenu.destroy(); +}); + +QUnit.test("messaging menu widget: sort dated previews before undated previews", function ( assert ) { + assert.expect(5); + + var dm = { + id: 2, + name: "DM", + channel_type: "chat", + }; + + this.data['mail.channel'].records.push(dm); + this.data.initMessaging.channel_slots.direct_message = [dm]; + + var messagingMenu = new MessagingMenu(); + testUtils.addMockEnvironment(messagingMenu, { + services: this.services, + data: this.data, + }); + + messagingMenu.appendTo($('#qunit-fixture')); + messagingMenu.$('.dropdown-toggle').click(); + + assert.strictEqual(messagingMenu.$('.o_mail_preview').length, 2, + "should have two previews in messaging menu"); + + var $preview1 = messagingMenu.$('.o_mail_preview').eq(0); + var $preview2 = messagingMenu.$('.o_mail_preview').eq(1); + + assert.strictEqual($preview1.data('preview-id'), 1, + "should have channel preview as the 1st preview (dated preview)"); + assert.notOk(_.isEmpty($preview1.find('.o_last_message_date').text().trim()), + "should have channel preview as dated"); + assert.strictEqual($preview2.data('preview-id'), 2, + "should have DM preview as the 1st preview (non-dated preview)"); + assert.ok(_.isEmpty($preview2.find('.o_last_message_date').text().trim()), + "should have DM preview as undated"); + + messagingMenu.destroy(); +}); + +QUnit.test('global counter with channel previews', function (assert) { + assert.expect(5); + + var channels = [{ + id: 1, + name: "channel1", + channel_type: "channel", + channel_message_ids: [1, 2], + message_unread_counter: 2, + }, { + id: 2, + name: "channel2", + channel_type: "channel", + channel_message_ids: [3], + message_unread_counter: 1, + }, { + id: 3, + name: "channel3", + channel_type: "channel", + channel_message_ids: [4], + message_unread_counter: 0, + }]; + + var messages = [{ + author_id: [1, "Demo"], + body: "message 1
", + channel_ids: [1], + id: 1, + model: 'mail.channel', + record_name: 'channel1', + res_id: 1, + }, { + author_id: [1, "Demo"], + body: "message 2
", + channel_ids: [1], + id: 2, + model: 'mail.channel', + record_name: 'channel1', + res_id: 1, + }, { + author_id: [1, "Demo"], + body: "message 3
", + channel_ids: [2], + id: 3, + model: 'mail.channel', + record_name: 'channel2', + res_id: 2, + }, { + author_id: [1, "Demo"], + body: "message 4
", + channel_ids: [3], + id: 4, + model: 'mail.channel', + record_name: 'channel3', + res_id: 3, + }]; + + this.data['mail.channel'].records = channels; + this.data.initMessaging.channel_slots.channel_channel = channels; + this.data['mail.message'].records = messages; + + var messagingMenu = new MessagingMenu(); + testUtils.addMockEnvironment(messagingMenu, { + services: this.services, + data: this.data, + session: { + partner_id: 3, + }, + }); + messagingMenu.appendTo($('#qunit-fixture')); + assert.strictEqual(messagingMenu.$('.o_notification_counter').text(), '2', + "should display a counter of 2 on the messaging menu icon"); + + messagingMenu.$('.dropdown-toggle').click(); + + assert.strictEqual(messagingMenu.$('.o_mail_preview').length, 3, + "should display 3 previews"); + var $previewChannel1 = messagingMenu.$('.o_mail_preview[data-preview-id=1]'); + var $previewChannel2 = messagingMenu.$('.o_mail_preview[data-preview-id=2]'); + var $previewChannel3 = messagingMenu.$('.o_mail_preview[data-preview-id=3]'); + + assert.strictEqual($previewChannel1.data('unread-counter'), 2, + "preview of channel 1 should have unread counter of 2"); + assert.strictEqual($previewChannel2.data('unread-counter'), 1, + "preview of channel 2 should have unread counter of 1"); + assert.strictEqual($previewChannel3.data('unread-counter'), 0, + "preview of channel 3 should have unread counter of 0"); + + messagingMenu.destroy(); +}); + }); }); diff --git a/addons/mail/static/tests/thread_window/blank_thread_window_tests.js b/addons/mail/static/tests/thread_window/blank_thread_window_tests.js index 0f3c7c7bbe7..4f103f71163 100644 --- a/addons/mail/static/tests/thread_window/blank_thread_window_tests.js +++ b/addons/mail/static/tests/thread_window/blank_thread_window_tests.js @@ -229,7 +229,7 @@ QUnit.test('open new DM chat from blank thread window', function (assert) { selectDef.then(function () { assert.strictEqual($('.o_thread_window').length, 1, "should be a single window"); - assert.strictEqual($('.o_thread_window_title').text().trim(), "#DemoUser1", + assert.strictEqual($('.o_thread_window_title').text().trim(), "DemoUser1", "should have thread window of the DM chat with 'DemoUser1'"); assert.strictEqual($('.o_composer_text_field').length, 1, "should have a composer in the DM chat window"); @@ -285,7 +285,7 @@ QUnit.test('open already detached DM chat from blank thread window', function (a assert.strictEqual($('.o_thread_window').length, 1, "should be a single window"); - assert.strictEqual($('.o_thread_window_title').text().trim(), "#DemoUser1", + assert.strictEqual($('.o_thread_window_title').text().trim(), "DemoUser1", "should have thread window of the DM chat with 'DemoUser1'"); assert.strictEqual($('.o_composer_text_field').length, 1, "should have a composer in the DM chat window"); @@ -304,7 +304,7 @@ QUnit.test('open already detached DM chat from blank thread window', function (a selectDef.then(function () { assert.strictEqual($('.o_thread_window').length, 1, "should now have a single thread window open"); - assert.strictEqual($('.o_thread_window_title').text().trim(), "#DemoUser1", + assert.strictEqual($('.o_thread_window_title').text().trim(), "DemoUser1", "the remaining thread window should be the DM chat with 'DemoUser1'"); self.unpatchAutocomplete(); diff --git a/addons/mail/wizard/invite.py b/addons/mail/wizard/invite.py index 35d04f66659..e8d9cbcbda3 100644 --- a/addons/mail/wizard/invite.py +++ b/addons/mail/wizard/invite.py @@ -1,6 +1,9 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. +from lxml import etree +from lxml.html import builder as html + from odoo import _, api, fields, models @@ -12,18 +15,27 @@ class Invite(models.TransientModel): @api.model def default_get(self, fields): result = super(Invite, self).default_get(fields) + if self._context.get('mail_invite_follower_channel_only'): + result['send_mail'] = False + if 'message' not in fields: + return result + user_name = self.env.user.display_name model = result.get('res_model') res_id = result.get('res_id') - if self._context.get('mail_invite_follower_channel_only'): - result['send_mail'] = False - if 'message' in fields and model and res_id: - model_name = self.env['ir.model']._get(model).display_name - document_name = self.env[model].browse(res_id).display_name - message = _('Hello,
%s invited you to follow %s document: %s.
Hello,
%s invited you to follow a new document.