fix: merge conflict

This commit is contained in:
Nabin Hait 2019-06-18 18:45:21 +05:30
commit b375ee9eef
38 changed files with 3258 additions and 2066 deletions

View file

@ -23,7 +23,7 @@ if sys.version[0] == '2':
reload(sys)
sys.setdefaultencoding("utf-8")
__version__ = '11.1.21'
__version__ = '11.1.36'
__title__ = "Frappe Framework"
local = Local()

View file

@ -6,7 +6,7 @@ from __future__ import unicode_literals
import frappe
import unittest
from frappe.core.doctype.doctype.doctype import UniqueFieldnameError, IllegalMandatoryError, DoctypeLinkError, WrongOptionsDoctypeLinkError,\
HiddenAndMandatoryWithoutDefaultError, CannotIndexedError, InvalidFieldNameError
HiddenAndMandatoryWithoutDefaultError, CannotIndexedError, InvalidFieldNameError, CannotCreateStandardDoctypeError
# test_records = frappe.get_test_records('DocType')

File diff suppressed because it is too large Load diff

View file

@ -9,16 +9,22 @@ frappe.ui.form.on('Role Permission for Page and Report', {
refresh: function(frm) {
frm.disable_save();
frm.role_area.hide();
frm.add_custom_button(__("Reset to defaults"), function() {
frm.trigger("reset_roles");
});
frm.add_custom_button(__("Update"), function() {
frm.trigger("update_report_page_data");
}).addClass('btn-primary');
frm.events.add_custom_buttons(frm);
},
add_custom_buttons: function(frm) {
frm.clear_custom_buttons();
if(frm.doc.set_role_for && frm.doc[frappe.model.scrub(frm.doc.set_role_for)]) {
frm.add_custom_button(__("Reset to defaults"), function() {
frm.trigger("reset_roles");
});
frm.add_custom_button(__("Update"), function() {
frm.trigger("update_report_page_data");
}).addClass('btn-primary');
}
},
onload: function(frm) {
if(!frm.roles_editor) {
frm.role_area = $('<div style="min-height: 300px">')
@ -48,14 +54,20 @@ frappe.ui.form.on('Role Permission for Page and Report', {
},
page: function(frm) {
frm.events.add_custom_buttons(frm);
if(frm.doc.page) {
frm.trigger("set_report_page_data");
} else {
frm.trigger("set_role_for");
}
},
report: function(frm){
frm.events.add_custom_buttons(frm);
if(frm.doc.report) {
frm.trigger("set_report_page_data");
} else {
frm.trigger("set_role_for");
}
},
@ -107,7 +119,7 @@ frappe.ui.form.on('Role Permission for Page and Report', {
if(!frm.doc.set_role_for){
frappe.throw(__("Mandatory field: set role for"))
}
if(frm.doc.set_role_for && !frm.doc[frm.doc.set_role_for.toLocaleLowerCase()]) {
frappe.throw(__("Mandatory field: {0}", [frm.doc.set_role_for]))
}

View file

@ -96,7 +96,7 @@ class User(Document):
clear_notifications(user=self.name)
frappe.clear_cache(user=self.name)
self.send_password_notification(self.__new_password)
create_contact(self)
create_contact(self, ignore_mandatory=True)
if self.name not in ('Administrator', 'Guest') and not self.user_image:
frappe.enqueue('frappe.core.doctype.user.user.update_gravatar', name=self.name)

View file

@ -68,7 +68,7 @@ class TestUserPermission(unittest.TestCase):
def test_for_apply_to_all_on_update_from_applicable(self):
''' Update User Permission from some to all applicable Doctypes'''
user = create_user('test_bulk_creation_update@example.com')
param = get_params(user, 'User', user.name,)
param = get_params(user, 'User', user.name)
# create User permissions that with applicable
is_created = add_user_permissions(get_params(user, 'User', user.name, applicable = ["Chat Room", "Chat Message"]))
@ -88,7 +88,6 @@ class TestUserPermission(unittest.TestCase):
self.assertIsNone(removed_applicable_second)
self.assertEquals(is_created, 1)
def create_user(email):
''' create user with role system manager '''
if frappe.db.exists('User', email):

View file

@ -151,6 +151,7 @@ class CustomizeForm(Document):
return
self.flags.update_db = False
self.flags.rebuild_doctype_for_global_search = False
self.set_property_setters()
self.update_custom_fields()
@ -165,6 +166,10 @@ class CustomizeForm(Document):
frappe.clear_cache(doctype=self.doc_type)
self.fetch_to_customize()
if self.flags.rebuild_doctype_for_global_search:
frappe.enqueue('frappe.utils.global_search.rebuild_for_doctype',
now=True, doctype=self.doc_type)
def set_property_setters(self):
meta = frappe.get_meta(self.doc_type)
# doctype property setters
@ -225,6 +230,10 @@ class CustomizeForm(Document):
frappe.msgprint(_("You can't set 'Translatable' for field {0}").format(df.label))
continue
elif (property == 'in_global_search' and
df.in_global_search != meta_df[0].get("in_global_search")):
self.flags.rebuild_doctype_for_global_search = True
self.make_property_setter(property=property, value=df.get(property),
property_type=docfield_properties[property], fieldname=df.fieldname)

View file

@ -7,6 +7,7 @@ from googleapiclient.errors import HttpError
import time
from datetime import datetime
from frappe.utils import add_days, add_years
from frappe.desk.doctype.event.event import has_permission
class CalendarConnector(BaseConnection):
def __init__(self, connector):
@ -64,24 +65,21 @@ class CalendarConnector(BaseConnection):
def insert(self, doctype, doc):
if doctype == 'Events':
from frappe.desk.doctype.event.event import has_permission
d = frappe.get_doc("Event", doc["name"])
if has_permission(d, self.account.name):
if doc["start_datetime"] >= datetime.now():
try:
doctype = "Event"
e = self.insert_events(doctype, doc)
return e
except Exception:
frappe.log_error(frappe.get_traceback(), "GCalendar Synchronization Error")
try:
doctype = "Event"
e = self.insert_events(doctype, doc)
return e
except Exception:
frappe.log_error(frappe.get_traceback(), "GCalendar Synchronization Error")
def update(self, doctype, doc, migration_id):
if doctype == 'Events':
from frappe.desk.doctype.event.event import has_permission
d = frappe.get_doc("Event", doc["name"])
if has_permission(d, self.account.name):
if doc["start_datetime"] >= datetime.now() and migration_id is not None:
if migration_id is not None:
try:
doctype = "Event"
return self.update_events(doctype, doc, migration_id)
@ -217,23 +215,23 @@ class CalendarConnector(BaseConnection):
day = []
if e.repeat_on == "Every Day":
if e.monday is not None:
if e.monday == 1:
day.append("MO")
if e.tuesday is not None:
if e.tuesday == 1:
day.append("TU")
if e.wednesday is not None:
if e.wednesday == 1:
day.append("WE")
if e.thursday is not None:
if e.thursday == 1:
day.append("TH")
if e.friday is not None:
if e.friday == 1:
day.append("FR")
if e.saturday is not None:
if e.saturday == 1:
day.append("SA")
if e.sunday is not None:
if e.sunday == 1:
day.append("SU")
day = "BYDAY=" + ",".join(str(d) for d in day)
frequency = "FREQ=DAILY"
frequency = "FREQ=WEEKLY"
elif e.repeat_on == "Every Week":
frequency = "FREQ=WEEKLY"

View file

@ -6,7 +6,7 @@ from __future__ import unicode_literals
import frappe, json, math
from frappe.model.document import Document
from frappe import _
from frappe.utils import get_source_value
from frappe.utils import get_source_value, cstr
class DataMigrationRun(Document):
def run(self):
@ -213,19 +213,19 @@ class DataMigrationRun(Document):
def get_deleted_local_data(self):
'''Fetch local deleted data using `frappe.get_all`. Used during Push'''
mapping = self.get_mapping(self.current_mapping)
or_filters = self.get_or_filters(mapping)
filters = dict(
deleted_doctype=mapping.local_doctype
)
filters = self.get_last_modified_condition()
filters.update({
"deleted_doctype": mapping.local_doctype
})
data = frappe.get_all('Deleted Document', fields=['data'],
filters=filters, or_filters=or_filters)
data = frappe.get_all('Deleted Document', fields=['name', 'data'],
filters=filters)
_data = []
for d in data:
doc = json.loads(d.data)
if doc.get(mapping.migration_id_field):
doc['_deleted_document_name'] = d.name
doc['_deleted_document_name'] = d["name"]
_data.append(doc)
return _data
@ -306,8 +306,8 @@ class DataMigrationRun(Document):
self.update_log('push_insert', 1)
# post process after insert
self.post_process_doc(local_doc=d, remote_doc=response_doc)
except Exception:
self.update_log('push_failed', d.name)
except Exception as e:
self.update_log('push_failed', {d.name: cstr(e)})
# update page_start
self.db_set('current_mapping_start',
@ -338,8 +338,8 @@ class DataMigrationRun(Document):
self.update_log('push_update', 1)
# post process after update
self.post_process_doc(local_doc=d, remote_doc=response_doc)
except Exception:
self.update_log('push_failed', d.name)
except Exception as e:
self.update_log('push_failed', {d.name: cstr(e)})
# update page_start
self.db_set('current_mapping_start',
@ -370,8 +370,8 @@ class DataMigrationRun(Document):
self.update_log('push_delete', 1)
# post process only when action is success
self.post_process_doc(local_doc=d, remote_doc=response_doc)
except Exception:
self.update_log('push_failed', d.name)
except Exception as e:
self.update_log('push_failed', {d.name: cstr(e)})
# update page_start
self.db_set('current_mapping_start',
@ -414,7 +414,7 @@ class DataMigrationRun(Document):
self.post_process_doc(remote_doc=d, local_doc=local_doc)
except Exception:
# failed, append to log
self.update_log('pull_failed', migration_id_value)
self.update_log('pull_failed', {migration_id_value: cstr(e)})
if len(data) < mapping.page_length:
# last page, done with pull

View file

@ -31,9 +31,15 @@ class AutoRepeat(Document):
validate_template(self.message or "")
def before_submit(self):
start_date_copy = self.start_date
today_copy = add_days(today(), -1)
if start_date_copy <= today_copy:
start_date_copy = today_copy
if not self.next_schedule_date:
self.next_schedule_date = get_next_schedule_date(
self.start_date, self.frequency, self.repeat_on_day)
start_date_copy, self.frequency, self.repeat_on_day)
def on_submit(self):
self.update_auto_repeat_id()
@ -119,14 +125,15 @@ class AutoRepeat(Document):
days = 60 if self.frequency in ['Daily', 'Weekly'] else 365
end_date_copy = add_days(today_copy, days)
start_date_copy = get_next_schedule_date(start_date_copy, self.frequency, self.repeat_on_day)
while (getdate(start_date_copy) < getdate(end_date_copy)):
start_date_copy = get_next_schedule_date(start_date_copy, self.frequency, self.repeat_on_day)
row = {
"reference_document" : self.reference_document,
"frequency" : self.frequency,
"next_scheduled_date" : start_date_copy
}
schedule_details.append(row)
start_date_copy = get_next_schedule_date(start_date_copy, self.frequency, self.repeat_on_day)
return schedule_details

View file

@ -8,7 +8,7 @@ import unittest
import frappe
from frappe.custom.doctype.custom_field.custom_field import create_custom_field
from frappe.desk.doctype.auto_repeat.auto_repeat import get_auto_repeat_entries, create_repeated_entries, disable_auto_repeat
from frappe.utils import today, add_days, getdate
from frappe.utils import today, add_days, getdate, add_months
def add_custom_fields():
@ -44,8 +44,8 @@ class TestAutoRepeat(unittest.TestCase):
self.assertEqual(todo.get('description'), new_todo.get('description'))
def test_monthly_auto_repeat(self):
start_date = '2018-01-01'
end_date = '2018-12-31'
start_date = today()
end_date = add_months(start_date, 12)
todo = frappe.get_doc(
dict(doctype='ToDo', description='test recurring todo', assigned_by='Administrator')).insert()
@ -103,7 +103,7 @@ def make_auto_repeat(**args):
'reference_document': args.reference_document or frappe.db.get_value('ToDo', {'docstatus': 1}, 'name'),
'frequency': args.frequency or 'Daily',
'start_date': args.start_date or add_days(today(), -1),
'end_date': args.end_date or add_days(today(), 1),
'end_date': args.end_date or add_days(today(), 2),
'submit_on_creation': args.submit_on_creation or 0,
'notify_by_email': args.notify or 0,
'recipients': args.recipients or "",

View file

@ -264,13 +264,17 @@ def get_prepared_report_result(report, filters, dn="", user=None):
data = json.loads(uncompressed_content)
if data:
columns = json.loads(doc.columns) if doc.columns else data[0]
for column in columns:
column["label"] = _(column["label"])
if isinstance(column, dict):
column["label"] = _(column["label"])
latest_report_data = {
"columns": columns,
"result": data
}
except Exception:
frappe.log_error(frappe.get_traceback())
frappe.delete_doc("Prepared Report", doc.name)
frappe.db.commit()
doc = None
@ -380,6 +384,8 @@ def add_total_row(result, columns, meta = None):
options = col.get("options")
for row in result:
if i >= len(row): continue
cell = row.get(fieldname) if isinstance(row, dict) else row[i]
if fieldtype in ["Currency", "Int", "Float", "Percent"] and flt(cell):
total_row[i] = flt(total_row[i]) + flt(cell)

View file

@ -1,237 +1,237 @@
{
"allow_rename": 1,
"creation": "2016-09-01 01:34:34.985457",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"report",
"user",
"enabled",
"column_break_4",
"report_type",
"reference_report",
"filter_data",
"send_if_data",
"data_modified_till",
"no_of_rows",
"report_filters",
"filters_display",
"filters",
"filter_meta",
"dynamic_report_filters_section",
"from_date_field",
"to_date_field",
"column_break_17",
"dynamic_date_period",
"email_settings",
"email_to",
"day_of_week",
"column_break_13",
"frequency",
"format",
"section_break_15",
"description"
],
"fields": [
{
"fieldname": "report",
"fieldtype": "Link",
"label": "Report",
"options": "Report",
"reqd": 1
},
{
"default": "User",
"fieldname": "user",
"fieldtype": "Link",
"label": "Based on Permissions For User",
"options": "User",
"reqd": 1
},
{
"default": "1",
"fieldname": "enabled",
"fieldtype": "Check",
"label": "Enabled"
},
{
"fieldname": "column_break_4",
"fieldtype": "Column Break"
},
{
"fetch_from": "report.report_type",
"fieldname": "report_type",
"fieldtype": "Read Only",
"label": "Report Type"
},
{
"fieldname": "filter_data",
"fieldtype": "Section Break",
"label": "Filter Data"
},
{
"default": "1",
"fieldname": "send_if_data",
"fieldtype": "Check",
"label": "Send only if there is any data"
},
{
"depends_on": "eval:doc.report_type=='Report Builder'",
"description": "Zero means send records updated at anytime",
"fieldname": "data_modified_till",
"fieldtype": "Int",
"label": "Only Send Records Updated in Last X Hours"
},
{
"default": "100",
"fieldname": "no_of_rows",
"fieldtype": "Int",
"label": "No of Rows (Max 500)"
},
{
"collapsible": 1,
"depends_on": "eval:doc.report_type !== 'Report Builder'",
"fieldname": "report_filters",
"fieldtype": "Section Break",
"label": "Report Filters"
},
{
"fieldname": "filters_display",
"fieldtype": "HTML",
"label": "Filters Display"
},
{
"fieldname": "filters",
"fieldtype": "Text",
"hidden": 1,
"label": "Filters"
},
{
"fieldname": "filter_meta",
"fieldtype": "Text",
"hidden": 1,
"label": "Filter Meta",
"read_only": 1
},
{
"collapsible": 1,
"depends_on": "eval:doc.report_type !== 'Report Builder'",
"fieldname": "dynamic_report_filters_section",
"fieldtype": "Section Break",
"label": "Dynamic Report Filters"
},
{
"fieldname": "from_date_field",
"fieldtype": "Select",
"label": "From Date Field"
},
{
"fieldname": "to_date_field",
"fieldtype": "Select",
"label": "To Date Field"
},
{
"fieldname": "column_break_17",
"fieldtype": "Column Break"
},
{
"fieldname": "dynamic_date_period",
"fieldtype": "Select",
"label": "Period",
"options": "\nDaily\nWeekly\nMonthly\nQuarterly\nHalf Yearly\nYearly"
},
{
"fieldname": "email_settings",
"fieldtype": "Section Break",
"label": "Email Settings"
},
{
"fieldname": "email_to",
"fieldtype": "Small Text",
"label": "Email To",
"reqd": 1
},
{
"default": "Monday",
"depends_on": "eval:doc.frequency=='Weekly'",
"fieldname": "day_of_week",
"fieldtype": "Select",
"label": "Day of Week",
"options": "Monday\nTuesday\nWednesday\nThursday\nFriday\nSaturday\nSunday"
},
{
"fieldname": "column_break_13",
"fieldtype": "Column Break"
},
{
"fieldname": "frequency",
"fieldtype": "Select",
"in_list_view": 1,
"in_standard_filter": 1,
"label": "Frequency",
"options": "Daily\nWeekdays\nWeekly\nMonthly",
"reqd": 1
},
{
"fieldname": "format",
"fieldtype": "Select",
"label": "Format",
"options": "HTML\nXLSX\nCSV",
"reqd": 1
},
{
"collapsible": 1,
"fieldname": "section_break_15",
"fieldtype": "Section Break",
"label": "Message"
},
{
"fieldname": "description",
"fieldtype": "Text Editor",
"label": "Message"
},
{
"fetch_from": "report.reference_report",
"fieldname": "reference_report",
"fieldtype": "Data",
"hidden": 1,
"label": "Reference Report",
"read_only": 1
}
],
"modified": "2019-05-09 22:38:27.570890",
"modified_by": "Administrator",
"module": "Email",
"name": "Auto Email Report",
"owner": "Administrator",
"permissions": [
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"share": 1,
"write": 1
},
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "Report Manager",
"share": 1,
"write": 1
}
],
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
}
"allow_rename": 1,
"creation": "2016-09-01 01:34:34.985457",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"report",
"user",
"enabled",
"column_break_4",
"report_type",
"reference_report",
"filter_data",
"send_if_data",
"data_modified_till",
"no_of_rows",
"report_filters",
"filters_display",
"filters",
"filter_meta",
"dynamic_report_filters_section",
"from_date_field",
"to_date_field",
"column_break_17",
"dynamic_date_period",
"email_settings",
"email_to",
"day_of_week",
"column_break_13",
"frequency",
"format",
"section_break_15",
"description"
],
"fields": [
{
"fieldname": "report",
"fieldtype": "Link",
"label": "Report",
"options": "Report",
"reqd": 1
},
{
"default": "User",
"fieldname": "user",
"fieldtype": "Link",
"label": "Based on Permissions For User",
"options": "User",
"reqd": 1
},
{
"default": "1",
"fieldname": "enabled",
"fieldtype": "Check",
"label": "Enabled"
},
{
"fieldname": "column_break_4",
"fieldtype": "Column Break"
},
{
"fetch_from": "report.report_type",
"fieldname": "report_type",
"fieldtype": "Read Only",
"label": "Report Type"
},
{
"fieldname": "filter_data",
"fieldtype": "Section Break",
"label": "Filter Data"
},
{
"default": "1",
"fieldname": "send_if_data",
"fieldtype": "Check",
"label": "Send only if there is any data"
},
{
"depends_on": "eval:doc.report_type=='Report Builder'",
"description": "Zero means send records updated at anytime",
"fieldname": "data_modified_till",
"fieldtype": "Int",
"label": "Only Send Records Updated in Last X Hours"
},
{
"default": "100",
"fieldname": "no_of_rows",
"fieldtype": "Int",
"label": "No of Rows (Max 500)"
},
{
"collapsible": 1,
"depends_on": "eval:doc.report_type !== 'Report Builder'",
"fieldname": "report_filters",
"fieldtype": "Section Break",
"label": "Report Filters"
},
{
"fieldname": "filters_display",
"fieldtype": "HTML",
"label": "Filters Display"
},
{
"fieldname": "filters",
"fieldtype": "Text",
"hidden": 1,
"label": "Filters"
},
{
"fieldname": "filter_meta",
"fieldtype": "Text",
"hidden": 1,
"label": "Filter Meta",
"read_only": 1
},
{
"collapsible": 1,
"depends_on": "eval:doc.report_type !== 'Report Builder'",
"fieldname": "dynamic_report_filters_section",
"fieldtype": "Section Break",
"label": "Dynamic Report Filters"
},
{
"fieldname": "from_date_field",
"fieldtype": "Select",
"label": "From Date Field"
},
{
"fieldname": "to_date_field",
"fieldtype": "Select",
"label": "To Date Field"
},
{
"fieldname": "column_break_17",
"fieldtype": "Column Break"
},
{
"fieldname": "dynamic_date_period",
"fieldtype": "Select",
"label": "Period",
"options": "\nDaily\nWeekly\nMonthly\nQuarterly\nHalf Yearly\nYearly"
},
{
"fieldname": "email_settings",
"fieldtype": "Section Break",
"label": "Email Settings"
},
{
"fieldname": "email_to",
"fieldtype": "Small Text",
"label": "Email To",
"reqd": 1
},
{
"default": "Monday",
"depends_on": "eval:doc.frequency=='Weekly'",
"fieldname": "day_of_week",
"fieldtype": "Select",
"label": "Day of Week",
"options": "Monday\nTuesday\nWednesday\nThursday\nFriday\nSaturday\nSunday"
},
{
"fieldname": "column_break_13",
"fieldtype": "Column Break"
},
{
"fieldname": "frequency",
"fieldtype": "Select",
"in_list_view": 1,
"in_standard_filter": 1,
"label": "Frequency",
"options": "Daily\nWeekdays\nWeekly\nMonthly",
"reqd": 1
},
{
"fieldname": "format",
"fieldtype": "Select",
"label": "Format",
"options": "HTML\nXLSX\nCSV",
"reqd": 1
},
{
"collapsible": 1,
"fieldname": "section_break_15",
"fieldtype": "Section Break",
"label": "Message"
},
{
"fieldname": "description",
"fieldtype": "Text Editor",
"label": "Message"
},
{
"fetch_from": "report.reference_report",
"fieldname": "reference_report",
"fieldtype": "Data",
"hidden": 1,
"label": "Reference Report",
"read_only": 1
}
],
"modified": "2019-05-09 22:38:27.570890",
"modified_by": "Administrator",
"module": "Email",
"name": "Auto Email Report",
"owner": "Administrator",
"permissions": [
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"share": 1,
"write": 1
},
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "Report Manager",
"share": 1,
"write": 1
}
],
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
}

View file

@ -3,7 +3,7 @@
"allow_import": 0,
"allow_rename": 0,
"beta": 0,
"creation": "2015-03-18 09:41:20.216319",
"creation": "2015-03-18 09:41:20.216320",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
@ -35,7 +35,7 @@
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"search_index": 1,
"set_only_once": 0,
"unique": 0
},
@ -172,4 +172,4 @@
"sort_order": "DESC",
"track_changes": 1,
"track_seen": 0
}
}

