소스 검색

Merge remote-tracking branch 'frappe/develop' into wip-4.1

version-14
Anand Doshi 11 년 전
부모
커밋
f1caa27625
29개의 변경된 파일320개의 추가작업 그리고 130개의 파일을 삭제
  1. +6
    -0
      frappe/app.py
  2. +5
    -0
      frappe/config/setup.py
  3. +12
    -2
      frappe/core/doctype/custom_script/custom_script.json
  4. +1
    -1
      frappe/core/doctype/doctype/doctype.py
  5. +0
    -0
      frappe/core/doctype/standard_reply/__init__.py
  6. +71
    -0
      frappe/core/doctype/standard_reply/standard_reply.json
  7. +9
    -0
      frappe/core/doctype/standard_reply/standard_reply.py
  8. +72
    -72
      frappe/core/doctype/system_settings/system_settings.json
  9. +2
    -1
      frappe/core/page/data_import_tool/data_import_tool.js
  10. +1
    -1
      frappe/core/page/data_import_tool/importer.py
  11. +1
    -1
      frappe/country_info.json
  12. +0
    -5
      frappe/handler.py
  13. +33
    -1
      frappe/model/base_document.py
  14. +5
    -0
      frappe/model/document.py
  15. +4
    -0
      frappe/model/meta.py
  16. +1
    -0
      frappe/patches.txt
  17. +10
    -0
      frappe/patches/v4_0/remove_user_owner_custom_field.py
  18. +0
    -8
      frappe/public/js/frappe/desk.js
  19. +3
    -1
      frappe/public/js/frappe/misc/number_format.js
  20. +1
    -1
      frappe/public/js/frappe/ui/filters.js
  21. +1
    -1
      frappe/public/js/frappe/ui/toolbar/toolbar.js
  22. +33
    -0
      frappe/public/js/frappe/views/communication.js
  23. +1
    -1
      frappe/public/js/frappe/views/doclistview.js
  24. +2
    -0
      frappe/public/js/frappe/views/reportview.js
  25. +15
    -12
      frappe/public/js/frappe/views/sidebar_stats.js
  26. +6
    -2
      frappe/public/js/legacy/print_format.js
  27. +17
    -14
      frappe/sessions.py
  28. +2
    -3
      frappe/templates/includes/navbar.html
  29. +6
    -3
      frappe/utils/__init__.py

+ 6
- 0
frappe/app.py 파일 보기

@@ -81,6 +81,12 @@ def application(request):
frappe.db.commit() frappe.db.commit()
rollback = False rollback = False


# update session
if getattr(frappe.local, "session_obj", None):
updated_in_db = frappe.local.session_obj.update()
if updated_in_db:
frappe.db.commit()

finally: finally:
if frappe.local.request.method in ("POST", "PUT") and frappe.db and rollback: if frappe.local.request.method in ("POST", "PUT") and frappe.db and rollback:
frappe.db.rollback() frappe.db.rollback()


+ 5
- 0
frappe/config/setup.py 파일 보기

