From f4081c8130b877aa627b9853062dd92ef4cdc79b Mon Sep 17 00:00:00 2001 From: Pratik Vyas Date: Mon, 28 Oct 2013 14:43:00 +0530 Subject: [PATCH 01/10] remove changing of memcached user in install_erpnext.py --- install_erpnext.py | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/install_erpnext.py b/install_erpnext.py index 139458c01b..db1f40265e 100644 --- a/install_erpnext.py +++ b/install_erpnext.py @@ -141,14 +141,7 @@ def install_using_apt(): update_config_for_debian() def update_config_for_debian(): - - # 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)) - - for service in ("mysql", "memcached", "ntpd"): + for service in ("mysql", "ntpd"): exec_in_shell("service %s restart" % service) def install_python_modules(): From de4b720912f1b1afefbe96e5bf28100f1780187a Mon Sep 17 00:00:00 2001 From: Pratik Vyas Date: Mon, 28 Oct 2013 18:43:34 +0530 Subject: [PATCH 02/10] remove changing of memcached user in install_erpnext.py --- install_erpnext.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/install_erpnext.py b/install_erpnext.py index db1f40265e..ca95baf8f7 100644 --- a/install_erpnext.py +++ b/install_erpnext.py @@ -113,12 +113,6 @@ def install_using_yum(): def update_config_for_redhat(): import re - # update memcache user - with open("/etc/sysconfig/memcached", "r") as original: - memcached_conf = original.read() - with open("/etc/sysconfig/memcached", "w") as modified: - modified.write(re.sub('USER.*', 'USER="%s"' % apache_user, memcached_conf)) - # set to autostart on startup for service in ("mysqld", "httpd", "memcached", "ntpd"): exec_in_shell("chkconfig --level 2345 %s on" % service) From a5bd3dd207d25d4f02389f04aa12a6cf08b46736 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Fri, 25 Oct 2013 15:39:17 +0530 Subject: [PATCH 03/10] [fix] [minor] update finished goods against production order --- .../production_order/production_order.py | 6 ++-- stock/doctype/stock_entry/stock_entry.py | 31 +++++++++++++------ 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/manufacturing/doctype/production_order/production_order.py b/manufacturing/doctype/production_order/production_order.py index 9d4ff32e2f..5266450ed3 100644 --- a/manufacturing/doctype/production_order/production_order.py +++ b/manufacturing/doctype/production_order/production_order.py @@ -133,16 +133,16 @@ class DocType: @webnotes.whitelist() def get_item_details(item): - res = webnotes.conn.sql("""select stock_uom + res = webnotes.conn.sql("""select stock_uom, description from `tabItem` where (ifnull(end_of_life, "")="" or end_of_life > now()) - and name=%s""", (item,), as_dict=1) + and name=%s""", item, as_dict=1) if not res: return {} res = res[0] bom = webnotes.conn.sql("""select name from `tabBOM` where item=%s - and ifnull(is_default, 0)=1""", (item,)) + and ifnull(is_default, 0)=1""", item) if bom: res.bom_no = bom[0][0] diff --git a/stock/doctype/stock_entry/stock_entry.py b/stock/doctype/stock_entry/stock_entry.py index 3837ca10a8..2cdccbcb09 100644 --- a/stock/doctype/stock_entry/stock_entry.py +++ b/stock/doctype/stock_entry/stock_entry.py @@ -451,35 +451,44 @@ class DocType(StockController): item["to_warehouse"] = "" # add raw materials to Stock Entry Detail table - self.add_to_stock_entry_detail(item_dict) + idx = self.add_to_stock_entry_detail(item_dict) # add finished good item to Stock Entry Detail table -- along with bom_no if self.doc.production_order and self.doc.purpose == "Manufacture/Repack": + item = webnotes.conn.get_value("Item", pro_obj.doc.production_item, ["item_name", + "description", "stock_uom", "purchase_account", "cost_center"], as_dict=1) self.add_to_stock_entry_detail({ cstr(pro_obj.doc.production_item): { "to_warehouse": pro_obj.doc.fg_warehouse, "from_warehouse": "", "qty": self.doc.fg_completed_qty, - "description": pro_obj.doc.description, - "stock_uom": pro_obj.doc.stock_uom + "item_name": item.item_name, + "description": item.description, + "stock_uom": item.stock_uom, + "expense_account": item.purchase_account, + "cost_center": item.cost_center, } - }, bom_no=pro_obj.doc.bom_no) + }, bom_no=pro_obj.doc.bom_no, idx=idx) elif self.doc.purpose in ["Material Receipt", "Manufacture/Repack"]: if self.doc.purpose=="Material Receipt": self.doc.from_warehouse = "" - item = webnotes.conn.sql("""select name, item_name, description, uom - from `tabItem` where name=%s""", (self.doc.bom_no), as_dict=1) + item = webnotes.conn.sql("""select name, item_name, description, + uom, purchase_account, cost_center from `tabItem` + where name=(select item from tabBOM where name=%s)""", + self.doc.bom_no, as_dict=1) self.add_to_stock_entry_detail({ item[0]["item"] : { "qty": self.doc.fg_completed_qty, "item_name": item[0].item_name, "description": item[0]["description"], "stock_uom": item[0]["uom"], - "from_warehouse": "" + "from_warehouse": "", + "expense_account": item[0].purchase_account, + "cost_center": item[0].cost_center, } - }, bom_no=self.doc.bom_no) + }, bom_no=self.doc.bom_no, idx=idx) self.get_stock_and_rate() @@ -543,8 +552,9 @@ class DocType(StockController): return issued_item_qty - def add_to_stock_entry_detail(self, item_dict, bom_no=None): - idx = 1 + def add_to_stock_entry_detail(self, item_dict, bom_no=None, idx=None): + webnotes.errprint([]) + if not idx: idx = 1 expense_account, cost_center = webnotes.conn.get_values("Company", self.doc.company, \ ["default_expense_account", "cost_center"])[0] @@ -572,6 +582,7 @@ class DocType(StockController): # increment idx by 1 idx += 1 + return idx def get_cust_values(self): """fetches customer details""" From ed3dc56da4b7b3b4342d5de6d35e520b1002023f Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Fri, 25 Oct 2013 17:19:05 +0530 Subject: [PATCH 04/10] [minor] Ignore permission while updating profile from employee --- hr/doctype/employee/employee.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hr/doctype/employee/employee.py b/hr/doctype/employee/employee.py index 56dfb35766..84b2641ce6 100644 --- a/hr/doctype/employee/employee.py +++ b/hr/doctype/employee/employee.py @@ -100,7 +100,7 @@ class DocType: except webnotes.DuplicateEntryError, e: # already exists pass - + profile_wrapper.ignore_permissions = True profile_wrapper.save() def validate_date(self): From dc89acaf053d33419657aae12f65725ef5e8e347 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Sat, 26 Oct 2013 15:06:09 +0530 Subject: [PATCH 05/10] [fix] [minor] fetch item and price list details on saving item price --- setup/doctype/item_price/item_price.py | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/setup/doctype/item_price/item_price.py b/setup/doctype/item_price/item_price.py index ddde87e98a..be235de27c 100644 --- a/setup/doctype/item_price/item_price.py +++ b/setup/doctype/item_price/item_price.py @@ -13,23 +13,18 @@ class DocType: def __init__(self, d, dl): self.doc, self.doclist = d, dl - def on_update(self): + def validate(self): + self.check_duplicate_item() self.update_price_list_details() self.update_item_details() - self.check_duplicate_item() def update_price_list_details(self): - self.doc.buying_or_selling = webnotes.conn.get_value("Price List", self.doc.price_list, - "buying_or_selling") - - self.doc.currency = webnotes.conn.get_value("Price List", self.doc.price_list, - "currency") + self.doc.buying_or_selling, self.doc.currency = webnotes.conn.get_value("Price List", + self.doc.price_list, ["buying_or_selling", "currency"]) def update_item_details(self): - self.doc.item_name = webnotes.conn.get_value("Item", self.doc.item_code, "item_name") - - self.doc.item_description = webnotes.conn.get_value("Item", self.doc.item_code, - "description") + self.doc.item_name, self.doc.item_description = webnotes.conn.get_value("Item", + self.doc.item_code, ["item_name", "description"]) def check_duplicate_item(self): if webnotes.conn.sql("""select name from `tabItem Price` From 392596cb9107712df0f2efaaa8426e44fd6ea7de Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Sun, 27 Oct 2013 16:20:51 +0530 Subject: [PATCH 06/10] [fix] [minor] account group balance in grid report --- public/js/account_tree_grid.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/js/account_tree_grid.js b/public/js/account_tree_grid.js index 28db1d7946..550d11f371 100644 --- a/public/js/account_tree_grid.js +++ b/public/js/account_tree_grid.js @@ -174,7 +174,7 @@ erpnext.AccountTreeGrid = wn.views.TreeGridReport.extend({ var me= this; $.each(this.data, function(i, account) { // update groups - if(account.rgt - account.lft == 1) { + if((account.group_or_ledger == "Ledger") || (account.rgt - account.lft == 1)) { var parent = me.parent_map[account.name]; while(parent) { var parent_account = me.item_by_name[parent]; From 494a216193698b1649a3cd19a5db4c1d7372b969 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Mon, 28 Oct 2013 15:33:36 +0530 Subject: [PATCH 07/10] [fix] [minor] Cost center is mandatory if tax is include din valuation and perpetual inventory enabled --- .../doctype/purchase_invoice/purchase_invoice.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/accounts/doctype/purchase_invoice/purchase_invoice.py b/accounts/doctype/purchase_invoice/purchase_invoice.py index ba6f5a4d45..d3c19cbe9d 100644 --- a/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -338,11 +338,14 @@ class DocType(BuyingController): ) # accumulate valuation tax - if tax.category in ("Valuation", "Valuation and Total") and flt(tax.tax_amount) \ - and tax.cost_center: - valuation_tax.setdefault(tax.cost_center, 0) - valuation_tax[tax.cost_center] += \ - (tax.add_deduct_tax == "Add" and 1 or -1) * flt(tax.tax_amount) + if tax.category in ("Valuation", "Valuation and Total") and flt(tax.tax_amount): + if auto_accounting_for_stock and not tax.cost_center: + webnotes.throw(_("Row %(row)s: Cost Center is mandatory \ + if tax/charges category is Valuation or Valuation and Total" % + {"row": tax.idx})) + valuation_tax.setdefault(tax.cost_center, 0) + valuation_tax[tax.cost_center] += \ + (tax.add_deduct_tax == "Add" and 1 or -1) * flt(tax.tax_amount) # item gl entries stock_item_and_auto_accounting_for_stock = False From fec52b5a8fd8f10a390b57c0f6e9beb87c544966 Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Mon, 28 Oct 2013 19:59:09 +0530 Subject: [PATCH 08/10] [minor] fixed stock entry and demo --- .../doctype/pos_setting/test_pos_setting.py | 1 - manufacturing/doctype/bom/bom.py | 3 +- stock/doctype/stock_entry/stock_entry.py | 1 - utilities/demo/demo_docs/Item_Price.csv | 49 +++++++++++++++++++ utilities/demo/demo_docs/Price_List.csv | 49 ------------------- utilities/demo/make_demo.py | 2 +- 6 files changed, 52 insertions(+), 53 deletions(-) create mode 100644 utilities/demo/demo_docs/Item_Price.csv delete mode 100644 utilities/demo/demo_docs/Price_List.csv diff --git a/accounts/doctype/pos_setting/test_pos_setting.py b/accounts/doctype/pos_setting/test_pos_setting.py index 579a75edcd..8d02c57fd1 100644 --- a/accounts/doctype/pos_setting/test_pos_setting.py +++ b/accounts/doctype/pos_setting/test_pos_setting.py @@ -6,7 +6,6 @@ test_records = [ "doctype": "POS Setting", "name": "_Test POS Setting", "currency": "INR", - "conversion_rate": 1.0, "selling_price_list": "_Test Price List", "company": "_Test Company", "warehouse": "_Test Warehouse - _TC", diff --git a/manufacturing/doctype/bom/bom.py b/manufacturing/doctype/bom/bom.py index 785851d17a..ac8c842195 100644 --- a/manufacturing/doctype/bom/bom.py +++ b/manufacturing/doctype/bom/bom.py @@ -409,7 +409,8 @@ def get_bom_items_as_dict(bom, qty=1, fetch_exploded=1): item_dict = {} query = """select - bom_item.item_code, + bom_item.item_code, + item.item_name, ifnull(sum(bom_item.qty_consumed_per_unit),0) * %(qty)s as qty, item.description, item.stock_uom, diff --git a/stock/doctype/stock_entry/stock_entry.py b/stock/doctype/stock_entry/stock_entry.py index 2cdccbcb09..26759af003 100644 --- a/stock/doctype/stock_entry/stock_entry.py +++ b/stock/doctype/stock_entry/stock_entry.py @@ -553,7 +553,6 @@ class DocType(StockController): return issued_item_qty def add_to_stock_entry_detail(self, item_dict, bom_no=None, idx=None): - webnotes.errprint([]) if not idx: idx = 1 expense_account, cost_center = webnotes.conn.get_values("Company", self.doc.company, \ ["default_expense_account", "cost_center"])[0] diff --git a/utilities/demo/demo_docs/Item_Price.csv b/utilities/demo/demo_docs/Item_Price.csv new file mode 100644 index 0000000000..d70b7b3e67 --- /dev/null +++ b/utilities/demo/demo_docs/Item_Price.csv @@ -0,0 +1,49 @@ +Data Import Template,,,,,,, +Table:,Item Price,,,,,, +,,,,,,, +,,,,,,, +Notes:,,,,,,, +Please do not change the template headings.,,,,,,, +First data column must be blank.,,,,,,, +"If you are uploading new records, leave the ""name"""" (ID) column blank.""",,,,,,, +"If you are uploading new records, ""Naming Series"""" becomes mandatory"," if present.""",,,,,, +Only mandatory fields are necessary for new records. You can delete non-mandatory columns if you wish.,,,,,,, +"For updating, you can update only selective columns.",,,,,,, +You can only upload upto 5000 records in one go. (may be less in some cases),,,,,,, +,,,,,,, +DocType:,Item Price,,,,,, +Column Labels:,ID,Price List,Item Code,Rate,Valid for Buying or Selling?,Item Name,Item Description +Column Name:,name,price_list,item_code,ref_rate,buying_or_selling,item_name,item_description +Mandatory:,Yes,Yes,Yes,Yes,No,No,No +Type:,Data (text),Link,Link,Currency,Select,Data,Text +Info:,,Valid Price List,Valid Item,,"One of: Selling, Buying",, +Start entering data below this line,,,,,,, +,,Standard Buying,Base Bearing Plate,15,Buying,, +,,Standard Buying,Base Plate,20,Buying,, +,,Standard Buying,Bearing Block,10,Buying,, +,,Standard Buying,Bearing Collar,20,Buying,, +,,Standard Buying,Bearing Pipe,15,Buying,, +,,Standard Buying,Blade Rib,10,Buying,, +,,Standard Buying,Disc Collars,74,Buying,, +,,Standard Buying,External Disc,45,Buying,, +,,Standard Buying,Internal Disc,33,Buying,, +,,Standard Buying,Shaft,30,Buying,, +,,Standard Buying,Stand,40,Buying,, +,,Standard Buying,Upper Bearing Plate,50,Buying,, +,,Standard Buying,Wing Sheet,22,Buying,, +,,Standard Selling,Wind Turbine,21,Selling,, +,,Standard Selling,Wind Mill A Series,28,Selling,, +,,Standard Selling,Wind MIll C Series,14,Selling,, +,,Standard Selling,Base Bearing Plate,28,Selling,, +,,Standard Selling,Base Plate,21,Selling,, +,,Standard Selling,Bearing Block,14,Selling,, +,,Standard Selling,Bearing Collar,103.6,Selling,, +,,Standard Selling,Bearing Pipe,63,Selling,, +,,Standard Selling,Blade Rib,46.2,Selling,, +,,Standard Selling,Disc Collars,42,Selling,, +,,Standard Selling,External Disc,56,Selling,, +,,Standard Selling,Internal Disc,70,Selling,, +,,Standard Selling,Shaft,340,Selling,, +,,Standard Selling,Stand,400,Selling,, +,,Standard Selling,Upper Bearing Plate,300,Selling,, +,,Standard Selling,Wing Sheet,30.8,Selling,, \ No newline at end of file diff --git a/utilities/demo/demo_docs/Price_List.csv b/utilities/demo/demo_docs/Price_List.csv deleted file mode 100644 index fb412399e1..0000000000 --- a/utilities/demo/demo_docs/Price_List.csv +++ /dev/null @@ -1,49 +0,0 @@ -Data Import Template,,,,,,,,,,, -Table:,Price List,,,,,,,,,, -,,,,,,,,,,, -,,,,,,,,,,, -Notes:,,,,,,,,,,, -Please do not change the template headings.,,,,,,,,,,, -First data column must be blank.,,,,,,,,,,, -"If you are uploading new records, leave the ""name"" (ID) column blank.",,,,,,,,,,, -"If you are uploading new records, ""Naming Series"" becomes mandatory, if present.",,,,,,,,,,, -Only mandatory fields are necessary for new records. You can delete non-mandatory columns if you wish.,,,,,,,,,,, -"For updating, you can update only selective columns.",,,,,,,,,,, -You can only upload upto 5000 records in one go. (may be less in some cases),,,,,,,,,,, -,,,,,,,,,,, -DocType:,Price List,,,,~,For Territory,valid_for_territories,~,Item Price,item_prices, -Column Labels:,ID,Price List Name,Currency,Valid for Buying or Selling?,,ID,Territory,,ID,Item Code,Rate -Column Name:,name,price_list_name,currency,buying_or_selling,~,name,territory,~,name,item_code,ref_rate -Mandatory:,Yes,Yes,Yes,Yes,,Yes,Yes,,Yes,Yes,Yes -Type:,Data (text),Data,Link,Select,,Data,Link,,Data,Link,Currency -Info:,,,Valid Currency,"One of: Buying, Selling",,Leave blank for new records,Valid Territory,,Leave blank for new records,Valid Item, -Start entering data below this line,,,,,,,,,,, -,Standard Buying,Standard Buying,USD,Buying,,,United States,,,Base Bearing Plate,15 -,,,,,,,,,,Base Plate,20 -,,,,,,,,,,Bearing Block,10 -,,,,,,,,,,Bearing Collar,20 -,,,,,,,,,,Bearing Pipe,15 -,,,,,,,,,,Blade Rib,10 -,,,,,,,,,,Disc Collars,74 -,,,,,,,,,,External Disc,45 -,,,,,,,,,,Internal Disc,33 -,,,,,,,,,,Shaft,30 -,,,,,,,,,,Stand,40 -,,,,,,,,,,Upper Bearing Plate,50 -,,,,,,,,,,Wing Sheet,22 -,Standard Selling,Standard Selling,USD,Selling,,,United States,,,Wind Turbine,21 -,,,,,,,,,,Wind Mill A Series,28 -,,,,,,,,,,Wind MIll C Series,14 -,,,,,,,,,,Base Bearing Plate,28 -,,,,,,,,,,Base Plate,21 -,,,,,,,,,,Bearing Block,14 -,,,,,,,,,,Bearing Collar,103.6 -,,,,,,,,,,Bearing Pipe,63 -,,,,,,,,,,Blade Rib,46.2 -,,,,,,,,,,Disc Collars,42 -,,,,,,,,,,External Disc,56 -,,,,,,,,,,Internal Disc,70 -,,,,,,,,,,Shaft,340 -,,,,,,,,,,Stand,400 -,,,,,,,,,,Upper Bearing Plate,300 -,,,,,,,,,,Wing Sheet,30.8 diff --git a/utilities/demo/make_demo.py b/utilities/demo/make_demo.py index 21da30b978..be42395031 100644 --- a/utilities/demo/make_demo.py +++ b/utilities/demo/make_demo.py @@ -396,7 +396,7 @@ def make_items(): import_data("BOM", submit=True) def make_price_lists(): - import_data("Price_List", overwrite=True) + import_data("Item_Price", overwrite=True) def make_customers_suppliers_contacts(): import_data(["Customer", "Supplier", "Contact", "Address", "Lead"]) From 4ec768b86cbefe4d73034910dd9d3e846aeb67d8 Mon Sep 17 00:00:00 2001 From: Pratik Vyas Date: Mon, 28 Oct 2013 21:57:59 +0530 Subject: [PATCH 09/10] fix ubuntu install --- install_erpnext.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/install_erpnext.py b/install_erpnext.py index ca95baf8f7..7b4f063a4c 100644 --- a/install_erpnext.py +++ b/install_erpnext.py @@ -19,6 +19,7 @@ requirements = [ "requests", "chardet", "dropbox", + "Werkzeug", "google-api-python-client ", "pygeoip" ] @@ -126,6 +127,11 @@ def install_using_apt(): print packages print "-"*80 exec_in_shell("apt-get install -y %s" % packages) + global root_password + if not root_password: + root_password = get_root_password() + exec_in_shell("echo mysql-server mysql-server/root_password password %s | sudo debconf-set-selections" % root_password) + exec_in_shell("echo mysql-server mysql-server/root_password_again password %s | sudo debconf-set-selections" % root_password) if not exec_in_shell("which mysql"): packages = "mysql-server libmysqlclient-dev" @@ -141,7 +147,6 @@ def update_config_for_debian(): def install_python_modules(): print "-"*80 print "Installing Python Modules: (This may take some time)" - print python_modules print "-"*80 if not exec_in_shell("which pip"): @@ -150,7 +155,7 @@ def install_python_modules(): exec_in_shell("pip install --upgrade pip") exec_in_shell("pip install --upgrade setuptools") exec_in_shell("pip install --upgrade virtualenv") - exec_in_shell("pip install -r {}".format(' '.join(requirements))) + exec_in_shell("pip install {}".format(' '.join(requirements))) def install_erpnext(install_path): print From f64dfa1d46e2565ddb9de97f68f15b935f30b690 Mon Sep 17 00:00:00 2001 From: Pratik Vyas Date: Thu, 31 Oct 2013 11:43:51 +0530 Subject: [PATCH 10/10] [minor] removed checking out of wsgi after clone in install script, booboo --- install_erpnext.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/install_erpnext.py b/install_erpnext.py index 7b4f063a4c..303c83b222 100644 --- a/install_erpnext.py +++ b/install_erpnext.py @@ -200,7 +200,7 @@ def setup_folders(install_path): app = os.path.join(install_path, "app") if not os.path.exists(app): print "Cloning erpnext" - exec_in_shell("cd %s && git clone https://github.com/webnotes/erpnext.git app && cd app && git checkout wsgi" % install_path) + exec_in_shell("cd %s && git clone https://github.com/webnotes/erpnext.git app" % install_path) exec_in_shell("cd app && git config core.filemode false") if not os.path.exists(app): raise Exception, "Couldn't clone erpnext repository" @@ -208,7 +208,7 @@ def setup_folders(install_path): lib = os.path.join(install_path, "lib") if not os.path.exists(lib): print "Cloning wnframework" - exec_in_shell("cd %s && git clone https://github.com/webnotes/wnframework.git lib && cd lib && git checkout wsgi" % install_path) + exec_in_shell("cd %s && git clone https://github.com/webnotes/wnframework.git lib" % install_path) exec_in_shell("cd lib && git config core.filemode false") if not os.path.exists(lib): raise Exception, "Couldn't clone wnframework repository"