View file

@ -77,19 +77,35 @@ def send(recipients=None, sender=None, subject=None, message=None, text_content=
except HTMLParser.HTMLParseError:
text_content = "See html attachment"
if reference_doctype and reference_name:
unsubscribed = [d.email for d in frappe.db.get_all("Email Unsubscribe", "email",
{"reference_doctype": reference_doctype, "reference_name": reference_name})]
recipients = list(set(recipients))
cc = list(set(cc))
unsubscribed += [d.email for d in frappe.db.get_all("Email Unsubscribe", "email",
{"global_unsubscribe": 1})]
else:
unsubscribed = []
all_ids = recipients + cc
recipients = [r for r in list(set(recipients)) if r and r not in unsubscribed]
unsubscribed = frappe.db.sql_list('''
SELECT
distinct email
from
`tabEmail Unsubscribe`
where
email in %(all_ids)s
and (
(
reference_doctype = %(reference_doctype)s
and reference_name = %(reference_name)s
)
or global_unsubscribe = 1
)
''', {
'all_ids': all_ids,
'reference_doctype': reference_doctype,
'reference_name': reference_name,
})
recipients = [r for r in recipients if r and r not in unsubscribed]
if cc:
cc = [r for r in list(set(cc)) if r and r not in unsubscribed]
cc = [r for r in cc if r and r not in unsubscribed]
if not recipients and not cc:
# Recipients may have been unsubscribed, exit quietly

View file

@ -33,6 +33,51 @@
"local_fieldname": "repeat_this_event",
"remote_fieldname": "repeat_this_event"
},
{
"is_child_table": 0,
"local_fieldname": "repeat_on",
"remote_fieldname": "repeat_on"
},
{
"is_child_table": 0,
"local_fieldname": "repeat_till",
"remote_fieldname": "repeat_till"
},
{
"is_child_table": 0,
"local_fieldname": "monday",
"remote_fieldname": "monday"
},
{
"is_child_table": 0,
"local_fieldname": "tuesday",
"remote_fieldname": "tuesday"
},
{
"is_child_table": 0,
"local_fieldname": "wednesday",
"remote_fieldname": "wednesday"
},
{
"is_child_table": 0,
"local_fieldname": "thursday",
"remote_fieldname": "thursday"
},
{
"is_child_table": 0,
"local_fieldname": "friday",
"remote_fieldname": "friday"
},
{
"is_child_table": 0,
"local_fieldname": "saturday",
"remote_fieldname": "saturday"
},
{
"is_child_table": 0,
"local_fieldname": "sunday",
"remote_fieldname": "sunday"
},
{
"is_child_table": 0,
"local_fieldname": "name",
@ -45,8 +90,8 @@
"mapping_name": "Event to GCalendar",
"mapping_type": "Push",
"migration_id_field": "gcalendar_sync_id",
"modified": "2018-05-18 14:38:43.658069",
"modified_by": "chdecultot@dokos.io",
"modified": "2019-03-26 10:16:45.400150",
"modified_by": "Administrator",
"name": "Event to GCalendar",
"owner": "Administrator",
"page_length": 10,

View file

@ -2,7 +2,7 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import frappe
from datetime import datetime
from datetime import datetime, timedelta
from dateutil.parser import parse
from pytz import timezone
from frappe.utils import add_days
@ -30,7 +30,7 @@ def pre_process(events):
event_tz = events["start"]["timeZone"]
else:
event_tz = events["calendar_tz"]
start_dt= timezone(event_tz).localize(start_dt)
start_dt = timezone(event_tz).localize(start_dt)
if end_dt.tzinfo is None or end_dt.tzinfo.utcoffset(end_dt) is None:
if "timeZone" in events["end"]:
@ -79,32 +79,37 @@ def get_recurrence_event_fields_value(recur_rule, starts_on):
else: repeat_on = "Every Year"
elif "UNTIL" in _str:
# get repeat till
date = datetime.strptime(_str.split("=")[1], "%Y%m%dT%H%M%SZ")
date = parse(_str.split("=")[1])
repeat_till = get_repeat_till_date(date)
elif "COUNT" in _str:
# get repeat till
date = datetime.strptime(starts_on, "%Y-%m-%d %H:%M:%S")
date = parse(starts_on)
repeat_till = get_repeat_till_date(date, count=_str.split("=")[1], repeat_on=repeat_on)
elif "BYDAY" in _str:
days = _str.split("=")[1]
if repeat_on == "DAILY":
repeat_days.update({
"sunday": 1 if "SU" in days else 0,
"monday": 1 if "MO" in days else 0,
"tuesday": 1 if "TU" in days else 0,
"wednesday": 1 if "WD" in days else 0,
"thursday": 1 if "TU" in days else 0,
"friday": 1 if "TU" in days else 0,
"saturday": 1 if "TU" in days else 0,
})
repeat_days.update({
"sunday": 1 if "SU" in days else 0,
"monday": 1 if "MO" in days else 0,
"tuesday": 1 if "TU" in days else 0,
"wednesday": 1 if "WD" in days else 0,
"thursday": 1 if "TH" in days else 0,
"friday": 1 if "FR" in days else 0,
"saturday": 1 if "SA" in days else 0,
})
repeat_on = "Every Day"
return {
recurrence = {
"repeat_on": repeat_on,
"repeat_till": repeat_till,
"repeat_this_event": 1,
"repeat_days": repeat_days
"repeat_this_event": 1
}
if repeat_days:
recurrence.update(repeat_days)
return recurrence
def get_repeat_till_date(date, count=None, repeat_on=None):
if count:
if repeat_on == "Every Day":

View file

@ -33,6 +33,51 @@
"local_fieldname": "repeat_this_event",
"remote_fieldname": "repeat_this_event"
},
{
"is_child_table": 0,
"local_fieldname": "repeat_on",
"remote_fieldname": "repeat_on"
},
{
"is_child_table": 0,
"local_fieldname": "repeat_till",
"remote_fieldname": "repeat_till"
},
{
"is_child_table": 0,
"local_fieldname": "monday",
"remote_fieldname": "monday"
},
{
"is_child_table": 0,
"local_fieldname": "tuesday",
"remote_fieldname": "tuesday"
},
{
"is_child_table": 0,
"local_fieldname": "wednesday",
"remote_fieldname": "wednesday"
},
{
"is_child_table": 0,
"local_fieldname": "thursday",
"remote_fieldname": "thursday"
},
{
"is_child_table": 0,
"local_fieldname": "friday",
"remote_fieldname": "friday"
},
{
"is_child_table": 0,
"local_fieldname": "saturday",
"remote_fieldname": "saturday"
},
{
"is_child_table": 0,
"local_fieldname": "sunday",
"remote_fieldname": "sunday"
},
{
"is_child_table": 0,
"local_fieldname": "gcalendar_sync_id",
@ -50,8 +95,8 @@
"mapping_name": "GCalendar to Event",
"mapping_type": "Pull",
"migration_id_field": "gcalendar_sync_id",
"modified": "2018-05-18 14:38:43.694867",
"modified_by": "chdecultot@dokos.io",
"modified": "2019-03-26 10:16:45.426138",
"modified_by": "Administrator",
"name": "GCalendar to Event",
"owner": "Administrator",
"page_length": 250,

View file

@ -2,7 +2,7 @@
"creation": "2018-03-23 19:10:23.715161",
"docstatus": 0,
"doctype": "Data Migration Plan",
"idx": 4,
"idx": 22,
"mappings": [
{
"enabled": 1,
@ -13,8 +13,8 @@
"mapping": "GCalendar to Event"
}
],
"modified": "2018-05-18 14:38:43.559026",
"modified_by": "chdecultot@dokos.io",
"modified": "2019-03-26 10:16:45.369037",
"modified_by": "Administrator",
"module": "Integrations",
"name": "GCalendar Sync",
"owner": "Administrator",

View file

@ -14,16 +14,16 @@ class LDAPSettings(Document):
return
if not self.flags.ignore_mandatory:
if self.ldap_search_string.endswith("={0}"):
if self.enabled:
connect_to_ldap(server_url=self.ldap_server_url,
base_dn=self.base_dn,
password=self.get_password(raise_exception=False),
ssl_tls_mode=self.ssl_tls_mode,
trusted_cert=self.require_trusted_certificate,
private_key_file=self.local_private_key_file,
server_cert_file=self.local_server_certificate_file,
ca_certs_file=self.local_ca_certs_file)
if self.ldap_search_string and self.ldap_search_string.endswith("={0}"):
connect_to_ldap(server_url=self.ldap_server_url,
base_dn=self.base_dn,
password=self.get_password(raise_exception=False),
ssl_tls_mode=self.ssl_tls_mode,
trusted_cert=self.require_trusted_certificate,
private_key_file=self.local_private_key_file,
server_cert_file=self.local_server_certificate_file,
ca_certs_file=self.local_ca_certs_file
)
else:
frappe.throw(_("LDAP Search String needs to end with a placeholder, eg sAMAccountName={0}"))
@ -160,7 +160,7 @@ def create_user(params):
"language": "",
"user_type": "System User",
"roles": [{
"role": _("Blogger")
"role": _("Customer")
}]
})

