Merge remote-tracking branch 'webnotes/4.0.0-wip' into permissions

Conflicts:
	erpnext/accounts/page/accounts_browser/accounts_browser.css
	erpnext/controllers/buying_controller.py
	erpnext/manufacturing/doctype/production_order/production_order.py
	erpnext/patches/patch_list.py
	erpnext/selling/doctype/customer/customer.txt
	erpnext/selling/doctype/sales_order/sales_order.py
	erpnext/selling/doctype/sales_order/test_sales_order.py
	erpnext/setup/doctype/features_setup/features_setup.txt
	erpnext/stock/doctype/stock_entry/test_stock_entry.py
	erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py
	startup/query_handlers.py
This commit is contained in:
Anand Doshi
2013-12-26 18:30:39 +05:30
1813 changed files with 12064 additions and 18858 deletions

97
erpnext/home/__init__.py Normal file
View File

@@ -0,0 +1,97 @@
# ERPNext - web based ERP (http://erpnext.com)
# Copyright (C) 2012 Web Notes Technologies Pvt Ltd
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from __future__ import unicode_literals
import webnotes
from webnotes import msgprint
feed_dict = {
# Project
'Project': ['[%(status)s]', '#000080'],
'Task': ['[%(status)s] %(subject)s', '#000080'],
# Sales
'Lead': ['%(lead_name)s', '#000080'],
'Quotation': ['[%(status)s] To %(customer_name)s worth %(currency)s %(grand_total_export)s', '#4169E1'],
'Sales Order': ['[%(status)s] To %(customer_name)s worth %(currency)s %(grand_total_export)s', '#4169E1'],
# Purchase
'Supplier': ['%(supplier_name)s, %(supplier_type)s', '#6495ED'],
'Purchase Order': ['[%(status)s] %(name)s To %(supplier_name)s for %(currency)s %(grand_total_import)s', '#4169E1'],
# Stock
'Delivery Note': ['[%(status)s] To %(customer_name)s', '#4169E1'],
'Purchase Receipt': ['[%(status)s] From %(supplier)s', '#4169E1'],
# Accounts
'Journal Voucher': ['[%(voucher_type)s] %(name)s', '#4169E1'],
'Purchase Invoice': ['To %(supplier_name)s for %(currency)s %(grand_total_import)s', '#4169E1'],
'Sales Invoice':['To %(customer_name)s for %(currency)s %(grand_total_export)s', '#4169E1'],
# HR
'Expense Claim': ['[%(approval_status)s] %(name)s by %(employee_name)s', '#4169E1'],
'Salary Slip': ['%(employee_name)s for %(month)s %(fiscal_year)s', '#4169E1'],
'Leave Transaction':['%(leave_type)s for %(employee)s', '#4169E1'],
# Support
'Customer Issue': ['[%(status)s] %(description)s by %(customer_name)s', '#000080'],
'Maintenance Visit':['To %(customer_name)s', '#4169E1'],
'Support Ticket': ["[%(status)s] %(subject)s", '#000080'],
# Website
'Web Page': ['%(title)s', '#000080'],
'Blog': ['%(title)s', '#000080']
}
def make_feed(feedtype, doctype, name, owner, subject, color):
"makes a new Feed record"
#msgprint(subject)
from webnotes.model.doc import Document
from webnotes.utils import get_fullname
if feedtype in ('Login', 'Comment', 'Assignment'):
# delete old login, comment feed
webnotes.conn.sql("""delete from tabFeed where
datediff(curdate(), creation) > 7 and doc_type in ('Comment', 'Login', 'Assignment')""")
else:
# one feed per item
webnotes.conn.sql("""delete from tabFeed
where doc_type=%s and doc_name=%s
and ifnull(feed_type,'') != 'Comment'""", (doctype, name))
f = Document('Feed')
f.owner = owner
f.feed_type = feedtype
f.doc_type = doctype
f.doc_name = name
f.subject = subject
f.color = color
f.full_name = get_fullname(owner)
f.save()
def update_feed(controller, method=None):
"adds a new feed"
doc = controller.doc
if method in ['on_update', 'on_submit']:
subject, color = feed_dict.get(doc.doctype, [None, None])
if subject:
make_feed('', doc.doctype, doc.name, doc.owner, subject % doc.fields, color)
def make_comment_feed(bean, method):
"""add comment to feed"""
doc = bean.doc
make_feed('Comment', doc.comment_doctype, doc.comment_docname, doc.comment_by,
'<i>"' + doc.comment + '"</i>', '#6B24B3')

