Merge branch 'responsive' of github.com:webnotes/erpnext into responsive

This commit is contained in:
Anand Doshi 2013-07-16 13:00:10 +05:30
commit 8ffc42594a
4 changed files with 378 additions and 162 deletions

View File

@ -19,10 +19,4 @@ Tabs!
### Copyright ### Copyright
The ERPNext code is licensed as GNU General Public License (v3) and the Documentation is licensed as Creative Commons (CC-BY-SA-3.0) and the copyright is owned by Web Notes Technologies Pvt Ltd (Web Notes). Unless otherwise asserted in the code files, Web Notes will own the copyright of all contributions too. That means Web Notes holds the rights to change the license in the future or offer Commercial Licenses. Please see README.md
We will only accept copyright assertions in case of a significant contribution like a whole new functionality or a major rewrite. We believe if your contribution is significant then you should have a say in what license Web Notes selects in the future and/or have a right to any revenue Web Notes gets from a Commercial License. Either ways Web Notes will have the right to decide what is a "significant" contribution.
Note: At the moment, Web Notes does not give Commercial License for ERPNext nor has specific plans do so in the future.
The brand name ERPNext and the logo are trademarks of Web Notes Technologies Pvt. Ltd.

View File

@ -4,40 +4,89 @@
Includes Accounting, Inventory, CRM, Sales, Purchase, Projects, HRMS. Built on Python / MySQL. Includes Accounting, Inventory, CRM, Sales, Purchase, Projects, HRMS. Built on Python / MySQL.
## Platform ERPNext is built on [wnframework](https://github.com/webnotes/wnframework)
ERPNext is built on [wnframework](https://github.com/webnotes/wnframework) (Version 2.0) - [User Guide](https://erpnext.org/docs.user.html)
- [Getting Help](https://erpnext.org/docs.user.help.html)
- [Developer Forum](http://groups.google.com/group/erpnext-developer-forum)
- [User Forum](http://groups.google.com/group/erpnext-user-forum)
## User Guide ---
[See wiki](https://github.com/webnotes/erpnext/wiki/User-Guide) ### Download and Install
## Download and Install ##### Virtual Image:
First install all the pre-requisites, then - [ERPNext Download](http://erpnext.com/erpnext-download)
$ git clone git://github.com/webnotes/erpnext.git ##### On Linux:
$ cd erpnext
$ python erpnext_install.py 1. Switch to root user using `sudo su`
1. create a folder where you want to install erpnext
1. go to the new folder
1. `wget https://raw.github.com/webnotes/erpnext/master/install_erpnext.py`
1. `python install_erpnext.py`
[See installation notes](https://github.com/webnotes/erpnext/wiki/How-to-Install-ERPNext) [See installation notes](https://github.com/webnotes/erpnext/wiki/How-to-Install-ERPNext)
## Patch and update ##### Patch and update
To patch and update from the latest git repository the erpnext folder and run. To patch and update from the latest git repository the erpnext folder and run.
You will have to set your origin in git remote You will have to set your origin in git remote
$ lib/wnf.py --update origin master $ lib/wnf.py --update origin master
## Forums ---
Please join our forums for more questions:
- [Developer Forum](http://groups.google.com/group/erpnext-developer-forum)
- [User Forum](http://groups.google.com/group/erpnext-user-forum)
## License ## License
GNU/General Public License (see licence.txt) GNU/General Public License (see LICENSE.txt)
Along with the GPL, the name "ERPNext" must be retained in all derivatives. The ERPNext code is licensed as GNU General Public License (v3) and the Documentation is licensed as Creative Commons (CC-BY-SA-3.0) and the copyright is owned by Web Notes Technologies Pvt Ltd (Web Notes).
### Copyright for Contributors
Unless otherwise asserted in the code files, Web Notes will own the copyright of all contributions too. That means Web Notes holds the rights to change the license in the future or offer Commercial Licenses.
Web Notes will only accept copyright assertions in case of a significant contribution like a whole new functionality or a major rewrite. We believe if your contribution is significant then you should have a say in what license Web Notes selects in the future and/or have a right to any revenue Web Notes gets from a Commercial License. Either ways Web Notes will have the right to decide what is a "significant" contribution.
Note: At the moment, Web Notes does not give Commercial License for ERPNext nor has specific plans do so in the future.
---
## Logo and Trademark
The brand name ERPNext and the logo are trademarks of Web Notes Technologies Pvt. Ltd.
### Introduction
Web Notes Technologies Pvt. Ltd. (Web Notes) owns and oversees the trademarks for the ERPNext name and logos. We have developed this trademark usage policy with the following goals in mind:
- Wed like to make it easy for anyone to use the ERPNext name or logo for community-oriented efforts that help spread and improve ERPNext.
- Wed like to make it clear how ERPNext-related businesses and projects can (and cannot) use the ERPNext name and logo.
- Wed like to make it hard for anyone to use the ERPNext name and logo to unfairly profit from, trick or confuse people who are looking for official ERPNext resources.
### Web Notes Trademark Usage Policy
Permission from Web Notes is required to use the ERPNext name or logo as part of any project, product, service, domain or company name.
We will grant permission to use the ERPNext name and logo for projects that meet the following criteria:
- The primary purpose of your project is to promote the spread and improvement of the ERPNext software.
- Your project is non-commercial in nature (it can make money to cover its costs or contribute to non-profit entities, but it cannot be run as a for-profit project or business).
Your project neither promotes nor is associated with entities that currently fail to comply with the GPL license under which ERPNext is distributed.
- If your project meets these criteria, you will be permitted to use the ERPNext name and logo to promote your project in any way you see fit with one exception: Please do not use ERPNext as part of a domain name.
Use of the ERPNext name and logo is additionally allowed in the following situations:
All other ERPNext-related businesses or projects can use the ERPNext name and logo to refer to and explain their services, but they cannot use them as part of a product, project, service, domain, or company name and they cannot use them in any way that suggests an affiliation with or endorsement by the ERPNext or WebNotes or the ERPNext open source project. For example, a consulting company can describe its business as “123 Web Services, offering ERPNext consulting for small businesses,” but cannot call its business “The ERPNext Consulting Company.”
Similarly, its OK to use the ERPNext logo as part of a page that describes your products or services, but it is not OK to use it as part of your company or product logo or branding itself. Under no circumstances is it permitted to use ERPNext as part of a top-level domain name.
We do not allow the use of the trademark in advertising, including AdSense/AdWords.
Please note that it is not the goal of this policy to limit commercial activity around ERPNext. We encourage ERPNext-based businesses, and we would love to see hundreds of them.
When in doubt about your use of the ERPNext name or logo, please contact the Web Notes Technologies for clarification.
(inspired from Wordpress)

View File

@ -17,7 +17,7 @@ Install ERPNext in one command!
1. Switch to root user using `sudo su` 1. Switch to root user using `sudo su`
1. create a folder where you want to install erpnext 1. create a folder where you want to install erpnext
1. go to the new folder 1. go to the new folder
1. `wget https://gist.github.com/anandpdoshi/5991402/raw/5b3b451720a8575f8708e58a640b9a760d048392/install_erpnext.py` 1. `wget https://raw.github.com/webnotes/erpnext/master/install_erpnext.py`
1. `python install_erpnext.py` 1. `python install_erpnext.py`
> If you are installing on your server for deployment, remember to change Administrator's password! > If you are installing on your server for deployment, remember to change Administrator's password!

View File

@ -1,170 +1,343 @@
#!/usr/bin/python #!/usr/bin/env python
from __future__ import unicode_literals from __future__ import unicode_literals
import os, commands, sys import os, sys
def install(): apache_user = None
# get required details is_redhat = is_debian = None
root_pwd = get_root_password() root_password = None
db_name, db_pwd = get_new_db_details()
# install path def install(install_path=None):
install_pre_requisites()
if not install_path:
install_path = os.getcwd() install_path = os.getcwd()
install_erpnext(install_path)
setup_folders(install_path) post_install(install_path)
setup_conf(install_path, db_name, db_pwd) def install_pre_requisites():
global is_redhat, is_debian
is_redhat, is_debian = validate_install()
if is_redhat:
install_using_yum()
elif is_debian:
install_using_apt()
# setup paths install_python_modules()
sys.path.append('.')
sys.path.append('lib')
sys.path.append('app')
setup_db(install_path, root_pwd, db_name) print "-"*80
print "Pre-requisites Installed"
print "-"*80
apply_patches(install_path) def validate_install():
import platform
show_remaining_steps() # check os
operating_system = platform.system()
print "Operating System =", operating_system
if operating_system != "Linux":
raise Exception, "Sorry! This installer works only for Linux based Operating Systems"
def setup_folders(path): # check python version
execute_in_shell("git clone git://github.com/webnotes/wnframework.git lib", verbose=1) python_version = sys.version.split(" ")[0]
execute_in_shell("git clone git://github.com/webnotes/erpnext.git app", verbose=1) print "Python Version =", python_version
public = os.path.join(path, "public") if not (python_version and int(python_version.split(".")[0])==2 and int(python_version.split(".")[1]) >= 6):
os.mkdir(public) raise Exception, "Hey! ERPNext needs Python version to be 2.6+"
os.mkdir(os.path.join(public, "files"))
os.mkdir(os.path.join(public, "backups"))
os.mkdir(os.path.join(path, "logs"))
def setup_conf(path, db_name, db_pwd): # check distribution
# read template conf file distribution = platform.linux_distribution()[0].lower().replace('"', '')
with open(os.path.join(path, 'lib', 'conf', 'conf.py'), 'r') as template: print "Distribution = ", distribution
content = template.read() is_redhat = distribution in ("redhat", "centos", "fedora")
is_debian = distribution in ("debian", "ubuntu", "elementary os")
# manipulate content if not (is_redhat or is_debian):
raise Exception, "Sorry! This installer works only with yum or apt-get package management"
return is_redhat, is_debian
def install_using_yum():
packages = "python python-setuptools MySQL-python httpd git memcached ntp vim-enhanced screen"
print "-"*80
print "Installing Packages: (This may take some time)"
print packages
print "-"*80
exec_in_shell("yum install -y %s" % packages)
if not exec_in_shell("which mysql"):
packages = "mysql mysql-server mysql-devel"
print "Installing Packages:", packages
exec_in_shell("yum install -y %s" % packages)
exec_in_shell("service mysqld restart")
# set a root password post install
global root_password
print "Please create a password for root user of MySQL"
root_password = (get_root_password() or "erpnext").strip()
exec_in_shell('mysqladmin -u root password "%s"' % (root_password,))
print "Root password set as", root_password
# install htop
if not exec_in_shell("which htop"):
try:
exec_in_shell("cd /tmp && rpm -i --force http://packages.sw.be/rpmforge-release/rpmforge-release-0.5.2-2.el6.rf.x86_64.rpm && yum install -y htop")
except:
pass
update_config_for_redhat()
def update_config_for_redhat():
import re import re
# set new_dbname, new_dbpassword, files_path, backup_path, log_file_name global apache_user
content = re.sub("db_name.*", "db_name = '%s'" % db_name, content) apache_user = "apache"
content = re.sub("db_password.*", "db_password = '%s'" % db_pwd, content)
# write conf file # update memcache user
with open(os.path.join(path, 'conf.py'), 'w') as new_conf: with open("/etc/sysconfig/memcached", "r") as original:
new_conf.write(content) memcached_conf = original.read()
with open("/etc/sysconfig/memcached", "w") as modified:
modified.write(re.sub('USER.*', 'USER="%s"' % apache_user, memcached_conf))
def setup_db(path, root_pwd, db_name): # set to autostart on startup
source = os.path.join(path, 'app', "master.sql") for service in ("mysqld", "httpd", "memcached", "ntpd"):
execute_in_shell("gunzip -c %s.gz > %s" % (source, source), verbose=1) exec_in_shell("chkconfig --level 2345 %s on" % service)
exec_in_shell("service %s restart" % service)
from webnotes.install_lib.install import Installer def install_using_apt():
inst = Installer('root', root_pwd) packages = "python python-setuptools python-mysqldb apache2 git memcached ntp vim screen htop"
inst.import_from_db(db_name, source_path=source, verbose = 1) print "-"*80
execute_in_shell("rm %s" % source) print "Installing Packages: (This may take some time)"
print packages
print "-"*80
exec_in_shell("apt-get install -y %s" % packages)
def apply_patches(path): if not exec_in_shell("which mysql"):
# need to build before patches, once, so that all-web.js and all-web.css exists packages = "mysql-server libmysqlclient-dev"
execute_in_shell("./lib/wnf.py -b", verbose=1) print "Installing Packages:", packages
execute_in_shell("./lib/wnf.py --patch_sync_build", verbose=1) exec_in_shell("apt-get install -y %s" % packages)
# set filemode false update_config_for_debian()
execute_in_shell("cd app && git config core.filemode false", verbose=1)
execute_in_shell("cd lib && git config core.filemode false", verbose=1) def update_config_for_debian():
global apache_user
apache_user = "www-data"
# update memcache user
with open("/etc/memcached.conf", "r") as original:
memcached_conf = original.read()
with open("/etc/memcached.conf", "w") as modified:
modified.write(memcached_conf.replace("-u memcache", "-u %s" % apache_user))
exec_in_shell("a2enmod rewrite")
for service in ("mysql", "apache2", "memcached", "ntpd"):
exec_in_shell("service %s restart" % service)
def install_python_modules():
python_modules = "pytz python-dateutil jinja2 markdown2 termcolor python-memcached requests chardet dropbox google-api-python-client pygeoip gitpython"
print "-"*80
print "Installing Python Modules: (This may take some time)"
print python_modules
print "-"*80
exec_in_shell("easy_install pip")
exec_in_shell("pip install -q %s" % python_modules)
def install_erpnext(install_path):
print
print "-"*80
print "Installing ERPNext"
print "-"*80
# ask for details
global root_password
if not root_password:
root_password = get_root_password()
test_root_connection(root_password)
db_name = raw_input("ERPNext Database Name: ")
if not db_name:
raise Exception, "Sorry! You must specify ERPNext Database Name"
# install folders and conf
setup_folders(install_path)
setup_conf(install_path, db_name)
# setup paths
sys.path.extend([".", "lib", "app"])
# install database, run patches, update schema
setup_db(install_path, root_password, db_name)
setup_cron(install_path)
setup_apache_conf(install_path)
def get_root_password(): def get_root_password():
# ask for root mysql password # ask for root mysql password
import getpass import getpass
root_pwd = None root_pwd = None
while not root_pwd:
root_pwd = getpass.getpass("MySQL Root user's Password: ") root_pwd = getpass.getpass("MySQL Root user's Password: ")
test_root_connection(root_pwd)
return root_pwd return root_pwd
def test_root_connection(root_pwd): def test_root_connection(root_pwd):
err, out = execute_in_shell("mysql -u root -p%s -e 'exit'" % \ out = exec_in_shell("mysql -u root %s -e 'exit'" % \
root_pwd.replace('$', '\$').replace(' ', '\ ')) (("-p"+root_pwd) if root_pwd else "").replace('$', '\$').replace(' ', '\ '))
if "access denied" in out.lower(): if "access denied" in out.lower():
raise Exception("Incorrect MySQL Root user's password") raise Exception("Incorrect MySQL Root user's password")
def get_new_db_details(): def setup_folders(install_path):
return get_input("New ERPNext Database Name: "), \ from git import Repo
get_input("New ERPNext Database's Password: ")
def get_input(msg): app = os.path.join(install_path, "app")
val = None if not os.path.exists(app):
while not val: print "Cloning erpnext"
val = raw_input(msg) Repo.clone_from("https://github.com/webnotes/erpnext.git", app)
return val exec_in_shell("cd app && git config core.filemode false")
def show_remaining_steps(): lib = os.path.join(install_path, "lib")
steps_remaining = """ if not os.path.exists(lib):
Notes: print "Cloning wnframework"
------ Repo.clone_from("https://github.com/webnotes/wnframework.git", lib)
exec_in_shell("cd lib && git config core.filemode false")
sample apache conf file public = os.path.join(install_path, "public")
#----------------------------------------------------------- for p in [public, os.path.join(public, "files"), os.path.join(public, "backups"),
SetEnv PYTHON_EGG_CACHE /var/www os.path.join(install_path, "logs")]:
if not os.path.exists(p):
os.mkdir(p)
# you can change 99 to any other port def setup_conf(install_path, db_name):
import os, string, random, re
Listen 99 # generate db password
NameVirtualHost *:99 char_range = string.ascii_letters + string.digits
<VirtualHost *:99> db_password = "".join((random.choice(char_range) for n in xrange(16)))
# make conf file
with open(os.path.join(install_path, "lib", "conf", "conf.py"), "r") as template:
conf = template.read()
conf = re.sub("db_name.*", 'db_name = "%s"' % (db_name,), conf)
conf = re.sub("db_password.*", 'db_password = "%s"' % (db_password,), conf)
with open(os.path.join(install_path, "conf.py"), "w") as conf_file:
conf_file.write(conf)
return db_password
def setup_db(install_path, root_password, db_name):
master_sql = os.path.join(install_path, "app", "master.sql")
exec_in_shell("gunzip -c %s.gz > %s" % (master_sql, master_sql))
from webnotes.install_lib.install import Installer
inst = Installer("root", root_password)
inst.import_from_db(db_name, source_path=master_sql, verbose=1)
exec_in_shell("rm -f %s" % (master_sql,))
# run patches and sync
exec_in_shell("./lib/wnf.py -b --no_cms")
exec_in_shell("./lib/wnf.py --patch_sync_build")
def setup_cron(install_path):
erpnext_cron_entries = [
"*/3 * * * * cd %s && python lib/wnf.py --run_scheduler >> /var/log/erpnext-sch.log 2>&1" % install_path,
"0 */6 * * * cd %s && python lib/wnf.py --backup >> /var/log/erpnext-backup.log 2>&1" % install_path
]
for row in erpnext_cron_entries:
try:
existing_cron = exec_in_shell("crontab -l")
if row not in existing_cron:
exec_in_shell('{ crontab -l; echo "%s"; } | crontab' % row)
except:
exec_in_shell('echo "%s" | crontab' % row)
def setup_apache_conf(install_path):
apache_conf_content = """Listen 8080
NameVirtualHost *:8080
<VirtualHost *:8080>
ServerName localhost ServerName localhost
DocumentRoot {path to erpnext's folder}/public DocumentRoot %s/public/
AddHandler cgi-script .cgi .xml .py
<Directory {path to erpnext's folder}/public/> AddHandler cgi-script .cgi .xml .py
AddType application/vnd.ms-fontobject .eot
AddType font/ttf .ttf
AddType font/otf .otf
AddType application/x-font-woff .woff
<Directory %s/public/>
# directory specific options # directory specific options
Options -Indexes +FollowSymLinks +ExecCGI Options -Indexes +FollowSymLinks +ExecCGI
# directory's index file # directory's index file
DirectoryIndex web.py DirectoryIndex web.py
# rewrite rule
RewriteEngine on
# condition 1:
# ignore login-page.html, app.html, blank.html, unsupported.html
RewriteCond %{REQUEST_URI} ^((?!app\.html|blank\.html|unsupported\.html).)*$
# condition 2: if there are no slashes
# and file is .html or does not containt a .
RewriteCond %{REQUEST_URI} ^(?!.+/)((.+\.html)|([^.]+))$
# rewrite if both of the above conditions are true
RewriteRule ^(.+)$ web.py?page=$1 [NC,L]
AllowOverride all AllowOverride all
Order Allow,Deny Order Allow,Deny
Allow from all Allow from all
# rewrite rule
RewriteEngine on
RewriteCond %%{REQUEST_FILENAME} !-f
RewriteCond %%{REQUEST_FILENAME} !-d
RewriteCond %%{REQUEST_FILENAME} !-l
RewriteRule ^([^/]+)$ /web.py?page=$1 [QSA,L]
</Directory> </Directory>
</VirtualHost> </VirtualHost>""" % (install_path, install_path)
#-----------------------------------------------------------
To Do: new_apache_conf_path = os.path.join(install_path, os.path.basename(install_path)+".conf")
with open(new_apache_conf_path, "w") as apache_conf_file:
apache_conf_file.write(apache_conf_content)
* Configure apache/http conf file to point to public folder def post_install(install_path):
* chown recursively all files in your folder to apache user global apache_user
* login using: user="Administrator" and password="admin" exec_in_shell("chown -R %s %s" % (apache_user, install_path))
""" apache_conf_filename = os.path.basename(install_path)+".conf"
if is_redhat:
os.symlink(os.path.join(install_path, apache_conf_filename),
os.path.join("/etc/httpd/conf.d", apache_conf_filename))
exec_in_shell("service httpd restart")
print steps_remaining elif is_debian:
os.symlink(os.path.join(install_path, apache_conf_filename),
os.path.join("/etc/apache2/sites-enabled", apache_conf_filename))
exec_in_shell("service apache2 restart")
def execute_in_shell(cmd, verbose=0): print
print "-"*80
print "Installation complete"
print "Open your browser and go to http://localhost:8080"
print "Login using username = Administrator and password = admin"
def exec_in_shell(cmd):
# using Popen instead of os.system - as recommended by python docs # using Popen instead of os.system - as recommended by python docs
from subprocess import Popen, PIPE from subprocess import Popen
p = Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE) import tempfile
# get err and output with tempfile.TemporaryFile() as stdout:
err, out = p.stderr.read(), p.stdout.read() with tempfile.TemporaryFile() as stderr:
p = Popen(cmd, shell=True, stdout=stdout, stderr=stderr)
p.wait()
if verbose: stdout.seek(0)
if err: print err out = stdout.read()
if out: print out
return err, out stderr.seek(0)
err = stderr.read()
if __name__=="__main__": if err and any((kw in err.lower() for kw in ["traceback", "error", "exception"])):
print out
raise Exception, err
else:
print "."
return out
if __name__ == "__main__":
install() install()