View file

@ -369,7 +369,7 @@ def manage_recurring_payment_profile_status(profile_id, action, args, url):
# error code 11556 indicates profile is not in active state(or already cancelled)
# thus could not cancel the subscription.
# thus raise exception only if error code not quals to 11556
# thus raise an exception only if the error code is not equal to 11556
if response.get("ACK")[0] != "Success" and response.get("L_ERRORCODE0", [])[0] != '11556':
frappe.throw(_("Failed while amending subscription"))

View file

@ -76,4 +76,3 @@ def migrate(verbose=True, rebuild_website=False):
with open(touched_tables_file, 'w') as f:
json.dump(list(frappe.flags.touched_tables), f, sort_keys=True, indent=4)
frappe.flags.touched_tables.clear()

View file

@ -60,24 +60,15 @@ def set_user_and_static_default_values(doc):
allowed_records, default_doc = filter_allowed_docs_for_doctype(doctype_user_permissions, df.parent, with_default_doc=True)
user_default_value = get_user_default_value(df, defaults, doctype_user_permissions, allowed_records, default_doc)
if user_default_value != None:
# do not set default if the field on which current field is dependent is not set
if is_dependent_field_set(df.depends_on, doc):
doc.set(df.fieldname, user_default_value)
if user_default_value is not None:
doc.set(df.fieldname, user_default_value)
else:
if df.fieldname != doc.meta.title_field:
static_default_value = get_static_default_value(df, doctype_user_permissions, allowed_records)
if static_default_value != None and is_dependent_field_set(df.depends_on, doc):
if static_default_value is not None:
doc.set(df.fieldname, static_default_value)
def is_dependent_field_set(fieldname, doc):
value_dict = doc.as_dict()
if not fieldname: return True
# to check if fieldname passed is valid
if fieldname not in value_dict: return True
return value_dict[fieldname]
def get_user_default_value(df, defaults, doctype_user_permissions, allowed_records, default_doc):
# don't set defaults for "User" link field using User Permissions!
if df.fieldtype == "Link" and df.options != "User":