View File

@@ -0,0 +1 @@
from __future__ import unicode_literals

View File

@@ -0,0 +1 @@
Activity Feed.

View File

@@ -0,0 +1 @@
from __future__ import unicode_literals

View File

@@ -0,0 +1,22 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
import webnotes
from webnotes.model import db_exists
from webnotes.model.bean import copy_doclist
class DocType:
def __init__(self,d,dl):
self.doc, self.doclist = d, dl
def on_doctype_update():
if not webnotes.conn.sql("""show index from `tabFeed`
where Key_name="feed_doctype_docname_index" """):
webnotes.conn.commit()
webnotes.conn.sql("""alter table `tabFeed`
add index feed_doctype_docname_index(doc_type, doc_name)""")

View File

@@ -0,0 +1,80 @@
[
{
"creation": "2012-07-03 13:29:42",
"docstatus": 0,
"modified": "2013-12-20 19:24:07",
"modified_by": "Administrator",
"owner": "Administrator"
},
{
"autoname": "_FEED.#####",
"doctype": "DocType",
"icon": "icon-rss",
"module": "Home",
"name": "__common__"
},
{
"doctype": "DocField",
"name": "__common__",
"parent": "Feed",
"parentfield": "fields",
"parenttype": "DocType",
"permlevel": 0
},
{
"doctype": "DocPerm",
"email": 1,
"name": "__common__",
"parent": "Feed",
"parentfield": "permissions",
"parenttype": "DocType",
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager"
},
{
"doctype": "DocType",
"name": "Feed"
},
{
"doctype": "DocField",
"fieldname": "feed_type",
"fieldtype": "Select",
"label": "Feed Type"
},
{
"doctype": "DocField",
"fieldname": "doc_type",
"fieldtype": "Data",
"label": "Doc Type"
},
{
"doctype": "DocField",
"fieldname": "doc_name",
"fieldtype": "Data",
"label": "Doc Name"
},
{
"doctype": "DocField",
"fieldname": "subject",
"fieldtype": "Data",
"label": "Subject"
},
{
"doctype": "DocField",
"fieldname": "color",
"fieldtype": "Data",
"label": "Color"
},
{
"doctype": "DocField",
"fieldname": "full_name",
"fieldtype": "Data",
"label": "Full Name"
},
{
"doctype": "DocPerm"
}
]

View File

@@ -0,0 +1 @@
from __future__ import unicode_literals

View File

@@ -0,0 +1 @@
List of latest activities based on Feed.

View File

@@ -0,0 +1 @@
from __future__ import unicode_literals

View File

@@ -0,0 +1,23 @@
#page-activity .label {
display: inline-block;
width: 100px;
margin-right: 7px;
}
#page-activity .label-info {
cursor: pointer;
}
#page-activity .user-info {
float: right;
color: #777;
font-size: 10px;
}
#page-activity .date-sep {
margin: 0px -15px 11px -15px;
padding: 5px 0px;
border-bottom: 2px solid #aaa;
color: #555;
font-size: 10px;
}

View File