@@ -121,6 +121,11 @@ def get_data():
"name": "Outgoing Email Settings", "name": "Outgoing Email Settings",
"description": _("Set outgoing mail server.") "description": _("Set outgoing mail server.")
}, },
{
"type": "doctype",
"name": "Standard Reply",
"description": _("Standard replies to common queries.")
},
] ]
}, },
{ {


+ 12
- 2
frappe/core/doctype/custom_script/custom_script.json 파일 보기

@@ -1,6 +1,6 @@
{ {
"autoname": "CustomScript.####", "autoname": "CustomScript.####",
"creation": "2013-01-10 16:34:01.000000",
"creation": "2013-01-10 16:34:01",
"description": "Adds a custom script (client or server) to a DocType", "description": "Adds a custom script (client or server) to a DocType",
"docstatus": 0, "docstatus": 0,
"doctype": "DocType", "doctype": "DocType",
@@ -8,6 +8,7 @@
{ {
"fieldname": "dt", "fieldname": "dt",
"fieldtype": "Link", "fieldtype": "Link",
"in_list_view": 1,
"label": "DocType", "label": "DocType",
"oldfieldname": "dt", "oldfieldname": "dt",
"oldfieldtype": "Link", "oldfieldtype": "Link",
@@ -19,6 +20,7 @@
"fieldname": "script_type", "fieldname": "script_type",
"fieldtype": "Select", "fieldtype": "Select",
"hidden": 1, "hidden": 1,
"in_list_view": 1,
"label": "Script Type", "label": "Script Type",
"oldfieldname": "script_type", "oldfieldname": "script_type",
"oldfieldtype": "Select", "oldfieldtype": "Select",
@@ -29,16 +31,24 @@
{ {
"fieldname": "script", "fieldname": "script",
"fieldtype": "Code", "fieldtype": "Code",
"in_list_view": 1,
"label": "Script", "label": "Script",
"oldfieldname": "script", "oldfieldname": "script",
"oldfieldtype": "Code", "oldfieldtype": "Code",
"options": "Script", "options": "Script",
"permlevel": 0 "permlevel": 0
},
{
"fieldname": "sample",
"fieldtype": "HTML",
"label": "Sample",
"options": "<h3>Custom Script Help</h3>\n<p>Custom Scripts are executed only on the client-side (i.e. in Forms). Here are some examples to get you started</p>\n<pre><code>\n// additional validation on dates\ncur_frm.cscript.custom_validate = function(doc) {\n if (doc.from_date < get_today()) {\n msgprint(\"You can not select past date in From Date\");\n validated = false;\n }\n}\n\n// make a field read-only after saving\ncur_frm.cscript.custom_refresh = function(doc) {\n // use the __islocal value of doc, to check if the doc is saved or not\n cur_frm.set_df_property(\"myfield\", \"read_only\", doc.__islocal ? 0 : 1);\n}\n\n// addtional permission checking\ncur_frm.cscript.custom_validate = function(doc) {\n if(user==\"user1@example.com\" && doc.purpose!=\"Material Receipt\") {\n msgprint(\"You are only allowed Material Receipt\");\n validated = false;\n }\n}\n\n// calculate sales incentive\ncur_frm.cscript.custom_validate = function(doc) {\n // calculate incentives for each person on the deal\n total_incentive = 0\n $.each(wn.model.get(\"Sales Team\", {parent:doc.name}), function(i, d) {\n\n // calculate incentive\n var incentive_percent = 2;\n if(doc.grand_total &gt; 400) incentive_percent = 4;\n\n // actual incentive\n d.incentives = flt(doc.grand_total) * incentive_percent / 100;\n total_incentive += flt(d.incentives)\n });\n\n doc.total_incentive = total_incentive;\n}\n</code>\n</pre>",
"permlevel": 0
} }
], ],
"icon": "icon-glass", "icon": "icon-glass",
"idx": 1, "idx": 1,
"modified": "2014-01-20 17:48:31.000000",
"modified": "2014-06-19 06:55:02.522204",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Core", "module": "Core",
"name": "Custom Script", "name": "Custom Script",


+ 1
- 1
frappe/core/doctype/doctype/doctype.py 파일 보기

@@ -41,7 +41,7 @@ class DocType(Document):
frappe.db.sql('UPDATE tabDocType SET modified=%s WHERE `name`=%s', (now(), p[0])) frappe.db.sql('UPDATE tabDocType SET modified=%s WHERE `name`=%s', (now(), p[0]))


def scrub_field_names(self): def scrub_field_names(self):
restricted = ('name','parent','idx','owner','creation','modified','modified_by',
restricted = ('name','parent','creation','modified','modified_by',
'parentfield','parenttype',"file_list") 'parentfield','parenttype',"file_list")
for d in self.get("fields"): for d in self.get("fields"):
if d.fieldtype: if d.fieldtype:


+ 0
- 0
frappe/core/doctype/standard_reply/__init__.py 파일 보기


+ 71
- 0
frappe/core/doctype/standard_reply/standard_reply.json 파일 보기

@@ -0,0 +1,71 @@
{
"allow_import": 1,
"autoname": "field:subject",
"creation": "2014-06-19 05:20:26.331041",
"docstatus": 0,
"doctype": "DocType",
"document_type": "Transaction",
"fields": [
{
"fieldname": "subject",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Subject",
"permlevel": 0,
"reqd": 1
},
{
"fieldname": "response",
"fieldtype": "Text Editor",
"in_list_view": 1,
"label": "Response",
"permlevel": 0,
"reqd": 1
},
{
"default": "user",
"fieldname": "owner",
"fieldtype": "Link",
"hidden": 1,
"label": "Owner",
"options": "User",
"permlevel": 0
}
],
"icon": "icon-comment",
"modified": "2014-06-19 05:45:09.855045",
"modified_by": "Administrator",
"module": "Core",
"name": "Standard Reply",
"name_case": "",
"owner": "Administrator",
"permissions": [
{
"permlevel": 0,
"read": 1,
"role": "All"
},
{
"apply_user_permissions": 1,
"create": 1,
"permlevel": 0,
"read": 1,
"role": "All",
"write": 1
},
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"import": 1,
"permlevel": 0,
"read": 1,
"report": 1,
"role": "System Manager",
"write": 1
}
],
"sort_field": "modified",
"sort_order": "DESC"
}

+ 9
- 0
frappe/core/doctype/standard_reply/standard_reply.py 파일 보기

@@ -0,0 +1,9 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# For license information, please see license.txt

from __future__ import unicode_literals
import frappe
from frappe.model.document import Document

class StandardReply(Document):
pass

+ 72
- 72
frappe/core/doctype/system_settings/system_settings.json 파일 보기

@@ -1,100 +1,100 @@
{ {
"creation": "2014-04-17 16:53:52.640856",
"docstatus": 0,
"doctype": "DocType",
"document_type": "System",
"creation": "2014-04-17 16:53:52.640856",
"docstatus": 0,
"doctype": "DocType",
"document_type": "System",
"fields": [ "fields": [
{ {
"fieldname": "localization",
"fieldtype": "Section Break",
"label": "Localization",
"fieldname": "localization",
"fieldtype": "Section Break",
"label": "Localization",
"permlevel": 0 "permlevel": 0
},
},
{ {
"fieldname": "language",
"fieldtype": "Select",
"in_list_view": 1,
"label": "Language",
"options": "Loading...",
"permlevel": 0,
"reqd": 1,
"fieldname": "language",
"fieldtype": "Select",
"in_list_view": 1,
"label": "Language",
"options": "Loading...",
"permlevel": 0,
"reqd": 1,
"search_index": 0 "search_index": 0
},
},
{ {
"fieldname": "time_zone",
"fieldtype": "Select",
"label": "Time Zone",
"permlevel": 0,
"fieldname": "time_zone",
"fieldtype": "Select",
"label": "Time Zone",
"permlevel": 0,
"reqd": 1 "reqd": 1
},
},
{ {
"fieldname": "date_and_number_format",
"fieldtype": "Section Break",
"label": "Date and Number Format",
"fieldname": "date_and_number_format",
"fieldtype": "Section Break",
"label": "Date and Number Format",
"permlevel": 0 "permlevel": 0
},
},
{ {
"fieldname": "date_format",
"fieldtype": "Select",
"label": "Date Format",
"options": "yyyy-mm-dd\ndd-mm-yyyy\ndd/mm/yyyy\ndd.mm.yyyy\nmm/dd/yyyy\nmm-dd-yyyy",
"permlevel": 0,
"fieldname": "date_format",
"fieldtype": "Select",
"label": "Date Format",
"options": "yyyy-mm-dd\ndd-mm-yyyy\ndd/mm/yyyy\ndd.mm.yyyy\nmm/dd/yyyy\nmm-dd-yyyy",
"permlevel": 0,
"reqd": 1 "reqd": 1
},
},
{ {
"fieldname": "number_format",
"fieldtype": "Select",
"label": "Number Format",
"options": "#,###.##\n#.###,##\n# ###.##\n# ###,##\n#,###.###\n#,##,###.##\n#.###\n#,###",
"permlevel": 0,
"fieldname": "number_format",
"fieldtype": "Select",
"label": "Number Format",
"options": "#,###.##\n#.###,##\n# ###.##\n# ###,##\n#'###.##\n#, ###.##\n#,##,###.##\n#,###.###\n#.###\n#,###",
"permlevel": 0,
"reqd": 1 "reqd": 1
},
},
{ {
"fieldname": "float_precision",
"fieldtype": "Select",
"label": "Float Precision",
"options": "\n2\n3\n4\n5\n6",
"fieldname": "float_precision",
"fieldtype": "Select",
"label": "Float Precision",
"options": "\n2\n3\n4\n5\n6",
"permlevel": 0 "permlevel": 0
},
},
{ {
"fieldname": "security",
"fieldtype": "Section Break",
"label": "Security",
"fieldname": "security",
"fieldtype": "Section Break",
"label": "Security",
"permlevel": 0 "permlevel": 0
},
},
{ {
"default": "06:00",
"description": "Session Expiry in Hours e.g. 06:00",
"fieldname": "session_expiry",
"fieldtype": "Data",
"label": "Session Expiry",
"options": "",
"default": "06:00",
"description": "Session Expiry in Hours e.g. 06:00",
"fieldname": "session_expiry",
"fieldtype": "Data",
"label": "Session Expiry",
"options": "",
"permlevel": 0 "permlevel": 0
},
},
{ {
"description": "Run scheduled jobs only if checked",
"fieldname": "enable_scheduler",
"fieldtype": "Check",
"in_list_view": 0,
"label": "Enable Scheduled Jobs",
"description": "Run scheduled jobs only if checked",
"fieldname": "enable_scheduler",
"fieldtype": "Check",
"in_list_view": 0,
"label": "Enable Scheduled Jobs",
"permlevel": 0 "permlevel": 0
} }
],
"icon": "icon-cog",
"issingle": 1,
"modified": "2014-06-02 02:09:03.623094",
"modified_by": "Administrator",
"module": "Core",
"name": "System Settings",
"name_case": "",
"owner": "Administrator",
],
"icon": "icon-cog",
"issingle": 1,
"modified": "2014-06-18 02:09:03.623094",
"modified_by": "Administrator",
"module": "Core",
"name": "System Settings",
"name_case": "",
"owner": "Administrator",
"permissions": [ "permissions": [
{ {
"create": 1,
"permlevel": 0,
"read": 1,
"role": "System Manager",
"create": 1,
"permlevel": 0,
"read": 1,
"role": "System Manager",
"write": 1 "write": 1
} }
] ]
}
}

+ 2
- 1
frappe/core/page/data_import_tool/data_import_tool.js 파일 보기

@@ -161,7 +161,8 @@ frappe.pages['data-import-tool'].onload = function(wrapper) {
$("#dit-output").empty(); $("#dit-output").empty();


$.each(r.messages, function(i, v) { $.each(r.messages, function(i, v) {
var $p = $('<p>').html(v).appendTo('#dit-output');
var $p = $('<p></p>').html(frappe.markdown(v)).appendTo('#dit-output');
$("<hr>").appendTo('#dit-output');
if(v.substr(0,5)=='Error') { if(v.substr(0,5)=='Error') {
$p.css('color', 'red'); $p.css('color', 'red');
} else if(v.substr(0,8)=='Inserted') { } else if(v.substr(0,8)=='Inserted') {


+ 1
- 1
frappe/core/page/data_import_tool/importer.py 파일 보기

@@ -217,7 +217,7 @@ def upload(rows = None, submit_after_import=None, ignore_encoding_errors=False,
error = True error = True
if doc: if doc:
frappe.errprint(doc if isinstance(doc, dict) else doc.as_dict()) frappe.errprint(doc if isinstance(doc, dict) else doc.as_dict())
err_msg = frappe.local.message_log and "<br>".join(frappe.local.message_log) or cstr(e)
err_msg = frappe.local.message_log and "\n\n".join(frappe.local.message_log) or cstr(e)
ret.append('Error for row (#%d) %s : %s' % (row_idx + 1, ret.append('Error for row (#%d) %s : %s' % (row_idx + 1,
len(row)>1 and row[1] or "", err_msg)) len(row)>1 and row[1] or "", err_msg))
frappe.errprint(frappe.get_traceback()) frappe.errprint(frappe.get_traceback())


+ 1
- 1
frappe/country_info.json 파일 보기

@@ -2556,7 +2556,7 @@
"code": "ve", "code": "ve",
"number_format": "#,###.##" "number_format": "#,###.##"
}, },
"Viet Nam": {
"Vietnam": {
"code": "vn", "code": "vn",
"currency": "VND", "currency": "VND",
"currency_name": "Dong", "currency_name": "Dong",


+ 0
- 5
frappe/handler.py 파일 보기

@@ -87,11 +87,6 @@ def execute_cmd(cmd):
if ret: if ret:
frappe.response['message'] = ret frappe.response['message'] = ret


# update session
if "session_obj" in frappe.local:
frappe.local.session_obj.update()


def get_attr(cmd): def get_attr(cmd):
"""get method object from cmd""" """get method object from cmd"""
if '.' in cmd: if '.' in cmd:


+ 33
- 1
frappe/model/base_document.py 파일 보기

@@ -13,6 +13,7 @@ class BaseDocument(object):


def __init__(self, d): def __init__(self, d):
self.update(d) self.update(d)
self.dont_update_if_missing = []


@property @property
def meta(self): def meta(self):
@@ -42,7 +43,8 @@ class BaseDocument(object):
if "doctype" in d: if "doctype" in d:
self.set("doctype", d.get("doctype")) self.set("doctype", d.get("doctype"))
for key, value in d.iteritems(): for key, value in d.iteritems():
if self.get(key) is None:
# dont_update_if_missing is a list of fieldnames, for which, you don't want to set default value
if (self.get(key) is None) and (value is not None) and (key not in self.dont_update_if_missing):
self.set(key, value) self.set(key, value)


def get_db_value(self, key): def get_db_value(self, key):
@@ -162,6 +164,9 @@ class BaseDocument(object):
if doc[k] is None: if doc[k] is None:
del doc[k] del doc[k]


if self.get("_user_tags"):
doc["_user_tags"] = self.get("_user_tags")

if self.get("__islocal"): if self.get("__islocal"):
doc["__islocal"] = 1 doc["__islocal"] = 1


@@ -275,6 +280,33 @@ class BaseDocument(object):


return invalid_links return invalid_links


def _validate_selects(self):
if frappe.flags.in_import:
return

for df in self.meta.get_select_fields():
if not (self.get(df.fieldname) and df.options):
continue

options = (df.options or "").split("\n")

# if only empty options
if not filter(None, options):
continue

# strip and set
self.set(df.fieldname, cstr(self.get(df.fieldname)).strip())
value = self.get(df.fieldname)

if value not in options and not (frappe.flags.in_test and value.startswith("_T-")):
# show an elaborate message
prefix = _("Row #{0}:").format(self.idx) if self.get("parentfield") else ""
label = _(self.meta.get_label(df.fieldname))
comma_options = '", "'.join(_(each) for each in options)

frappe.throw(_('{0} {1} cannot be "{2}". It should be one of "{3}"').format(prefix, label,
value, comma_options))

def _validate_constants(self): def _validate_constants(self):
if frappe.flags.in_import: if frappe.flags.in_import:
return return


+ 5
- 0
frappe/model/document.py 파일 보기

@@ -48,6 +48,7 @@ def get_controller(doctype):
class Document(BaseDocument): class Document(BaseDocument):
def __init__(self, arg1, arg2=None): def __init__(self, arg1, arg2=None):
self.doctype = self.name = None self.doctype = self.name = None

if arg1 and isinstance(arg1, basestring): if arg1 and isinstance(arg1, basestring):
if not arg2: if not arg2:
# single # single
@@ -72,6 +73,8 @@ class Document(BaseDocument):
# incorrect arguments. let's not proceed. # incorrect arguments. let's not proceed.
raise frappe.DataError("Document({0}, {1})".format(arg1, arg2)) raise frappe.DataError("Document({0}, {1})".format(arg1, arg2))


self.dont_update_if_missing = []

def load_from_db(self): def load_from_db(self):
if not getattr(self, "_metaclass", False) and self.meta.issingle: if not getattr(self, "_metaclass", False) and self.meta.issingle:
self.update(frappe.db.get_singles_dict(self.doctype)) self.update(frappe.db.get_singles_dict(self.doctype))
@@ -225,8 +228,10 @@ class Document(BaseDocument):
def _validate(self): def _validate(self):
self._validate_mandatory() self._validate_mandatory()
self._validate_links() self._validate_links()
self._validate_selects()
self._validate_constants() self._validate_constants()
for d in self.get_all_children(): for d in self.get_all_children():
d._validate_selects()
d._validate_constants() d._validate_constants()


self._extract_images_from_text_editor() self._extract_images_from_text_editor()


+ 4
- 0
frappe/model/meta.py 파일 보기

@@ -61,6 +61,10 @@ class Meta(Document):
def get_link_fields(self): def get_link_fields(self):
return self.get("fields", {"fieldtype": "Link", "options":["!=", "[Select]"]}) return self.get("fields", {"fieldtype": "Link", "options":["!=", "[Select]"]})


def get_select_fields(self):
return self.get("fields", {"fieldtype": "Select", "options":["not in",
["[Select]", "Loading...", "attach_files:"]]})

def get_table_fields(self): def get_table_fields(self):
if not hasattr(self, "_table_fields"): if not hasattr(self, "_table_fields"):
if self.name!="DocType": if self.name!="DocType":


+ 1
- 0
frappe/patches.txt 파일 보기

@@ -40,3 +40,4 @@ execute:import frappe.website.render; frappe.website.render.clear_cache("login")
frappe.patches.v4_0.fix_attach_field_file_url frappe.patches.v4_0.fix_attach_field_file_url
execute:frappe.reset_perms("User") #2014-06-13 execute:frappe.reset_perms("User") #2014-06-13
execute:frappe.db.sql("""delete from `tabUserRole` where ifnull(parentfield, '')=''""") #2014-06-17 execute:frappe.db.sql("""delete from `tabUserRole` where ifnull(parentfield, '')=''""") #2014-06-17
frappe.patches.v4_0.remove_user_owner_custom_field

+ 10
- 0
frappe/patches/v4_0/remove_user_owner_custom_field.py 파일 보기

@@ -0,0 +1,10 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# MIT License. See license.txt

from __future__ import unicode_literals
import frappe

def execute():
user_owner = frappe.db.get_value("Custom Field", {"fieldname": "user_owner"})
if user_owner:
frappe.delete_doc("Custom Field", user_owner)

+ 0
- 8
frappe/public/js/frappe/desk.js 파일 보기

@@ -1,14 +1,6 @@
// Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors // Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
// MIT License. See license.txt // MIT License. See license.txt


if(!console) {
var console = {
log: function(txt) {
// suppress
}
}
}

$(document).ready(function() { $(document).ready(function() {
frappe.assets.check(); frappe.assets.check();
frappe.provide('frappe.app'); frappe.provide('frappe.app');


+ 3
- 1
frappe/public/js/frappe/misc/number_format.js 파일 보기

@@ -60,8 +60,10 @@ frappe.number_format_info = {
"#.###,##": {decimal_str:",", group_sep:".", precision:2}, "#.###,##": {decimal_str:",", group_sep:".", precision:2},
"# ###.##": {decimal_str:".", group_sep:" ", precision:2}, "# ###.##": {decimal_str:".", group_sep:" ", precision:2},
"# ###,##": {decimal_str:",", group_sep:" ", precision:2}, "# ###,##": {decimal_str:",", group_sep:" ", precision:2},
"#,###.###": {decimal_str:".", group_sep:",", precision:3},
"#'###.##": {decimal_str:".", group_sep:"'", precision:2},
"#, ###.##": {decimal_str:".", group_sep:", ", precision:2},
"#,##,###.##": {decimal_str:".", group_sep:",", precision:2}, "#,##,###.##": {decimal_str:".", group_sep:",", precision:2},
"#,###.###": {decimal_str:".", group_sep:",", precision:3},
"#.###": {decimal_str:"", group_sep:".", precision:0}, "#.###": {decimal_str:"", group_sep:".", precision:0},
"#,###": {decimal_str:"", group_sep:",", precision:0}, "#,###": {decimal_str:"", group_sep:",", precision:0},
} }


+ 1
- 1
frappe/public/js/frappe/ui/filters.js 파일 보기

@@ -255,7 +255,7 @@ frappe.ui.Filter = Class.extend({
if(df.fieldtype=='Check') { if(df.fieldtype=='Check') {
df.fieldtype='Select'; df.fieldtype='Select';
df.options='No\nYes'; df.options='No\nYes';
} else if(['Text','Small Text','Text Editor','Code','Tags','Comments'].indexOf(df.fieldtype)!=-1) {
} else if(['Text','Small Text','Text Editor','Code','Tag','Comments'].indexOf(df.fieldtype)!=-1) {
df.fieldtype = 'Data'; df.fieldtype = 'Data';
} else if(df.fieldtype=='Link' && this.$w.find('.condition').val()!="=") { } else if(df.fieldtype=='Link' && this.$w.find('.condition').val()!="=") {
df.fieldtype = 'Data'; df.fieldtype = 'Data';


+ 1
- 1
frappe/public/js/frappe/ui/toolbar/toolbar.js 파일 보기

@@ -45,7 +45,7 @@ frappe.ui.toolbar.Toolbar = Class.extend({
placeholder="' + __("Search or type a command") + '" \ placeholder="' + __("Search or type a command") + '" \
style="padding: 2px 6px; height: 24px; margin-top: 5px; \ style="padding: 2px 6px; height: 24px; margin-top: 5px; \
margin-left: 10px; background-color: #ddd; \ margin-left: 10px; background-color: #ddd; \
min-width: 230px; \
min-width: 230px; font-size: 85%;\
border-radius: 10px;">\ border-radius: 10px;">\
</div>\ </div>\
</form>\ </form>\


+ 33
- 0
frappe/public/js/frappe/views/communication.js 파일 보기

@@ -113,6 +113,7 @@ frappe.views.CommunicationList = Class.extend({
}); });


frappe.last_edited_communication = {}; frappe.last_edited_communication = {};
frappe.standard_replies = {};


frappe.views.CommunicationComposer = Class.extend({ frappe.views.CommunicationComposer = Class.extend({
init: function(opts) { init: function(opts) {
@@ -129,6 +130,8 @@ frappe.views.CommunicationComposer = Class.extend({
description:__("Email addresses, separted by commas")}, description:__("Email addresses, separted by commas")},
{label:__("Subject"), fieldtype:"Data", reqd: 1, {label:__("Subject"), fieldtype:"Data", reqd: 1,
fieldname:"subject"}, fieldname:"subject"},
{label:__("Standard Reply"), fieldtype:"Link", options:"Standard Reply",
fieldname:"standard_reply"},
{label:__("Message"), fieldtype:"Text Editor", reqd: 1, {label:__("Message"), fieldtype:"Text Editor", reqd: 1,
fieldname:"content"}, fieldname:"content"},
{label:__("Send As Email"), fieldtype:"Check", {label:__("Send As Email"), fieldtype:"Check",
@@ -155,6 +158,7 @@ frappe.views.CommunicationComposer = Class.extend({
this.dialog.$wrapper.find("[data-edit='outdent']").remove(); this.dialog.$wrapper.find("[data-edit='outdent']").remove();
this.dialog.get_input("send").addClass("btn-primary"); this.dialog.get_input("send").addClass("btn-primary");



$(document).on("upload_complete", function(event, attachment) { $(document).on("upload_complete", function(event, attachment) {
if(me.dialog.display) { if(me.dialog.display) {
var wrapper = $(me.dialog.fields_dict.select_attachments.wrapper); var wrapper = $(me.dialog.fields_dict.select_attachments.wrapper);
@@ -185,10 +189,39 @@ frappe.views.CommunicationComposer = Class.extend({
this.setup_email(); this.setup_email();
this.setup_autosuggest(); this.setup_autosuggest();
this.setup_last_edited_communication(); this.setup_last_edited_communication();
this.setup_standard_reply();
$(this.dialog.fields_dict.recipients.input).val(this.recipients || "").change(); $(this.dialog.fields_dict.recipients.input).val(this.recipients || "").change();
$(this.dialog.fields_dict.subject.input).val(this.subject || "").change(); $(this.dialog.fields_dict.subject.input).val(this.subject || "").change();
this.setup_earlier_reply(); this.setup_earlier_reply();
}, },

setup_standard_reply: function() {
var me = this;
this.dialog.get_input("standard_reply").on("change", function() {
var standard_reply = $(this).val();
var prepend_reply = function() {
var content_field = me.dialog.fields_dict.content;
var content = content_field.get_value() || "";
content_field.set_input(
frappe.standard_replies[standard_reply]
+ "<br><br>" + content);
}
if(frappe.standard_replies[standard_reply]) {
prepend_reply();
} else {
$.ajax({
url:"/api/resource/Standard Reply/" + standard_reply,
statusCode: {
200: function(data) {
frappe.standard_replies[standard_reply] = data.data.response;
prepend_reply();
}
}
});
}
});
},

setup_last_edited_communication: function() { setup_last_edited_communication: function() {
var me = this; var me = this;
this.dialog.onhide = function() { this.dialog.onhide = function() {


+ 1
- 1
frappe/public/js/frappe/views/doclistview.js 파일 보기

@@ -238,7 +238,7 @@ frappe.views.DocListView = frappe.ui.Listing.extend({
init_minbar: function() { init_minbar: function() {
var me = this; var me = this;
this.appframe.add_icon_btn("2", 'icon-tag', __('Show Tags'), function() { me.toggle_tags(); }); this.appframe.add_icon_btn("2", 'icon-tag', __('Show Tags'), function() { me.toggle_tags(); });
this.wrapper.on("click", ".list-tag-preview", function() { me.toggle_tags(); });
this.$page.on("click", ".list-tag-preview", function() { me.toggle_tags(); });
if(this.can_delete || this.listview.settings.selectable) { if(this.can_delete || this.listview.settings.selectable) {
this.appframe.add_icon_btn("2", 'icon-remove', __('Delete'), function() { me.delete_items(); }); this.appframe.add_icon_btn("2", 'icon-remove', __('Delete'), function() { me.delete_items(); });
this.appframe.add_icon_btn("2", 'icon-ok', __('Select All'), function() { this.appframe.add_icon_btn("2", 'icon-ok', __('Select All'), function() {


+ 2
- 0
frappe/public/js/frappe/views/reportview.js 파일 보기

@@ -397,12 +397,14 @@ frappe.views.ReportView = frappe.ui.Listing.extend({
this.$w.find('.result-list').on("click", ".label-info", function() { this.$w.find('.result-list').on("click", ".label-info", function() {
if($(this).attr("data-label")) { if($(this).attr("data-label")) {
me.set_filter("_user_tags", $(this).attr("data-label")); me.set_filter("_user_tags", $(this).attr("data-label"));
me.refresh();
} }
}); });
this.$w.find('.result-list').on("click", "[data-workflow-state]", function() { this.$w.find('.result-list').on("click", "[data-workflow-state]", function() {
if($(this).attr("data-workflow-state")) { if($(this).attr("data-workflow-state")) {
me.set_filter(me.state_fieldname, me.set_filter(me.state_fieldname,
$(this).attr("data-workflow-state")); $(this).attr("data-workflow-state"));
me.refresh();
} }
}); });
}, },


+ 15
- 12
frappe/public/js/frappe/views/sidebar_stats.js 파일 보기

@@ -3,7 +3,7 @@


frappe.provide('frappe.views'); frappe.provide('frappe.views');


// opts:
// opts:
// stats = list of fields // stats = list of fields
// doctype // doctype
// parent // parent
@@ -29,7 +29,7 @@ frappe.views.SidebarStats = Class.extend({
$.each(me.stats, function(i, v) { $.each(me.stats, function(i, v) {
me.render_stat(v, (r.message || {})[v]); me.render_stat(v, (r.message || {})[v]);
}); });
// reload button at the end // reload button at the end
if(me.stats.length) { if(me.stats.length) {
$('<a class="small"><i class="refresh"></i> '+__('Refresh')+'</a>') $('<a class="small"><i class="refresh"></i> '+__('Refresh')+'</a>')
@@ -46,11 +46,14 @@ frappe.views.SidebarStats = Class.extend({
}, },
render_stat: function(field, stat) { render_stat: function(field, stat) {
var me = this; var me = this;
var show_tags = '<a class="list-tag-preview small" style="margin-left: 7px;">'
+__("Show tags") +'</a>';


if(!stat || !stat.length) { if(!stat || !stat.length) {
if(field==='_user_tags') { if(field==='_user_tags') {
$('<div class="side-panel">\ $('<div class="side-panel">\
<h5 class="text-muted"><i class="icon-tag"></i> '+__('Tags')+'</h5>\
<h5 class="text-muted"><i class="icon-tag">\
</i> '+__('Tags')+show_tags+'</h5>\
<div class="side-panel-body">\ <div class="side-panel-body">\
<div class="text-muted small"><i>'+__('No records tagged.')+'</i><br>' <div class="text-muted small"><i>'+__('No records tagged.')+'</i><br>'
+'</div>\ +'</div>\
@@ -59,9 +62,9 @@ frappe.views.SidebarStats = Class.extend({
return; return;
} }


var label = frappe.meta.docfield_map[this.doctype][field] ?
var label = frappe.meta.docfield_map[this.doctype][field] ?
frappe.meta.docfield_map[this.doctype][field].label : field; frappe.meta.docfield_map[this.doctype][field].label : field;
if(label==='_user_tags') label = 'Tags';
if(label==='_user_tags') label = 'Tags' + show_tags;


// grid // grid
var $w = $('<div class="side-panel">\ var $w = $('<div class="side-panel">\
@@ -76,12 +79,12 @@ frappe.views.SidebarStats = Class.extend({
$.each(stat, function(i,v) { sum = sum + v[1]; }) $.each(stat, function(i,v) { sum = sum + v[1]; })


// render items // render items
$.each(stat, function(i, v) {
$.each(stat, function(i, v) {
me.render_stat_item(i, v, sum, field).appendTo($w.find('.side-panel-body')); me.render_stat_item(i, v, sum, field).appendTo($w.find('.side-panel-body'));
}); });


$w.appendTo(this.wrapper); $w.appendTo(this.wrapper);
},
},
render_stat_item: function(i, v, max, field) { render_stat_item: function(i, v, max, field) {
var me = this; var me = this;
var args = {} var args = {}
@@ -91,8 +94,8 @@ frappe.views.SidebarStats = Class.extend({
args.count = v[1]; args.count = v[1];
args.field = field; args.field = field;
args.bar_style = ""; args.bar_style = "";
$item = $(repl('<div class="progress">\
$item = $(repl('<div class="progress" style="height: 7px;">\
<div class="progress-bar %(bar_style)s" style="width: %(width)s%"></div>\ <div class="progress-bar %(bar_style)s" style="width: %(width)s%"></div>\
</div>\ </div>\
<div class="stat-label" style="margin-top: -19px; text-align: center; \ <div class="stat-label" style="margin-top: -19px; text-align: center; \
@@ -100,7 +103,7 @@ frappe.views.SidebarStats = Class.extend({
<a href="#" data-label="%(label)s" data-field="%(field)s">\ <a href="#" data-label="%(label)s" data-field="%(field)s">\
%(_label)s</a> (%(count)s)\ %(_label)s</a> (%(count)s)\
</div>', args)); </div>', args));
this.setup_stat_item_click($item); this.setup_stat_item_click($item);
return $item; return $item;
}, },
@@ -116,5 +119,5 @@ frappe.views.SidebarStats = Class.extend({
me.set_filter(fieldname, label); me.set_filter(fieldname, label);
return false; return false;
}); });
},
});
},
});

+ 6
- 2
frappe/public/js/legacy/print_format.js 파일 보기

@@ -285,8 +285,9 @@ $.extend(_p, {


// This is used to calculate and substitude values in the HTML // This is used to calculate and substitude values in the HTML
run_embedded_js: function(container, doc) { run_embedded_js: function(container, doc) {
script_list = $(container).find("script");
for(var i=0; i<script_list.length; i++) {
var script_list = $(container).find("script");

for(var i=0, j=script_list.length; i<j; i++) {
var element = script_list[i]; var element = script_list[i];
var code = element.innerHTML; var code = element.innerHTML;
var new_html = code ? (eval(code) || "") : ""; var new_html = code ? (eval(code) || "") : "";
@@ -294,6 +295,9 @@ $.extend(_p, {
$(element).replaceWith(this.add_span(new_html + "")); $(element).replaceWith(this.add_span(new_html + ""));
} }
} }

// remove scripts once executed
$(container).find("script").remove();
}, },


add_span: function(html) { add_span: function(html) {


+ 17
- 14
frappe/sessions.py 파일 보기

@@ -250,29 +250,32 @@ class Session:


def update(self, force=False): def update(self, force=False):
"""extend session expiry""" """extend session expiry"""
self.data['data']['last_updated'] = frappe.utils.now()
self.data['data']['lang'] = unicode(frappe.lang)
if (frappe.session['user'] == "Guest" or frappe.form_dict.cmd=="logout"):
return

now = frappe.utils.now()


self.data['data']['last_updated'] = now
self.data['data']['lang'] = unicode(frappe.lang)


# update session in db # update session in db
time_diff = None
last_updated = frappe.cache().get_value("last_db_session_update:" + self.sid) last_updated = frappe.cache().get_value("last_db_session_update:" + self.sid)
time_diff = frappe.utils.time_diff_in_seconds(now, last_updated) if last_updated else None


if last_updated:
time_diff = frappe.utils.time_diff_in_seconds(frappe.utils.now(),
last_updated)

if force or (frappe.session['user'] != 'Guest' and \
((time_diff==None) or (time_diff > 1800))):
# database persistence is secondary, don't update it too often
# database persistence is secondary, don't update it too often
updated_in_db = False
if force or (time_diff==None) or (time_diff > 600):
frappe.db.sql("""update tabSessions set sessiondata=%s, frappe.db.sql("""update tabSessions set sessiondata=%s,
lastupdate=NOW() where sid=%s""" , (str(self.data['data']), lastupdate=NOW() where sid=%s""" , (str(self.data['data']),
self.data['sid'])) self.data['sid']))


if frappe.form_dict.cmd not in ("frappe.sessions.clear", "logout"):
frappe.cache().set_value("last_db_session_update:" + self.sid,
frappe.utils.now())
frappe.cache().set_value("session:" + self.sid, self.data)
updated_in_db = True

# set in memcache
frappe.cache().set_value("last_db_session_update:" + self.sid, now)
frappe.cache().set_value("session:" + self.sid, self.data)

return updated_in_db


def get_expiry_period(): def get_expiry_period():
exp_sec = frappe.defaults.get_global_default("session_expiry") or "06:00:00" exp_sec = frappe.defaults.get_global_default("session_expiry") or "06:00:00"


+ 2
- 3
frappe/templates/includes/navbar.html 파일 보기

@@ -55,9 +55,8 @@
{%- endfor -%} {%- endfor -%}
</ul> </ul>
</li> </li>
{% if not disable_signup %}
<li class="btn-login-area"><a href="/login">Sign Up / Login</a></li>
{% endif %}
<li class="btn-login-area"><a href="/login">
{%- if not disable_signup %}Sign Up / {% endif -%} Login</a></li>
</ul> </ul>
</div> </div>
</div> </div>


+ 6
- 3
frappe/utils/__init__.py 파일 보기

@@ -393,13 +393,16 @@ def fmt_money(amount, precision=None, currency=None):
return amount return amount


number_format_info = { number_format_info = {
"#.###": ("", ".", 0),
"#,###": ("", ",", 0),
"#,###.##": (".", ",", 2), "#,###.##": (".", ",", 2),
"#,##,###.##": (".", ",", 2),
"#.###,##": (",", ".", 2), "#.###,##": (",", ".", 2),
"# ###.##": (".", " ", 2), "# ###.##": (".", " ", 2),
"# ###,##": (",", " ", 2),
"#'###.##": (".", "'", 2),
"#, ###.##": (".", ", ", 2),
"#,##,###.##": (".", ",", 2),
"#,###.###": (".", ",", 3), "#,###.###": (".", ",", 3),
"#.###": ("", ".", 0),
"#,###": ("", ",", 0)
} }


def get_number_format_info(format): def get_number_format_info(format):


불러오는 중...
취소
저장