File diff suppressed because it is too large Load diff

View file

@ -469,7 +469,7 @@ frappe.Application = Class.extend({
},
set_rtl: function() {
if (["ar", "he", "fa"].indexOf(frappe.boot.lang) >= 0) {
if (frappe.utils.is_rtl()) {
var ls = document.createElement('link');
ls.rel="stylesheet";
ls.href= "assets/css/frappe-rtl.css";

View file

@ -121,6 +121,29 @@ frappe.ui.form.PrintPreview = Class.extend({
if (e.print_format) {
this.print_sel.val(e.print_format);
}
// start a new print format
frappe.prompt([
{
label: __("New Print Format Name"),
fieldname: "print_format_name",
fieldtype: "Data",
reqd: 1,
},
{
label: __('Based On'),
fieldname: 'based_on',
fieldtype: 'Read Only',
default: print_format.name || 'Standard'
}
], function (data) {
frappe.route_options = {
make_new: true,
doctype: me.frm.doctype,
name: data.print_format_name,
based_on: data.based_on
};
frappe.set_route("print-format-builder");
}, __("New Custom Print Format"), __("Start"));
});
},
set_user_lang: function () {
@ -578,4 +601,3 @@ frappe.ui.form.qz_fail = function (e) {
indicator: 'red'
}, 20);
}

View file

@ -90,7 +90,7 @@ $.extend(frappe.model, {
for(var fid=0;fid<docfields.length;fid++) {
var f = docfields[fid];
if(!in_list(frappe.model.no_value_type, f.fieldtype) && doc[f.fieldname]==null) {
var v = !f.depends_on || doc[f.depends_on] ? frappe.model.get_default_value(f, doc, parent_doc) : null;
var v = frappe.model.get_default_value(f, doc, parent_doc);
if(v) {
if(in_list(["Int", "Check"], f.fieldtype))
v = cint(v);

View file

@ -389,7 +389,7 @@ $.extend(frappe.model, {
tasks.push(() => frappe.model.trigger(key, value, doc));
} else {
// execute link triggers (want to reselect to execute triggers)
if(fieldtype=="Link" && doc) {
if(in_list(["Link", "Dynamic Link"], fieldtype) && doc) {
tasks.push(() => frappe.model.trigger(key, value, doc));
}
}

View file

@ -716,6 +716,9 @@ Object.assign(frappe.utils, {
indicator: 'green',
message: __('Copied to clipboard.')
});
},
is_rtl() {
return ["ar", "he", "fa"].includes(frappe.boot.lang);
}
});
@ -736,4 +739,3 @@ if (!Array.prototype.uniqBy) {
}
});
}

View file

@ -253,6 +253,8 @@ frappe.views.CommunicationComposer = Class.extend({
$.extend(last_edited_communication, {
sender: me.dialog.get_value("sender"),
recipients: me.dialog.get_value("recipients"),
cc: me.dialog.get_value("cc"),
bcc: me.dialog.get_value("bcc"),
subject: me.dialog.get_value("subject"),
content: me.dialog.get_value("content"),
});
@ -265,6 +267,8 @@ frappe.views.CommunicationComposer = Class.extend({
me.dialog.set_value("sender", last_edited_communication.sender || "");
me.dialog.set_value("subject", last_edited_communication.subject || "");
me.dialog.set_value("recipients", last_edited_communication.recipients || "");
me.dialog.set_value("cc", last_edited_communication.cc || "");
me.dialog.set_value("bcc", last_edited_communication.bcc || "");
me.dialog.set_value("content", last_edited_communication.content || "");
}
}

View file

@ -457,6 +457,7 @@ frappe.views.QueryReport = class QueryReport extends frappe.views.BaseList {
layout: 'fixed',
cellHeight: 33,
showTotalRow: this.raw_data.add_total_row,
direction: frappe.utils.is_rtl() ? 'rtl' : 'ltr',
hooks: {
columnTotal: frappe.utils.report_column_total
}
@ -468,6 +469,9 @@ frappe.views.QueryReport = class QueryReport extends frappe.views.BaseList {
this.datatable = new DataTable(this.$report[0], datatable_options);
}
if (typeof this.report_settings.initial_depth == "number") {
this.datatable.rowmanager.setTreeDepth(this.report_settings.initial_depth);
}
if (this.report_settings.after_datatable_render) {
this.report_settings.after_datatable_render(this.datatable);
}
@ -789,8 +793,9 @@ frappe.views.QueryReport = class QueryReport extends frappe.views.BaseList {
print_settings: print_settings,
landscape: landscape,
filters: this.get_filter_values(),
data: custom_format ? this.data : this.get_data_for_print(),
data: this.get_data_for_print(),
columns: custom_format ? this.columns : this.get_columns_for_print(),
original_data: this.data,
report: this
});
}
@ -802,7 +807,7 @@ frappe.views.QueryReport = class QueryReport extends frappe.views.BaseList {
const custom_format = this.report_settings.html_format || null;
const columns = custom_format ? this.columns : this.get_columns_for_print();
const data = custom_format ? this.data : this.get_data_for_print();
const data = this.get_data_for_print();
const applied_filters = this.get_filter_values();
const filters_html = this.get_filters_html_for_print();
@ -811,6 +816,7 @@ frappe.views.QueryReport = class QueryReport extends frappe.views.BaseList {
subtitle: filters_html,
filters: applied_filters,
data: data,
original_data: this.data,
columns: columns,
report: this
});
@ -924,7 +930,6 @@ frappe.views.QueryReport = class QueryReport extends frappe.views.BaseList {
return this.data[index];
}
}).filter(Boolean);
let totalRow = this.datatable.bodyRenderer.getTotalRow().reduce((row, cell) => {
row[cell.column.id] = cell.content;
return row;

View file

@ -265,6 +265,7 @@ frappe.views.ReportView = class ReportView extends frappe.views.ListView {
checkboxColumn: true,
inlineFilters: true,
cellHeight: 35,
direction: frappe.utils.is_rtl() ? 'rtl' : 'ltr',
events: {
onRemoveColumn: (column) => {
this.remove_column_from_datatable(column);
@ -526,7 +527,20 @@ frappe.views.ReportView = class ReportView extends frappe.views.ListView {
.then((updated_doc) => {
const _data = this.data.find(d => d.name === updated_doc.name);
for (let field in _data) {
_data[field] = updated_doc[field];
if (field.includes(':')) {
// child table field
const [cdt, _field] = field.split(':');
const cdt_row = Object.keys(updated_doc)
.filter(key => Array.isArray(updated_doc[key]) && updated_doc[key][0].doctype === cdt)
.map(key => updated_doc[key])
.map(a => a[0])
.filter(cdoc => cdoc.name === _data[cdt + ':name'])[0];
if (cdt_row) {
_data[field] = cdt_row[_field];
}
} else {
_data[field] = updated_doc[field];
}
}
})
.then(() => this.refresh_charts());

File diff suppressed because it is too large Load diff

View file

@ -5,7 +5,6 @@ from __future__ import unicode_literals
import frappe, unittest, os
from frappe.utils import cint
from frappe.model.naming import revert_series_if_last, make_autoname, parse_naming_series
from frappe.utils.testutils import add_custom_field, clear_custom_fields
class TestDocument(unittest.TestCase):
def test_get_return_empty_list_for_table_field_if_none(self):
@ -237,20 +236,3 @@ class TestDocument(unittest.TestCase):
new_current = cint(frappe.db.get_value('Series', prefix, "current", order_by="name"))
self.assertEqual(cint(old_current) - 1, new_current)
def test_default_of_dependent_field(self):
add_custom_field('ToDo', 'parent_field', 'Data')
add_custom_field('ToDo', 'dependent_field', 'Data',
default='Some Data', depends_on='parent_field')
add_custom_field('ToDo', 'independent_field', 'Data',
default='Some Data')
doc = frappe.new_doc('ToDo')
self.assertFalse(doc.get('dependent_field'))
self.assertEqual(doc.get('independent_field'), 'Some Data')
clear_custom_fields('ToDo')

View file

@ -4,15 +4,13 @@ from __future__ import unicode_literals
import frappe
def add_custom_field(doctype, fieldname, fieldtype='Data', options=None, default=None, depends_on=None):
def add_custom_field(doctype, fieldname, fieldtype='Data', options=None):
frappe.get_doc({
"doctype": "Custom Field",
"dt": doctype,
"fieldname": fieldname,
"fieldtype": fieldtype,
"options": options,
"default": default,
"depends_on": depends_on
"options": options
}).insert()
def clear_custom_fields(doctype):

View file

@ -315,7 +315,6 @@ def disable_users(limits=None):
user_list = ['Administrator', 'Guest']
if system_manager:
user_list.append(system_manager[-1])
#exclude system manager from active user list
# active_users = frappe.db.sql_list("""select name from tabUser
# where name not in ('Administrator', 'Guest', %s) and user_type = 'System User' and enabled=1

View file

@ -374,7 +374,7 @@ $.extend(frappe, {
// Utility functions
window.valid_email = function(id) {
// eslint-disable-next-line
// eslint-disable-next-line
return /[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?/.test(id.toLowerCase());
}

View file

@ -38,7 +38,6 @@ def get_context(context):
"icon": icon
})
context["social_login"] = True
ldap_settings = get_ldap_client_settings()
context["ldap_settings"] = ldap_settings