@@ -0,0 +1,88 @@
// Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
wn.pages['activity'].onload = function(wrapper) {
wn.ui.make_app_page({
parent: wrapper,
title: wn._("Activity"),
single_column: true
})
wrapper.appframe.add_module_icon("Activity");
var list = new wn.ui.Listing({
hide_refresh: true,
appframe: wrapper.appframe,
method: 'erpnext.home.page.activity.activity.get_feed',
parent: $(wrapper).find(".layout-main"),
render_row: function(row, data) {
new erpnext.ActivityFeed(row, data);
}
});
list.run();
wrapper.appframe.set_title_right("Refresh", function() { list.run(); });
// Build Report Button
if(wn.boot.profile.can_get_report.indexOf("Feed")!=-1) {
wrapper.appframe.add_primary_action(wn._('Build Report'), function() {
wn.set_route('Report', "Feed");
}, 'icon-th')
}
}
erpnext.last_feed_date = false;
erpnext.ActivityFeed = Class.extend({
init: function(row, data) {
this.scrub_data(data);
this.add_date_separator(row, data);
if(!data.add_class) data.add_class = "label-default";
$(row).append(repl('<div style="margin: 0px">\
<span class="avatar avatar-small"><img src="%(imgsrc)s" /></span> \
<span %(onclick)s class="label %(add_class)s">%(feed_type)s</span>\
%(link)s %(subject)s <span class="user-info">%(by)s</span></div>', data));
},
scrub_data: function(data) {
data.by = wn.user_info(data.owner).fullname;
data.imgsrc = wn.utils.get_file_link(wn.user_info(data.owner).image);
// feedtype
if(!data.feed_type) {
data.feed_type = wn._(data.doc_type);
data.add_class = "label-info";
data.onclick = repl('onclick="window.location.href=\'#!List/%(feed_type)s\';"', data)
}
// color for comment
if(data.feed_type=='Comment') {
data.add_class = "label-danger";
}
if(data.feed_type=='Assignment') {
data.add_class = "label-warning";
}
// link
if(data.doc_name && data.feed_type!='Login') {
data.link = wn.format(data.doc_name, {"fieldtype":"Link", "options":data.doc_type})
} else {
data.link = "";
}
},
add_date_separator: function(row, data) {
var date = dateutil.str_to_obj(data.modified);
var last = erpnext.last_feed_date;
if((last && dateutil.obj_to_str(last) != dateutil.obj_to_str(date)) || (!last)) {
var diff = dateutil.get_day_diff(new Date(), date);
if(diff < 1) {
pdate = 'Today';
} else if(diff < 2) {
pdate = 'Yesterday';
} else {
pdate = dateutil.global_date_format(date);
}
$(row).html(repl('<div class="date-sep">%(date)s</div>', {date: pdate}));
}
erpnext.last_feed_date = date;
}
})

View File

@@ -0,0 +1,21 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
import webnotes
@webnotes.whitelist()
def get_feed(arg=None):
"""get feed"""
return webnotes.conn.sql("""select
distinct t1.name, t1.feed_type, t1.doc_type, t1.doc_name, t1.subject, t1.owner,
t1.modified
from tabFeed t1, tabDocPerm t2
where t1.doc_type = t2.parent
and t2.role in ('%s')
and t2.permlevel = 0
and ifnull(t2.`read`,0) = 1
order by t1.modified desc
limit %s, %s""" % ("','".join(webnotes.get_roles()),
webnotes.form_dict['limit_start'], webnotes.form_dict['limit_page_length']),
as_dict=1)

View File

@@ -0,0 +1,33 @@
[
{
"creation": "2013-04-09 11:45:31",
"docstatus": 0,
"modified": "2013-07-11 14:40:20",
"modified_by": "Administrator",
"owner": "Administrator"
},
{
"doctype": "Page",
"icon": "icon-play",
"module": "Home",
"name": "__common__",
"page_name": "activity",
"standard": "Yes",
"title": "Activity"
},
{
"doctype": "Page Role",
"name": "__common__",
"parent": "activity",
"parentfield": "roles",
"parenttype": "Page",
"role": "All"
},
{
"doctype": "Page",
"name": "activity"
},
{
"doctype": "Page Role"
}
]

View File

@@ -0,0 +1 @@
Update log.

View File

