From 340995f55db248246eec0ca47f62aaabedccf02d Mon Sep 17 00:00:00 2001 From: Vladislav Date: Thu, 21 Apr 2022 01:44:40 +0300 Subject: [PATCH 01/35] Update ru.csv --- frappe/translations/ru.csv | 186 ++++++++++++++++++------------------- 1 file changed, 93 insertions(+), 93 deletions(-) diff --git a/frappe/translations/ru.csv b/frappe/translations/ru.csv index 197f2cb26d..0af57072e5 100644 --- a/frappe/translations/ru.csv +++ b/frappe/translations/ru.csv @@ -66,8 +66,8 @@ Details,Подробности, Document Name,название документа, Document Status,Статус документа, Document Type,тип документа, -Domain,Домен, -Domains,Направление деятельности, +Domain,Сфера деятельности, +Domains,Сферы деятельности, Draft,Проект, Edit,редактировать, Email Account,Электронная почта, @@ -1178,7 +1178,7 @@ Generate Keys,Создать ключи, Generate New Report,Создать новый отчет, Generated File,Сгенерированный файл, Geo,Гео, -Geolocation,геолокации, +Geolocation,Геолокация, Get Alerts for Today,Виртуальный на сегодняшний день, Get Contacts,Получить контакты, Get Fields,Получить поля, @@ -1204,19 +1204,19 @@ HTML,HTML, HTML Editor,Редактор HTML, "HTML Header, Robots and Redirects","Заголовок HTML, роботы и перенаправления", HTML for header section. Optional,HTML для секции header. Необязательно, -Half,половина, -Has Attachment,Имеет Вложения, -Has Attachments,Имеет приложения, +Half,Половина, +Has Attachment,Содержит вложения, +Has Attachments,Содержит приложения, Has Domain,Имеет домен, Has Role,Имеет роль, Has Web View,Имеет Web View, -Have an account? Login,Иметь аккаунт? Авторизоваться, +Have an account? Login,Уже есть аккаунт? Авторизоваться, Header,Шапка, Header HTML,Заголовок HTML, Header HTML set from attachment {0},HTML-код заголовка из вложения {0}, Header Image,Заглавное изображение, Headers,Заголовки, -Heading,заголовок, +Heading,Заголовок, Hello {0},"Здравствуйте, {0}", Hello!,Здравствуйте!, Help Articles,Статьи помощи, @@ -1381,26 +1381,26 @@ Is First Startup,Первый запуск, Is Folder,Папка, Is Global,Является глобальным, Is Globally Pinned,Глобально закреплено, -Is Home Folder,Является Главная Папка, -Is Mandatory Field,Является обязательным поле, +Is Home Folder,Является корневой папкой, +Is Mandatory Field,Является обязательным полем, Is Pinned,Прикреплено, Is Primary Contact,Основной контакт, Is Private,Является личным, Is Published Field,Есть Опубликовано поле, Is Published Field must be a valid fieldname,Опубликовано Поле должно быть действительным имя_полем, -Is Single,Одинокий, +Is Single,Единственный, Is Spam,Спам, Is Standard,Стандартный отчёт, -Is Submittable,подлежит проведению, -Is Table,Является ли таблица, -Is Your Company Address,Является ли Ваша компания Адрес, +Is Submittable,Подлежит исполнению, +Is Table,Является таблицей, +Is Your Company Address,Является адресом вашей компании, It is risky to delete this file: {0}. Please contact your System Manager.,"Это рискованно, чтобы удалить этот файл: {0}. Пожалуйста, обратитесь к менеджеру системы.", Item cannot be added to its own descendents,Продукт не может быть добавлен к своим подпродуктам, JS,JS, JSON,JSON, JavaScript Format: frappe.query_reports['REPORTNAME'] = {},Формат JavaScript: frappe.query_reports ['REPORTNAME'] = {}, Javascript to append to the head section of the page.,Javascript для добавления к головной части страницы., -Jinja,дзиндзя, +Jinja,Jinja, John Doe,Джон Доу, Kanban,Канбан, Kanban Board Column,Колонка канбан-доски, @@ -1448,16 +1448,16 @@ Last Year,Прошлый год, Last synced {0},Последняя синхронизация {0}, Leave a Comment,Оставить комментарий, Leave blank to repeat always,"Оставьте пустым, чтобы повторить всегда", -Leave this conversation,Оставьте этот разговор, -Left this conversation,Левая этот разговор, +Leave this conversation,Покинуть этот разговор, +Left this conversation,Покинуть этот разговор, Length,Длина, Length of {0} should be between 1 and 1000,Длина {0} должно быть от 1 до 1000, Let's avoid repeated words and characters,Давайте избегать повторяющихся слов и символов, Let's prepare the system for first use.,Давайте подготовить систему для первого использования., Letter,Письмо, -Letter Head Based On,Письмо на основе, -Letter Head Image,Изображение головы письма, -Letter Head Name,Имя Бланк, +Letter Head Based On,Заголовок письма на основе, +Letter Head Image,Изображение в заголовке письма, +Letter Head Name,Название заголовка письма, Letter Head in HTML,Заголовок письма в HTML, Level Name,Название уровня, Liked,Понравилось, @@ -1468,11 +1468,11 @@ Limit Number of DB Backups,Ограничение количества резе Line,Линия, Link DocType,Ссылка DocType, Link Expired,Срок действия ссылки, -Link Name,Ссылка Имя, -Link Title,Линк Титл, +Link Name,Имя ссылки, +Link Title,Название ссылки, "Link that is the website home page. Standard Links (index, login, products, blog, about, contact)","Ссылка, что находитесь на сайте домашняя страница. Стандартные ссылки (индекс, логин, продукты, блог, о, контакт)", Link to the page you want to open. Leave blank if you want to make it a group parent.,"Ссылка на страницу, вы хотите, чтобы открыть. Оставьте пустым, если вы хотите, чтобы сделать его группа родителей.", -Linked,связанный, +Linked,Связанный, Linked With,Связанные с, Linked with {0},Связано с {0}, Links,Связи, @@ -1506,7 +1506,7 @@ Login and view in Browser,Вход и просмотр в браузере, Login not allowed at this time,Войти не допускается в это время, "Login session expired, refresh page to retry","Срок действия сеанса истек, обновить страницу, чтобы повторить попытку", Login to comment,Вход на комментарий, -Login token required,Требуется токен входа, +Login token required,Для входа требуется токен, Login with LDAP,Вход с LDAP, Logout,Выход, Long Text,Длинный текст, @@ -1515,7 +1515,7 @@ Looks like something is wrong with this site's payment gateway configuration. No "Looks like something went wrong during the transaction. Since we haven't confirmed the payment, Paypal will automatically refund you this amount. If it doesn't, please send us an email and mention the Correlation ID: {0}.","Похоже, что-то пошло не так во время транзакции. Поскольку мы не подтвердили платеж, Paypal автоматически вернет вам эту сумму. Если это не так, отправьте нам электронное письмо и укажите идентификатор корреляции: {0}.", Madam,Госпожа, Main Section,Основной раздел, -"Make ""name"" searchable in Global Search",Сделать «имя» для поиска в Глобальном Поиске, +"Make ""name"" searchable in Global Search",Индексировать ""name"" для глобального поиска, Make use of longer keyboard patterns,Используйте более длинных моделей клавиатуры, Manage Third Party Apps,Управление приложениями сторонних разработчиков, Mandatory Information missing:,Обязательная информация отсутствует:, @@ -1529,7 +1529,7 @@ Mappings,Отображения, Mark as Read,"Пометить, как прочитанное", Mark as Spam,Отметить как спам, Mark as Unread,Отметить как непрочитанные, -Markdown,Уценка, +Markdown,Markdown, Markdown Editor,Редактор Markdown, Marked As Spam,Помеченные как спам, Max 500 records at a time,Max 500 записей за один раз, @@ -1640,14 +1640,14 @@ No Copy,Без копии, No Email Account,Нет аккаунта электронной почты, No Email Accounts Assigned,Аккаунты электронной почты не установлены, No Emails,Нет сообщений электронной почты, -No Label,Без марки, +No Label,Без отметки, No Permissions Specified,Нет разрешенных разрешений, No Permissions set for this criteria.,Разрешения не установлен для этого критериев., No Preview,Нет предварительного просмотра, No Preview Available,Предварительный просмотр недоступен, No Printer is Available.,Принтер не доступен., No Results,Нет результатов, -No Tags,Нет меток, +No Tags,Нет тегов, No alerts for today,Нет предупреждений на сегодня, No comments yet,Комментариев нет, No comments yet. Start a new discussion.,Пока без коментариев. Начать новое обсуждение., @@ -1681,7 +1681,7 @@ Not In,Не в, Not Linked to any record,Не привязано к какой-либо записи, Not Published,Не опубликовано, Not Saved,Не сохранено, -Not Seen,Не Видел, +Not Seen,Непрочитанно, Not Sent,Не Отправлено, Not Set,Не указано, Not a valid Comma Separated Value (CSV File),"Не является допустимым значения, разделенные запятыми (CSV-файл)", @@ -2157,7 +2157,7 @@ Script,Скрипт, Script Report,Программируемый отчёт, Script or Query reports,Отчёты-выборка или программируемый отчёт, Script to attach to all web pages.,Сценарий для подключения к всех веб-страниц., -Search Fields,Поиск Поля, +Search Fields,Поиск полей, Search Help,Поиск по справке, Search field {0} is not valid,Поле поиска {0} не является действительным, Search for '{0}',Поиск '{0}', @@ -2326,13 +2326,13 @@ Single Types have only one record no tables associated. Values are stored in tab Skip Authorization,Пропустить авторизацию, Skip rows with errors,Пропустить строки с ошибками, Skype,Skype, -Slack,слабина, -Slack Channel,Слабый канал, -Slack Webhook Error,Ошибка слабой ошибки Webhook, +Slack,Slack, +Slack Channel,Slack канал, +Slack Webhook Error,Slack Webhook ошибка, Slack Webhook URL,Неверный URL веб-хостинга, Slack Webhooks for internal integration,Slack Webhooks для внутренней интеграции, -Slideshow Items,Продукты слайд-шоу, -Slideshow Name,Слайд-шоу Имя, +Slideshow Items,Элементы слайд-шоу, +Slideshow Name,Название слайд-шоу, Slideshow like display for the website,"Слайд-шоу, как дисплей для сайта", Small Text,Маленьикий текст, Smallest Currency Fraction Value,Минимальное дробное значение, @@ -2558,11 +2558,11 @@ Total Rows,Всего строк, Total Subscribers,Всего Подписчики, Total number of emails to sync in initial sync process ,Общее количество писем для синхронизации в начальном процессе синхронизации, Totals Row,Итоговые строки, -Track Changes,Отслеживать изменения, -Track Email Status,Статус отслеживания электронной почты, -Track Field,Трек Поле, -Track Seen,Трек посещение, -Track Views,Просмотр дорожек, +Track Changes,Трекер изменений, +Track Email Status,Статус трекера электронной почты, +Track Field,Трекер поля, +Track Seen,Трекер посещение, +Track Views,Трекер просмотров, "Track if your email has been opened by the recipient.\n
\nNote: If you're sending to multiple recipients, even if 1 recipient reads the email, it'll be considered ""Opened""","Отслеживайте, если ваш адрес электронной почты был открыт получателем.
Примечание. Если вы отправляете нескольким получателям, даже если один получатель читает электронное письмо, он будет считаться «открытым»,", Track milestones for any document,Отслеживайте этапы для любого документа, Transaction Hash,Сделка транзакций, @@ -2570,14 +2570,14 @@ Transaction Log,Журнал транзакций, Transaction Log Report,Отчет о транзакционном журнале, Transition Rules,Переходные правила, Transitions,Переходы, -Translatable,переводимый, +Translatable,Переводимый, Translate {0},Перевести {0}, Translated Text,Переведенный текст, Translation,Перевод, Translations,Переводы, -Trash,дрянь, -Tree,дерево, -Trigger Method,Метод Trigger, +Trash,Мусор, +Tree,Дерево, +Trigger Method,Метод триггера, Trigger Name,Имя триггера, "Trigger on valid methods like ""before_insert"", ""after_update"", etc (will depend on the DocType selected)","Запуск по уважительным методы, такие как "before_insert", "after_update", и т.д. (будет зависеть от выбранного DocType)", Try to avoid repeated words and characters,Старайтесь избегать повторяющихся слов и символов, @@ -3148,7 +3148,7 @@ Access not allowed from this IP Address,Доступ с этого IP-адрес Action Type,Тип действия, Activity Log by ,Активность Журнал по, Add Fields,Добавить поля, -Administration,администрация, +Administration,Администрация, After Cancel,После отмены, After Delete,После удаления, After Save,После сохранения, @@ -3398,7 +3398,7 @@ LDAP Middle Name Field,Поле второго имени LDAP, LDAP Mobile Field,LDAP Mobile Field, LDAP Phone Field,Поле телефона LDAP, LDAP User Creation and Mapping,Создание и сопоставление пользователей LDAP, -Landscape,Пейзаж, +Landscape,Альбомный, Last,Последний, Last Backup On,Последнее резервное копирование включено, Last Execution,Последнее исполнение, @@ -3422,7 +3422,7 @@ Mapping column {0} to field {1},Отображение столбца {0} в п Mark all as Read,Отметить все как прочитанное, Maximum Points,Максимум очков, Maximum points allowed after multiplying points with the multiplier value\n(Note: For no limit leave this field empty or set 0),"Максимальное количество баллов, допустимое после умножения баллов на значение множителя (Примечание: для ограничения не оставляйте это поле пустым или установите 0)", -Me,мне, +Me,Мне, Mention,Упоминание, Modules,Модули, Monthly Long,Ежемесячно долго, @@ -3543,8 +3543,8 @@ Session Defaults Saved,Сеансы по умолчанию сохранены, Set as Default Theme,Установить как тему по умолчанию, Setting up Global Search documents.,Настройка документов глобального поиска., Show Document,Показать документ, -Show Failed Logs,Показать ошибочные журналы, -Show Keyboard Shortcuts,Показать сочетания клавиш, +Show Failed Logs,Показать журнал ошибок, +Show Keyboard Shortcuts,Показать горячие клавиш, Show More Activity,Показать больше активности, Show Traceback,Показать трассировку, Show Warnings,Показать предупреждения, @@ -3568,7 +3568,7 @@ Sync Calendar,Синхронизировать календарь, Sync Contacts,Синхронизация контактов, Sync with Google Calendar,Синхронизировать с календарем Google, Sync with Google Contacts,Синхронизировать с контактами Google, -Synced,синхронизированные, +Synced,Синхронизированные, Syncing,Синхронизации, Syncing {0} of {1},Синхронизация {0} из {1}, Tag Link,Ссылка на тег, @@ -3604,7 +3604,7 @@ Trigger Primary Action,Триггер Основное действие, URL for documentation or help,URL для документации или помощи, URL must start with 'http://' or 'https://',URL должен начинаться с «http: //» или «https: //», Unchanged,без изменений, -Unpin,открепить, +Unpin,Открепить, Untitled Column,Колонка без названия, Untranslated,Непереведенные, Upcoming Events,Предстоящие События, @@ -3628,7 +3628,7 @@ User {0} has requested for data deletion,Пользователь {0} запро Users assigned to the reference document will get points.,"Пользователи, назначенные для справочного документа, получат баллы.", Value must be one of {0},Значение должно быть одним из {0}, Value {0} missing for {1},Значение {0} отсутствует для {1}, -Verification,верификация, +Verification,Верификация, Verification Code,Код верификации, Verification code email not sent. Please contact Administrator.,"Письмо с кодом подтверждения не отправлено. Пожалуйста, свяжитесь с администратором.", Verified,Проверенный, @@ -3818,61 +3818,61 @@ Attach File,Прикрепить файл, Barcode,Штрих-код, Beginning with,Начиная с, Bold,Жирный, -CANCELLED,Отменено, +CANCELLED,ОТМЕНЕНО, Calendar,Календарь, Center,Центр, -Clear,ясно, +Clear,Отчистить, Comment,Комментарий, Comments,Комментарии, -DRAFT,Проект, +DRAFT,ЧЕРНОВИК, Dashboard,Приборная доска, DocType,DocType, Download,Скачать, EMail,Эл. адрес, Edit in Full Page,Редактировать на полной странице, Email Inbox,Email Inbox, -File,файл, -Forward,Вперед, +File,Файл, +Forward,Дальше, Icon,Икона, In,В, -Inbox,входящие, +Inbox,Входящие, Insert New Records,Вставить новые записи, JavaScript,JavaScript, LDAP Settings,Настройки LDAP, Left,Слева, -Like,подобно, +Like,Лайк, Link,Ссылка на сайт, Logged in,Войти в систему, -New,новый, +New,Новый, Not Found,Не найдено, Not Like,Не как, Notify by Email,Уведомить по электронной почте, Now,Сейчас, Off,от, One of,Один из, -Page,страница, +Page,Страница, Print,Распечатать, Reference Name,Имя ссылки, Refresh,Обновить, -Repeat,повторить, +Repeat,Повторить, Right,Справа, Roles HTML,Роли HTML, Scheduled To Send,Планируется отправить, Search Results for ,Результаты поиска для, Send Notification To,Отправить уведомление на, -Success,успех, +Success,Успешно, Tags,Теги, Time,Время, Updated Successfully,Успешно Обновлено, -Upload,загружать, -User ,пользователь, +Upload,Загрузить, +User ,Пользователь , Value,Значение, Web Link,Ссылка на сайт, Your Email Address,Ваш адрес электронной почты, Desktop,Настольный, -Usage Info,Использование Info, -Download Backups,Скачать Резервные копии, -Recorder,самописец, +Usage Info,Информация об использовании, +Download Backups,Скачать резервные копии, +Recorder,Регистратор, Role Permissions Manager,Менеджер разрешений на роль, Translation Tool,Инструмент перевода, Awaiting password,Ожидание пароля, @@ -3880,16 +3880,16 @@ Current status,Текущее состояние, Download template,Скачать шаблон, Edit in full page,Редактировать на полной странице, Email Id,Email ID, -Email address,Адрес Электронной Почты, +Email address,Адрес электронной почты, Ends on,Заканчивается на, Half-yearly,Полугодовой, -Hidden,скрытый, +Hidden,Скрытый, Javascript,Javascript, Ldap settings,Настройки Ldap, Mobile number,Мобильный номер, Mx,Mx, -No,нет, -Not found,не обнаружена, +No,Нет, +Not found,Не обнаружена, Notes:,Примечания:, Notify by email,Уведомление по почте, Permitted Documents For User,Разрешенные документы для пользователя, @@ -3905,7 +3905,7 @@ Sign up,Подписаться, Time format,Формат времени, Upload failed,Загрузка не удалась, User Id,Идентификатор пользователя, -Yes,да, +Yes,Да, Your email address,Ваша электронная почта, added,добавленной, added {0},Добавлено {0}, @@ -3917,11 +3917,11 @@ book,книга, calendar,календарь, certificate,сертификат, check,чек, -clear,ясно, +clear,отчистить, comment,комментарий, comments,Комментарии, created,созданный, -danger,Опасность, +danger,опасность, dashboard,Панель приборов, download,скачать, edit,Редактировать, @@ -3929,47 +3929,47 @@ email inbox,Входящая почта, file,файл, filter,фильтр, flag,помечать, -font,Шрифт (font), -forward,forward, +font,шрифт, +forward,дальше, green,зеленый, home,дом, icon,значок, -inbox,Входящие, +inbox,хходящие, like,Мне нравится, -link,Ссылка, +link,ссылка, list,список, lock,запирать, -logged in,Записан в, +logged in,записан в, message,сообщение, -module,Модуль, -move,переехать, -music,Музыка, -new,Новый, -now,Теперь, +module,модуль, +move,переместить, +music,музыка, +new,новый, +now,сейчас, off,выкл, one of,один из, orange,оранжевый, -page,Страница, +page,страница, print,печать, purple,пурпурный, random,случайный, red,красный, refresh,обновление, -remove,Удалить, +remove,удалить, response,отклик, search,поиск, share,Поделиться, stop,стоп, -success,Успешно, -tag,Тэг, +success,успешно, +tag,тэг, tags,теги, -tasks,Задачи, +tasks,задачи, time,время, -trash,дрянь, -upload,Загрузить, +trash,мусор, +upload,загрузить, user,пользователь, value,значение, -web link,Ссылка, +web link,ссылка, yellow,желтый, Not permitted,Не разрешено, Add Chart to Dashboard,Добавить диаграмму на панель инструментов, From c9df86f9efc52fb56ba81ad01d123fa7a4b63180 Mon Sep 17 00:00:00 2001 From: saxenabhishek Date: Thu, 7 Apr 2022 20:25:12 +0530 Subject: [PATCH 02/35] feat: multi table queries --- frappe/database/database.py | 4 ++-- frappe/database/query.py | 30 +++++++++++++++++++++++------- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/frappe/database/database.py b/frappe/database/database.py index fb631951fa..df476c20cc 100644 --- a/frappe/database/database.py +++ b/frappe/database/database.py @@ -1019,13 +1019,13 @@ class Database(object): return self.get_value(dt, dn, ignore=True, cache=cache) - def count(self, dt, filters=None, debug=False, cache=False): + def count(self, dt, filters=None, debug=False, cache=False, distinct:bool = True): """Returns `COUNT(*)` for given DocType and filters.""" if cache and not filters: cache_count = frappe.cache().get_value("doctype:count:{}".format(dt)) if cache_count is not None: return cache_count - query = self.query.get_sql(table=dt, filters=filters, fields=Count("*")) + query = self.query.get_sql(table=dt, filters=filters, fields=Count("*"), distinct=distinct) if filters: count = self.sql(query, debug=debug)[0][0] return count diff --git a/frappe/database/query.py b/frappe/database/query.py index 136f5c86b6..7bb3597574 100644 --- a/frappe/database/query.py +++ b/frappe/database/query.py @@ -4,7 +4,7 @@ from typing import Any, Dict, List, Tuple, Union import frappe from frappe import _ -from frappe.query_builder import Criterion, Field, Order +from frappe.query_builder import Criterion, Field, Order, Table def like(key: str, value: str) -> frappe.qb: @@ -139,7 +139,9 @@ OPERATOR_MAP = { class Query: - def get_condition(self, table: str, **kwargs) -> frappe.qb: + tables:dict = {} + + def get_condition(self, table: Union[str, Table], **kwargs) -> frappe.qb: """Get initial table object Args: @@ -148,11 +150,20 @@ class Query: Returns: frappe.qb: DocType with initial condition """ + table_object = self.get_table(table) if kwargs.get("update"): - return frappe.qb.update(table) + return frappe.qb.update(table_object) if kwargs.get("into"): - return frappe.qb.into(table) - return frappe.qb.from_(table) + return frappe.qb.into(table_object) + return frappe.qb.from_(table_object) + + def get_table(self, table_name: Union[str, Table])->Table: + if isinstance(table_name, Table): + return table_name + table_name = table_name.strip('"').strip("'") + if table_name not in self.tables: + self.tables[table_name] = frappe.qb.DocType(table_name) + return self.tables[table_name] def criterion_query(self, table: str, criterion: Criterion, **kwargs) -> frappe.qb: """Generate filters from Criterion objects @@ -217,8 +228,13 @@ class Query: conditions = conditions.where(_operator(Field(filters[0]), filters[2])) break else: - _operator = OPERATOR_MAP[f[1]] - conditions = conditions.where(_operator(Field(f[0]), f[2])) + _operator = OPERATOR_MAP[f[-2]] + if len(f) == 4: + table_object = self.get_table(f[0]) + _field = table_object[f[1]] + else: + _field = Field(f[0]) + conditions = conditions.where(_operator(_field, f[-1])) return self.add_conditions(conditions, **kwargs) From d39e6a78901f09dfefd8957a81fcd5a2dc974754 Mon Sep 17 00:00:00 2001 From: saxenabhishek Date: Wed, 13 Apr 2022 01:28:59 +0530 Subject: [PATCH 03/35] refactor: new query engine in `get_count()` --- frappe/database/database.py | 14 +++++--------- frappe/database/query.py | 26 +++++++++++++------------- frappe/desk/reportview.py | 7 ++----- 3 files changed, 20 insertions(+), 27 deletions(-) diff --git a/frappe/database/database.py b/frappe/database/database.py index df476c20cc..eca1656424 100644 --- a/frappe/database/database.py +++ b/frappe/database/database.py @@ -1019,21 +1019,17 @@ class Database(object): return self.get_value(dt, dn, ignore=True, cache=cache) - def count(self, dt, filters=None, debug=False, cache=False, distinct:bool = True): + def count(self, dt, filters=None, debug=False, cache=False, distinct : bool = True): """Returns `COUNT(*)` for given DocType and filters.""" if cache and not filters: cache_count = frappe.cache().get_value("doctype:count:{}".format(dt)) if cache_count is not None: return cache_count query = self.query.get_sql(table=dt, filters=filters, fields=Count("*"), distinct=distinct) - if filters: - count = self.sql(query, debug=debug)[0][0] - return count - else: - count = self.sql(query, debug=debug)[0][0] - if cache: - frappe.cache().set_value("doctype:count:{}".format(dt), count, expires_in_sec=86400) - return count + count = query.run(debug=debug)[0][0] + if not filters and cache: + frappe.cache().set_value("doctype:count:{}".format(dt), count, expires_in_sec=86400) + return count @staticmethod def format_date(date): diff --git a/frappe/database/query.py b/frappe/database/query.py index 7bb3597574..44c341b6a2 100644 --- a/frappe/database/query.py +++ b/frappe/database/query.py @@ -7,7 +7,7 @@ from frappe import _ from frappe.query_builder import Criterion, Field, Order, Table -def like(key: str, value: str) -> frappe.qb: +def like(key: Field, value: str) -> frappe.qb: """Wrapper method for `LIKE` Args: @@ -17,10 +17,10 @@ def like(key: str, value: str) -> frappe.qb: Returns: frappe.qb: `frappe.qb object with `LIKE` """ - return Field(key).like(value) + return key.like(value) -def func_in(key: str, value: Union[List, Tuple]) -> frappe.qb: +def func_in(key: Field, value: Union[List, Tuple]) -> frappe.qb: """Wrapper method for `IN` Args: @@ -30,10 +30,10 @@ def func_in(key: str, value: Union[List, Tuple]) -> frappe.qb: Returns: frappe.qb: `frappe.qb object with `IN` """ - return Field(key).isin(value) + return key.isin(value) -def not_like(key: str, value: str) -> frappe.qb: +def not_like(key: Field, value: str) -> frappe.qb: """Wrapper method for `NOT LIKE` Args: @@ -43,10 +43,10 @@ def not_like(key: str, value: str) -> frappe.qb: Returns: frappe.qb: `frappe.qb object with `NOT LIKE` """ - return Field(key).not_like(value) + return key.not_like(value) -def func_not_in(key: str, value: Union[List, Tuple]): +def func_not_in(key: Field, value: Union[List, Tuple]): """Wrapper method for `NOT IN` Args: @@ -56,10 +56,10 @@ def func_not_in(key: str, value: Union[List, Tuple]): Returns: frappe.qb: `frappe.qb object with `NOT IN` """ - return Field(key).notin(value) + return key.notin(value) -def func_regex(key: str, value: str) -> frappe.qb: +def func_regex(key: Field, value: str) -> frappe.qb: """Wrapper method for `REGEX` Args: @@ -69,10 +69,10 @@ def func_regex(key: str, value: str) -> frappe.qb: Returns: frappe.qb: `frappe.qb object with `REGEX` """ - return Field(key).regex(value) + return key.regex(value) -def func_between(key: str, value: Union[List, Tuple]) -> frappe.qb: +def func_between(key: Field, value: Union[List, Tuple]) -> frappe.qb: """Wrapper method for `BETWEEN` Args: @@ -82,7 +82,7 @@ def func_between(key: str, value: Union[List, Tuple]) -> frappe.qb: Returns: frappe.qb: `frappe.qb object with `BETWEEN` """ - return Field(key)[slice(*value)] + return key[slice(*value)] def make_function(key: Any, value: Union[int, str]): @@ -265,7 +265,7 @@ class Query: if isinstance(value, (list, tuple)): if isinstance(value[1], (list, tuple)) or value[0] in list(OPERATOR_MAP.keys())[-4:]: _operator = OPERATOR_MAP[value[0]] - conditions = conditions.where(_operator(key, value[1])) + conditions = conditions.where(_operator(Field(key), value[1])) else: _operator = OPERATOR_MAP[value[0]] conditions = conditions.where(_operator(Field(key), value[1])) diff --git a/frappe/desk/reportview.py b/frappe/desk/reportview.py index b45f80f6ff..2813061347 100644 --- a/frappe/desk/reportview.py +++ b/frappe/desk/reportview.py @@ -48,15 +48,12 @@ def get_list(): @frappe.read_only() def get_count(): args = get_form_params() - if is_virtual_doctype(args.doctype): controller = get_controller(args.doctype) data = controller(args.doctype).get_count(args) else: - distinct = "distinct " if args.distinct == "true" else "" - args.fields = [f"count({distinct}`tab{args.doctype}`.name) as total_count"] - data = execute(**args)[0].get("total_count") - + distinct = args["distinct"] == "true" + data = frappe.db.count(args["doctype"], args["filters"], distinct=distinct) return data From 3498445733db3fae7216e1743a89892b3548144c Mon Sep 17 00:00:00 2001 From: saxenabhishek Date: Wed, 13 Apr 2022 16:06:43 +0530 Subject: [PATCH 04/35] test: multiple_tables_in_filters --- frappe/database/query.py | 6 +++--- frappe/tests/test_query.py | 19 +++++++++++++++++++ 2 files changed, 22 insertions(+), 3 deletions(-) create mode 100644 frappe/tests/test_query.py diff --git a/frappe/database/query.py b/frappe/database/query.py index 44c341b6a2..65ac375148 100644 --- a/frappe/database/query.py +++ b/frappe/database/query.py @@ -139,7 +139,7 @@ OPERATOR_MAP = { class Query: - tables:dict = {} + tables: dict = {} def get_condition(self, table: Union[str, Table], **kwargs) -> frappe.qb: """Get initial table object @@ -157,7 +157,7 @@ class Query: return frappe.qb.into(table_object) return frappe.qb.from_(table_object) - def get_table(self, table_name: Union[str, Table])->Table: + def get_table(self, table_name: Union[str, Table]) -> Table: if isinstance(table_name, Table): return table_name table_name = table_name.strip('"').strip("'") @@ -309,7 +309,7 @@ class Query: self, table: str, fields: Union[List, Tuple], - filters: Union[Dict[str, Union[str, int]], str, int] = None, + filters: Union[Dict[str, Union[str, int]], str, int, List[Union[List, str, int]]] = None, **kwargs, ): criterion = self.build_conditions(table, filters, **kwargs) diff --git a/frappe/tests/test_query.py b/frappe/tests/test_query.py new file mode 100644 index 0000000000..fc03a66166 --- /dev/null +++ b/frappe/tests/test_query.py @@ -0,0 +1,19 @@ +import unittest +import frappe + +from frappe.tests.test_query_builder import db_type_is, run_only_if + +@run_only_if(db_type_is.MARIADB) +class TestQuery(unittest.TestCase): + def test_multiple_tables_in_filters(self): + self.assertEqual( + frappe.db.query.get_sql( + "DocType", + ["*"], + [ + ["BOM Update Log", "name", "like", "f%"], + ["DocType", "parent", "=", "something"], + ], + ).get_sql(), + "SELECT * FROM `tabDocType` WHERE `tabBOM Update Log`.`name` LIKE 'f%' AND `tabDocType`.`parent`='something'", + ) \ No newline at end of file From 0450a25822af2e18a9a17702c456e518b0a6d72c Mon Sep 17 00:00:00 2001 From: saxenabhishek Date: Tue, 19 Apr 2022 12:15:37 +0530 Subject: [PATCH 05/35] test: get_count --- frappe/tests/test_db.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/frappe/tests/test_db.py b/frappe/tests/test_db.py index 6cba55c425..4d105ef28e 100644 --- a/frappe/tests/test_db.py +++ b/frappe/tests/test_db.py @@ -482,6 +482,33 @@ class TestDB(unittest.TestCase): frappe.db.delete("ToDo", {"description": test_body}) + def test_count(self): + frappe.db.delete("Note") + + frappe.get_doc(doctype="Note", title="note1", content="something").insert() + frappe.get_doc(doctype="Note", title="note2", content="someting else").insert() + + # Count with no filtes + self.assertEquals((frappe.db.count("Note")), 2) + + # simple filters + self.assertEquals((frappe.db.count("Note", ["title", "=", "note1"])), 1) + + frappe.get_doc(doctype="Note", title="note3", content="something other").insert() + + # List of list filters with tables + self.assertEquals( + ( + frappe.db.count( + "Note", + [["Note", "title", "like", "note%"], ["Note", "content", "like", "some%"]], + ) + ), + 3, + ) + + frappe.db.rollback() + @run_only_if(db_type_is.MARIADB) class TestDDLCommandsMaria(unittest.TestCase): From b1a0a3816b9a6dd30bfdb36820e09b1c5225cf92 Mon Sep 17 00:00:00 2001 From: saxenabhishek Date: Tue, 19 Apr 2022 13:02:21 +0530 Subject: [PATCH 06/35] style: Applied Frappe linting --- frappe/database/database.py | 2 +- frappe/tests/test_query.py | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/frappe/database/database.py b/frappe/database/database.py index eca1656424..9e249fc2ad 100644 --- a/frappe/database/database.py +++ b/frappe/database/database.py @@ -1019,7 +1019,7 @@ class Database(object): return self.get_value(dt, dn, ignore=True, cache=cache) - def count(self, dt, filters=None, debug=False, cache=False, distinct : bool = True): + def count(self, dt, filters=None, debug=False, cache=False, distinct: bool = True): """Returns `COUNT(*)` for given DocType and filters.""" if cache and not filters: cache_count = frappe.cache().get_value("doctype:count:{}".format(dt)) diff --git a/frappe/tests/test_query.py b/frappe/tests/test_query.py index fc03a66166..85d1355d71 100644 --- a/frappe/tests/test_query.py +++ b/frappe/tests/test_query.py @@ -1,8 +1,9 @@ import unittest -import frappe +import frappe from frappe.tests.test_query_builder import db_type_is, run_only_if + @run_only_if(db_type_is.MARIADB) class TestQuery(unittest.TestCase): def test_multiple_tables_in_filters(self): @@ -16,4 +17,4 @@ class TestQuery(unittest.TestCase): ], ).get_sql(), "SELECT * FROM `tabDocType` WHERE `tabBOM Update Log`.`name` LIKE 'f%' AND `tabDocType`.`parent`='something'", - ) \ No newline at end of file + ) From 36de21c059b5bd1c133817ddf9a3473c07db4ae4 Mon Sep 17 00:00:00 2001 From: saxenabhishek Date: Tue, 26 Apr 2022 15:37:54 +0530 Subject: [PATCH 07/35] feat: left join tables by default --- frappe/database/query.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/frappe/database/query.py b/frappe/database/query.py index 65ac375148..f7393bfa54 100644 --- a/frappe/database/query.py +++ b/frappe/database/query.py @@ -312,7 +312,16 @@ class Query: filters: Union[Dict[str, Union[str, int]], str, int, List[Union[List, str, int]]] = None, **kwargs, ): + # Clean up state before each query + self.tables = {} criterion = self.build_conditions(table, filters, **kwargs) + + if len(self.tables) > 1: + primary_table = self.tables[table] + del self.tables[table] + for table_object in self.tables.values(): + criterion = criterion.left_join(table_object).on(table_object.parent == primary_table.name) + if isinstance(fields, (list, tuple)): query = criterion.select(*kwargs.get("field_objects", fields)) From ba51289c3727919feb49d7b1c2286734dc473c09 Mon Sep 17 00:00:00 2001 From: saxenabhishek Date: Tue, 26 Apr 2022 15:59:50 +0530 Subject: [PATCH 08/35] test: update test_multiple_tables_in_filters --- frappe/tests/test_query.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/tests/test_query.py b/frappe/tests/test_query.py index 85d1355d71..949c3e9433 100644 --- a/frappe/tests/test_query.py +++ b/frappe/tests/test_query.py @@ -16,5 +16,5 @@ class TestQuery(unittest.TestCase): ["DocType", "parent", "=", "something"], ], ).get_sql(), - "SELECT * FROM `tabDocType` WHERE `tabBOM Update Log`.`name` LIKE 'f%' AND `tabDocType`.`parent`='something'", + "SELECT * FROM `tabDocType` LEFT JOIN `tabBOM Update Log` ON `tabBOM Update Log`.`parent`=`tabDocType`.`name` WHERE `tabBOM Update Log`.`name` LIKE 'f%' AND `tabDocType`.`parent`='something'", ) From 63e2e328c6c0a1d350b23be4fd13408d54b936a6 Mon Sep 17 00:00:00 2001 From: hrwx Date: Thu, 28 Apr 2022 13:38:36 +0100 Subject: [PATCH 09/35] feat: disable change log --- .../core/doctype/system_settings/system_settings.json | 11 +++++++++-- frappe/public/js/frappe/desk.js | 3 ++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/frappe/core/doctype/system_settings/system_settings.json b/frappe/core/doctype/system_settings/system_settings.json index 0c9b87e618..1247a8c0ee 100644 --- a/frappe/core/doctype/system_settings/system_settings.json +++ b/frappe/core/doctype/system_settings/system_settings.json @@ -71,7 +71,8 @@ "column_break_64", "max_auto_email_report_per_user", "system_updates_section", - "disable_system_update_notification" + "disable_system_update_notification", + "disable_change_log_notification" ], "fields": [ { @@ -497,12 +498,18 @@ "fieldname": "max_auto_email_report_per_user", "fieldtype": "Int", "label": "Max auto email report per user" + }, + { + "default": "0", + "fieldname": "disable_change_log_notification", + "fieldtype": "Check", + "label": "Disable Change Log Notification" } ], "icon": "fa fa-cog", "issingle": 1, "links": [], - "modified": "2022-04-21 09:11:35.218721", + "modified": "2022-04-28 14:31:50.330954", "modified_by": "Administrator", "module": "Core", "name": "System Settings", diff --git a/frappe/public/js/frappe/desk.js b/frappe/public/js/frappe/desk.js index 72e8010605..a8cbe020f3 100644 --- a/frappe/public/js/frappe/desk.js +++ b/frappe/public/js/frappe/desk.js @@ -511,7 +511,8 @@ frappe.Application = class Application { // "version": "12.2.0" // }]; - if (!Array.isArray(change_log) || !change_log.length || window.Cypress) { + if (!Array.isArray(change_log) || !change_log.length || + window.Cypress || cint(frappe.boot.sysdefaults.disable_change_log_notification)) { return; } From 34b1beae5b2701987ee1285864b9ab369f58daf8 Mon Sep 17 00:00:00 2001 From: Vlad Date: Mon, 2 May 2022 20:26:03 +0300 Subject: [PATCH 10/35] fix: Update translation --- frappe/translations/ru.csv | 982 ++++++++++++++++++------------------- 1 file changed, 491 insertions(+), 491 deletions(-) diff --git a/frappe/translations/ru.csv b/frappe/translations/ru.csv index 0af57072e5..7e437c9b3e 100644 --- a/frappe/translations/ru.csv +++ b/frappe/translations/ru.csv @@ -145,7 +145,7 @@ Monthly,Ежемесячно, More,Далее, More Information,Больше информации, More...,Больше..., -Move,перемещение, +Move,Переместить, My Account,Мой аккаунт, New Address,Новый адрес, New Contact,Новый контакт, @@ -178,7 +178,7 @@ Please select Company,"Пожалуйста, выберите компанию", Please select {0},"Пожалуйста, выберите {0}", Please set Email Address,"Пожалуйста, установите адрес электронной почты", Portal,Портал, -Portal Settings,портал Настройки, +Portal Settings,Настройки портала, Preview,Просмотр, Primary,Основной, Print Format,Формат печати, @@ -188,9 +188,9 @@ Private,Личные, Property,Свойство, Public,Публично, Published,Опубликовано, -Purchase Manager,Менеджер поставок, -Purchase Master Manager,Руководитель поставок, -Purchase User,Специалист поставок, +Purchase Manager,Менеджер закупок, +Purchase Master Manager,Мастер закупок, +Purchase User,Специалист закупок, Query Options,Параметры запроса, Range,Диапазон, Rating,Рейтинг, @@ -212,11 +212,11 @@ Report,Отчет, Report Builder,Конструктор отчетов, Report Type,Тип отчета, Reports,Отчеты, -Response,ответ, +Response,Ответ, Role,Роль, -Route,маршрут, +Route,Маршрут, Sales Manager,Менеджер продаж, -Sales Master Manager,Руководитель продаж, +Sales Master Manager,Мастер продаж, Sales User,Продавец, Salutation,Обращение, Sample,Образец, @@ -228,31 +228,31 @@ Search,Поиск, Secret Key,Секретный ключ, Select,Выбрать, Select DocType,Выберите тип документа, -Send Now,Отправить Сейчас, +Send Now,Отправить сейчас, Sent,Отправлено, Series {0} already used in {1},Идентификатор {0} уже используется в {1}, Service,Услуги, Set as Default,Установить по умолчанию, -Settings,настройки, +Settings,Настройки, Shipping,Доставка, -Short Name,Короткое Имя, +Short Name,Короткое имя, Slideshow,Слайд-шоу, Some information is missing,Некоторая информация отсутствует, Source,Источник, Source Name,Имя источника, Standard,Стандартный, -Start Date,Дата Начала, +Start Date,Дата начала, Start Import,Начать импорт, -State,государственный, +State,Состояние, Stopped,Приостановлено, Subject,Тема, Submit,Провести, -Successful,успешный, +Successful,Успешно, Summary,Резюме, Sunday,Воскресенье, System Manager,Менеджер системы, -Target,цель, -Task,задача, +Target,Цель, +Task,Задача, Tax Category,Налоговая категория, Test,Тест, Thank you,Спасибо, @@ -265,7 +265,7 @@ Traceback,Диагностика, URL,URL, Unsubscribed,Отписался, Use Sandbox,Использовать «песочницу», -User,пользователь, +User,Пользователь, User ID,ID пользователя, Users,Пользователи, Validity,Период действия, @@ -286,7 +286,7 @@ old_parent,old_parent, """Company History""","""История компании""", """Parent"" signifies the parent table in which this row must be added","«Родитель» означает родительскую таблицу, в которую должна быть добавлена эта строка", """Team Members"" or ""Management""","""Члены команды"" или ""Управление""", -<head> HTML,HTML, +<head> HTML,<head> HTML, 'In Global Search' not allowed for type {0} in row {1},«В глобальном поиске» не допускается тип {0} в строке {1}, 'In List View' not allowed for type {0} in row {1},"""Режим Просмотра Списком"" не допускается для типа {0} в строке {1}", 'Recipients' not specified,«Получатели» не указаны, @@ -304,7 +304,7 @@ old_parent,old_parent, ; not allowed in condition,; Не допускается в состоянии, "

Default Template

\n

Uses Jinja Templating and all the fields of Address (including Custom Fields if any) will be available

\n
{{ address_line1 }}<br>\n{% if address_line2 %}{{ address_line2 }}<br>{% endif -%}\n{{ city }}<br>\n{% if state %}{{ state }}<br>{% endif -%}\n{% if pincode %} PIN:  {{ pincode }}<br>{% endif -%}\n{{ country }}<br>\n{% if phone %}Phone: {{ phone }}<br>{% endif -%}\n{% if fax %}Fax: {{ fax }}<br>{% endif -%}\n{% if email_id %}Email: {{ email_id }}<br>{% endif -%}\n
","

Шаблон по умолчанию \n <р> Использование дзиндзя Templating и все поля адрес ( в том числе Пользовательские поля если таковые имеются) будут доступны \n
 <код> {{address_line1}} & LT; BR & GT; \n {%, если address_line2%} {{address_line2}} & лт; бр & GT; { % ENDIF -%} \n {{город}} & Lt; BR & GT; \n {%, если государство%} {{состояние}} & Lt; BR & GT; {% ENDIF -%} \n {%, если пин-код%} PIN: {{пин-код}} & Lt; BR & GT; {% ENDIF -%} \n {{страна}} & Lt; BR & GT; \n {%, если телефон%} Телефон: {{телефон}} & Lt; BR & GT; { % ENDIF -%} \n {%, если факс%} Факс: {{FAX}} & Lt; BR & GT; {% ENDIF -%} \n {%, если email_id%} E-mail: {{email_id}} & Lt; BR & GT ; {% ENDIF -%} \n </ код> 

", A Lead with this Email Address should exist,Обращение с этим адресом электронной почты должно существовать, -A list of resources which the Client App will have access to after the user allows it.
e.g. project,"Список ресурсов, которые Клиент App будет иметь доступ к после того, как пользователь позволяет.
например, проект", +A list of resources which the Client App will have access to after the user allows it.
e.g. project,"Список ресурсов, к которым клиентское приложение будет иметь доступ после того, как пользователь разрешит это.
например. проект", A log of request errors,Журнал ошибок запроса, A new account has been created for you at {0},Новая учетная запись была создана для вас в {0}, A symbol for this currency. For e.g. $,"Символ этой валюты. Например, ₽", @@ -337,12 +337,12 @@ Add Contact,Добавить контакт, Add Contacts,Добавить контакты, Add Filter,Добавить фильтр, Add Group,Добавить группу, -Add New Permission Rule,Добавить новое Правило доступа, +Add New Permission Rule,Добавить новое правило доступа, Add Review,Добавить отзыв, Add Signature,Добавить подпись, -Add Subscribers,Добавить Подписчики, +Add Subscribers,Добавить подписчиков, Add Total Row,Добавить итоговую строку, -Add Unsubscribe Link,Добавить ссылку Отказаться, +Add Unsubscribe Link,Добавить ссылку Отписаться, Add User Permissions,Добавить разрешения пользователя, Add a New Role,Добавить новую роль, Add a column,Добавить столбец, @@ -354,7 +354,7 @@ Add custom forms.,Добавить пользовательские формы., Add custom javascript to forms.,Добавить пользовательские JavaScript в формах., Add fields to forms.,Добавление полей в формах., Add meta tags to your web pages,Добавьте метатеги на свои веб-страницы, -Add script for Child Table,Добавить скрипт для Child Table, +Add script for Child Table,Добавить скрипт для дочерней таблицы, Add to table,Добавить в таблицу, Add your own translations,Добавить свои собственные переводы, "Added HTML in the <head> section of the web page, primarily used for website verification and SEO","Добавлена HTML в <HEAD> часть веб-страницы, в основном используется для проверки веб-сайтов и SEO", @@ -368,7 +368,7 @@ Addresses And Contacts,Адреса и контакты, Adds a client custom script to a DocType,Добавляет клиентский пользовательский скрипт в DocType, Adds a custom field to a DocType,Добавляет настраиваемое поле в DocType, Admin,Администратор, -Administrator Logged In,Администратор Записан В, +Administrator Logged In,Администратор вошел в систему, Administrator accessed {0} on {1} via IP Address {2}.,Администратор обращались {0} {1} с помощью IP-адреса {2}., Advanced,Продвинутый, Advanced Control,Расширенный контроль, @@ -380,7 +380,7 @@ All customizations will be removed. Please confirm.,"Все настройки "All possible Workflow States and roles of the workflow. Docstatus Options: 0 is""Saved"", 1 is ""Submitted"" and 2 is ""Cancelled""","Все возможные статусы и роли бизнес-процесса. Варианты статуса документа: 0 — ""Сохранён (черновик)"", 1 — ""Проведён/ Утвержден"" и 2 — ""Отменен""", All-uppercase is almost as easy to guess as all-lowercase.,"All-прописные почти так же легко догадаться, как все-строчными буквами.", Allocated To,Выделяемых на, -Allow,Позволять, +Allow,Разрешить, Allow Bulk Edit,Разрешить массовое редактирование, Allow Comments,Разрешить комментарии, Allow Consecutive Login Attempts ,Разрешить последовательные попытки авторизации, @@ -388,18 +388,18 @@ Allow Dropbox Access,Разрешить доступ Dropbox, Allow Edit,Разрешить редактирование, Allow Guest to View,"Разрешить для гостей, чтобы посмотреть", Allow Import (via Data Import Tool),Разрешить импорт (с помощью инструмента импорта данных), -Allow Incomplete Forms,Разрешить Неполные формы, +Allow Incomplete Forms,Разрешить неполные формы, Allow Login After Fail,Разрешить авторизацию после неудачной попытки, Allow Login using Mobile Number,Разрешить вход в систему с помощью мобильного номера, Allow Login using User Name,Разрешить использование имени пользователя, Allow Modules,Разрешить модули, Allow Multiple,Разрешить многократный, Allow Print,Разрешить печать, -Allow Print for Cancelled,Разрешить печать для Отменено, -Allow Print for Draft,Разрешить печать для проекта, +Allow Print for Cancelled,Разрешить печать для отмененых, +Allow Print for Draft,Разрешить печать для черновика, Allow Read On All Link Options,Разрешить чтение всех ссылок, Allow Rename,Разрешить переименовать, -Allow Roles,Разрешить роли, +Allow Roles,Разрешить ролям, Allow Self Approval,Разрешить самостоятельное утверждение, Allow approval for creator of the document,Разрешает утверждать создателю документа, Allow events in timeline,Разрешить события на временной шкале, @@ -412,15 +412,15 @@ Allow user to login only after this hour (0-24),Разрешить пользо Allow user to login only before this hour (0-24),Разрешать пользователю входить только до этого часа (0—24), Allowed,Разрешено, Allowed In Mentions,Разрешено в упоминаниях, -"Allowing DocType, DocType. Be careful!","Разрешение DocType, DocType. Осторожно!", +"Allowing DocType, DocType. Be careful!","Разрешение DocType, DocType. Будьте осторожны!", Already Registered,Уже регистрировались, Also adding the dependent currency field {0},Также добавление зависимого валютного поля {0}, "Always add ""Draft"" Heading for printing draft documents",Всегда добавляйте "Черновик" Заголовок для печати проектов документов, -Always use Account's Email Address as Sender,Всегда используйте учетную запись Адрес электронной почты в качестве отправителя, -Always use Account's Name as Sender's Name,Всегда используйте имя учетной записи в качестве имени отправителя, +Always use Account's Email Address as Sender,Всегда использовать почту учетной записи в качестве отправителя, +Always use Account's Name as Sender's Name,Всегда использовать имя учетной записи в качестве имени отправителя, Amend,Изменен, -Amending,исправление, -Amount Based On Field,Сумма На основании поле, +Amending,Исправление, +Amount Based On Field,Сумма на основании поля, Amount Field,Сумма поле, Amount must be greater than 0.,Сумма должна быть больше 0., An error occured during the payment process. Please contact us.,В процессе оплаты произошла ошибка. Пожалуйста свяжитесь с нами., @@ -443,12 +443,12 @@ App {0} is not installed,Приложение {0} не установленно, Append To,Добавить к, Append To can be one of {0},Добавить к может быть одним из {0}, Append To is mandatory for incoming mails,Добавить к является обязательным для входящих сообщений, -"Append as communication against this DocType (must have fields, ""Status"", ""Subject"")","Добавьте в связи с этой DocType (должен иметь поля, ""статус"", ""Тема"")", +"Append as communication against this DocType (must have fields, ""Status"", ""Subject"")","Добавить как коммуникацию для этого DocType (должен иметь поля, ""Статус"", ""Тема"")", Applicable Document Types,Применимые типы документов, Apply,Подать заявление, Apply Strict User Permissions,Применение строгих пользовательских разрешений, Apply To All Document Types,Применить ко всем типам документов, -Apply this rule if the User is the Owner,"Применить это правило, если Пользователь Владелец", +Apply this rule if the User is the Owner,"Применить это правило, если пользователь является владелец", Apply to all Documents Types,Применить ко всем типам документов, Appreciate,понимать, Appreciation,Признательность, @@ -456,22 +456,22 @@ Archive,Архив, Archived,Архивные, Archived Columns,архивные Колонны, Are you sure you want to delete the attachment?,"Вы уверены, что хотите удалить вложение?", -Are you sure you want to relink this communication to {0}?,"Вы уверены, что хотите перелинковать это сообщение на {0}?", -Are you sure?,Уверены ли вы?, +Are you sure you want to relink this communication to {0}?,"Вы уверены, что хотите перелинковать эту куммуникацию на {0}?", +Are you sure?,Вы уверены?, Arial,Arial, "As a best practice, do not assign the same set of permission rule to different Roles. Instead, set multiple Roles to the same User.","В качестве лучшего решения, не присваивайте одинаковый набор правил доступа для различных ролей. Вместо этого, установите несколько ролей одному и тому же пользователю.", Assign Condition,Назначить условие, Assign To Users,Назначить пользователям, "Assign one by one, in sequence","Назначить по одному, в последовательности", -Assign to me,Назначить мне, +Assign to me,Назначить самому себе, Assign to the one who has the least assignments,"Назначьте тому, у кого меньше всего заданий", -Assigned,назначенный, +Assigned,Назначенный, Assigned By,Назначаются, Assigned By Full Name,Присваиваемый Полное имя, Assigned By Me,Назначенные мной, Assigned To,Назначено для, Assigned To/Owner,Назначено / Владельца, -Assignment,назначение, +Assignment,Назначение, Assignment Complete,Назначение Полная, Assignment Completed,Задание выполнено, Assignment Rule,Правило назначения, @@ -504,11 +504,11 @@ Authorize URL,Авторизованный URL, Authorized,уполномоченный, Auto,Авто, Auto Email Report,Автоотчет по электронной почте, -Auto Name,Авто Имя, +Auto Name,Авто имя, Auto Reply Message,Автоматический ответ, Auto assignment failed: {0},Автоматическое назначение не выполнено: {0}, Automatically Assign Documents to Users,Автоматически назначать документы пользователям, -Automation,автоматизация, +Automation,Автоматизация, Avatar,Аватар, Average,Средний, Average of {0},Среднее из {0}, @@ -518,13 +518,13 @@ Avoid sequences like abc or 6543 as they are easy to guess,"Избегайте Avoid years that are associated with you.,"Избегайте лет, которые связаны с вами.", Awaiting Password,В ожидании пароля, Away,Далеко, -BCC,BCC, +BCC,Скрытая копия, Back to Desk,Вернуться к списку, Back to Login,Вернуться на страницу входа, Background Color,Цвет фона, Background Email Queue,Фоновая очередь электронной почты, Background Jobs,Фоновые задания, -Background Workers,Фоновые Рабочие, +Background Workers,Фоновые процессы, Backup,Резервное копирование, Backup Frequency,Частота резервного копирования, Backup Limit,Ограничение резервного копирования, @@ -542,18 +542,18 @@ Better add a few more letters or another word,Лучше добавить еще Between,Между, Bio,Биография, Birth Date,Дата рождения, -Block Module,Блок Модуль, +Block Module,Блок модуль, Block Modules,Блок модули, Blocked,Блокирован, Blog,Блог, -Blog Category,Категория Блога, +Blog Category,Категория блога, Blog Intro,Блог Intro, -Blog Introduction,Блог Введение, +Blog Introduction,Блог введение, Blog Post,Пост блога, -Blog Settings,Настройки Блога, +Blog Settings,Настройки блога, Blog Title,Название блога, Blogger,Блоггер, -Bot,Bot, +Bot,Бот, Both DocType and Name required,И DocType и имя требуется, Both login and password required,Необходимо ввести логин и пароль, Bounced,Возвращенные, @@ -563,20 +563,20 @@ Brand HTML,Марка HTML, Brand Image,Изображение бренда, Breadcrumbs,Панировочные сухари, Browser not supported,Браузер не поддерживается, -Brute Force Security,Защита от Брутфорса, +Brute Force Security,Защита от перебора, Build Report,Построить отчет, Bulk Delete,Массовое удаление, -Bulk Edit {0},Массовая Правка {0}, +Bulk Edit {0},Массовая правка {0}, Bulk Rename,Массовое переименование, Bulk Update,Массовое обновление, Busy,Занятый, Button,Кнопка, -Button Help,Кнопка Помощь, -Button Label,Кнопка Этикетка, +Button Help,Кнопка помощь, +Button Label,Кнопка ярлык, Bypass Two Factor Auth for users who login from restricted IP Address,"Обход двух факторов для пользователей, которые подключаются с ограниченным IP-адресом", Bypass restricted IP Address check If Two Factor Auth Enabled,Обход ограниченного IP-адреса. Если включен параметр Two Factor Auth, -CC,CC, -"CC, BCC & Email Template","CC, BCC и шаблон электронной почты", +CC,Копия, +"CC, BCC & Email Template","Копия, Скрытая копия и Шаблон электронной почты", CSS,CSS, CSV,CSV, Cache Cleared,Кэш очищен, @@ -584,22 +584,22 @@ Calculate,Рассчитать, Calendar Name,Имя календаря, Calendar View,Просмотр календаря, Call,Звонок, -Can Read,Может Читать, -Can Share,Может Поделиться, -Can Write,Может Написать, +Can Read,Может читать, +Can Share,Может поделиться, +Can Write,Может изменять, Can't identify open {0}. Try something else.,Не удается идентифицировать открытое {0}. Попробуйте что-нибудь другое., Can't save the form as data import is in progress.,Невозможно сохранить форму в процессе импорта данных., Cancel {0} documents?,Отменить {0} документы?, Cancelled Document restored as Draft,Отмененный документ восстановлен как черновик, -Cancelling,отмена, +Cancelling,Отмена, Cancelling {0},Отмена {0}, Cannot Remove,Не удается удалить, -Cannot cancel before submitting. See Transition {0},Нельзя отменить перед проведением. См. Переход {0}, +Cannot cancel before submitting. See Transition {0},Нельзя отменить перед проведением. См. транзакцию {0}, Cannot change docstatus from 0 to 2,Нельзя изменить статус документа с 0 на 2, Cannot change docstatus from 1 to 0,Нельзя изменить статус документа с 1 на 0, Cannot change header content,Невозможно изменить содержимое заголовка, Cannot change state of Cancelled Document. Transition row {0},Невозможно изменить состояние Отмененные документа. Переход строка {0}, -Cannot change user details in demo. Please signup for a new account at https://erpnext.com,Невозможно изменить данные пользователя в демо. Подпишитесь на новую учетную запись на https://erpnext.com, +Cannot change user details in demo. Please signup for a new account at https://erpnext.com,Невозможно изменить данные пользователя в демо. Создайте новую учетную запись на https://erpnext.com, Cannot create a {0} against a child document: {1},Невозможно создать {0} против дочернего документа: {1}, Cannot delete Home and Attachments folders,Не удается удалить Дома и папки Вложения, Cannot delete file as it belongs to {0} {1} for which you do not have permissions,"Не удается удалить файл, поскольку он принадлежит {0} {1}, для которого у вас нет прав доступа", @@ -609,10 +609,10 @@ Cannot delete {0},Не удается удалить {0}, Cannot delete {0} as it has child nodes,"Не удается удалить {0}, поскольку он имеет дочерние узлы", "Cannot edit Standard Notification. To edit, please disable this and duplicate it","Не удается изменить стандартное уведомление. Чтобы отредактировать, отключите это и продублируйте его.", Cannot edit a standard report. Please duplicate and create a new report,"Изменять стандартный отчёт нельзя. Пожалуйста, создайте новый отчёт из копии", -Cannot edit cancelled document,Не можете редактировать отменен документ, -Cannot edit standard fields,Не можете редактировать стандартные поля, +Cannot edit cancelled document,Нельзя редактировать отмененый документ, +Cannot edit standard fields,Нельзя редактировать стандартные поля, Cannot have multiple printers mapped to a single print format.,"Невозможно иметь несколько принтеров, сопоставленных с одним форматом печати.", -Cannot link cancelled document: {0},Не можете связать отменен документ: {0}, +Cannot link cancelled document: {0},Нельзя привязать отмененый документ: {0}, Cannot map because following condition fails: ,"Невозможно отобразить, потому что не выполняется следующее условие:", Cannot move row,Невозможно переместить строку, Cannot open instance when its {0} is open,"Не могу открыть экземпляр, когда его {0} открыто", @@ -633,7 +633,7 @@ Chaining Hash,Цепочный хэш, Change Label (via Custom Translation),Изменение этикетки (с помощью пользовательского перевода), Change Password,Изменить пароль, "Change field properties (hide, readonly, permission etc.)","Изменение свойств поля (скрыть, только для чтения, доступ и т.д.)", -Channel,канал, +Channel,Канал, Chart Name,Название диаграммы, Chart Options,Параметры диаграммы, Chart Source,Источник диаграммы, @@ -643,11 +643,11 @@ Chat,Чат, Chat Background,История чата, Chat Message,Чат-сообщение, Chat Operators,Операторы чата, -Chat Profile,Профиль пользователя Chat, +Chat Profile,Профиль пользователя чата, Chat Profile for User {0} exists.,Профиль чата для пользователя {0} существует., Chat Room,Общение, Chat Room Name,Имя в чате, -Chat Room User,Пользователь Chat Room, +Chat Room User,Пользователь комнаты чата, Chat Token,Чат-токен, Chat Type,Тип чата, Chat messages and other notifications.,Чат сообщения и другие уведомления., @@ -664,7 +664,7 @@ Child Tables are shown as a Grid in other DocTypes,Дочерние таблиц Choose authentication method to be used by all users,"Выберите метод аутентификации, который будет использоваться всеми пользователями.", Clear Error Logs,Очистить журналы ошибок, Clear User Permissions,Очистить разрешения пользователя, -Clear all roles,Очистите все роли, +Clear all roles,Отчистить все роли, "Clearing end date, as it cannot be in the past for published pages.","Очистка даты окончания, поскольку она не может быть в прошлом для опубликованных страниц.", Click here to post bugs and suggestions,"Нажмите здесь, чтобы сообщать об ошибках и предложениях", Click here to verify,"Нажмите здесь, чтобы проверить,", @@ -673,7 +673,7 @@ Click on the link below to download your data,"Нажмите на ссылку Click on the link below to verify your request,"Нажмите на ссылку ниже, чтобы подтвердить свой запрос", Click table to edit,Нажмите для редактирования таблиц, Click to Set Filters,"Нажмите, чтобы установить фильтры", -Clicked,Нажал, +Clicked,Нажато, Client Credentials,Учетные данные клиента, Client Information,Информация о клиенте, Client Script,Скрипт клиента, @@ -684,15 +684,15 @@ Collapsible Depends On,Складные Зависит от, Column,Колонка, Column {0} already exist.,Столбец {0} уже существует., Column Break,Разрыв столбца, -Column Labels:,Колонка Ярлыки:, +Column Labels:,Колонка ярлыки:, Column Name,Имя столбца, Column Name cannot be empty,Имя столбца не может быть пустым, Columns,Колонны, Columns based on,Колонки на основе…, Combination of Grant Type ({0}) and Response Type ({1}) not allowed,Сочетание типа гранта ( {0} ) и типа ответа ( {1} ) не допускается, -Comment By,Комментарий По, +Comment By,Комментарий по, Comment Email,Комментарий по электронной почте, -Comment Type,Комментарий Тип, +Comment Type,Тип комментариев, Comment can only be edited by the owner,Комментарий может редактировать только владелец, Commented on {0}: {1},Комментарии {0}: {1}, Comments and Communications will be associated with this linked document,Комментарии и коммуникации будут связаны с этой связанного документа, @@ -701,7 +701,7 @@ Common names and surnames are easy to guess.,Общие имена и фамил Communicated via {0} on {1}: {2},Сообщается через {0} {1}: {2}, Communication Type,Вид коммуникации, Company History,История компании, -Company Introduction,Компания Введение, +Company Introduction,Компания - введение, Compiled Successfully,Успешно скомпилировано, Complete By,Завершить до, Complete Registration,Полная регистрация, @@ -709,27 +709,27 @@ Complete Setup,Завершение установки, Completed By,Завершено, Compose Email,Написать письмо, Condition Detail,Детализация условий, -Conditions,условия, +Conditions,Условия, Configure Chart,Настроить диаграмму, Configure Charts,Настроить графики, -Confirm,подтвердить, +Confirm,Подтвердить, Confirm Deletion of Data,Подтвердите удаление данных, Confirm Request,Подтвердите запрос, -Confirm Your Email,Подтвердите Ваш Адрес Электронной Почты, +Confirm Your Email,Подтвердите ваш адрес электронной почты, Confirmed,Подтвердил, Connected to QZ Tray!,Подключен к QZ Tray!, Connection Name,Название соединения, -Connection Success,Успех подключения, +Connection Success,Успешно подключено, Connection lost. Some features might not work.,Соединение потеряно. Некоторые функции могут не работать., Connector Name,Имя соединителя, Connector Type,Тип соединителя, Contact Us Settings,Контакты Настройки, "Contact options, like ""Sales Query, Support Query"" etc each on a new line or separated by commas.","Параметры контакта, как ""Sales Query, поддержки Query"" и т.д. каждого с новой строки или через запятую.", -Contacts,контакты, +Contacts,Контакты, Content (HTML),Контент (HTML), -Content (Markdown),Содержание (Уценка), -Content Hash,Содержимое Hash, -Content web page.,Содержимое веб-страницы., +Content (Markdown),Контент (Markdown), +Content Hash,Контент Hash, +Content web page.,Контент веб-страницы., Conversation Tones,Разговорные тона, Copyright,Авторское право, Core,Центр управления, @@ -740,24 +740,24 @@ Could not find {0} in {1},Не удалось найти {0} в {1}, Could not identify {0},Не удалось определить {0}, Count,подсчитывать, Country Name,Название страны, -County,округ, +County,Округ, Create Chart,Создать диаграмму, Create New,Создать, Create Post,Создать пост, -Create User Email,Создание Электронной почты Пользователя, +Create User Email,Создать электронной почты пользователя, Create a New Format,Создать новый формат, Create a new record,Создать новую запись, Create a new {0},Создать {0}, Create and Send Newsletters,Создание и отправка рассылки, Create and manage newsletter,Создать и управлять рассылкой, -Created,созданный, +Created,Созданный, Created Custom Field {0} in {1},Дата создания настраиваемого поля {0} в {1}, Created On,Дата создания, -Criticism,критика, -Criticize,критиковать, -Ctrl + Down,Ctrl + Вниз, -Ctrl + Up,Ctrl +, -Ctrl+Enter to add comment,"Ctrl + Enter, чтобы добавить комментарий", +Criticism,Критика, +Criticize,Критиковать, +Ctrl + Down,Ctrl + Down, +Ctrl + Up,Ctrl + Up, +Ctrl+Enter to add comment,"Ctrl+Enter, чтобы добавить комментарий", Currency Name,Название валюты, Currency Precision,Точность валюты, Current Mapping,Текущее сопоставление, @@ -769,28 +769,28 @@ Currently Viewing,Сейчас просматривают, Currently updating {0},В настоящее время обновление {0}, Custom,Пользовательские, Custom Base URL,Пользовательский базовый URL, -Custom CSS,Свой CSS, +Custom CSS,Пользовательский CSS, Custom DocPerm,Пользовательские DocPerm, Custom Field,Пользовательские поля, Custom Fields can only be added to a standard DocType.,Пользовательские поля могут быть добавлены только к стандартному типу документа., Custom Fields cannot be added to core DocTypes.,Пользовательские поля не могут быть добавлены в основные типы документов., -Custom Format,Собственный формат, -Custom HTML Help,Особый HTML Помощь, +Custom Format,Пользовательский формат, +Custom HTML Help,Пользовательский HTML Помощь, Custom JS,Пользовательский JS, Custom Menu Items,Пользовательские пункты меню, Custom Report,Пользовательский отчет, Custom Reports,Пользовательские отчеты, Custom Role,Пользовательские роли, -Custom Script,Специального сценария, -Custom Sidebar Menu,Пользовательские боковой панели меню, -Custom Translations,Пользовательские Переводы, +Custom Script,Пользовательский сценарий, +Custom Sidebar Menu,Пользовательское боковое меню, +Custom Translations,Пользовательские переводы, Customization,Пользовательские настройки, Customizations Reset,Сброс настроек, Customizations for {0} exported to:
{1},Настройки для {0} экспортированы в:
{1}, Customize Form,Настроить форму, Customize Form Field,Настроить поля формы, "Customize Label, Print Hide, Default etc.","Настроить Label, распечатать спрятать, Default т.д.", -Customize...,Настройка ..., +Customize...,Пользовательские настройки..., "Customized Formats for Printing, Email","Индивидуальные форматы для печати, электронной почты", Customized HTML Templates for printing transactions.,Индивидуальные шаблоны HTML для печатных операций., Cut,Порез, @@ -806,7 +806,7 @@ Dashboards,Сводки, Data,Данные, Data Export,Экспорт данных, Data Import,Импорт данных, -Data Import Template,Шаблон Импорт данных, +Data Import Template,Шаблон импорт данных, Data Migration,Перенос данных, Data Migration Connector,Разделитель данных, Data Migration Mapping,Миграция данных, @@ -824,19 +824,19 @@ Day of Week,День недели, Days After,Дней после, Days Before,Дней до, Days Before or After,Дней до или после, -"Dear System Manager,","Уважаемый Менеджер системы,", +"Dear System Manager,","Уважаемый менеджер системы,", "Dear User,","Дорогой пользователь,", Dear {0},Уважаемый {0}, Default Address Template cannot be deleted,Адрес по умолчанию шаблона не может быть удален, -Default Inbox,По умолчанию Входящие, -Default Incoming,По умолчанию Входящий, -Default Outgoing,По умолчанию Исходящие, +Default Inbox,По умолчанию входящие, +Default Incoming,По умолчанию для входящих, +Default Outgoing,По умолчанию для исходящих, Default Print Format,Печатная форма по умолчанию, Default Print Language,Язык печати по умолчанию, -Default Redirect URI,По умолчанию Перенаправление URI, -Default Role at Time of Signup,По умолчанию Роль Время в Signup, -Default Sending,По умолчанию Отправка, -Default Sending and Inbox,По умолчанию Отправка и Входящие, +Default Redirect URI,По умолчанию перенаправление URI, +Default Role at Time of Signup,Роль по умолчанию во время регистрации, +Default Sending,По умолчанию для отправки, +Default Sending and Inbox,По умолчанию отправка и получение, Default Sort Field,Поле сортировки по умолчанию, Default Sort Order,Порядок сортировки по умолчанию, Default Value,Значение по умолчанию, @@ -851,10 +851,10 @@ Delete comment?,Удалить комментарий?, Delete this record to allow sending to this email address,"Удалить эту запись, чтобы разрешить отправку на этот адрес электронной почты", Delete {0} items permanently?,Удалить {0} продуктов навсегда?, Deleted,Удаленный, -Deleted DocType,Удаляется DocType, -Deleted Document,Удаляется документ, +Deleted DocType,Удаленный DocType, +Deleted Document,Удаленный документ, Deleted Documents,Удаленные документы, -Deleted Name,Удаляется Имя, +Deleted Name,Удаляется имя, Deleting {0},Удаление {0}, Depends On,Зависит от, Descendants Of,Потомки, @@ -868,7 +868,7 @@ Did not cancel,Не отменить, Did not find {0} for {0} ({1}),Не нашли {0} {0} ({1}), Did not remove,Не удален, "Different ""States"" this document can exist in. Like ""Open"", ""Pending Approval"" etc.","Документ может содержать различные Статусы. Например, ""Создан"", ""Ожидает утверждения"" и т.д.", -Direct,непосредственный, +Direct,Непосредственный, Direct room with {0} already exists.,Прямая комната с {0} уже существует., Disable Auto Refresh,Отключить автоматическое обновление, Disable Count,Отключить счет, @@ -879,16 +879,16 @@ Disable SMTP server authentication,Отключить аутентификаци Disable Sidebar Stats,Отключить статистику боковой панели, Disable Signup,Отключение Регистрация, Disable Standard Email Footer,Отключить стандартный нижний колонтитул электронной почты, -Discard,отбрасывать, +Discard,Отбросить, Display,Показать, Display Depends On,Показание зависит от, Do not allow user to change after set the first time,Не позволяйте пользователю изменять после установить в первый раз, Do not edit headers which are preset in the template,"Не редактируйте заголовки, которые заданы в шаблоне", Do not send Emails,Не отправлять письма, -Doc Event,Событие Doc, -Doc Events,События Doc, +Doc Event,Событие документа, +Doc Events,События документа, Doc Status,Статус документа, -DocField,Поле документа, +DocField,DocField, DocPerm,DocPerm, DocShare,DocShare, DocType {0} provided for the field {1} must have atleast one Link field,"DocType {0}, предоставленный для поля {1}, должен иметь как минимум одно поле Link", @@ -902,10 +902,10 @@ Doctype required,Требуется Doctype, Document,Документ, Document Follow,Документ следовать, Document Follow Notification,Документ следовать уведомлению, -Document Queued,Документ Queued, +Document Queued,Документ в очереди, Document Restored,Восстановленный документ, Document Share Report,Документ Поделиться Пожаловаться, -Document States,Статусы Документа, +Document States,Состояния документа, Document Type is not importable,Тип документа не импортируется, Document Type is not submittable,Тип документа не подлежит отправке, Document Type to Track,Тип документа для отслеживания, @@ -947,7 +947,7 @@ Edit DocType,Редактирование DocType, Edit Filter,Изменить фильтр, Edit Format,Изменить формат, Edit HTML,Изменить HTML, -Edit Heading,Редактировать Заголовок, +Edit Heading,Редактировать заголовок, Edit Properties,Изменить свойства, Edit to add content,"Изменить, чтобы добавить содержание", Edit {0},Изменить {0}, @@ -971,7 +971,7 @@ Email Queue records.,Записи очереди электронной почт Email Reply Help,Ответить на Email Помощь, Email Rule,Правило электронной почты, Email Server,Сервер электронной почты, -Email Settings,Настройки Электронной Почты, +Email Settings,Настройки электронной почты, Email Signature,Подпись электронной почты, Email Status,Статус электронной почты, Email Sync Option,Опция синхронизации электронной почты, @@ -1044,7 +1044,7 @@ Excel,превосходить, Exception,Исключение, Exception Type,Тип исключения, Execution Time: {0} sec,Время выполнения: {0} сек, -Expert,эксперт, +Expert,Эксперт, Expiration time,Время истечения, Expire Notification On,Expire Уведомление о, Expires In,Истекает, @@ -1069,7 +1069,7 @@ Fetch Images,Получение изображений, Fetch attached images from document,Получение прикрепленных изображений из документа, "Field ""route"" is mandatory for Web Views",Поле «маршрут» обязательно для веб-представлений, "Field ""value"" is mandatory. Please specify value to be updated","Поле ""Значение"" является обязательным. Пожалуйста, укажите значение, чтобы обновить", -Field Description,Описание Поля, +Field Description,Описание поля, Field Maps,Карты полей, Field Type,Тип поля, "Field that represents the Workflow State of the transaction (if field is not present, a new hidden Custom Field will be created)","Поле, показывающее статус бизнес-процесса (если поле отсутствует, будет создано новое скрытое настраиваемое поле)", @@ -1128,28 +1128,28 @@ Fold must come before a Section Break,Сложите должны прийти Folder,Папка, Folder name should not include '/' (slash),Имя папки не должно включать «/» (косая черта), Folder {0} is not empty,Папка {0} не пуста, -Follow,следить, +Follow,Следить, Followed by,С последующим, Following fields are missing:,Эти поля отсутствуют:, Following fields have missing values:,Эти поля имеют пропущенные значения:, Font,Шрифт, Font Size,Размер шрифта, Fonts,Шрифты, -Footer,Низ страницы, +Footer,Нижний колонтитул, Footer HTML,Нижний колонтитул HTML, -Footer Items,Элементы колонтитула, +Footer Items,Элементы нижнего колонтитула, Footer will display correctly only in PDF,Нижний колонтитул будет отображаться правильно только в PDF, For Document Type,Для типа документа, -"For Links, enter the DocType as range.\nFor Select, enter list of Options, each on a new line.","Для ссылки, введите DOCTYPE как диапазона. Для Select, введите список вариантов, каждый с новой строки.", +"For Links, enter the DocType as range.\nFor Select, enter list of Options, each on a new line.","Для ссылки, введите DOCTYPE как диапазона.\nДля выбора, введите список вариантов, каждый с новой строки.", For User,Для пользователей, -For Value,Для ценности, +For Value,Для значений, "For currency {0}, the minimum transaction amount should be {1}",Для валюты {0} минимальная сумма транзакции должна быть {1}, For example if you cancel and amend INV004 it will become a new document INV004-1. This helps you to keep track of each amendment.,"Например, если вы отмените и измените INV004, он станет новым документом INV004-1. Это поможет вам отследить каждую правку.", "For example: If you want to include the document ID, use {0}","Например: Если вы хотите добавить идентификатор документа, используйте {0}", "For updating, you can update only selective columns.","Для обновления, вы можете обновить только выборочные столбцы.", For {0} at level {1} in {2} in row {3},Для {0} на уровне {1} в {2} в строке {3}, Force,Принудительно, -Force Show,Force Show, +Force Show,Принудительно показывать, Forgot Password,Забыли пароль, Forgot Password?,Забыли пароль?, Form Customization,Настройка формы, @@ -1163,7 +1163,7 @@ Frames,Рамки, Frappe,Frappe, Frappe Framework,Frappe Framework, Friendly Title,Упрощённое наименование, -From Date Field,Поле даты, +From Date Field,Из поля даты, From Document Type,Из типа документа, From Full Name,От полного имени, Full Page,Полная страница, @@ -1179,13 +1179,13 @@ Generate New Report,Создать новый отчет, Generated File,Сгенерированный файл, Geo,Гео, Geolocation,Геолокация, -Get Alerts for Today,Виртуальный на сегодняшний день, +Get Alerts for Today,Получить оповещения на сегодня, Get Contacts,Получить контакты, Get Fields,Получить поля, Get your globally recognized avatar from Gravatar.com,Получить всемирно признанный аватара из Gravatar.com, GitHub,GitHub, Give Review Points,Дайте очки обзора, -Global Unsubscribe,Глобальный Отказаться, +Global Unsubscribe,Глобальная отписка, Go to the document,Перейти к документу, Go to this URL after completing the form (only for Guest users),Перейдите по этому URL-адресу после заполнения формы (только для гостевых пользователей), Go to {0},Перейти к {0}, @@ -1211,7 +1211,7 @@ Has Domain,Имеет домен, Has Role,Имеет роль, Has Web View,Имеет Web View, Have an account? Login,Уже есть аккаунт? Авторизоваться, -Header,Шапка, +Header,Заголовок, Header HTML,Заголовок HTML, Header HTML set from attachment {0},HTML-код заголовка из вложения {0}, Header Image,Заглавное изображение, @@ -1221,7 +1221,7 @@ Hello {0},"Здравствуйте, {0}", Hello!,Здравствуйте!, Help Articles,Статьи помощи, Help Category,Категория помощи, -Help on Search,Помощь в Поиске, +Help on Search,Помощь в поиске, "Help: To link to another record in the system, use ""#Form/Note/[Note Name]"" as the Link URL. (don't use ""http://"")","Помощь: Чтобы связать с другой записью в системе, используйте «# Form/Note/[Название статьи]», в виде ссылки URL. (Не используйте «http://»)", Helvetica,Helvetica, Hi {0},Привет {0}, @@ -1230,7 +1230,7 @@ Hide Footer Signup,Скрыть колонтитул регистрации, Hide Sidebar and Menu,Скрыть боковую панель и меню, Hide Standard Menu,Скрыть стандартное меню, Hide Weekends,Скрыть выходные, -Hide details,Скрыть детали, +Hide details,Скрыть подробности, Hide footer in auto email reports,Скрыть нижний колонтитул в автоответах электронной почты, Higher priority rule will be applied first,Правило с более высоким приоритетом будет применено первым, Highlight,Выделить, @@ -1238,9 +1238,9 @@ Highlight,Выделить, Home Page,Домашняя Страница, Home Settings,Домашние настройки, Home/Test Folder 1,Главная/Тестовая Папка 1, -Home/Test Folder 1/Test Folder 3,Главная/Тестовая Папка 1/ Тестовая Папка 3, +Home/Test Folder 1/Test Folder 3,Главная/Тестовая Папка 1/Тестовая Папка 3, Home/Test Folder 2,Главная/Тестовая Папка 2, -Host,Хозяин, +Host,Host, Hostname,Hostname, "How should this currency be formatted? If not set, will use system defaults","Как следует отображать числа в этой валюте? Если не указано, то будут использоваться системные значения", I found these: ,Я нашел следующее:, @@ -1251,25 +1251,25 @@ Identity Details,Сведения о личности, Idx,Idx, "If Apply Strict User Permission is checked and User Permission is defined for a DocType for a User, then all the documents where value of the link is blank, will not be shown to that User","Если флажок Apply Strict User Permission установлен, а для пользователя DocType для пользователя задано разрешение пользователя, тогда все документы, где значение ссылки пустым, не будут показаны этому пользователю", If Checked workflow status will not override status in list view,"Если установлен флажок, статус процесса не будет отменять статус в журнале", -If Owner,Если Владелец, -"If a Role does not have access at Level 0, then higher levels are meaningless.","Если Роль не имеет доступа на уровне 0, то более высокие уровни не имеют смысла.", -"If checked, all other workflows become inactive.","Если этот флажок установлен, все остальные рабочие процессы становятся неактивными.", -"If checked, this field will be not overwritten based on Fetch From if a value already exists.","Если флажок установлен, это поле не будет перезаписано на основе извлечения из, если значение уже существует.", +If Owner,Если владелец, +"If a Role does not have access at Level 0, then higher levels are meaningless.","Если роль не имеет доступа на уровне 0, то более высокие уровни не имеют смысла.", +"If checked, all other workflows become inactive.","Если этот флажок установлен, то все остальные рабочие процессы становятся неактивными.", +"If checked, this field will be not overwritten based on Fetch From if a value already exists.","Если флажок установлен, это поле не будет перезаписано на основе Извлечено из, если значение уже существует.", "If checked, users will not see the Confirm Access dialog.","Если этот флажок установлен, пользователи не будут видеть диалоговое окно подтверждения доступа.", -"If disabled, this role will be removed from all users.","Если эта функция отключена, эта роль будет удалена от всех пользователей.", +"If disabled, this role will be removed from all users.","Если эта функция отключена, эта роль будет удалена у всех пользователей.", "If enabled, user can login from any IP Address using Two Factor Auth, this can also be set for all users in System Settings","Если включено, пользователь может войти в систему с любого IP-адреса, используя двухфакторную аутентификацию, это также можно установить для всех пользователей в настройках системы.", -"If enabled, all users can login from any IP Address using Two Factor Auth. This can also be set only for specific user(s) in User Page","Если включено, все пользователи могут войти в систему с любого IP-адреса, используя Two Factor Auth. Это также можно установить только для определенных пользователей (пользователей) на странице пользователя", +"If enabled, all users can login from any IP Address using Two Factor Auth. This can also be set only for specific user(s) in User Page","Если включено, все пользователи могут войти в систему с любого IP-адреса, используя двухфакторную аутентификацию. Это также можно установить только для определенных пользователей на странице пользователя", "If enabled, changes to the document are tracked and shown in timeline","Если включено, изменения в документе отслеживаются и отображаются на временной шкале.", "If enabled, document views are tracked, this can happen multiple times","Если включено, просмотры документов отслеживаются, это может происходить несколько раз", "If enabled, the document is marked as seen, the first time a user opens it","Если этот параметр включен, документ помечается как видимый, когда пользователь впервые открывает его", -"If enabled, the password strength will be enforced based on the Minimum Password Score value. A value of 2 being medium strong and 4 being very strong.","Если включено, сила пароля будет применяться в зависимости от значения минимального пароля. Значение 2 является средним сильным, а 4 - очень сильным.", -"If enabled, users who login from Restricted IP Address, won't be prompted for Two Factor Auth","Если включено, пользователи, которые подключаются с ограниченным IP-адресом, не будут запрашиваться для Two Factor Auth", -"If enabled, users will be notified every time they login. If not enabled, users will only be notified once.","Если включено, пользователи будут уведомляться каждый раз при входе в систему. Если этот параметр не включен, пользователи будут получать уведомления только один раз.", +"If enabled, the password strength will be enforced based on the Minimum Password Score value. A value of 2 being medium strong and 4 being very strong.","Если включено, сложность пароля будет определяться в зависимости от значения минимальной оценки пароля. Значение 2 является средней сложностью, а 4 - очень сложным.", +"If enabled, users who login from Restricted IP Address, won't be prompted for Two Factor Auth","Если включено, пользователи, которые подключаются с установленного IP-адреса, не будут проходить двухфакторную аутентификацию", +"If enabled, users will be notified every time they login. If not enabled, users will only be notified once.","Если включено, пользователи будут получать уведомления каждый раз при входе в систему. Если этот параметр выключен, пользователи будут получать уведомления только один раз.", If non standard port (e.g. 587),"Если, не стандартный порт (например, 587)", "If non standard port (e.g. 587). If on Google Cloud, try port 2525.","Если нестандартный порт (например, 587). Если в Google Cloud, попробуйте порт 2525.", "If not set, the currency precision will depend on number format","Если не установлено, точность валюты будет зависеть от формата числа", If the condition is satisfied user will be rewarded with the points. eg. doc.status == 'Closed'\n,"Если условие выполнено, пользователь будет вознагражден баллами. например. doc.status == 'Закрыто'", -"If the user has any role checked, then the user becomes a ""System User"". ""System User"" has access to the desktop","Если пользователь имеет какую-либо роль, то он становится «Пользователем системы». Пользователем системы имеет доступ к рабочему столу", +"If the user has any role checked, then the user becomes a ""System User"". ""System User"" has access to the desktop","Если пользователь имеет какую-либо роль, то он становится «Пользователем системы». Пользователи системы имеет доступ к рабочему столу", "If these instructions where not helpful, please add in your suggestions on GitHub Issues.","Если эти инструкции бесполезны, пожалуйста, добавьте предложения в GitHub.", "If this is checked, rows with valid data will be imported and invalid rows will be dumped into a new file for you to import later.","Если этот флажок установлен, строки с достоверными данными будут импортированы, а недопустимые строки будут сбрасываться в новый файл для последующего импорта.", If user is the owner,Если пользователь является владельцем, @@ -1281,19 +1281,19 @@ If you don't want to create any new records while updating the older records.,Е "If you set this, this Item will come in a drop-down under the selected parent.","Если вы установите это, этот предмет придет в раскрывающемся списке под выбранной родителя.", "If you think this is unauthorized, please change the Administrator password.","Если вы думаете, что это несанкционированное, пожалуйста, измените пароль администратора.", "If your data is in HTML, please copy paste the exact HTML code with the tags.","Если данные в HTML, скопируйте вставьте точный HTML код с тегами.", -Ignore User Permissions,Игнорировать разрешеник пользователя, +Ignore User Permissions,Игнорировать разрешения пользователя, Ignore XSS Filter,Игнорировать XSS-фильтр, -Ignore attachments over this size,Игнорировать вложения более такого размера, +Ignore attachments over this size,Игнорировать вложения больше указаного размера, Ignore encoding errors,Игнорировать ошибки кодирования, Ignored: {0} to {1},Игнорируется: {0} до {1}, Illegal Access Token. Please try again,"Неправильный токен доступа. Пожалуйста, попробуйте еще раз", Illegal Document Status for {0},Недопустимый статус документа для {0}, Image Field,Поле изображения, Image Link,Ссылка на изображение, -Image field must be a valid fieldname,Поле Изображение должно быть допустимым имя_поля, -Image field must be of type Attach Image,Поле Изображение должно быть типа Присоединить изображения, -Images,Изображении, -Implicit,неявный, +Image field must be a valid fieldname,Поле изображения должно быть допустимым имя_поля, +Image field must be of type Attach Image,Поле изображения должно быть типа Прикрепить изображение, +Images,Изображения, +Implicit,Неявный, Import,Импорт, Import Email From,Импортировать электронную почту из, Import Status,Статус импорта, @@ -1307,8 +1307,8 @@ In List View,В виде списка, In Preview,В предварительном просмотре, In Reply To,В ответ на, In Standard Filter,В стандартный фильтр, -In Valid Request,Неверный запрос, -In points. Default is 9.,В точках. По умолчанию 9., +In Valid Request,В действующем запросе, +In points. Default is 9.,В баллах. По умолчанию 9., In seconds,В секундах, Include Search in Top Bar,Включить поиск в верхней панели, "Include symbols, numbers and capital letters in the password","Включить символы, цифры и заглавные буквы в пароле", @@ -1318,15 +1318,15 @@ Incorrect User or Password,Неверный пользователь или па Incorrect Verification code,Неверный код подтверждения, Incorrect value in row {0}: {1} must be {2} {3},Неверное значение в строке {0}: {1} должно быть {2} {3}, Incorrect value: {0} must be {1} {2},Неверное значение: {0} должно быть {1} {2}, -Index,индекс, +Index,Индекс, Indicator,Индикатор, Info,Информация, Info:,Информация:, Initial Sync Count,Первоначальная синхронизация Count, InnoDB,InnoDB, -Insert Above,Вставьте Над, -Insert After,Вставьте После, -Insert After cannot be set as {0},Вставка После не может быть установлен как {0}, +Insert Above,Вставить сверху, +Insert After,Вставить после, +Insert After cannot be set as {0},Вставка после не может быть установлен как {0}, "Insert After field '{0}' mentioned in Custom Field '{1}', with label '{2}', does not exist","После того, как вставить поле '{0}', упомянутой в настраиваемое поле '{1}', с меткой '{2}', не существует", Insert Below,Вставить ниже, Insert Column Before {0},Вставить столбец до {0}, @@ -1344,39 +1344,39 @@ Internal Server Error,Внутренняя ошибка сервера, Internal record of document shares,Внутренняя запись акций документов, Introduce your company to the website visitor.,Представьте вашу компанию на посетителя сайта., Introductory information for the Contact Us Page,Вводная информация для страницы контактов, -Invalid,Инвалид, +Invalid,Неверно, "Invalid ""depends_on"" expression",Недопустимое выражение "depends_on", Invalid Access Key ID or Secret Access Key.,Недействительный ключ ключа доступа или секретный ключ доступа., Invalid CSV Format,Неверный формат CSV, Invalid Home Page,Неверная главная страница, Invalid Link,Неверная ссылка, -Invalid Login Token,Неверный Логин маркера, +Invalid Login Token,Неверный логин токен, Invalid Login. Try again.,Неверный логин. Попробуй еще раз., Invalid Mail Server. Please rectify and try again.,"Неверный почтовый сервер. Пожалуйста, исправьте и попробуйте еще раз.", -Invalid Outgoing Mail Server or Port,Неверный Сервер исходящей почты или порт, +Invalid Outgoing Mail Server or Port,Неверный сервер исходящей почты или порт, Invalid Output Format,Неверный формат выходного, Invalid Password,Неверный пароль, Invalid Password:,Неверный пароль:, Invalid Request,Неверная заявка, Invalid Search Field {0},Неверное поле поиска {0}, Invalid Subscription,Недействительная подписка, -Invalid Token,Недопустимый маркер, +Invalid Token,Недопустимый токен, Invalid User Name or Support Password. Please rectify and try again.,"Неверное имя пользователя или поддержки Пароль. Пожалуйста, исправить и попробовать еще раз.", Invalid column,Недопустимый столбец, Invalid field name {0},Недопустимое имя поля {0}, -Invalid fieldname '{0}' in autoname,Invalid имя_поля '{0}' в autoname, +Invalid fieldname '{0}' in autoname,Недопустимое имя_поля '{0}' в autoname, Invalid file path: {0},Неверный путь к файлу: {0}, Invalid login or password,Неверный логин или пароль, Invalid module path,Недопустимый путь к модулю, Invalid naming series (. missing),Неверный идентификатор по имени (отсутствует), -Invalid payment gateway credentials,Неверные учетные данные платежный шлюз, +Invalid payment gateway credentials,Неверные учетные данные платежного шлюза, Invalid recipient address,Неверный адрес получателя, Invalid {0} condition,Недопустимое условие {0}, Inverse,Обратный, Is,Является, -Is Attachments Folder,Является Вложения Папка, -Is Child Table,Является дочерней таблице, -Is Custom Field,На заказ поле, +Is Attachments Folder,Является папкой вложений, +Is Child Table,Является дочерней таблицей, +Is Custom Field,Это нестандартное поле, Is First Startup,Первый запуск, Is Folder,Папка, Is Global,Является глобальным, @@ -1385,7 +1385,7 @@ Is Home Folder,Является корневой папкой, Is Mandatory Field,Является обязательным полем, Is Pinned,Прикреплено, Is Primary Contact,Основной контакт, -Is Private,Является личным, +Is Private,Является приватным, Is Published Field,Есть Опубликовано поле, Is Published Field must be a valid fieldname,Опубликовано Поле должно быть действительным имя_полем, Is Single,Единственный, @@ -1394,7 +1394,7 @@ Is Standard,Стандартный отчёт, Is Submittable,Подлежит исполнению, Is Table,Является таблицей, Is Your Company Address,Является адресом вашей компании, -It is risky to delete this file: {0}. Please contact your System Manager.,"Это рискованно, чтобы удалить этот файл: {0}. Пожалуйста, обратитесь к менеджеру системы.", +It is risky to delete this file: {0}. Please contact your System Manager.,"Рискованно удалять этот файл: {0}. Пожалуйста, обратитесь к менеджеру системы.", Item cannot be added to its own descendents,Продукт не может быть добавлен к своим подпродуктам, JS,JS, JSON,JSON, @@ -1407,13 +1407,13 @@ Kanban Board Column,Колонка канбан-доски, Kanban Board Name,Наименование канбан-доски, Karma,Карма, Keep track of all update feeds,Следите за всеми фидами обновлений, -Keeps track of all communications,Отслеживает все сообщения, +Keeps track of all communications,Отслеживать все коммуникации, Key,Ключ, Knowledge Base,База знаний, Knowledge Base Contributor,Пользователь базы знаний, Knowledge Base Editor,Редактор базы знаний, LDAP Email Field,LDAP Email Поле, -LDAP First Name Field,LDAP Имя поля, +LDAP First Name Field,LDAP поле Имя, LDAP Not Installed,LDAP не установлен, LDAP Search String,LDAP Строка поиска, "LDAP Search String needs to end with a placeholder, eg sAMAccountName={0}","Строка поиска LDAP должна заканчиваться заполнителем, например, sAMAccountName = {0}", @@ -1421,12 +1421,12 @@ LDAP Security,LDAP Security, LDAP Server Url,URL cервера LDAP, LDAP Username Field,LDAP Имя пользователя Поле, LDAP is not enabled.,LDAP не включен., -Label Help,Этикетка Помощь, -Label and Type,Этикетка и Тип, -Label is mandatory,Этикетка является обязательным, +Label Help,Ярлык Помощь, +Label and Type,Ярлык и Тип, +Label is mandatory,Ярлык является обязательным, Landing Page,Страница входа, -Language,язык, -Language Code,таблица условных сигналов, +Language,Язык, +Language Code,Языковой код, "Language, Date and Time settings","Настройки языка, даты и времени", Last Active,Последнее посещение, Last IP,Последний IP, @@ -1437,7 +1437,7 @@ Last Modified By,Последнее изменение, Last Modified Date,Дата последней модификации, Last Modified On,Дата последнего обновления, Last Month,Прошлый месяц, -Last Point Allocation Date,Дата выделения последней точки, +Last Point Allocation Date,Дата последнего начисления баллов, Last Quarter,Последняя четверть, Last Synced On,Последняя синхронизация включена, Last Updated By,Последнее обновление, @@ -1447,7 +1447,7 @@ Last Week,Прошлая неделя, Last Year,Прошлый год, Last synced {0},Последняя синхронизация {0}, Leave a Comment,Оставить комментарий, -Leave blank to repeat always,"Оставьте пустым, чтобы повторить всегда", +Leave blank to repeat always,"Оставьте пустым, чтобы повторять всегда", Leave this conversation,Покинуть этот разговор, Left this conversation,Покинуть этот разговор, Length,Длина, @@ -1470,8 +1470,8 @@ Link DocType,Ссылка DocType, Link Expired,Срок действия ссылки, Link Name,Имя ссылки, Link Title,Название ссылки, -"Link that is the website home page. Standard Links (index, login, products, blog, about, contact)","Ссылка, что находитесь на сайте домашняя страница. Стандартные ссылки (индекс, логин, продукты, блог, о, контакт)", -Link to the page you want to open. Leave blank if you want to make it a group parent.,"Ссылка на страницу, вы хотите, чтобы открыть. Оставьте пустым, если вы хотите, чтобы сделать его группа родителей.", +"Link that is the website home page. Standard Links (index, login, products, blog, about, contact)","Ссылка, которая является стартовой страницей сайта. Стандартные ссылки (индекс, логин, продукты, блог, о, контакт)", +Link to the page you want to open. Leave blank if you want to make it a group parent.,"Ссылка на страницу, которую вы хотите открыть. Оставьте пустым, если хотите сделать его родительским элементом группы.", Linked,Связанный, Linked With,Связанные с, Linked with {0},Связано с {0}, @@ -1482,36 +1482,36 @@ List View Setting,Настройка просмотра списка, List a document type,Перечислите тип документа, "List as [{""label"": _(""Jobs""), ""route"":""jobs""}]","Список как [{ "этикетка": _ ( "Работа"), "маршрут": "работа"}]", List of backups available for download,"Список резервных копий, доступных для загрузки", -List of patches executed,Список исправлений выполняется, +List of patches executed,Список выполненных патчей, List of themes for Website.,Список тем для веб-сайта., -Load Balancing,Балансировки нагрузки, +Load Balancing,Балансировка нагрузки, Loading,Идёт загрузка, Local DocType,Локальный DocType, Local Fieldname,Локальное имя поля, Local Primary Key,Местный первичный ключ, Locals,Локальные переменные, Log Details,Сведения о журнале, -Log of Scheduler Errors,Журнал ошибок Scheduler, -Log of error during requests.,Войти ошибки во время запросов., -Log of error on automated events (scheduler).,Войти ошибки на автоматизированных событий (планировщик)., -Logged Out,Вышли из, -Logged in as Guest or Administrator,Вы вошли как Гость или Administrator, +Log of Scheduler Errors,Журнал ошибок планировщика, +Log of error during requests.,Журнал ошибок во время запросов., +Log of error on automated events (scheduler).,Журнал ошибок автоматизированных событий (планировщик)., +Logged Out,Вышел из системы, +Logged in as Guest or Administrator,Войти как гость или администратор, Login,Войти, -Login After,Входить после, -Login Before,Входить до, -Login Id is required,Войти Id требуется, -Login Required,Войти Обязательные, +Login After,Войти после, +Login Before,Войти до, +Login Id is required,Требуется ID для входа, +Login Required,Авторизация обязательна, Login Verification Code from {},Код подтверждения входа в систему {}, Login and view in Browser,Вход и просмотр в браузере, -Login not allowed at this time,Войти не допускается в это время, +Login not allowed at this time,Авторизация не допускается в это время, "Login session expired, refresh page to retry","Срок действия сеанса истек, обновить страницу, чтобы повторить попытку", -Login to comment,Вход на комментарий, +Login to comment,Авторизоваться чтобы оставить комментарий, Login token required,Для входа требуется токен, Login with LDAP,Вход с LDAP, Logout,Выход, Long Text,Длинный текст, Looks like something is wrong with this site's Paypal configuration.,"Похоже, что что-то не так с конфигурацией Paypal этого сайта.", -Looks like something is wrong with this site's payment gateway configuration. No payment has been made.,"Похоже, что-то не так с конфигурацией платежного шлюза этого сайта. Платеж не был достигнут.", +Looks like something is wrong with this site's payment gateway configuration. No payment has been made.,"Похоже, что-то не так с конфигурацией платежного шлюза этого сайта. Платеж не был выполнен.", "Looks like something went wrong during the transaction. Since we haven't confirmed the payment, Paypal will automatically refund you this amount. If it doesn't, please send us an email and mention the Correlation ID: {0}.","Похоже, что-то пошло не так во время транзакции. Поскольку мы не подтвердили платеж, Paypal автоматически вернет вам эту сумму. Если это не так, отправьте нам электронное письмо и укажите идентификатор корреляции: {0}.", Madam,Госпожа, Main Section,Основной раздел, @@ -1521,7 +1521,7 @@ Manage Third Party Apps,Управление приложениями сторо Mandatory Information missing:,Обязательная информация отсутствует:, Mandatory field: set role for,Обязательное поле: установить роль для, Mandatory field: {0},Обязательное поле: {0}, -"Mandatory fields required in table {0}, Row {1}","Обязательные поля, требуемые в таблице {0}, строке {1}", +"Mandatory fields required in table {0}, Row {1}","Обязательные поля, требуемые в таблице {0}, строка {1}", Mandatory fields required in {0},"Обязательные поля, необходимые в {0}", Mandatory:,Обязательно:, Mapping Name,Название карты, @@ -1532,19 +1532,19 @@ Mark as Unread,Отметить как непрочитанные, Markdown,Markdown, Markdown Editor,Редактор Markdown, Marked As Spam,Помеченные как спам, -Max 500 records at a time,Max 500 записей за один раз, -Max Attachment Size (in MB),Максимальный размер вложения (в МБ), -Max Attachments,Максимальное Вложения, -Max Length,Максимальная длина, -Max Value,Максимальное значение, -Max width for type Currency is 100px in row {0},Максимальная ширина для типа валюта 100px в строке {0}, -Maximum Attachment Limit for this record reached.,Максимальная Приложение Лимит на этой записи достигли., -Maximum {0} rows allowed,Максимальные {0} строк разрешено, +Max 500 records at a time,Макс. 500 записей за один раз, +Max Attachment Size (in MB),Макс. размер вложения (в МБ), +Max Attachments,Макс. вложений, +Max Length,Макс. длина, +Max Value,Макс. значение, +Max width for type Currency is 100px in row {0},Макс. ширина для типа валюты 100px в строке {0}, +Maximum Attachment Limit for this record reached.,Достигнут предел вложений для этой записи., +Maximum {0} rows allowed,Макс. {0} строк разрешено, "Meaning of Submit, Cancel, Amend","Значение Провести, Отменить, Изменить", Mention transaction completion page URL,URL-ссылка на страницу-упоминание о завершении транзакции, Mentions,Упоминания, Menu,Меню, -Merchant ID,идентификатор продавца, +Merchant ID,Идентификатор продавца, Merge with existing,Слияние с существующими, Merging is only possible between Group-to-Group or Leaf Node-to-Leaf Node,Слияние возможно только между Группа-в-группе или Leaf узел-листовой узел, Message Count,Количество сообщений, @@ -1554,7 +1554,7 @@ Message Preview,Предварительный просмотр сообщени Message clipped,Сообщение обрезано, Message not setup,Сообщение не установлено, Message to be displayed on successful completion (only for Guest users),"Сообщение, которое будет отображаться при успешном завершении (только для гостевых пользователей)", -Message-id,Message-ID, +Message-id,ID сообщения, Meta Tags,Мета-теги, Migration ID Field,Поле идентификатора миграции, Milestone,Этап, @@ -1566,26 +1566,26 @@ Missing parameter Kanban Board Name,Отсутствует параметр На Missing parameters for login,Недостающие параметры для входа, Models (building blocks) of the Application,Модели (строительные блоки) приложения, Modified By,Модифицирован, -Module,модуль, +Module,Модуль, Module Def,Модуль Def, Module Name,Название модуля, Module Not Found,Модуль не найден, Module Path,Путь модуля, Module to Export,Модуль для экспорта, -Modules HTML,Модули HTML-, +Modules HTML,Модули HTML, Monospace,Моноширинный, More articles on {0},Другие статьи на {0}, More content for the bottom of the page.,Более контент для нижней части страницы., Most Used,Наиболее используемое, Move To,Переместить в, Move To Trash,Переместить в корзину, -Move to Row Number,Переместить в номер строки, +Move to Row Number,Переместить на строку, Mr,Г-н, Mrs,Г-жа, Ms,Госпожа, Multiple root nodes not allowed.,Несколько корневые узлы не допускается., Multiplier Field,Поле множителя, -"Must be of type ""Attach Image""",Должно быть типа "Присоединить изображение", +"Must be of type ""Attach Image""",Должно быть типа "Прикрепить изображение", Must have report permission to access this report.,Должен иметь разрешение отчета для доступа к этой отчета., Must specify a Query to run,"Необходимо указать запрос, чтобы запустить", Mute Sounds,Отключить звуки, @@ -1659,7 +1659,7 @@ No further records,Никаких дополнительных записей, No matching records. Search something new,Нет соответствующих записей. Поиск что-то новое, "No need for symbols, digits, or uppercase letters.","Нет необходимости для символов, цифр или букв в верхнем регистре.", No of Columns,Кол-во колонок, -No of Rows (Max 500),Кол-во строк (максимум 500), +No of Rows (Max 500),Кол-во строк (максимум 500), No of emails remaining to be synced,Нет сообщений для синхронизации, No permission for {0},Нет доступа для {0}, No permission to '{0}' {1},Нет доступа для '{0}' {1}, @@ -1685,10 +1685,10 @@ Not Seen,Непрочитанно, Not Sent,Не Отправлено, Not Set,Не указано, Not a valid Comma Separated Value (CSV File),"Не является допустимым значения, разделенные запятыми (CSV-файл)", -Not a valid User Image.,Недействительный образ пользователя., -Not a valid Workflow Action,Недоступное Действие бизнес-процесса, +Not a valid User Image.,Недействительный изображение пользователя., +Not a valid Workflow Action,Недоступное действие рабочего-процесса, Not a valid user,Не является действительным пользователем, -Not a zip file,Не архивный файл, +Not a zip file,Не zip файл, Not allowed for {0}: {1},Не разрешено для {0}: {1}, Not allowed for {0}: {1} in Row {2}. Restricted field: {3},Недопустимо для {0}: {1} в строке {2}. Запрещенное поле: {3}, Not allowed for {0}: {1}. Restricted field: {2},Не допускается для {0}: {1}. Запрещенное поле: {2}, @@ -1707,7 +1707,7 @@ Note: Changing the Page Name will break previous URL to this page.,Примеч Note: Multiple sessions will be allowed in case of mobile device,Примечание: Несколько сессий будет разрешено в случае мобильного устройства, Nothing to show,"К сожалению, здесь еще ничего не размещено", Nothing to update,Нечего обновлять, -Notification,уведомление, +Notification,Уведомление, Notification Recipient,Получатель уведомлений, Notification Tones,Сигналы уведомления, Notifications,Уведомления, @@ -1763,8 +1763,8 @@ Open {0},Открыть {0}, Opened,Открыт, Operator must be one of {0},Оператор должен быть одним из {0}, Option 1,Опция 1, -Option 2,Вариант 2, -Option 3,Вариант 3, +Option 2,Опция 2, +Option 3,Опция 3, Optional: Always send to these ids. Each Email Address on a new row,Дополнительно: Всегда рассылают по этим идентификаторам. Каждый адрес электронной почты в новой строке, Optional: The alert will be sent if this expression is true,"Дополнительно: предупреждение будет отправлено, если это выражение истинно", Options 'Dynamic Link' type of field must point to another Link Field with options as 'DocType',"""Dynamic Link 'Тип варианты поле должен указывать на другой Link Field с вариантами, как« DocType """, @@ -1772,19 +1772,19 @@ Options Help,Опции Помощь, Options for select. Each option on a new line.,Варианты выбора. Каждый вариант с новой строки., Options not set for link field {0},Опции не установлен поля связи {0}, Or login with,Или войти в систему с, -Order,порядок, +Order,Порядок, Org History,Org История, Org History Heading,Org История Заголовок, -Orientation,ориентация, -Original Value,первоначальная стоимость, +Orientation,Ориентация, +Original Value,Первоначальная стоимость, Outgoing email account not correct,Исходящая учетная запись электронной почты не верна, Outlook.com,Outlook.com, Output,Вывод, PDF,PDF, PDF Page Size,Размер PDF страницы, PDF Settings,Настройки PDF, -PDF generation failed,Не удалось создать PDF-файл, -PDF generation failed because of broken image links,Поколение PDF удалось из-за битых ссылок изображения, +PDF generation failed,Не удалось сгенерировать PDF-файл, +PDF generation failed because of broken image links,Не удалось сгенерировать PDF из-за битых ссылок изображения, "PDF printing via ""Raw Print"" is not yet supported. Please remove the printer mapping in Printer Settings and try again.",Печать PDF через «Raw Print» пока не поддерживается. Удалите отображение принтера в настройках принтера и повторите попытку., Page HTML,Страница HTML, Page Length,Длина страницы, @@ -1807,7 +1807,7 @@ Passive,Пассивный, Password Reset,Сброс пароля, Password Updated,Пароль обновлён, Password for Base DN,Пароль для Base DN, -Password is required or select Awaiting Password,Пароль требуется или выбрать Впредь пароль, +Password is required or select Awaiting Password,Требуется пароль или выберите Ожидание пароля, Password not found,Пароль не найден, Password reset instructions have been sent to your email,Инструкции по восстановлению пароля были отправлены на ваш email, Paste,Вставить, @@ -1820,7 +1820,7 @@ PayPal Settings,Настройки PayPal, PayPal payment gateway settings,Настройки оплаты шлюз PayPal, Payment Cancelled,Оплата отменена, Payment Failed,Платеж не прошел, -Payment Success,Оплата успеха, +Payment Success,Оплата прошла успешно, Pending Approval,В ожидании утверждения, Pending Verification,ожидает подтвержения, Percent,Процент, @@ -1830,12 +1830,12 @@ Permanent,Постоянный, Permanently Cancel {0}?,Постоянно Отменить {0}?, Permanently Submit {0}?,Постоянно провести {0}?, Permanently delete {0}?,Навсегда удалить {0}?, -Permission Error,Ошибка разрешения, +Permission Error,Ошибка доступа, Permission Level,Уровень доступа, Permission Levels,Уровни доступа, Permission Rules,Правило доступа, Permissions,Разрешения, -Permissions are automatically applied to Standard Reports and searches.,Разрешения автоматически применяются к стандартным отчетам и поисковым запросам., +Permissions are automatically applied to Standard Reports and searches.,Разрешения автоматически применяются к стандартнSым отчетам и поисковым запросам., "Permissions are set on Roles and Document Types (called DocTypes) by setting rights like Read, Write, Create, Delete, Submit, Cancel, Amend, Report, Import, Export, Print, Email and Set User Permissions.","Разрешения устанавливаются в Ролях и Типах Документов (называемые DocTypes) путем наделения правами Чтение, Запись, Создание, Удаление, Проведение, Отмена, Изменение, Создание отчета, Импорт, Экпорт, Печать, Отправка email и Назначение прав пользователя.", Permissions at higher levels are Field Level permissions. All Fields have a Permission Level set against them and the rules defined at that permissions apply to the field. This is useful in case you want to hide or make certain field read-only for certain Roles.,"Разрешения на более высоких уровнях - это разрешения на уровне поля. Все поля имеют установленный для них уровень разрешения, и правила, определенные в этих разрешениях, относятся к полю. Это полезно, если вы хотите скрыть или сделать определенное поле только для чтения для определенных ролей.", "Permissions at level 0 are Document Level permissions, i.e. they are primary for access to the document.","Разрешения на уровне 0 это разрешения на уровне документа, то есть они являются первичными для доступа к документу.", @@ -1846,14 +1846,14 @@ Personal Data Download Request,Запрос на скачивание личны Phone No.,Номер телефона, Pick Columns,Выберите столбцы, Plant,Завод, -Please Duplicate this Website Theme to customize.,"Пожалуйста, дублировать эту страницу Тема для настройки.", -Please Enter Your Password to Continue,"Пожалуйста, введите Ваш пароль чтобы продолжить", +Please Duplicate this Website Theme to customize.,"Пожалуйста, дублировать эту тему для настройки.", +Please Enter Your Password to Continue,"Пожалуйста, введите ваш пароль чтобы продолжить", Please Install the ldap3 library via pip to use ldap functionality.,"Пожалуйста, установите библиотеку ldap3 через pip, чтобы использовать функциональность ldap.", -Please Update SMS Settings,Обновите настройки СМС, +Please Update SMS Settings,Обновите настройки SMS, Please add a subject to your email,"Пожалуйста, укажите тему вашего письма", Please ask your administrator to verify your sign-up,"Пожалуйста, обратитесь к администратору, для подтверждения регистрации", -Please attach a file first.,"Пожалуйста, приложите файл первый.", -Please attach an image file to set HTML,"Пожалуйста, приложите файл изображения, чтобы установить HTML", +Please attach a file first.,"Пожалуйста, прикрепите первый файл.", +Please attach an image file to set HTML,"Пожалуйста, прикрепите файл изображения, чтобы установить HTML", Please check your email for verification,"Пожалуйста, проверьте свою электронную почту для подтверждения", Please check your registered email address for instructions on how to proceed. Do not close this window as you will have to return to it.,"Пожалуйста, проверьте электронную почту регистрации для получения инструкций. Не закрывайте это окно, так как вам придется вернуться к нему.", Please close this window,"Пожалуйста, закройте это окно", @@ -1873,7 +1873,7 @@ Please enter the password,"Пожалуйста, введите пароль", Please enter valid mobile nos,Введите действительные мобильных NOS, Please enter values for App Access Key and App Secret Key,"Пожалуйста, введите ключ доступа и секретный ключ приложения", Please make sure that there are no empty columns in the file.,"Пожалуйста, убедитесь, что нет никаких пустые столбцы в файле.", -Please make sure the Reference Communication Docs are not circularly linked.,"Удостоверьтесь, что справочные сообщения не связаны по кругу.", +Please make sure the Reference Communication Docs are not circularly linked.,"Пожалуйста, убедитесь, что справочные коммуникационные документы не имеют циклических ссылок.", Please refresh to get the latest document.,"Обновите, чтобы получить последнюю документ.", Please save before attaching.,"Пожалуйста, сохраните перед установкой.", Please save the Newsletter before sending,"Пожалуйста, сохраните бюллетень перед отправкой", @@ -1891,7 +1891,7 @@ Please select another payment method. PayPal does not support transactions in cu Please select another payment method. Razorpay does not support transactions in currency '{0}',"Пожалуйста, выберите другой способ оплаты. Razorpay не поддерживает транзакции в валюте «{0}»", Please select atleast 1 column from {0} to sort/group,"Пожалуйста, выберите по крайней мере 1 столбец {0} для сортировки / групп", Please select document type first.,Сначала выберите тип документа., -Please select the Document Type.,Выберите Тип документа., +Please select the Document Type.,Выберите тип документа., Please set Base URL in Social Login Key for Frappe,Укажите базовый URL-адрес в ключе социального входа для Frappe, Please set Dropbox access keys in your site config,"Пожалуйста, установите ключи доступа Dropbox на своем сайте конфигурации", Please set a printer mapping for this print format in the Printer Settings,"Пожалуйста, установите сопоставление принтера для этого формата печати в настройках принтера", @@ -1904,8 +1904,8 @@ Please specify which value field must be checked,"Просьба уточнит Please try again,"Пожалуйста, попробуйте еще раз", Please verify your Email Address,"Пожалуйста, подтвердите свой адрес электронной почты", Point Allocation Periodicity,Периодичность распределения точек, -Points,Точки, -Points Given,Очки даны, +Points,Баллы, +Points Given,Баллы засчитаны, Port,Порт, Portal Menu,Меню портала, Portal Menu Item,Портал Пункт меню, @@ -1932,12 +1932,12 @@ Previous,Предыдущая, Previous Hash,Предыдущий хэш, Primary Color,Основной цвет, Print Documents,Печать документов, -Print Format Builder,Конструктор Печатных форм, -Print Format Help,Помощь по Печатным формам, -Print Format Type,Тип Печатной формы, +Print Format Builder,Конструктор печатных форм, +Print Format Help,Помощь по печатным формам, +Print Format Type,Тип печатной формы, Print Format {0} is disabled,Печатная форма {0} отключена, -Print Hide,Распечатать Свернуть, -Print Hide If No Value,Печать Скрыть Если нет значения, +Print Hide,Не печатать, +Print Hide If No Value,Не печатать если нет значения, Print Sent to the printer!,Печать отправлена на принтер!, Print Server,Сервер печати, Print Style,Стиль печати, @@ -1946,23 +1946,23 @@ Print Style Preview,Предварительный просмотр стиля Print Width,Ширина печати, "Print Width of the field, if the field is a column in a table","Ширина поля при печати, если поле является столбцом в таблице", Print with letterhead,Печать с помощью фирменных бланков, -Printer,принтер, +Printer,Принтер, Printer Mapping,Отображение принтера, Printer Name,Имя принтера, Printer Settings,Настройки принтера, Printing failed,Ошибка печати, Private Key,Закрытый ключ, -Private and public Notes.,Личные и общедоступные Примечания., +Private and public Notes.,Личные и общедоступные примечания., ProTip: Add Reference: {{ reference_doctype }} {{ reference_name }} to send document reference,ProTip: Добавить Reference: {{ reference_doctype }} {{ reference_name }} отправить справочный документ, -Processing,обработка, -Processing...,Обработка ..., +Processing,Обработка, +Processing...,Обработка..., Prof,Проф., Progress,Готовность, Property Setter,Сеттер недвижимости, Property Setter overrides a standard DocType or Field property,Недвижимость сеттер отменяет стандартный DOCTYPE или свойств поля, Property Type,Тип недвижимости, -Provider,поставщик, -Provider Name,Имя провайдера, +Provider,Поставщик, +Provider Name,Имя поставщика, Public Key,Открытый ключ, Publishable Key,Ключ для публикации, Published On,Опубликовано на, @@ -1981,37 +1981,37 @@ QR Code,QR код, QR Code for Login Verification,QR-код для подтверждения входа, QZ Tray Connection Active!,Подключение к лотку QZ активно!, QZ Tray Failed: ,QZ Tray Failed:, -Quarter Day,День Квартал, -Query,запрос, +Quarter Day,Четверть дня, +Query,Запрос, Query Report,Отчёт-выборка, Query must be a SELECT,Запрос должен быть ВЫБОР, Queue should be one of {0},Очередь должна быть одной из {0}, Queued for backup. It may take a few minutes to an hour.,Queued для резервного копирования. Это может занять несколько минут до часа., Queued for backup. You will receive an email with the download link,Очередь для резервного копирования. Вы получите электронное письмо с ссылкой для загрузки, Quick Help for Setting Permissions,Быстрая помощь при настройки прав доступа, -Rating: ,Рейтинг:, -Raw Commands,Сырые команды, +Rating: ,Рейтинг: , +Raw Commands,Необработанные команды, Raw Email,Необработанная почта, -Raw Printing,Сырая печать, +Raw Printing,Необработанная печать, Razorpay Payment gateway settings,Настройки шлюза оплаты Razorpay, Razorpay Settings,Настройки Razorpay, Re: ,На:, Re: {0},На: {0}, Read,Читать, Read Only,Только чтения, -Read by Recipient,Читать Получатель, -Read by Recipient On,Прочитать Получатель, -Rebuild,перестраивать, -Receiver Parameter,Параметры Получателя, +Read by Recipient,Прочитано получателем, +Read by Recipient On,Прочитано получателем вкл., +Rebuild,Перестраивать, +Receiver Parameter,Параметры получателя, Recent years are easy to guess.,За последние годы легко догадаться., Recipient,Сторона-реципиент, -Recipient Unsubscribed,Получатель Подписка отменена, +Recipient Unsubscribed,Получатель отменил подписку, Record does not exist,Запись не существует, Records for following doctypes will be filtered,Записи для следующих доктринов будут отфильтрованы, Redirect To,Перенаправить, Redirect URI Bound To Auth Code,"Перенаправление URI, связанного с Auth кодекса", Redirect URIs,Перенаправление идентификаторы URI, -Redis cache server not running. Please contact Administrator / Tech support,"Кэш-сервер Redis не работает. Пожалуйста, обратитесь к администратору / техническая поддержка", +Redis cache server not running. Please contact Administrator / Tech support,"Кэш-сервер Redis не работает. Пожалуйста, обратитесь к администратору / техническую поддержку", Ref DocType,DocType ссылки, Ref Report DocType,Ref Report DocType, Reference DocName,Ссылка DocName, @@ -2021,39 +2021,39 @@ Reference: {0} {1},Ссылка: {0} {1}, Refreshing...,Обновление..., Register OAuth Client App,Регистрация OAuth Client App, Registered but disabled,Зарегистрированный но отключен, -Relapsed,Рецидив, -Relapses,Рецидивы, +Relapsed,Повторный, +Relapses,Повторные, Relink,Перередактируйте, -Relink Communication,Relink связи, -Relinked,Relinked, +Relink Communication,Повторно связать коммуникации, +Relinked,Связать повторно, Reload,Обновить страницу, -Remember Last Selected Value,Помните Последнее выбранное значение, +Remember Last Selected Value,Помнить последнее выбранное значение, Remote,Дистанционный пульт, Remote Fieldname,Удаленное имя поля, Remote ID,Удаленный идентификатор, Remote Objectname,Удаленное имя объекта, Remote Primary Key,Удаленный основной ключ, -Remove,Удалять, +Remove,Удалить, Remove Field,Удалить поле, Remove Filter,Удалить фильтр, Remove Section,Удалить раздел, Remove Tag,Убрать метку, -Remove all customizations?,Удалите все настройки?, +Remove all customizations?,Удалить все настройки?, Removed {0},Удалены {0}, Rename many items by uploading a .csv file.,"Переименовать много пунктов, загрузив. Файл CSV.", Rename {0},Переименовать {0}, Repeat Header and Footer in PDF,Повторите Колонтитулы в PDF, -Repeat On,Повторите На, -Repeat Till,Повторите До, -Repeat on Day,Повторить в День, -Repeat this Event,Повторите этот событие, +Repeat On,Повторите на, +Repeat Till,Повторите до, +Repeat on Day,Повторить в день, +Repeat this Event,Повторить этот событие, "Repeats like ""aaa"" are easy to guess","Повторы, как "ааа" легко догадаться,", "Repeats like ""abcabcabc"" are only slightly harder to guess than ""abc""","Повторы, как "abcabcabc" лишь немного труднее угадать, чем "Азбуки"", Reply,Ответить, Reply All,Ответить всем, Report End Time,Время окончания отчета, Report Filters,Фильтры отчетов, -Report Hide,Сообщить Свернуть, +Report Hide,Скрыть отчет, Report Manager,Диспетчер отчетов, Report Name,Название отчета, Report Start Time,Время начала отчета, @@ -2088,19 +2088,19 @@ Restrict user for specific document,Ограничить пользовател Restrict user from this IP address only. Multiple IP addresses can be added by separating with commas. Also accepts partial IP addresses like (111.111.111),"Разрешить пользователю только этот IP-адрес. Несколько IP-адресов могут быть добавлены через запятую. Принимает также частичные IP-адреса, например 111.111.111", Resume Sending,Резюме Отправка, Retake,пересдавать, -Retry,Retry, +Retry,Повторить, Return to the Verification screen and enter the code displayed by your authentication app,"Вернитесь на экран проверки и введите код, отображаемый приложением для аутентификации.", Reverse Icon Color,Обратный цвет значка, -Revert,возвращаться, -Revert Of,Возврат Из, +Revert,Вернуть, +Revert Of,Вернуть из, Reverted,Отменено, Review Level,Уровень обзора, Review Levels,Уровни обзора, Review Points,Очки обзора, Reviews,Отзывы, -Revoke,отзывать, -Revoked,Revoked, -Rich Text,Rich Text, +Revoke,Аннулировать, +Revoked,Аннулировано, +Rich Text,Форматированный текст, Robots.txt,Robots.txt, Role Name,Имя роли, Role Permission for Page and Report,Роль Разрешение на страницу и отчет, @@ -2108,7 +2108,7 @@ Role Permissions,Разрешения роли, Role Profile,Профиль ролей, Role and Level,Роль и уровень, Roles,Роли, -Roles Assigned,Роли Assigned, +Roles Assigned,Роли назначены, Roles can be set for users from their User page.,Роли могут быть установлены для пользователей со страницы пользователя., Root {0} cannot be deleted,Корневая {0} не может быть удален, Round Robin,По-круговой, @@ -2118,26 +2118,26 @@ Route to Success Link,Ссылка маршрута к успеху, Row,Строка, Row #{0}:,Строка #{0}:, Row Index,Индекс строк, -Row No,Строка Нет, +Row No,Строка №, Row Status,Статус строки, Row Values Changed,Значения строк Измененные, Row {0}: Not allowed to disable Mandatory for standard fields,Строка {0}: не разрешено отключать обязательные для стандартных полей, Row {0}: Not allowed to enable Allow on Submit for standard fields,Ряд {0}: Не разрешается включать Разрешить проведение для стандартных полей, Rows Added,Ряды Добавлено, Rows Removed,Ряды Удалены, -Rule,правило, +Rule,Правило, Rule Name,Название правила, Rules defining transition of state in the workflow.,"Правила, определяющие переход этапов в потоке.", "Rules for how states are transitions, like next state and which role is allowed to change state etc.","Правила для перехода статусов, например, следующий статус и роль, которой доступна смена статуса и т.д.", -Run,Бег, +Run,Запуск, Run scheduled jobs only if checked,"Запуск запланированных заданий, только если проверяются", S3 Backup Settings,Настройки резервного копирования S3, S3 Backup complete!,Резервное копирование S3 завершено!, -SMS,СМС, -SMS Gateway URL,URL СМС-шлюза, -SMS Parameter,Параметр СМС, -SMS Settings,Настройки СМС, -SMS sent to following numbers: {0},СМС отправлено следующим номерам: {0}, +SMS,SMS, +SMS Gateway URL,URL SMS-шлюза, +SMS Parameter,Параметр SMS, +SMS Settings,Настройки SMS, +SMS sent to following numbers: {0},SMS отправлено следующим номерам: {0}, SMTP Server,SMTP-сервер, SMTP Settings for outgoing emails,Настройки SMTP для исходящих писем, "SQL Conditions. Example: status=""Open""",SQL условия. Пример: статус = "Открыть", @@ -2150,7 +2150,7 @@ Save Filter,Сохранить фильтр, Save Report,Сохранить отчет, Save filters,Сохранить фильтры, Saving,Сохранение, -Saving...,Сохранение ..., +Saving...,Сохранение..., Scan the QR Code and enter the resulting code displayed.,Сканируйте QR-код и введите полученный код., Scopes,Области применения, Script,Скрипт, @@ -2166,7 +2166,7 @@ Search in a document type,Поиск в тип документа, Search or Create a New Chat,Поиск или создание нового чата, Search or type a command,Поиск либо введите команду, Search...,Поиск..., -Searching,поиск, +Searching,Поиск, Searching ...,Поиск ..., Section Break,Разделитель Секций, Section Heading,Заголовок раздела, @@ -2175,28 +2175,28 @@ Security Settings,Настройки безопасности, See all past reports.,Посмотреть все прошлые отчеты., See on Website,Посмотреть на веб-сайте, See the document at {0},См. Документ в {0}, -Seems API Key or API Secret is wrong !!!,"Кажется, ключ API или API Секрет неправильно !!!", +Seems API Key or API Secret is wrong !!!,"Кажется, ключ API или API Секрет неверны !!!", Seems Publishable Key or Secret Key is wrong !!!,"Кажется, что ключ для публикации или секретный ключ неправильный !!!", "Seems issue with server's razorpay config. Don't worry, in case of failure amount will get refunded to your account.","Кажется, вопрос с razorpay конфигурации сервера. Не волнуйтесь, в случае отказа суммы будет получить возврат на ваш счет.", Seems token you are using is invalid!,"Кажется, токен, который вы используете, недействителен!", Seen,Посещение, Seen By,Виденный, Seen By Table,Увиденные таблице, -Select Attachments,Выберите Вложения, +Select Attachments,Выберите вложения, Select Child Table,Выберите дочерний стол, Select Column,Выберите колонку, Select Columns,Выбрать столбцы, Select Document Type,Выбор типа документа, Select Document Type or Role to start.,"Выберите тип документа или роль, чтобы начать.", -Select Document Types to set which User Permissions are used to limit access.,"Выберите Типы документов, чтобы указать, какие пользовательские разрешения используются для ограничения доступа.", +Select Document Types to set which User Permissions are used to limit access.,"Выберите типы документов, чтобы указать, какие пользовательские разрешения используются для ограничения доступа.", Select File Format,Выберите формат файла, Select File Type,Выберите тип файла, Select Language...,Выберите язык..., -Select Languages,Выберите Языки, +Select Languages,Выберите языки, Select Module,Выбор модуля, Select Print Format,Выберите Печатную форму, Select Print Format to Edit,Выберите Печатную форму для Редактирование, -Select Role,Выберите Роль, +Select Role,Выберите роль, Select Table Columns for {0},Выберите столбцы таблицы для {0}, Select Your Region,Выберите регион, Select a Brand Image first.,Выберите бренд изображение в первую очередь., @@ -2222,12 +2222,12 @@ Send Notification to,Отправить уведомление на, Send Notifications To,Отправлять уведомления, Send Print as PDF,Отправить Печать в формате PDF, Send Read Receipt,Отправить прочтение, -Send Unsubscribe Link,Отправить ссылку Отказаться, +Send Unsubscribe Link,Отправить ссылку отписки, Send Welcome Email,Отправить приветственное письмо, Send alert if date matches this field's value,"Отправить уведомление, если дата соответствует значению этого поля", Send alert if this field's value changes,"Отправить уведомление, если изменяется значение этого поля", Send an email reminder in the morning,Отправить утром напоминание по электронной почте, -Send days before or after the reference date,Отправить дня до или после отчетной даты, +Send days before or after the reference date,Отправить за несколько дней до или после отчетной даты, Send enquiries to this email address,Отправить запросы на этот адрес электронной почты, Send me a copy,Отправить мне копию, Send only if there is any data,"Отправить только если есть какие-либо данные,", @@ -2241,7 +2241,7 @@ Sent/Received Email,Отправлено/Получено письмо, Server IP,IP-адрес сервера, Session Expired,Сеанс истек, Session Expiry,Время сессии, -Session Expiry Mobile,Сессия Срок Мобильная, +Session Expiry Mobile,Срок мобильной сессии, Session Expiry in Hours e.g. 06:00,"Время сессии в часах, например 06:00", Session Expiry must be in format {0},Время сессии должно быть в формате {0}, Session Start Failed,Сбой запуска сеанса, @@ -2266,16 +2266,16 @@ Set numbering series for transactions.,Установить идентифика Set up rules for user assignments.,Установите правила для пользовательских назначений., Setting this Address Template as default as there is no other default,"Установка этого Адрес шаблон по умолчанию, поскольку нет никакого другого умолчанию", Setting up your system,Настройка системы, -Settings for About Us Page.,Настройки для О нас страницы., -Settings for Contact Us Page,Настройки для контакт мы страница, -Settings for Contact Us Page.,Настройки для Контакты Page., +Settings for About Us Page.,Настройки страницы О нас., +Settings for Contact Us Page,Настройки страницы контактов, +Settings for Contact Us Page.,Настройки страницы контактов., Settings for OAuth Provider,Настройки для OAuth провайдера, -Settings for the About Us Page,Установки для О нас Страница, +Settings for the About Us Page,Установки для страницы О нас, Setup Auto Email,Настройка автоматической электронной почты, Setup Complete,Завершение установки, Setup Notifications based on various criteria.,Настройка уведомлений на основе различных критериев., Setup Reports to be emailed at regular intervals,Настройка регулярной отправки отчетов по электронной почте, -"Setup of top navigation bar, footer and logo.","Настройка верхней панели, навигации, подвала и логотипа.", +"Setup of top navigation bar, footer and logo.","Настройка верхней панели, навигации, нижнего колонтитула и логотипа.", Share,Поделиться, Share URL,Поделиться URL, Share With,Поделиться с, @@ -2292,11 +2292,11 @@ Show Calendar,Показать календарь, Show Dashboard,Показать панель инструментов, Show Full Error and Allow Reporting of Issues to the Developer,Показать полную ошибку и разрешить отправку отчетов разработчикам, Show Line Breaks after Sections,Показать разрывы строк после разделов, -Show Permissions,Показать права Доступа, +Show Permissions,Показать права доступа, Show Preview Popup,Предварительный просмотр, -Show Relapses,Показать Рецидивы, +Show Relapses,Показать рецидивы, Show Report,Показать отчет, -Show Section Headings,Показать Заголовки разделов, +Show Section Headings,Показать заголовки разделов, Show Sidebar,Показать боковую панель, Show Title,Показать Название, Show Totals,Показать итоги, @@ -2305,16 +2305,16 @@ Show all Versions,Показать все версии, Show as Grid,Показать как сетку, Show as cc,Показать в кубических сантиметрах, Show failed jobs,Показывать не удалось рабочих мест, -Show in Module Section,Показать в разделе Модуль, +Show in Module Section,Показать в секции модулей, Show in filter,Показать в фильтре, Show more details,Показать больше информации, Show only errors,Показать только ошибки, "Show title in browser window as ""Prefix - title""",Показать название в окне браузера как "префикс - название", Showing only Numeric fields from Report,Отображение только числовых полей из отчета, -Sidebar Items,Продукты боковой панели, -Sidebar Settings,Боковая панель Настройки, +Sidebar Items,Элементы боковой панели, +Sidebar Settings,Настройки боковой панели, Sidebar and Comments,Боковая панель и комментарии, -Sign Up,Подписаться, +Sign Up,Регистрация, Sign Up is disabled,Регистрация отключена, Signature,Подпись, "Simple Python Expression, Example: Status in (""Closed"", ""Cancelled"")","Простое выражение Python, пример: Статус в («Закрыто», «Отменено»)", @@ -2363,7 +2363,7 @@ Special Characters are not allowed,Спецсимволы не допустим Standard Print Format cannot be updated,Стандартный Формат печати не может быть обновлен, Standard Print Style cannot be changed. Please duplicate to edit.,Стандартный стиль печати не может быть изменен. Повторите попытку для редактирования., Standard Reports,Стандартные отчеты, -Standard Sidebar Menu,Стандартное меню Боковая панель, +Standard Sidebar Menu,Стандартное боковое меню, Standard roles cannot be disabled,Стандартные роли не могут быть отключены, Standard roles cannot be renamed,Стандартные роли не могут быть переименованы, Standings,Турнирная таблица, @@ -2388,7 +2388,7 @@ Stripe Settings,Настройки Stripe, Stripe payment gateway settings,Настройки платежного шлюза, Style,Стиль, Style Settings,Настройки стилей, -"Style represents the button color: Success - Green, Danger - Red, Inverse - Black, Primary - Dark Blue, Info - Light Blue, Warning - Orange","Стиль представляет цвет кнопки: Успех - Зеленый, Danger - красный, Обратная - черный, Первичная - темно-синий, информация - светло-голубой, Предупреждение - Оранжевый", +"Style represents the button color: Success - Green, Danger - Red, Inverse - Black, Primary - Dark Blue, Info - Light Blue, Warning - Orange","Стиль представляет цвет кнопки: Success - Green, Danger - Red, Inverse - Black, Primary - Dark Blue, Info - Light Blue, Warning - Orange", Stylesheets for Print Formats,Таблицы стилей для печатных форматов, "Sub-currency. For e.g. ""Cent""","Разменные единицы, например «цент»", Sub-domain provided by erpnext.com,Суб-домен предоставляется erpnext.com, @@ -2411,7 +2411,7 @@ Successfully Done,Успешно сделано, Successfully Updated,Успешно обновлено, Successfully updated translations,Успешно обновленные переводы, Suggested Username: {0},Похожие Имя пользователя: {0}, -Sum,сумма, +Sum,Сумма, Sum of {0},Сумма {0}, Support Email Address Not Specified,Адрес электронной почты поддержки не указан, Suspend Sending,Приостановить Отправка, @@ -2431,7 +2431,7 @@ Table HTML,Таблица HTML, Table MultiSelect,Таблица MultiSelect, Table updated,Таблица обновляется, Table {0} cannot be empty,Таблица {0} не может быть пустым, -Take Backup Now,Take Backup Now, +Take Backup Now,Сделать резервную копию сейчас, Take Photo,Фотографировать, Team Members,Члены команды, Team Members Heading,Члены команды Возглавлять, @@ -2440,14 +2440,14 @@ Test Email Address,Проверить адрес электронной почт Test Runner,Тест Runner, Test_Folder,Test_Folder, Text,Текст, -Text Align,Text Align, +Text Align,Выравнивание текста, Text Color,Цвет текста, -Text Content,Text Content, +Text Content,Содержимое текста, Text Editor,Редактор текста, Text to be displayed for Link to Web Page if this form has a web page. Link route will be automatically generated based on `page_name` and `parent_website_route`,"Текст, отображаемый в течение ссылка на веб-страницу, если эта форма имеет веб-страницу. Маршрут Ссылка будет генерироваться автоматически на основе `page_name` и` parent_website_route`", Thank you for your email,Спасибо за ваше письмо!, -Thank you for your interest in subscribing to our updates,Спасибо за ваш интерес к подписке на обновления, -Thank you for your message,Спасибо за Ваше сообщение, +Thank you for your interest in subscribing to our updates,Спасибо за ваш интерес и подписку на обновления, +Thank you for your message,Спасибо за ваше сообщение, The CSV format is case sensitive,Формат CSV чувствителен к регистру, The Condition '{0}' is invalid,Условие '{0}' является недействительным, The First User: You,Первый пользователя: Вы, @@ -2461,7 +2461,7 @@ The process for deletion of {0} data associated with {1} has been initiated.,"П The resource you are looking for is not available,"Ресурс, который вы ищете не доступен", The system provides many pre-defined roles. You can add new roles to set finer permissions.,"Система предоставляет множество заранее определенных ролей. Вы можете добавить новые роли, чтобы установить более тонкие разрешения.", The user from this field will be rewarded points,Пользователь из этого поля будет вознагражден баллами, -Theme,тема, +Theme,Тема, Theme URL,URL темы, There can be only one Fold in a form,Там может быть только один Fold в виде, There is an error in your Address Template {0},Существует ошибка в адресной Шаблон {0}, @@ -2489,14 +2489,14 @@ This email was sent to {0},Это письмо было отправлено н This email was sent to {0} and copied to {1},Это письмо было отправлено на адрес {0} и его копии на {1}, This feature is brand new and still experimental,Эта функция является новой и до сих пор экспериментальная, This field will appear only if the fieldname defined here has value OR the rules are true (examples): \nmyfield\neval:doc.myfield=='My Value'\neval:doc.age>18,"Это поле появляется только в случае, если имя_поля определено здесь имеет значение или правила являются истинными (примеры): MyField Eval: doc.myfield == 'My Value' Eval: doc.age> 18", -This form does not have any input,Эта форма не имеет никакого вход, +This form does not have any input,Эта форма не имеет никакого поля для заполнения, This form has been modified after you have loaded it,Эта форма была изменена после загрузки его, This format is used if country specific format is not found,"Этот формат используется, когда формат конкретной страна не найден", This goes above the slideshow.,Это идет над слайд-шоу., This is a background report. Please set the appropriate filters and then generate a new one.,"Это фоновый отчет. Пожалуйста, установите соответствующие фильтры, а затем сгенерируйте новый.", -This is a top-10 common password.,Это топ-10 общий пароль., -This is a top-100 common password.,Это обычный пароль топ-100., -This is a very common password.,Это очень общий пароль., +This is a top-10 common password.,Это из топ-10 простых паролей., +This is a top-100 common password.,Это из топ-100 простых паролей., +This is a very common password.,Это очень простой пароль., This is an automatically generated reply,Это автоматически генерируется ответ, This is similar to a commonly used password.,Это похоже на обычно используемый пароль., This is the template file generated with only the rows having some error. You should use this file for correction and import.,"Это файл шаблона, сгенерированный только строками с некоторой ошибкой. Вы должны использовать этот файл для исправления и импорта.", @@ -2508,7 +2508,7 @@ This query style is discontinued,Этот стиль запроса прекра This report was generated on {0},Этот отчет был создан в {0}, This report was generated {0}.,Этот отчет был сгенерирован {0}., This request has not yet been approved by the user.,Этот запрос еще не был одобрен пользователем., -This role update User Permissions for a user,Эта роль Разрешения обновление пользователя пользователь, +This role update User Permissions for a user,Эта роль обновляет разрешения пользователя для пользователя, This will log out {0} from all other devices,Это выведет {0} из всех других устройств, This will permanently remove your data.,Это навсегда удалит ваши данные., Throttled,Throttled, @@ -2519,14 +2519,14 @@ Time Series Based On,Временные ряды на основе, Time Zone,Часовой пояс, Time Zones,Часовые пояса, Time in seconds to retain QR code image on server. Min:240,"Время в секундах, чтобы сохранить изображение QR-кода на сервере. Мин.: 240", -Timeline DocType,Сроки DocType, -Timeline Field,Сроки поле, -Timeline Links,Хронология Ссылки, -Timeline Name,Сроки Имя, +Timeline DocType,Хронология DocType, +Timeline Field,Хронология поля, +Timeline Links,Хронология ссылок, +Timeline Name,Хронология имени, Timeline field must be a Link or Dynamic Link,Сроки поле должно быть Ссылка или Dynamic Link, Timeline field must be a valid fieldname,Сроки поле должно быть действительным имя_поля, Timeseries,Временные ряды, -Timestamp,Время, +Timestamp,Временная отметка, Title Case,Название дела, Title Field,Название поля, Title Prefix,Название Приставка, @@ -2536,7 +2536,7 @@ To Do,Список дел, To User,Пользователю, "To add dynamic subject, use jinja tags like\n\n
New {{ doc.doctype }} #{{ doc.name }}
","Чтобы добавить динамический объект, используйте теги jinja, например
 New {{ doc.doctype }} #{{ doc.name }} 
", "To add dynamic subject, use jinja tags like\n\n
{{ doc.name }} Delivered
","Чтобы добавить динамический объект, использовать теги, как дзиндзя
 {{ doc.name }} Delivered 
", -To and CC,Чтобы и CC, +To and CC,Получатели, "To get the updated report, click on {0}.","Чтобы получить обновленный отчет, нажмите {0}.", ToDo,Список задач, Today,Cегодня, @@ -2544,7 +2544,7 @@ Toggle Chart,Переключить диаграмму, Toggle Charts,Переключить диаграммы, Toggle Grid View,Просмотр сетки, Toggle Sidebar,Переключить боковую панель, -Token,знак, +Token,Токен, Token is missing,Маркер отсутствует, "Too many users signed up recently, so the registration is disabled. Please try back in an hour","Слишком много пользователей зарегистрировались в последнее время, так что регистрация отключена. Пожалуйста, повторите попытку через час", Too many writes in one request. Please send smaller requests,"Слишком много пишет в одном запросе. Пожалуйста, пришлите меньшие запросы", @@ -2589,7 +2589,7 @@ Type:,Тип:, UID,UID, UIDNEXT,UIDNEXT, UIDVALIDITY,UIDVALIDITY, -UNSEEN,UNSEEN, +UNSEEN,НЕПРОЧИТАННО, UPPER CASE,ВЕРХНИЙ РЕГИСТР, "URIs for receiving authorization code once the user allows access, as well as failure responses. Typically a REST endpoint exposed by the Client App.\n
e.g. http://hostname//api/method/frappe.www.login.login_via_facebook","Идентификаторы URI для получения кода авторизации, как только пользователь разрешает доступ, а также ответы недостаточность. Как правило, конечная точка REST подвергается Клиентом App.
например, HTTP: //hostname//api/method/frappe.www.login.login_via_facebook", URLs,URL-адрес, @@ -2606,24 +2606,24 @@ Under Development,В разработке, Unfollow,Отписаться, Unhandled Email,Необработанная электронная почта, Unique,Уникальный, -Unknown Column: {0},Неизвестный Колонка: {0}, +Unknown Column: {0},Неизвестная колонка: {0}, Unknown User,Неизвестный пользователь, "Unknown file encoding. Tried utf-8, windows-1250, windows-1252.","Неизвестная кодировка файла. Ни UTF-8, ни windows-1250, ни windows-1252.", Unread,Не прочитано, Unread Notification Sent,Не читать уведомления об отправке, Unselect All,Снять все, -Unshared,неразделенный, +Unshared,Неразделенный, Unsubscribe,Отказаться от подписки, -Unsubscribe Method,Метод Отказаться, +Unsubscribe Method,Метод отписки, Unsubscribe Param,Отказаться от Param, Unsupported File Format,Неподдерживаемый формат файла, -Unzip,расстегнуть молнию, +Unzip,Распаковать, Unzipped {0} files,Распакованные файлы {0}, -Unzipping files...,Распаковка файлов ..., +Unzipping files...,Распаковка файлов..., Upcoming Events for Today,Предстоящие события на сегодня, Update Field,Обновляемое поле, Update Translations,Обновление переводов, -Update Value,Обновляемое Значение, +Update Value,Обновляемое значение, Update many values at one time.,Обновить несколько значений одновременно., Update records,Обновить записи, Updated,Обновлено, @@ -2639,11 +2639,11 @@ Use IMAP,Использование IMAP, Use POST,Использовать POST, Use SSL,Использовать SSL, Use TLS,Использовать TLS, -"Use a few words, avoid common phrases.","Используйте несколько слов, избегать общих фраз.", +"Use a few words, avoid common phrases.","Используйте несколько слов, избегайте общих фраз.", Use of sub-query or function is restricted,Использование подзапроса или функции ограничено, Use socketio to upload file,Использовать socketio для загрузки файла, Use this fieldname to generate title,Используйте этот имя_поля генерировать название, -User '{0}' already has the role '{1}',Пользователь '{0}' уже играет роль '{1}', +User '{0}' already has the role '{1}',Пользователь '{0}' уже имеет роль '{1}', User Cannot Create,Пользователь не может создавать, User Cannot Search,Пользователь не может искать, User Defaults,По умолчанию пользователя, @@ -2673,31 +2673,31 @@ User {0} cannot be disabled,Пользователь {0} не может быт User {0} cannot be renamed,Пользователь {0} не может быть переименован, User {0} does not have access to this document,Пользователь {0} не имеет доступа к этому документу, User {0} does not have doctype access via role permission for document {1},Пользователь {0} не имеет доступа к типу документа через разрешение роли для документа {1}, -Username,имя пользователя, +Username,Имя пользователя, Username {0} already exists,Имя пользователя {0} уже существует, Users with role {0}:,Пользователи с ролью {0}:, Uses the Email Address Name mentioned in this Account as the Sender's Name for all emails sent using this Account.,"Использует имя адреса электронной почты, указанное в этой учетной записи, в качестве имени отправителя для всех электронных писем, отправленных с использованием этой учетной записи.", Uses the Email Address mentioned in this Account as the Sender for all emails sent using this Account. ,"Использует адрес электронной почты, указанный в этом аккаунте в качестве отправителя для всех писем, отправляемых с использованием этой учетной записи.", -Valid,действительный, +Valid,Действительный, Valid Login id required.,Требуется действительный ID логин., Valid email and name required,Требуются действительные email и имя, Value Based On,Значение на основе, Value Change,Стоимость Изменение, -Value Changed,Значение Изменен, +Value Changed,Значение изменено, Value To Be Set,"Значение, которое должно быть установлено", Value cannot be changed for {0},Значение не может быть изменено для {0}, Value for a check field can be either 0 or 1,"Значение для поля проверки может быть либо 0, либо 1", Value for {0} cannot be a list,Значение {0} не может быть списком, Value missing for,Нет значения для, Value too big,Слишком большое значение, -Values Changed,Значения Изменено, +Values Changed,Значения изменено, Verdana,Verdana, Verfication Code,Код проверки, Verification Link,Ссылка для проверки, Verification code has been sent to your registered email address.,Код подтверждения отправлен на ваш адрес электронной почты регистрации., Verify,Проверить, -Verify Password,Подтвердите Пароль, -Verifying...,Проверка ..., +Verify Password,Подтвердите пароль, +Verifying...,Проверка..., Version,Версия, Version Updated,Версия обновлена, View All,Посмотреть все, @@ -2714,12 +2714,12 @@ View this in your browser,Просмотреть это в вашем брауз View {0},Просмотреть {0}, Viewed By,просмотрены, Visit,Посетите нас по адресу, -Visitor,посетитель, +Visitor,Посетитель, We have received a request for deletion of {0} data associated with: {1},"Мы получили запрос на удаление {0} данных, связанных с: {1}", We have received a request from you to download your {0} data associated with: {1},"Мы получили от вас запрос на загрузку данных {0}, связанных с: {1}", -Web Form,Web Form, -Web Form Field,Web Form Field, -Web Form Fields,Web Form Поля, +Web Form,Веб форма, +Web Form Field,Поле веб формы, +Web Form Fields,Поля веб формы, Web Page,Веб-страница, Web Page Link Text,Web Текст Ссылка на страницу, Web Site,Веб-сайт, @@ -2739,9 +2739,9 @@ Website Sidebar,Боковая панель Веб-сайт, Website Sidebar Item,Сайт Sidebar товара, Website Slideshow,Сайт Слайд-шоу, Website Slideshow Item,Сайт Слайд-шоу Пункт, -Website Theme,Сайт Тема, -Website Theme Image,Сайт Тема изображения, -Website Theme Image Link,Сайт Тема Ссылка на изображение, +Website Theme,Тема сайта, +Website Theme Image,Изображение темы сайта, +Website Theme Image Link,Ссылка на изображение темы сайта, Website User,Пользователь сайта, Welcome Message,Приветственное сообщение, "When you Amend a document after Cancel and save it, it will get a new number that is a version of the old number.","Когда вы Измените (Amend) документ после Отмены (Cancel) и сохраните его, он получит новый номер, который является версией старого номера.", @@ -2750,18 +2750,18 @@ Widths can be set in px or %.,Ширина может быть установл Will be used in url (usually first name).,Будет использоваться в URL (обычно имя)., Will be your login ID,Будет ли ваш идентификатор входа в систему, Will only be shown if section headings are enabled,"Будет показано, только если заголовки разделов включены", -With Letter head,С головой Письмо, +With Letter head,С буквенным заголовком, With Letterhead,На фирменном бланке, -Workflow Action,Действия бизнес-процесса, -Workflow Action Master,Настройка Действий бизнес-процесса, -Workflow Action Name,Название Действий бизнес-процесса, -Workflow Document State,Состояние документа потока, -Workflow Name,Название потока, -Workflow State,Состояние потока, -Workflow State Field,Поле Статуса Процесса, +Workflow Action,Действия рабочего процесса, +Workflow Action Master,Мастер действий рабочего процесса, +Workflow Action Name,Название действия рабочего процесса, +Workflow Document State,Состояние документа рабочего процесса, +Workflow Name,Название рабочего процесса, +Workflow State,Состояние рабочего процесса, +Workflow State Field,Состояние поля рабочего процесса, Workflow State not set,Состояние рабочего процесса не установлено, -Workflow Transition,Переход потока, -Workflow state represents the current state of a document.,Состояние потока представлено текущим состоянием документа., +Workflow Transition,Переход рабочего процесса, +Workflow state represents the current state of a document.,Состояние рабочего процесса представлено текущим состоянием документа., Write,Написать, Wrong fieldname {0} in add_fetch configuration of custom script,Неверное имя поля {0} в конфигурации add_fetch пользовательского скрипта, X Axis Field,Поле оси X, @@ -2777,31 +2777,31 @@ You are not allowed to print this document,Вы не можете распеча You are not allowed to print this report,У вас нет прав для печати этого отчета, You are not allowed to send emails related to this document,"Вы не можете отправлять письма, связанные с этим документом", You are not allowed to update this Web Form Document,Вы не можете обновить эту веб-форму документа, -You are not connected to Internet. Retry after sometime.,Вы не подключены к Интернету. Повторите попытку через некоторое время., +You are not connected to Internet. Retry after sometime.,Вы не подключены к интернету. Повторите попытку через некоторое время., You are not permitted to access this page.,Вам не разрешен доступ к этой странице., You are not permitted to view the newsletter.,У Вас нет прав для просмотра данной новостной ленты, -You are now following this document. You will receive daily updates via email. You can change this in User Settings.,Вы сейчас следуете этому документу. Вы будете получать ежедневные обновления по электронной почте. Вы можете изменить это в настройках пользователя., -You can add dynamic properties from the document by using Jinja templating.,Вы можете добавить динамические свойства из документа с помощью шаблонов дзиндзя., -You can also copy-paste this ,Вы также можете скопировать и вставить это, +You are now following this document. You will receive daily updates via email. You can change this in User Settings.,Вы подписаны на обновления данного документа. Вы будете получать ежедневные обновления по электронной почте. Вы можете изменить это в настройках пользователя., +You can add dynamic properties from the document by using Jinja templating.,Вы можете добавить динамические свойства из документа с помощью шаблонов Jinja., +You can also copy-paste this ,Вы также можете скопировать и вставить это , "You can change Submitted documents by cancelling them and then, amending them.","Вы можете изменить Проведенные (Submitted) документы, отменив их, а затем изменив их.", -You can find things by asking 'find orange in customers',Моно искать что-либо написав «найти апельсин у клиентов», +You can find things by asking 'find orange in customers',Можно искать что-либо написав «найти апельсин у клиентов», You can only upload upto 5000 records in one go. (may be less in some cases),"Вы можете загружать одновременно до 5000 записей. (Возможно меньше, в некоторых случаях)", You can use Customize Form to set levels on fields.,Вы можете использовать Настройку формы (Customize Form) для установки уровней для полей., -You can use wildcard %,Вы можете использовать подстановочные%, -You can't set 'Options' for field {0},Нельзя включить «Параметры» для поля {0}, +You can use wildcard %,Вы можете использовать подстановочные %, +You can't set 'Options' for field {0},Нельзя включить «Опции» для поля {0}, You can't set 'Translatable' for field {0},Вы не можете установить «Переводимый» для поля {0}, You cannot give review points to yourself,Вы не можете давать оценки себе, You cannot unset 'Read Only' for field {0},Нельзя отменить «только чтение» для поля {0}, You do not have enough permissions to access this resource. Please contact your manager to get access.,"У вас нет достаточных прав для доступа к этому ресурсу. Пожалуйста, обратитесь к своему менеджеру, чтобы получить доступ.", You do not have enough permissions to complete the action,У Вас нет достаточных прав для завершения действия, -You do not have enough points,Вам не хватает очков, -You do not have enough review points,Вам не хватает точек обзора, +You do not have enough points,Вам не хватает баллов, +You do not have enough review points,Вам не хватает баллов обзора, You don't have access to Report: {0},Вы не имеете доступа к отчету: {0}, You don't have any messages yet.,У вас пока нет сообщений., You don't have permission to access this file,У Вас нет разрешения на доступ к этому файлу, You don't have permission to get a report on: {0},У Вас нет разрешения на получение отчета о: {0}, You don't have the permissions to access this document,У Вас нет разрешения на доступ к этому документу, -You gained {0} point,Вы набрали {0} очков, +You gained {0} point,Вы набрали {0} балл, You gained {0} points,Вы набрали {0} баллов, You have a new message from: ,У вас есть новое сообщение от:, You have been successfully logged out,Вы успешно вышли, @@ -2810,7 +2810,7 @@ You must login to submit this form,Для подтверждения этой ф You need to be in developer mode to edit a Standard Web Form,Вы должны быть в режиме разработчика для изменения стандартной веб-формы, You need to be logged in and have System Manager Role to be able to access backups.,"Вы должны войти в систему (и иметь роль менеджера системы), чтобы иметь доступ к резервным копиям.", You need to be logged in to access this {0}.,"Вы должны войти, чтобы получить доступ к {0}.", -"You need to have ""Share"" permission","Вы должны иметь ""Share"" разрешение", +"You need to have ""Share"" permission","Вы должны иметь разрешение ""Поделиться""", You need write permission to rename,"Вам нужно письменное разрешение, чтобы переименовать", You selected Draft or Cancelled documents,Вы выбрали черновик или отмененные документы, You unfollowed this document,Вы отписались от этого документа, @@ -2860,26 +2860,26 @@ camera,Камера, cancelled this document,отменил этот документ, changed value of {0},изменил значение {0}, changed values for {0},измененные значения для {0}, -chevron-down,шеврона вниз, -chevron-left,шеврона оставили, -chevron-right,шеврона право, -chevron-up,шеврона до, -circle-arrow-down,Круг со стрелкой вниз, -circle-arrow-left,Круг со стрелкой налево, -circle-arrow-right,Круг со стрелкой направо, -circle-arrow-up,Круг со стрелкой вверх, +chevron-down,шеврон-вниз, +chevron-left,шеврон-влево, +chevron-right,шеврон-право, +chevron-up,шеврон-вверх, +circle-arrow-down,круг-со-стрелкой-вниз, +circle-arrow-left,круг-со-стрелкой-налево, +circle-arrow-right,круг-со-стрелкой-направо, +circle-arrow-up,круг-со-стрелкой-вверх, cn-north-1,сп-северо-1, cn-northwest-1,сп-северо-запад-1, cog,зубец, darkgrey,темно-серый, dd-mm-yyyy,дд-мм-гггг, dd.mm.yyyy,дд.мм.гггг, -dd/mm/yyyy,дд / мм / гггг, -"document type..., e.g. customer","тип документа ..., например, клиент", +dd/mm/yyyy,дд/мм/гггг, +"document type..., e.g. customer","тип документа..., например, клиент", domain name,доменное имя, download-alt,скачать-альт, -"e.g. ""Support"", ""Sales"", ""Jerry Yang""","например ""Поддержка "","" Продажи "","" Джерри Янг """, -e.g. (55 + 434) / 4 or =Math.sin(Math.PI/2)...,"например, (55 + 434) / 4 = или Math.sin (Math.PI / 2) ...", +"e.g. ""Support"", ""Sales"", ""Jerry Yang""","например ""Поддержка"",""Продажи"",""Джерри Янг""", +e.g. (55 + 434) / 4 or =Math.sin(Math.PI/2)...,"например, (55 + 434) / 4 или =Math.sin (Math.PI / 2)...", e.g. pop.gmail.com / imap.gmail.com,например pop.gmail.com / imap.gmail.com, e.g. replies@yourcomany.com. All replies will come to this inbox.,например replies@yourcomany.com. Все ответы будут приходить на этот почтовый ящик., e.g. smtp.gmail.com,например smtp.gmail.com, @@ -2933,12 +2933,12 @@ minus,минус, minus-sign,минус-знак, mm-dd-yyyy,мм-дд-гггг, mm/dd/yyyy,мм/дд/гггг, -module name...,Модуль имя ..., +module name...,Модуль имя..., new type of document,новый тип документа, no failed attempts,нет неудачных попыток, none of,ни один из, ok,ok, -ok-circle,в порядке круга, +ok-circle,ok-circle, ok-sign,в порядке-знак, on_cancel,on_cancel, on_change,по изменению, @@ -2953,13 +2953,13 @@ pencil,карандаш, picture,картинка, plane,самолет, play,играть, -play-circle,играть круга, -plus,А ТАКЖЕ, +play-circle,играть-круг, +plus,плюс, plus-sign,знак плюс, -qrcode,QR код, +qrcode,QR-код, query-report,запрос-отчет, question-sign,Вопрос-знак, -remove-circle,удалить круга, +remove-circle,удалить-круг, remove-sign,удалить-знак, removed,удален, renamed from {0} to {1},переименован из {0} до {1}, @@ -3106,7 +3106,7 @@ zoom-out,отдалить, {0}: {1} is set to state {2},{0}: {1} установлено состояние {2}, {app_title},{app_title}, {{{0}}} is not a valid fieldname pattern. It should be {{field_name}}.,{{{0}}} недопустимый шаблон имени поля. Должно быть {{field_name}}., -Communication Link,Связь Связь, +Communication Link,Связь коммуникации, Force User to Reset Password,Заставить пользователя сбросить пароль, In Days,В днях, Last Password Reset Date,Дата последнего сброса пароля, @@ -3166,7 +3166,7 @@ Allow Guest,Разрешить гость, Allow Guests to Upload Files,Разрешить гостям загружать файлы, Also adding the status dependency field {0},Также добавляем поле зависимости статуса {0}, An error occurred while setting Session Defaults,Произошла ошибка при настройке параметров сеанса по умолчанию, -Annual,За год, +Annual,Ежегодный, Append Emails to Sent Folder,Добавить электронные письма в отправленную папку, Apply Assignment Rule,Применить правило назначения, Apply Only Once,Применить только один раз, @@ -3223,7 +3223,7 @@ Contact Email,Эл.почта для связи, Contact Numbers,Контактные номера, Contact Phone,Контактный телефон, Contact Synced with Google Contacts.,Контакт синхронизирован с контактами Google., -Context,контекст, +Context,Контекст, Contribute Translations,Внести перевод, Contributed,Внесенный, Controller method get_razorpay_order missing,Метод контроллера get_razorpay_order отсутствует, @@ -3258,11 +3258,11 @@ Documentation Link,Документация Ссылка, Don't Import,Не импортировать, Don't Send Emails,Не отправлять электронные письма, "Drag and drop files, ","Перетащите файлы,", -Drop,Капля, -Drop Here,Падение здесь, +Drop,Бросить, +Drop Here,Бросить тут, Drop files here,Перетащите файлы сюда, Dynamic Template,Динамический шаблон, -ERPNext Role,ERPNext Роль, +ERPNext Role,ERPNext роль, Email / Notifications,Уведомления по электронной почте, Email Account setup please enter your password for: {0},"Настройка учетной записи электронной почты, введите ваш пароль для: {0}", Email Address whose Google Contacts are to be synced.,"Адрес электронной почты, чьи контакты Google должны быть синхронизированы.", @@ -3273,7 +3273,7 @@ Enable Automatic Linking in Documents,Включить автоматическ Enable Email Notifications,Включить уведомления по электронной почте, Enable Google API in Google Settings.,Включить Google API в настройках Google., Enable Security,Включить безопасность, -Energy Point,Энергетическая точка, +Energy Point,Балл активности, Enter Client Id and Client Secret in Google Settings.,Введите идентификатор клиента и секрет клиента в настройках Google., Enter Code displayed in OTP App.,"Введите код, отображаемый в приложении OTP.", Event Configurations,Конфигурации событий, @@ -3295,7 +3295,7 @@ Export Type,Тип экспорта, Export {0} records,Экспорт {0} записей, Failed to connect to the Event Producer site. Retry after some time.,Не удалось подключиться к сайту источника событий. Повторите попытку через некоторое время., Failed to create an Event Consumer or an Event Consumer for the current site is already registered.,"Не удалось создать получателя событий или получателя событий для текущего сайта, который уже зарегистрирован.", -Failure,недостаточность, +Failure,Неудача, Fetching default Global Search documents.,Извлечение документов глобального поиска по умолчанию., Fetching posts...,Получение сообщений ..., Field Mapping,Полевое картографирование, @@ -3352,10 +3352,10 @@ Group By,Группа по, Group By Based On,Группировать по на основе, Group By Type,Группировать по типу, Group By field is required to create a dashboard chart,Поле «По группам» необходимо для создания диаграммы панели инструментов, -HH:mm,HH: мм, -HH:mm:ss,HH: мм: сс, -HOOK-.####,HOOK -. ####, -HTML Page,HTML-страница, +HH:mm,ЧЧ:мм, +HH:mm:ss,ЧЧ:мм:сс, +HOOK-.####,HOOK-.####, +HTML Page,HTML страница, Has Mapping,Имеет отображение, Hourly Long,Почасовая, "If non-standard port (e.g. POP3: 995/110, IMAP: 993/143)","Если нестандартный порт (например, POP3: 995/110, IMAP: 993/143)", @@ -3375,7 +3375,7 @@ Importing {0} of {1},Импорт {0} из {1}, Include indentation,Включить отступ, Incoming Change,Входящие изменения, Invalid Filter Value,Неверное значение фильтра, -Invalid URL,неправильный адрес, +Invalid URL,Неправильный URL, Invalid field name: {0},Неверное имя поля: {0}, Invalid file URL. Please contact System Administrator.,"Неверный URL файла. Пожалуйста, свяжитесь с системным администратором.", Invalid include path,Неверный путь включения, @@ -3386,7 +3386,7 @@ Is Primary Phone,Основной телефон, Is Tree,Дерево, JSON Request Body,Тело запроса JSON, Javascript is disabled on your browser,Javascript отключен в вашем браузере, -Job,работа, +Job,Работа, Jump to field,Перейти к полю, Keyboard Shortcuts,Горячие клавиши, LDAP Group,LDAP Group, @@ -3395,8 +3395,8 @@ LDAP Group Mapping,LDAP Group Mapping, LDAP Group Mappings,Отображения группы LDAP, LDAP Last Name Field,Поле Фамилия LDAP, LDAP Middle Name Field,Поле второго имени LDAP, -LDAP Mobile Field,LDAP Mobile Field, -LDAP Phone Field,Поле телефона LDAP, +LDAP Mobile Field,LDAP мобильный, +LDAP Phone Field,LDAP телефон, LDAP User Creation and Mapping,Создание и сопоставление пользователей LDAP, Landscape,Альбомный, Last,Последний, @@ -3407,20 +3407,20 @@ Last Update,Последнее обновление, Last refreshed,Последнее обновление, Link Document Type,Тип документа ссылки, Link Fieldname,Имя поля ссылки, -Loading import file...,Загрузка файла импорта ..., +Loading import file...,Загрузка файла импорта..., Local Document Type,Локальный тип документа, Log Data,Данные журнала, Main Section (HTML),Основной раздел (HTML), -Main Section (Markdown),Основной раздел (Уценка), +Main Section (Markdown),Основной раздел (Markdown), "Maintains a Log of all inserts, updates and deletions on Event Producer site for documents that have consumers.","Ведение журнала всех вставок, обновлений и удалений на сайте Event Producer для документов, имеющих потребителей.", Maintains a log of every event consumed along with the status of the sync and a Resync button in case sync fails.,"Ведение журнала всех использованных событий, а также состояния синхронизации и кнопки Resync в случае сбоя синхронизации.", Make all attachments private,Сделайте все вложения приватными, -Mandatory Depends On,Обязательный Зависит от, +Mandatory Depends On,Обязательно зависит от, Map Columns,Столбцы карты, Map columns from {0} to fields in {1},Сопоставить столбцы из {0} с полями в {1}, Mapping column {0} to field {1},Отображение столбца {0} в поле {1}, Mark all as Read,Отметить все как прочитанное, -Maximum Points,Максимум очков, +Maximum Points,Максимум баллов, Maximum points allowed after multiplying points with the multiplier value\n(Note: For no limit leave this field empty or set 0),"Максимальное количество баллов, допустимое после умножения баллов на значение множителя (Примечание: для ограничения не оставляйте это поле пустым или установите 0)", Me,Мне, Mention,Упоминание, @@ -3473,14 +3473,14 @@ Page Shortcuts,Ярлыки страниц, Parent Field (Tree),Родительское поле (дерево), Parent Field must be a valid fieldname,Родительское поле должно быть допустимым именем поля, Pin Globally,Pin глобально, -Places,места, -Please check the filter values set for Dashboard Chart: {},"Проверьте значения фильтра, установленные для Диаграммы панели инструментов: {}", +Places,Места, +Please check the filter values set for Dashboard Chart: {},"Проверьте значения фильтра, установленные для диаграммы панели инструментов: {}", Please enable pop-ups in your browser,"Пожалуйста, включите всплывающие окна в вашем браузере", Please find attached {0}: {1},"Пожалуйста, найдите прикрепленный {0}: {1}", Please select applicable Doctypes,"Пожалуйста, выберите подходящий тип документа", -Portrait,Портрет, +Portrait,Портретная, Press Alt Key to trigger additional shortcuts in Menu and Sidebar,"Нажмите клавишу Alt, чтобы вызвать дополнительные ярлыки в меню и боковой панели", -Print Settings...,Настройки печати ..., +Print Settings...,Настройки печати..., Producer Document Name,Название документа производителя, Producer URL,URL производителя, Property Depends On,Недвижимость зависит от, @@ -3491,8 +3491,8 @@ Pulled from Google Contacts,Вытащено из контактов Google, Push to Google Calendar,Нажмите на Google Calendar, Push to Google Contacts,Нажмите на контакты Google, Queue / Worker,Очередь / Рабочий, -RAW Information Log,RAW информационный журнал, -Raw Printing Settings...,Настройки сырой печати ..., +RAW Information Log,Необработанный информационный журнал, +Raw Printing Settings...,Настройки необработанной печати..., Read Only Depends On,Только чтение зависит от, Recent Activity,Недавняя активность, Reference document has been cancelled,Справочный документ был отменен, @@ -3508,7 +3508,7 @@ Restricted,Ограниченный, Restrictions,ограничения, Resync,Синхронизировать, Row Number,Номер строки, -Row {0},Ряд {0}, +Row {0},Строка {0}, Run Jobs only Daily if Inactive For (Days),"Запускать задания только ежедневно, если неактивен в течение (дней)", SMS was not sent. Please contact Administrator.,"SMS не было отправлено. Пожалуйста, свяжитесь с администратором.", Saved Successfully,Успешно сохранено, @@ -3524,11 +3524,11 @@ Search Source Text,Поиск исходного текста, Search by filename or extension,Поиск по имени файла или расширению, Select Date Range,Выберите диапазон дат, Select Field,Выберите поле, -Select Field...,Выберите поле ..., +Select Field...,Выберите поле..., Select Filters,Выберите фильтры, Select Google Calendar to which event should be synced.,"Выберите Календарь Google, к которому нужно синхронизировать событие.", Select Google Contacts to which contact should be synced.,"Выберите Google Контакты, с которыми контакт должен быть синхронизирован.", -Select Group By...,Выбрать группу по ..., +Select Group By...,Выбрать группу по..., Select Mandatory,Выберите Обязательный, Select atleast 2 actions,Выберите по крайней мере 2 действия, Select list item,Выберите элемент списка, @@ -3556,8 +3556,8 @@ Social Home,Социальный Дом, Some columns might get cut off when printing to PDF. Try to keep number of columns under 10.,"Некоторые столбцы могут быть обрезаны при печати в PDF. Старайтесь, чтобы количество столбцов было меньше 10.", Something went wrong during the token generation. Click on {0} to generate a new one.,"Что-то пошло не так во время генерации токенов. Нажмите {0}, чтобы создать новый.", Submit After Import,Отправить после импорта, -Submitting...,Добавляю ..., -Success! You are good to go 👍,Успех! Ты хорош идти go, +Submitting...,Добавляю..., +Success! You are good to go 👍,Успех! Вы можете продолжать 👍, Successful Transactions,Успешные транзакции, Successfully Submitted!,Успешно отправлено!, Successfully imported {0} record.,Успешно импортирована запись {0}., @@ -3597,13 +3597,13 @@ To enable it follow the instructions in the following link: {0},"Чтобы вк "To use Google Contacts, enable {0}.","Чтобы использовать контакты Google, включите {0}.", "To use Google Drive, enable {0}.","Чтобы использовать Google Диск, включите {0}.", Today's Events,Сегодняшние события, -Toggle Public/Private,Переключить Публичный / Частный, +Toggle Public/Private,Переключить Публичный/Приватный, Tracks milestones on the lifecycle of a document if it undergoes multiple stages.,"Отслеживает этапы жизненного цикла документа, если он проходит несколько этапов.", Tree structures are implemented using Nested Set,Древовидные структуры реализованы с использованием Nested Set, Trigger Primary Action,Триггер Основное действие, URL for documentation or help,URL для документации или помощи, -URL must start with 'http://' or 'https://',URL должен начинаться с «http: //» или «https: //», -Unchanged,без изменений, +URL must start with 'http://' or 'https://',URL должен начинаться с «http://» или «https://», +Unchanged,Без изменений, Unpin,Открепить, Untitled Column,Колонка без названия, Untranslated,Непереведенные, @@ -3632,7 +3632,7 @@ Verification,Верификация, Verification Code,Код верификации, Verification code email not sent. Please contact Administrator.,"Письмо с кодом подтверждения не отправлено. Пожалуйста, свяжитесь с администратором.", Verified,Проверенный, -Verifier,контрольник, +Verifier,Проверяющий, View Full Log,Посмотреть полный журнал, "View Log of all print, download and export events","Просмотр журнала всех событий печати, загрузки и экспорта", Visit Web Page,Посетить веб-страницу, @@ -3646,7 +3646,7 @@ Workflow Status,Состояние рабочего процесса, You are not allowed to export {} doctype,Вы не можете экспортировать {} doctype, You can try changing the filters of your report.,Вы можете попробовать изменить фильтры вашего отчета., You do not have permissions to cancel all linked documents.,У вас нет прав для отмены всех связанных документов., -You need to create these first: ,Вам нужно сначала создать это:, +You need to create these first: ,Вам нужно сначала создать это: , You need to enable JavaScript for your app to work.,Вам нужно включить JavaScript для вашего приложения для работы., You need to install pycups to use this feature!,"Вам нужно установить pycups, чтобы использовать эту функцию!", Your Target,Ваша цель, @@ -3696,10 +3696,10 @@ Browse,Обзор, Cancelled,отменен, Chart,Диаграмма, Close,Закрыть, -Communication,Общение, +Communication,Коммуникация, Compact Item Print,Компактный товара печати, Company,Организация, -Complete,полный, +Complete,Завершен, Completed,Завершено, Continue,Продолжать, Country,Страна, @@ -3728,31 +3728,31 @@ Error,Ошибка, Expired,Истек срок действия, Export,Экспорт, Export not allowed. You need {0} role to export.,Экспорт не допускается. Вам нужно {0} роль для экспорта., -Fetching...,Fetching ..., -Field,поле, +Fetching...,Получение..., +Field,Поле, File Manager,Файловый менеджер, Filters,Фильтры, Get Items,Получить продукты, Goal,Цель, -Group,группа, -Group Node,Узел Группа, +Group,Группа, +Group Node,Групповой узел, Help,Помощь, Help Article,Статья помощи, Home,Главная, Import Data from CSV / Excel files.,Импорт данных из файлов CSV / Excel., In Progress,Выполняется, -Intermediate,промежуточный, +Intermediate,Промежуточный, Invite as User,Пригласить в пользователя, "It seems that there is an issue with the server's stripe configuration. In case of failure, the amount will get refunded to your account.","Кажется, что существует проблема с конфигурацией полосок сервера. В случае сбоя сумма будет возвращена на ваш счет.", Loading...,Загрузка..., Location,Местоположение, Looks like someone sent you to an incomplete URL. Please ask them to look into it.,"Похоже, кто-то послал вас к неполному URL. Пожалуйста, попросите их посмотреть в нее.", -Master,Магистр, +Master,Мастер, Message,Сообщение, Missing Values Required,Не заполнены обязательные поля, Mobile No,Мобильный номер, Month,Mесяц, -Name,имя, +Name,Имя, Newsletter,Рассылка новостей, Not Allowed,Не разрешено, Note,Заметки, @@ -3767,12 +3767,12 @@ Please select another payment method. Stripe does not support transactions in cu Please specify,"Пожалуйста, сформулируйте", Printing,Печать, Priority,Приоритет, -Project,проект, +Project,Проект, Quarterly,Ежеквартально, Queued,В очереди, Quick Entry,Быстрый доступ, Reason,Причина, -Refreshing,освежение, +Refreshing,Обновление, Rename,Переименовать, Reset,Сброс, Review,Обзор, @@ -3780,7 +3780,7 @@ Room,Комната, Room Type,Тип номера, Save,Сохранить, Search results for,Результаты поиска, -Select All,Выбрать Все, +Select All,Выбрать все, Send,Отправить, Sending,Отправка, Server Error,Ошибка сервера, @@ -3790,7 +3790,7 @@ Setup Wizard,Мастер установки, Size,Размер, Sr,Sr, Start,Начать, -Start Time,Время, +Start Time,Стартовое время, Status,Статус, Submitted,Проведенный, Tag,Тег, @@ -3825,7 +3825,7 @@ Clear,Отчистить, Comment,Комментарий, Comments,Комментарии, DRAFT,ЧЕРНОВИК, -Dashboard,Приборная доска, +Dashboard,панель инструментов, DocType,DocType, Download,Скачать, EMail,Эл. адрес, @@ -3847,8 +3847,8 @@ New,Новый, Not Found,Не найдено, Not Like,Не как, Notify by Email,Уведомить по электронной почте, -Now,Сейчас, -Off,от, +Now,Только что, +Off,Выключен, One of,Один из, Page,Страница, Print,Распечатать, @@ -3893,7 +3893,7 @@ Not found,Не обнаружена, Notes:,Примечания:, Notify by email,Уведомление по почте, Permitted Documents For User,Разрешенные документы для пользователя, -Reference Docname,Ссылка DOCNAME, +Reference Docname,Ссылка Docname, Reference Doctype,Ссылка DocType, Reference name,Имя ссылки, Roles Html,Роли Html, @@ -3901,7 +3901,7 @@ Row #,Строка #, Scheduled to send,Запланировано для отправки, Select Doctype,Выберите Doctype, Send Email for Successful backup,Отправить письмо об успешном завершении резервного копирования, -Sign up,Подписаться, +Sign up,Зарегистрироваться, Time format,Формат времени, Upload failed,Загрузка не удалась, User Id,Идентификатор пользователя, @@ -3912,14 +3912,14 @@ added {0},Добавлено {0}, barcode,штрих-код, beginning with,начиная с, blue,синий, -bold,храбрый самоуверенный, +bold,жирный, book,книга, calendar,календарь, certificate,сертификат, -check,чек, +check,проверить, clear,отчистить, comment,комментарий, -comments,Комментарии, +comments,комментарии, created,созданный, danger,опасность, dashboard,Панель приборов, @@ -3933,9 +3933,9 @@ font,шрифт, forward,дальше, green,зеленый, home,дом, -icon,значок, -inbox,хходящие, -like,Мне нравится, +icon,иконка, +inbox,входящие, +like,нравится, link,ссылка, list,список, lock,запирать, @@ -3945,7 +3945,7 @@ module,модуль, move,переместить, music,музыка, new,новый, -now,сейчас, +now,только что, off,выкл, one of,один из, orange,оранжевый, @@ -3973,7 +3973,7 @@ web link,ссылка, yellow,желтый, Not permitted,Не разрешено, Add Chart to Dashboard,Добавить диаграмму на панель инструментов, -Add to Dashboard,Добавить в Личный кабинет, +Add to Dashboard,Добавить на панель инструментов, Google Translation,Гугл-перевод, Important,Важный, No Filters Set,Фильтры не установлены, @@ -3994,19 +3994,19 @@ Desk Page,Рабочий стол, Desk Shortcut,Сочетание клавиш, Developer Mode Only,Только режим разработчика, Disable User Customization,Отключить настройку пользователя, -For example: {} Open,Например: {} Открыть, +For example: {} Open,Например: {} Open, Link Cards,Карты ссылок, Link To,Ссылка к, Onboarding,Вводный, -Percentage,процент, -Pie,пирог, -Pin To Bottom,Pin To Bottom, -Pin To Top,Pin To Top, +Percentage,Процент, +Pie,Пирог, +Pin To Bottom,Закрепить внизу, +Pin To Top,Закрепить сверху, Restrict to Domain,Ограничить доступ к домену, Shortcuts,Ярлыки, -X Field,X Field, +X Field,Поле X, Y Axis,Ось Y, -workspace,Рабочее пространство, +workspace,рабочее пространство, Setup > User,Настройка> Пользователь, Setup > Customize Form,Настройка> Настройка формы, Setup > User Permissions,Настройка> Полномочия пользователя, @@ -4067,9 +4067,9 @@ Scheduler Event,Планировщик событий, Select Event Type,Выберите тип события, Schedule Script,Сценарий расписания, Duration,Продолжительность, -Donut,Пончик, +Donut,Донат, Custom Options,Пользовательские параметры, -"Ex: ""colors"": [""#d1d8dd"", ""#ff5858""]","Пример: "colors": ["# d1d8dd", "# ff5858"]", +"Ex: ""colors"": [""#d1d8dd"", ""#ff5858""]","Пример: ""colors"": [""#d1d8dd"", ""#ff5858""]", Confirmation Email Template,Шаблон письма с подтверждением, Welcome Email Template,Шаблон приветственного письма, Schedule Send,Расписание отправки, @@ -4095,7 +4095,7 @@ Browser,Браузер, Browser Version,Версия браузера, Web Template Field,Поле веб-шаблона, Section,Раздел, -Hide,Спрятать, +Hide,Скрыть, Enable In App Website Tracking,Включить отслеживание веб-сайтов в приложении, Enable Google Indexing,Включить индексирование Google, "To use Google Indexing, enable Google Settings.","Чтобы использовать индексирование Google, включите настройки Google .", @@ -4110,7 +4110,7 @@ Button Gradients,Градиенты кнопок, Light Color,Светлый цвет, Stylesheet,Таблица стилей, Custom SCSS,Пользовательский SCSS, -Navbar,Навбар, +Navbar,Навигационна панель, Source Message,Исходное сообщение, Translated Message,Переведенное сообщение, Verified By,Утверждено, @@ -4118,7 +4118,7 @@ Using this console may allow attackers to impersonate you and steal your informa {0} m,{0} м, {0} h,{0} ч, {0} d,{0} д, -{0} w,{0} нед., +{0} w,{0} н, {0} M,{0} М, {0} y,{0} г, yesterday,вчерашний день, @@ -4174,7 +4174,7 @@ Account SID,SID аккаунта, Steps,Шаги, email,Эл. адрес, Component,Компонент, -Subtitle,подзаголовок, +Subtitle,Подзаголовок, Global Defaults,Глобальные вводные по умолчанию, Prefix,Префикс, Is Public,Публично, @@ -4193,13 +4193,13 @@ Number Card Link,Номер карты Ссылка, Card,Карта, API Access,Доступ к API, Access Key Secret,Секретный ключ доступа, -S3 Bucket Details,Детали ковша S3, +S3 Bucket Details,Детали хранилища S3, Bucket Name,Название сегмента, Backup Details,Детали резервного копирования, Backup Files,Резервные файлы, Backup public and private files along with the database.,Резервное копирование общедоступных и частных файлов вместе с базой данных., Set to 0 for no limit on the number of backups taken,"Установите значение 0, чтобы не было ограничений на количество создаваемых резервных копий.", -Meta Description,Мета Описание, +Meta Description,Мета описание, Meta Image,Мета-изображение, Google Snippet Preview,Предварительный просмотр фрагмента кода Google, This is an example Google SERP Preview.,Это пример предварительного просмотра Google SERP., @@ -4231,7 +4231,7 @@ Invalid Option,Неверный вариант, Request Body consists of an invalid JSON structure,Тело запроса состоит из недопустимой структуры JSON, Invalid JSON,Неверный JSON, Party GSTIN,Партия GSTIN, -GST State,Штат GST, +GST State,Состояние НДС, Andaman and Nicobar Islands,Андаманские и Никобарские острова, Andhra Pradesh,Андхра-Прадеш, Arunachal Pradesh,Аруначал-Прадеш, @@ -4299,7 +4299,7 @@ Application Name,Имя приложения, Application Version,Версия приложения, Git Branch,Git Branch, Installed Applications,Установленные приложения, -Navbar Item,Элемент Navbar, +Navbar Item,Элемент навигационной панели, Item Label,Этикетка товара, Item Type,Тип объекта, Separator,Разделитель, @@ -4323,15 +4323,15 @@ Hourly rate limit for generating password reset links,Лимит почасов Send document Web View link in email,Отправить документ Ссылка на веб-просмотр по электронной почте, Enable Auto-deletion of Prepared Reports,Включить автоматическое удаление подготовленных отчетов, Prepared Report Expiry Period (Days),Срок действия подготовленного отчета (дни), -System will automatically delete Prepared Reports after these many days since creation,Система автоматически удалит подготовленные отчеты по прошествии многих дней с момента создания., +System will automatically delete Prepared Reports after these many days since creation,Система автоматически удалит подготовленные отчеты по прошествии нескольких дней с момента создания., Package Document Type,Тип документа пакета, Include Attachments,Включить вложения, Overwrite,Перезаписать, Package Publish Target,Цель публикации пакета, -Site URL,адрес сайта, +Site URL,Адрес сайта, Package Publish Tool,Инструмент публикации пакетов, Click on the row for accessing filters.,Щелкните строку для доступа к фильтрам., -Sites,Места, +Sites,Сайты, Last Deployed On,Последнее развертывание, Console Log,Журнал консоли, "Set Default Options for all charts on this Dashboard (Ex: ""colors"": [""#d1d8dd"", ""#ff5858""])","Установите параметры по умолчанию для всех диаграмм на этой панели инструментов (например: «colors»: [«# d1d8dd», «# ff5858»])", @@ -4354,13 +4354,13 @@ Is Complete,Завершено, Alert,Предупреждение, Document Link,Ссылка на документ, Attached File,Прикрепленный файл, -Attachment Link,Ссылка на приложение, +Attachment Link,Прикрепленная ссылка, Open Reference Document,Открыть справочный документ, Custom Configuration,Пользовательская конфигурация, Filters Configuration,Конфигурация фильтров, Dynamic Filters Section,Раздел динамических фильтров, Please create Card first,"Пожалуйста, сначала создайте карту", -Onboarding Permission,Разрешение на посадку, +Onboarding Permission,Разрешение на подключение, Onboarding Step,Начальный этап, Is Mandatory,Является обязательным, Is Skipped,Пропущено, @@ -4392,7 +4392,7 @@ Commit,Зафиксировать, Execute Console script,Выполнить скрипт консоли, Execute,Выполнить, Create Contacts from Incoming Emails,Создание контактов из входящих писем, -Inbox User,Входящие Пользователь, +Inbox User,Входящие пользователя, Disabled Auto Reply,Отключен автоматический ответ, Schedule Sending,Расписание отправки, Message (Markdown),Сообщение (Markdown), @@ -4409,7 +4409,7 @@ Send System Notification,Отправить системное уведомле Send To All Assignees,Отправить всем уполномоченным, Receiver By Document Field,Получатель по полю документа, Receiver By Role,Получатель по роли, -Child Table,Дочерний стол, +Child Table,Дочерняя таблица, Remote Value Filters,Удаленные фильтры значений, API Key of the user(Event Subscriber) on the producer site,API-ключ пользователя (подписчика на событие) на сайте производителя, API Secret of the user(Event Subscriber) on the producer site,API Secret пользователя (подписчика на событие) на сайте производителя, @@ -4425,8 +4425,8 @@ me-south-1,мне-юг-1, Twilio Number Group,Группа номеров Twilio, Twilio Settings,Настройки Twilio, Auth Token,Токен аутентификации, -Read Time,Время Читать, -in minutes,в считанные минуты, +Read Time,Время на чтение, +in minutes,в минутах, Featured,Рекомендуемые, Hide CTA,Скрыть CTA, "Description for listing page, in plain text, only a couple of lines. (max 200 characters)","Описание страницы с листингом в виде простого текста, всего пара строк. (не более 200 символов)", @@ -4442,7 +4442,7 @@ Social Link Settings,Настройки социальных ссылок, Social Link Type,Тип социальной ссылки, facebook,facebook, linkedin,linkedin, -twitter,твиттер, +twitter,twitter, "If Icon is set, it will be shown instead of Label","Если установлен значок, он будет отображаться вместо метки.", Apply Document Permissions,Применить разрешения документа, "For help see Client Script API and Examples","Для получения справки см. API клиентских скриптов и примеры.", @@ -4459,7 +4459,7 @@ URL of the page,URL страницы, Content type for building the page,Тип контента для построения страницы, "You can select one from the following,","Вы можете выбрать один из следующих,", Standard rich text editor with controls,Стандартный редактор форматированного текста с элементами управления, -Github flavoured markdown syntax,Синтаксис уценки со вкусом Github, +Github flavoured markdown syntax,Синтаксис markdown в стиле Github, HTML with jinja support,HTML с поддержкой jinja, Frappe page builder using components,Конструктор страниц Frappe с использованием компонентов, Checking this will show a text area where you can write custom javascript that will run on this page.,"При выборе этого параметра будет отображаться текстовая область, в которой вы можете написать собственный javascript, который будет запускаться на этой странице.", @@ -4472,7 +4472,7 @@ Add Space on Bottom,Добавить пространство внизу, Is Unique,Уникальный, User Agent,Пользовательский агент, Table Break,Таблица Break, -Hide Login,Скрыть Логин, +Hide Login,Скрыть логин, Navbar Template,Шаблон навигационной панели, Navbar Template Values,Значения шаблона навигационной панели, Call To Action,Призыв к действию, @@ -4493,24 +4493,24 @@ Are you sure you want to save this document?,"Вы уверены, что хот Refresh All,Обновить все, "Level 0 is for document level permissions, higher levels for field level permissions.","Уровень 0 предназначен для разрешений на уровне документа, более высокие уровни - для разрешений на уровне поля.", Website Analytics,Веб-аналитика, -d,d,Days (Field: Duration) -h,час,Hours (Field: Duration) +d,д,Days (Field: Duration) +h,ч,Hours (Field: Duration) m,м,Minutes (Field: Duration) -s,s,Seconds (Field: Duration) +s,с,Seconds (Field: Duration) Less,Меньше, Not a valid DocType view:,Недопустимое представление DocType:, Unknown View,Неизвестный вид, -Go Back,Вернитесь назад, +Go Back,Вернуться назад, Let's take you back to onboarding,Вернемся к адаптации, Great Job,Прекрасная работа, Looks Great,Выглядит отлично, Looks like you didn't change the value,"Похоже, вы не меняли значение", -Oops,Ой, +Oops,Упс, Skip Step,Пропустить шаг, "You're doing great, let's take you back to the onboarding page.","У вас все отлично, давайте вернемся на страницу адаптации.", Good Work 🎉,Хорошая работа 🎉, Submit this document to complete this step.,"Отправьте этот документ, чтобы завершить этот шаг.", -Great,большой, +Great,Отлично, You may continue with onboarding,Вы можете продолжить регистрацию, You seem good to go!,"Кажется, ты в порядке!", Onboarding Complete,Посадка завершена, @@ -4530,13 +4530,13 @@ Delete and Generate New,Удалить и создать новое, Select Fields To Insert,Выберите поля для вставки, Select Fields To Update,Выберите поля для обновления, "This document is already amended, you cannot ammend it again","В этот документ уже внесены поправки, вы не можете изменить его снова", -Add to ToDo,Добавить в ToDo, +Add to ToDo,Добавить в список задач, {0} is currently {1},{0} в настоящее время {1}, {0} are currently {1},{0} в настоящее время {1}, Currently Replying,Отвечаю сейчас, created {0},создано {0}, Make a call,Позвонить, -Change,+ Изменить,Coins +Change,Изменить,Coins Too Many Requests,Слишком много запросов, "Invalid Authorization headers, add a token with a prefix from one of the following: {0}.","Недопустимые заголовки авторизации, добавьте токен с одним из следующих префиксов: {0}.", "Invalid Authorization Type {0}, must be one of {1}.","Недействительный тип авторизации {0}, должен быть одним из {1}.", @@ -4599,7 +4599,7 @@ Please enable twilio settings before sending WhatsApp messages,"Пожалуйс Delivery Failed,Доставка не удалась, Twilio WhatsApp Message Error,Ошибка сообщения Twilio WhatsApp, A featured post must have a cover image,В избранном посте должна быть обложка., -Load More,Загрузи больше, +Load More,Показать больше, Published on,Опубликован в, Enable developer mode to create a standard Web Template,"Включите режим разработчика, чтобы создать стандартный веб-шаблон", Was this article helpful?,Эта статья была полезной?, @@ -4627,8 +4627,8 @@ New module created {0},Создан новый модуль {0}, There are documents which have workflow states that do not exist in this Workflow. It is recommended that you add these states to the Workflow and change their states before removing these states.,"Есть документы, в которых есть состояния рабочего процесса, которых нет в этом рабочем процессе. Рекомендуется добавить эти состояния в рабочий процесс и изменить их состояния перед удалением этих состояний.", Worflow States Don't Exist,Состояния Worflow не существуют, Save Anyway,Все равно сохранить, -Energy Points:,Очки энергии:, -Review Points:,Очки обзора:, +Energy Points:,Баллы активности:, +Review Points:,Баллы обзора:, Rank:,Ранг:, Monthly Rank:,Месячный рейтинг:, Invalid expression set in filter {0} ({1}),Недопустимое выражение в фильтре {0} ({1}), @@ -4639,8 +4639,8 @@ Not permitted to view {0},Не разрешено просматривать {0} Camera,Камера, Invalid filter: {0},Недействительный фильтр: {0}, Let's Get Started,Давайте начнем, -Reports & Masters,Отчеты и магистры, -New {0} {1} added to Dashboard {2},Новый {0} {1} добавлен в Личный кабинет {2}, +Reports & Masters,Отчеты и мастеры, +New {0} {1} added to Dashboard {2},Новый {0} {1} добавлен на панель инструментов {2}, New {0} {1} created,Создан новый {0} {1}, New {0} Created,Новый {0} создан, "Invalid ""depends_on"" expression set in filter {0}",В фильтре {0} задано недопустимое выражение "depends_on", @@ -4678,7 +4678,7 @@ Cannot delete standard link. You can hide it if you want,"Невозможно Cannot delete standard action. You can hide it if you want,"Невозможно удалить стандартное действие. Вы можете скрыть это, если хотите", Applied On,Применено, Row Name,Название строки, -For DocType Link / DocType Action,Для DocType Link / DocType Action, +For DocType Link / DocType Action,Для DocType ссылки / DocType действия, Cannot edit filters for standard charts,Невозможно редактировать фильтры для стандартных диаграмм, Event Producer Last Update,Последнее обновление Event Producer, Default for 'Check' type of field {0} must be either '0' or '1',"По умолчанию для типа поля "Проверка" {0} должен быть либо "0", либо "1".", @@ -4686,7 +4686,7 @@ Non Negative,Не отрицательный, Rules with higher priority number will be applied first.,Сначала будут применяться правила с более высоким номером приоритета., Open URL in a New Tab,Открыть URL в новой вкладке, Align Right,Выровнять по правому краю, -Loading Filters...,Загрузка фильтров ..., +Loading Filters...,Загрузка фильтров..., Count Customizations,Подсчет настроек, For Example: {} Open,Например: {} Открыть, Choose Existing Card or create New Card,Выберите существующую карту или создайте новую карту, From 2aa09c9033ce7ad7666258d6c52c2cb53f259780 Mon Sep 17 00:00:00 2001 From: Jannat Patel Date: Fri, 6 May 2022 10:19:32 +0530 Subject: [PATCH 11/35] fix: web form login message --- frappe/public/js/frappe/web_form/webform_script.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/web_form/webform_script.js b/frappe/public/js/frappe/web_form/webform_script.js index cd687f8dd8..084a767f31 100644 --- a/frappe/public/js/frappe/web_form/webform_script.js +++ b/frappe/public/js/frappe/web_form/webform_script.js @@ -26,8 +26,8 @@ frappe.ready(function() { window.location.replace('/login?redirect-to=' + window.location.pathname); } }); - login_required.set_message(__("You are not permitted to access this page.")); login_required.show(); + login_required.set_message(__("You are not permitted to access this page.")); } function show_grid() { From 5941f3c4ac97580d509e16d4454bd50c7d5b40b5 Mon Sep 17 00:00:00 2001 From: Jannat Patel Date: Fri, 6 May 2022 10:24:34 +0530 Subject: [PATCH 12/35] fix: better login message --- frappe/public/js/frappe/web_form/webform_script.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/web_form/webform_script.js b/frappe/public/js/frappe/web_form/webform_script.js index 084a767f31..30ff03cb5d 100644 --- a/frappe/public/js/frappe/web_form/webform_script.js +++ b/frappe/public/js/frappe/web_form/webform_script.js @@ -27,7 +27,7 @@ frappe.ready(function() { } }); login_required.show(); - login_required.set_message(__("You are not permitted to access this page.")); + login_required.set_message(__("You are not permitted to access this page without login.")); } function show_grid() { From 48458aa129eb5b8adfcbac706f5b7df6cb04c99b Mon Sep 17 00:00:00 2001 From: Steve Date: Fri, 6 May 2022 01:18:15 -0400 Subject: [PATCH 13/35] Update list_settings.js Don't limit list view to 4 --- frappe/public/js/frappe/list/list_settings.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/list/list_settings.js b/frappe/public/js/frappe/list/list_settings.js index 186a4370bc..b7318ea780 100644 --- a/frappe/public/js/frappe/list/list_settings.js +++ b/frappe/public/js/frappe/list/list_settings.js @@ -78,7 +78,7 @@ export default class ListSettings { if (field_count < 4) { field_count = 4; } else if (field_count > 10) { - field_count = 4; + field_count = 10; } me.dialog.set_value("total_fields", field_count); From 852dbae6ceb663d4ed0f0891f376b5ff9d12610f Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Fri, 6 May 2022 12:09:13 +0530 Subject: [PATCH 14/35] fix: Do not convert timezone of date field --- frappe/public/js/frappe/form/controls/date.js | 8 ++++---- frappe/public/js/frappe/form/controls/datetime.js | 2 -- frappe/public/js/frappe/utils/datetime.js | 5 ++++- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/frappe/public/js/frappe/form/controls/date.js b/frappe/public/js/frappe/form/controls/date.js index 0f80371706..bea7e77bd1 100644 --- a/frappe/public/js/frappe/form/controls/date.js +++ b/frappe/public/js/frappe/form/controls/date.js @@ -137,13 +137,13 @@ frappe.ui.form.ControlDate = class ControlDate extends frappe.ui.form.ControlDat }); } parse(value) { - if(value) { - return frappe.datetime.user_to_str(value); + if (value) { + return frappe.datetime.user_to_str(value, false, true); } } format_for_input(value) { - if(value) { - return frappe.datetime.str_to_user(value); + if (value) { + return frappe.datetime.str_to_user(value, false, true); } return ""; } diff --git a/frappe/public/js/frappe/form/controls/datetime.js b/frappe/public/js/frappe/form/controls/datetime.js index d1a06a6ac6..9b10465d7b 100644 --- a/frappe/public/js/frappe/form/controls/datetime.js +++ b/frappe/public/js/frappe/form/controls/datetime.js @@ -45,8 +45,6 @@ frappe.ui.form.ControlDatetime = class ControlDatetime extends frappe.ui.form.Co } format_for_input(value) { if (!value) return ""; - - return frappe.datetime.str_to_user(value, false); } set_description() { diff --git a/frappe/public/js/frappe/utils/datetime.js b/frappe/public/js/frappe/utils/datetime.js index 196bdf68a3..2bf64fd88e 100644 --- a/frappe/public/js/frappe/utils/datetime.js +++ b/frappe/public/js/frappe/utils/datetime.js @@ -133,7 +133,7 @@ $.extend(frappe.datetime, { return frappe.sys_defaults && frappe.sys_defaults.date_format || "yyyy-mm-dd"; }, - str_to_user: function(val, only_time = false) { + str_to_user: function(val, only_time=false, only_date=false) { if (!val) return ""; const user_date_fmt = frappe.datetime.get_user_date_fmt().toUpperCase(); const user_time_fmt = frappe.datetime.get_user_time_fmt(); @@ -142,6 +142,9 @@ $.extend(frappe.datetime, { if (only_time) { let date_obj = moment(val, frappe.defaultTimeFormat); return date_obj.format(user_format); + } else if (only_date) { + let date_obj = moment(val, frappe.defaultDateFormat); + return date_obj.format(user_date_fmt); } else { let date_obj = moment.tz(val, frappe.boot.time_zone.system); if (typeof val !== "string" || val.indexOf(" ") === -1) { From 1b36dcabe401b679782533842db70c7dd28b4fb3 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Mon, 9 May 2022 15:48:19 +0530 Subject: [PATCH 15/35] chore: remove dead code --- frappe/public/js/lib/clusterize.min.js | 16 ---------------- frappe/public/js/report.bundle.js | 1 - 2 files changed, 17 deletions(-) delete mode 100644 frappe/public/js/lib/clusterize.min.js diff --git a/frappe/public/js/lib/clusterize.min.js b/frappe/public/js/lib/clusterize.min.js deleted file mode 100644 index 36c2ecba3c..0000000000 --- a/frappe/public/js/lib/clusterize.min.js +++ /dev/null @@ -1,16 +0,0 @@ -/*! Clusterize.js - v0.17.6 - 2017-03-05 -* http://NeXTs.github.com/Clusterize.js/ -* Copyright (c) 2015 Denis Lukov; Licensed GPLv3 */ - -;(function(q,n){"undefined"!=typeof module?module.exports=n():"function"==typeof define&&"object"==typeof define.amd?define(n):this[q]=n()})("Clusterize",function(){function q(b,a,c){return a.addEventListener?a.addEventListener(b,c,!1):a.attachEvent("on"+b,c)}function n(b,a,c){return a.removeEventListener?a.removeEventListener(b,c,!1):a.detachEvent("on"+b,c)}function r(b){return"[object Array]"===Object.prototype.toString.call(b)}function m(b,a){return window.getComputedStyle?window.getComputedStyle(a)[b]: - a.currentStyle[b]}var l=function(){for(var b=3,a=document.createElement("b"),c=a.all||[];a.innerHTML="\x3c!--[if gt IE "+ ++b+"]>=l&&!c.tag&&(c.tag=b[0].match(/<([^>\s/]*)/)[1].toLowerCase()),1>=this.content_elem.children.length&&(a.data=this.html(b[0]+b[0]+b[0])),c.tag||(c.tag=this.content_elem.children[0].tagName.toLowerCase()), - this.getRowsHeight(b))},getRowsHeight:function(b){var a=this.options,c=a.item_height;a.cluster_height=0;if(b.length){b=this.content_elem.children;var d=b[Math.floor(b.length/2)];a.item_height=d.offsetHeight;"tr"==a.tag&&"collapse"!=m("borderCollapse",this.content_elem)&&(a.item_height+=parseInt(m("borderSpacing",this.content_elem),10)||0);"tr"!=a.tag&&(b=parseInt(m("marginTop",d),10)||0,d=parseInt(m("marginBottom",d),10)||0,a.item_height+=Math.max(b,d));a.block_height=a.item_height*a.rows_in_block; - a.rows_in_cluster=a.blocks_in_cluster*a.rows_in_block;a.cluster_height=a.blocks_in_cluster*a.block_height;return c!=a.item_height}},getClusterNum:function(){this.options.scroll_top=this.scroll_elem.scrollTop;return Math.floor(this.options.scroll_top/(this.options.cluster_height-this.options.block_height))||0},generateEmptyRow:function(){var b=this.options;if(!b.tag||!b.show_no_data_row)return[];var a=document.createElement(b.tag),c=document.createTextNode(b.no_data_text),d;a.className=b.no_data_class; - "tr"==b.tag&&(d=document.createElement("td"),d.colSpan=100,d.appendChild(c));a.appendChild(d||c);return[a.outerHTML]},generate:function(b,a){var c=this.options,d=b.length;if(de&&g++;f=l&&"tr"==this.options.tag){var c=document.createElement("div");for(c.innerHTML=""+b+"
";b=a.lastChild;)a.removeChild(b);for(c=this.getChildNodes(c.firstChild.firstChild);c.length;)a.appendChild(c.shift())}else a.innerHTML=b},getChildNodes:function(b){b=b.children;for(var a=[],c=0,d=b.length;c Date: Mon, 9 May 2022 18:42:54 +0530 Subject: [PATCH 16/35] fix: frappe.throw in case of list of errors (#16855) --- frappe/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/__init__.py b/frappe/__init__.py index 8bd7783283..46313e9ee9 100644 --- a/frappe/__init__.py +++ b/frappe/__init__.py @@ -435,7 +435,7 @@ def msgprint( if as_table and type(msg) in (list, tuple): out.as_table = 1 - if as_list and type(msg) in (list, tuple) and len(msg) > 1: + if as_list and type(msg) in (list, tuple): out.as_list = 1 if flags.print_messages and out.message: From 970ae83147af67ab8bc122ec8bb239a7ac5f5424 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Sun, 8 May 2022 20:03:01 +0530 Subject: [PATCH 17/35] fix: duplicate list_update realtime events - list_update is fired separately from document.py, this causes duplicate events. - move reportview specific realtime update --- frappe/public/js/frappe/list/list_view.js | 14 -------------- frappe/public/js/frappe/model/model.js | 7 ------- .../public/js/frappe/views/reports/report_view.js | 5 +++++ 3 files changed, 5 insertions(+), 21 deletions(-) diff --git a/frappe/public/js/frappe/list/list_view.js b/frappe/public/js/frappe/list/list_view.js index 35e387b8d8..358f9ba23c 100644 --- a/frappe/public/js/frappe/list/list_view.js +++ b/frappe/public/js/frappe/list/list_view.js @@ -1973,22 +1973,8 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList { return filters; } - - static trigger_list_update(data) { - const doctype = data.doctype; - if (!doctype) return; - frappe.provide("frappe.views.trees"); - - // refresh list view - const page_name = frappe.get_route_str(); - const list_view = frappe.views.list_view[page_name]; - list_view && list_view.on_update(data); - } }; -$(document).on("save", (event, doc) => { - frappe.views.ListView.trigger_list_update(doc); -}); frappe.get_list_view = (doctype) => { let route = `List/${doctype}/List`; diff --git a/frappe/public/js/frappe/model/model.js b/frappe/public/js/frappe/model/model.js index ad7a1181f6..4b6ee31b71 100644 --- a/frappe/public/js/frappe/model/model.js +++ b/frappe/public/js/frappe/model/model.js @@ -47,8 +47,6 @@ $.extend(frappe.model, { init: function() { // setup refresh if the document is updated somewhere else frappe.realtime.on("doc_update", function(data) { - // set list dirty - frappe.views.ListView.trigger_list_update(data); var doc = locals[data.doctype] && locals[data.doctype][data.name]; if(doc) { @@ -69,11 +67,6 @@ $.extend(frappe.model, { } } }); - - frappe.realtime.on("list_update", function(data) { - frappe.views.ListView.trigger_list_update(data); - }); - }, is_value_type: function(fieldtype) { diff --git a/frappe/public/js/frappe/views/reports/report_view.js b/frappe/public/js/frappe/views/reports/report_view.js index 2747a2723d..0f32b70b88 100644 --- a/frappe/public/js/frappe/views/reports/report_view.js +++ b/frappe/public/js/frappe/views/reports/report_view.js @@ -48,9 +48,14 @@ frappe.views.ReportView = class ReportView extends frappe.views.ListView { setup_view() { this.setup_columns(); super.setup_new_doc_event(); + this.setup_events() this.page.main.addClass('report-view'); } + setup_events() { + frappe.realtime.on("list_update", (data) => this.on_update(data)); + } + setup_page() { this.menu_items = this.report_menu_items(); super.setup_page(); From d23b293e1e4fb8c66665b2c747a80afb0987c3cb Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Mon, 9 May 2022 19:22:13 +0530 Subject: [PATCH 18/35] fix(webform): Only show published web forms --- frappe/website/page_renderers/web_form.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/website/page_renderers/web_form.py b/frappe/website/page_renderers/web_form.py index 913252c155..1953118790 100644 --- a/frappe/website/page_renderers/web_form.py +++ b/frappe/website/page_renderers/web_form.py @@ -4,7 +4,7 @@ from frappe.website.page_renderers.document_page import DocumentPage class WebFormPage(DocumentPage): def can_render(self): - webform_name = frappe.db.exists("Web Form", {"route": self.path}, cache=True) + webform_name = frappe.db.exists("Web Form", {"route": self.path, "published": 1}, cache=True) if webform_name: self.doctype = "Web Form" self.docname = webform_name From e59e68efbda9a181bcff6273091fe78bada75ab1 Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Mon, 9 May 2022 19:27:18 +0530 Subject: [PATCH 19/35] test: Add a case to cover webform publish functionality --- frappe/tests/test_webform.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/frappe/tests/test_webform.py b/frappe/tests/test_webform.py index 92dc441bdf..d95e4a7498 100644 --- a/frappe/tests/test_webform.py +++ b/frappe/tests/test_webform.py @@ -1,10 +1,27 @@ import unittest import frappe +from frappe.utils import set_request +from frappe.website.serve import get_response from frappe.www.list import get_list_context -class TestWebsite(unittest.TestCase): +class TestWebform(unittest.TestCase): + def test_webform_publish_functionality(self): + edit_profile = frappe.get_doc("Web Form", "edit-profile") + # publish webform + edit_profile.published = True + edit_profile.save() + set_request(method="GET", path="update-profile") + response = get_response() + self.assertEqual(response.status_code, 200) + + # un-publish webform + edit_profile.published = False + edit_profile.save() + response = get_response() + self.assertEqual(response.status_code, 404) + def test_get_context_hook_of_webform(self): create_custom_doctype() create_webform() From 8c768b509fc59864db37098c5e7d12050812e17f Mon Sep 17 00:00:00 2001 From: Steve Date: Tue, 10 May 2022 10:47:51 +1000 Subject: [PATCH 20/35] Update list_view.js Be consistent with other list view settings, max fields allowed is 10 --- frappe/public/js/frappe/list/list_view.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/list/list_view.js b/frappe/public/js/frappe/list/list_view.js index 35e387b8d8..a4b5a59287 100644 --- a/frappe/public/js/frappe/list/list_view.js +++ b/frappe/public/js/frappe/list/list_view.js @@ -385,7 +385,7 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList { if (window.innerWidth <= 1366) { total_fields = 4; } else if (window.innerWidth >= 1920) { - total_fields = 8; + total_fields = 10; } this.columns = this.columns.slice(0, this.list_view_settings.total_fields || total_fields); From 7098f29dfea6d4812dad4be2341b01bfd5d87473 Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Tue, 10 May 2022 13:31:00 +0530 Subject: [PATCH 21/35] fix(dashboard): Consistent "No Data" message in all charts --- frappe/public/js/frappe/widgets/chart_widget.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/widgets/chart_widget.js b/frappe/public/js/frappe/widgets/chart_widget.js index 53e9ecf6bf..b1d82bab08 100644 --- a/frappe/public/js/frappe/widgets/chart_widget.js +++ b/frappe/public/js/frappe/widgets/chart_widget.js @@ -55,7 +55,7 @@ export default class ChartWidget extends Widget { this.empty = $( `
${__( - "No Data..." + "No Data" )}
` ); this.empty.hide().appendTo(this.body); From b618d29296732d096c5d74885a25bc4251981024 Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Tue, 10 May 2022 13:32:40 +0530 Subject: [PATCH 22/35] fix(dashboard): Don't show stats in number widget if NaN --- frappe/public/js/frappe/widgets/number_card_widget.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/frappe/public/js/frappe/widgets/number_card_widget.js b/frappe/public/js/frappe/widgets/number_card_widget.js index 11e567af42..80e69631a2 100644 --- a/frappe/public/js/frappe/widgets/number_card_widget.js +++ b/frappe/public/js/frappe/widgets/number_card_widget.js @@ -255,18 +255,21 @@ export default class NumberCardWidget extends Widget { }; const stats_qualifier = stats_qualifier_map[this.card_doc.stats_time_interval]; - let get_stat = () => { + let stat = (() => { if (this.percentage_stat == undefined) return NaN; const parts = this.percentage_stat.split(' '); const symbol = parts[1] || ''; return Math.abs(parts[0]) + ' ' + symbol; - }; + })(); + + // don't show stats if not valid number - skip showing `NaN %` in card + if (isNaN(stat)) return; $(this.body).find('.widget-content').append(`
${caret_html} - ${get_stat()} % + ${stat} % From d0efa8e3ff734268a30b4804427641d2a5ed643e Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Tue, 10 May 2022 13:33:53 +0530 Subject: [PATCH 23/35] fix: Show site name along with debugging messages Without the site name, the output doesn't really make sense :') --- frappe/utils/scheduler.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/frappe/utils/scheduler.py b/frappe/utils/scheduler.py index 156f2ab04d..6444a2d079 100755 --- a/frappe/utils/scheduler.py +++ b/frappe/utils/scheduler.py @@ -103,11 +103,11 @@ def enqueue_events(site): def is_scheduler_inactive(): if frappe.local.conf.maintenance_mode: - cprint("Maintenance mode is ON") + cprint(f"{frappe.local.site}: Maintenance mode is ON") return True if frappe.local.conf.pause_scheduler: - cprint("frappe.conf.pause_scheduler is SET") + cprint(f"{frappe.local.site}: frappe.conf.pause_scheduler is SET") return True if is_scheduler_disabled(): @@ -118,14 +118,14 @@ def is_scheduler_inactive(): def is_scheduler_disabled(): if frappe.conf.disable_scheduler: - cprint("frappe.conf.disable_scheduler is SET") + cprint(f"{frappe.local.site}: frappe.conf.disable_scheduler is SET") return True scheduler_disabled = not frappe.utils.cint( frappe.db.get_single_value("System Settings", "enable_scheduler") ) if scheduler_disabled: - cprint("SystemSettings.enable_scheduler is UNSET") + cprint(f"{frappe.local.site}: SystemSettings.enable_scheduler is UNSET") return scheduler_disabled From 74d7753a5aca6f57aa8a12fa5637e6cf4aa692eb Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Thu, 28 Apr 2022 19:12:08 +0530 Subject: [PATCH 24/35] refactor: split make_boilerplate function --- frappe/tests/test_boilerplate.py | 131 ++++++++++++++++++++++--------- frappe/utils/boilerplate.py | 47 +++++++---- 2 files changed, 125 insertions(+), 53 deletions(-) diff --git a/frappe/tests/test_boilerplate.py b/frappe/tests/test_boilerplate.py index 4dfb6e615b..8c9f8be683 100644 --- a/frappe/tests/test_boilerplate.py +++ b/frappe/tests/test_boilerplate.py @@ -1,4 +1,5 @@ import ast +import copy import glob import os import shutil @@ -6,33 +7,39 @@ import unittest from unittest.mock import patch import frappe -from frappe.utils.boilerplate import make_boilerplate +from frappe.utils.boilerplate import _create_app_boilerplate, _get_inputs class TestBoilerPlate(unittest.TestCase): @classmethod def setUpClass(cls): - title = "Test App" - description = "This app's description contains 'single quotes' and \"double quotes\"." - publisher = "Test Publisher" - email = "example@example.org" - icon = "" # empty -> default - color = "" - app_license = "MIT" + cls.default_hooks = frappe._dict( + { + "app_name": "test_app", + "app_title": "Test App", + "app_description": "This app's description contains 'single quotes' and \"double quotes\".", + "app_publisher": "Test Publisher", + "app_email": "example@example.org", + "app_icon": "octicon octicon-file-directory", + "app_color": "grey", + "app_license": "MIT", + } + ) - cls.user_input = [ - title, - description, - publisher, - email, - icon, - color, - app_license, - ] + cls.default_user_input = frappe._dict( + { + "title": "Test App", + "description": "This app's description contains 'single quotes' and \"double quotes\".", + "publisher": "Test Publisher", + "email": "example@example.org", + "icon": "", # empty -> default + "color": "", + "app_license": "MIT", + } + ) cls.bench_path = frappe.utils.get_bench_path() cls.apps_dir = os.path.join(cls.bench_path, "apps") - cls.app_names = ("test_app", "test_app_no_git") cls.gitignore_file = ".gitignore" cls.git_folder = ".git" @@ -55,39 +62,91 @@ class TestBoilerPlate(unittest.TestCase): "public", ] + def create_app(self, hooks, no_git=False): + self.addCleanup(self.delete_test_app, hooks.app_name) + _create_app_boilerplate(self.apps_dir, hooks, no_git) + @classmethod - def tearDownClass(cls): - test_app_dirs = (os.path.join(cls.bench_path, "apps", app_name) for app_name in cls.app_names) - for test_app_dir in test_app_dirs: - if os.path.exists(test_app_dir): - shutil.rmtree(test_app_dir) + def delete_test_app(cls, app_name): + test_app_dir = os.path.join(cls.bench_path, "apps", app_name) + if os.path.exists(test_app_dir): + shutil.rmtree(test_app_dir) + + @staticmethod + def get_user_input_stream(inputs): + user_inputs = [] + for value in inputs.values(): + if isinstance(value, list): + user_inputs.extend(value) + else: + user_inputs.append(value) + return user_inputs + + def test_simple_input_to_boilerplate(self): + with patch("builtins.input", side_effect=self.get_user_input_stream(self.default_user_input)): + hooks = _get_inputs(self.default_hooks.app_name) + self.assertDictEqual(hooks, self.default_hooks) + + def test_invalid_inputs(self): + invalid_inputs = copy.deepcopy(self.default_user_input).update( + { + "title": ["1nvalid Title", "valid title"], + } + ) + with patch("builtins.input", side_effect=self.get_user_input_stream(invalid_inputs)): + hooks = _get_inputs(self.default_hooks.app_name) + self.assertEqual(hooks.app_title, "valid title") def test_create_app(self): - with patch("builtins.input", side_effect=self.user_input): - make_boilerplate(self.apps_dir, self.app_names[0]) + app_name = "test_app" - new_app_dir = os.path.join(self.bench_path, self.apps_dir, self.app_names[0]) + hooks = frappe._dict( + { + "app_name": app_name, + "app_title": "Test App", + "app_description": "This app's description contains 'single quotes' and \"double quotes\".", + "app_publisher": "Test Publisher", + "app_email": "example@example.org", + "app_icon": "octicon octicon-file-directory", + "app_color": "grey", + "app_license": "MIT", + } + ) - paths = self.get_paths(new_app_dir, self.app_names[0]) + self.create_app(hooks) + new_app_dir = os.path.join(self.bench_path, self.apps_dir, app_name) + + paths = self.get_paths(new_app_dir, app_name) for path in paths: - self.assertTrue(os.path.exists(path), msg=f"{path} should exist in {self.app_names[0]} app") + self.assertTrue(os.path.exists(path), msg=f"{path} should exist in {app_name} app") self.check_parsable_python_files(new_app_dir) def test_create_app_without_git_init(self): - with patch("builtins.input", side_effect=self.user_input): - make_boilerplate(self.apps_dir, self.app_names[1], no_git=True) + app_name = "test_app_no_git" - new_app_dir = os.path.join(self.apps_dir, self.app_names[1]) + hooks = frappe._dict( + { + "app_name": app_name, + "app_title": "Test App", + "app_description": "This app's description contains 'single quotes' and \"double quotes\".", + "app_publisher": "Test Publisher", + "app_email": "example@example.org", + "app_icon": "octicon octicon-file-directory", + "app_color": "grey", + "app_license": "MIT", + } + ) + self.create_app(hooks, no_git=True) - paths = self.get_paths(new_app_dir, self.app_names[1]) + new_app_dir = os.path.join(self.apps_dir, app_name) + + paths = self.get_paths(new_app_dir, app_name) for path in paths: if os.path.basename(path) in (self.git_folder, self.gitignore_file): - self.assertFalse( - os.path.exists(path), msg=f"{path} shouldn't exist in {self.app_names[1]} app" - ) + self.assertFalse(os.path.exists(path), msg=f"{path} shouldn't exist in {app_name} app") else: - self.assertTrue(os.path.exists(path), msg=f"{path} should exist in {self.app_names[1]} app") + self.assertTrue(os.path.exists(path), msg=f"{path} should exist in {app_name} app") self.check_parsable_python_files(new_app_dir) diff --git a/frappe/utils/boilerplate.py b/frappe/utils/boilerplate.py index f5243ecc95..c2ba3f0eec 100644 --- a/frappe/utils/boilerplate.py +++ b/frappe/utils/boilerplate.py @@ -17,23 +17,32 @@ def make_boilerplate(dest, app_name, no_git=False): # app_name should be in snake_case app_name = frappe.scrub(app_name) + hooks = _get_inputs(app_name) + _create_app_boilerplate(dest, hooks, no_git=no_git) + + +def _get_inputs(app_name): + """Prompt user for various inputs related to new app and return config.""" + app_name = frappe.scrub(app_name) hooks = frappe._dict() hooks.app_name = app_name app_title = hooks.app_name.replace("_", " ").title() - for key in ( - "App Title (default: {0})".format(app_title), - "App Description", - "App Publisher", - "App Email", - "App Icon (default 'octicon octicon-file-directory')", - "App Color (default 'grey')", - "App License (default 'MIT')", - ): - hook_key = key.split(" (")[0].lower().replace(" ", "_") + + NEW_APP_CONFIG = { + "app_title": {"prompt": "App Title (default: {0})".format(app_title)}, + "app_description": {"prompt": "App Description"}, + "app_publisher": {"prompt": "App Publisher"}, + "app_email": {"prompt": "App Email"}, + "app_icon": {"prompt": "App Icon (default 'octicon octicon-file-directory')"}, + "app_color": {"prompt": "App Color (default 'grey')"}, + "app_license": {"prompt": "App License (default 'MIT')"}, + } + + for property, config in NEW_APP_CONFIG.items(): hook_val = None while not hook_val: - hook_val = cstr(input(key + ": ")) + hook_val = cstr(input(config["prompt"] + ": ")) if not hook_val: defaults = { @@ -42,13 +51,13 @@ def make_boilerplate(dest, app_name, no_git=False): "app_color": "grey", "app_license": "MIT", } - if hook_key in defaults: - hook_val = defaults[hook_key] + if property in defaults: + hook_val = defaults[property] - if hook_key == "app_name" and hook_val.lower().replace(" ", "_") != hook_val: + if property == "app_name" and hook_val.lower().replace(" ", "_") != hook_val: print("App Name must be all lowercase and without spaces") hook_val = "" - elif hook_key == "app_title" and not re.match( + elif property == "app_title" and not re.match( r"^(?![\W])[^\d_\s][\w -]+$", hook_val, re.UNICODE ): print( @@ -56,8 +65,12 @@ def make_boilerplate(dest, app_name, no_git=False): ) hook_val = "" - hooks[hook_key] = hook_val + hooks[property] = hook_val + return hooks + + +def _create_app_boilerplate(dest, hooks, no_git=False): frappe.create_folder( os.path.join(dest, hooks.app_name, hooks.app_name, frappe.scrub(hooks.app_title)), with_init=True ) @@ -132,7 +145,7 @@ def make_boilerplate(dest, app_name, no_git=False): app_repo.git.add(A=True) app_repo.index.commit("feat: Initialize App") - print("'{app}' created at {path}".format(app=app_name, path=app_directory)) + print(f"'{hooks.app_name}' created at {app_directory}") manifest_template = """include MANIFEST.in From 53f54c37614a486ace9112936ca0779b633103b7 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Thu, 28 Apr 2022 20:26:29 +0530 Subject: [PATCH 25/35] refactor: use click for new-app prompts --- frappe/tests/test_boilerplate.py | 9 ++--- frappe/utils/boilerplate.py | 61 +++++++++++++++----------------- 2 files changed, 34 insertions(+), 36 deletions(-) diff --git a/frappe/tests/test_boilerplate.py b/frappe/tests/test_boilerplate.py index 8c9f8be683..ef1f0a12dc 100644 --- a/frappe/tests/test_boilerplate.py +++ b/frappe/tests/test_boilerplate.py @@ -4,6 +4,7 @@ import glob import os import shutil import unittest +from io import StringIO from unittest.mock import patch import frappe @@ -80,20 +81,20 @@ class TestBoilerPlate(unittest.TestCase): user_inputs.extend(value) else: user_inputs.append(value) - return user_inputs + return StringIO("\n".join(user_inputs)) def test_simple_input_to_boilerplate(self): - with patch("builtins.input", side_effect=self.get_user_input_stream(self.default_user_input)): + with patch("sys.stdin", self.get_user_input_stream(self.default_user_input)): hooks = _get_inputs(self.default_hooks.app_name) self.assertDictEqual(hooks, self.default_hooks) def test_invalid_inputs(self): - invalid_inputs = copy.deepcopy(self.default_user_input).update( + invalid_inputs = copy.copy(self.default_user_input).update( { "title": ["1nvalid Title", "valid title"], } ) - with patch("builtins.input", side_effect=self.get_user_input_stream(invalid_inputs)): + with patch("sys.stdin", self.get_user_input_stream(invalid_inputs)): hooks = _get_inputs(self.default_hooks.app_name) self.assertEqual(hooks.app_title, "valid title") diff --git a/frappe/utils/boilerplate.py b/frappe/utils/boilerplate.py index c2ba3f0eec..b26aadb9d1 100644 --- a/frappe/utils/boilerplate.py +++ b/frappe/utils/boilerplate.py @@ -4,6 +4,7 @@ import os import re +import click import git import frappe @@ -29,47 +30,43 @@ def _get_inputs(app_name): hooks.app_name = app_name app_title = hooks.app_name.replace("_", " ").title() - NEW_APP_CONFIG = { - "app_title": {"prompt": "App Title (default: {0})".format(app_title)}, + new_app_config = { + "app_title": { + "prompt": "App Title".format(app_title), + "default": app_title, + "validator": is_valid_title, + }, "app_description": {"prompt": "App Description"}, "app_publisher": {"prompt": "App Publisher"}, "app_email": {"prompt": "App Email"}, - "app_icon": {"prompt": "App Icon (default 'octicon octicon-file-directory')"}, - "app_color": {"prompt": "App Color (default 'grey')"}, - "app_license": {"prompt": "App License (default 'MIT')"}, + "app_icon": {"prompt": "App Icon", "default": "octicon octicon-file-directory"}, + "app_color": {"prompt": "App Color", "default": "grey"}, + "app_license": {"prompt": "App License", "default": "MIT"}, } - for property, config in NEW_APP_CONFIG.items(): - hook_val = None - while not hook_val: - hook_val = cstr(input(config["prompt"] + ": ")) - - if not hook_val: - defaults = { - "app_title": app_title, - "app_icon": "octicon octicon-file-directory", - "app_color": "grey", - "app_license": "MIT", - } - if property in defaults: - hook_val = defaults[property] - - if property == "app_name" and hook_val.lower().replace(" ", "_") != hook_val: - print("App Name must be all lowercase and without spaces") - hook_val = "" - elif property == "app_title" and not re.match( - r"^(?![\W])[^\d_\s][\w -]+$", hook_val, re.UNICODE - ): - print( - "App Title should start with a letter and it can only consist of letters, numbers, spaces and underscores" - ) - hook_val = "" - - hooks[property] = hook_val + for property, config in new_app_config.items(): + value = None + while value is None: + value = click.prompt( + config["prompt"], default=config.get("default"), type=config.get("type", str) + ) + if validator_function := config.get("validator"): + if not validator_function(value): + value = None + hooks[property] = value return hooks +def is_valid_title(title) -> bool: + if not re.match(r"^(?![\W])[^\d_\s][\w -]+$", title, re.UNICODE): + print( + "App Title should start with a letter and it can only consist of letters, numbers, spaces and underscores" + ) + return False + return True + + def _create_app_boilerplate(dest, hooks, no_git=False): frappe.create_folder( os.path.join(dest, hooks.app_name, hooks.app_name, frappe.scrub(hooks.app_title)), with_init=True From 3fd4759dd4bee6e497c5830256944533c1243c11 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Fri, 29 Apr 2022 17:15:40 +0530 Subject: [PATCH 26/35] fix: gitignore node_modules in new frappe apps --- frappe/utils/boilerplate.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frappe/utils/boilerplate.py b/frappe/utils/boilerplate.py index b26aadb9d1..b5e49aa6b6 100644 --- a/frappe/utils/boilerplate.py +++ b/frappe/utils/boilerplate.py @@ -408,7 +408,8 @@ gitignore_template = """.DS_Store *.egg-info *.swp tags -{app_name}/docs/current""" +{app_name}/docs/current +node_modules/""" docs_template = '''""" Configuration for docs From 42942f36a6d088ca97412b614a53843876cccb1f Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Fri, 29 Apr 2022 17:12:59 +0530 Subject: [PATCH 27/35] feat: provide github workflow for unittest in new app --- frappe/tests/test_boilerplate.py | 17 +++- frappe/utils/boilerplate.py | 129 +++++++++++++++++++++++++++++-- 2 files changed, 136 insertions(+), 10 deletions(-) diff --git a/frappe/tests/test_boilerplate.py b/frappe/tests/test_boilerplate.py index ef1f0a12dc..e4b8c680a9 100644 --- a/frappe/tests/test_boilerplate.py +++ b/frappe/tests/test_boilerplate.py @@ -7,8 +7,14 @@ import unittest from io import StringIO from unittest.mock import patch +import yaml + import frappe -from frappe.utils.boilerplate import _create_app_boilerplate, _get_inputs +from frappe.utils.boilerplate import ( + _create_app_boilerplate, + _get_user_inputs, + github_workflow_template, +) class TestBoilerPlate(unittest.TestCase): @@ -24,6 +30,7 @@ class TestBoilerPlate(unittest.TestCase): "app_icon": "octicon octicon-file-directory", "app_color": "grey", "app_license": "MIT", + "create_github_workflow": False, } ) @@ -36,6 +43,7 @@ class TestBoilerPlate(unittest.TestCase): "icon": "", # empty -> default "color": "", "app_license": "MIT", + "github_workflow": "n", } ) @@ -85,7 +93,7 @@ class TestBoilerPlate(unittest.TestCase): def test_simple_input_to_boilerplate(self): with patch("sys.stdin", self.get_user_input_stream(self.default_user_input)): - hooks = _get_inputs(self.default_hooks.app_name) + hooks = _get_user_inputs(self.default_hooks.app_name) self.assertDictEqual(hooks, self.default_hooks) def test_invalid_inputs(self): @@ -95,9 +103,12 @@ class TestBoilerPlate(unittest.TestCase): } ) with patch("sys.stdin", self.get_user_input_stream(invalid_inputs)): - hooks = _get_inputs(self.default_hooks.app_name) + hooks = _get_user_inputs(self.default_hooks.app_name) self.assertEqual(hooks.app_title, "valid title") + def test_valid_ci_yaml(self): + yaml.safe_load(github_workflow_template.format(**self.default_hooks)) + def test_create_app(self): app_name = "test_app" diff --git a/frappe/utils/boilerplate.py b/frappe/utils/boilerplate.py index b5e49aa6b6..12119037e0 100644 --- a/frappe/utils/boilerplate.py +++ b/frappe/utils/boilerplate.py @@ -2,13 +2,14 @@ # License: MIT. See LICENSE import os +import pathlib import re import click import git import frappe -from frappe.utils import cstr, touch_file +from frappe.utils import touch_file def make_boilerplate(dest, app_name, no_git=False): @@ -18,11 +19,11 @@ def make_boilerplate(dest, app_name, no_git=False): # app_name should be in snake_case app_name = frappe.scrub(app_name) - hooks = _get_inputs(app_name) + hooks = _get_user_inputs(app_name) _create_app_boilerplate(dest, hooks, no_git=no_git) -def _get_inputs(app_name): +def _get_user_inputs(app_name): """Prompt user for various inputs related to new app and return config.""" app_name = frappe.scrub(app_name) @@ -32,7 +33,7 @@ def _get_inputs(app_name): new_app_config = { "app_title": { - "prompt": "App Title".format(app_title), + "prompt": "App Title", "default": app_title, "validator": is_valid_title, }, @@ -42,14 +43,23 @@ def _get_inputs(app_name): "app_icon": {"prompt": "App Icon", "default": "octicon octicon-file-directory"}, "app_color": {"prompt": "App Color", "default": "grey"}, "app_license": {"prompt": "App License", "default": "MIT"}, + "create_github_workflow": { + "prompt": "Create GitHub Workflow action for unittests", + "default": False, + "type": bool, + }, } for property, config in new_app_config.items(): value = None + input_type = config.get("type", str) + while value is None: - value = click.prompt( - config["prompt"], default=config.get("default"), type=config.get("type", str) - ) + if input_type == bool: + value = click.confirm(config["prompt"], default=config.get("default")) + else: + value = click.prompt(config["prompt"], default=config.get("default"), type=input_type) + if validator_function := config.get("validator"): if not validator_function(value): value = None @@ -133,6 +143,9 @@ def _create_app_boilerplate(dest, hooks, no_git=False): app_directory = os.path.join(dest, hooks.app_name) + if hooks.create_github_workflow: + _create_github_workflow_files(dest, hooks) + if not no_git: with open(os.path.join(dest, hooks.app_name, ".gitignore"), "w") as f: f.write(frappe.as_unicode(gitignore_template.format(app_name=hooks.app_name))) @@ -145,6 +158,15 @@ def _create_app_boilerplate(dest, hooks, no_git=False): print(f"'{hooks.app_name}' created at {app_directory}") +def _create_github_workflow_files(dest, hooks): + workflows_path = pathlib.Path(dest) / hooks.app_name / ".github" / "workflows" + workflows_path.mkdir(parents=True, exist_ok=True) + + ci_workflow = workflows_path / "ci.yml" + with open(ci_workflow, "w") as f: + f.write(github_workflow_template.format(**hooks)) + + manifest_template = """include MANIFEST.in include requirements.txt include *.json @@ -422,3 +444,96 @@ Configuration for docs def get_context(context): context.brand_html = "{app_title}" ''' + + +github_workflow_template = """ +name: CI + +on: + push: + branches: + - develop + pull_request: + +concurrency: + group: develop-{app_name}-${{{{ github.event.number }}}} + cancel-in-progress: true + +jobs: + tests: + runs-on: ubuntu-latest + strategy: + fail-fast: false + name: Server + + services: + mariadb: + image: mariadb:10.3 + env: + MYSQL_ROOT_PASSWORD: root + ports: + - 3306:3306 + options: --health-cmd="mysqladmin ping" --health-interval=5s --health-timeout=2s --health-retries=3 + + steps: + - name: Clone + uses: actions/checkout@v2 + + - name: Setup Python + uses: actions/setup-python@v2 + with: + python-version: 3.9 + + - name: Setup Node + uses: actions/setup-node@v2 + with: + node-version: 14 + check-latest: true + + - name: Cache pip + uses: actions/cache@v2 + with: + path: ~/.cache/pip + key: ${{{{ runner.os }}}}-pip-${{{{ hashFiles('**/*requirements.txt') }}}} + restore-keys: | + ${{{{ runner.os }}}}-pip- + ${{{{ runner.os }}}}- + + - name: Get yarn cache directory path + id: yarn-cache-dir-path + run: 'echo "::set-output name=dir::$(yarn cache dir)"' + + - uses: actions/cache@v2 + id: yarn-cache + with: + path: ${{{{ steps.yarn-cache-dir-path.outputs.dir }}}} + key: ${{{{ runner.os }}}}-yarn-${{{{ hashFiles('**/yarn.lock') }}}} + restore-keys: | + ${{{{ runner.os }}}}-yarn- + + - name: Setup + run: | + pip install frappe-bench + bench init --skip-redis-config-generation --skip-assets --python "$(which python)" ~/frappe-bench + mysql --host 127.0.0.1 --port 3306 -u root -proot -e "SET GLOBAL character_set_server = 'utf8mb4'" + mysql --host 127.0.0.1 --port 3306 -u root -proot -e "SET GLOBAL collation_server = 'utf8mb4_unicode_ci'" + + - name: Install + working-directory: /home/runner/frappe-bench + run: | + bench get-app {app_name} $GITHUB_WORKSPACE + bench setup requirements --dev + bench new-site --db-root-password root --admin-password admin test_site + bench --site test_site install-app {app_name} + bench build + env: + CI: 'Yes' + + - name: Run Tests + working-directory: /home/runner/frappe-bench + run: | + bench --site test_site set-config allow_tests true + bench --site test_site run-tests --app {app_name} + env: + TYPE: server +""" From 665f871c09bc623a7fc91354c04f0ea61a42f4b3 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Sun, 1 May 2022 21:04:28 +0530 Subject: [PATCH 28/35] test: delete duplicate test --- frappe/tests/test_commands.py | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/frappe/tests/test_commands.py b/frappe/tests/test_commands.py index 67de6c6e41..d4a86bd111 100644 --- a/frappe/tests/test_commands.py +++ b/frappe/tests/test_commands.py @@ -413,26 +413,6 @@ class TestCommands(BaseTestCommands): self.assertEqual(self.returncode, 0) self.assertEqual(check_password("Administrator", "test2"), "Administrator") - def test_make_app(self): - user_input = [ - b"Test App", # title - b"This app's description contains 'single quotes' and \"double quotes\".", # description - b"Test Publisher", # publisher - b"example@example.org", # email - b"", # icon - b"", # color - b"MIT", # app_license - ] - app_name = "testapp0" - apps_path = os.path.join(get_bench_path(), "apps") - test_app_path = os.path.join(apps_path, app_name) - self.execute(f"bench make-app {apps_path} {app_name}", {"cmd_input": b"\n".join(user_input)}) - self.assertEqual(self.returncode, 0) - self.assertTrue(os.path.exists(test_app_path)) - - # cleanup - shutil.rmtree(test_app_path) - @skipIf( not ( frappe.conf.root_password and frappe.conf.admin_password and frappe.conf.db_type == "mariadb" From 8a1889301a85d74fa88f9fbb8f6f8d4e42069b6b Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Mon, 2 May 2022 11:27:05 +0530 Subject: [PATCH 29/35] chore!: remove dead hooks `app_icon` & `app_color` --- frappe/hooks.py | 2 -- frappe/tests/test_boilerplate.py | 6 ------ frappe/utils/boilerplate.py | 6 ------ hooks.md | 2 -- 4 files changed, 16 deletions(-) diff --git a/frappe/hooks.py b/frappe/hooks.py index f7a67dc7ec..ee8417a3ec 100644 --- a/frappe/hooks.py +++ b/frappe/hooks.py @@ -4,8 +4,6 @@ app_name = "frappe" app_title = "Frappe Framework" app_publisher = "Frappe Technologies" app_description = "Full stack web framework with Python, Javascript, MariaDB, Redis, Node" -app_icon = "octicon octicon-circuit-board" -app_color = "orange" source_link = "https://github.com/frappe/frappe" app_license = "MIT" app_logo_url = "/assets/frappe/images/frappe-framework-logo.svg" diff --git a/frappe/tests/test_boilerplate.py b/frappe/tests/test_boilerplate.py index e4b8c680a9..092a1ff126 100644 --- a/frappe/tests/test_boilerplate.py +++ b/frappe/tests/test_boilerplate.py @@ -27,8 +27,6 @@ class TestBoilerPlate(unittest.TestCase): "app_description": "This app's description contains 'single quotes' and \"double quotes\".", "app_publisher": "Test Publisher", "app_email": "example@example.org", - "app_icon": "octicon octicon-file-directory", - "app_color": "grey", "app_license": "MIT", "create_github_workflow": False, } @@ -119,8 +117,6 @@ class TestBoilerPlate(unittest.TestCase): "app_description": "This app's description contains 'single quotes' and \"double quotes\".", "app_publisher": "Test Publisher", "app_email": "example@example.org", - "app_icon": "octicon octicon-file-directory", - "app_color": "grey", "app_license": "MIT", } ) @@ -144,8 +140,6 @@ class TestBoilerPlate(unittest.TestCase): "app_description": "This app's description contains 'single quotes' and \"double quotes\".", "app_publisher": "Test Publisher", "app_email": "example@example.org", - "app_icon": "octicon octicon-file-directory", - "app_color": "grey", "app_license": "MIT", } ) diff --git a/frappe/utils/boilerplate.py b/frappe/utils/boilerplate.py index 12119037e0..22ca64eb1a 100644 --- a/frappe/utils/boilerplate.py +++ b/frappe/utils/boilerplate.py @@ -40,8 +40,6 @@ def _get_user_inputs(app_name): "app_description": {"prompt": "App Description"}, "app_publisher": {"prompt": "App Publisher"}, "app_email": {"prompt": "App Email"}, - "app_icon": {"prompt": "App Icon", "default": "octicon octicon-file-directory"}, - "app_color": {"prompt": "App Color", "default": "grey"}, "app_license": {"prompt": "App License", "default": "MIT"}, "create_github_workflow": { "prompt": "Create GitHub Workflow action for unittests", @@ -197,8 +195,6 @@ app_name = "{app_name}" app_title = "{app_title}" app_publisher = "{app_publisher}" app_description = "{app_description}" -app_icon = "{app_icon}" -app_color = "{app_color}" app_email = "{app_email}" app_license = "{app_license}" @@ -396,8 +392,6 @@ def get_data(): return [ {{ "module_name": "{app_title}", - "color": "{app_color}", - "icon": "{app_icon}", "type": "module", "label": _("{app_title}") }} diff --git a/hooks.md b/hooks.md index 5ff70471c9..efb58f2645 100644 --- a/hooks.md +++ b/hooks.md @@ -7,8 +7,6 @@ 1. `app_publisher` 1. `app_description` 1. `app_version` -1. `app_icon` - font-awesome icon or image url -1. `app_color` - hex colour background of the app icon #### Install From c16bec3407328ae14e07d1e1c5f8f3419849bda6 Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Tue, 10 May 2022 15:00:52 +0530 Subject: [PATCH 30/35] chore: Simplify get_open_count doc usage --- frappe/desk/notifications.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/frappe/desk/notifications.py b/frappe/desk/notifications.py index e92a7492ce..2a987f5539 100644 --- a/frappe/desk/notifications.py +++ b/frappe/desk/notifications.py @@ -249,9 +249,9 @@ def get_open_count(doctype, name, items=None): if frappe.flags.in_migrate or frappe.flags.in_install: return {"count": []} - frappe.has_permission(doc=frappe.get_doc(doctype, name), throw=True) - - meta = frappe.get_meta(doctype) + doc = frappe.get_doc(doctype, name) + doc.check_permission() + meta = doc.meta links = meta.get_dashboard_data() # compile all items in a list @@ -266,7 +266,6 @@ def get_open_count(doctype, name, items=None): out = [] for d in items: if d in links.get("internal_links", {}): - # internal link continue filters = get_filters_for(d) From 66ccd103ed1504c31da29a8bdb691d7268702835 Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Tue, 10 May 2022 15:03:18 +0530 Subject: [PATCH 31/35] fix: Fetch meta to ensure formatting for Dashboard Charts * This handles setting meta for dashboard chart of types: Sum, Count, Average, Group By * Dhashboard Charts of type Report have to pass fieldtype in chart data Dict to apply formatting. This can't be done magically AFAIK --- .../public/js/frappe/widgets/chart_widget.js | 53 ++++++++++++++----- 1 file changed, 39 insertions(+), 14 deletions(-) diff --git a/frappe/public/js/frappe/widgets/chart_widget.js b/frappe/public/js/frappe/widgets/chart_widget.js index b1d82bab08..2a51020c38 100644 --- a/frappe/public/js/frappe/widgets/chart_widget.js +++ b/frappe/public/js/frappe/widgets/chart_widget.js @@ -529,7 +529,26 @@ export default class ChartWidget extends Widget { return frappe.xcall(method, args); } - render() { + async get_source_doctype() { + if (this.chart_doc.document_type) { + return this.chart_doc.document_type; + } + if (this.chart_doc.chart_type == "Report" && this.chart_doc.report_name) { + return await frappe.db.get_value("Report", this.chart_doc.report_name, "ref_doctype").then(r => r.message.ref_doctype); + } + } + + async render() { + let setup_dashboard_chart = () => { + const chart_args = this.get_chart_args(); + + if (!this.dashboard_chart) { + this.dashboard_chart = frappe.utils.make_chart(this.chart_wrapper[0], chart_args); + } else { + this.dashboard_chart.update(this.data); + } + } + if (!this.data || !this.data.labels || !Object.keys(this.data).length) { this.chart_wrapper.hide(); this.loading.hide(); @@ -539,13 +558,12 @@ export default class ChartWidget extends Widget { this.loading.hide(); this.empty.hide(); this.chart_wrapper.show(); + this.chart_doc.document_type = await this.get_source_doctype(); - const chart_args = this.get_chart_args(); - - if (!this.dashboard_chart) { - this.dashboard_chart = frappe.utils.make_chart(this.chart_wrapper[0], chart_args); + if (this.chart_doc.document_type) { + frappe.model.with_doctype(this.chart_doc.document_type, setup_dashboard_chart); } else { - this.dashboard_chart.update(this.data); + setup_dashboard_chart(); } this.width == "Full" && this.summary && this.set_summary(); @@ -555,6 +573,7 @@ export default class ChartWidget extends Widget { get_chart_args() { let colors = this.get_chart_colors(); + let fieldtype, options; const chart_type_map = { Line: "line", @@ -577,16 +596,22 @@ export default class ChartWidget extends Widget { }, }; - if (this.report_result && this.report_result.chart) { - chart_args.tooltipOptions = { - formatTooltipY: value => - frappe.format(value, { - fieldtype: this.report_result.chart.fieldtype, - options: this.report_result.chart.options - }, { always_show_decimals: true, inline: true }) - }; + if (this.chart_doc.document_type) { + let doctype_meta = frappe.get_meta(this.chart_doc.document_type); + let field = doctype_meta.fields.find(x => x.fieldname == this.chart_doc.value_based_on); + fieldtype = field.fieldtype; + options = field.options; } + if (this.chart_doc.chart_type == "Report" && this.report_result?.chart?.fieldtype) { + fieldtype = this.report_result.chart.fieldtype; + options = this.report_result.chart.options; + } + + chart_args.tooltipOptions = { + formatTooltipY: value => frappe.format(value, { fieldtype, options }, { always_show_decimals: true, inline: true }) + }; + if (this.chart_doc.type == "Heatmap") { const heatmap_year = parseInt(this.selected_heatmap_year || this.chart_settings.heatmap_year || this.chart_doc.heatmap_year); chart_args.data.start = new Date(`${heatmap_year}-01-01`); From 5ac729252f3319dec35608be5c39c305afdf02f5 Mon Sep 17 00:00:00 2001 From: Himanshu Date: Tue, 10 May 2022 15:11:11 +0100 Subject: [PATCH 32/35] fix: change ordering to creation (#16863) --- frappe/contacts/address_and_contact.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/contacts/address_and_contact.py b/frappe/contacts/address_and_contact.py index 1eb9f1cf33..036594926e 100644 --- a/frappe/contacts/address_and_contact.py +++ b/frappe/contacts/address_and_contact.py @@ -17,7 +17,7 @@ def load_address_and_contact(doc, key=None): ["Dynamic Link", "link_name", "=", doc.name], ["Dynamic Link", "parenttype", "=", "Address"], ] - address_list = frappe.get_list("Address", filters=filters, fields=["*"]) + address_list = frappe.get_list("Address", filters=filters, fields=["*"], order_by="creation asc") address_list = [a.update({"display": get_address_display(a)}) for a in address_list] From c55c8e4f970d6364065f721043e912f61a9a5578 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Wed, 11 May 2022 11:44:31 +0530 Subject: [PATCH 33/35] refactor(DX): add type hints for some utilities (#16871) - Added type hints to majority of most used functions in `utils/data.py` - added overloads for functions whose output depends on input type. This helps A LOT if your LSP supports type narrowing (like pyright) Example: Same function with 3 diff singatures narrowed by input value. Screenshot 2022-05-10 at 8 02 02 PM --- frappe/__init__.py | 4 +- frappe/utils/data.py | 250 +++++++++++++++++++++++++++++++------------ 2 files changed, 182 insertions(+), 72 deletions(-) diff --git a/frappe/__init__.py b/frappe/__init__.py index 46313e9ee9..eb5ecdf99b 100644 --- a/frappe/__init__.py +++ b/frappe/__init__.py @@ -25,7 +25,7 @@ import importlib import inspect import json import sys -from typing import TYPE_CHECKING, Dict, List, Union +from typing import TYPE_CHECKING, Dict, List, Optional, Union import click from werkzeug.local import Local, release_local @@ -973,7 +973,7 @@ def get_precision(doctype, fieldname, currency=None, doc=None): return get_field_precision(get_meta(doctype).get_field(fieldname), doc, currency) -def generate_hash(txt=None, length=None): +def generate_hash(txt: Optional[str] = None, length: Optional[int] = None) -> str: """Generates random hash for given text + current timestamp + random string.""" import hashlib import time diff --git a/frappe/utils/data.py b/frappe/utils/data.py index 05ae7034eb..f63d603da3 100644 --- a/frappe/utils/data.py +++ b/frappe/utils/data.py @@ -8,9 +8,10 @@ import math import operator import re import time +import typing from code import compile_command from enum import Enum -from typing import Any, Dict, List, Optional, Tuple, Union +from typing import Any, Dict, List, Literal, Optional, Tuple, TypeVar, Union from urllib.parse import quote, urljoin from click import secho @@ -18,6 +19,14 @@ from click import secho import frappe from frappe.desk.utils import slug +DateTimeLikeObject = Union[str, datetime.date, datetime.datetime] +NumericType = Union[int, float] + + +if typing.TYPE_CHECKING: + T = TypeVar("T") + + DATE_FORMAT = "%Y-%m-%d" TIME_FORMAT = "%H:%M:%S.%f" DATETIME_FORMAT = DATE_FORMAT + " " + TIME_FORMAT @@ -33,23 +42,22 @@ class Weekday(Enum): Saturday = 6 -def get_first_day_of_the_week(): +def get_first_day_of_the_week() -> str: return frappe.get_system_settings("first_day_of_the_week") or "Sunday" -def get_start_of_week_index(): +def get_start_of_week_index() -> int: return Weekday[get_first_day_of_the_week()].value -def is_invalid_date_string(date_string): +def is_invalid_date_string(date_string: str) -> bool: # dateutil parser does not agree with dates like "0001-01-01" or "0000-00-00" return not isinstance(date_string, str) or ( (not date_string) or (date_string or "").startswith(("0001-01-01", "0000-00-00")) ) -# datetime functions -def getdate(string_date: Optional[str] = None): +def getdate(string_date: Optional["DateTimeLikeObject"] = None) -> Optional[datetime.date]: """ Converts string date (yyyy-mm-dd) to datetime.date object. If no input is provided, current date is returned. @@ -76,7 +84,9 @@ def getdate(string_date: Optional[str] = None): ) -def get_datetime(datetime_str=None): +def get_datetime( + datetime_str: Optional["DateTimeLikeObject"] = None, +) -> Optional[datetime.datetime]: from dateutil import parser if datetime_str is None: @@ -132,7 +142,7 @@ def get_timedelta(time: Optional[str] = None) -> Optional[datetime.timedelta]: return None -def to_timedelta(time_str): +def to_timedelta(time_str: Union[str, datetime.time]) -> datetime.timedelta: from dateutil import parser if isinstance(time_str, datetime.time): @@ -148,6 +158,7 @@ def to_timedelta(time_str): return time_str +@typing.overload def add_to_date( date, years=0, @@ -157,9 +168,56 @@ def add_to_date( hours=0, minutes=0, seconds=0, + as_string: Literal[False] = False, + as_datetime: Literal[False] = False, +) -> datetime.date: + ... + + +@typing.overload +def add_to_date( + date, + years=0, + months=0, + weeks=0, + days=0, + hours=0, + minutes=0, + seconds=0, + as_string: Literal[False] = False, + as_datetime: Literal[True] = True, +) -> datetime.datetime: + ... + + +@typing.overload +def add_to_date( + date, + years=0, + months=0, + weeks=0, + days=0, + hours=0, + minutes=0, + seconds=0, + as_string: Literal[True] = True, + as_datetime: bool = False, +) -> str: + ... + + +def add_to_date( + date: DateTimeLikeObject, + years=0, + months=0, + weeks=0, + days=0, + hours=0, + minutes=0, + seconds=0, as_string=False, as_datetime=False, -): +) -> DateTimeLikeObject: """Adds `days` to the given date""" from dateutil import parser from dateutil.parser._parser import ParserError @@ -272,7 +330,7 @@ def convert_utc_to_user_timezone(utc_timestamp): return convert_utc_to_timezone(utc_timestamp, time_zone) -def now(): +def now() -> str: """return current datetime as yyyy-mm-dd hh:mm:ss""" if frappe.flags.current_date: return ( @@ -284,16 +342,16 @@ def now(): return now_datetime().strftime(DATETIME_FORMAT) -def nowdate(): +def nowdate() -> str: """return current date as yyyy-mm-dd""" return now_datetime().strftime(DATE_FORMAT) -def today(): +def today() -> str: return nowdate() -def get_abbr(string, max_len=2): +def get_abbr(string: str, max_len: int = 2) -> str: abbr = "" for part in string.split(" "): if len(abbr) < max_len and part: @@ -302,12 +360,25 @@ def get_abbr(string, max_len=2): return abbr or "?" -def nowtime(): +def nowtime() -> str: """return current time in hh:mm""" return now_datetime().strftime(TIME_FORMAT) -def get_first_day(dt, d_years=0, d_months=0, as_str=False): +@typing.overload +def get_first_day(dt, d_years=0, d_months=0, as_str: Literal[False] = False) -> datetime.date: + ... + + +@typing.overload +def get_first_day(dt, d_years=0, d_months=0, as_str: Literal[True] = False) -> str: + ... + + +# TODO: first arg +def get_first_day( + dt, d_years: int = 0, d_months: int = 0, as_str: bool = False +) -> Union[str, datetime.date]: """ Returns the first day of the month for the date specified by date object Also adds `d_years` and `d_months` if specified @@ -325,7 +396,17 @@ def get_first_day(dt, d_years=0, d_months=0, as_str=False): ) -def get_quarter_start(dt, as_str=False): +@typing.overload +def get_quarter_start(dt, as_str: Literal[False] = False) -> datetime.date: + ... + + +@typing.overload +def get_quarter_start(dt, as_str: Literal[True] = False) -> str: + ... + + +def get_quarter_start(dt, as_str: bool = False) -> Union[str, datetime.date]: date = getdate(dt) quarter = (date.month - 1) // 3 + 1 first_date_of_quarter = datetime.date(date.year, ((quarter - 1) * 3) + 1, 1) @@ -414,19 +495,19 @@ def get_time(time_str: str) -> datetime.time: raise e -def get_datetime_str(datetime_obj): +def get_datetime_str(datetime_obj) -> str: if isinstance(datetime_obj, str): datetime_obj = get_datetime(datetime_obj) return datetime_obj.strftime(DATETIME_FORMAT) -def get_date_str(date_obj): +def get_date_str(date_obj) -> str: if isinstance(date_obj, str): date_obj = get_datetime(date_obj) return date_obj.strftime(DATE_FORMAT) -def get_time_str(timedelta_obj): +def get_time_str(timedelta_obj) -> str: if isinstance(timedelta_obj, str): timedelta_obj = to_timedelta(timedelta_obj) @@ -435,7 +516,7 @@ def get_time_str(timedelta_obj): return "{0}:{1}:{2}".format(hours, minutes, seconds) -def get_user_date_format(): +def get_user_date_format() -> str: """Get the current user date format. The result will be cached.""" if getattr(frappe.local, "user_date_format", None) is None: frappe.local.user_date_format = frappe.db.get_default("date_format") @@ -446,7 +527,7 @@ def get_user_date_format(): get_user_format = get_user_date_format # for backwards compatibility -def get_user_time_format(): +def get_user_time_format() -> str: """Get the current user time format. The result will be cached.""" if getattr(frappe.local, "user_time_format", None) is None: frappe.local.user_time_format = frappe.db.get_default("time_format") @@ -454,7 +535,7 @@ def get_user_time_format(): return frappe.local.user_time_format or "HH:mm:ss" -def format_date(string_date=None, format_string=None): +def format_date(string_date=None, format_string: Optional[str] = None) -> str: """Converts the given string date to :data:`user_date_format` User format specified in defaults @@ -487,7 +568,7 @@ def format_date(string_date=None, format_string=None): formatdate = format_date # For backwards compatibility -def format_time(time_string=None, format_string=None): +def format_time(time_string=None, format_string: Optional[str] = None) -> str: """Converts the given string time to :data:`user_time_format` User format specified in defaults @@ -514,7 +595,9 @@ def format_time(time_string=None, format_string=None): return formatted_time -def format_datetime(datetime_string, format_string=None): +def format_datetime( + datetime_string: DateTimeLikeObject, format_string: Optional[str] = None +) -> str: """Converts the given string time to :data:`user_datetime_format` User format specified in defaults @@ -624,7 +707,7 @@ def get_weekdays(): return ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"] -def get_weekday(datetime=None): +def get_weekday(datetime: Optional[datetime.datetime] = None) -> str: if not datetime: datetime = now_datetime() weekdays = get_weekdays() @@ -698,7 +781,7 @@ def global_date_format(date, format="long"): return formatted_date -def has_common(l1, l2): +def has_common(l1: typing.Hashable, l2: typing.Hashable) -> bool: """Returns truthy value if there are common elements in lists l1 and l2""" return set(l1) & set(l2) @@ -790,7 +873,17 @@ def cast(fieldtype, value=None): return value -def flt(s, precision=None): +@typing.overload +def flt(s: Union[NumericType, str], precision: Literal[0] = None) -> int: + ... + + +@typing.overload +def flt(s: Union[NumericType, str], precision: Optional[int] = None) -> float: + ... + + +def flt(s: Union[NumericType, str], precision: Optional[int] = None) -> float: """Convert to float (ignoring commas in string) :param s: Number in string or other numeric format. @@ -823,7 +916,7 @@ def flt(s, precision=None): return num -def cint(s, default=0): +def cint(s: Union[NumericType, str], default: int = 0) -> int: """Convert to integer :param s: Number in string or other numeric format. @@ -938,7 +1031,7 @@ def rounded(num, precision=0): return (num / multiplier) if precision else num -def remainder(numerator, denominator, precision=2): +def remainder(numerator: NumericType, denominator: NumericType, precision: int = 2) -> NumericType: precision = cint(precision) multiplier = 10**precision @@ -950,7 +1043,7 @@ def remainder(numerator, denominator, precision=2): return flt(_remainder, precision) -def safe_div(numerator, denominator, precision=2): +def safe_div(numerator: NumericType, denominator: NumericType, precision: int = 2) -> float: """ SafeMath division that returns zero when divided by zero. """ @@ -1007,7 +1100,12 @@ def parse_val(v): return v -def fmt_money(amount, precision=None, currency=None, format=None): +def fmt_money( + amount: Union[str, float, int], + precision: Optional[int] = None, + currency: Optional[str] = None, + format: Optional[str] = None, +) -> str: """ Convert to string with commas for thousands, millions etc """ @@ -1104,7 +1202,9 @@ def get_number_format_info(format: str) -> Tuple[str, str, int]: # convert currency to words # def money_in_words( - number: str, main_currency: Optional[str] = None, fraction_currency: Optional[str] = None + number: Union[str, float, int], + main_currency: Optional[str] = None, + fraction_currency: Optional[str] = None, ): """ Returns string in words with currency and fraction currency. @@ -1177,7 +1277,7 @@ def money_in_words( # # convert number to words # -def in_words(integer, in_million=True): +def in_words(integer: int, in_million=True) -> str: """ Returns string in words for the given integer. """ @@ -1194,13 +1294,13 @@ def in_words(integer, in_million=True): return ret.replace("-", " ") -def is_html(text): +def is_html(text: str) -> bool: if not isinstance(text, str): return False return re.search("<[^>]+>", text) -def is_image(filepath): +def is_image(filepath: str) -> bool: from mimetypes import guess_type # filepath can be https://example.com/bed.jpg?v=129 @@ -1249,7 +1349,7 @@ def get_thumbnail_base64_for_image(src): return cache().hget("thumbnail_base64", src, generator=_get_base64) -def image_to_base64(image, extn): +def image_to_base64(image, extn: str) -> bytes: from io import BytesIO buffered = BytesIO() @@ -1260,7 +1360,7 @@ def image_to_base64(image, extn): return img_str -def pdf_to_base64(filename): +def pdf_to_base64(filename: str) -> Optional[bytes]: from frappe.utils.file_manager import get_file_path if "../" in filename or filename.rsplit(".")[-1] not in ["pdf", "PDF"]: @@ -1280,12 +1380,12 @@ def pdf_to_base64(filename): _striptags_re = re.compile(r"(|<[^>]*>)") -def strip_html(text): +def strip_html(text: str) -> str: """removes anything enclosed in and including <>""" return _striptags_re.sub("", text) -def escape_html(text): +def escape_html(text: str) -> str: if not isinstance(text, str): return text @@ -1300,7 +1400,7 @@ def escape_html(text): return "".join(html_escape_table.get(c, c) for c in text) -def pretty_date(iso_datetime): +def pretty_date(iso_datetime: Union[datetime.datetime, str]) -> str: """ Takes an ISO time and returns a string representing how long ago the date represents. @@ -1391,12 +1491,12 @@ def new_line_sep(some_list): return some_list -def filter_strip_join(some_list, sep): +def filter_strip_join(some_list: List[str], sep: str) -> List[str]: """given a list, filter None values, strip spaces and join""" return (cstr(sep)).join((cstr(a).strip() for a in filter(None, some_list))) -def get_url(uri=None, full_address=False): +def get_url(uri: Optional[str] = None, full_address: bool = False) -> str: """get app url from request""" host_name = frappe.local.conf.host_name or frappe.local.conf.hostname @@ -1453,7 +1553,7 @@ def get_url(uri=None, full_address=False): return url -def get_host_name_from_request(): +def get_host_name_from_request() -> str: if hasattr(frappe.local, "request") and frappe.local.request and frappe.local.request.host: protocol = ( "https://" if "https" == frappe.get_request_header("X-Forwarded-Proto", "") else "http://" @@ -1461,23 +1561,29 @@ def get_host_name_from_request(): return protocol + frappe.local.request.host -def url_contains_port(url): +def url_contains_port(url: str) -> bool: parts = url.split(":") return len(parts) > 2 -def get_host_name(): +def get_host_name() -> str: return get_url().rsplit("//", 1)[-1] -def get_link_to_form(doctype, name, label=None): +def get_link_to_form(doctype: str, name: str, label: Optional[str] = None) -> str: if not label: label = name return """{1}""".format(get_url_to_form(doctype, name), label) -def get_link_to_report(name, label=None, report_type=None, doctype=None, filters=None): +def get_link_to_report( + name: str, + label: Optional[str] = None, + report_type: Optional[str] = None, + doctype: Optional[str] = None, + filters: Optional[Dict] = None, +) -> str: if not label: label = name @@ -1501,19 +1607,21 @@ def get_link_to_report(name, label=None, report_type=None, doctype=None, filters return """{1}""".format(get_url_to_report(name, report_type, doctype), label) -def get_absolute_url(doctype, name): +def get_absolute_url(doctype: str, name: str) -> str: return "/app/{0}/{1}".format(quoted(slug(doctype)), quoted(name)) -def get_url_to_form(doctype, name): +def get_url_to_form(doctype: str, name: str) -> str: return get_url(uri="/app/{0}/{1}".format(quoted(slug(doctype)), quoted(name))) -def get_url_to_list(doctype): +def get_url_to_list(doctype: str) -> str: return get_url(uri="/app/{0}".format(quoted(slug(doctype)))) -def get_url_to_report(name, report_type=None, doctype=None): +def get_url_to_report( + name, report_type: Optional[str] = None, doctype: Optional[str] = None +) -> str: if report_type == "Report Builder": return get_url(uri="/app/{0}/view/report/{1}".format(quoted(slug(doctype)), quoted(name))) else: @@ -1680,7 +1788,7 @@ def make_filter_dict(filters): return _filter -def sanitize_column(column_name): +def sanitize_column(column_name: str) -> None: import sqlparse from frappe import _ @@ -1716,14 +1824,14 @@ def sanitize_column(column_name): _raise_exception() -def scrub_urls(html): +def scrub_urls(html: str) -> str: html = expand_relative_urls(html) # encoding should be responsibility of the composer # html = quote_urls(html) return html -def expand_relative_urls(html): +def expand_relative_urls(html: str) -> str: # expand relative urls url = get_url() if url.endswith("/"): @@ -1752,11 +1860,11 @@ def expand_relative_urls(html): return html -def quoted(url): +def quoted(url: str) -> str: return cstr(quote(encode(cstr(url)), safe=b"~@#$&()*!+=:;,.?/'")) -def quote_urls(html): +def quote_urls(html: str) -> str: def _quote_url(match): groups = list(match.groups()) groups[2] = quoted(groups[2]) @@ -1765,7 +1873,7 @@ def quote_urls(html): return re.sub(r'(href|src){1}([\s]*=[\s]*[\'"]?)((?:http)[^\'">]+)([\'"]?)', _quote_url, html) -def unique(seq): +def unique(seq: typing.Sequence["T"]) -> List["T"]: """use this instead of list(set()) to preserve order of the original list. Thanks to Stackoverflow: http://stackoverflow.com/questions/480214/how-do-you-remove-duplicates-from-a-list-in-python-whilst-preserving-order""" @@ -1774,26 +1882,23 @@ def unique(seq): return [x for x in seq if not (x in seen or seen_add(x))] -def strip(val, chars=None): +def strip(val: str, chars: Optional[str] = None) -> str: # \ufeff is no-width-break, \u200b is no-width-space return (val or "").replace("\ufeff", "").replace("\u200b", "").strip(chars) -def to_markdown(html): +def to_markdown(html: str) -> str: from html.parser import HTMLParser from html2text import html2text - text = None try: - text = html2text(html or "") + return html2text(html or "") except HTMLParser.HTMLParseError: pass - return text - -def md_to_html(markdown_text): +def md_to_html(markdown_text: str) -> Optional["UnicodeWithAttrs"]: from markdown2 import MarkdownError from markdown2 import markdown as _markdown @@ -1806,14 +1911,11 @@ def md_to_html(markdown_text): "html-classes": {"table": "table table-bordered", "img": "screenshot"}, } - html = None try: - html = UnicodeWithAttrs(_markdown(markdown_text or "", extras=extras)) + return UnicodeWithAttrs(_markdown(markdown_text or "", extras=extras)) except MarkdownError: pass - return html - def markdown(markdown_text): return md_to_html(markdown_text) @@ -1911,7 +2013,13 @@ def validate_json_string(string: str) -> None: raise frappe.ValidationError -def get_user_info_for_avatar(user_id: str) -> Dict: +class _UserInfo(typing.TypedDict): + email: str + image: Optional[str] + name: str + + +def get_user_info_for_avatar(user_id: str) -> _UserInfo: try: user = frappe.get_cached_doc("User", user_id) return {"email": user.email, "image": user.user_image, "name": user.full_name} @@ -1921,7 +2029,9 @@ def get_user_info_for_avatar(user_id: str) -> Dict: return {"email": user_id, "image": "", "name": user_id} -def validate_python_code(string: str, fieldname=None, is_expression: bool = True) -> None: +def validate_python_code( + string: str, fieldname: Optional[str] = None, is_expression: bool = True +) -> None: """Validate python code fields by using compile_command to ensure that expression is valid python. args: From 6994cc684f342667699bacc4ca6825b880fbc086 Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Wed, 11 May 2022 13:28:38 +0530 Subject: [PATCH 34/35] fix(metatags): check if value is set for key --- frappe/website/website_components/metatags.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/website/website_components/metatags.py b/frappe/website/website_components/metatags.py index 0551f946ef..3d35be5514 100644 --- a/frappe/website/website_components/metatags.py +++ b/frappe/website/website_components/metatags.py @@ -16,7 +16,7 @@ class MetaTags: def init_metatags_from_context(self): for key in METATAGS: - if key not in self.tags and self.context.get(key): + if not self.tags.get(key) and self.context.get(key): self.tags[key] = self.context[key] if not self.tags.get("title"): From eeab5edf5f9400dc174f7c01ab636b70fde7f6b7 Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Wed, 11 May 2022 13:29:03 +0530 Subject: [PATCH 35/35] test: test for metatag rendering --- frappe/tests/test_website.py | 5 +++++ frappe/www/_test/_test_metatags.html | 5 +++++ frappe/www/_test/_test_metatags.py | 8 ++++++++ 3 files changed, 18 insertions(+) create mode 100644 frappe/www/_test/_test_metatags.html create mode 100644 frappe/www/_test/_test_metatags.py diff --git a/frappe/tests/test_website.py b/frappe/tests/test_website.py index 9fa0025e38..37ac611b4e 100644 --- a/frappe/tests/test_website.py +++ b/frappe/tests/test_website.py @@ -312,6 +312,11 @@ class TestWebsite(unittest.TestCase): self.assertIn("test.__test", content) self.assertNotIn("frappe.exceptions.ValidationError: Illegal template", content) + def test_metatags(self): + content = get_response_content("/_test/_test_metatags") + self.assertIn('', content) + self.assertIn('', content) + def set_home_page_hook(key, value): from frappe import hooks diff --git a/frappe/www/_test/_test_metatags.html b/frappe/www/_test/_test_metatags.html new file mode 100644 index 0000000000..cd430938a4 --- /dev/null +++ b/frappe/www/_test/_test_metatags.html @@ -0,0 +1,5 @@ +--- +base_template: frappe/templates/web.html +--- + +

Test Metatags

\ No newline at end of file diff --git a/frappe/www/_test/_test_metatags.py b/frappe/www/_test/_test_metatags.py new file mode 100644 index 0000000000..b5b504a246 --- /dev/null +++ b/frappe/www/_test/_test_metatags.py @@ -0,0 +1,8 @@ +# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors +# MIT License. See license.txt + +from __future__ import unicode_literals + + +def get_context(): + return {"title": "Test Title Metatag", "description": "Test Description for Metatag"}