@@ -0,0 +1,50 @@
// Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
wn.pages['latest-updates'].onload = function(wrapper) {
wn.ui.make_app_page({
parent: wrapper,
title: wn._('Latest Updates'),
single_column: true
});
var parent = $(wrapper).find(".layout-main");
parent.html('<div class="progress progress-striped active">\
<div class="progress-bar" style="width: 100%;"></div></div>')
return wn.call({
method: "erpnext.home.page.latest_updates.latest_updates.get",
callback: function(r) {
parent.empty();
$("<p class='help'>"+wn._("Report issues at")+
"<a href='https://github.com/webnotes/erpnext/issues'>"+wn._("GitHub Issues")+"</a></p>\
<hr><h3>"+wn._("Commit Log")+"</h3>")
.appendTo(parent);
var $tbody = $('<table class="table table-bordered"><tbody></tbody></table>')
.appendTo(parent).find("tbody");
$.each(r.message, function(i, log) {
if(log.message.indexOf("minor")===-1
&& log.message.indexOf("docs")===-1
&& log.message.indexOf("[")!==-1) {
log.message = log.message.replace(/(\[[^\]]*\])/g,
function(match, p1, offset, string) {
match = match.toLowerCase();
var color_class = "";
$.each(["bug", "fix"], function(i, v) {
if(!color_class && match.indexOf(v)!==-1)
color_class = "label-danger";
});
return '<span class="label ' + color_class +'">' + p1.slice(1,-1) + '</span> '
});
log.repo = log.repo==="lib" ? "wnframework" : "erpnext";
$(repl('<tr>\
<td><b><a href="https://github.com/webnotes/%(repo)s/commit/%(commit)s" \
target="_blank">%(message)s</b>\
<br><span class="text-muted">By %(author)s on %(date)s</span></td></tr>', log)).appendTo($tbody);
}
})
}
})
};

View File

@@ -0,0 +1,63 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
import webnotes, os, subprocess, tempfile, json, datetime
@webnotes.whitelist()
def get():
with open("../app/home/page/latest_updates/latest_updates.json", "r") as lufile:
return json.loads(lufile.read())
def make():
def add_to_logs(out, repo):
out.seek(0)
last_commit = None
for l in out.readlines():
l = l.decode('utf-8')
if last_commit is not None:
if l.startswith("Date:"):
last_commit["date"] = l[8:-1]
last_commit["datetime"] = datetime.datetime.strptime(last_commit["date"][:-6], "%a %b %d %H:%M:%S %Y")
if l.startswith("Author:"):
last_commit["author"] = l[8:-1]
if l.startswith(" "):
last_commit["message"] = l[4:-1]
if l.startswith("commit"):
last_commit = {
"repo": repo,
"commit": l.split(" ")[1][:-1]
}
logs.append(last_commit)
os.chdir("lib")
logs = []
out_lib = tempfile.TemporaryFile()
subprocess.call("git --no-pager log -n 200 --no-color", shell=True, stdout=out_lib)
add_to_logs(out_lib, "lib")
os.chdir("../app")
out_app = tempfile.TemporaryFile()
subprocess.call("git --no-pager log -n 200 --no-color", shell=True, stdout=out_app)
add_to_logs(out_app, "app")
logs.sort(key=lambda a: a["datetime"], reverse=True)
for a in logs:
del a["datetime"]
for i in xrange(len(logs)):
if i and logs[i]["message"]==logs[i-1]["message"]:
logs[i]["delete"] = True
if logs[i]["message"].startswith("Merge branch") or "[" not in logs[i]["message"]:
logs[i]["delete"] = True
logs = filter(lambda a: a if not a.get("delete") else None, logs)
os.chdir("..")
with open("app/home/page/latest_updates/latest_updates.json", "w") as lufile:
lufile.write(json.dumps(logs, indent=1, sort_keys=True))
if __name__=="__main__":
make()

View File

@@ -0,0 +1,33 @@
[
{
"creation": "2012-11-19 12:06:54",
"docstatus": 0,
"modified": "2013-07-11 14:43:20",
"modified_by": "Administrator",
"owner": "Administrator"
},
{
"doctype": "Page",
"icon": "icon-asterisk",
"module": "Home",
"name": "__common__",
"page_name": "latest-updates",
"standard": "Yes",
"title": "Latest Updates"
},
{
"doctype": "Page Role",
"name": "__common__",
"parent": "latest-updates",
"parentfield": "roles",
"parenttype": "Page",
"role": "All"
},
{
"doctype": "Page",
"name": "latest-updates"
},
{
"doctype": "Page Role"
}
]