From 5cd22894b090f29b1c435ce5207bf34e5fa744a3 Mon Sep 17 00:00:00 2001 From: WebNotes Date: Mon, 11 Mar 2013 10:58:42 +0530 Subject: [PATCH 01/30] it's done --- .../doctype/backup_manager/backup_dropbox.py | 51 +++++++++---------- .../doctype/backup_manager/backup_manager.py | 5 +- 2 files changed, 29 insertions(+), 27 deletions(-) diff --git a/setup/doctype/backup_manager/backup_dropbox.py b/setup/doctype/backup_manager/backup_dropbox.py index 3b0857fdd9..e8eed3be19 100644 --- a/setup/doctype/backup_manager/backup_dropbox.py +++ b/setup/doctype/backup_manager/backup_dropbox.py @@ -1,6 +1,7 @@ import os import webnotes -from webnotes.utils import get_request_site_address +from webnotes.utils import get_request_site_address, get_base_path +from webnotes import _ @webnotes.whitelist() def get_dropbox_authorize_url(): @@ -67,22 +68,23 @@ def backup_to_dropbox(): backup = new_backup() filename = backup.backup_path_db upload_file_to_dropbox(filename, "database", dropbox_client) - - # upload files - response = dropbox_client.metadata("files") - + path1 = os.path.join(get_base_path(), "public", "backups") + response = dropbox_client.metadata('/database') - # add missing files - for filename in os.listdir(os.path.join("public", "files")): + #add missing files + found = False + for filename in os.listdir(path1): found = False + pth=path1+'/'+filename + size=os.stat(pth).st_size for file_metadata in response["contents"]: if filename==os.path.basename(file_metadata["path"]): - if os.stat(os.path.join("public", "files", filename)).st_size==file_metadata["bytes"]: + if size==file_metadata["bytes"]: found=True - if not found: - upload_file_to_dropbox(os.path.join("public", "files", filename), "files", dropbox_client) - + upload_file_to_dropbox(pth, "database", dropbox_client) + if found: + webnotes.msgprint("no backup required everything is upto date") def get_dropbox_session(): from dropbox import session @@ -96,20 +98,17 @@ def get_dropbox_session(): return sess def upload_file_to_dropbox(filename, folder, dropbox_client): - if __name__=="__main__": - print "Uploading " + filename - size = os.stat(filename).st_size - f = open(filename,'r') - - if size > 4194304: - uploader = dropbox_client.get_chunked_uploader(f, size) - while uploader.offset < size: - try: - uploader.upload_chunked() - except rest.ErrorResponse, e: - pass - else: - response = dropbox_client.put_file(folder + "/" + os.path.basename(filename), f, overwrite=True) + size = os.stat(filename).st_size + f = open(filename,'r') + if size > 4194304: + uploader = dropbox_client.get_chunked_uploader(f, size) + while uploader.offset < size: + try: + uploader.upload_chunked() + except rest.ErrorResponse, e: + pass + else: + response = dropbox_client.put_file(folder + "/" + os.path.basename(filename), f, overwrite=True) if __name__=="__main__": - backup_to_dropbox() \ No newline at end of file + backup_to_dropbox() \ No newline at end of file diff --git a/setup/doctype/backup_manager/backup_manager.py b/setup/doctype/backup_manager/backup_manager.py index 48d48e817c..2b9cfca85a 100644 --- a/setup/doctype/backup_manager/backup_manager.py +++ b/setup/doctype/backup_manager/backup_manager.py @@ -3,6 +3,7 @@ from __future__ import unicode_literals import webnotes from webnotes import _ +from webnotes.utils import getTraceback class DocType: def __init__(self, d, dl): @@ -25,6 +26,7 @@ def take_backups(): backup_to_dropbox() send_email(True, "Dropbox") except Exception, e: + webnotes.errprint(e) send_email(False, "Dropbox", e) def send_email(success, service_name, error_status=None): @@ -40,7 +42,8 @@ def send_email(success, service_name, error_status=None): failed.

Error message: %s

Please contact your system manager for more information.

- """ % (service_name, error_status) +

Detailed Error Trace: %s

""" % \ + (service_name, error_status, getTraceback().replace("\n", "
")) # email system managers from webnotes.utils.email_lib import sendmail From 71bed3116fb45cb1be0abdb97187e9cfcf62ca1c Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Wed, 13 Mar 2013 12:57:04 +0530 Subject: [PATCH 02/30] working on merging sales purchase return into stock entry --- .../doctype/pos_setting/test_pos_setting.py | 14 ++ .../doctype/sales_invoice/sales_invoice.py | 6 +- .../doctype/sales_invoice/sales_invoice.txt | 5 +- .../sales_invoice/test_sales_invoice.py | 2 +- .../march_2013/p04_pos_update_stock_check.py | 18 +++ patches/patch_list.py | 1 + .../global_defaults/global_defaults.txt | 11 +- stock/doctype/bin/bin.py | 6 +- stock/doctype/stock_entry/stock_entry.js | 72 +++++++-- stock/doctype/stock_entry/stock_entry.py | 142 +++++++++++++++--- stock/doctype/stock_entry/test_stock_entry.py | 126 +++++++++++++++- stock/doctype/stock_ledger/stock_ledger.py | 3 +- .../stock_ledger_entry/stock_ledger_entry.py | 2 +- stock/stock_ledger.py | 5 +- 14 files changed, 365 insertions(+), 48 deletions(-) create mode 100644 accounts/doctype/pos_setting/test_pos_setting.py create mode 100644 patches/march_2013/p04_pos_update_stock_check.py diff --git a/accounts/doctype/pos_setting/test_pos_setting.py b/accounts/doctype/pos_setting/test_pos_setting.py new file mode 100644 index 0000000000..2c45c4dce8 --- /dev/null +++ b/accounts/doctype/pos_setting/test_pos_setting.py @@ -0,0 +1,14 @@ +test_records = [ + [{ + "doctype": "POS Setting", + "name": "_Test POS Setting", + "currency": "INR", + "conversion_rate": 1.0, + "price_list_name": "_Test Price List", + "company": "_Test Company", + "warehouse": "_Test Warehouse", + "cash_bank_account": "_Test Account Bank Account - _TC", + "income_account": "Sales - _TC", + "cost_center": "_Test Cost Center - _TC", + }] +] \ No newline at end of file diff --git a/accounts/doctype/sales_invoice/sales_invoice.py b/accounts/doctype/sales_invoice/sales_invoice.py index de3ee95897..0271a5855e 100644 --- a/accounts/doctype/sales_invoice/sales_invoice.py +++ b/accounts/doctype/sales_invoice/sales_invoice.py @@ -47,6 +47,7 @@ class DocType(SellingController): def validate(self): super(DocType, self).validate() + self.validate_posting_time() self.so_dn_required() self.validate_proj_cust() sales_com_obj = get_obj('Sales Common') @@ -636,10 +637,9 @@ class DocType(SellingController): # Reduce actual qty from warehouse self.make_sl_entry( d, d['warehouse'], - flt(d['qty']) , 0, update_stock) - + get_obj('Stock Ledger', 'Stock Ledger').update_stock(self.values) - - + def get_actual_qty(self,args): args = eval(args) actual_qty = webnotes.conn.sql("select actual_qty from `tabBin` where item_code = '%s' and warehouse = '%s'" % (args['item_code'], args['warehouse']), as_dict=1) diff --git a/accounts/doctype/sales_invoice/sales_invoice.txt b/accounts/doctype/sales_invoice/sales_invoice.txt index c7c8fbac71..35710b4d49 100644 --- a/accounts/doctype/sales_invoice/sales_invoice.txt +++ b/accounts/doctype/sales_invoice/sales_invoice.txt @@ -1,8 +1,8 @@ [ { - "creation": "2013-01-29 17:54:09", + "creation": "2013-03-12 11:56:25", "docstatus": 0, - "modified": "2013-01-29 18:22:52", + "modified": "2013-03-12 14:31:24", "modified_by": "Administrator", "owner": "Administrator" }, @@ -77,7 +77,6 @@ "print_hide": 1 }, { - "default": "1", "depends_on": "eval:doc.is_pos==1", "doctype": "DocField", "fieldname": "update_stock", diff --git a/accounts/doctype/sales_invoice/test_sales_invoice.py b/accounts/doctype/sales_invoice/test_sales_invoice.py index 84eddea218..91c0622cee 100644 --- a/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -297,7 +297,7 @@ class TestSalesInvoice(unittest.TestCase): ]) ps.insert() -test_dependencies = ["Journal Voucher"] +test_dependencies = ["Journal Voucher", "POS Setting"] test_records = [ [ diff --git a/patches/march_2013/p04_pos_update_stock_check.py b/patches/march_2013/p04_pos_update_stock_check.py new file mode 100644 index 0000000000..da48efe155 --- /dev/null +++ b/patches/march_2013/p04_pos_update_stock_check.py @@ -0,0 +1,18 @@ +import webnotes + +def execute(): + from webnotes.utils import cint + webnotes.reload_doc("setup", "doctype", "global_defaults") + + doctype_list = webnotes.get_doctype("Sales Invoice") + update_stock_df = doctype_list.get_field("update_stock") + + global_defaults = webnotes.bean("Global Defaults", "Global Defaults") + global_defaults.doc.update_stock = cint(update_stock_df.default) + global_defaults.save() + + webnotes.conn.sql("""delete from `tabProperty Setter` + where doc_type='Sales Invoice' and doctype_or_field='DocField' + and field_name='update_stock' and property='default'""") + + webnotes.reload_doc("accounts", "doctype", "sales_invoice") \ No newline at end of file diff --git a/patches/patch_list.py b/patches/patch_list.py index 5a504f8a51..f27ed31f0a 100644 --- a/patches/patch_list.py +++ b/patches/patch_list.py @@ -213,4 +213,5 @@ patch_list = [ "patches.march_2013.p03_rename_blog_to_blog_post", "execute:webnotes.bean('Style Settings', 'Style Settings').save()", "execute:webnotes.reload_doc('hr', 'search_criteria', 'monthly_attendance_details')", + "patches.march_2013.p04_pos_update_stock_check", ] \ No newline at end of file diff --git a/setup/doctype/global_defaults/global_defaults.txt b/setup/doctype/global_defaults/global_defaults.txt index 960da7e231..a55c6c0cdc 100644 --- a/setup/doctype/global_defaults/global_defaults.txt +++ b/setup/doctype/global_defaults/global_defaults.txt @@ -1,8 +1,8 @@ [ { - "creation": "2013-02-19 12:28:27", + "creation": "2013-03-08 15:37:09", "docstatus": 0, - "modified": "2013-02-20 14:09:00", + "modified": "2013-03-12 18:48:53", "modified_by": "Administrator", "owner": "Administrator" }, @@ -249,6 +249,13 @@ "fieldname": "column_break4", "fieldtype": "Column Break" }, + { + "description": "If checked, then in POS Sales Invoice, Update Stock gets checked by default", + "doctype": "DocField", + "fieldname": "update_stock", + "fieldtype": "Check", + "label": "Update Stock when using POS Sales Invoice" + }, { "doctype": "DocField", "fieldname": "account_info", diff --git a/stock/doctype/bin/bin.py b/stock/doctype/bin/bin.py index 37ecf85d2c..e1bc6bd20a 100644 --- a/stock/doctype/bin/bin.py +++ b/stock/doctype/bin/bin.py @@ -70,7 +70,7 @@ class DocType: "posting_date": args.get("posting_date"), "posting_time": args.get("posting_time") }) - + def update_qty(self, args): # update the stock values (for current quantities) self.doc.actual_qty = flt(self.doc.actual_qty) + flt(args.get("actual_qty")) @@ -83,11 +83,11 @@ class DocType: flt(self.doc.indented_qty) + flt(self.doc.planned_qty) - flt(self.doc.reserved_qty) self.doc.save() - + if (flt(args.get("actual_qty")) < 0 or flt(args.get("reserved_qty")) > 0) \ and args.get("is_cancelled") == 'No' and args.get("is_amended")=='No': self.reorder_item(args.get("voucher_type"), args.get("voucher_no")) - + def get_first_sle(self): sle = sql(""" select * from `tabStock Ledger Entry` diff --git a/stock/doctype/stock_entry/stock_entry.js b/stock/doctype/stock_entry/stock_entry.js index ba1f64802a..010b27040d 100644 --- a/stock/doctype/stock_entry/stock_entry.js +++ b/stock/doctype/stock_entry/stock_entry.js @@ -18,6 +18,39 @@ wn.require("public/app/js/controllers/stock_controller.js"); wn.provide("erpnext.stock"); erpnext.stock.StockEntry = erpnext.stock.StockController.extend({ + setup: function() { + var me = this; + + this.frm.fields_dict.delivery_note_no.get_query = function() { + return { query: "stock.doctype.stock_entry.stock_entry.query_sales_return_doc" }; + }; + + this.frm.fields_dict.sales_invoice_no.get_query = + this.frm.fields_dict.delivery_note_no.get_query; + + this.frm.fields_dict.purchase_receipt_no.get_query = function() { + return { query: "stock.doctype.stock_entry.stock_entry.query_purchase_return_doc" }; + }; + + this.frm.fields_dict.mtn_details.grid.get_field('item_code').get_query = function() { + if(in_list(["Sales Return", "Purchase Return"], me.frm.doc.purpose) && + me.get_doctype_docname()) { + return { + query: "stock.doctype.stock_entry.stock_entry.query_return_item", + filters: { + purpose: me.frm.doc.purpose, + delivery_note_no: me.frm.doc.delivery_note_no, + sales_invoice_no: me.frm.doc.sales_invoice_no, + purchase_receipt_no: me.frm.doc.purchase_receipt_no + } + }; + } else { + return erpnext.queries.item({is_stock_item: "Yes"}); + } + }; + + }, + onload_post_render: function() { if(this.frm.doc.__islocal && (this.frm.doc.production_order || this.frm.doc.bom_no) && !getchildren('Stock Entry Detail', this.frm.doc.name, 'mtn_details').length) { @@ -80,6 +113,36 @@ erpnext.stock.StockEntry = erpnext.stock.StockController.extend({ toggle_enable_bom: function() { this.frm.toggle_enable("bom_no", !this.frm.doc.production_order); }, + + get_doctype_docname: function() { + if(this.frm.doc.purpose === "Sales Return") { + if(this.frm.doc.delivery_note_no && this.frm.doc.sales_invoice_no) { + // both specified + msgprint(wn._("You can not enter both Delivery Note No and Sales Invoice No. \ + Please enter any one.")); + + } else if(!(this.frm.doc.delivery_note_no || this.frm.doc.sales_invoice_no)) { + // none specified + msgprint(wn._("Please enter Delivery Note No or Sales Invoice No to proceed")); + + } else if(this.frm.doc.delivery_note_no) { + return {doctype: "Delivery Note", docname: this.frm.doc.delivery_note_no}; + + } else if(this.frm.doc.sales_invoice_no) { + return {doctype: "Sales Invoice", docname: this.frm.doc.sales_invoice_no}; + + } + } else if(this.frm.doc.purpose === "Purchase Return") { + if(this.frm.doc.purchase_receipt_no) { + return {doctype: "Purchase Receipt", docname: this.frm.doc.purchase_receipt_no}; + + } else { + // not specified + msgprint(wn._("Please enter Purchase Receipt No to proceed")); + + } + } + }, }); @@ -140,15 +203,6 @@ cur_frm.cscript.purpose = function(doc, cdt, cdn) { cur_frm.cscript.toggle_related_fields(doc, cdt, cdn); } -// item code - only if quantity present in source warehosue -var fld = cur_frm.fields_dict['mtn_details'].grid.get_field('item_code'); -fld.query_description = "If Source Warehouse is selected, items with existing stock \ - for that warehouse will be selected"; - -fld.get_query = function() { - return erpnext.queries.item({is_stock_item: "Yes"}); -} - // copy over source and target warehouses cur_frm.fields_dict['mtn_details'].grid.onrowadd = function(doc, cdt, cdn){ var d = locals[cdt][cdn]; diff --git a/stock/doctype/stock_entry/stock_entry.py b/stock/doctype/stock_entry/stock_entry.py index 74b71d97b3..d987fa7c5f 100644 --- a/stock/doctype/stock_entry/stock_entry.py +++ b/stock/doctype/stock_entry/stock_entry.py @@ -26,8 +26,9 @@ from stock.utils import get_incoming_rate from stock.stock_ledger import get_previous_sle import json - sql = webnotes.conn.sql + +class NotUpdateStockError(webnotes.ValidationError): pass from controllers.accounts_controller import AccountsController @@ -38,6 +39,7 @@ class DocType(AccountsController): self.fname = 'mtn_details' def validate(self): + self.validate_posting_time() self.validate_purpose() self.validate_serial_nos() @@ -237,26 +239,54 @@ class DocType(AccountsController): or update the Quantity manually."), raise_exception=1) def validate_return_reference_doc(self): - """ validate item with reference doc""" - ref_doctype = ref_docname = "" - if self.doc.purpose == "Sales Return" and \ - (self.doc.delivery_note_no or self.doc.sales_invoice_no): - ref_doctype = self.doc.delivery_note_no and "Delivery Note" or "Sales Invoice" - ref_docname = self.doc.delivery_note_no or self.doc.sales_invoice_no - elif self.doc.purpose == "Purchase Return" and self.doc.purchase_receipt_no: - ref_doctype = "Purchase Receipt" - ref_docname = self.doc.purchase_receipt_no + """validate item with reference doc""" + ref_doclist = parentfields = None + + # get ref_doclist + if self.doc.purpose in return_map: + for fieldname, val in return_map[self.doc.purpose].items(): + if self.doc.fields.get(fieldname): + ref_doclist = webnotes.get_doclist(val[0], self.doc.fields[fieldname]) + parentfields = val[1] + + if ref_doclist: + # validate docstatus + if ref_doclist[0].docstatus != 1: + webnotes.msgprint(_(ref_doclist[0].doctype) + ' "' + ref_doclist[0].name + '": ' + + _("Status should be Submitted"), raise_exception=webnotes.InvalidStatusError) + + + # update stock check + if ref_doclist[0].doctype == "Sales Invoice" and (cint(ref_doclist[0].is_pos) != 1 \ + or cint(ref_doclist[0].update_stock) != 1): + webnotes.msgprint(_(ref_doclist[0].doctype) + ' "' + ref_doclist[0].name + '": ' + + _("Is POS and Update Stock should be checked."), + raise_exception=NotUpdateStockError) + + # posting date check + ref_posting_datetime = "%s %s" % (cstr(ref_doclist[0].posting_date), + cstr(ref_doclist[0].posting_time)) + this_posting_datetime = "%s %s" % (cstr(self.doc.posting_date), + cstr(self.doc.posting_time)) + if this_posting_datetime < ref_posting_datetime: + from webnotes.utils.dateutils import datetime_in_user_format + webnotes.msgprint(_("Posting Date Time cannot be before") + + ": " + datetime_in_user_format(ref_posting_datetime), + raise_exception=True) + + stock_items = get_stock_items_for_return(ref_doclist, parentfields) - if ref_doctype and ref_docname: for item in self.doclist.get({"parentfield": "mtn_details"}): - ref_exists = webnotes.conn.sql("""select name from `tab%s` - where parent = %s and item_code = %s and docstatus=1""" % - (ref_doctype + " Item", '%s', '%s'), (ref_docname, item.item_code)) - - if not ref_exists: - msgprint(_("Item: '") + item.item_code + _("' does not exists in ") + - ref_doctype + ": " + ref_docname, raise_exception=1) - + # validate if item exists in the ref doclist and that it is a stock item + if item.item_code not in stock_items: + msgprint(_("Item") + ': "' + item.item_code + _("\" does not exist in ") + + ref_doclist[0].doctype + ": " + ref_doclist[0].name, + raise_exception=webnotes.DoesNotExistError) + + # validate quantity <= ref item's qty + ref_item = ref_doclist.getone({"item_code": item.item_code}) + self.validate_value("transfer_qty", "<=", ref_item.qty, item) + def update_serial_no(self, is_submit): """Create / Update Serial No""" from stock.utils import get_valid_serial_nos @@ -288,6 +318,7 @@ class DocType(AccountsController): self.add_to_values(d, cstr(d.s_warehouse), -flt(d.transfer_qty), is_cancelled) if cstr(d.t_warehouse): self.add_to_values(d, cstr(d.t_warehouse), flt(d.transfer_qty), is_cancelled) + get_obj('Stock Ledger', 'Stock Ledger').update_stock(self.values, self.doc.amended_from and 'Yes' or 'No') @@ -607,4 +638,75 @@ def get_production_order_details(production_order): result = webnotes.conn.sql("""select bom_no, ifnull(qty, 0) - ifnull(produced_qty, 0) as fg_completed_qty, use_multi_level_bom from `tabProduction Order` where name = %s""", production_order, as_dict=1) - return result and result[0] or {} \ No newline at end of file + return result and result[0] or {} + +def query_sales_return_doc(doctype, txt, searchfield, start, page_len, filters): + conditions = "" + if doctype == "Sales Invoice": + conditions = "and is_pos=1 and update_stock=1" + + return webnotes.conn.sql("""select name, customer, customer_name + from `tab%s` where docstatus = 1 + and (`%s` like %%(txt)s or `customer` like %%(txt)s) %s + order by name, customer, customer_name + limit %s""" % (doctype, searchfield, conditions, "%(start)s, %(page_len)s"), + {"txt": "%%%s%%" % txt, "start": start, "page_len": page_len}, as_list=True) + +def query_purchase_return_doc(doctype, txt, searchfield, start, page_len, filters): + return webnotes.conn.sql("""select name, supplier, supplier_name + from `tab%s` where docstatus = 1 + and (`%s` like %%(txt)s or `supplier` like %%(txt)s) + order by name, supplier, supplier_name + limit %s""" % (doctype, searchfield, "%(start)s, %(page_len)s"), + {"txt": "%%%s%%" % txt, "start": start, "page_len": page_len}, as_list=True) + +def query_return_item(doctype, txt, searchfield, start, page_len, filters): + txt = txt.replace("%", "") + + for fieldname, val in return_map[filters["purpose"]].items(): + if filters.get(fieldname): + ref_doclist = webnotes.get_doclist(val[0], filters[fieldname]) + parentfields = val[1] + + stock_items = get_stock_items_for_return(ref_doclist, parentfields) + + result = [] + for item in ref_doclist.get({"parentfield": ["in", parentfields]}): + if item.item_code in stock_items: + item.item_name = cstr(item.item_name) + item.description = cstr(item.description) + if (txt in item.item_code) or (txt in item.item_name) or (txt in item.description): + val = [ + item.item_code, + (len(item.item_name) > 40) and (item.item_name[:40] + "...") or item.item_name, + (len(item.description) > 40) and (item.description[:40] + "...") or \ + item.description + ] + if val not in result: + result.append(val) + + return result[start:start+page_len] + +def get_stock_items_for_return(ref_doclist, parentfields): + """return item codes filtered from doclist, which are stock items""" + if isinstance(parentfields, basestring): + parentfields = [parentfields] + + all_items = list(set([d.item_code for d in + ref_doclist.get({"parentfield": ["in", parentfields]})])) + stock_items = webnotes.conn.sql_list("""select name from `tabItem` + where is_stock_item='Yes' and name in (%s)""" % (", ".join(["%s"] * len(all_items))), + tuple(all_items)) + + return stock_items + +return_map = { + "Sales Return": { + # [Ref DocType, [Item tables' parentfields]] + "delivery_note_no": ["Delivery Note", ["delivery_note_details", "packing_details"]], + "sales_invoice_no": ["Sales Invoice", ["entries", "packing_details"]] + }, + "Purchase Return": { + "purchase_receipt_no": ["Purchase Receipt", ["purchase_receipt_details"]] + } +} \ No newline at end of file diff --git a/stock/doctype/stock_entry/test_stock_entry.py b/stock/doctype/stock_entry/test_stock_entry.py index 21d15f7e23..78f051fe27 100644 --- a/stock/doctype/stock_entry/test_stock_entry.py +++ b/stock/doctype/stock_entry/test_stock_entry.py @@ -3,6 +3,7 @@ from __future__ import unicode_literals import webnotes, unittest +from webnotes.utils import flt class TestStockEntry(unittest.TestCase): def test_auto_material_request(self): @@ -22,7 +23,7 @@ class TestStockEntry(unittest.TestCase): self.assertTrue(mr_name) - def test_material_receipt_gl_entry(self): + def atest_material_receipt_gl_entry(self): webnotes.conn.sql("delete from `tabStock Ledger Entry`") webnotes.defaults.set_global_default("auto_inventory_accounting", 1) @@ -45,7 +46,7 @@ class TestStockEntry(unittest.TestCase): webnotes.defaults.set_global_default("auto_inventory_accounting", 0) - def test_material_issue_gl_entry(self): + def atest_material_issue_gl_entry(self): webnotes.conn.sql("delete from `tabStock Ledger Entry`") webnotes.defaults.set_global_default("auto_inventory_accounting", 1) @@ -80,7 +81,7 @@ class TestStockEntry(unittest.TestCase): self.assertEquals(expected_sle[i][1], sle.warehouse) self.assertEquals(expected_sle[i][2], sle.actual_qty) - def check_gl_entries(self, voucher_type, voucher_no, expected_gl_entries): + def acheck_gl_entries(self, voucher_type, voucher_no, expected_gl_entries): # check gl entries gl_entries = webnotes.conn.sql("""select account, debit, credit @@ -92,6 +93,125 @@ class TestStockEntry(unittest.TestCase): self.assertEquals(expected_gl_entries[i][0], gle.account) self.assertEquals(expected_gl_entries[i][1], gle.debit) self.assertEquals(expected_gl_entries[i][2], gle.credit) + + def test_sales_invoice_return_of_non_packing_item(self): + from stock.doctype.stock_entry.stock_entry import NotUpdateStockError + + from accounts.doctype.sales_invoice.test_sales_invoice \ + import test_records as sales_invoice_test_records + + # invalid sales invoice as update stock not checked + si = webnotes.bean(copy=sales_invoice_test_records[1]) + si.insert() + si.submit() + + se = webnotes.bean(copy=test_records[0]) + se.doc.purpose = "Sales Return" + se.doc.sales_invoice_no = si.doc.name + se.doclist[1].qty = 2.0 + self.assertRaises(NotUpdateStockError, se.insert) + + webnotes.conn.sql("delete from `tabStock Ledger Entry`") + webnotes.conn.sql("""delete from `tabBin`""") + material_receipt = webnotes.bean(copy=test_records[0]) + material_receipt.insert() + material_receipt.submit() + + # check currency available qty in bin + actual_qty_0 = flt(webnotes.conn.get_value("Bin", {"item_code": "_Test Item", + "warehouse": "_Test Warehouse"}, "actual_qty")) + + # insert a pos invoice with update stock + si = webnotes.bean(copy=sales_invoice_test_records[1]) + si.doc.is_pos = si.doc.update_stock = 1 + si.doclist[1].warehouse = "_Test Warehouse" + si.insert() + si.submit() + + # check available bin qty after invoice submission + actual_qty_1 = flt(webnotes.conn.get_value("Bin", {"item_code": "_Test Item", + "warehouse": "_Test Warehouse"}, "actual_qty")) + self.assertEquals(actual_qty_0 - 5, actual_qty_1) + + # check if item is validated + se = webnotes.bean(copy=test_records[0]) + se.doc.purpose = "Sales Return" + se.doc.sales_invoice_no = si.doc.name + se.doc.posting_date = "2013-03-10" + se.doclist[1].item_code = "_Test Item Home Desktop 100" + se.doclist[1].qty = 2.0 + se.doclist[1].transfer_qty = 2.0 + + # check if stock entry gets submitted + self.assertRaises(webnotes.DoesNotExistError, se.insert) + + # try again + se = webnotes.bean(copy=test_records[0]) + se.doc.purpose = "Sales Return" + se.doc.posting_date = "2013-03-10" + se.doc.sales_invoice_no = si.doc.name + se.doclist[1].qty = 2.0 + se.doclist[1].transfer_qty = 2.0 + se.insert() + + se.submit() + + # check if available qty is increased + actual_qty_2 = flt(webnotes.conn.get_value("Bin", {"item_code": "_Test Item", + "warehouse": "_Test Warehouse"}, "actual_qty")) + self.assertEquals(actual_qty_1 + 2, actual_qty_2) + + def test_sales_invoice_return_of_packing_item(self): + webnotes.conn.sql("delete from `tabStock Ledger Entry`") + webnotes.conn.sql("""delete from `tabBin`""") + material_receipt = webnotes.bean(copy=test_records[0]) + material_receipt.insert() + material_receipt.submit() + + # check currency available qty in bin + actual_qty_0 = flt(webnotes.conn.get_value("Bin", {"item_code": "_Test Item", + "warehouse": "_Test Warehouse"}, "actual_qty")) + + from accounts.doctype.sales_invoice.test_sales_invoice \ + import test_records as sales_invoice_test_records + + # insert a pos invoice with update stock + si = webnotes.bean(copy=sales_invoice_test_records[1]) + si.doc.is_pos = si.doc.update_stock = 1 + si.doclist[1].item_code = "_Test Sales BOM Item" + si.doclist[1].warehouse = "_Test Warehouse" + si.insert() + si.submit() + + # check available bin qty after invoice submission + actual_qty_1 = flt(webnotes.conn.get_value("Bin", {"item_code": "_Test Item", + "warehouse": "_Test Warehouse"}, "actual_qty")) + self.assertEquals(actual_qty_0 - 25, actual_qty_1) + + se = webnotes.bean(copy=test_records[0]) + se.doc.purpose = "Sales Return" + se.doc.posting_date = "2013-03-10" + se.doc.sales_invoice_no = si.doc.name + se.doclist[1].qty = 20.0 + se.doclist[1].transfer_qty = 20.0 + se.insert() + + se.submit() + + # check if available qty is increased + actual_qty_2 = flt(webnotes.conn.get_value("Bin", {"item_code": "_Test Item", + "warehouse": "_Test Warehouse"}, "actual_qty")) + self.assertEquals(actual_qty_1 + 20, actual_qty_2) + + + # def test_delivery_note_return_of_non_packing_item(self): + # pass + # + # def test_delivery_note_return_of_packing_item(self): + # pass + # + # def test_purchase_receipt_return(self): + # pass test_records = [ [ diff --git a/stock/doctype/stock_ledger/stock_ledger.py b/stock/doctype/stock_ledger/stock_ledger.py index 5dff992ae4..fcb4a54a47 100644 --- a/stock/doctype/stock_ledger/stock_ledger.py +++ b/stock/doctype/stock_ledger/stock_ledger.py @@ -209,12 +209,13 @@ class DocType: if v.get("actual_qty"): sle_id = self.make_entry(v) - + args = v.copy() args.update({ "sle_id": sle_id, "is_amended": is_amended }) + get_obj('Warehouse', v["warehouse"]).update_bin(args) diff --git a/stock/doctype/stock_ledger_entry/stock_ledger_entry.py b/stock/doctype/stock_ledger_entry/stock_ledger_entry.py index d1fe3d95b2..3089a57081 100644 --- a/stock/doctype/stock_ledger_entry/stock_ledger_entry.py +++ b/stock/doctype/stock_ledger_entry/stock_ledger_entry.py @@ -39,7 +39,7 @@ class DocType: self.check_stock_frozen_date() self.scrub_posting_time() self.doc.fiscal_year = get_fiscal_year(self.doc.posting_date)[0] - + #check for item quantity available in stock def actual_amt_check(self): if self.doc.batch_no: diff --git a/stock/stock_ledger.py b/stock/stock_ledger.py index 883ced7f71..f15866d46d 100644 --- a/stock/stock_ledger.py +++ b/stock/stock_ledger.py @@ -36,6 +36,7 @@ def update_entries_after(args, verbose=1): } """ previous_sle = get_sle_before_datetime(args) + qty_after_transaction = flt(previous_sle.get("qty_after_transaction")) valuation_rate = flt(previous_sle.get("valuation_rate")) stock_queue = json.loads(previous_sle.get("stock_queue") or "[]") @@ -43,7 +44,7 @@ def update_entries_after(args, verbose=1): entries_to_fix = get_sle_after_datetime(previous_sle or \ {"item_code": args["item_code"], "warehouse": args["warehouse"]}, for_update=True) - + valuation_method = get_valuation_method(args["item_code"]) for sle in entries_to_fix: @@ -127,7 +128,7 @@ def get_stock_ledger_entries(args, conditions=None, order="desc", limit=None, fo if not args.get("posting_date"): args["posting_date"] = "1900-01-01" if not args.get("posting_time"): - args["posting_time"] = "12:00" + args["posting_time"] = "00:00" return webnotes.conn.sql("""select * from `tabStock Ledger Entry` where item_code = %%(item_code)s From ee3d5cc621ae99ebeedb29f8d97a986a94c024db Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Wed, 13 Mar 2013 12:58:54 +0530 Subject: [PATCH 03/30] added validate posting time method --- utilities/transaction_base.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/utilities/transaction_base.py b/utilities/transaction_base.py index 905e98f4bc..2dc8c6a2d7 100644 --- a/utilities/transaction_base.py +++ b/utilities/transaction_base.py @@ -16,7 +16,7 @@ from __future__ import unicode_literals import webnotes -from webnotes.utils import load_json, cstr, flt +from webnotes.utils import load_json, cstr, flt, now_datetime from webnotes.model.doc import addchild from webnotes.model.controller import DocListController @@ -246,4 +246,8 @@ class TransactionBase(DocListController): [d.update({"doctype":"Communication"}) for d in comm_list] self.doclist.extend(webnotes.doclist([webnotes.doc(fielddata=d) \ - for d in comm_list])) \ No newline at end of file + for d in comm_list])) + + def validate_posting_time(self): + if not self.doc.posting_time: + self.doc.posting_time = now_datetime().strftime('%H:%M:%S') \ No newline at end of file From 47428c2d92d49153f95086246d22c2cba001dcaf Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Wed, 13 Mar 2013 15:30:05 +0530 Subject: [PATCH 04/30] more test cases for stock entry --- stock/doctype/stock_entry/test_stock_entry.py | 152 +++++++++++------- 1 file changed, 93 insertions(+), 59 deletions(-) diff --git a/stock/doctype/stock_entry/test_stock_entry.py b/stock/doctype/stock_entry/test_stock_entry.py index 3cd285d045..caf3291534 100644 --- a/stock/doctype/stock_entry/test_stock_entry.py +++ b/stock/doctype/stock_entry/test_stock_entry.py @@ -160,7 +160,21 @@ class TestStockEntry(unittest.TestCase): self.assertEquals(expected_gl_entries[i][1], gle.debit) self.assertEquals(expected_gl_entries[i][2], gle.credit) - def test_sales_invoice_return_of_non_packing_item(self): + def _clear_stock(self): + webnotes.conn.sql("delete from `tabStock Ledger Entry`") + webnotes.conn.sql("""delete from `tabBin`""") + + def _insert_material_receipt(self): + self._clear_stock() + material_receipt = webnotes.bean(copy=test_records[0]) + material_receipt.insert() + material_receipt.submit() + + def _get_actual_qty(self): + return flt(webnotes.conn.get_value("Bin", {"item_code": "_Test Item", + "warehouse": "_Test Warehouse"}, "actual_qty")) + + def _test_sales_invoice_return(self, item_code, delivered_qty, returned_qty): from stock.doctype.stock_entry.stock_entry import NotUpdateStockError from accounts.doctype.sales_invoice.test_sales_invoice \ @@ -174,39 +188,36 @@ class TestStockEntry(unittest.TestCase): se = webnotes.bean(copy=test_records[0]) se.doc.purpose = "Sales Return" se.doc.sales_invoice_no = si.doc.name - se.doclist[1].qty = 2.0 + se.doclist[1].qty = returned_qty + se.doclist[1].transfer_qty = returned_qty self.assertRaises(NotUpdateStockError, se.insert) - webnotes.conn.sql("delete from `tabStock Ledger Entry`") - webnotes.conn.sql("""delete from `tabBin`""") - material_receipt = webnotes.bean(copy=test_records[0]) - material_receipt.insert() - material_receipt.submit() + self._insert_material_receipt() # check currency available qty in bin - actual_qty_0 = flt(webnotes.conn.get_value("Bin", {"item_code": "_Test Item", - "warehouse": "_Test Warehouse"}, "actual_qty")) + actual_qty_0 = self._get_actual_qty() # insert a pos invoice with update stock si = webnotes.bean(copy=sales_invoice_test_records[1]) si.doc.is_pos = si.doc.update_stock = 1 si.doclist[1].warehouse = "_Test Warehouse" + si.doclist[1].item_code = item_code si.insert() si.submit() # check available bin qty after invoice submission - actual_qty_1 = flt(webnotes.conn.get_value("Bin", {"item_code": "_Test Item", - "warehouse": "_Test Warehouse"}, "actual_qty")) - self.assertEquals(actual_qty_0 - 5, actual_qty_1) + actual_qty_1 = self._get_actual_qty() + + self.assertEquals(actual_qty_0 - delivered_qty, actual_qty_1) # check if item is validated se = webnotes.bean(copy=test_records[0]) se.doc.purpose = "Sales Return" se.doc.sales_invoice_no = si.doc.name se.doc.posting_date = "2013-03-10" - se.doclist[1].item_code = "_Test Item Home Desktop 100" - se.doclist[1].qty = 2.0 - se.doclist[1].transfer_qty = 2.0 + se.doclist[1].item_code = "_Test Item Home Desktop 200" + se.doclist[1].qty = returned_qty + se.doclist[1].transfer_qty = returned_qty # check if stock entry gets submitted self.assertRaises(webnotes.DoesNotExistError, se.insert) @@ -216,68 +227,91 @@ class TestStockEntry(unittest.TestCase): se.doc.purpose = "Sales Return" se.doc.posting_date = "2013-03-10" se.doc.sales_invoice_no = si.doc.name - se.doclist[1].qty = 2.0 - se.doclist[1].transfer_qty = 2.0 + se.doclist[1].qty = returned_qty + se.doclist[1].transfer_qty = returned_qty + # in both cases item code remains _Test Item when returning se.insert() se.submit() # check if available qty is increased - actual_qty_2 = flt(webnotes.conn.get_value("Bin", {"item_code": "_Test Item", - "warehouse": "_Test Warehouse"}, "actual_qty")) - self.assertEquals(actual_qty_1 + 2, actual_qty_2) + actual_qty_2 = self._get_actual_qty() + + self.assertEquals(actual_qty_1 + returned_qty, actual_qty_2) + + def test_sales_invoice_return_of_non_packing_item(self): + self._test_sales_invoice_return("_Test Item", 5, 2) def test_sales_invoice_return_of_packing_item(self): - webnotes.conn.sql("delete from `tabStock Ledger Entry`") - webnotes.conn.sql("""delete from `tabBin`""") - material_receipt = webnotes.bean(copy=test_records[0]) - material_receipt.insert() - material_receipt.submit() + self._test_sales_invoice_return("_Test Sales BOM Item", 25, 20) - # check currency available qty in bin - actual_qty_0 = flt(webnotes.conn.get_value("Bin", {"item_code": "_Test Item", - "warehouse": "_Test Warehouse"}, "actual_qty")) + def _test_delivery_note_return(self, item_code, delivered_qty, returned_qty): + self._insert_material_receipt() - from accounts.doctype.sales_invoice.test_sales_invoice \ - import test_records as sales_invoice_test_records - - # insert a pos invoice with update stock - si = webnotes.bean(copy=sales_invoice_test_records[1]) - si.doc.is_pos = si.doc.update_stock = 1 - si.doclist[1].item_code = "_Test Sales BOM Item" - si.doclist[1].warehouse = "_Test Warehouse" - si.insert() - si.submit() + actual_qty_0 = self._get_actual_qty() - # check available bin qty after invoice submission - actual_qty_1 = flt(webnotes.conn.get_value("Bin", {"item_code": "_Test Item", - "warehouse": "_Test Warehouse"}, "actual_qty")) - self.assertEquals(actual_qty_0 - 25, actual_qty_1) + # insert and submit delivery note + from stock.doctype.delivery_note.test_delivery_note \ + import test_records as delivery_note_test_records + dn = webnotes.bean(copy=delivery_note_test_records[0]) + dn.doclist[1].item_code = item_code + dn.insert() + dn.submit() + actual_qty_1 = self._get_actual_qty() + + self.assertEquals(actual_qty_0 - delivered_qty, actual_qty_1) + + # insert and submit stock entry for sales return se = webnotes.bean(copy=test_records[0]) se.doc.purpose = "Sales Return" - se.doc.posting_date = "2013-03-10" - se.doc.sales_invoice_no = si.doc.name - se.doclist[1].qty = 20.0 - se.doclist[1].transfer_qty = 20.0 - se.insert() + se.doc.delivery_note_no = dn.doc.name + se.doc.posting_date = "2013-03-01" + se.doclist[1].qty = se.doclist[1].transfer_qty = returned_qty + se.insert() se.submit() - # check if available qty is increased - actual_qty_2 = flt(webnotes.conn.get_value("Bin", {"item_code": "_Test Item", - "warehouse": "_Test Warehouse"}, "actual_qty")) - self.assertEquals(actual_qty_1 + 20, actual_qty_2) + actual_qty_2 = self._get_actual_qty() + self.assertEquals(actual_qty_1 + returned_qty, actual_qty_2) + def test_delivery_note_return_of_non_packing_item(self): + self._test_delivery_note_return("_Test Item", 5, 2) + + def test_delivery_note_return_of_packing_item(self): + self._test_delivery_note_return("_Test Sales BOM Item", 25, 20) + + def test_purchase_receipt_return(self): + self._clear_stock() + + actual_qty_0 = self._get_actual_qty() + + from stock.doctype.purchase_receipt.test_purchase_receipt \ + import test_records as purchase_receipt_test_records + + # submit purchase receipt + pr = webnotes.bean(copy=purchase_receipt_test_records[0]) + pr.insert() + pr.submit() + + actual_qty_1 = self._get_actual_qty() + + self.assertEquals(actual_qty_0 + 10, actual_qty_1) + + # submit purchase return + se = webnotes.bean(copy=test_records[0]) + se.doc.purpose = "Purchase Return" + se.doc.purchase_receipt_no = pr.doc.name + se.doc.posting_date = "2013-03-01" + se.doclist[1].qty = se.doclist[1].transfer_qty = 5 + se.doclist[1].s_warehouse = "_Test Warehouse" + se.insert() + se.submit() + + actual_qty_2 = self._get_actual_qty() + + self.assertEquals(actual_qty_1 - 5, actual_qty_2) - # def test_delivery_note_return_of_non_packing_item(self): - # pass - # - # def test_delivery_note_return_of_packing_item(self): - # pass - # - # def test_purchase_receipt_return(self): - # pass test_records = [ [ From 87052b366b91f25549559982ddba22cfbcc726b3 Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Fri, 15 Mar 2013 11:32:40 +0530 Subject: [PATCH 05/30] validate over-return of stock for sales purchase return --- stock/doctype/stock_entry/stock_entry.js | 34 +++++++ stock/doctype/stock_entry/stock_entry.py | 88 ++++++++++++------- stock/doctype/stock_entry/test_stock_entry.py | 17 ++++ 3 files changed, 109 insertions(+), 30 deletions(-) diff --git a/stock/doctype/stock_entry/stock_entry.js b/stock/doctype/stock_entry/stock_entry.js index 010b27040d..158184486f 100644 --- a/stock/doctype/stock_entry/stock_entry.js +++ b/stock/doctype/stock_entry/stock_entry.js @@ -66,6 +66,17 @@ erpnext.stock.StockEntry = erpnext.stock.StockController.extend({ if (this.frm.doc.docstatus==1) { this.show_stock_ledger(); } + + if(this.frm.doc.docstatus === 1 && wn.boot.profile.can_create("Journal Voucher")) { + if(this.frm.doc.purpose === "Sales Return") { + this.frm.add_custom_button("Make Credit Note", this.make_return_jv); + this.add_excise_button(); + } else if(this.frm.doc.purpose === "Purchase Return") { + this.frm.add_custom_button("Make Debit Note", this.make_return_jv); + this.add_excise_button(); + } + } + }, on_submit: function() { @@ -143,6 +154,29 @@ erpnext.stock.StockEntry = erpnext.stock.StockController.extend({ } } }, + + add_excise_button: function() { + if(wn.boot.control_panel.country === "India") + this.frm.add_custom_button("Make Excise Invoice", function() { + var excise = wn.model.make_new_doc_and_get_name('Journal Voucher'); + excise = locals['Journal Voucher'][excise]; + excise.voucher_type = 'Excise Voucher'; + loaddoc('Journal Voucher', excise.name); + }); + }, + + make_return_jv: function() { + this.frm.call({ + method: "make_return_jv", + args: { + stock_entry: this.frm.doc.name + }, + callback: function(r) { + console.log(r); + loaddoc("Journal Voucher", r.message); + } + }); + }, }); diff --git a/stock/doctype/stock_entry/stock_entry.py b/stock/doctype/stock_entry/stock_entry.py index 38ab5ba7e4..80756b40ed 100644 --- a/stock/doctype/stock_entry/stock_entry.py +++ b/stock/doctype/stock_entry/stock_entry.py @@ -29,6 +29,7 @@ import json sql = webnotes.conn.sql class NotUpdateStockError(webnotes.ValidationError): pass +class StockOverReturnError(webnotes.ValidationError): pass from controllers.accounts_controller import AccountsController @@ -278,32 +279,24 @@ class DocType(AccountsController): def validate_return_reference_doc(self): """validate item with reference doc""" - ref_doclist = parentfields = None + ref = get_return_reference_details(self.doc.fields) - # get ref_doclist - if self.doc.purpose in return_map: - for fieldname, val in return_map[self.doc.purpose].items(): - if self.doc.fields.get(fieldname): - ref_doclist = webnotes.get_doclist(val[0], self.doc.fields[fieldname]) - parentfields = val[1] - - if ref_doclist: + if ref.doclist: # validate docstatus - if ref_doclist[0].docstatus != 1: - webnotes.msgprint(_(ref_doclist[0].doctype) + ' "' + ref_doclist[0].name + '": ' + if ref.doclist[0].docstatus != 1: + webnotes.msgprint(_(ref.doclist[0].doctype) + ' "' + ref.doclist[0].name + '": ' + _("Status should be Submitted"), raise_exception=webnotes.InvalidStatusError) - # update stock check - if ref_doclist[0].doctype == "Sales Invoice" and (cint(ref_doclist[0].is_pos) != 1 \ - or cint(ref_doclist[0].update_stock) != 1): - webnotes.msgprint(_(ref_doclist[0].doctype) + ' "' + ref_doclist[0].name + '": ' + if ref.doclist[0].doctype == "Sales Invoice" and (cint(ref.doclist[0].is_pos) != 1 \ + or cint(ref.doclist[0].update_stock) != 1): + webnotes.msgprint(_(ref.doclist[0].doctype) + ' "' + ref.doclist[0].name + '": ' + _("Is POS and Update Stock should be checked."), raise_exception=NotUpdateStockError) # posting date check - ref_posting_datetime = "%s %s" % (cstr(ref_doclist[0].posting_date), - cstr(ref_doclist[0].posting_time)) + ref_posting_datetime = "%s %s" % (cstr(ref.doclist[0].posting_date), + cstr(ref.doclist[0].posting_time)) this_posting_datetime = "%s %s" % (cstr(self.doc.posting_date), cstr(self.doc.posting_time)) if this_posting_datetime < ref_posting_datetime: @@ -312,18 +305,27 @@ class DocType(AccountsController): + ": " + datetime_in_user_format(ref_posting_datetime), raise_exception=True) - stock_items = get_stock_items_for_return(ref_doclist, parentfields) + stock_items = get_stock_items_for_return(ref.doclist, ref.parentfields) + already_returned_item_qty = self.get_already_returned_item_qty(ref.fieldname) for item in self.doclist.get({"parentfield": "mtn_details"}): # validate if item exists in the ref doclist and that it is a stock item if item.item_code not in stock_items: msgprint(_("Item") + ': "' + item.item_code + _("\" does not exist in ") + - ref_doclist[0].doctype + ": " + ref_doclist[0].name, + ref.doclist[0].doctype + ": " + ref.doclist[0].name, raise_exception=webnotes.DoesNotExistError) - # validate quantity <= ref item's qty - ref_item = ref_doclist.getone({"item_code": item.item_code}) - self.validate_value("transfer_qty", "<=", ref_item.qty, item) + # validate quantity <= ref item's qty - qty already returned + ref_item = ref.doclist.getone({"item_code": item.item_code}) + returnable_qty = ref_item.qty - flt(already_returned_item_qty.get(item.item_code)) + self.validate_value("transfer_qty", "<=", returnable_qty, item, + raise_exception=StockOverReturnError) + + def get_already_returned_item_qty(self, ref_fieldname): + return dict(webnotes.conn.sql("""select item_code, sum(transfer_qty) as qty + from `tabStock Entry Detail` where parent in ( + select name from `tabStock Entry` where `%s`=%s and docstatus=1) + group by item_code""" % (ref_fieldname, "%s"), (self.doc.fields.get(ref_fieldname),))) def update_serial_no(self, is_submit): """Create / Update Serial No""" @@ -670,7 +672,7 @@ class DocType(AccountsController): + " " + _("Row #") + (" %d %s " % (mreq_item.idx, _("of"))) + _("Material Request") + (" - %s" % item.material_request), raise_exception=webnotes.MappingMismatchError) - + @webnotes.whitelist() def get_production_order_details(production_order): result = webnotes.conn.sql("""select bom_no, @@ -700,16 +702,13 @@ def query_purchase_return_doc(doctype, txt, searchfield, start, page_len, filter def query_return_item(doctype, txt, searchfield, start, page_len, filters): txt = txt.replace("%", "") - - for fieldname, val in return_map[filters["purpose"]].items(): - if filters.get(fieldname): - ref_doclist = webnotes.get_doclist(val[0], filters[fieldname]) - parentfields = val[1] + + ref = get_return_reference_details(filters) - stock_items = get_stock_items_for_return(ref_doclist, parentfields) + stock_items = get_stock_items_for_return(ref.doclist, ref.parentfields) result = [] - for item in ref_doclist.get({"parentfield": ["in", parentfields]}): + for item in ref.doclist.get({"parentfield": ["in", ref.parentfields]}): if item.item_code in stock_items: item.item_name = cstr(item.item_name) item.description = cstr(item.description) @@ -738,6 +737,20 @@ def get_stock_items_for_return(ref_doclist, parentfields): return stock_items +def get_return_reference_details(args): + ref = webnotes._dict() + + # get ref_doclist + if args["purpose"] in return_map: + for fieldname, val in return_map[args["purpose"]].items(): + if args.get(fieldname): + ref.fieldname = fieldname + ref.doclist = webnotes.get_doclist(val[0], args[fieldname]) + ref.parentfields = val[1] + break + + return ref + return_map = { "Sales Return": { # [Ref DocType, [Item tables' parentfields]] @@ -748,3 +761,18 @@ return_map = { "purchase_receipt_no": ["Purchase Receipt", ["purchase_receipt_details"]] } } + +def make_return_jv(stock_entry): + jv = webnotes.bean({ + "doctype": "Journal Voucher", + "__islocal": 1 + }) + + se = webnotes.bean("Stock Entry", stock_entry) + + if not webnotes.response.get("docs"): + webnotes.response["docs"] = [] + + webnotes.response["docs"] = jv.doclist + + return jv.doc.name \ No newline at end of file diff --git a/stock/doctype/stock_entry/test_stock_entry.py b/stock/doctype/stock_entry/test_stock_entry.py index caf3291534..c0f8f28240 100644 --- a/stock/doctype/stock_entry/test_stock_entry.py +++ b/stock/doctype/stock_entry/test_stock_entry.py @@ -312,6 +312,23 @@ class TestStockEntry(unittest.TestCase): self.assertEquals(actual_qty_1 - 5, actual_qty_2) + return pr.doc.name + + def test_over_stock_return(self): + from stock.doctype.stock_entry.stock_entry import StockOverReturnError + + # out of 10, 5 gets returned + pr_docname = self.test_purchase_receipt_return() + + # submit purchase return - return another 6 qtys so that exception is raised + se = webnotes.bean(copy=test_records[0]) + se.doc.purpose = "Purchase Return" + se.doc.purchase_receipt_no = pr_docname + se.doc.posting_date = "2013-03-01" + se.doclist[1].qty = se.doclist[1].transfer_qty = 6 + se.doclist[1].s_warehouse = "_Test Warehouse" + + self.assertRaises(StockOverReturnError, se.insert) test_records = [ [ From 1524c2a5b6f2a2643aa4f564891be514b2d519f3 Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Fri, 15 Mar 2013 17:42:45 +0530 Subject: [PATCH 06/30] create return jv --- stock/doctype/stock_entry/stock_entry.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/stock/doctype/stock_entry/stock_entry.py b/stock/doctype/stock_entry/stock_entry.py index 80756b40ed..d5764fa54e 100644 --- a/stock/doctype/stock_entry/stock_entry.py +++ b/stock/doctype/stock_entry/stock_entry.py @@ -769,6 +769,19 @@ def make_return_jv(stock_entry): }) se = webnotes.bean("Stock Entry", stock_entry) + ref = get_return_reference_details(se.doc.fields) + + for se_item in se.doclist.get({"parentfield": "mtn_details"}): + # find item in ref.doclist + ref_item = ref.doclist.getone({"item_code": se_item.item_code}) + + # add row for customer/supplier account + + # find income account and value and add corresponding rows + + # find tax account and value and add corresponding rows + + pass if not webnotes.response.get("docs"): webnotes.response["docs"] = [] From 6230aa9292a4a2362b9ba05a129d9a235e23b0b9 Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Sat, 16 Mar 2013 19:05:11 +0530 Subject: [PATCH 07/30] make return jv for sales return --- stock/doctype/stock_entry/stock_entry.py | 142 ++++++++++++++++++++--- 1 file changed, 125 insertions(+), 17 deletions(-) diff --git a/stock/doctype/stock_entry/stock_entry.py b/stock/doctype/stock_entry/stock_entry.py index d5764fa54e..dc67b9f441 100644 --- a/stock/doctype/stock_entry/stock_entry.py +++ b/stock/doctype/stock_entry/stock_entry.py @@ -25,6 +25,7 @@ from webnotes import msgprint, _ from stock.utils import get_incoming_rate from stock.stock_ledger import get_previous_sle import json +from accounts.utils import get_balance_on sql = webnotes.conn.sql @@ -762,30 +763,137 @@ return_map = { } } +@webnotes.whitelist() def make_return_jv(stock_entry): - jv = webnotes.bean({ - "doctype": "Journal Voucher", - "__islocal": 1 - }) - se = webnotes.bean("Stock Entry", stock_entry) + if not se.doc.purpose in ["Sales Return", "Purchase Return"]: + return + ref = get_return_reference_details(se.doc.fields) - for se_item in se.doclist.get({"parentfield": "mtn_details"}): - # find item in ref.doclist - ref_item = ref.doclist.getone({"item_code": se_item.item_code}) - - # add row for customer/supplier account - - # find income account and value and add corresponding rows - - # find tax account and value and add corresponding rows - - pass + if ref.doclist[0].doctype == "Delivery Note": + result = make_return_jv_from_delivery_note(se, ref) + elif ref.doclist[0].doctype == "Sales Invoice": + result = make_return_jv_from_sales_invoice(se, ref) + elif ref.doclist[0].doctype == "Purchase Receipt": + result = make_return_jv_from_purchase_receipt(se, ref) + + # create jv doclist and fetch balance for each unique row item if not webnotes.response.get("docs"): webnotes.response["docs"] = [] webnotes.response["docs"] = jv.doclist - return jv.doc.name \ No newline at end of file + return jv.doc.name + +def make_return_jv_from_sales_invoice(se, ref): + # customer account entry + parent = { + "account": ref.doclist[0].debit_to, + "credit": 0.0, + "against_invoice": ref.doclist[0].name, + } + + # income account entries + children = {} + for se_item in se.doclist.get({"parentfield": "mtn_details"}): + # find item in ref.doclist + ref_item = ref.doclist.getone({"item_code": se_item.item_code}) + + account, debit = get_sales_account_and_amount_from_item(ref.doclist, ref_item, + se_item.transfer_qty) + + if account not in children: + children[account] = 0 + children[account] += debit + parent["credit"] += debit + + # find tax account and value and add corresponding rows + + return [parent] + [{"account": account, "debit": debit} for account, debit in children.items()] + +def get_sales_account_and_amount_from_item(doclist, ref_item, transfer_qty): + account = debit = None + if not ref_item.income_account: + if ref_item.parent_item: + parent_item = doclist.getone({"item_code": ref_item.parent_item}) + packing_ratio = parent_item.qty / ref_item.qty + + debit = parent_item.basic_rate * transfer_qty * packing_ratio + account = parent_item.income_account + else: + debit = ref_item.basic_rate * transfer_qty + account = ref_item.income_account + + return account, debit + +def make_return_jv_from_delivery_note(se, ref): + invoices_against_delivery = get_invoice_list("Sales Invoice Item", "delivery_note", + ref.doclist[0].name) + + if not invoices_against_delivery: + item_codes = [item.item_code for item in se.doclist.get({"parentfield": "mtn_details"})] + sales_orders_against_delivery = [d.prev_docname for d in + ref.doclist.get({"prev_doctype": "Sales Order"}) + if d.prev_docname and d.item_code in item_codes] + + invoices_against_delivery = get_invoice_list("Sales Order Item", "sales_order", + sales_orders_against_delivery) + + against_invoice = {} + + for se_item in se.doclist.get({"parentfield": "mtn_details"}): + pending = se_item.transfer_qty + for sales_invoice in invoices_against_delivery: + si_doclist = webnotes.get_doclist("Sales Invoice", sales_invoice) + ref_item = si_doclist.get({"item_code": se_item.item_code}) + if not ref_item: + continue + + ref_item = ref_item[0] + + if ref_item.qty < pending: + transfer_qty = ref_item.qty + pending -= ref_item.qty + else: + transfer_qty = pending + pending = 0 + + account, debit = get_sales_account_and_amount_from_item(si_doclist, ref_item, + transfer_qty) + + if si_doclist[0].name not in against_invoice: + against_invoice[sales_invoice] = { + "parent": {"account": si_doclist[0].debit_to, "credit": 0}, + "children": {} + } + + against_invoice[sales_invoice]["parent"]["credit"] += debit + + if account not in against_invoice[sales_invoice]["children"]: + against_invoice[sales_invoice]["children"][account] = 0 + + against_invoice[sales_invoice]["children"][account] += debit + + # find tax account and value and add corresponding rows + + if pending <= 0: + break + + result = [] + for sales_invoice, opts in against_invoice.items(): + result += [opts["parent"]] + [{"account": account, "debit": debit} + for account, debit in opts["children"].items()] + return result + +def get_invoice_list(doctype, link_field, value): + if isinstance(value, basestring): + value = [value] + + return webnotes.conn.sql_list("""select distinct parent from `tab%s` + where docstatus = 1 and `%s` in (%s)""" % (doctype, link_field, + ", ".join(["%s"]*len(value))), tuple(value)) + +def make_return_jv_from_purchase_receipt(se, ref): + pass From ab7b7c2974b635d37f7b8d0f28cfa050566ec4e9 Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Mon, 18 Mar 2013 17:37:31 +0530 Subject: [PATCH 08/30] completed sales purchase return as part of stock entry --- stock/doctype/delivery_note/delivery_note.py | 2 +- stock/doctype/stock_entry/stock_entry.js | 21 +- stock/doctype/stock_entry/stock_entry.py | 122 +++++++-- stock/doctype/stock_entry/test_stock_entry.py | 257 +++++++++++++++++- 4 files changed, 364 insertions(+), 38 deletions(-) diff --git a/stock/doctype/delivery_note/delivery_note.py b/stock/doctype/delivery_note/delivery_note.py index 229ec40a54..46c6ee4bd4 100644 --- a/stock/doctype/delivery_note/delivery_note.py +++ b/stock/doctype/delivery_note/delivery_note.py @@ -133,7 +133,7 @@ class DocType(SellingController): super(DocType, self).validate() import utilities - utilities.validate_status(self.doc.status, ["Draft", "submitted", "Cancelled"]) + utilities.validate_status(self.doc.status, ["Draft", "Submitted", "Cancelled"]) self.so_required() self.validate_fiscal_year() diff --git a/stock/doctype/stock_entry/stock_entry.js b/stock/doctype/stock_entry/stock_entry.js index 158184486f..0b27d99bad 100644 --- a/stock/doctype/stock_entry/stock_entry.js +++ b/stock/doctype/stock_entry/stock_entry.js @@ -60,6 +60,7 @@ erpnext.stock.StockEntry = erpnext.stock.StockController.extend({ }, refresh: function() { + var me = this; erpnext.hide_naming_series(); this.toggle_related_fields(this.frm.doc); this.toggle_enable_bom(); @@ -67,12 +68,13 @@ erpnext.stock.StockEntry = erpnext.stock.StockController.extend({ this.show_stock_ledger(); } - if(this.frm.doc.docstatus === 1 && wn.boot.profile.can_create("Journal Voucher")) { + if(this.frm.doc.docstatus === 1 && + wn.boot.profile.can_create.indexOf("Journal Voucher")!==-1) { if(this.frm.doc.purpose === "Sales Return") { - this.frm.add_custom_button("Make Credit Note", this.make_return_jv); + this.frm.add_custom_button("Make Credit Note", function() { me.make_return_jv(); }); this.add_excise_button(); } else if(this.frm.doc.purpose === "Purchase Return") { - this.frm.add_custom_button("Make Debit Note", this.make_return_jv); + this.frm.add_custom_button("Make Debit Note", function() { me.make_return_jv(); }); this.add_excise_button(); } } @@ -172,8 +174,17 @@ erpnext.stock.StockEntry = erpnext.stock.StockController.extend({ stock_entry: this.frm.doc.name }, callback: function(r) { - console.log(r); - loaddoc("Journal Voucher", r.message); + if(!r.exc) { + var jv_name = wn.model.make_new_doc_and_get_name('Journal Voucher'); + var jv = locals["Journal Voucher"][jv_name]; + $.extend(jv, r.message[0]); + $.each(r.message.slice(1), function(i, jvd) { + var child = wn.model.add_child(jv, "Journal Voucher Detail", "entries"); + $.extend(child, jvd); + }); + loaddoc("Journal Voucher", jv_name); + } + } }); }, diff --git a/stock/doctype/stock_entry/stock_entry.py b/stock/doctype/stock_entry/stock_entry.py index dc67b9f441..131e9ffcd4 100644 --- a/stock/doctype/stock_entry/stock_entry.py +++ b/stock/doctype/stock_entry/stock_entry.py @@ -25,7 +25,6 @@ from webnotes import msgprint, _ from stock.utils import get_incoming_rate from stock.stock_ledger import get_previous_sle import json -from accounts.utils import get_balance_on sql = webnotes.conn.sql @@ -297,7 +296,7 @@ class DocType(AccountsController): # posting date check ref_posting_datetime = "%s %s" % (cstr(ref.doclist[0].posting_date), - cstr(ref.doclist[0].posting_time)) + cstr(ref.doclist[0].posting_time) or "00:00:00") this_posting_datetime = "%s %s" % (cstr(self.doc.posting_date), cstr(self.doc.posting_time)) if this_posting_datetime < ref_posting_datetime: @@ -779,13 +778,30 @@ def make_return_jv(stock_entry): result = make_return_jv_from_purchase_receipt(se, ref) # create jv doclist and fetch balance for each unique row item + jv_list = [{ + "__islocal": 1, + "doctype": "Journal Voucher", + "posting_date": se.doc.posting_date, + "voucher_type": se.doc.purpose == "Sales Return" and "Credit Note" or "Debit Note", + "fiscal_year": se.doc.fiscal_year, + "company": se.doc.company + }] - if not webnotes.response.get("docs"): - webnotes.response["docs"] = [] - - webnotes.response["docs"] = jv.doclist - - return jv.doc.name + from accounts.utils import get_balance_on + for r in result: + jv_list.append({ + "__islocal": 1, + "doctype": "Journal Voucher Detail", + "parentfield": "entries", + "account": r.get("account"), + "debit": r.get("debit"), + "credit": r.get("credit"), + "against_invoice": r.get("against_invoice"), + "against_voucher": r.get("against_voucher"), + "balance": get_balance_on(r.get("account"), se.doc.posting_date) + }) + + return jv_list def make_return_jv_from_sales_invoice(se, ref): # customer account entry @@ -833,12 +849,10 @@ def make_return_jv_from_delivery_note(se, ref): ref.doclist[0].name) if not invoices_against_delivery: - item_codes = [item.item_code for item in se.doclist.get({"parentfield": "mtn_details"})] - sales_orders_against_delivery = [d.prev_docname for d in - ref.doclist.get({"prev_doctype": "Sales Order"}) - if d.prev_docname and d.item_code in item_codes] - - invoices_against_delivery = get_invoice_list("Sales Order Item", "sales_order", + sales_orders_against_delivery = [d.prevdoc_docname for d in + ref.doclist.get({"prevdoc_doctype": "Sales Order"}) if d.prevdoc_docname] + + invoices_against_delivery = get_invoice_list("Sales Invoice Item", "sales_order", sales_orders_against_delivery) against_invoice = {} @@ -846,8 +860,10 @@ def make_return_jv_from_delivery_note(se, ref): for se_item in se.doclist.get({"parentfield": "mtn_details"}): pending = se_item.transfer_qty for sales_invoice in invoices_against_delivery: - si_doclist = webnotes.get_doclist("Sales Invoice", sales_invoice) - ref_item = si_doclist.get({"item_code": se_item.item_code}) + si = webnotes.bean("Sales Invoice", sales_invoice) + si.run_method("make_packing_list") + ref_item = si.doclist.get({"item_code": se_item.item_code}) + if not ref_item: continue @@ -860,12 +876,12 @@ def make_return_jv_from_delivery_note(se, ref): transfer_qty = pending pending = 0 - account, debit = get_sales_account_and_amount_from_item(si_doclist, ref_item, + account, debit = get_sales_account_and_amount_from_item(si.doclist, ref_item, transfer_qty) - if si_doclist[0].name not in against_invoice: + if si.doclist[0].name not in against_invoice: against_invoice[sales_invoice] = { - "parent": {"account": si_doclist[0].debit_to, "credit": 0}, + "parent": {"account": si.doclist[0].debit_to, "credit": 0}, "children": {} } @@ -883,17 +899,79 @@ def make_return_jv_from_delivery_note(se, ref): result = [] for sales_invoice, opts in against_invoice.items(): - result += [opts["parent"]] + [{"account": account, "debit": debit} + parent = opts["parent"] + parent.update({"against_invoice": sales_invoice}) + children = [{"account": account, "debit": debit} for account, debit in opts["children"].items()] + result += [parent] + children return result def get_invoice_list(doctype, link_field, value): if isinstance(value, basestring): value = [value] - + return webnotes.conn.sql_list("""select distinct parent from `tab%s` where docstatus = 1 and `%s` in (%s)""" % (doctype, link_field, ", ".join(["%s"]*len(value))), tuple(value)) def make_return_jv_from_purchase_receipt(se, ref): - pass + invoice_against_receipt = get_invoice_list("Purchase Invoice Item", "purchase_receipt", + ref.doclist[0].name) + + if not invoice_against_receipt: + purchase_orders_against_receipt = [d.prevdoc_docname for d in + ref.doclist.get({"prevdoc_doctype": "Purchase Order"}) if d.prevdoc_docname] + + invoice_against_receipt = get_invoice_list("Purchase Invoice Item", "purchase_order", + purchase_orders_against_receipt) + + against_voucher = {} + + for se_item in se.doclist.get({"parentfield": "mtn_details"}): + pending = se_item.transfer_qty + for purchase_invoice in invoice_against_receipt: + pi = webnotes.bean("Purchase Invoice", purchase_invoice) + ref_item = pi.doclist.get({"item_code": se_item.item_code}) + + if not ref_item: + continue + + ref_item = ref_item[0] + + if ref_item.qty < pending: + transfer_qty = ref_item.qty + pending -= ref_item.qty + else: + transfer_qty = pending + pending = 0 + + credit = ref_item.rate * transfer_qty + account = ref_item.expense_head + + if pi.doclist[0].name not in against_voucher: + against_voucher[purchase_invoice] = { + "parent": {"account": pi.doclist[0].credit_to, "debit": 0}, + "children": {} + } + + against_voucher[purchase_invoice]["parent"]["debit"] += credit + + if account not in against_voucher[purchase_invoice]["children"]: + against_voucher[purchase_invoice]["children"][account] = 0 + + against_voucher[purchase_invoice]["children"][account] += credit + + # find tax account and value and add corresponding rows + + if pending <= 0: + break + + result = [] + for purchase_invoice, opts in against_voucher.items(): + parent = opts["parent"] + parent.update({"against_voucher": purchase_invoice}) + children = [{"account": account, "credit": credit} + for account, credit in opts["children"].items()] + result += [parent] + children + return result + \ No newline at end of file diff --git a/stock/doctype/stock_entry/test_stock_entry.py b/stock/doctype/stock_entry/test_stock_entry.py index c0f8f28240..049b0e66c8 100644 --- a/stock/doctype/stock_entry/test_stock_entry.py +++ b/stock/doctype/stock_entry/test_stock_entry.py @@ -9,6 +9,9 @@ class TestStockEntry(unittest.TestCase): def test_auto_material_request(self): webnotes.conn.sql("""delete from `tabMaterial Request Item`""") webnotes.conn.sql("""delete from `tabMaterial Request`""") + self._clear_stock() + + webnotes.conn.set_value("Global Defaults", None, "auto_indent", True) st1 = webnotes.bean(copy=test_records[0]) st1.insert() @@ -166,9 +169,14 @@ class TestStockEntry(unittest.TestCase): def _insert_material_receipt(self): self._clear_stock() - material_receipt = webnotes.bean(copy=test_records[0]) - material_receipt.insert() - material_receipt.submit() + se1 = webnotes.bean(copy=test_records[0]) + se1.insert() + se1.submit() + + se2 = webnotes.bean(copy=test_records[0]) + se2.doclist[1].item_code = "_Test Item Home Desktop 100" + se2.insert() + se2.submit() def _get_actual_qty(self): return flt(webnotes.conn.get_value("Bin", {"item_code": "_Test Item", @@ -238,6 +246,8 @@ class TestStockEntry(unittest.TestCase): actual_qty_2 = self._get_actual_qty() self.assertEquals(actual_qty_1 + returned_qty, actual_qty_2) + + return se def test_sales_invoice_return_of_non_packing_item(self): self._test_sales_invoice_return("_Test Item", 5, 2) @@ -248,11 +258,12 @@ class TestStockEntry(unittest.TestCase): def _test_delivery_note_return(self, item_code, delivered_qty, returned_qty): self._insert_material_receipt() - actual_qty_0 = self._get_actual_qty() - - # insert and submit delivery note from stock.doctype.delivery_note.test_delivery_note \ import test_records as delivery_note_test_records + + actual_qty_0 = self._get_actual_qty() + + # make a delivery note based on this invoice dn = webnotes.bean(copy=delivery_note_test_records[0]) dn.doclist[1].item_code = item_code dn.insert() @@ -262,11 +273,26 @@ class TestStockEntry(unittest.TestCase): self.assertEquals(actual_qty_0 - delivered_qty, actual_qty_1) + si_doclist = webnotes.map_doclist([ + ["Delivery Note", "Sales Invoice"], + ["Delivery Note Item", "Sales Invoice Item"], + ["Sales Taxes and Charges", "Sales Taxes and Charges"], + ["Sales Team", "Sales Team"]], dn.doc.name) + + si = webnotes.bean(si_doclist) + si.doc.posting_date = dn.doc.posting_date + si.doc.debit_to = "_Test Customer - _TC" + for d in si.doclist.get({"parentfield": "entries"}): + d.income_account = "Sales - _TC" + d.cost_center = "_Test Cost Center - _TC" + si.insert() + si.submit() + # insert and submit stock entry for sales return se = webnotes.bean(copy=test_records[0]) se.doc.purpose = "Sales Return" se.doc.delivery_note_no = dn.doc.name - se.doc.posting_date = "2013-03-01" + se.doc.posting_date = "2013-03-10" se.doclist[1].qty = se.doclist[1].transfer_qty = returned_qty se.insert() @@ -275,12 +301,115 @@ class TestStockEntry(unittest.TestCase): actual_qty_2 = self._get_actual_qty() self.assertEquals(actual_qty_1 + returned_qty, actual_qty_2) + return se + def test_delivery_note_return_of_non_packing_item(self): self._test_delivery_note_return("_Test Item", 5, 2) def test_delivery_note_return_of_packing_item(self): self._test_delivery_note_return("_Test Sales BOM Item", 25, 20) + def _test_sales_return_jv(self, se, returned_value): + from stock.doctype.stock_entry.stock_entry import make_return_jv + jv_list = make_return_jv(se.doc.name) + + self.assertEqual(len(jv_list), 3) + self.assertEqual(jv_list[0].get("voucher_type"), "Credit Note") + self.assertEqual(jv_list[0].get("posting_date"), se.doc.posting_date) + self.assertEqual(jv_list[1].get("account"), "_Test Customer - _TC") + self.assertEqual(jv_list[2].get("account"), "Sales - _TC") + self.assertTrue(jv_list[1].get("against_invoice")) + + # debit == credit + debit = sum([flt(d.get("debit")) for d in jv_list]) + credit = sum([flt(d.get("credit")) for d in jv_list]) + self.assertEqual(debit, credit) + + # validate value of debit + self.assertEqual(debit, returned_value) + + def test_make_return_jv_for_sales_invoice_non_packing_item(self): + se = self._test_sales_invoice_return("_Test Item", 5, 2) + self._test_sales_return_jv(se, 1000) + + def test_make_return_jv_for_sales_invoice_packing_item(self): + se = self._test_sales_invoice_return("_Test Sales BOM Item", 25, 20) + self._test_sales_return_jv(se, 2000) + + def test_make_return_jv_for_delivery_note_non_packing_item(self): + se = self._test_delivery_note_return("_Test Item", 5, 2) + self._test_sales_return_jv(se, 200) + + se = self._test_delivery_note_return_against_sales_order("_Test Item", 5, 2) + self._test_sales_return_jv(se, 200) + + def test_make_return_jv_for_delivery_note_packing_item(self): + se = self._test_delivery_note_return("_Test Sales BOM Item", 25, 20) + self._test_sales_return_jv(se, 400) + + se = self._test_delivery_note_return_against_sales_order("_Test Sales BOM Item", 25, 20) + self._test_sales_return_jv(se, 400) + + def _test_delivery_note_return_against_sales_order(self, item_code, delivered_qty, returned_qty): + self._insert_material_receipt() + + from selling.doctype.sales_order.test_sales_order \ + import test_records as sales_order_test_records + + actual_qty_0 = self._get_actual_qty() + + so = webnotes.bean(copy=sales_order_test_records[0]) + so.doclist[1].item_code = item_code + so.doclist[1].qty = 5.0 + so.insert() + so.submit() + + dn_doclist = webnotes.map_doclist([ + ["Sales Order", "Delivery Note"], + ["Sales Order Item", "Delivery Note Item"], + ["Sales Taxes and Charges", "Sales Taxes and Charges"], + ["Sales Team", "Sales Team"]], so.doc.name) + + dn = webnotes.bean(dn_doclist) + dn.doc.status = "Draft" + dn.doc.posting_date = so.doc.delivery_date + dn.insert() + dn.submit() + + actual_qty_1 = self._get_actual_qty() + + self.assertEquals(actual_qty_0 - delivered_qty, actual_qty_1) + + si_doclist = webnotes.map_doclist([ + ["Sales Order", "Sales Invoice"], + ["Sales Order Item", "Sales Invoice Item"], + ["Sales Taxes and Charges", "Sales Taxes and Charges"], + ["Sales Team", "Sales Team"]], so.doc.name) + + si = webnotes.bean(si_doclist) + si.doc.posting_date = dn.doc.posting_date + si.doc.debit_to = "_Test Customer - _TC" + for d in si.doclist.get({"parentfield": "entries"}): + d.income_account = "Sales - _TC" + d.cost_center = "_Test Cost Center - _TC" + si.insert() + si.submit() + + # insert and submit stock entry for sales return + se = webnotes.bean(copy=test_records[0]) + se.doc.purpose = "Sales Return" + se.doc.delivery_note_no = dn.doc.name + se.doc.posting_date = "2013-03-10" + se.doclist[1].qty = se.doclist[1].transfer_qty = returned_qty + + se.insert() + se.submit() + + actual_qty_2 = self._get_actual_qty() + self.assertEquals(actual_qty_1 + returned_qty, actual_qty_2) + + return se + def test_purchase_receipt_return(self): self._clear_stock() @@ -298,6 +427,24 @@ class TestStockEntry(unittest.TestCase): self.assertEquals(actual_qty_0 + 10, actual_qty_1) + pi_doclist = webnotes.map_doclist([ + ["Purchase Receipt", "Purchase Invoice"], + ["Purchase Receipt Item", "Purchase Invoice Item"], + ["Purchase Taxes and Charges", "Purchase Taxes and Charges"]], pr.doc.name) + + pi = webnotes.bean(pi_doclist) + pi.doc.posting_date = pr.doc.posting_date + pi.doc.credit_to = "_Test Supplier - _TC" + for d in pi.doclist.get({"parentfield": "entries"}): + d.expense_head = "_Test Account Cost for Goods Sold - _TC" + d.cost_center = "_Test Cost Center - _TC" + for d in pi.doclist.get({"parentfield": "purchase_tax_details"}): + d.cost_center = "_Test Cost Center - _TC" + + pi.run_method("calculate_taxes_and_totals") + pi.insert() + pi.submit() + # submit purchase return se = webnotes.bean(copy=test_records[0]) se.doc.purpose = "Purchase Return" @@ -312,13 +459,13 @@ class TestStockEntry(unittest.TestCase): self.assertEquals(actual_qty_1 - 5, actual_qty_2) - return pr.doc.name + return se, pr.doc.name def test_over_stock_return(self): from stock.doctype.stock_entry.stock_entry import StockOverReturnError # out of 10, 5 gets returned - pr_docname = self.test_purchase_receipt_return() + prev_se, pr_docname = self.test_purchase_receipt_return() # submit purchase return - return another 6 qtys so that exception is raised se = webnotes.bean(copy=test_records[0]) @@ -329,7 +476,97 @@ class TestStockEntry(unittest.TestCase): se.doclist[1].s_warehouse = "_Test Warehouse" self.assertRaises(StockOverReturnError, se.insert) - + + def _test_purchase_return_jv(self, se, returned_value): + from stock.doctype.stock_entry.stock_entry import make_return_jv + jv_list = make_return_jv(se.doc.name) + + self.assertEqual(len(jv_list), 3) + self.assertEqual(jv_list[0].get("voucher_type"), "Debit Note") + self.assertEqual(jv_list[0].get("posting_date"), se.doc.posting_date) + self.assertEqual(jv_list[1].get("account"), "_Test Supplier - _TC") + self.assertEqual(jv_list[2].get("account"), "_Test Account Cost for Goods Sold - _TC") + self.assertTrue(jv_list[1].get("against_voucher")) + + # debit == credit + debit = sum([flt(d.get("debit")) for d in jv_list]) + credit = sum([flt(d.get("credit")) for d in jv_list]) + self.assertEqual(debit, credit) + + # validate value of credit + self.assertEqual(credit, returned_value) + + def test_make_return_jv_for_purchase_receipt(self): + se, pr_name = self.test_purchase_receipt_return() + self._test_purchase_return_jv(se, 250) + + se, pr_name = self._test_purchase_return_return_against_purchase_order() + self._test_purchase_return_jv(se, 250) + + def _test_purchase_return_return_against_purchase_order(self): + self._clear_stock() + + actual_qty_0 = self._get_actual_qty() + + from buying.doctype.purchase_order.test_purchase_order \ + import test_records as purchase_order_test_records + + # submit purchase receipt + po = webnotes.bean(copy=purchase_order_test_records[0]) + po.doc.is_subcontracted = None + po.doclist[1].item_code = "_Test Item" + po.doclist[1].import_rate = 50 + po.insert() + po.submit() + + pr_doclist = webnotes.map_doclist([ + ["Purchase Order", "Purchase Receipt"], + ["Purchase Order Item", "Purchase Receipt Item"], + ["Purchase Taxes and Charges", "Purchase Taxes and Charges"]], po.doc.name) + + pr = webnotes.bean(pr_doclist) + pr.doc.posting_date = po.doc.transaction_date + pr.insert() + pr.submit() + + actual_qty_1 = self._get_actual_qty() + + self.assertEquals(actual_qty_0 + 10, actual_qty_1) + + pi_doclist = webnotes.map_doclist([ + ["Purchase Order", "Purchase Invoice"], + ["Purchase Order Item", "Purchase Invoice Item"], + ["Purchase Taxes and Charges", "Purchase Taxes and Charges"]], po.doc.name) + + pi = webnotes.bean(pi_doclist) + pi.doc.posting_date = pr.doc.posting_date + pi.doc.credit_to = "_Test Supplier - _TC" + for d in pi.doclist.get({"parentfield": "entries"}): + d.expense_head = "_Test Account Cost for Goods Sold - _TC" + d.cost_center = "_Test Cost Center - _TC" + for d in pi.doclist.get({"parentfield": "purchase_tax_details"}): + d.cost_center = "_Test Cost Center - _TC" + + pi.run_method("calculate_taxes_and_totals") + pi.insert() + pi.submit() + + # submit purchase return + se = webnotes.bean(copy=test_records[0]) + se.doc.purpose = "Purchase Return" + se.doc.purchase_receipt_no = pr.doc.name + se.doc.posting_date = "2013-03-01" + se.doclist[1].qty = se.doclist[1].transfer_qty = 5 + se.doclist[1].s_warehouse = "_Test Warehouse" + se.insert() + se.submit() + + actual_qty_2 = self._get_actual_qty() + + self.assertEquals(actual_qty_1 - 5, actual_qty_2) + + return se, pr.doc.name + test_records = [ [ { From 080f9098c01d81d3c413a3e56c28692c5025ecdb Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Mon, 18 Mar 2013 17:57:59 +0530 Subject: [PATCH 09/30] deprecated sales and purchase return tool --- accounts/page/accounts_home/accounts_home.js | 6 - buying/page/buying_home/buying_home.js | 6 - home/page/latest_updates/latest_updates.js | 1 + .../p06_remove_sales_purchase_return_tool.py | 5 + patches/patch_list.py | 1 + .../__init__.py | 1 - .../locale/_messages_doc.json | 13 - .../locale/ar-doc.json | 13 - .../locale/de-doc.json | 13 - .../locale/es-doc.json | 13 - .../locale/fr-doc.json | 13 - .../locale/hi-doc.json | 13 - .../locale/hr-doc.json | 13 - .../locale/nl-doc.json | 13 - .../locale/pt-BR-doc.json | 13 - .../locale/pt-doc.json | 13 - .../locale/sr-doc.json | 13 - .../locale/ta-doc.json | 13 - .../locale/th-doc.json | 13 - .../sales_and_purchase_return_item.py | 22 -- .../sales_and_purchase_return_item.txt | 110 --------- selling/page/selling_home/selling_home.js | 6 - .../__init__.py | 1 - .../locale/_messages_doc.json | 21 -- .../locale/ar-doc.json | 21 -- .../locale/de-doc.json | 21 -- .../locale/es-doc.json | 21 -- .../locale/fr-doc.json | 21 -- .../locale/hi-doc.json | 21 -- .../locale/hr-doc.json | 21 -- .../locale/nl-doc.json | 21 -- .../locale/pt-BR-doc.json | 21 -- .../locale/pt-doc.json | 21 -- .../locale/sr-doc.json | 21 -- .../locale/ta-doc.json | 21 -- .../locale/th-doc.json | 21 -- .../sales_and_purchase_return_tool.js | 229 ------------------ .../sales_and_purchase_return_tool.py | 71 ------ .../sales_and_purchase_return_tool.txt | 191 --------------- stock/page/stock_home/stock_home.js | 6 - 40 files changed, 7 insertions(+), 1091 deletions(-) create mode 100644 patches/march_2013/p06_remove_sales_purchase_return_tool.py delete mode 100644 selling/doctype/sales_and_purchase_return_item/__init__.py delete mode 100644 selling/doctype/sales_and_purchase_return_item/locale/_messages_doc.json delete mode 100644 selling/doctype/sales_and_purchase_return_item/locale/ar-doc.json delete mode 100644 selling/doctype/sales_and_purchase_return_item/locale/de-doc.json delete mode 100644 selling/doctype/sales_and_purchase_return_item/locale/es-doc.json delete mode 100644 selling/doctype/sales_and_purchase_return_item/locale/fr-doc.json delete mode 100644 selling/doctype/sales_and_purchase_return_item/locale/hi-doc.json delete mode 100644 selling/doctype/sales_and_purchase_return_item/locale/hr-doc.json delete mode 100644 selling/doctype/sales_and_purchase_return_item/locale/nl-doc.json delete mode 100644 selling/doctype/sales_and_purchase_return_item/locale/pt-BR-doc.json delete mode 100644 selling/doctype/sales_and_purchase_return_item/locale/pt-doc.json delete mode 100644 selling/doctype/sales_and_purchase_return_item/locale/sr-doc.json delete mode 100644 selling/doctype/sales_and_purchase_return_item/locale/ta-doc.json delete mode 100644 selling/doctype/sales_and_purchase_return_item/locale/th-doc.json delete mode 100644 selling/doctype/sales_and_purchase_return_item/sales_and_purchase_return_item.py delete mode 100644 selling/doctype/sales_and_purchase_return_item/sales_and_purchase_return_item.txt delete mode 100644 stock/doctype/sales_and_purchase_return_tool/__init__.py delete mode 100644 stock/doctype/sales_and_purchase_return_tool/locale/_messages_doc.json delete mode 100644 stock/doctype/sales_and_purchase_return_tool/locale/ar-doc.json delete mode 100644 stock/doctype/sales_and_purchase_return_tool/locale/de-doc.json delete mode 100644 stock/doctype/sales_and_purchase_return_tool/locale/es-doc.json delete mode 100644 stock/doctype/sales_and_purchase_return_tool/locale/fr-doc.json delete mode 100644 stock/doctype/sales_and_purchase_return_tool/locale/hi-doc.json delete mode 100644 stock/doctype/sales_and_purchase_return_tool/locale/hr-doc.json delete mode 100644 stock/doctype/sales_and_purchase_return_tool/locale/nl-doc.json delete mode 100644 stock/doctype/sales_and_purchase_return_tool/locale/pt-BR-doc.json delete mode 100644 stock/doctype/sales_and_purchase_return_tool/locale/pt-doc.json delete mode 100644 stock/doctype/sales_and_purchase_return_tool/locale/sr-doc.json delete mode 100644 stock/doctype/sales_and_purchase_return_tool/locale/ta-doc.json delete mode 100644 stock/doctype/sales_and_purchase_return_tool/locale/th-doc.json delete mode 100644 stock/doctype/sales_and_purchase_return_tool/sales_and_purchase_return_tool.js delete mode 100644 stock/doctype/sales_and_purchase_return_tool/sales_and_purchase_return_tool.py delete mode 100644 stock/doctype/sales_and_purchase_return_tool/sales_and_purchase_return_tool.txt diff --git a/accounts/page/accounts_home/accounts_home.js b/accounts/page/accounts_home/accounts_home.js index f2faf93785..403d7bdb3f 100644 --- a/accounts/page/accounts_home/accounts_home.js +++ b/accounts/page/accounts_home/accounts_home.js @@ -63,12 +63,6 @@ wn.module_page["Accounts"] = [ "doctype": "Period Closing Voucher", description: "Close Balance Sheet and book Profit or Loss." }, - { - "route":"Form/Sales and Purchase Return Tool/Sales and Purchase Return Tool", - "label": wn._("Sales and Purchase Return Tool"), - description: wn._("Manage sales or purchase returns"), - "doctype": "Sales and Purchase Return Tool" - }, { "page":"voucher-import-tool", "label": wn._("Voucher Import Tool"), diff --git a/buying/page/buying_home/buying_home.js b/buying/page/buying_home/buying_home.js index 922e7acefa..2df5f6fb07 100644 --- a/buying/page/buying_home/buying_home.js +++ b/buying/page/buying_home/buying_home.js @@ -80,12 +80,6 @@ wn.module_page["Buying"] = [ title: wn._("Tools"), icon: "icon-wrench", items: [ - { - "route":"Form/Sales and Purchase Return Tool/Sales and Purchase Return Tool", - "label":wn._("Purchase Returns"), - "description":wn._("Helper for managing return of goods (sales or purchase)"), - doctype: "Sales and Purchase Return Tool" - }, ] }, { diff --git a/home/page/latest_updates/latest_updates.js b/home/page/latest_updates/latest_updates.js index 84db37287f..183352ce04 100644 --- a/home/page/latest_updates/latest_updates.js +++ b/home/page/latest_updates/latest_updates.js @@ -1,4 +1,5 @@ erpnext.updates = [ + ["19th March", ["Sales and Purchase Return Tool deprecated. Use Stock Entry instead."]], ["12th March", ["Updates to website module. Added more options in Style Settings and Website Settings."]], ["5th March", ["Refactored Upload Attendance Tool"]], ["4th March", ["Lead organization added in Quotation classic/spartan/modern print format"]], diff --git a/patches/march_2013/p06_remove_sales_purchase_return_tool.py b/patches/march_2013/p06_remove_sales_purchase_return_tool.py new file mode 100644 index 0000000000..e907e4a1c2 --- /dev/null +++ b/patches/march_2013/p06_remove_sales_purchase_return_tool.py @@ -0,0 +1,5 @@ +import webnotes + +def execute(): + webnotes.delete_doc("DocType", "Sales and Purchase Return Item") + webnotes.delete_doc("DocType", "Sales and Purchase Return Tool") \ No newline at end of file diff --git a/patches/patch_list.py b/patches/patch_list.py index 1120848535..236ef45fd2 100644 --- a/patches/patch_list.py +++ b/patches/patch_list.py @@ -213,4 +213,5 @@ patch_list = [ "execute:webnotes.reload_doc('hr', 'search_criteria', 'monthly_attendance_details')", "patches.march_2013.p04_pos_update_stock_check", "patches.march_2013.p05_payment_reconciliation", + "patches.march_2013.p06_remove_sales_purchase_return_tool", ] \ No newline at end of file diff --git a/selling/doctype/sales_and_purchase_return_item/__init__.py b/selling/doctype/sales_and_purchase_return_item/__init__.py deleted file mode 100644 index baffc48825..0000000000 --- a/selling/doctype/sales_and_purchase_return_item/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/selling/doctype/sales_and_purchase_return_item/locale/_messages_doc.json b/selling/doctype/sales_and_purchase_return_item/locale/_messages_doc.json deleted file mode 100644 index 5129542747..0000000000 --- a/selling/doctype/sales_and_purchase_return_item/locale/_messages_doc.json +++ /dev/null @@ -1,13 +0,0 @@ -[ - "Selling", - "Description", - "Sales and Purchase Return Item", - "Qty", - "Serial No", - "Rate", - "Detail Name", - "Batch No", - "Returned Qty", - "Item Code", - "UOM" -] \ No newline at end of file diff --git a/selling/doctype/sales_and_purchase_return_item/locale/ar-doc.json b/selling/doctype/sales_and_purchase_return_item/locale/ar-doc.json deleted file mode 100644 index 79de9e8203..0000000000 --- a/selling/doctype/sales_and_purchase_return_item/locale/ar-doc.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "Batch No": "\u0644\u0627 \u062f\u0641\u0639\u0629", - "Description": "\u0648\u0635\u0641", - "Detail Name": "\u0627\u0644\u0627\u0633\u0645", - "Item Code": "\u0627\u0644\u0628\u0646\u062f \u0627\u0644\u0631\u0645\u0632", - "Qty": "\u0627\u0644\u0643\u0645\u064a\u0629", - "Rate": "\u0645\u0639\u062f\u0644", - "Returned Qty": "\u0639\u0627\u062f \u0627\u0644\u0643\u0645\u064a\u0629", - "Sales and Purchase Return Item": "\u0645\u0628\u064a\u0639\u0627\u062a \u0648\u0634\u0631\u0627\u0621 \u0627\u0644\u0633\u0644\u0639\u0629 \u0627\u0644\u0639\u0648\u062f\u0629", - "Selling": "\u0628\u064a\u0639", - "Serial No": "\u0627\u0644\u0645\u0633\u0644\u0633\u0644 \u0644\u0627", - "UOM": "UOM" -} \ No newline at end of file diff --git a/selling/doctype/sales_and_purchase_return_item/locale/de-doc.json b/selling/doctype/sales_and_purchase_return_item/locale/de-doc.json deleted file mode 100644 index bfcbf4e9ea..0000000000 --- a/selling/doctype/sales_and_purchase_return_item/locale/de-doc.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "Batch No": "Batch No", - "Description": "Beschreibung", - "Detail Name": "Detail Name", - "Item Code": "Item Code", - "Qty": "Menge", - "Rate": "Rate", - "Returned Qty": "Kehrte Menge", - "Sales and Purchase Return Item": "Sales and Purchase Zur\u00fcck Artikel", - "Selling": "Verkauf", - "Serial No": "Serial In", - "UOM": "UOM" -} \ No newline at end of file diff --git a/selling/doctype/sales_and_purchase_return_item/locale/es-doc.json b/selling/doctype/sales_and_purchase_return_item/locale/es-doc.json deleted file mode 100644 index 189f5e9203..0000000000 --- a/selling/doctype/sales_and_purchase_return_item/locale/es-doc.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "Batch No": "Lote n \u00ba", - "Description": "Descripci\u00f3n", - "Detail Name": "Detalle Nombre", - "Item Code": "C\u00f3digo del art\u00edculo", - "Qty": "Cantidad", - "Rate": "Velocidad", - "Returned Qty": "Cantidad devuelta", - "Sales and Purchase Return Item": "Venta y Compra de art\u00edculo de vuelta", - "Selling": "De venta", - "Serial No": "N\u00famero de orden", - "UOM": "UOM" -} \ No newline at end of file diff --git a/selling/doctype/sales_and_purchase_return_item/locale/fr-doc.json b/selling/doctype/sales_and_purchase_return_item/locale/fr-doc.json deleted file mode 100644 index 5064cd702a..0000000000 --- a/selling/doctype/sales_and_purchase_return_item/locale/fr-doc.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "Batch No": "Aucun lot", - "Description": "Description", - "Detail Name": "Nom de d\u00e9tails", - "Item Code": "Code de l'article", - "Qty": "Qt\u00e9", - "Rate": "Taux", - "Returned Qty": "Quantit\u00e9 retourn\u00e9e", - "Sales and Purchase Return Item": "Vente et achat du lot Retour", - "Selling": "Vente", - "Serial No": "N \u00b0 de s\u00e9rie", - "UOM": "Emballage" -} \ No newline at end of file diff --git a/selling/doctype/sales_and_purchase_return_item/locale/hi-doc.json b/selling/doctype/sales_and_purchase_return_item/locale/hi-doc.json deleted file mode 100644 index 283b26642d..0000000000 --- a/selling/doctype/sales_and_purchase_return_item/locale/hi-doc.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "Batch No": "\u0915\u094b\u0908 \u092c\u0948\u091a", - "Description": "\u0935\u093f\u0935\u0930\u0923", - "Detail Name": "\u0935\u093f\u0938\u094d\u0924\u093e\u0930 \u0938\u0947 \u0928\u093e\u092e", - "Item Code": "\u0906\u0907\u091f\u092e \u0915\u094b\u0921", - "Qty": "\u092e\u093e\u0924\u094d\u0930\u093e", - "Rate": "\u0926\u0930", - "Returned Qty": "\u0935\u093e\u092a\u0938 \u0906 \u0917\u090f \u092e\u093e\u0924\u094d\u0930\u093e", - "Sales and Purchase Return Item": "\u092c\u093f\u0915\u094d\u0930\u0940 \u0914\u0930 \u0916\u0930\u0940\u0926 \u0915\u0947 \u092e\u0926 \u0935\u093e\u092a\u0938\u0940", - "Selling": "\u0935\u093f\u0915\u094d\u0930\u092f", - "Serial No": "\u0928\u0939\u0940\u0902 \u0938\u0940\u0930\u093f\u092f\u0932", - "UOM": "UOM" -} \ No newline at end of file diff --git a/selling/doctype/sales_and_purchase_return_item/locale/hr-doc.json b/selling/doctype/sales_and_purchase_return_item/locale/hr-doc.json deleted file mode 100644 index 6d5ba064c2..0000000000 --- a/selling/doctype/sales_and_purchase_return_item/locale/hr-doc.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "Batch No": "Hrpa Ne", - "Description": "Opis", - "Detail Name": "Detalj Ime", - "Item Code": "Stavka \u0160ifra", - "Qty": "Kol", - "Rate": "Stopa", - "Returned Qty": "Vra\u0107eno Kol", - "Sales and Purchase Return Item": "Prodaja i kupnja Povratak Stavka", - "Selling": "Prodaja", - "Serial No": "Serijski br", - "UOM": "UOM" -} \ No newline at end of file diff --git a/selling/doctype/sales_and_purchase_return_item/locale/nl-doc.json b/selling/doctype/sales_and_purchase_return_item/locale/nl-doc.json deleted file mode 100644 index 8fe31bea89..0000000000 --- a/selling/doctype/sales_and_purchase_return_item/locale/nl-doc.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "Batch No": "Batch nr.", - "Description": "Beschrijving", - "Detail Name": "Detail Naam", - "Item Code": "Artikelcode", - "Qty": "Aantal", - "Rate": "Tarief", - "Returned Qty": "Geretourneerde Aantal", - "Sales and Purchase Return Item": "Verkoop en Inkoop Return Item", - "Selling": "Selling", - "Serial No": "Serienummer", - "UOM": "Verpakking" -} \ No newline at end of file diff --git a/selling/doctype/sales_and_purchase_return_item/locale/pt-BR-doc.json b/selling/doctype/sales_and_purchase_return_item/locale/pt-BR-doc.json deleted file mode 100644 index 3cc5b3441e..0000000000 --- a/selling/doctype/sales_and_purchase_return_item/locale/pt-BR-doc.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "Batch No": "N\u00ba do Lote", - "Description": "Descri\u00e7\u00e3o", - "Detail Name": "Nome do Detalhe", - "Item Code": "C\u00f3digo do Item", - "Qty": "Qtde.", - "Rate": "Taxa", - "Returned Qty": "Qtde. retornada", - "Sales and Purchase Return Item": "Item de retorno de compra e venda", - "Selling": "Vendas", - "Serial No": "N\u00ba de S\u00e9rie", - "UOM": "UDM" -} \ No newline at end of file diff --git a/selling/doctype/sales_and_purchase_return_item/locale/pt-doc.json b/selling/doctype/sales_and_purchase_return_item/locale/pt-doc.json deleted file mode 100644 index 56340bc041..0000000000 --- a/selling/doctype/sales_and_purchase_return_item/locale/pt-doc.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "Batch No": "No lote", - "Description": "Descri\u00e7\u00e3o", - "Detail Name": "Nome detalhes", - "Item Code": "C\u00f3digo do artigo", - "Qty": "Qty", - "Rate": "Taxa", - "Returned Qty": "Qtde voltou", - "Sales and Purchase Return Item": "Vendas e item retorno de compra", - "Selling": "Vendendo", - "Serial No": "N \u00ba de S\u00e9rie", - "UOM": "UOM" -} \ No newline at end of file diff --git a/selling/doctype/sales_and_purchase_return_item/locale/sr-doc.json b/selling/doctype/sales_and_purchase_return_item/locale/sr-doc.json deleted file mode 100644 index e507094727..0000000000 --- a/selling/doctype/sales_and_purchase_return_item/locale/sr-doc.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "Batch No": "\u0413\u0440\u0443\u043f\u043d\u043e \u041d\u0435\u043c\u0430", - "Description": "\u041e\u043f\u0438\u0441", - "Detail Name": "\u0414\u0435\u0442\u0430\u0459 \u0418\u043c\u0435", - "Item Code": "\u0428\u0438\u0444\u0440\u0430", - "Qty": "\u041a\u043e\u043b", - "Rate": "\u0421\u0442\u043e\u043f\u0430", - "Returned Qty": "\u0412\u0440\u0430\u045b\u0435\u043d\u0438 \u041a\u043e\u043b", - "Sales and Purchase Return Item": "\u041f\u0440\u043e\u0434\u0430\u0458\u0430 \u0438 \u043a\u0443\u043f\u043e\u0432\u0438\u043d\u0430 \u041f\u043e\u0432\u0440\u0430\u0442\u0430\u043a \u0430\u0443\u043a\u0446\u0438\u0458\u0438", - "Selling": "\u041f\u0440\u043e\u0434\u0430\u0458\u0430", - "Serial No": "\u0421\u0435\u0440\u0438\u0458\u0441\u043a\u0438 \u0431\u0440\u043e\u0458", - "UOM": "\u0423\u041e\u041c" -} \ No newline at end of file diff --git a/selling/doctype/sales_and_purchase_return_item/locale/ta-doc.json b/selling/doctype/sales_and_purchase_return_item/locale/ta-doc.json deleted file mode 100644 index c60a0814c2..0000000000 --- a/selling/doctype/sales_and_purchase_return_item/locale/ta-doc.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "Batch No": "\u0ba4\u0bc6\u0bbe\u0b95\u0bc1\u0ba4\u0bbf \u0b87\u0bb2\u0bcd\u0bb2\u0bc8", - "Description": "\u0bb5\u0bbf\u0bb3\u0b95\u0bcd\u0b95\u0bae\u0bcd", - "Detail Name": "\u0bb5\u0bbf\u0bb0\u0bbf\u0bb5\u0bbe\u0b95 \u0baa\u0bc6\u0baf\u0bb0\u0bcd", - "Item Code": "\u0b89\u0bb0\u0bc1\u0baa\u0bcd\u0baa\u0b9f\u0bbf\u0baf\u0bc8 \u0b95\u0bc7\u0bbe\u0b9f\u0bcd", - "Qty": "\u0b85\u0bb3\u0bb5\u0bc1", - "Rate": "\u0bb5\u0bbf\u0bb2\u0bc8", - "Returned Qty": "\u0ba4\u0bbf\u0bb0\u0bc1\u0bae\u0bcd\u0baa\u0bbf \u0b85\u0bb3\u0bb5\u0bc1", - "Sales and Purchase Return Item": "\u0bb5\u0bbf\u0bb1\u0bcd\u0baa\u0ba9\u0bc8 \u0bae\u0bb1\u0bcd\u0bb1\u0bc1\u0bae\u0bcd \u0b95\u0bc6\u0bbe\u0bb3\u0bcd\u0bae\u0bc1\u0ba4\u0bb2\u0bcd \u0ba4\u0bbf\u0bb0\u0bc1\u0bae\u0bcd\u0baa \u0b89\u0bb0\u0bc1\u0baa\u0bcd\u0baa\u0b9f\u0bbf", - "Selling": "\u0bb5\u0bbf\u0bb1\u0bcd\u0baa\u0ba9\u0bc8", - "Serial No": "\u0b87\u0bb2\u0bcd\u0bb2\u0bc8 \u0ba4\u0bc6\u0bbe\u0b9f\u0bb0\u0bcd", - "UOM": "\u0bae\u0bc6\u0bbe\u0bb1\u0b9f\u0bcd\u0b9f\u0bc1\u0bb5 \u0baa\u0bb2\u0bcd\u0b95\u0bb2\u0bc8\u0b95\u0bb4\u0b95\u0bae\u0bcd" -} \ No newline at end of file diff --git a/selling/doctype/sales_and_purchase_return_item/locale/th-doc.json b/selling/doctype/sales_and_purchase_return_item/locale/th-doc.json deleted file mode 100644 index b47f740a3a..0000000000 --- a/selling/doctype/sales_and_purchase_return_item/locale/th-doc.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "Batch No": "\u0e0a\u0e38\u0e14\u0e44\u0e21\u0e48\u0e21\u0e35", - "Description": "\u0e25\u0e31\u0e01\u0e29\u0e13\u0e30", - "Detail Name": "\u0e0a\u0e37\u0e48\u0e2d\u0e23\u0e32\u0e22\u0e25\u0e30\u0e40\u0e2d\u0e35\u0e22\u0e14", - "Item Code": "\u0e23\u0e2b\u0e31\u0e2a\u0e2a\u0e34\u0e19\u0e04\u0e49\u0e32", - "Qty": "\u0e08\u0e33\u0e19\u0e27\u0e19", - "Rate": "\u0e2d\u0e31\u0e15\u0e23\u0e32", - "Returned Qty": "\u0e08\u0e33\u0e19\u0e27\u0e19\u0e01\u0e25\u0e31\u0e1a", - "Sales and Purchase Return Item": "\u0e01\u0e32\u0e23\u0e02\u0e32\u0e22\u0e41\u0e25\u0e30\u0e01\u0e32\u0e23\u0e0b\u0e37\u0e49\u0e2d\u0e2a\u0e34\u0e19\u0e04\u0e49\u0e32\u0e01\u0e25\u0e31\u0e1a", - "Selling": "\u0e02\u0e32\u0e22", - "Serial No": "\u0e2d\u0e19\u0e38\u0e01\u0e23\u0e21\u0e44\u0e21\u0e48\u0e21\u0e35", - "UOM": "UOM" -} \ No newline at end of file diff --git a/selling/doctype/sales_and_purchase_return_item/sales_and_purchase_return_item.py b/selling/doctype/sales_and_purchase_return_item/sales_and_purchase_return_item.py deleted file mode 100644 index 7f48feb2eb..0000000000 --- a/selling/doctype/sales_and_purchase_return_item/sales_and_purchase_return_item.py +++ /dev/null @@ -1,22 +0,0 @@ -# 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 . - -from __future__ import unicode_literals -import webnotes - -class DocType: - def __init__(self, d, dl): - self.doc, self.doclist = d, dl \ No newline at end of file diff --git a/selling/doctype/sales_and_purchase_return_item/sales_and_purchase_return_item.txt b/selling/doctype/sales_and_purchase_return_item/sales_and_purchase_return_item.txt deleted file mode 100644 index 4f844b3158..0000000000 --- a/selling/doctype/sales_and_purchase_return_item/sales_and_purchase_return_item.txt +++ /dev/null @@ -1,110 +0,0 @@ -[ - { - "creation": "2013-02-22 01:27:52", - "docstatus": 0, - "modified": "2013-03-07 07:03:30", - "modified_by": "Administrator", - "owner": "wasim@webnotestech.com" - }, - { - "doctype": "DocType", - "istable": 1, - "module": "Selling", - "name": "__common__" - }, - { - "doctype": "DocField", - "name": "__common__", - "parent": "Sales and Purchase Return Item", - "parentfield": "fields", - "parenttype": "DocType", - "permlevel": 0 - }, - { - "doctype": "DocType", - "name": "Sales and Purchase Return Item" - }, - { - "doctype": "DocField", - "fieldname": "item_code", - "fieldtype": "Link", - "label": "Item Code", - "oldfieldname": "item_code", - "oldfieldtype": "Link", - "options": "Item", - "read_only": 1, - "reqd": 1 - }, - { - "doctype": "DocField", - "fieldname": "description", - "fieldtype": "Data", - "label": "Description", - "oldfieldname": "description", - "oldfieldtype": "Data", - "print_width": "300px", - "read_only": 1, - "width": "300px" - }, - { - "doctype": "DocField", - "fieldname": "uom", - "fieldtype": "Link", - "label": "UOM", - "oldfieldname": "uom", - "oldfieldtype": "Link", - "options": "UOM", - "read_only": 1, - "search_index": 0 - }, - { - "doctype": "DocField", - "fieldname": "rate", - "fieldtype": "Currency", - "label": "Rate", - "oldfieldname": "rate", - "oldfieldtype": "Currency", - "options": "Company:company:default_currency", - "read_only": 1 - }, - { - "doctype": "DocField", - "fieldname": "qty", - "fieldtype": "Data", - "label": "Qty", - "oldfieldname": "qty", - "oldfieldtype": "Data", - "read_only": 1 - }, - { - "doctype": "DocField", - "fieldname": "returned_qty", - "fieldtype": "Data", - "label": "Returned Qty", - "oldfieldname": "returned_qty", - "oldfieldtype": "Data", - "reqd": 1 - }, - { - "doctype": "DocField", - "fieldname": "serial_no", - "fieldtype": "Small Text", - "label": "Serial No" - }, - { - "doctype": "DocField", - "fieldname": "batch_no", - "fieldtype": "Data", - "label": "Batch No" - }, - { - "doctype": "DocField", - "fieldname": "detail_name", - "fieldtype": "Data", - "hidden": 1, - "label": "Detail Name", - "oldfieldname": "detail_name", - "oldfieldtype": "Data", - "read_only": 1 - } -] \ No newline at end of file diff --git a/selling/page/selling_home/selling_home.js b/selling/page/selling_home/selling_home.js index 7af9b71eb7..994bb4a555 100644 --- a/selling/page/selling_home/selling_home.js +++ b/selling/page/selling_home/selling_home.js @@ -120,12 +120,6 @@ wn.module_page["Selling"] = [ title: wn._("Tools"), icon: "icon-wrench", items: [ - { - "route":"Form/Sales and Purchase Return Tool/Sales and Purchase Return Tool", - "label":wn._("Sales Returns"), - "description":wn._("Helper for managing return of goods (sales or purchase)"), - doctype: "Sales and Purchase Return Tool" - }, { "route":"Form/SMS Center/SMS Center", "label":wn._("SMS Center"), diff --git a/stock/doctype/sales_and_purchase_return_tool/__init__.py b/stock/doctype/sales_and_purchase_return_tool/__init__.py deleted file mode 100644 index baffc48825..0000000000 --- a/stock/doctype/sales_and_purchase_return_tool/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from __future__ import unicode_literals diff --git a/stock/doctype/sales_and_purchase_return_tool/locale/_messages_doc.json b/stock/doctype/sales_and_purchase_return_tool/locale/_messages_doc.json deleted file mode 100644 index 979f20fc1e..0000000000 --- a/stock/doctype/sales_and_purchase_return_tool/locale/_messages_doc.json +++ /dev/null @@ -1,21 +0,0 @@ -[ - "Make Credit Note", - "Make Excise Invoice", - "Sales Return", - "Get Items", - "Delivery Note No", - "Company", - "Customer/Supplier", - "Sales and Purchase Return Tool", - "Make Debit Note", - "Cust/Supp Address", - "Sales Invoice No", - "Make Stock Entry", - "Purchase Receipt No", - "Purchase Return", - "Sales and Purchase Return Items", - "Return Date", - "Cust/Supp Name", - "Return Type", - "Stock" -] \ No newline at end of file diff --git a/stock/doctype/sales_and_purchase_return_tool/locale/ar-doc.json b/stock/doctype/sales_and_purchase_return_tool/locale/ar-doc.json deleted file mode 100644 index d11ece6797..0000000000 --- a/stock/doctype/sales_and_purchase_return_tool/locale/ar-doc.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "Company": "\u0634\u0631\u0643\u0629", - "Cust/Supp Address": "\u0627\u0644\u0632\u0628\u0648\u0646 / \u0627\u0644\u0645\u0644\u062d\u0642 \u0627\u0644\u0639\u0646\u0648\u0627\u0646", - "Cust/Supp Name": "\u0627\u0644\u0632\u0628\u0648\u0646 / \u0627\u0644\u0645\u0644\u062d\u0642 \u0627\u0633\u0645", - "Customer/Supplier": "\u0627\u0644\u0639\u0645\u064a\u0644 / \u0645\u0632\u0648\u062f", - "Delivery Note No": "\u0645\u0644\u0627\u062d\u0638\u0629 \u0644\u0627 \u062a\u0633\u0644\u064a\u0645", - "Get Items": "\u0627\u0644\u062d\u0635\u0648\u0644 \u0639\u0644\u0649 \u0627\u0644\u0639\u0646\u0627\u0635\u0631", - "Make Credit Note": "\u062c\u0639\u0644 \u0627\u0644\u0627\u0626\u062a\u0645\u0627\u0646\u064a", - "Make Debit Note": "\u0645\u0644\u0627\u062d\u0638\u0629 \u062c\u0639\u0644 \u0627\u0644\u062e\u0635\u0645", - "Make Excise Invoice": "\u062c\u0639\u0644 \u0627\u0644\u0641\u0627\u062a\u0648\u0631\u0629 \u0627\u0644\u0645\u0643\u0648\u0633", - "Make Stock Entry": "\u062c\u0639\u0644 \u0627\u0644\u062f\u062e\u0648\u0644 \u0644\u0644\u0633\u0647\u0645", - "Purchase Receipt No": "\u0644\u0627 \u0634\u0631\u0627\u0621 \u0627\u0633\u062a\u0644\u0627\u0645", - "Purchase Return": "\u0634\u0631\u0627\u0621 \u0627\u0644\u0639\u0648\u062f\u0629", - "Return Date": "\u0627\u0644\u0639\u0648\u062f\u0629 \u062a\u0627\u0631\u064a\u062e", - "Return Type": "\u0627\u0644\u0639\u0648\u062f\u0629 \u0646\u0648\u0639", - "Sales Invoice No": "\u0641\u0627\u062a\u0648\u0631\u0629 \u0645\u0628\u064a\u0639\u0627\u062a \u0644\u0627", - "Sales Return": "\u0645\u0628\u064a\u0639\u0627\u062a \u0627\u0644\u0639\u0648\u062f\u0629", - "Sales and Purchase Return Items": "\u0645\u0627\u062f\u0629 \u0639\u0627\u0626\u062f \u0627\u0644\u0645\u0628\u064a\u0639\u0627\u062a \u0648\u0627\u0644\u0645\u0634\u062a\u0631\u064a\u0627\u062a", - "Sales and Purchase Return Tool": "\u0645\u0628\u064a\u0639\u0627\u062a \u0648\u0634\u0631\u0627\u0621 \u0623\u062f\u0627\u0629 \u0627\u0644\u0639\u0648\u062f\u0629", - "Stock": "\u0627\u0644\u0623\u0648\u0631\u0627\u0642 \u0627\u0644\u0645\u0627\u0644\u064a\u0629" -} \ No newline at end of file diff --git a/stock/doctype/sales_and_purchase_return_tool/locale/de-doc.json b/stock/doctype/sales_and_purchase_return_tool/locale/de-doc.json deleted file mode 100644 index 9bd8c9af40..0000000000 --- a/stock/doctype/sales_and_purchase_return_tool/locale/de-doc.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "Company": "Firma", - "Cust/Supp Address": "Cust / Supp Adresse", - "Cust/Supp Name": "Cust / Supp Namen", - "Customer/Supplier": "Kunde / Lieferant", - "Delivery Note No": "Lieferschein Nein", - "Get Items": "Holen Artikel", - "Make Credit Note": "Machen Gutschrift", - "Make Debit Note": "Machen Lastschrift", - "Make Excise Invoice": "Machen Excise Rechnung", - "Make Stock Entry": "Machen Eintrag Stock", - "Purchase Receipt No": "Kaufbeleg", - "Purchase Return": "Kauf zur\u00fcckgeben", - "Return Date": "Zur\u00fcck Datum", - "Return Type": "R\u00fcckgabetyp", - "Sales Invoice No": "Sales Invoice In", - "Sales Return": "Umsatzrendite", - "Sales and Purchase Return Items": "Verkauf und Kauf zur\u00fccksenden Artikel", - "Sales and Purchase Return Tool": "Sales and Purchase Return-Tool", - "Stock": "Lager" -} \ No newline at end of file diff --git a/stock/doctype/sales_and_purchase_return_tool/locale/es-doc.json b/stock/doctype/sales_and_purchase_return_tool/locale/es-doc.json deleted file mode 100644 index ac4404951b..0000000000 --- a/stock/doctype/sales_and_purchase_return_tool/locale/es-doc.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "Company": "Empresa", - "Cust/Supp Address": "Cust / Supp Direcci\u00f3n", - "Cust/Supp Name": "Cust / Supp Nombre", - "Customer/Supplier": "Cliente / Proveedor", - "Delivery Note No": "Entrega Nota No", - "Get Items": "Obtener elementos", - "Make Credit Note": "Hacer Nota de Cr\u00e9dito", - "Make Debit Note": "Hacer Nota de D\u00e9bito", - "Make Excise Invoice": "Hacer Factura Impuestos Especiales", - "Make Stock Entry": "Hacer de la entrada", - "Purchase Receipt No": "No recibo de compra", - "Purchase Return": "Comprar Volver", - "Return Date": "Fecha de regreso", - "Return Type": "Devuelto", - "Sales Invoice No": "Ventas factura n \u00ba", - "Sales Return": "Ventas Retorno", - "Sales and Purchase Return Items": "Ventas y comprar art\u00edculos de Retorno", - "Sales and Purchase Return Tool": "Herramienta de ventas y devoluci\u00f3n de compra", - "Stock": "Valores" -} \ No newline at end of file diff --git a/stock/doctype/sales_and_purchase_return_tool/locale/fr-doc.json b/stock/doctype/sales_and_purchase_return_tool/locale/fr-doc.json deleted file mode 100644 index c3fc153a39..0000000000 --- a/stock/doctype/sales_and_purchase_return_tool/locale/fr-doc.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "Company": "Entreprise", - "Cust/Supp Address": "Cust / Supp Adresse", - "Cust/Supp Name": "Cust / Supp Nom", - "Customer/Supplier": "Client / Fournisseur", - "Delivery Note No": "Remarque Aucune livraison", - "Get Items": "Obtenir les \u00e9l\u00e9ments", - "Make Credit Note": "Assurez note de cr\u00e9dit", - "Make Debit Note": "Assurez note de d\u00e9bit", - "Make Excise Invoice": "Assurez facture d'accise", - "Make Stock Entry": "Assurez Entr\u00e9e Stock", - "Purchase Receipt No": "Achetez un accus\u00e9 de r\u00e9ception", - "Purchase Return": "Achat de retour", - "Return Date": "Date de retour", - "Return Type": "Retour Type", - "Sales Invoice No": "Aucune facture de vente", - "Sales Return": "Ventes de retour", - "Sales and Purchase Return Items": "Ventes et articles de retour d'achat", - "Sales and Purchase Return Tool": "Outil de vente et de retour d'achat", - "Stock": "Stock" -} \ No newline at end of file diff --git a/stock/doctype/sales_and_purchase_return_tool/locale/hi-doc.json b/stock/doctype/sales_and_purchase_return_tool/locale/hi-doc.json deleted file mode 100644 index b407775aa4..0000000000 --- a/stock/doctype/sales_and_purchase_return_tool/locale/hi-doc.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "Company": "\u0915\u0902\u092a\u0928\u0940", - "Cust/Supp Address": "Cust / Supp \u092a\u0924\u093e", - "Cust/Supp Name": "Cust / Supp \u0928\u093e\u092e", - "Customer/Supplier": "\u0917\u094d\u0930\u093e\u0939\u0915 / \u0906\u092a\u0942\u0930\u094d\u0924\u093f\u0915\u0930\u094d\u0924\u093e", - "Delivery Note No": "\u0921\u093f\u0932\u093f\u0935\u0930\u0940 \u0928\u094b\u091f", - "Get Items": "\u0906\u0907\u091f\u092e \u092a\u093e\u0928\u0947 \u0915\u0947 \u0932\u093f\u090f", - "Make Credit Note": "\u0915\u094d\u0930\u0947\u0921\u093f\u091f \u0928\u094b\u091f", - "Make Debit Note": "\u0921\u0947\u092c\u093f\u091f \u0928\u094b\u091f", - "Make Excise Invoice": "\u0909\u0924\u094d\u092a\u093e\u0926 \u0936\u0941\u0932\u094d\u0915 \u091a\u093e\u0932\u093e\u0928", - "Make Stock Entry": "\u0938\u094d\u091f\u0949\u0915 \u090f\u0902\u091f\u094d\u0930\u0940", - "Purchase Receipt No": "\u0930\u0938\u0940\u0926 \u0916\u0930\u0940\u0926 \u0928\u0939\u0940\u0902", - "Purchase Return": "\u0915\u094d\u0930\u092f \u0935\u093e\u092a\u0938\u0940", - "Return Date": "\u0924\u093f\u0925\u093f \u0932\u094c\u091f\u0947\u0902", - "Return Type": "\u092a\u094d\u0930\u0915\u093e\u0930 \u0932\u094c\u091f\u0947\u0902", - "Sales Invoice No": "\u092c\u093f\u0915\u094d\u0930\u0940 \u091a\u093e\u0932\u093e\u0928 \u0928\u0939\u0940\u0902", - "Sales Return": "\u092c\u093f\u0915\u094d\u0930\u0940 \u0932\u094c\u091f\u0947\u0902", - "Sales and Purchase Return Items": "\u092c\u093f\u0915\u094d\u0930\u0940 \u0914\u0930 \u0916\u0930\u0940\u0926 \u0915\u0947 \u0930\u093f\u091f\u0930\u094d\u0928 \u0906\u0907\u091f\u092e", - "Sales and Purchase Return Tool": "\u092c\u093f\u0915\u094d\u0930\u0940 \u0914\u0930 \u0916\u0930\u0940\u0926 \u0915\u0947 \u0930\u093f\u091f\u0930\u094d\u0928 \u091f\u0942\u0932", - "Stock": "\u0938\u094d\u091f\u0949\u0915" -} \ No newline at end of file diff --git a/stock/doctype/sales_and_purchase_return_tool/locale/hr-doc.json b/stock/doctype/sales_and_purchase_return_tool/locale/hr-doc.json deleted file mode 100644 index aa579a9565..0000000000 --- a/stock/doctype/sales_and_purchase_return_tool/locale/hr-doc.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "Company": "Dru\u0161tvo", - "Cust/Supp Address": "Cust / Supp Adresa", - "Cust/Supp Name": "Cust / Supp Ime", - "Customer/Supplier": "Kupac / Dobavlja\u010d", - "Delivery Note No": "Dostava Napomena Ne", - "Get Items": "Nabavite artikle", - "Make Credit Note": "Napravite Credit Note", - "Make Debit Note": "Napravite tere\u0107enju", - "Make Excise Invoice": "Napravite tro\u0161arinama fakture", - "Make Stock Entry": "Napravite Stock Entry", - "Purchase Receipt No": "Ra\u010dun kupnje Ne", - "Purchase Return": "Kupnja Povratak", - "Return Date": "Povratak Datum", - "Return Type": "Povratak Vid", - "Sales Invoice No": "Prodaja Ra\u010dun br", - "Sales Return": "Prodaje Povratak", - "Sales and Purchase Return Items": "Prodaja i kupnja Povratak Stavke", - "Sales and Purchase Return Tool": "Prodaja i kupnja Povratak Tool", - "Stock": "Zaliha" -} \ No newline at end of file diff --git a/stock/doctype/sales_and_purchase_return_tool/locale/nl-doc.json b/stock/doctype/sales_and_purchase_return_tool/locale/nl-doc.json deleted file mode 100644 index fd586c1e18..0000000000 --- a/stock/doctype/sales_and_purchase_return_tool/locale/nl-doc.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "Company": "Vennootschap", - "Cust/Supp Address": "Cust / Supp Adres", - "Cust/Supp Name": "Cust / Supp Naam", - "Customer/Supplier": "Klant / leverancier", - "Delivery Note No": "Levering aantekening", - "Get Items": "Get Items", - "Make Credit Note": "Maak Creditnota", - "Make Debit Note": "Maak debetnota", - "Make Excise Invoice": "Maak Accijnzen Factuur", - "Make Stock Entry": "Maak Stock Entry", - "Purchase Receipt No": "Aankoopbewijs Geen", - "Purchase Return": "Aankoop Return", - "Return Date": "Keer terug Datum", - "Return Type": "Terug Type", - "Sales Invoice No": "Verkoop Factuur nr.", - "Sales Return": "Verkoop Terug", - "Sales and Purchase Return Items": "Verkoop en Inkoop Return Items", - "Sales and Purchase Return Tool": "Verkoop en Inkoop Return Tool", - "Stock": "Voorraad" -} \ No newline at end of file diff --git a/stock/doctype/sales_and_purchase_return_tool/locale/pt-BR-doc.json b/stock/doctype/sales_and_purchase_return_tool/locale/pt-BR-doc.json deleted file mode 100644 index f218bfa7c8..0000000000 --- a/stock/doctype/sales_and_purchase_return_tool/locale/pt-BR-doc.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "Company": "Empresa", - "Cust/Supp Address": "Endere\u00e7o do Cliente/Fornecedor", - "Cust/Supp Name": "Nome do Cliente/Fornecedor", - "Customer/Supplier": "Cliente / Fornecedor", - "Delivery Note No": "N\u00ba da Guia de Remessa", - "Get Items": "Obter itens", - "Make Credit Note": "Fazer Nota de Cr\u00e9dito", - "Make Debit Note": "Fazer Nota de D\u00e9bito", - "Make Excise Invoice": "Fazer fatura de imposto", - "Make Stock Entry": "Fazer lan\u00e7amento de estoque", - "Purchase Receipt No": "N\u00ba do Recibo de Compra", - "Purchase Return": "Devolu\u00e7\u00e3o de Compra", - "Return Date": "Data de retorno", - "Return Type": "Tipo de retorno", - "Sales Invoice No": "N\u00ba da Nota Fiscal de Venda", - "Sales Return": "Retorno de Vendas", - "Sales and Purchase Return Items": "Itens de retorno de compra e venda", - "Sales and Purchase Return Tool": "Ferramenta de retorno de compra e venda", - "Stock": "Estoque" -} \ No newline at end of file diff --git a/stock/doctype/sales_and_purchase_return_tool/locale/pt-doc.json b/stock/doctype/sales_and_purchase_return_tool/locale/pt-doc.json deleted file mode 100644 index ce3685ed1c..0000000000 --- a/stock/doctype/sales_and_purchase_return_tool/locale/pt-doc.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "Company": "Companhia", - "Cust/Supp Address": "Cust / Supp Endere\u00e7o", - "Cust/Supp Name": "Cust / Supp Nome", - "Customer/Supplier": "Cliente / Fornecedor", - "Delivery Note No": "Nota de Entrega N\u00e3o", - "Get Items": "Obter itens", - "Make Credit Note": "Fa\u00e7a Nota de Cr\u00e9dito", - "Make Debit Note": "Fa\u00e7a Nota de D\u00e9bito", - "Make Excise Invoice": "Fa\u00e7a fatura Excise", - "Make Stock Entry": "Fa\u00e7a entrada de material", - "Purchase Receipt No": "Compra recibo N\u00e3o", - "Purchase Return": "Voltar comprar", - "Return Date": "Data de regresso", - "Return Type": "Tipo de retorno", - "Sales Invoice No": "Vendas factura n", - "Sales Return": "Vendas Retorno", - "Sales and Purchase Return Items": "Vendas e itens de retorno de Compra", - "Sales and Purchase Return Tool": "Ferramenta de vendas e retorno de compra", - "Stock": "Estoque" -} \ No newline at end of file diff --git a/stock/doctype/sales_and_purchase_return_tool/locale/sr-doc.json b/stock/doctype/sales_and_purchase_return_tool/locale/sr-doc.json deleted file mode 100644 index 4903a9fab0..0000000000 --- a/stock/doctype/sales_and_purchase_return_tool/locale/sr-doc.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "Company": "\u041a\u043e\u043c\u043f\u0430\u043d\u0438\u0458\u0430", - "Cust/Supp Address": "\u041a\u043e\u0440\u0438\u0441\u043d\u0438\u0447\u043a\u0430 / \u0421\u0443\u043f\u043f \u0410\u0434\u0440\u0435\u0441\u0430", - "Cust/Supp Name": "\u041a\u043e\u0440\u0438\u0441\u043d\u0438\u0447\u043a\u0430 / \u0421\u0443\u043f\u043f \u0418\u043c\u0435", - "Customer/Supplier": "\u041a\u043e\u0440\u0438\u0441\u043d\u0438\u0447\u043a\u0438 / \u0414\u043e\u0431\u0430\u0432\u0459\u0430\u0447", - "Delivery Note No": "\u0418\u0441\u043f\u043e\u0440\u0443\u043a\u0430 \u041d\u0430\u043f\u043e\u043c\u0435\u043d\u0430 \u041d\u0435", - "Get Items": "\u0413\u0435\u0442 \u0441\u0442\u0430\u0432\u043a\u0435", - "Make Credit Note": "\u041d\u0430\u043f\u0440\u0430\u0432\u0438\u0442\u0435 \u041d\u043e\u0442\u0435 \u0426\u0440\u0435\u0434\u0438\u0442", - "Make Debit Note": "\u041d\u0430\u043f\u0440\u0430\u0432\u0438\u0442\u0435 \u0437\u0430\u0434\u0443\u0436\u0435\u045a\u0443", - "Make Excise Invoice": "\u041d\u0430\u043f\u0440\u0430\u0432\u0438\u0442\u0435 \u0430\u043a\u0446\u0438\u0437\u0430\u043c\u0430 \u0444\u0430\u043a\u0442\u0443\u0440\u0443", - "Make Stock Entry": "\u041d\u0430\u043f\u0440\u0430\u0432\u0438\u0442\u0435 \u0443\u043d\u043e\u0441 \u0421\u0442\u043e\u0446\u043a", - "Purchase Receipt No": "\u041a\u0443\u043f\u043e\u0432\u0438\u043d\u0430 \u041f\u0440\u0438\u0458\u0435\u043c \u041d\u0435\u043c\u0430", - "Purchase Return": "\u041a\u0443\u043f\u043e\u0432\u0438\u043d\u0430 \u0420\u0435\u0442\u0443\u0440\u043d", - "Return Date": "\u0420\u0435\u0442\u0443\u0440\u043d \u0414\u0430\u0442\u0435", - "Return Type": "\u041f\u043e\u0432\u0440\u0430\u0442\u0430\u043a \u0412\u0438\u0434", - "Sales Invoice No": "\u041f\u0440\u043e\u0434\u0430\u0458\u0430 \u0420\u0430\u0447\u0443\u043d \u041d\u0435\u043c\u0430", - "Sales Return": "\u041f\u0440\u043e\u0434\u0430\u0458\u0430 \u0420\u0435\u0442\u0443\u0440\u043d", - "Sales and Purchase Return Items": "\u041f\u0440\u043e\u0434\u0430\u0458\u0430 \u0438 \u043f\u0440\u0435\u0434\u043c\u0435\u0442\u0438 \u041f\u043e\u0432\u0440\u0430\u0442\u0430\u043a \u041a\u0443\u043f\u043e\u0432\u0438\u043d\u0430", - "Sales and Purchase Return Tool": "\u041f\u0440\u043e\u0434\u0430\u0458\u0430 \u0438 \u043a\u0443\u043f\u043e\u0432\u0438\u043d\u0430 \u0430\u043b\u0430\u0442\u0430 \u041f\u043e\u0432\u0440\u0430\u0442\u0430\u043a", - "Stock": "\u0417\u0430\u043b\u0438\u0445\u0430" -} \ No newline at end of file diff --git a/stock/doctype/sales_and_purchase_return_tool/locale/ta-doc.json b/stock/doctype/sales_and_purchase_return_tool/locale/ta-doc.json deleted file mode 100644 index 4d1ddc3a3f..0000000000 --- a/stock/doctype/sales_and_purchase_return_tool/locale/ta-doc.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "Company": "\u0ba8\u0bbf\u0bb1\u0bc1\u0bb5\u0ba9\u0bae\u0bcd", - "Cust/Supp Address": "Cust / \u0b9a\u0baa\u0bcd \u0bae\u0bc1\u0b95\u0bb5\u0bb0\u0bbf", - "Cust/Supp Name": "Cust / \u0b9a\u0baa\u0bcd \u0baa\u0bc6\u0baf\u0bb0\u0bcd", - "Customer/Supplier": "\u0bb5\u0bbe\u0b9f\u0bbf\u0b95\u0bcd\u0b95\u0bc8\u0baf\u0bbe\u0bb3\u0bb0\u0bcd / \u0b9a\u0baa\u0bcd\u0bb3\u0bc8\u0baf\u0bb0\u0bcd", - "Delivery Note No": "\u0b9f\u0bc6\u0bb2\u0bbf\u0bb5\u0bb0\u0bbf \u0b95\u0bc1\u0bb1\u0bbf\u0baa\u0bcd\u0baa\u0bc1 \u0b87\u0bb2\u0bcd\u0bb2\u0bc8", - "Get Items": "\u0baa\u0bc6\u0bbe\u0bb0\u0bc1\u0b9f\u0bcd\u0b95\u0bb3\u0bcd \u0b95\u0bbf\u0b9f\u0bc8\u0b95\u0bcd\u0b95\u0bc1\u0bae\u0bcd", - "Make Credit Note": "\u0b95\u0b9f\u0ba9\u0bcd \u0b95\u0bc1\u0bb1\u0bbf\u0baa\u0bcd\u0baa\u0bc1 \u0b9a\u0bc6\u0baf\u0bcd\u0baf", - "Make Debit Note": "\u0baa\u0bb1\u0bcd\u0bb1\u0bc1 \u0b95\u0bc1\u0bb1\u0bbf\u0baa\u0bcd\u0baa\u0bc1 \u0b9a\u0bc6\u0baf\u0bcd\u0baf", - "Make Excise Invoice": "\u0bae\u0ba4\u0bc1\u0bb5\u0bb0\u0bbf \u0bb5\u0bbf\u0bb2\u0bc8\u0baa\u0bcd\u0baa\u0b9f\u0bcd\u0b9f\u0bbf\u0baf\u0bb2\u0bcd \u0bb5\u0bc8\u0b95\u0bcd\u0b95", - "Make Stock Entry": "\u0baa\u0b99\u0bcd\u0b95\u0bc1 \u0ba8\u0bc1\u0bb4\u0bc8\u0bb5\u0bc1 \u0b9a\u0bc6\u0baf\u0bcd\u0baf", - "Purchase Receipt No": "\u0b87\u0bb2\u0bcd\u0bb2\u0bc8 \u0b9a\u0bc0\u0b9f\u0bcd\u0b9f\u0bc1 \u0bb5\u0bbe\u0b99\u0bcd\u0b95", - "Purchase Return": "\u0ba4\u0bbf\u0bb0\u0bc1\u0bae\u0bcd\u0baa \u0bb5\u0bbe\u0b99\u0bcd\u0b95", - "Return Date": "\u0ba4\u0bc7\u0ba4\u0bbf \u0ba4\u0bbf\u0bb0\u0bc1\u0bae\u0bcd\u0baa\u0bbf", - "Return Type": "\u0bb5\u0b95\u0bc8 \u0ba4\u0bbf\u0bb0\u0bc1\u0bae\u0bcd\u0baa", - "Sales Invoice No": "\u0bb5\u0bbf\u0bb1\u0bcd\u0baa\u0ba9\u0bc8 \u0bb5\u0bbf\u0bb2\u0bc8\u0baa\u0bcd\u0baa\u0b9f\u0bcd\u0b9f\u0bbf\u0baf\u0bb2\u0bcd \u0b87\u0bb2\u0bcd\u0bb2\u0bc8", - "Sales Return": "\u0bb5\u0bbf\u0bb1\u0bcd\u0baa\u0ba9\u0bc8 Return", - "Sales and Purchase Return Items": "\u0bb5\u0bbf\u0bb1\u0bcd\u0baa\u0ba9\u0bc8 \u0bae\u0bb1\u0bcd\u0bb1\u0bc1\u0bae\u0bcd \u0b95\u0bc6\u0bbe\u0bb3\u0bcd\u0bae\u0bc1\u0ba4\u0bb2\u0bcd \u0ba4\u0bbf\u0bb0\u0bc1\u0bae\u0bcd\u0baa \u0b89\u0bb0\u0bc1\u0baa\u0bcd\u0baa\u0b9f\u0bbf\u0b95\u0bb3\u0bcd", - "Sales and Purchase Return Tool": "\u0bb5\u0bbf\u0bb1\u0bcd\u0baa\u0ba9\u0bc8 \u0bae\u0bb1\u0bcd\u0bb1\u0bc1\u0bae\u0bcd \u0b95\u0bc6\u0bbe\u0bb3\u0bcd\u0bae\u0bc1\u0ba4\u0bb2\u0bcd \u0ba4\u0bbf\u0bb0\u0bc1\u0bae\u0bcd\u0baa \u0b95\u0bb0\u0bc1\u0bb5\u0bbf", - "Stock": "\u0baa\u0b99\u0bcd\u0b95\u0bc1" -} \ No newline at end of file diff --git a/stock/doctype/sales_and_purchase_return_tool/locale/th-doc.json b/stock/doctype/sales_and_purchase_return_tool/locale/th-doc.json deleted file mode 100644 index 732dfd75ca..0000000000 --- a/stock/doctype/sales_and_purchase_return_tool/locale/th-doc.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "Company": "\u0e1a\u0e23\u0e34\u0e29\u0e31\u0e17", - "Cust/Supp Address": "\u0e17\u0e35\u0e48\u0e2d\u0e22\u0e39\u0e48 cust / Supp", - "Cust/Supp Name": "\u0e0a\u0e37\u0e48\u0e2d cust / Supp", - "Customer/Supplier": "\u0e25\u0e39\u0e01\u0e04\u0e49\u0e32 / \u0e1c\u0e39\u0e49\u0e1c\u0e25\u0e34\u0e15", - "Delivery Note No": "\u0e2b\u0e21\u0e32\u0e22\u0e40\u0e2b\u0e15\u0e38\u0e08\u0e31\u0e14\u0e2a\u0e48\u0e07\u0e2a\u0e34\u0e19\u0e04\u0e49\u0e32\u0e44\u0e21\u0e48\u0e21\u0e35", - "Get Items": "\u0e23\u0e31\u0e1a\u0e2a\u0e34\u0e19\u0e04\u0e49\u0e32", - "Make Credit Note": "\u0e43\u0e2b\u0e49\u0e08\u0e14\u0e1a\u0e31\u0e19\u0e17\u0e36\u0e01\u0e40\u0e04\u0e23\u0e14\u0e34\u0e15", - "Make Debit Note": "\u0e43\u0e2b\u0e49\u0e08\u0e14\u0e1a\u0e31\u0e19\u0e17\u0e36\u0e01\u0e40\u0e14\u0e1a\u0e34\u0e15", - "Make Excise Invoice": "\u0e17\u0e33\u0e43\u0e2b\u0e49\u0e43\u0e1a\u0e41\u0e08\u0e49\u0e07\u0e2b\u0e19\u0e35\u0e49\u0e2a\u0e23\u0e23\u0e1e\u0e2a\u0e32\u0e21\u0e34\u0e15", - "Make Stock Entry": "\u0e17\u0e33\u0e23\u0e32\u0e22\u0e01\u0e32\u0e23\u0e2a\u0e34\u0e19\u0e04\u0e49\u0e32", - "Purchase Receipt No": "\u0e43\u0e1a\u0e40\u0e2a\u0e23\u0e47\u0e08\u0e23\u0e31\u0e1a\u0e40\u0e07\u0e34\u0e19\u0e0b\u0e37\u0e49\u0e2d\u0e44\u0e21\u0e48\u0e21\u0e35", - "Purchase Return": "\u0e0b\u0e37\u0e49\u0e2d\u0e01\u0e25\u0e31\u0e1a", - "Return Date": "\u0e01\u0e25\u0e31\u0e1a\u0e27\u0e31\u0e19\u0e17\u0e35\u0e48", - "Return Type": "\u0e01\u0e25\u0e31\u0e1a\u0e0a\u0e19\u0e34\u0e14", - "Sales Invoice No": "\u0e02\u0e32\u0e22\u0e43\u0e1a\u0e41\u0e08\u0e49\u0e07\u0e2b\u0e19\u0e35\u0e49\u0e44\u0e21\u0e48\u0e21\u0e35", - "Sales Return": "\u0e02\u0e32\u0e22\u0e01\u0e25\u0e31\u0e1a", - "Sales and Purchase Return Items": "\u0e01\u0e32\u0e23\u0e02\u0e32\u0e22\u0e41\u0e25\u0e30\u0e01\u0e32\u0e23\u0e0b\u0e37\u0e49\u0e2d\u0e23\u0e32\u0e22\u0e01\u0e32\u0e23\u0e22\u0e49\u0e2d\u0e19\u0e01\u0e25\u0e31\u0e1a", - "Sales and Purchase Return Tool": "\u0e01\u0e32\u0e23\u0e02\u0e32\u0e22\u0e41\u0e25\u0e30\u0e01\u0e32\u0e23\u0e0b\u0e37\u0e49\u0e2d\u0e40\u0e04\u0e23\u0e37\u0e48\u0e2d\u0e07\u0e21\u0e37\u0e2d\u0e22\u0e49\u0e2d\u0e19\u0e01\u0e25\u0e31\u0e1a", - "Stock": "\u0e04\u0e25\u0e31\u0e07\u0e2a\u0e34\u0e19\u0e04\u0e49\u0e32" -} \ No newline at end of file diff --git a/stock/doctype/sales_and_purchase_return_tool/sales_and_purchase_return_tool.js b/stock/doctype/sales_and_purchase_return_tool/sales_and_purchase_return_tool.js deleted file mode 100644 index 2dd2e71cb1..0000000000 --- a/stock/doctype/sales_and_purchase_return_tool/sales_and_purchase_return_tool.js +++ /dev/null @@ -1,229 +0,0 @@ -// 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 . - -cur_frm.add_fetch("delivery_note_no", "company", "company"); -cur_frm.add_fetch("sales_invoice_no", "company", "company"); -cur_frm.add_fetch("purchase_receipt_no", "company", "company"); - -// Onload -//------------------------------- -cur_frm.cscript.onload = function(doc,dt,dn){ - if(!doc.return_date) set_multiple(dt,dn,{return_date:get_today()}); - doc.delivery_note_no = ''; - doc.purchase_receipt_no = ''; - doc.sales_invoice_no = ''; - doc.return_type =''; - refresh_many(['delivery_note_no', 'sales_invoice_no', 'purchase_receipt_no', 'return_type']); -} - -// Link field query -//-------------------------------- -cur_frm.fields_dict.delivery_note_no.get_query = function(doc) { - return 'SELECT DISTINCT `tabDelivery Note`.name FROM `tabDelivery Note` WHERE `tabDelivery Note`.docstatus = 1 AND `tabDelivery Note`.%(key)s LIKE "%s" ORDER BY `tabDelivery Note`.name desc LIMIT 50'; -} - -cur_frm.fields_dict.sales_invoice_no.get_query = function(doc) { - return 'SELECT DISTINCT `tabSales Invoice`.name FROM `tabSales Invoice` WHERE `tabSales Invoice`.docstatus = 1 AND `tabSales Invoice`.%(key)s LIKE "%s" ORDER BY `tabSales Invoice`.name desc LIMIT 50'; -} - -cur_frm.fields_dict.purchase_receipt_no.get_query = function(doc) { - return 'SELECT DISTINCT `tabPurchase Receipt`.name FROM `tabPurchase Receipt` WHERE `tabPurchase Receipt`.docstatus = 1 AND `tabPurchase Receipt`.%(key)s LIKE "%s" ORDER BY `tabPurchase Receipt`.name desc LIMIT 50'; -} - -// Hide/unhide based on return type -//---------------------------------- -cur_frm.cscript.return_type = function(doc, cdt, cdn) { - var cp = wn.control_panel; - hide_field(['purchase_receipt_no', 'delivery_note_no', 'sales_invoice_no', 'return_details', 'get_items', 'make_excise_invoice', 'make_stock_entry', 'make_debit_note', 'make_credit_note']); - - if(doc.return_type == 'Sales Return') { - unhide_field(['delivery_note_no', 'sales_invoice_no', 'get_items', 'return_details', 'make_credit_note', 'make_stock_entry']); - - if(cp.country == 'India') { unhide_field(['make_excise_invoice']); } - - } else if(doc.return_type == 'Purchase Return') { - unhide_field(['purchase_receipt_no', 'get_items', 'return_details', 'make_debit_note', 'make_stock_entry']); - - if(cp.country == 'India') { unhide_field(['make_excise_invoice']);} - } - - cur_frm.cscript.clear_fields(doc); -} - -// Create item table -//------------------------------- -cur_frm.cscript.get_items = function(doc, cdt, cdn) { - flag = 0 - if(doc.return_type == 'Sales Return') { - if (doc.delivery_note_no && doc.sales_invoice_no) { - msgprint("You can not enter both Delivery Note No and Sales Invoice No. Please enter any one."); - flag = 1; - } else if (!doc.delivery_note_no && !doc.sales_invoice_no) { - msgprint("Please enter Delivery Note No or Sales Invoice No to proceed"); - flag = 1; - } - } else if (doc.return_type == 'Purchase Return' && !doc.purchase_receipt_no) { - msgprint("Please enter Purchase Receipt No to proceed"); - flag = 1; - } - if (!flag) - $c_obj(make_doclist(doc.doctype, doc.name),'pull_item_details','', function(r, rt) { - refresh_many(['return_details', 'cust_supp', 'cust_supp_name', 'cust_supp_address']); - }); -} - -// Clear fields -//------------------------------- -cur_frm.cscript.clear_fields = function(doc) { - doc.purchase_receipt_no, doc.delivery_note_no, doc.sales_invoice_no = '', '', ''; - var cl = getchildren('Sales and Purchase Return Item', doc.name, 'return_details') - if(cl.length) $c_obj(make_doclist(doc.doctype, doc.name),'clear_return_table','', function(r, rt) {refresh_field('return_details')}); - refresh_many(['delivery_note_no', 'sales_invoice_no', 'purchase_receipt_no', 'return_details']); -} - -// Make Stock Entry -//------------------------------- -cur_frm.cscript.make_stock_entry = function(doc, cdt, cdn) { - var cl = getchildren('Sales and Purchase Return Item', doc.name, 'return_details'); - if (!cl.length) - msgprint("Item table can not be blank. Please click on 'Get Items'."); - else if (!cur_frm.cscript.validate_returned_qty(cl)) { - se = cur_frm.cscript.map_parent_fields(doc,cdt,cdn); - cur_frm.cscript.map_child_fields(cl, se); - loaddoc('Stock Entry', se.name); - } -} - -// Validate returned qty -//--------------------------- -cur_frm.cscript.validate_returned_qty = function(cl) { - flag = 0 - for(var i = 0; i cl[i].qty) { - msgprint("Returned Qty can not be greater than qty. Please check for item: " + cl[i].item_code); - flag = 1 - } - } - return flag -} - - -// map parent fields of stock entry -//---------------------------------- -cur_frm.cscript.map_parent_fields = function(doc, cdt, cdn) { - var se = wn.model.make_new_doc_and_get_name('Stock Entry'); - se = locals['Stock Entry'][se]; - se.posting_date = dateutil.obj_to_str(new Date()); - se.transfer_date = dateutil.obj_to_str(new Date()); - se.fiscal_year = sys_defaults.fiscal_year; - se.purpose = doc.return_type; - se.remarks = doc.return_type + ' of ' + (doc.delivery_note_no || doc.sales_invoice_no || doc.purchase_receipt_no); - if(doc.return_type == 'Sales Return'){ - se.delivery_note_no = doc.delivery_note_no; - se.sales_invoice_no = doc.sales_invoice_no; - se.customer = doc.cust_supp_name; - se.customer_name = doc.cust_supp_name; - se.customer_address = doc.cust_supp_address; - } - else if(doc.return_type == 'Purchase Return'){ - se.purchase_receipt_no = doc.purchase_receipt_no; - se.supplier = doc.cust_supp_name; - se.supplier_name = doc.cust_supp_name; - se.supplier_address = doc.cust_supp_address; - } - return se -} - -// map child fields of stock entry -//--------------------------------- -cur_frm.cscript.map_child_fields = function(cl, se) { - for(var i = 0; i. - -from __future__ import unicode_literals -import webnotes - -from webnotes.utils import flt -from webnotes.model import db_exists -from webnotes.model.doc import addchild -from webnotes.model.bean import copy_doclist - -sql = webnotes.conn.sql - - -class DocType : - def __init__(self, doc, doclist=[]): - self.doc = doc - self.doclist = doclist - - # Pull Item Details - # --------------------------- - def pull_item_details(self): - if self.doc.return_type == 'Sales Return': - if self.doc.delivery_note_no: - det = sql("select t1.name, t1.item_code, t1.description, t1.qty, t1.uom, t2.export_rate * t3.conversion_rate, t3.customer, t3.customer_name, t3.customer_address, t2.serial_no, t2.batch_no from `tabDelivery Note Packing Item` t1, `tabDelivery Note Item` t2, `tabDelivery Note` t3 where t1.parent = t3.name and t2.parent = t3.name and t1.parent_detail_docname = t2.name and t3.name = '%s' and t3.docstatus = 1" % self.doc.delivery_note_no) - elif self.doc.sales_invoice_no: - det = sql("select t1.name, t1.item_code, t1.description, t1.qty, t1.stock_uom, t1.export_rate * t2.conversion_rate, t2.customer, t2.customer_name, t2.customer_address, t1.serial_no from `tabSales Invoice Item` t1, `tabSales Invoice` t2 where t1.parent = t2.name and t2.name = '%s' and t2.docstatus = 1" % self.doc.sales_invoice_no) - elif self.doc.return_type == 'Purchase Return' and self.doc.purchase_receipt_no: - det = sql("select t1.name, t1.item_code, t1.description, t1.received_qty, t1.uom, t1.purchase_rate, t2.supplier, t2.supplier_name, t2.supplier_address, t1.serial_no, t1.batch_no from `tabPurchase Receipt Item` t1, `tabPurchase Receipt` t2 where t1.parent = t2.name and t2.name = '%s' and t2.docstatus = 1" % self.doc.purchase_receipt_no) - - self.doc.cust_supp = det and det[0][6] or '' - self.doc.cust_supp_name = det and det[0][7] or '' - self.doc.cust_supp_address = det and det[0][8] or '' - self.create_item_table(det) - self.doc.save() - - # Create Item Table - # ----------------------------- - def create_item_table(self, det): - self.doclist = self.doc.clear_table(self.doclist, 'return_details', 1) - for i in det: - ch = addchild(self.doc, 'return_details', 'Sales and Purchase Return Item', - self.doclist) - ch.detail_name = i and i[0] or '' - ch.item_code = i and i[1] or '' - ch.description = i and i[2] or '' - ch.qty = i and flt(i[3]) or 0 - ch.uom = i and i[4] or '' - ch.rate = i and flt(i[5]) or 0 - ch.serial_no = i and i[9] or '' - ch.batch_no = (len(i) == 11) and i[10] or '' - ch.save() - - # Clear return table - # -------------------------------- - def clear_return_table(self): - self.doclist = self.doc.clear_table(self.doclist, 'return_details', 1) - self.doc.save() \ No newline at end of file diff --git a/stock/doctype/sales_and_purchase_return_tool/sales_and_purchase_return_tool.txt b/stock/doctype/sales_and_purchase_return_tool/sales_and_purchase_return_tool.txt deleted file mode 100644 index 2daf6ac3f5..0000000000 --- a/stock/doctype/sales_and_purchase_return_tool/sales_and_purchase_return_tool.txt +++ /dev/null @@ -1,191 +0,0 @@ -[ - { - "creation": "2013-01-10 16:34:29", - "docstatus": 0, - "modified": "2013-01-23 16:48:38", - "modified_by": "Administrator", - "owner": "wasim@webnotestech.com" - }, - { - "doctype": "DocType", - "issingle": 1, - "istable": 0, - "module": "Stock", - "name": "__common__" - }, - { - "doctype": "DocField", - "name": "__common__", - "parent": "Sales and Purchase Return Tool", - "parentfield": "fields", - "parenttype": "DocType", - "permlevel": 0 - }, - { - "create": 1, - "doctype": "DocPerm", - "name": "__common__", - "parent": "Sales and Purchase Return Tool", - "parentfield": "permissions", - "parenttype": "DocType", - "permlevel": 0, - "read": 1, - "report": 0, - "submit": 0, - "write": 1 - }, - { - "doctype": "DocType", - "name": "Sales and Purchase Return Tool" - }, - { - "doctype": "DocField", - "fieldname": "return_date", - "fieldtype": "Date", - "label": "Return Date", - "no_copy": 1, - "oldfieldname": "return_date", - "oldfieldtype": "Date", - "reqd": 1 - }, - { - "doctype": "DocField", - "fieldname": "return_type", - "fieldtype": "Select", - "label": "Return Type", - "no_copy": 1, - "oldfieldname": "return_type", - "oldfieldtype": "Select", - "options": "\nSales Return\nPurchase Return", - "reqd": 1 - }, - { - "doctype": "DocField", - "fieldname": "delivery_note_no", - "fieldtype": "Link", - "hidden": 1, - "label": "Delivery Note No", - "no_copy": 1, - "oldfieldname": "delivery_note_no", - "oldfieldtype": "Link", - "options": "Delivery Note", - "reqd": 0 - }, - { - "doctype": "DocField", - "fieldname": "sales_invoice_no", - "fieldtype": "Link", - "hidden": 1, - "label": "Sales Invoice No", - "options": "Sales Invoice" - }, - { - "doctype": "DocField", - "fieldname": "purchase_receipt_no", - "fieldtype": "Link", - "hidden": 1, - "label": "Purchase Receipt No", - "no_copy": 1, - "oldfieldname": "purchase_receipt_no", - "oldfieldtype": "Link", - "options": "Purchase Receipt" - }, - { - "doctype": "DocField", - "fieldname": "company", - "fieldtype": "Link", - "hidden": 1, - "label": "Company", - "options": "Company", - "print_hide": 1 - }, - { - "doctype": "DocField", - "fieldname": "cust_supp", - "fieldtype": "Data", - "hidden": 1, - "label": "Customer/Supplier", - "print_hide": 1, - "read_only": 1 - }, - { - "doctype": "DocField", - "fieldname": "cust_supp_name", - "fieldtype": "Data", - "hidden": 1, - "label": "Cust/Supp Name", - "print_hide": 1, - "read_only": 1 - }, - { - "doctype": "DocField", - "fieldname": "cust_supp_address", - "fieldtype": "Small Text", - "hidden": 1, - "label": "Cust/Supp Address", - "print_hide": 1, - "read_only": 1 - }, - { - "doctype": "DocField", - "fieldname": "get_items", - "fieldtype": "Button", - "hidden": 1, - "label": "Get Items", - "oldfieldtype": "Button" - }, - { - "doctype": "DocField", - "fieldname": "return_details", - "fieldtype": "Table", - "hidden": 1, - "label": "Sales and Purchase Return Items", - "no_copy": 1, - "oldfieldname": "return_details", - "oldfieldtype": "Table", - "options": "Sales and Purchase Return Item", - "read_only": 1 - }, - { - "doctype": "DocField", - "fieldname": "make_stock_entry", - "fieldtype": "Button", - "hidden": 1, - "label": "Make Stock Entry", - "oldfieldtype": "Button" - }, - { - "doctype": "DocField", - "fieldname": "make_excise_invoice", - "fieldtype": "Button", - "hidden": 1, - "label": "Make Excise Invoice", - "oldfieldtype": "Button" - }, - { - "doctype": "DocField", - "fieldname": "make_credit_note", - "fieldtype": "Button", - "hidden": 1, - "label": "Make Credit Note", - "oldfieldtype": "Button" - }, - { - "doctype": "DocField", - "fieldname": "make_debit_note", - "fieldtype": "Button", - "hidden": 1, - "label": "Make Debit Note", - "oldfieldtype": "Button" - }, - { - "amend": 0, - "cancel": 0, - "doctype": "DocPerm", - "role": "Material User" - }, - { - "doctype": "DocPerm", - "role": "Accounts User" - } -] \ No newline at end of file diff --git a/stock/page/stock_home/stock_home.js b/stock/page/stock_home/stock_home.js index a09cae75bd..db77fced0e 100644 --- a/stock/page/stock_home/stock_home.js +++ b/stock/page/stock_home/stock_home.js @@ -95,12 +95,6 @@ wn.module_page["Stock"] = [ description: wn._("Change UOM for an Item."), "doctype": "Stock UOM Replace Utility" }, - { - "route":"Form/Sales and Purchase Return Tool/Sales and Purchase Return Tool", - "label": wn._("Sales and Purchase Return Tool"), - doctype: "Sales and Purchase Return Tool", - description: wn._("Manage sales or purchase returns") - }, ] }, { From 5afe037a5b754b84c98ab2b1b1787d0d519fa93a Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Mon, 18 Mar 2013 17:59:56 +0530 Subject: [PATCH 10/30] deprecate sales and purchase return tool --- accounts/__init__.py | 206 ------------------------------------------- 1 file changed, 206 deletions(-) diff --git a/accounts/__init__.py b/accounts/__init__.py index 707203f500..145ad6b869 100644 --- a/accounts/__init__.py +++ b/accounts/__init__.py @@ -32,209 +32,3 @@ def get_default_bank_account(): WHERE name=%s AND docstatus<2""", company) if res: return res[0][0] - -@webnotes.whitelist() -def get_new_jv_details(): - """ - Get details which will help create new jv on sales/purchase return - """ - doclist = webnotes.form_dict.get('doclist') - fiscal_year = webnotes.form_dict.get('fiscal_year') - if not (isinstance(doclist, basestring) and isinstance(fiscal_year, basestring)): return - - import json - doclist = json.loads(doclist) - doc, children = doclist[0], doclist[1:] - - if doc.get('return_type')=='Sales Return': - if doc.get('sales_invoice_no'): - return get_invoice_details(doc, children, fiscal_year) - elif doc.get('delivery_note_no'): - return get_delivery_note_details(doc, children, fiscal_year) - - elif doc.get('purchase_receipt_no'): - return get_purchase_receipt_details(doc, children, fiscal_year) - - -def get_invoice_details(doc, children, fiscal_year): - """ - Gets details from an invoice to make new jv - Returns [{ - 'account': , - 'balance': , - 'debit': , - 'credit': , - 'against_invoice': , - 'against_payable': - }, { ... }, ...] - """ - if doc.get('return_type')=='Sales Return': - obj = get_obj('Sales Invoice', doc.get('sales_invoice_no'), with_children=1) - else: - obj = get_obj('Purchase Invoice', doc.get('purchase_invoice_no'), with_children=1) - if not obj.doc.docstatus==1: return - - # Build invoice account jv detail record - invoice_rec = get_invoice_account_jv_record(doc, children, fiscal_year, obj) - - # Build item accountwise jv detail records - item_accountwise_list = get_item_accountwise_jv_record(doc, children, fiscal_year, obj) - - return [invoice_rec] + item_accountwise_list - - -def get_invoice_account_jv_record(doc, children, fiscal_year, obj): - """ - Build customer/supplier account jv detail record - """ - # Calculate total return amount - total_amt = sum([(flt(ch.get('rate')) * flt(ch.get('returned_qty'))) for ch in children]) - - ret = {} - - if doc.get('return_type')=='Sales Return': - account = obj.doc.debit_to - ret['against_invoice'] = doc.get('sales_invoice_no') - ret['credit'] = total_amt - else: - account = obj.doc.credit_to - ret['against_voucher'] = doc.get('purchase_invoice_no') - ret['debit'] = total_amt - - ret.update({ - 'account': account, - 'balance': get_balance_on(account, doc.get("return_date")) - }) - - return ret - - -def get_item_accountwise_jv_record(doc, children, fiscal_year, obj): - """ - Build item accountwise jv detail records - """ - if doc.get('return_type')=='Sales Return': - amt_field = 'debit' - ac_field = 'income_account' - else: - amt_field = 'credit' - ac_field = 'expense_head' - - inv_children = dict([[ic.fields.get('item_code'), ic] for ic in obj.doclist if ic.fields.get('item_code')]) - - accwise_list = [] - - for ch in children: - inv_ch = inv_children.get(ch.get('item_code')) - if not inv_ch: continue - - amount = flt(ch.get('rate')) * flt(ch.get('returned_qty')) - - accounts = [[jvd['account'], jvd['cost_center']] for jvd in accwise_list] - - if [inv_ch.fields.get(ac_field), inv_ch.fields.get('cost_center')] not in accounts: - rec = { - 'account': inv_ch.fields.get(ac_field), - 'cost_center': inv_ch.fields.get('cost_center'), - 'balance': get_balance_on(inv_ch.fields.get(ac_field), - doc.get("return_date")) - } - rec[amt_field] = amount - accwise_list.append(rec) - else: - rec = accwise_list[accounts.index([inv_ch.fields.get(ac_field), inv_ch.fields.get('cost_center')])] - rec[amt_field] = rec[amt_field] + amount - - return accwise_list - - -def get_jv_details_from_inv_list(doc, children, fiscal_year, inv_list, jv_details_list): - """ - Get invoice details and make jv detail records - """ - for inv in inv_list: - if not inv[0]: continue - - if doc.get('return_type')=='Sales Return': - doc['sales_invoice_no'] = inv[0] - else: - doc['purchase_invoice_no'] = inv[0] - - jv_details = get_invoice_details(doc, children, fiscal_year) - - if jv_details and len(jv_details)>1: jv_details_list.extend(jv_details) - - return jv_details_list - - -def get_prev_doc_list(obj, prev_doctype): - """ - Returns a list of previous doc's names - """ - prevdoc_list = [] - for ch in obj.doclist: - if ch.fields.get('prevdoc_docname') and ch.fields.get('prevdoc_doctype')==prev_doctype: - prevdoc_list.append(ch.fields.get('prevdoc_docname')) - return prevdoc_list - - -def get_inv_list(table, field, value): - """ - Returns invoice list - """ - if isinstance(value, basestring): - return webnotes.conn.sql("""\ - SELECT DISTINCT parent FROM `%s` - WHERE %s='%s' AND docstatus=1""" % (table, field, value)) - elif isinstance(value, list): - return webnotes.conn.sql("""\ - SELECT DISTINCT parent FROM `%s` - WHERE %s IN ("%s") AND docstatus=1""" % (table, field, '", "'.join(value))) - else: - return [] - - -def get_delivery_note_details(doc, children, fiscal_year): - """ - Gets sales invoice numbers from delivery note details - and returns detail records for jv - """ - jv_details_list = [] - - dn_obj = get_obj('Delivery Note', doc['delivery_note_no'], with_children=1) - - inv_list = get_inv_list('tabSales Invoice Item', 'delivery_note', doc['delivery_note_no']) - - if inv_list: - jv_details_list = get_jv_details_from_inv_list(doc, children, fiscal_year, inv_list, jv_details_list) - - if not (inv_list and jv_details_list): - so_list = get_prev_doc_list(dn_obj, 'Sales Order') - inv_list = get_inv_list('tabSales Invoice Item', 'sales_order', so_list) - if inv_list: - jv_details_list = get_jv_details_from_inv_list(doc, children, fiscal_year, inv_list, jv_details_list) - - return jv_details_list - - -def get_purchase_receipt_details(doc, children, fiscal_year): - """ - Gets purchase invoice numbers from purchase receipt details - and returns detail records for jv - """ - jv_details_list = [] - - pr_obj = get_obj('Purchase Receipt', doc['purchase_receipt_no'], with_children=1) - - inv_list = get_inv_list('tabPurchase Invoice Item', 'purchase_receipt', doc['purchase_receipt_no']) - - if inv_list: - jv_details_list = get_jv_details_from_inv_list(doc, children, fiscal_year, inv_list, jv_details_list) - - if not (inv_list and jv_details_list): - po_list = get_prev_doc_list(pr_obj, 'Purchase Order') - inv_list = get_inv_list('tabPurchase Invoice Item', 'purchase_order', po_list) - if inv_list: - jv_details_list = get_jv_details_from_inv_list(doc, children, fiscal_year, inv_list, jv_details_list) - - return jv_details_list From 35e037651c93fd87b178541efeda111bee527a1e Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Tue, 19 Mar 2013 11:58:57 +0530 Subject: [PATCH 11/30] fixes in packing slip --- stock/doctype/packing_slip/packing_slip.js | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/stock/doctype/packing_slip/packing_slip.js b/stock/doctype/packing_slip/packing_slip.js index a332ca8345..706c6f5141 100644 --- a/stock/doctype/packing_slip/packing_slip.js +++ b/stock/doctype/packing_slip/packing_slip.js @@ -28,18 +28,10 @@ cur_frm.fields_dict['item_details'].grid.get_field('item_code').get_query = func // Fetch item details -cur_frm.cscript.item_code = function(doc, cdt, cdn) { - if(locals[cdt][cdn].item_code) { - $c_obj(make_doclist(cdt, cdn), 'get_item_details', doc.delivery_note, function(r, rt) { - if(r.exc) { - msgprint(r.exc); - } else { - refresh_field('item_details'); - } - }); - } -} - +cur_frm.add_fetch("item_code", "item_name", "item_name"); +cur_frm.add_fetch("item_code", "stock_uom", "stock_uom"); +cur_frm.add_fetch("item_code", "net_weight", "net_weight"); +cur_frm.add_fetch("item_code", "weight_uom", "weight_uom"); cur_frm.cscript.onload_post_render = function(doc, cdt, cdn) { if(doc.delivery_note && doc.__islocal) { From c3afb256b450cbceab5b427297a80774ac4d3b52 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Tue, 19 Mar 2013 12:01:24 +0530 Subject: [PATCH 12/30] aii: stock entry --- controllers/selling_controller.py | 29 +------ controllers/stock_controller.py | 71 +++++++++++++++++ stock/doctype/stock_entry/stock_entry.js | 9 ++- stock/doctype/stock_entry/stock_entry.py | 42 +++------- stock/doctype/stock_entry/stock_entry.txt | 79 +++++++++++++++---- stock/doctype/stock_entry/test_stock_entry.py | 3 + stock/stock_ledger.py | 2 +- stock/utils.py | 20 ++--- 8 files changed, 174 insertions(+), 81 deletions(-) create mode 100644 controllers/stock_controller.py diff --git a/controllers/selling_controller.py b/controllers/selling_controller.py index 40606c3198..f9498cbac9 100644 --- a/controllers/selling_controller.py +++ b/controllers/selling_controller.py @@ -19,9 +19,9 @@ import webnotes from webnotes.utils import cint from setup.utils import get_company_currency -from controllers.accounts_controller import AccountsController +from controllers.stock_controller import StockController -class SellingController(AccountsController): +class SellingController(StockController): def validate(self): self.set_total_in_words() @@ -37,27 +37,4 @@ class SellingController(AccountsController): self.doc.grand_total or self.doc.rounded_total, company_currency) if self.meta.get_field("in_words_export"): self.doc.in_words_export = money_in_words(disable_rounded_total and - self.doc.grand_total_export or self.doc.rounded_total_export, self.doc.currency) - - def get_stock_ledger_entries(self): - item_list, warehouse_list = self.get_distinct_item_warehouse() - if item_list and warehouse_list: - return webnotes.conn.sql("""select item_code, voucher_type, voucher_no, - voucher_detail_no, posting_date, posting_time, stock_value, - warehouse, actual_qty as qty from `tabStock Ledger Entry` - where ifnull(`is_cancelled`, "No") = "No" and company = %s - and item_code in (%s) and warehouse in (%s) - order by item_code desc, warehouse desc, posting_date desc, - posting_time desc, name desc""" % - ('%s', ', '.join(['%s']*len(item_list)), ', '.join(['%s']*len(warehouse_list))), - tuple([self.doc.company] + item_list + warehouse_list), as_dict=1) - - def get_distinct_item_warehouse(self): - item_list = [] - warehouse_list = [] - for item in self.doclist.get({"parentfield": self.fname}) \ - + self.doclist.get({"parentfield": "packing_details"}): - item_list.append(item.item_code) - warehouse_list.append(item.warehouse) - - return list(set(item_list)), list(set(warehouse_list)) \ No newline at end of file + self.doc.grand_total_export or self.doc.rounded_total_export, self.doc.currency) \ No newline at end of file diff --git a/controllers/stock_controller.py b/controllers/stock_controller.py new file mode 100644 index 0000000000..3a900aa8be --- /dev/null +++ b/controllers/stock_controller.py @@ -0,0 +1,71 @@ +# 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 . + +from __future__ import unicode_literals +import webnotes +from controllers.accounts_controller import AccountsController + +class StockController(AccountsController): + def make_gl_entries(self, against_stock_account, amount, cost_center=None): + stock_in_hand_account = self.get_stock_in_hand_account() + + if amount: + gl_entries = [ + # stock in hand account + self.get_gl_dict({ + "account": stock_in_hand_account, + "against": against_stock_account, + "debit": amount, + "remarks": self.doc.remarks or "Accounting Entry for Stock", + }, self.doc.docstatus == 2), + + # account against stock in hand + self.get_gl_dict({ + "account": against_stock_account, + "against": stock_in_hand_account, + "credit": amount, + "cost_center": cost_center or None, + "remarks": self.doc.remarks or "Accounting Entry for Stock", + }, self.doc.docstatus == 2), + ] + from accounts.general_ledger import make_gl_entries + make_gl_entries(gl_entries, cancel=self.doc.docstatus == 2) + + + def get_stock_ledger_entries(self, item_list=None, warehouse_list=None): + if not (item_list and warehouse_list): + item_list, warehouse_list = self.get_distinct_item_warehouse() + + if item_list and warehouse_list: + return webnotes.conn.sql("""select item_code, voucher_type, voucher_no, + voucher_detail_no, posting_date, posting_time, stock_value, + warehouse, actual_qty as qty from `tabStock Ledger Entry` + where ifnull(`is_cancelled`, "No") = "No" and company = %s + and item_code in (%s) and warehouse in (%s) + order by item_code desc, warehouse desc, posting_date desc, + posting_time desc, name desc""" % + ('%s', ', '.join(['%s']*len(item_list)), ', '.join(['%s']*len(warehouse_list))), + tuple([self.doc.company] + item_list + warehouse_list), as_dict=1) + + def get_distinct_item_warehouse(self): + item_list = [] + warehouse_list = [] + for item in self.doclist.get({"parentfield": self.fname}) \ + + self.doclist.get({"parentfield": "packing_details"}): + item_list.append(item.item_code) + warehouse_list.append(item.warehouse) + + return list(set(item_list)), list(set(warehouse_list)) \ No newline at end of file diff --git a/stock/doctype/stock_entry/stock_entry.js b/stock/doctype/stock_entry/stock_entry.js index ba1f64802a..0a75914a62 100644 --- a/stock/doctype/stock_entry/stock_entry.js +++ b/stock/doctype/stock_entry/stock_entry.js @@ -234,4 +234,11 @@ cur_frm.cscript.validate_items = function(doc) { cur_frm.fields_dict.customer.get_query = erpnext.utils.customer_query; -cur_frm.fields_dict.supplier.get_query = erpnext.utils.supplier_query; \ No newline at end of file +cur_frm.fields_dict.supplier.get_query = erpnext.utils.supplier_query; + +cur_frm.fields_dict["expense_adjustment_account"].get_query = function(doc) { + return { + "query": "accounts.utils.get_account_list", + "filters": { "company": doc.company } + } +} \ No newline at end of file diff --git a/stock/doctype/stock_entry/stock_entry.py b/stock/doctype/stock_entry/stock_entry.py index cd20266d6b..17e265591c 100644 --- a/stock/doctype/stock_entry/stock_entry.py +++ b/stock/doctype/stock_entry/stock_entry.py @@ -26,12 +26,11 @@ from stock.utils import get_incoming_rate from stock.stock_ledger import get_previous_sle import json - sql = webnotes.conn.sql -from controllers.accounts_controller import AccountsController +from controllers.stock_controller import StockController -class DocType(AccountsController): +class DocType(StockController): def __init__(self, doc, doclist=[]): self.doc = doc self.doclist = doclist @@ -168,41 +167,24 @@ class DocType(AccountsController): if not cint(webnotes.defaults.get_global_default("auto_inventory_accounting")): return - abbr = webnotes.conn.get_value("Company", self.doc.company, "abbr") - stock_in_hand_account = self.get_stock_in_hand_account() - total_valuation_amount = self.get_total_valuation_amount() - - if total_valuation_amount: - gl_entries = [ - # debit stock in hand account - self.get_gl_dict({ - "account": stock_in_hand_account, - "against": "Stock Adjustment - %s" % abbr, - "debit": total_valuation_amount, - "remarks": self.doc.remarks or "Accounting Entry for Stock", - }, self.doc.docstatus == 2), - - # debit stock received but not billed account - self.get_gl_dict({ - "account": "Stock Adjustment - %s" % abbr, - "against": stock_in_hand_account, - "credit": total_valuation_amount, - "cost_center": "Auto Inventory Accounting - %s" % abbr, - "remarks": self.doc.remarks or "Accounting Entry for Stock", - }, self.doc.docstatus == 2), - ] - from accounts.general_ledger import make_gl_entries - make_gl_entries(gl_entries, cancel=self.doc.docstatus == 2) + if not self.doc.expense_adjustment_account: + webnotes.msgprint(_("Please enter Expense/Adjustment Account"), raise_exception=1) + cost_center = "Auto Inventory Accounting - %s" % (self.company_abbr,) + total_valuation_amount = self.get_total_valuation_amount() + + super(DocType, self).make_gl_entries(self.doc.expense_adjustment_account, + total_valuation_amount, cost_center) + def get_total_valuation_amount(self): total_valuation_amount = 0 for item in self.doclist.get({"parentfield": "mtn_details"}): if item.t_warehouse and not item.s_warehouse: total_valuation_amount += flt(item.incoming_rate) * flt(item.transfer_qty) - + if item.s_warehouse and not item.t_warehouse: total_valuation_amount -= flt(item.incoming_rate) * flt(item.transfer_qty) - + return total_valuation_amount def get_stock_and_rate(self): diff --git a/stock/doctype/stock_entry/stock_entry.txt b/stock/doctype/stock_entry/stock_entry.txt index 2554455764..013265244a 100644 --- a/stock/doctype/stock_entry/stock_entry.txt +++ b/stock/doctype/stock_entry/stock_entry.txt @@ -1,8 +1,8 @@ [ { - "creation": "2013-01-23 19:57:20", + "creation": "2013-03-07 18:50:32", "docstatus": 0, - "modified": "2013-01-28 17:59:20", + "modified": "2013-03-14 12:25:00", "modified_by": "Administrator", "owner": "Administrator" }, @@ -60,6 +60,7 @@ "fieldtype": "Column Break", "oldfieldtype": "Column Break", "print_width": "50%", + "read_only": 0, "width": "50%" }, { @@ -76,6 +77,7 @@ "oldfieldtype": "Select", "options": "\nSTE", "print_hide": 1, + "read_only": 0, "report_hide": 0, "reqd": 1, "search_index": 0 @@ -95,6 +97,7 @@ "oldfieldtype": "Select", "options": "Material Issue\nMaterial Receipt\nMaterial Transfer\nManufacture/Repack\nSubcontract\nSales Return\nPurchase Return", "print_hide": 0, + "read_only": 0, "report_hide": 0, "reqd": 1, "search_index": 0 @@ -105,6 +108,7 @@ "fieldtype": "Column Break", "oldfieldtype": "Column Break", "print_width": "50%", + "read_only": 0, "width": "50%" }, { @@ -122,6 +126,7 @@ "oldfieldname": "posting_date", "oldfieldtype": "Date", "print_hide": 1, + "read_only": 0, "report_hide": 0, "reqd": 1, "search_index": 1 @@ -138,16 +143,26 @@ "oldfieldname": "posting_time", "oldfieldtype": "Time", "print_hide": 1, + "read_only": 0, "report_hide": 0, "reqd": 1, "search_index": 0 }, + { + "depends_on": "eval:sys_defaults.auto_inventory_accounting", + "doctype": "DocField", + "fieldname": "expense_adjustment_account", + "fieldtype": "Link", + "label": "Expense/Adjustment Account", + "options": "Account" + }, { "doctype": "DocField", "fieldname": "items_section", "fieldtype": "Section Break", "label": "Items", - "oldfieldtype": "Section Break" + "oldfieldtype": "Section Break", + "read_only": 0 }, { "allow_on_submit": 0, @@ -163,6 +178,7 @@ "oldfieldtype": "Link", "options": "Warehouse", "print_hide": 1, + "read_only": 0, "report_hide": 0, "reqd": 0, "search_index": 0 @@ -170,7 +186,8 @@ { "doctype": "DocField", "fieldname": "cb0", - "fieldtype": "Column Break" + "fieldtype": "Column Break", + "read_only": 0 }, { "allow_on_submit": 0, @@ -186,6 +203,7 @@ "oldfieldtype": "Link", "options": "Warehouse", "print_hide": 1, + "read_only": 0, "report_hide": 0, "reqd": 0, "search_index": 0 @@ -194,7 +212,8 @@ "doctype": "DocField", "fieldname": "sb0", "fieldtype": "Section Break", - "options": "Simple" + "options": "Simple", + "read_only": 0 }, { "allow_on_submit": 0, @@ -209,6 +228,7 @@ "oldfieldtype": "Table", "options": "Stock Entry Detail", "print_hide": 0, + "read_only": 0, "report_hide": 0, "reqd": 0, "search_index": 0 @@ -221,13 +241,15 @@ "label": "Get Stock and Rate", "oldfieldtype": "Button", "options": "get_stock_and_rate", - "print_hide": 1 + "print_hide": 1, + "read_only": 0 }, { "doctype": "DocField", "fieldname": "sb1", "fieldtype": "Section Break", - "label": "Reference" + "label": "Reference", + "read_only": 0 }, { "allow_on_submit": 0, @@ -243,6 +265,7 @@ "oldfieldtype": "Link", "options": "Production Order", "print_hide": 1, + "read_only": 0, "report_hide": 0, "reqd": 0, "search_index": 1 @@ -253,7 +276,8 @@ "fieldname": "bom_no", "fieldtype": "Link", "label": "BOM No", - "options": "BOM" + "options": "BOM", + "read_only": 0 }, { "allow_on_submit": 0, @@ -269,6 +293,7 @@ "oldfieldname": "fg_completed_qty", "oldfieldtype": "Currency", "print_hide": 1, + "read_only": 0, "report_hide": 0, "reqd": 0, "search_index": 0 @@ -287,6 +312,7 @@ "oldfieldtype": "Link", "options": "Delivery Note", "print_hide": 1, + "read_only": 0, "report_hide": 0, "reqd": 0, "search_index": 1 @@ -305,6 +331,7 @@ "oldfieldtype": "Link", "options": "Purchase Receipt", "print_hide": 1, + "read_only": 0, "report_hide": 0, "reqd": 0, "search_index": 1 @@ -312,7 +339,8 @@ { "doctype": "DocField", "fieldname": "cb1", - "fieldtype": "Column Break" + "fieldtype": "Column Break", + "read_only": 0 }, { "default": "1", @@ -321,7 +349,8 @@ "doctype": "DocField", "fieldname": "use_multi_level_bom", "fieldtype": "Check", - "label": "Use Multi-Level BOM" + "label": "Use Multi-Level BOM", + "read_only": 0 }, { "allow_on_submit": 0, @@ -335,6 +364,7 @@ "no_copy": 0, "oldfieldtype": "Button", "print_hide": 1, + "read_only": 0, "report_hide": 0, "reqd": 0, "search_index": 0 @@ -348,14 +378,16 @@ "label": "Sales Invoice No", "no_copy": 1, "options": "Sales Invoice", - "print_hide": 1 + "print_hide": 1, + "read_only": 0 }, { "depends_on": "eval:(doc.purpose==\"Sales Return\" || doc.purpose==\"Purchase Return\")", "doctype": "DocField", "fieldname": "contact_section", "fieldtype": "Section Break", - "label": "Contact Info" + "label": "Contact Info", + "read_only": 0 }, { "allow_on_submit": 0, @@ -371,6 +403,7 @@ "oldfieldtype": "Link", "options": "Supplier", "print_hide": 1, + "read_only": 0, "report_hide": 0, "reqd": 0, "search_index": 0 @@ -406,6 +439,7 @@ "oldfieldname": "supplier_address", "oldfieldtype": "Small Text", "print_hide": 0, + "read_only": 0, "report_hide": 0, "reqd": 0, "search_index": 0 @@ -424,6 +458,7 @@ "oldfieldtype": "Link", "options": "Customer", "print_hide": 1, + "read_only": 0, "report_hide": 0, "reqd": 0, "search_index": 0 @@ -459,6 +494,7 @@ "oldfieldname": "customer_address", "oldfieldtype": "Small Text", "print_hide": 0, + "read_only": 0, "report_hide": 0, "reqd": 0, "search_index": 0 @@ -468,13 +504,15 @@ "fieldname": "more_info", "fieldtype": "Section Break", "label": "More Info", - "oldfieldtype": "Section Break" + "oldfieldtype": "Section Break", + "read_only": 0 }, { "doctype": "DocField", "fieldname": "col4", "fieldtype": "Column Break", "print_width": "50%", + "read_only": 0, "width": "50%" }, { @@ -485,7 +523,8 @@ "label": "Project Name", "oldfieldname": "project_name", "oldfieldtype": "Link", - "options": "Project" + "options": "Project", + "read_only": 0 }, { "allow_on_submit": 0, @@ -500,6 +539,7 @@ "oldfieldtype": "Link", "options": "Print Heading", "print_hide": 0, + "read_only": 0, "report_hide": 0, "reqd": 0, "search_index": 0 @@ -517,6 +557,7 @@ "oldfieldtype": "Link", "options": "Company", "print_hide": 1, + "read_only": 0, "report_hide": 0, "reqd": 1, "search_index": 0 @@ -526,6 +567,7 @@ "fieldname": "col5", "fieldtype": "Column Break", "print_width": "50%", + "read_only": 0, "width": "50%" }, { @@ -558,6 +600,7 @@ "oldfieldname": "remarks", "oldfieldtype": "Text", "print_hide": 1, + "read_only": 0, "report_hide": 0, "reqd": 0, "search_index": 0 @@ -569,5 +612,13 @@ { "doctype": "DocPerm", "role": "Manufacturing User" + }, + { + "doctype": "DocPerm", + "role": "Manufacturing Manager" + }, + { + "doctype": "DocPerm", + "role": "Material Manager" } ] \ No newline at end of file diff --git a/stock/doctype/stock_entry/test_stock_entry.py b/stock/doctype/stock_entry/test_stock_entry.py index a4103c37bb..f193826402 100644 --- a/stock/doctype/stock_entry/test_stock_entry.py +++ b/stock/doctype/stock_entry/test_stock_entry.py @@ -168,6 +168,7 @@ test_records = [ "posting_time": "17:14:24", "purpose": "Material Receipt", "fiscal_year": "_Test Fiscal Year 2013", + "expense_adjustment_account": "Stock Adjustment - _TC" }, { "conversion_factor": 1.0, @@ -190,6 +191,7 @@ test_records = [ "posting_time": "17:15", "purpose": "Material Issue", "fiscal_year": "_Test Fiscal Year 2013", + "expense_adjustment_account": "Stock Adjustment - _TC" }, { "conversion_factor": 1.0, @@ -212,6 +214,7 @@ test_records = [ "posting_time": "17:14:24", "purpose": "Material Transfer", "fiscal_year": "_Test Fiscal Year 2013", + "expense_adjustment_account": "Stock Adjustment - _TC" }, { "conversion_factor": 1.0, diff --git a/stock/stock_ledger.py b/stock/stock_ledger.py index 883ced7f71..d00b243e81 100644 --- a/stock/stock_ledger.py +++ b/stock/stock_ledger.py @@ -71,7 +71,7 @@ def update_entries_after(args, verbose=1): (qty_after_transaction * valuation_rate) or 0 else: stock_value = sum((flt(batch[0]) * flt(batch[1]) for batch in stock_queue)) - + # print sle.posting_date, sle.actual_qty, sle.incoming_rate, stock_queue, stock_value # update current sle webnotes.conn.sql("""update `tabStock Ledger Entry` set qty_after_transaction=%s, valuation_rate=%s, stock_queue=%s, diff --git a/stock/utils.py b/stock/utils.py index bf5e2f9dcd..b4d07701ff 100644 --- a/stock/utils.py +++ b/stock/utils.py @@ -165,8 +165,8 @@ def get_warehouse_list(doctype, txt, searchfield, start, page_len, filters): return wlist def get_buying_amount(item_code, warehouse, qty, voucher_type, voucher_no, voucher_detail_no, - stock_ledger_entries, item_sales_bom): - if item_sales_bom.get(item_code): + stock_ledger_entries, item_sales_bom=None): + if item_sales_bom and item_sales_bom.get(item_code): # sales bom item buying_amount = 0.0 for bom_item in item_sales_bom[item_code]: @@ -182,13 +182,15 @@ def _get_buying_amount(voucher_type, voucher_no, item_row, item_code, warehouse, stock_ledger_entries): for i, sle in enumerate(stock_ledger_entries): if sle.voucher_type == voucher_type and sle.voucher_no == voucher_no and \ - len(stock_ledger_entries) > i+1: - if (sle.voucher_detail_no == item_row) or \ - (sle.item_code == item_code and sle.warehouse == warehouse and \ - abs(flt(sle.qty)) == qty): - buying_amount = flt(stock_ledger_entries[i+1].stock_value) - \ - flt(sle.stock_value) - return buying_amount + (sle.voucher_detail_no == item_row or (sle.voucher_type != "Stock Reconciliation" + and sle.item_code == item_code and sle.warehouse == warehouse and flt(sle.qty) == qty)): + # print "previous_sle", stock_ledger_entries[i+1] + # print "current sle", sle + previous_stock_value = len(stock_ledger_entries) > i+1 and \ + flt(stock_ledger_entries[i+1].stock_value) or 0.0 + + buying_amount = previous_stock_value - flt(sle.stock_value) + return buying_amount return 0.0 def get_sales_bom(): From 89a94d8135f4c22c9b22522ec1f00c9a9c064207 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Tue, 19 Mar 2013 12:01:46 +0530 Subject: [PATCH 13/30] aii: stock reconciliation with test case --- accounts/doctype/account/account.py | 2 +- accounts/doctype/fiscal_year/fiscal_year.txt | 23 +- .../purchase_invoice/purchase_invoice.js | 7 +- .../doctype/sales_invoice/sales_invoice.js | 21 +- .../doctype/sales_invoice/sales_invoice.py | 3 +- .../sales_invoice_item/sales_invoice_item.txt | 8 +- accounts/report/gross_profit/gross_profit.py | 6 +- controllers/accounts_controller.py | 2 +- controllers/buying_controller.py | 4 +- setup/doctype/company/company.py | 48 ++-- setup/doctype/company/company.txt | 59 ++++- stock/doctype/delivery_note/delivery_note.py | 33 +-- .../purchase_receipt/purchase_receipt.py | 29 +-- .../stock_reconciliation.js | 17 +- .../stock_reconciliation.py | 79 ++++-- .../stock_reconciliation.txt | 34 ++- .../test_stock_reconciliation.py | 230 ++++++++++++------ 17 files changed, 383 insertions(+), 222 deletions(-) diff --git a/accounts/doctype/account/account.py b/accounts/doctype/account/account.py index 08bf80fdce..3cd131fc29 100644 --- a/accounts/doctype/account/account.py +++ b/accounts/doctype/account/account.py @@ -207,4 +207,4 @@ def get_parent_account(doctype, txt, searchfield, start, page_len, filters): where group_or_ledger = 'Group' and docstatus != 2 and company = %s and %s like %s order by name limit %s, %s""" % ("%s", searchfield, "%s", "%s", "%s"), - (filters["company"], "%%%s%%" % txt, start, page_len), as_list=1) + (filters["company"], "%%%s%%" % txt, start, page_len), as_list=1) \ No newline at end of file diff --git a/accounts/doctype/fiscal_year/fiscal_year.txt b/accounts/doctype/fiscal_year/fiscal_year.txt index 18f20dd4f1..935b76f16f 100644 --- a/accounts/doctype/fiscal_year/fiscal_year.txt +++ b/accounts/doctype/fiscal_year/fiscal_year.txt @@ -1,8 +1,8 @@ [ { - "creation": "2013-01-10 16:34:06", + "creation": "2013-01-22 16:50:25", "docstatus": 0, - "modified": "2013-01-22 14:46:59", + "modified": "2013-03-13 12:29:40", "modified_by": "Administrator", "owner": "Administrator" }, @@ -23,7 +23,6 @@ "permlevel": 0 }, { - "amend": 0, "cancel": 1, "create": 1, "doctype": "DocPerm", @@ -42,22 +41,6 @@ "doctype": "DocType", "name": "Fiscal Year" }, - { - "doctype": "DocField", - "fieldname": "year_details", - "fieldtype": "Section Break", - "label": "Fiscal Year Details", - "oldfieldtype": "Section Break" - }, - { - "doctype": "DocField", - "fieldname": "trash_reason", - "fieldtype": "Small Text", - "label": "Trash Reason", - "oldfieldname": "trash_reason", - "oldfieldtype": "Small Text", - "read_only": 1 - }, { "description": "For e.g. 2012, 2012-13", "doctype": "DocField", @@ -73,6 +56,7 @@ "fieldname": "year_start_date", "fieldtype": "Date", "label": "Year Start Date", + "no_copy": 1, "oldfieldname": "year_start_date", "oldfieldtype": "Date", "reqd": 1 @@ -84,6 +68,7 @@ "fieldname": "is_fiscal_year_closed", "fieldtype": "Select", "label": "Year Closed", + "no_copy": 1, "oldfieldname": "is_fiscal_year_closed", "oldfieldtype": "Select", "options": "\nNo\nYes", diff --git a/accounts/doctype/purchase_invoice/purchase_invoice.js b/accounts/doctype/purchase_invoice/purchase_invoice.js index f4a2e68e5f..4a1cbbac17 100644 --- a/accounts/doctype/purchase_invoice/purchase_invoice.js +++ b/accounts/doctype/purchase_invoice/purchase_invoice.js @@ -238,8 +238,11 @@ cur_frm.cscript.expense_head = function(doc, cdt, cdn){ refresh_field('entries'); } -cur_frm.fields_dict['entries'].grid.get_field("cost_center").get_query = function(doc) { - return 'SELECT `tabCost Center`.`name` FROM `tabCost Center` WHERE `tabCost Center`.`company_name` = "' +doc.company+'" AND `tabCost Center`.%(key)s LIKE "%s" AND `tabCost Center`.`group_or_ledger` = "Ledger" AND `tabCost Center`.docstatus != 2 ORDER BY `tabCost Center`.`name` ASC LIMIT 50'; +cur_frm.fields_dict["entries"].grid.get_field("cost_center").get_query = function(doc) { + return { + query: "accounts.utils.get_cost_center_list", + filters: { company_name: doc.company} + } } cur_frm.cscript.cost_center = function(doc, cdt, cdn){ diff --git a/accounts/doctype/sales_invoice/sales_invoice.js b/accounts/doctype/sales_invoice/sales_invoice.js index a24e256ec9..5cc09a0c10 100644 --- a/accounts/doctype/sales_invoice/sales_invoice.js +++ b/accounts/doctype/sales_invoice/sales_invoice.js @@ -271,8 +271,6 @@ cur_frm.cscript.is_opening = function(doc, dt, dn) { if (doc.is_opening == 'Yes') unhide_field('aging_date'); } -/* **************************** TRIGGERS ********************************** */ - // Get Items based on SO or DN Selected cur_frm.cscript.get_items = function(doc, dt, dn) { var callback = function(r,rt) { @@ -371,6 +369,18 @@ cur_frm.set_query("income_account", "entries", function(doc) { return 'SELECT tabAccount.name FROM tabAccount WHERE (tabAccount.debit_or_credit="Credit" OR tabAccount.account_type = "Income Account") AND tabAccount.group_or_ledger="Ledger" AND tabAccount.docstatus!=2 AND tabAccount.company="'+doc.company+'" AND tabAccount.%(key)s LIKE "%s"'; }) +// expense account +cur_frm.fields_dict['entries'].grid.get_field('expense_account').get_query = function(doc) { + return { + "query": "accounts.utils.get_account_list", + "filters": { + "is_pl_account": "Yes", + "debit_or_credit": "Debit", + "company": doc.company + } + } +} + // warehouse in detail table //---------------------------- cur_frm.fields_dict['entries'].grid.get_field('warehouse').get_query= function(doc, cdt, cdn) { @@ -380,8 +390,11 @@ cur_frm.fields_dict['entries'].grid.get_field('warehouse').get_query= function(d // Cost Center in Details Table // ----------------------------- -cur_frm.fields_dict.entries.grid.get_field("cost_center").get_query = function(doc) { - return 'SELECT `tabCost Center`.`name` FROM `tabCost Center` WHERE `tabCost Center`.`company_name` = "' +doc.company+'" AND `tabCost Center`.%(key)s LIKE "%s" AND `tabCost Center`.`group_or_ledger` = "Ledger" AND `tabCost Center`.`docstatus`!= 2 ORDER BY `tabCost Center`.`name` ASC LIMIT 50'; +cur_frm.fields_dict["entries"].grid.get_field("cost_center").get_query = function(doc) { + return { + query: "accounts.utils.get_cost_center_list", + filters: { company_name: doc.company} + } } // Sales Order diff --git a/accounts/doctype/sales_invoice/sales_invoice.py b/accounts/doctype/sales_invoice/sales_invoice.py index de3ee95897..b6b1f0ba10 100644 --- a/accounts/doctype/sales_invoice/sales_invoice.py +++ b/accounts/doctype/sales_invoice/sales_invoice.py @@ -804,8 +804,9 @@ class DocType(SellingController): item_buying_amount = 0 if stock_ledger_entries: # is pos and update stock - item_buying_amount = get_buying_amount(item.item_code, item.warehouse, item.qty, + item_buying_amount = get_buying_amount(item.item_code, item.warehouse, -1*item.qty, self.doc.doctype, self.doc.name, item.name, stock_ledger_entries, item_sales_bom) + item.buying_amount = item_buying_amount > 0 and item_buying_amount or 0 elif item.delivery_note and item.dn_detail: # against delivery note dn_item = webnotes.conn.get_value("Delivery Note Item", item.dn_detail, diff --git a/accounts/doctype/sales_invoice_item/sales_invoice_item.txt b/accounts/doctype/sales_invoice_item/sales_invoice_item.txt index ca078b53f4..6f6ad399c5 100644 --- a/accounts/doctype/sales_invoice_item/sales_invoice_item.txt +++ b/accounts/doctype/sales_invoice_item/sales_invoice_item.txt @@ -2,7 +2,7 @@ { "creation": "2013-03-07 11:42:55", "docstatus": 0, - "modified": "2013-03-11 14:58:50", + "modified": "2013-03-18 15:41:19", "modified_by": "Administrator", "owner": "Administrator" }, @@ -207,14 +207,16 @@ "width": "120px" }, { + "depends_on": "eval:sys_defaults.auto_inventory_accounting", "doctype": "DocField", "fieldname": "expense_account", "fieldtype": "Link", - "hidden": 1, + "hidden": 0, "in_filter": 1, "label": "Expense Account", "options": "Account", - "print_hide": 1 + "print_hide": 1, + "width": "120px" }, { "doctype": "DocField", diff --git a/accounts/report/gross_profit/gross_profit.py b/accounts/report/gross_profit/gross_profit.py index f1ae00e13f..2480e17679 100644 --- a/accounts/report/gross_profit/gross_profit.py +++ b/accounts/report/gross_profit/gross_profit.py @@ -24,8 +24,10 @@ def execute(filters=None): data = [] for row in delivery_note_items: selling_amount = flt(row.amount) - buying_amount = get_buying_amount(row.item_code, row.warehouse, - row.qty, "Delivery Note", row.name, row.item_row, stock_ledger_entries, item_sales_bom) + buying_amount = get_buying_amount(row.item_code, row.warehouse, -1*row.qty, + "Delivery Note", row.name, row.item_row, stock_ledger_entries, item_sales_bom) + buying_amount = buying_amount > 0 and buying_amount or 0 + if selling_amount: gross_profit = selling_amount - buying_amount gross_profit_percent = (gross_profit / selling_amount) * 100.0 diff --git a/controllers/accounts_controller.py b/controllers/accounts_controller.py index 73d7608240..f328473329 100644 --- a/controllers/accounts_controller.py +++ b/controllers/accounts_controller.py @@ -18,6 +18,7 @@ from __future__ import unicode_literals import webnotes from webnotes import msgprint, _ from webnotes.utils import flt + from utilities.transaction_base import TransactionBase class AccountsController(TransactionBase): @@ -70,7 +71,6 @@ class AccountsController(TransactionBase): def get_stock_in_hand_account(self): stock_in_hand_account = webnotes.conn.get_value("Company", self.doc.company, "stock_in_hand_account") - if not stock_in_hand_account: msgprint(_("Missing") + ": " + _(webnotes.get_doctype("company").get_label("stock_in_hand_account") diff --git a/controllers/buying_controller.py b/controllers/buying_controller.py index 2f3128c98c..03d2a92660 100644 --- a/controllers/buying_controller.py +++ b/controllers/buying_controller.py @@ -24,9 +24,9 @@ from buying.utils import get_item_details from setup.utils import get_company_currency from webnotes.model.utils import round_floats_in_doc -from controllers.accounts_controller import AccountsController +from controllers.stock_controller import StockController -class BuyingController(AccountsController): +class BuyingController(StockController): def validate(self): if self.meta.get_field("currency"): self.company_currency = get_company_currency(self.doc.company) diff --git a/setup/doctype/company/company.py b/setup/doctype/company/company.py index 9cf722fca4..405171760b 100644 --- a/setup/doctype/company/company.py +++ b/setup/doctype/company/company.py @@ -17,7 +17,7 @@ from __future__ import unicode_literals import webnotes -from webnotes.utils import cstr, set_default +from webnotes.utils import cstr from webnotes.model.doc import Document from webnotes.model.code import get_obj import webnotes.defaults @@ -49,6 +49,8 @@ class DocType: ['Earnest Money','Securities and Deposits','Ledger','No','','Debit',self.doc.name,''], ['Stock In Hand','Current Assets','Group','No','','Debit',self.doc.name,''], ['Stock','Stock In Hand','Ledger','No','','Debit',self.doc.name,''], + ['Stock Delivered But Not Billed', 'Stock In Hand', 'Ledger', + 'No', '', 'Debit', self.doc.name, ''], ['Tax Assets','Current Assets','Group','No','','Debit',self.doc.name,''], ['Stock Delivered But Not Billed','Current Assets','Ledger','No','','Debit',self.doc.name,''], ['Fixed Assets','Application of Funds (Assets)','Group','No','','Debit',self.doc.name,''], @@ -62,9 +64,9 @@ class DocType: ['Temporary Account (Assets)','Temporary Accounts (Assets)','Ledger','No','','Debit',self.doc.name,''], ['Expenses','','Group','Yes','Expense Account','Debit',self.doc.name,''], ['Direct Expenses','Expenses','Group','Yes','Expense Account','Debit',self.doc.name,''], - ['Cost of Goods Sold','Direct Expenses','Ledger','Yes','Expense Account','Debit',self.doc.name,''], - ['Expenses Included In Valuation','Direct Expenses','Ledger','Yes','Expense Account','Debit',self.doc.name,''], - ['Stock Adjustment','Direct Expenses','Ledger','Yes','Expense Account','Debit',self.doc.name,''], + ['Stock Expenses','Direct Expenses','Group','Yes','Expense Account','Debit',self.doc.name,''], + ['Cost of Goods Sold','Stock Expenses','Ledger','Yes','Expense Account','Debit',self.doc.name,''], + ['Stock Adjustment','Stock Expenses','Ledger','Yes','Expense Account','Debit',self.doc.name,''], ['Indirect Expenses','Expenses','Group','Yes','Expense Account','Debit',self.doc.name,''], ['Advertising and Publicity','Indirect Expenses','Ledger','Yes','Chargeable','Debit',self.doc.name,''], ['Bad Debts Written Off','Indirect Expenses','Ledger','Yes','Expense Account','Debit',self.doc.name,''], @@ -101,6 +103,9 @@ class DocType: ['Shareholders Funds','Capital Account','Group','No','','Credit',self.doc.name,''], ['Current Liabilities','Source of Funds (Liabilities)','Group','No','','Credit',self.doc.name,''], ['Accounts Payable','Current Liabilities','Group','No','','Credit',self.doc.name,''], + ['Stock Liabilities','Current Liabilities','Group','No','','Credit',self.doc.name,''], + ['Stock Received But Not Billed', 'Stock Liabilities', 'Ledger', + 'No', '', 'Credit', self.doc.name, ''], ['Duties and Taxes','Current Liabilities','Group','No','','Credit',self.doc.name,''], ['Loans (Liabilities)','Current Liabilities','Group','No','','Credit',self.doc.name,''], ['Secured Loans','Loans (Liabilities)','Group','No','','Credit',self.doc.name,''], @@ -186,14 +191,30 @@ class DocType: self.doc.letter_head = header - # Set default AR and AP group - # --------------------------------------------------- - def set_default_groups(self): - if not self.doc.receivables_group: - webnotes.conn.set(self.doc, 'receivables_group', 'Accounts Receivable - '+self.doc.abbr) - if not self.doc.payables_group: - webnotes.conn.set(self.doc, 'payables_group', 'Accounts Payable - '+self.doc.abbr) + def set_default_accounts(self): + if not self.doc.receivables_group and webnotes.conn.exists('Account', + 'Accounts Receivable - ' + self.doc.abbr): + webnotes.conn.set(self.doc, 'receivables_group', 'Accounts Receivable - ' + + self.doc.abbr) + + if not self.doc.payables_group and webnotes.conn.exists('Account', + 'Accounts Payable - ' + self.doc.abbr): + webnotes.conn.set(self.doc, 'payables_group', 'Accounts Payable - ' + self.doc.abbr) + if not self.doc.stock_delivered_but_not_billed and webnotes.conn.exists("Account", + "Stock Delivered But Not Billed - " + self.doc.abbr): + webnotes.conn.set(self.doc, "stock_delivered_but_not_billed", + "Stock Delivered But Not Billed - " + self.doc.abbr) + + if not self.doc.stock_received_but_not_billed and webnotes.conn.exists("Account", + "Stock Received But Not Billed - " + self.doc.abbr): + webnotes.conn.set(self.doc, "stock_received_but_not_billed", + "Stock Received But Not Billed - " + self.doc.abbr) + + if not self.doc.stock_adjustment_account and webnotes.conn.exists("Account", + "Stock Adjustment - " + self.doc.abbr): + webnotes.conn.set(self.doc, "stock_adjustment_account", "Stock Adjustment - " + + self.doc.abbr) # Create default cost center # --------------------------------------------------- @@ -228,7 +249,7 @@ class DocType: self.doc.name) if not ac: self.create_default_accounts() - self.set_default_groups() + self.set_default_accounts() cc = sql("select name from `tabCost Center` where cost_center_name = 'Root' and company_name = '%s'"%(self.doc.name)) if not cc: self.create_default_cost_center() @@ -258,9 +279,6 @@ class DocType: #update value as blank for tabSingles Global Defaults sql("update `tabSingles` set value = '' where doctype='Global Defaults' and field = 'default_company' and value = %s", self.doc.name) - - # on rename - # --------- def on_rename(self,newdn,olddn): sql("update `tabCompany` set company_name = '%s' where name = '%s'" %(newdn,olddn)) sql("update `tabSingles` set value = %s where doctype='Global Defaults' and field = 'default_company' and value = %s", (newdn, olddn)) diff --git a/setup/doctype/company/company.txt b/setup/doctype/company/company.txt index d97cfc34af..d8c649ff28 100644 --- a/setup/doctype/company/company.txt +++ b/setup/doctype/company/company.txt @@ -1,8 +1,8 @@ [ { - "creation": "2013-02-22 01:27:54", + "creation": "2013-02-27 09:38:05", "docstatus": 0, - "modified": "2013-02-26 10:57:39", + "modified": "2013-03-18 16:34:04", "modified_by": "Administrator", "owner": "Administrator" }, @@ -124,17 +124,6 @@ "oldfieldtype": "Link", "options": "Account" }, - { - "depends_on": "eval:!doc.__islocal", - "description": "This account will be used to maintain value of available stock", - "doctype": "DocField", - "fieldname": "stock_in_hand_account", - "fieldtype": "Link", - "label": "Stock In Hand Account", - "no_copy": 1, - "options": "Account", - "read_only": 0 - }, { "doctype": "DocField", "fieldname": "column_break0", @@ -181,6 +170,50 @@ "oldfieldtype": "Select", "options": "\nWarn\nIgnore\nStop" }, + { + "depends_on": "eval:!doc.__islocal && sys_defaults.auto_inventory_accounting", + "doctype": "DocField", + "fieldname": "auto_inventory_accounting_settings", + "fieldtype": "Section Break", + "label": "Auto Inventory Accounting Settings" + }, + { + "description": "This account will be used to maintain value of available stock", + "doctype": "DocField", + "fieldname": "stock_in_hand_account", + "fieldtype": "Link", + "label": "Stock In Hand Account", + "no_copy": 1, + "options": "Account", + "read_only": 0 + }, + { + "doctype": "DocField", + "fieldname": "stock_adjustment_account", + "fieldtype": "Link", + "label": "Stock Adjustment Account", + "options": "Account" + }, + { + "doctype": "DocField", + "fieldname": "col_break23", + "fieldtype": "Column Break", + "width": "50%" + }, + { + "doctype": "DocField", + "fieldname": "stock_delivered_but_not_billed", + "fieldtype": "Link", + "label": "Stock Delivered But Not Billed", + "options": "Account" + }, + { + "doctype": "DocField", + "fieldname": "stock_received_but_not_billed", + "fieldtype": "Link", + "label": "Stock Received But Not Billed", + "options": "Account" + }, { "description": "For reference only.", "doctype": "DocField", diff --git a/stock/doctype/delivery_note/delivery_note.py b/stock/doctype/delivery_note/delivery_note.py index 229ec40a54..aef79390c2 100644 --- a/stock/doctype/delivery_note/delivery_note.py +++ b/stock/doctype/delivery_note/delivery_note.py @@ -24,7 +24,6 @@ from webnotes import msgprint sql = webnotes.conn.sql - from controllers.selling_controller import SellingController class DocType(SellingController): @@ -401,9 +400,10 @@ class DocType(SellingController): if stock_ledger_entries: for item in self.doclist.get({"parentfield": "delivery_note_details"}): - item.buying_amount = get_buying_amount(item.item_code, item.warehouse, item.qty, + buying_amount = get_buying_amount(item.item_code, item.warehouse, -1*item.qty, self.doc.doctype, self.doc.name, item.name, stock_ledger_entries, item_sales_bom) + item.buying_amount = buying_amount > 0 and buying_amount or 0 webnotes.conn.set_value("Delivery Note Item", item.name, "buying_amount", item.buying_amount) @@ -420,32 +420,11 @@ class DocType(SellingController): if not cint(webnotes.defaults.get_global_default("auto_inventory_accounting")): return - abbr = webnotes.conn.get_value("Company", self.doc.company, "abbr") - stock_delivered_account = "Stock Delivered But Not Billed - %s" % (abbr,) - stock_in_hand_account = self.get_stock_in_hand_account() - + against_stock_account = "Stock Delivered But Not Billed - %s" % (self.company_abbr,) total_buying_amount = self.get_total_buying_amount() - if total_buying_amount: - gl_entries = [ - # credit stock in hand account - self.get_gl_dict({ - "account": stock_in_hand_account, - "against": stock_delivered_account, - "credit": total_buying_amount, - "remarks": self.doc.remarks or "Accounting Entry for Stock", - }, self.doc.docstatus == 2), - - # debit stock received but not billed account - self.get_gl_dict({ - "account": stock_delivered_account, - "against": stock_in_hand_account, - "debit": total_buying_amount, - "remarks": self.doc.remarks or "Accounting Entry for Stock", - }, self.doc.docstatus == 2), - ] - from accounts.general_ledger import make_gl_entries - make_gl_entries(gl_entries, cancel=self.doc.docstatus == 2) - + + super(DocType, self).make_gl_entries(against_stock_account, -1*total_buying_amount) + def get_total_buying_amount(self): total_buying_amount = sum([item.buying_amount for item in self.doclist.get({"parentfield": "delivery_note_details"})]) diff --git a/stock/doctype/purchase_receipt/purchase_receipt.py b/stock/doctype/purchase_receipt/purchase_receipt.py index cce1493141..e26c0a6d1e 100644 --- a/stock/doctype/purchase_receipt/purchase_receipt.py +++ b/stock/doctype/purchase_receipt/purchase_receipt.py @@ -20,8 +20,7 @@ import webnotes from webnotes.utils import cstr, flt, cint from webnotes.model.bean import getlist from webnotes.model.code import get_obj -from webnotes.model.doc import Document -from webnotes import msgprint, _ +from webnotes import msgprint sql = webnotes.conn.sql @@ -319,32 +318,10 @@ class DocType(BuyingController): if not cint(webnotes.defaults.get_global_default("auto_inventory_accounting")): return - abbr = webnotes.conn.get_value("Company", self.doc.company, "abbr") - stock_received_account = "Stock Received But Not Billed - %s" % (abbr,) - stock_in_hand_account = self.get_stock_in_hand_account() - + against_stock_account = "Stock Received But Not Billed - %s" % (self.company_abbr,) total_valuation_amount = self.get_total_valuation_amount() - if total_valuation_amount: - gl_entries = [ - # debit stock in hand account - self.get_gl_dict({ - "account": stock_in_hand_account, - "against": stock_received_account, - "debit": total_valuation_amount, - "remarks": self.doc.remarks or "Accounting Entry for Stock", - }, self.doc.docstatus == 2), - - # credit stock received but not billed account - self.get_gl_dict({ - "account": stock_received_account, - "against": stock_in_hand_account, - "credit": total_valuation_amount, - "remarks": self.doc.remarks or "Accounting Entry for Stock", - }, self.doc.docstatus == 2), - ] - from accounts.general_ledger import make_gl_entries - make_gl_entries(gl_entries, cancel=self.doc.docstatus == 2) + super(DocType, self).make_gl_entries(against_stock_account, total_valuation_amount) def get_total_valuation_amount(self): total_valuation_amount = 0.0 diff --git a/stock/doctype/stock_reconciliation/stock_reconciliation.js b/stock/doctype/stock_reconciliation/stock_reconciliation.js index f1508ac766..fb4053ca9e 100644 --- a/stock/doctype/stock_reconciliation/stock_reconciliation.js +++ b/stock/doctype/stock_reconciliation/stock_reconciliation.js @@ -18,6 +18,10 @@ wn.require("public/app/js/controllers/stock_controller.js"); wn.provide("erpnext.stock"); erpnext.stock.StockReconciliation = erpnext.stock.StockController.extend({ + setup: function() { + this.frm.add_fetch("company", "stock_adjustment_account", "expense_account"); + }, + refresh: function() { if(this.frm.doc.docstatus===0) { this.show_download_template(); @@ -122,4 +126,15 @@ erpnext.stock.StockReconciliation = erpnext.stock.StockController.extend({ }, }); -cur_frm.cscript = new erpnext.stock.StockReconciliation({frm: cur_frm}); \ No newline at end of file +cur_frm.cscript = new erpnext.stock.StockReconciliation({frm: cur_frm}); + +cur_frm.fields_dict["expense_account"].get_query = function(doc) { + return { + "query": "accounts.utils.get_account_list", + "filters": { + "is_pl_account": "Yes", + "debit_or_credit": "Debit", + "company": doc.company + } + } +} \ No newline at end of file diff --git a/stock/doctype/stock_reconciliation/stock_reconciliation.py b/stock/doctype/stock_reconciliation/stock_reconciliation.py index e0f7f09c58..c2f5a940c5 100644 --- a/stock/doctype/stock_reconciliation/stock_reconciliation.py +++ b/stock/doctype/stock_reconciliation/stock_reconciliation.py @@ -18,22 +18,26 @@ from __future__ import unicode_literals import webnotes import json from webnotes import msgprint, _ -from webnotes.utils import cstr, flt -from webnotes.model.controller import DocListController +from webnotes.utils import cstr, flt, cint from stock.stock_ledger import update_entries_after +from controllers.stock_controller import StockController -class DocType(DocListController): +class DocType(StockController): def setup(self): self.head_row = ["Item Code", "Warehouse", "Quantity", "Valuation Rate"] + self.entries = [] def validate(self): self.validate_data() def on_submit(self): self.insert_stock_ledger_entries() + self.set_stock_value_difference() + self.make_gl_entries() def on_cancel(self): self.delete_stock_ledger_entries() + self.make_gl_entries() def validate_data(self): if not self.doc.reconciliation_json: @@ -134,6 +138,7 @@ class DocType(DocListController): data = json.loads(self.doc.reconciliation_json) for row_num, row in enumerate(data[data.index(self.head_row)+1:]): row = webnotes._dict(zip(row_template, row)) + row["row_num"] = row_num previous_sle = get_previous_sle({ "item_code": row.item_code, "warehouse": row.warehouse, @@ -162,8 +167,7 @@ class DocType(DocListController): def sle_for_moving_avg(self, row, previous_sle, change_in_qty, change_in_rate): """Insert Stock Ledger Entries for Moving Average valuation""" - def _get_incoming_rate(qty, valuation_rate, previous_qty, - previous_valuation_rate): + def _get_incoming_rate(qty, valuation_rate, previous_qty, previous_valuation_rate): if previous_valuation_rate == 0: return flt(valuation_rate) else: @@ -177,9 +181,9 @@ class DocType(DocListController): incoming_rate = _get_incoming_rate(flt(row.qty), flt(row.valuation_rate), flt(previous_sle.get("qty_after_transaction")), flt(previous_sle.get("valuation_rate"))) - - self.insert_entries({"actual_qty": change_in_qty, - "incoming_rate": incoming_rate}, row) + + row["voucher_detail_no"] = "Row: " + cstr(row.row_num) + "/Actual Entry" + self.insert_entries({"actual_qty": change_in_qty, "incoming_rate": incoming_rate}, row) elif change_in_rate and flt(previous_sle.get("qty_after_transaction")) > 0: # if no change in qty, but change in rate @@ -190,9 +194,11 @@ class DocType(DocListController): flt(previous_sle.get("valuation_rate"))) # +1 entry + row["voucher_detail_no"] = "Row: " + cstr(row.row_num) + "/Valuation Adjustment +1" self.insert_entries({"actual_qty": 1, "incoming_rate": incoming_rate}, row) # -1 entry + row["voucher_detail_no"] = "Row: " + cstr(row.row_num) + "/Valuation Adjustment -1" self.insert_entries({"actual_qty": -1}, row) def sle_for_fifo(self, row, previous_sle, change_in_qty, change_in_rate): @@ -206,14 +212,16 @@ class DocType(DocListController): if previous_stock_queue != [[row.qty, row.valuation_rate]]: # make entry as per attachment if row.qty: + row["voucher_detail_no"] = "Row: " + cstr(row.row_num) + "/Actual Entry" self.insert_entries({"actual_qty": row.qty, "incoming_rate": flt(row.valuation_rate)}, row) # Make reverse entry if previous_stock_qty: + row["voucher_detail_no"] = "Row: " + cstr(row.row_num) + "/Reverse Entry" self.insert_entries({"actual_qty": -1 * previous_stock_qty, - "incoming_rate": previous_stock_qty < 0 and \ - flt(row.valuation_rate) or 0}, row) + "incoming_rate": previous_stock_qty < 0 and + flt(row.valuation_rate) or 0}, row) if change_in_qty: @@ -221,8 +229,7 @@ class DocType(DocListController): # dont want change in valuation if previous_stock_qty > 0: # set valuation_rate as previous valuation_rate - row.valuation_rate = \ - previous_stock_value / flt(previous_stock_qty) + row.valuation_rate = previous_stock_value / flt(previous_stock_qty) _insert_entries() @@ -234,8 +241,8 @@ class DocType(DocListController): _insert_entries() def insert_entries(self, opts, row): - """Insert Stock Ledger Entries""" - args = { + """Insert Stock Ledger Entries""" + args = webnotes._dict({ "doctype": "Stock Ledger Entry", "item_code": row.item_code, "warehouse": row.warehouse, @@ -243,9 +250,10 @@ class DocType(DocListController): "posting_time": self.doc.posting_time, "voucher_type": self.doc.doctype, "voucher_no": self.doc.name, - "company": webnotes.conn.get_default("company"), + "company": self.doc.company, "is_cancelled": "No", - } + "voucher_detail_no": row.voucher_detail_no + }) args.update(opts) # create stock ledger entry sle_wrapper = webnotes.bean([args]) @@ -254,17 +262,18 @@ class DocType(DocListController): # update bin webnotes.get_obj('Warehouse', row.warehouse).update_bin(args) - - return sle_wrapper + + # append to entries + self.entries.append(args) def delete_stock_ledger_entries(self): """ Delete Stock Ledger Entries related to this Stock Reconciliation and repost future Stock Ledger Entries""" - + existing_entries = webnotes.conn.sql("""select item_code, warehouse - from `tabStock Ledger Entry` where voucher_type='Stock Reconciliation' + from `tabStock Ledger Entry` where voucher_type='Stock Reconciliation' and voucher_no=%s""", self.doc.name, as_dict=1) - + # delete entries webnotes.conn.sql("""delete from `tabStock Ledger Entry` where voucher_type='Stock Reconciliation' and voucher_no=%s""", self.doc.name) @@ -277,7 +286,33 @@ class DocType(DocListController): "posting_date": self.doc.posting_date, "posting_time": self.doc.posting_time }) - + + def set_stock_value_difference(self): + """stock_value_difference is the increment in the stock value""" + from stock.utils import get_buying_amount + + item_list = [d.item_code for d in self.entries] + warehouse_list = [d.warehouse for d in self.entries] + stock_ledger_entries = self.get_stock_ledger_entries(item_list, warehouse_list) + + self.doc.stock_value_difference = 0.0 + for d in self.entries: + self.doc.stock_value_difference -= get_buying_amount(d.item_code, d.warehouse, + d.actual_qty, self.doc.doctype, self.doc.name, d.voucher_detail_no, + stock_ledger_entries) + webnotes.conn.set(self.doc, "stock_value_difference", self.doc.stock_value_difference) + + def make_gl_entries(self): + if not cint(webnotes.defaults.get_global_default("auto_inventory_accounting")): + return + + if not self.doc.expense_account: + msgprint(_("Please enter Expense Account"), raise_exception=1) + + cost_center = "Auto Inventory Accounting - %s" % (self.company_abbr,) + + super(DocType, self).make_gl_entries(self.doc.expense_account, + self.doc.stock_value_difference, cost_center) @webnotes.whitelist() def upload(): diff --git a/stock/doctype/stock_reconciliation/stock_reconciliation.txt b/stock/doctype/stock_reconciliation/stock_reconciliation.txt index 094e90384f..9137cae972 100644 --- a/stock/doctype/stock_reconciliation/stock_reconciliation.txt +++ b/stock/doctype/stock_reconciliation/stock_reconciliation.txt @@ -1,8 +1,8 @@ [ { - "creation": "2013-01-19 10:23:35", + "creation": "2013-01-22 16:50:41", "docstatus": 0, - "modified": "2013-01-22 14:57:24", + "modified": "2013-03-18 12:48:42", "modified_by": "Administrator", "owner": "Administrator" }, @@ -30,6 +30,7 @@ "permlevel": 0 }, { + "amend": 1, "cancel": 1, "create": 1, "doctype": "DocPerm", @@ -40,6 +41,7 @@ "permlevel": 0, "read": 1, "report": 1, + "role": "Material Manager", "submit": 1, "write": 1 }, @@ -79,6 +81,22 @@ "print_hide": 1, "read_only": 1 }, + { + "doctype": "DocField", + "fieldname": "company", + "fieldtype": "Link", + "label": "Company", + "options": "Company", + "reqd": 1 + }, + { + "depends_on": "eval:sys_defaults.auto_inventory_accounting", + "doctype": "DocField", + "fieldname": "expense_account", + "fieldtype": "Link", + "label": "Expense Account", + "options": "Account" + }, { "doctype": "DocField", "fieldname": "col1", @@ -119,12 +137,14 @@ "read_only": 1 }, { - "amend": 0, - "doctype": "DocPerm", - "role": "Material Manager" + "doctype": "DocField", + "fieldname": "stock_value_difference", + "fieldtype": "Currency", + "hidden": 1, + "label": "Stock Value Difference", + "print_hide": 1 }, { - "doctype": "DocPerm", - "role": "System Manager" + "doctype": "DocPerm" } ] \ No newline at end of file diff --git a/stock/doctype/stock_reconciliation/test_stock_reconciliation.py b/stock/doctype/stock_reconciliation/test_stock_reconciliation.py index 80579aed5b..cebc6ffc53 100644 --- a/stock/doctype/stock_reconciliation/test_stock_reconciliation.py +++ b/stock/doctype/stock_reconciliation/test_stock_reconciliation.py @@ -1,40 +1,15 @@ # 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 . - +# For license information, please see license.txt from __future__ import unicode_literals -import unittest -import webnotes -from webnotes.tests import insert_test_data +import webnotes, unittest from webnotes.utils import flt import json - -company = webnotes.conn.get_default("company") +from accounts.utils import get_fiscal_year class TestStockReconciliation(unittest.TestCase): - def setUp(self): - webnotes.conn.begin() - self.insert_test_data() - - def tearDown(self): - # print "Message Log:", "\n--\n".join(webnotes.message_log) - # print "Debug Log:", "\n--\n".join(webnotes.debug_log) - webnotes.conn.rollback() - def test_reco_for_fifo(self): + webnotes.defaults.set_global_default("auto_inventory_accounting", 0) # [[qty, valuation_rate, posting_date, # posting_time, expected_stock_value, bin_qty, bin_valuation]] input_data = [ @@ -53,28 +28,32 @@ class TestStockReconciliation(unittest.TestCase): ] for d in input_data: + self.cleanup_data() self.insert_existing_sle("FIFO") - - self.submit_stock_reconciliation(d[0], d[1], d[2], d[3]) + stock_reco = self.submit_stock_reconciliation(d[0], d[1], d[2], d[3]) + # check stock value res = webnotes.conn.sql("""select stock_value from `tabStock Ledger Entry` - where item_code = 'Android Jack D' and warehouse = 'Default Warehouse' + where item_code = '_Test Item' and warehouse = '_Test Warehouse' and posting_date = %s and posting_time = %s order by name desc limit 1""", (d[2], d[3])) - self.assertEqual(res and flt(res[0][0]) or 0, d[4]) + # check bin qty and stock value bin = webnotes.conn.sql("""select actual_qty, stock_value from `tabBin` - where item_code = 'Android Jack D' and warehouse = 'Default Warehouse'""") + where item_code = '_Test Item' and warehouse = '_Test Warehouse'""") self.assertEqual(bin and [flt(bin[0][0]), flt(bin[0][1])] or [], [d[5], d[6]]) + # no gl entries + gl_entries = webnotes.conn.sql("""select name from `tabGL Entry` + where voucher_type = 'Stock Reconciliation' and voucher_no = %s""", + stock_reco.doc.name) + self.assertFalse(gl_entries) - self.tearDown() - self.setUp() - def test_reco_for_moving_average(self): + webnotes.defaults.set_global_default("auto_inventory_accounting", 0) # [[qty, valuation_rate, posting_date, # posting_time, expected_stock_value, bin_qty, bin_valuation]] input_data = [ @@ -94,95 +73,194 @@ class TestStockReconciliation(unittest.TestCase): ] for d in input_data: + self.cleanup_data() self.insert_existing_sle("Moving Average") + stock_reco = self.submit_stock_reconciliation(d[0], d[1], d[2], d[3]) - self.submit_stock_reconciliation(d[0], d[1], d[2], d[3]) - + # check stock value in sle res = webnotes.conn.sql("""select stock_value from `tabStock Ledger Entry` - where item_code = 'Android Jack D' and warehouse = 'Default Warehouse' + where item_code = '_Test Item' and warehouse = '_Test Warehouse' and posting_date = %s and posting_time = %s order by name desc limit 1""", (d[2], d[3])) self.assertEqual(res and flt(res[0][0], 4) or 0, d[4]) + # bin qty and stock value bin = webnotes.conn.sql("""select actual_qty, stock_value from `tabBin` - where item_code = 'Android Jack D' and warehouse = 'Default Warehouse'""") + where item_code = '_Test Item' and warehouse = '_Test Warehouse'""") self.assertEqual(bin and [flt(bin[0][0]), flt(bin[0][1], 4)] or [], [flt(d[5]), flt(d[6])]) - - self.tearDown() - self.setUp() + + # no gl entries + gl_entries = webnotes.conn.sql("""select name from `tabGL Entry` + where voucher_type = 'Stock Reconciliation' and voucher_no = %s""", + stock_reco.doc.name) + self.assertFalse(gl_entries) + def test_reco_fifo_gl_entries(self): + webnotes.defaults.set_global_default("auto_inventory_accounting", 1) + + # [[qty, valuation_rate, posting_date, + # posting_time, stock_in_hand_debit]] + input_data = [ + [50, 1000, "2012-12-26", "12:00", 38000], + [5, 1000, "2012-12-26", "12:00", -7000], + [15, 1000, "2012-12-26", "12:00", 3000], + [25, 900, "2012-12-26", "12:00", 10500], + [20, 500, "2012-12-26", "12:00", -2000], + ["", 1000, "2012-12-26", "12:05", 3000], + [20, "", "2012-12-26", "12:05", 4000], + [10, 2000, "2012-12-26", "12:10", 8000], + [0, "", "2012-12-26", "12:10", -12000], + [50, 1000, "2013-01-01", "12:00", 50000], + [5, 1000, "2013-01-01", "12:00", 5000], + [1, 1000, "2012-12-01", "00:00", 1000], + + ] + + for d in input_data: + self.cleanup_data() + self.insert_existing_sle("FIFO") + stock_reco = self.submit_stock_reconciliation(d[0], d[1], d[2], d[3]) + + # check gl_entries + self.check_gl_entries(stock_reco.doc.name, d[4]) + + # cancel + stock_reco.cancel() + self.check_gl_entries(stock_reco.doc.name, -d[4], True) + + webnotes.defaults.set_global_default("auto_inventory_accounting", 0) + + def test_reco_moving_average_gl_entries(self): + webnotes.defaults.set_global_default("auto_inventory_accounting", 1) + + # [[qty, valuation_rate, posting_date, + # posting_time, stock_in_hand_debit]] + input_data = [ + [50, 1000, "2012-12-26", "12:00", 36500], + [5, 1000, "2012-12-26", "12:00", -8500], + [15, 1000, "2012-12-26", "12:00", 1500], + [25, 900, "2012-12-26", "12:00", 9000], + [20, 500, "2012-12-26", "12:00", -3500], + ["", 1000, "2012-12-26", "12:05", 1500], + [20, "", "2012-12-26", "12:05", 4500], + [10, 2000, "2012-12-26", "12:10", 6500], + [0, "", "2012-12-26", "12:10", -13500], + [50, 1000, "2013-01-01", "12:00", 50000], + [5, 1000, "2013-01-01", "12:00", 5000], + [1, 1000, "2012-12-01", "00:00", 1000], + + ] + + for d in input_data: + self.cleanup_data() + self.insert_existing_sle("Moving Average") + stock_reco = self.submit_stock_reconciliation(d[0], d[1], d[2], d[3]) + + # check gl_entries + self.check_gl_entries(stock_reco.doc.name, d[4]) + + # cancel + stock_reco.cancel() + self.check_gl_entries(stock_reco.doc.name, -d[4], True) + + webnotes.defaults.set_global_default("auto_inventory_accounting", 0) + + + def cleanup_data(self): + webnotes.conn.sql("delete from `tabStock Ledger Entry`") + webnotes.conn.sql("delete from tabBin") + def submit_stock_reconciliation(self, qty, rate, posting_date, posting_time): - return webnotes.bean([{ + stock_reco = webnotes.bean([{ "doctype": "Stock Reconciliation", - "name": "RECO-001", - "__islocal": 1, "posting_date": posting_date, "posting_time": posting_time, + "fiscal_year": get_fiscal_year(posting_date)[0], + "company": "_Test Company", + "expense_account": "Stock Adjustment - _TC", "reconciliation_json": json.dumps([ ["Item Code", "Warehouse", "Quantity", "Valuation Rate"], - ["Android Jack D", "Default Warehouse", qty, rate] + ["_Test Item", "_Test Warehouse", qty, rate] ]), - }]).submit() + }]) + stock_reco.insert() + stock_reco.submit() + return stock_reco - def insert_test_data(self): - # create default warehouse - if not webnotes.conn.exists("Warehouse", "Default Warehouse"): - webnotes.insert({"doctype": "Warehouse", - "warehouse_name": "Default Warehouse", - "warehouse_type": "Stores"}) - - # create UOM: Nos. - if not webnotes.conn.exists("UOM", "Nos"): - webnotes.insert({"doctype": "UOM", "uom_name": "Nos"}) - - # create item groups and items - insert_test_data("Item Group", - sort_fn=lambda ig: (ig[0].get('parent_item_group'), ig[0].get('name'))) - insert_test_data("Item") + def check_gl_entries(self, voucher_no, stock_value_diff, cancel=None): + stock_in_hand_account = webnotes.conn.get_value("Company", "_Test Company", + "stock_in_hand_account") + debit_amount = stock_value_diff > 0 and stock_value_diff or 0.0 + credit_amount = stock_value_diff < 0 and abs(stock_value_diff) or 0.0 + + expected_gl_entries = sorted([ + [stock_in_hand_account, debit_amount, credit_amount], + ["Stock Adjustment - _TC", credit_amount, debit_amount] + ]) + if cancel: + expected_gl_entries = sorted([ + [stock_in_hand_account, debit_amount, credit_amount], + ["Stock Adjustment - _TC", credit_amount, debit_amount], + [stock_in_hand_account, credit_amount, debit_amount], + ["Stock Adjustment - _TC", debit_amount, credit_amount] + ]) + + gl_entries = webnotes.conn.sql("""select account, debit, credit + from `tabGL Entry` where voucher_type='Stock Reconciliation' and voucher_no=%s + order by account asc, debit asc""", voucher_no, as_dict=1) + self.assertTrue(gl_entries) + + for i, gle in enumerate(gl_entries): + self.assertEquals(expected_gl_entries[i][0], gle.account) + self.assertEquals(expected_gl_entries[i][1], gle.debit) + self.assertEquals(expected_gl_entries[i][2], gle.credit) def insert_existing_sle(self, valuation_method): - webnotes.conn.set_value("Item", "Android Jack D", "valuation_method", valuation_method) + webnotes.conn.set_value("Item", "_Test Item", "valuation_method", valuation_method) webnotes.conn.set_default("allow_negative_stock", 1) existing_ledgers = [ { "doctype": "Stock Ledger Entry", "__islocal": 1, "voucher_type": "Stock Entry", "voucher_no": "TEST", - "item_code": "Android Jack D", "warehouse": "Default Warehouse", + "item_code": "_Test Item", "warehouse": "_Test Warehouse", "posting_date": "2012-12-12", "posting_time": "01:00", - "actual_qty": 20, "incoming_rate": 1000, "company": company + "actual_qty": 20, "incoming_rate": 1000, "company": "_Test Company" }, { "doctype": "Stock Ledger Entry", "__islocal": 1, "voucher_type": "Stock Entry", "voucher_no": "TEST", - "item_code": "Android Jack D", "warehouse": "Default Warehouse", + "item_code": "_Test Item", "warehouse": "_Test Warehouse", "posting_date": "2012-12-15", "posting_time": "02:00", - "actual_qty": 10, "incoming_rate": 700, "company": company + "actual_qty": 10, "incoming_rate": 700, "company": "_Test Company" }, { "doctype": "Stock Ledger Entry", "__islocal": 1, "voucher_type": "Stock Entry", "voucher_no": "TEST", - "item_code": "Android Jack D", "warehouse": "Default Warehouse", + "item_code": "_Test Item", "warehouse": "_Test Warehouse", "posting_date": "2012-12-25", "posting_time": "03:00", - "actual_qty": -15, "company": company + "actual_qty": -15, "company": "_Test Company" }, { "doctype": "Stock Ledger Entry", "__islocal": 1, "voucher_type": "Stock Entry", "voucher_no": "TEST", - "item_code": "Android Jack D", "warehouse": "Default Warehouse", + "item_code": "_Test Item", "warehouse": "_Test Warehouse", "posting_date": "2012-12-31", "posting_time": "08:00", - "actual_qty": -20, "company": company + "actual_qty": -20, "company": "_Test Company" }, { "doctype": "Stock Ledger Entry", "__islocal": 1, "voucher_type": "Stock Entry", "voucher_no": "TEST", - "item_code": "Android Jack D", "warehouse": "Default Warehouse", + "item_code": "_Test Item", "warehouse": "_Test Warehouse", "posting_date": "2013-01-05", "posting_time": "07:00", - "actual_qty": 15, "incoming_rate": 1200, "company": company + "actual_qty": 15, "incoming_rate": 1200, "company": "_Test Company" }, ] - webnotes.get_obj("Stock Ledger").update_stock(existing_ledgers) \ No newline at end of file + webnotes.get_obj("Stock Ledger").update_stock(existing_ledgers) + + +test_dependencies = ["Item", "Warehouse"] \ No newline at end of file From e68103be30eef0ccb840fc18980518b0e74d5697 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Tue, 19 Mar 2013 12:34:47 +0530 Subject: [PATCH 14/30] fixes in reorder level and company --- setup/doctype/company/company.py | 8 +++----- stock/doctype/bin/bin.py | 19 +++++-------------- stock/doctype/item_reorder/item_reorder.txt | 13 ++++++++----- 3 files changed, 16 insertions(+), 24 deletions(-) diff --git a/setup/doctype/company/company.py b/setup/doctype/company/company.py index 405171760b..e895b49fdc 100644 --- a/setup/doctype/company/company.py +++ b/setup/doctype/company/company.py @@ -47,12 +47,11 @@ class DocType: ['Loans and Advances (Assets)','Current Assets','Group','No','','Debit',self.doc.name,''], ['Securities and Deposits','Current Assets','Group','No','','Debit',self.doc.name,''], ['Earnest Money','Securities and Deposits','Ledger','No','','Debit',self.doc.name,''], - ['Stock In Hand','Current Assets','Group','No','','Debit',self.doc.name,''], - ['Stock','Stock In Hand','Ledger','No','','Debit',self.doc.name,''], - ['Stock Delivered But Not Billed', 'Stock In Hand', 'Ledger', + ['Stock Assets','Current Assets','Group','No','','Debit',self.doc.name,''], + ['Stock In Hand','Stock Assets','Ledger','No','','Debit',self.doc.name,''], + ['Stock Delivered But Not Billed', 'Stock Assets', 'Ledger', 'No', '', 'Debit', self.doc.name, ''], ['Tax Assets','Current Assets','Group','No','','Debit',self.doc.name,''], - ['Stock Delivered But Not Billed','Current Assets','Ledger','No','','Debit',self.doc.name,''], ['Fixed Assets','Application of Funds (Assets)','Group','No','','Debit',self.doc.name,''], ['Capital Equipments','Fixed Assets','Ledger','No','Fixed Asset Account','Debit',self.doc.name,''], ['Computers','Fixed Assets','Ledger','No','Fixed Asset Account','Debit',self.doc.name,''], @@ -111,7 +110,6 @@ class DocType: ['Secured Loans','Loans (Liabilities)','Group','No','','Credit',self.doc.name,''], ['Unsecured Loans','Loans (Liabilities)','Group','No','','Credit',self.doc.name,''], ['Bank Overdraft Account','Loans (Liabilities)','Group','No','','Credit',self.doc.name,''], - ['Stock Received But Not Billed','Current Liabilities','Ledger','No','','Credit',self.doc.name,''], ['Temporary Accounts (Liabilities)','Source of Funds (Liabilities)','Group','No','','Credit',self.doc.name,''], ['Temporary Account (Liabilities)','Temporary Accounts (Liabilities)','Ledger','No','','Credit',self.doc.name,''] ] diff --git a/stock/doctype/bin/bin.py b/stock/doctype/bin/bin.py index 37ecf85d2c..204053d9ee 100644 --- a/stock/doctype/bin/bin.py +++ b/stock/doctype/bin/bin.py @@ -16,15 +16,8 @@ from __future__ import unicode_literals import webnotes -from webnotes import _ - -from webnotes.utils import add_days, cint, cstr, flt, now, nowdate, \ - get_url_to_form, formatdate -from webnotes.model import db_exists -from webnotes.model.doc import Document, addchild -from webnotes.model.bean import copy_doclist -from webnotes.model.code import get_obj -from webnotes import msgprint +from webnotes.utils import add_days, cint,flt, nowdate, get_url_to_form, formatdate +from webnotes import msgprint, _ sql = webnotes.conn.sql import webnotes.defaults @@ -61,7 +54,7 @@ class DocType: from stock.stock_ledger import update_entries_after if not args.get("posting_date"): - posting_date = nowdate() + args["posting_date"] = nowdate() # update valuation and qty after transaction for post dated entry update_entries_after({ @@ -108,11 +101,10 @@ class DocType: #check if re-order is required item_reorder = webnotes.conn.get("Item Reorder", {"parent": self.doc.item_code, "warehouse": self.doc.warehouse}) - if item_reorder: reorder_level = item_reorder.warehouse_reorder_level reorder_qty = item_reorder.warehouse_reorder_qty - material_request_type = item_reorder.material_request_type + material_request_type = item_reorder.material_request_type or "Purchase" else: reorder_level, reorder_qty = webnotes.conn.get_value("Item", self.doc.item_code, ["re_order_level", "re_order_qty"]) @@ -123,7 +115,7 @@ class DocType: material_request_type) def create_material_request(self, doc_type, doc_name, reorder_level, reorder_qty, - material_request_type): + material_request_type="Purchase"): """ Create indent on reaching reorder level """ defaults = webnotes.defaults.get_defaults() item = webnotes.doc("Item", self.doc.item_code) @@ -151,7 +143,6 @@ class DocType: "qty": reorder_qty, "brand": item.brand, }]) - mr.insert() mr.submit() diff --git a/stock/doctype/item_reorder/item_reorder.txt b/stock/doctype/item_reorder/item_reorder.txt index 43ed4fed86..b6933c7458 100644 --- a/stock/doctype/item_reorder/item_reorder.txt +++ b/stock/doctype/item_reorder/item_reorder.txt @@ -1,8 +1,8 @@ [ { - "creation": "2013-02-22 01:28:01", + "creation": "2013-03-07 11:42:59", "docstatus": 0, - "modified": "2013-03-07 07:03:22", + "modified": "2013-03-19 12:22:44", "modified_by": "Administrator", "owner": "Administrator" }, @@ -20,7 +20,8 @@ "parent": "Item Reorder", "parentfield": "fields", "parenttype": "DocType", - "permlevel": 0 + "permlevel": 0, + "read_only": 0 }, { "doctype": "DocType", @@ -38,7 +39,8 @@ "doctype": "DocField", "fieldname": "warehouse_reorder_level", "fieldtype": "Float", - "label": "Re-order Level" + "label": "Re-order Level", + "reqd": 1 }, { "doctype": "DocField", @@ -51,6 +53,7 @@ "fieldname": "material_request_type", "fieldtype": "Select", "label": "Material Request Type", - "options": "Purchase\nTransfer" + "options": "Purchase\nTransfer", + "reqd": 1 } ] \ No newline at end of file From d98e511c8b45ac9249fb618fa510ec548711dd79 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Tue, 19 Mar 2013 12:45:02 +0530 Subject: [PATCH 15/30] deafult account creation in company --- setup/doctype/company/company.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup/doctype/company/company.py b/setup/doctype/company/company.py index e895b49fdc..6ba7985d6d 100644 --- a/setup/doctype/company/company.py +++ b/setup/doctype/company/company.py @@ -66,6 +66,7 @@ class DocType: ['Stock Expenses','Direct Expenses','Group','Yes','Expense Account','Debit',self.doc.name,''], ['Cost of Goods Sold','Stock Expenses','Ledger','Yes','Expense Account','Debit',self.doc.name,''], ['Stock Adjustment','Stock Expenses','Ledger','Yes','Expense Account','Debit',self.doc.name,''], + ['Expenses Included In Valuation', "Stock Expenses", 'Ledger', 'Yes', 'Expense Account', 'Debit', self.doc.name, ''], ['Indirect Expenses','Expenses','Group','Yes','Expense Account','Debit',self.doc.name,''], ['Advertising and Publicity','Indirect Expenses','Ledger','Yes','Chargeable','Debit',self.doc.name,''], ['Bad Debts Written Off','Indirect Expenses','Ledger','Yes','Expense Account','Debit',self.doc.name,''], From f9e51bbab3f8df8142f525e0be64eb133d755697 Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Tue, 19 Mar 2013 13:33:51 +0530 Subject: [PATCH 16/30] removed complications from sales purchase return --- stock/doctype/stock_entry/stock_entry.py | 132 ++++++------------ stock/doctype/stock_entry/test_stock_entry.py | 36 ++--- 2 files changed, 53 insertions(+), 115 deletions(-) diff --git a/stock/doctype/stock_entry/stock_entry.py b/stock/doctype/stock_entry/stock_entry.py index 131e9ffcd4..edaf63b4e1 100644 --- a/stock/doctype/stock_entry/stock_entry.py +++ b/stock/doctype/stock_entry/stock_entry.py @@ -279,7 +279,7 @@ class DocType(AccountsController): def validate_return_reference_doc(self): """validate item with reference doc""" - ref = get_return_reference_details(self.doc.fields) + ref = get_return_doclist_and_details(self.doc.fields) if ref.doclist: # validate docstatus @@ -703,7 +703,7 @@ def query_purchase_return_doc(doctype, txt, searchfield, start, page_len, filter def query_return_item(doctype, txt, searchfield, start, page_len, filters): txt = txt.replace("%", "") - ref = get_return_reference_details(filters) + ref = get_return_doclist_and_details(filters) stock_items = get_stock_items_for_return(ref.doclist, ref.parentfields) @@ -737,7 +737,7 @@ def get_stock_items_for_return(ref_doclist, parentfields): return stock_items -def get_return_reference_details(args): +def get_return_doclist_and_details(args): ref = webnotes._dict() # get ref_doclist @@ -768,7 +768,7 @@ def make_return_jv(stock_entry): if not se.doc.purpose in ["Sales Return", "Purchase Return"]: return - ref = get_return_reference_details(se.doc.fields) + ref = get_return_doclist_and_details(se.doc.fields) if ref.doclist[0].doctype == "Delivery Note": result = make_return_jv_from_delivery_note(se, ref) @@ -794,8 +794,6 @@ def make_return_jv(stock_entry): "doctype": "Journal Voucher Detail", "parentfield": "entries", "account": r.get("account"), - "debit": r.get("debit"), - "credit": r.get("credit"), "against_invoice": r.get("against_invoice"), "against_voucher": r.get("against_voucher"), "balance": get_balance_on(r.get("account"), se.doc.posting_date) @@ -807,42 +805,32 @@ def make_return_jv_from_sales_invoice(se, ref): # customer account entry parent = { "account": ref.doclist[0].debit_to, - "credit": 0.0, "against_invoice": ref.doclist[0].name, } # income account entries - children = {} + children = [] for se_item in se.doclist.get({"parentfield": "mtn_details"}): # find item in ref.doclist ref_item = ref.doclist.getone({"item_code": se_item.item_code}) - account, debit = get_sales_account_and_amount_from_item(ref.doclist, ref_item, - se_item.transfer_qty) + account = get_sales_account_from_item(ref.doclist, ref_item) if account not in children: - children[account] = 0 - children[account] += debit - parent["credit"] += debit + children.append(account) - # find tax account and value and add corresponding rows + return [parent] + [{"account": account} for account in children] - return [parent] + [{"account": account, "debit": debit} for account, debit in children.items()] - -def get_sales_account_and_amount_from_item(doclist, ref_item, transfer_qty): - account = debit = None +def get_sales_account_from_item(doclist, ref_item): + account = None if not ref_item.income_account: if ref_item.parent_item: parent_item = doclist.getone({"item_code": ref_item.parent_item}) - packing_ratio = parent_item.qty / ref_item.qty - - debit = parent_item.basic_rate * transfer_qty * packing_ratio account = parent_item.income_account else: - debit = ref_item.basic_rate * transfer_qty account = ref_item.income_account - return account, debit + return account def make_return_jv_from_delivery_note(se, ref): invoices_against_delivery = get_invoice_list("Sales Invoice Item", "delivery_note", @@ -854,11 +842,14 @@ def make_return_jv_from_delivery_note(se, ref): invoices_against_delivery = get_invoice_list("Sales Invoice Item", "sales_order", sales_orders_against_delivery) + + if not invoices_against_delivery: + return [] - against_invoice = {} + parent = {} + children = [] for se_item in se.doclist.get({"parentfield": "mtn_details"}): - pending = se_item.transfer_qty for sales_invoice in invoices_against_delivery: si = webnotes.bean("Sales Invoice", sales_invoice) si.run_method("make_packing_list") @@ -866,44 +857,24 @@ def make_return_jv_from_delivery_note(se, ref): if not ref_item: continue - + ref_item = ref_item[0] - if ref_item.qty < pending: - transfer_qty = ref_item.qty - pending -= ref_item.qty - else: - transfer_qty = pending - pending = 0 + account = get_sales_account_from_item(si.doclist, ref_item) - account, debit = get_sales_account_and_amount_from_item(si.doclist, ref_item, - transfer_qty) - - if si.doclist[0].name not in against_invoice: - against_invoice[sales_invoice] = { - "parent": {"account": si.doclist[0].debit_to, "credit": 0}, - "children": {} - } - - against_invoice[sales_invoice]["parent"]["credit"] += debit + if account not in children: + children.append(account) - if account not in against_invoice[sales_invoice]["children"]: - against_invoice[sales_invoice]["children"][account] = 0 + if not parent: + parent = {"account": si.doc.debit_to} + + break - against_invoice[sales_invoice]["children"][account] += debit - - # find tax account and value and add corresponding rows - - if pending <= 0: - break + if len(invoices_against_delivery) == 1: + parent["against_invoice"] = invoices_against_delivery[0] + + result = [parent] + [{"account": account} for account in children] - result = [] - for sales_invoice, opts in against_invoice.items(): - parent = opts["parent"] - parent.update({"against_invoice": sales_invoice}) - children = [{"account": account, "debit": debit} - for account, debit in opts["children"].items()] - result += [parent] + children return result def get_invoice_list(doctype, link_field, value): @@ -925,53 +896,36 @@ def make_return_jv_from_purchase_receipt(se, ref): invoice_against_receipt = get_invoice_list("Purchase Invoice Item", "purchase_order", purchase_orders_against_receipt) - against_voucher = {} + if not invoice_against_receipt: + return [] + + parent = {} + children = [] for se_item in se.doclist.get({"parentfield": "mtn_details"}): - pending = se_item.transfer_qty for purchase_invoice in invoice_against_receipt: pi = webnotes.bean("Purchase Invoice", purchase_invoice) ref_item = pi.doclist.get({"item_code": se_item.item_code}) if not ref_item: continue - + ref_item = ref_item[0] - if ref_item.qty < pending: - transfer_qty = ref_item.qty - pending -= ref_item.qty - else: - transfer_qty = pending - pending = 0 - - credit = ref_item.rate * transfer_qty account = ref_item.expense_head - if pi.doclist[0].name not in against_voucher: - against_voucher[purchase_invoice] = { - "parent": {"account": pi.doclist[0].credit_to, "debit": 0}, - "children": {} - } + if account not in children: + children.append(account) - against_voucher[purchase_invoice]["parent"]["debit"] += credit + if not parent: + parent = {"account": pi.doc.credit_to} - if account not in against_voucher[purchase_invoice]["children"]: - against_voucher[purchase_invoice]["children"][account] = 0 - - against_voucher[purchase_invoice]["children"][account] += credit + break - # find tax account and value and add corresponding rows - - if pending <= 0: - break + if len(invoice_against_receipt) == 1: + parent["against_voucher"] = invoice_against_receipt[0] + + result = [parent] + [{"account": account} for account in children] - result = [] - for purchase_invoice, opts in against_voucher.items(): - parent = opts["parent"] - parent.update({"against_voucher": purchase_invoice}) - children = [{"account": account, "credit": credit} - for account, credit in opts["children"].items()] - result += [parent] + children return result \ No newline at end of file diff --git a/stock/doctype/stock_entry/test_stock_entry.py b/stock/doctype/stock_entry/test_stock_entry.py index 049b0e66c8..322fcfac26 100644 --- a/stock/doctype/stock_entry/test_stock_entry.py +++ b/stock/doctype/stock_entry/test_stock_entry.py @@ -309,7 +309,7 @@ class TestStockEntry(unittest.TestCase): def test_delivery_note_return_of_packing_item(self): self._test_delivery_note_return("_Test Sales BOM Item", 25, 20) - def _test_sales_return_jv(self, se, returned_value): + def _test_sales_return_jv(self, se): from stock.doctype.stock_entry.stock_entry import make_return_jv jv_list = make_return_jv(se.doc.name) @@ -320,35 +320,27 @@ class TestStockEntry(unittest.TestCase): self.assertEqual(jv_list[2].get("account"), "Sales - _TC") self.assertTrue(jv_list[1].get("against_invoice")) - # debit == credit - debit = sum([flt(d.get("debit")) for d in jv_list]) - credit = sum([flt(d.get("credit")) for d in jv_list]) - self.assertEqual(debit, credit) - - # validate value of debit - self.assertEqual(debit, returned_value) - def test_make_return_jv_for_sales_invoice_non_packing_item(self): se = self._test_sales_invoice_return("_Test Item", 5, 2) - self._test_sales_return_jv(se, 1000) + self._test_sales_return_jv(se) def test_make_return_jv_for_sales_invoice_packing_item(self): se = self._test_sales_invoice_return("_Test Sales BOM Item", 25, 20) - self._test_sales_return_jv(se, 2000) + self._test_sales_return_jv(se) def test_make_return_jv_for_delivery_note_non_packing_item(self): se = self._test_delivery_note_return("_Test Item", 5, 2) - self._test_sales_return_jv(se, 200) + self._test_sales_return_jv(se) se = self._test_delivery_note_return_against_sales_order("_Test Item", 5, 2) - self._test_sales_return_jv(se, 200) + self._test_sales_return_jv(se) def test_make_return_jv_for_delivery_note_packing_item(self): se = self._test_delivery_note_return("_Test Sales BOM Item", 25, 20) - self._test_sales_return_jv(se, 400) + self._test_sales_return_jv(se) se = self._test_delivery_note_return_against_sales_order("_Test Sales BOM Item", 25, 20) - self._test_sales_return_jv(se, 400) + self._test_sales_return_jv(se) def _test_delivery_note_return_against_sales_order(self, item_code, delivered_qty, returned_qty): self._insert_material_receipt() @@ -477,7 +469,7 @@ class TestStockEntry(unittest.TestCase): self.assertRaises(StockOverReturnError, se.insert) - def _test_purchase_return_jv(self, se, returned_value): + def _test_purchase_return_jv(self, se): from stock.doctype.stock_entry.stock_entry import make_return_jv jv_list = make_return_jv(se.doc.name) @@ -488,20 +480,12 @@ class TestStockEntry(unittest.TestCase): self.assertEqual(jv_list[2].get("account"), "_Test Account Cost for Goods Sold - _TC") self.assertTrue(jv_list[1].get("against_voucher")) - # debit == credit - debit = sum([flt(d.get("debit")) for d in jv_list]) - credit = sum([flt(d.get("credit")) for d in jv_list]) - self.assertEqual(debit, credit) - - # validate value of credit - self.assertEqual(credit, returned_value) - def test_make_return_jv_for_purchase_receipt(self): se, pr_name = self.test_purchase_receipt_return() - self._test_purchase_return_jv(se, 250) + self._test_purchase_return_jv(se) se, pr_name = self._test_purchase_return_return_against_purchase_order() - self._test_purchase_return_jv(se, 250) + self._test_purchase_return_jv(se) def _test_purchase_return_return_against_purchase_order(self): self._clear_stock() From 688b52e14b1554106c34665b4e0c79df5598ca5c Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Tue, 19 Mar 2013 13:35:40 +0530 Subject: [PATCH 17/30] increase width of taxes table in print format --- .../sales_taxes_and_charges_master.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/accounts/doctype/sales_taxes_and_charges_master/sales_taxes_and_charges_master.js b/accounts/doctype/sales_taxes_and_charges_master/sales_taxes_and_charges_master.js index 7d441abd78..b1cbbdcbfc 100644 --- a/accounts/doctype/sales_taxes_and_charges_master/sales_taxes_and_charges_master.js +++ b/accounts/doctype/sales_taxes_and_charges_master/sales_taxes_and_charges_master.js @@ -45,8 +45,7 @@ cur_frm.pformat.other_charges= function(doc){ var make_row = function(title,val,bold){ var bstart = ''; var bend = ''; return ''+(bold?bstart:'')+title+(bold?bend:'')+'' - +'' - +''+format_currency(val, doc.currency)+'' + +''+format_currency(val, doc.currency)+'' +'' } From af6f1ba82ecae66da1fd9b5a81cdb554fd5a778f Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Tue, 19 Mar 2013 13:43:49 +0530 Subject: [PATCH 18/30] fixes in sales purchase return for stock entry --- stock/doctype/stock_entry/stock_entry.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/stock/doctype/stock_entry/stock_entry.py b/stock/doctype/stock_entry/stock_entry.py index edaf63b4e1..37d55d90cb 100644 --- a/stock/doctype/stock_entry/stock_entry.py +++ b/stock/doctype/stock_entry/stock_entry.py @@ -840,8 +840,9 @@ def make_return_jv_from_delivery_note(se, ref): sales_orders_against_delivery = [d.prevdoc_docname for d in ref.doclist.get({"prevdoc_doctype": "Sales Order"}) if d.prevdoc_docname] - invoices_against_delivery = get_invoice_list("Sales Invoice Item", "sales_order", - sales_orders_against_delivery) + if sales_orders_against_delivery: + invoices_against_delivery = get_invoice_list("Sales Invoice Item", "sales_order", + sales_orders_against_delivery) if not invoices_against_delivery: return [] @@ -893,8 +894,9 @@ def make_return_jv_from_purchase_receipt(se, ref): purchase_orders_against_receipt = [d.prevdoc_docname for d in ref.doclist.get({"prevdoc_doctype": "Purchase Order"}) if d.prevdoc_docname] - invoice_against_receipt = get_invoice_list("Purchase Invoice Item", "purchase_order", - purchase_orders_against_receipt) + if purchase_orders_against_receipt: + invoice_against_receipt = get_invoice_list("Purchase Invoice Item", "purchase_order", + purchase_orders_against_receipt) if not invoice_against_receipt: return [] From f6b06a6b3091190f9e4c0929899dfec447ea08c2 Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Tue, 19 Mar 2013 15:01:07 +0530 Subject: [PATCH 19/30] fixes in sales purchase return --- stock/doctype/stock_entry/stock_entry.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/stock/doctype/stock_entry/stock_entry.py b/stock/doctype/stock_entry/stock_entry.py index 37d55d90cb..5b90c625a5 100644 --- a/stock/doctype/stock_entry/stock_entry.py +++ b/stock/doctype/stock_entry/stock_entry.py @@ -789,6 +789,8 @@ def make_return_jv(stock_entry): from accounts.utils import get_balance_on for r in result: + if not r.get("account"): + print result jv_list.append({ "__islocal": 1, "doctype": "Journal Voucher Detail", @@ -846,6 +848,9 @@ def make_return_jv_from_delivery_note(se, ref): if not invoices_against_delivery: return [] + + packing_item_parent_map = dict([[d.item_code, d.parent_item] for d in ref.doclist.get( + {"parentfield": ref.parentfields[1]})]) parent = {} children = [] @@ -853,8 +858,11 @@ def make_return_jv_from_delivery_note(se, ref): for se_item in se.doclist.get({"parentfield": "mtn_details"}): for sales_invoice in invoices_against_delivery: si = webnotes.bean("Sales Invoice", sales_invoice) - si.run_method("make_packing_list") - ref_item = si.doclist.get({"item_code": se_item.item_code}) + + if se_item.item_code in packing_item_parent_map: + ref_item = si.doclist.get({"item_code": packing_item_parent_map[se_item.item_code]}) + else: + ref_item = si.doclist.get({"item_code": se_item.item_code}) if not ref_item: continue From 73091ecac3cbc49343885c5b6557008ee81f6c78 Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Tue, 19 Mar 2013 15:15:12 +0530 Subject: [PATCH 20/30] shifted return reference fields in stock entry to the main section --- stock/doctype/stock_entry/stock_entry.txt | 98 +++++++++++------------ 1 file changed, 49 insertions(+), 49 deletions(-) diff --git a/stock/doctype/stock_entry/stock_entry.txt b/stock/doctype/stock_entry/stock_entry.txt index 2554455764..4509f3ddab 100644 --- a/stock/doctype/stock_entry/stock_entry.txt +++ b/stock/doctype/stock_entry/stock_entry.txt @@ -1,8 +1,8 @@ [ { - "creation": "2013-01-23 19:57:20", + "creation": "2013-03-11 12:34:40", "docstatus": 0, - "modified": "2013-01-28 17:59:20", + "modified": "2013-03-19 15:13:07", "modified_by": "Administrator", "owner": "Administrator" }, @@ -99,6 +99,53 @@ "reqd": 1, "search_index": 0 }, + { + "allow_on_submit": 0, + "depends_on": "eval:doc.purpose==\"Sales Return\"", + "doctype": "DocField", + "fieldname": "delivery_note_no", + "fieldtype": "Link", + "hidden": 1, + "in_filter": 0, + "label": "Delivery Note No", + "no_copy": 1, + "oldfieldname": "delivery_note_no", + "oldfieldtype": "Link", + "options": "Delivery Note", + "print_hide": 1, + "report_hide": 0, + "reqd": 0, + "search_index": 1 + }, + { + "depends_on": "eval:doc.purpose==\"Sales Return\"", + "doctype": "DocField", + "fieldname": "sales_invoice_no", + "fieldtype": "Link", + "hidden": 1, + "label": "Sales Invoice No", + "no_copy": 1, + "options": "Sales Invoice", + "print_hide": 1 + }, + { + "allow_on_submit": 0, + "depends_on": "eval:doc.purpose==\"Purchase Return\"", + "doctype": "DocField", + "fieldname": "purchase_receipt_no", + "fieldtype": "Link", + "hidden": 1, + "in_filter": 0, + "label": "Purchase Receipt No", + "no_copy": 1, + "oldfieldname": "purchase_receipt_no", + "oldfieldtype": "Link", + "options": "Purchase Receipt", + "print_hide": 1, + "report_hide": 0, + "reqd": 0, + "search_index": 1 + }, { "doctype": "DocField", "fieldname": "col2", @@ -273,42 +320,6 @@ "reqd": 0, "search_index": 0 }, - { - "allow_on_submit": 0, - "depends_on": "eval:doc.purpose==\"Sales Return\"", - "doctype": "DocField", - "fieldname": "delivery_note_no", - "fieldtype": "Link", - "hidden": 1, - "in_filter": 0, - "label": "Delivery Note No", - "no_copy": 1, - "oldfieldname": "delivery_note_no", - "oldfieldtype": "Link", - "options": "Delivery Note", - "print_hide": 1, - "report_hide": 0, - "reqd": 0, - "search_index": 1 - }, - { - "allow_on_submit": 0, - "depends_on": "eval:doc.purpose==\"Purchase Return\"", - "doctype": "DocField", - "fieldname": "purchase_receipt_no", - "fieldtype": "Link", - "hidden": 1, - "in_filter": 0, - "label": "Purchase Receipt No", - "no_copy": 1, - "oldfieldname": "purchase_receipt_no", - "oldfieldtype": "Link", - "options": "Purchase Receipt", - "print_hide": 1, - "report_hide": 0, - "reqd": 0, - "search_index": 1 - }, { "doctype": "DocField", "fieldname": "cb1", @@ -339,17 +350,6 @@ "reqd": 0, "search_index": 0 }, - { - "depends_on": "eval:doc.purpose==\"Sales Return\"", - "doctype": "DocField", - "fieldname": "sales_invoice_no", - "fieldtype": "Link", - "hidden": 1, - "label": "Sales Invoice No", - "no_copy": 1, - "options": "Sales Invoice", - "print_hide": 1 - }, { "depends_on": "eval:(doc.purpose==\"Sales Return\" || doc.purpose==\"Purchase Return\")", "doctype": "DocField", From 3e967ab9b6ff26ddb89cebb546e5f28daae35d3a Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Tue, 19 Mar 2013 16:22:22 +0530 Subject: [PATCH 21/30] hide Reference section break when using Sales or Purchase Return --- stock/doctype/stock_entry/stock_entry.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/stock/doctype/stock_entry/stock_entry.txt b/stock/doctype/stock_entry/stock_entry.txt index 4509f3ddab..ecbd9c6b72 100644 --- a/stock/doctype/stock_entry/stock_entry.txt +++ b/stock/doctype/stock_entry/stock_entry.txt @@ -2,7 +2,7 @@ { "creation": "2013-03-11 12:34:40", "docstatus": 0, - "modified": "2013-03-19 15:13:07", + "modified": "2013-03-19 15:33:14", "modified_by": "Administrator", "owner": "Administrator" }, @@ -271,6 +271,7 @@ "print_hide": 1 }, { + "depends_on": "eval:doc.purpose!==\"Sales Return\" || doc.purpose!===\"Purchase Return\"", "doctype": "DocField", "fieldname": "sb1", "fieldtype": "Section Break", From a2b3eb17e3abe2c9391161a757ee0d82622a4c87 Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Tue, 19 Mar 2013 17:48:50 +0530 Subject: [PATCH 22/30] fix in depends on of stock entry --- stock/doctype/stock_entry/stock_entry.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stock/doctype/stock_entry/stock_entry.txt b/stock/doctype/stock_entry/stock_entry.txt index ecbd9c6b72..af703989cc 100644 --- a/stock/doctype/stock_entry/stock_entry.txt +++ b/stock/doctype/stock_entry/stock_entry.txt @@ -2,7 +2,7 @@ { "creation": "2013-03-11 12:34:40", "docstatus": 0, - "modified": "2013-03-19 15:33:14", + "modified": "2013-03-19 17:48:29", "modified_by": "Administrator", "owner": "Administrator" }, @@ -271,7 +271,7 @@ "print_hide": 1 }, { - "depends_on": "eval:doc.purpose!==\"Sales Return\" || doc.purpose!===\"Purchase Return\"", + "depends_on": "eval:(doc.purpose!==\"Sales Return\" || doc.purpose!==\"Purchase Return\")", "doctype": "DocField", "fieldname": "sb1", "fieldtype": "Section Break", From 80abad2ee0c29eacb2796761da76e0943e549909 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Tue, 19 Mar 2013 18:18:52 +0530 Subject: [PATCH 23/30] aii: default account from company --- .../purchase_invoice/purchase_invoice.py | 7 ++- .../doctype/sales_invoice/sales_invoice.py | 7 +-- controllers/accounts_controller.py | 25 +++++---- controllers/stock_controller.py | 2 +- setup/doctype/company/company.py | 5 ++ setup/doctype/company/company.txt | 9 +++- .../global_defaults/global_defaults.txt | 6 +-- stock/doctype/delivery_note/delivery_note.py | 16 +++--- .../purchase_receipt/purchase_receipt.py | 2 +- stock/doctype/stock_entry/stock_entry.js | 50 +++++++++++++++--- .../stock_reconciliation.js | 51 ++++++++++++++----- 11 files changed, 130 insertions(+), 50 deletions(-) diff --git a/accounts/doctype/purchase_invoice/purchase_invoice.py b/accounts/doctype/purchase_invoice/purchase_invoice.py index 7722c98a07..b56e2ace10 100644 --- a/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -444,6 +444,9 @@ class DocType(BuyingController): # item gl entries stock_item_and_auto_inventory_accounting = False + if auto_inventory_accounting: + stock_acocunt = self.get_default_account("stock_received_but_not_billed") + for item in self.doclist.get({"parentfield": "entries"}): if auto_inventory_accounting and item.item_code in self.stock_items: if flt(item.valuation_rate): @@ -455,7 +458,7 @@ class DocType(BuyingController): gl_entries.append( self.get_gl_dict({ - "account": "Stock Received But Not Billed - %s" % (self.company_abbr,), + "account": stock_acocunt, "against": self.doc.credit_to, "debit": flt(item.valuation_rate) * flt(item.conversion_factor) \ * flt(item.qty), @@ -480,7 +483,7 @@ class DocType(BuyingController): # this will balance out valuation amount included in cost of goods sold gl_entries.append( self.get_gl_dict({ - "account": "Expenses Included In Valuation - %s" % (self.company_abbr,), + "account": self.get_default_account("expenses_included_in_valuation"), "cost_center": "Auto Inventory Accounting - %s" % self.company_abbr, "against": self.doc.credit_to, "credit": valuation_tax, diff --git a/accounts/doctype/sales_invoice/sales_invoice.py b/accounts/doctype/sales_invoice/sales_invoice.py index b6b1f0ba10..f81a71b1a4 100644 --- a/accounts/doctype/sales_invoice/sales_invoice.py +++ b/accounts/doctype/sales_invoice/sales_invoice.py @@ -704,9 +704,9 @@ class DocType(SellingController): if auto_inventory_accounting: if cint(self.doc.is_pos) and cint(self.doc.update_stock): - stock_account = self.get_stock_in_hand_account() + stock_account = self.get_default_account("stock_in_hand_account") else: - stock_account = "Stock Delivered But Not Billed - %s" % (self.company_abbr,) + stock_account = self.get_default_account("stock_delivered_but_not_billed") for item in self.doclist.get({"parentfield": "entries"}): # income account gl entries @@ -794,7 +794,8 @@ class DocType(SellingController): stock_ledger_entries = item_sales_bom = None for item in self.doclist.get({"parentfield": "entries"}): - if item.item_code in self.stock_items: + if item.item_code in self.stock_items or \ + (item_sales_bom and item_sales_bom.get(item.item_code)): item.buying_amount = self.get_item_buying_amount(item, stock_ledger_entries, item_sales_bom) webnotes.conn.set_value("Sales Invoice Item", item.name, diff --git a/controllers/accounts_controller.py b/controllers/accounts_controller.py index 66a5d9e09e..df78212cd1 100644 --- a/controllers/accounts_controller.py +++ b/controllers/accounts_controller.py @@ -71,15 +71,15 @@ class AccountsController(TransactionBase): "advance_amount": flt(d.amount), "allocate_amount": 0 }) - - def get_stock_in_hand_account(self): - stock_in_hand_account = webnotes.conn.get_value("Company", self.doc.company, "stock_in_hand_account") - if not stock_in_hand_account: - msgprint(_("Missing") + ": " - + _(webnotes.get_doctype("company").get_label("stock_in_hand_account") - + " " + _("for Company") + " " + self.doc.company), raise_exception=True) - return stock_in_hand_account + def get_default_account(self, account_for): + account = webnotes.conn.get_value("Company", self.doc.company, account_for) + if not account: + msgprint(_("Please mention default account for '") + + _(webnotes.get_doctype("company").get_label(account_for) + + _("' in Company: ") + self.doc.company), raise_exception=True) + + return account @property def stock_items(self): @@ -88,7 +88,7 @@ class AccountsController(TransactionBase): self._stock_items = [r[0] for r in webnotes.conn.sql("""select name from `tabItem` where name in (%s) and is_stock_item='Yes'""" % \ (", ".join((["%s"]*len(item_codes))),), item_codes)] - + return self._stock_items @property @@ -96,4 +96,9 @@ class AccountsController(TransactionBase): if not hasattr(self, "_abbr"): self._abbr = webnotes.conn.get_value("Company", self.doc.company, "abbr") - return self._abbr \ No newline at end of file + return self._abbr + + +@webnotes.whitelist() +def get_default_account(account_for, company): + return webnotes.conn.get_value("Company", company, account_for) \ No newline at end of file diff --git a/controllers/stock_controller.py b/controllers/stock_controller.py index 3a900aa8be..eec7352f1a 100644 --- a/controllers/stock_controller.py +++ b/controllers/stock_controller.py @@ -20,7 +20,7 @@ from controllers.accounts_controller import AccountsController class StockController(AccountsController): def make_gl_entries(self, against_stock_account, amount, cost_center=None): - stock_in_hand_account = self.get_stock_in_hand_account() + stock_in_hand_account = self.get_default_account("stock_in_hand_account") if amount: gl_entries = [ diff --git a/setup/doctype/company/company.py b/setup/doctype/company/company.py index 6ba7985d6d..15241a2ba6 100644 --- a/setup/doctype/company/company.py +++ b/setup/doctype/company/company.py @@ -214,6 +214,11 @@ class DocType: "Stock Adjustment - " + self.doc.abbr): webnotes.conn.set(self.doc, "stock_adjustment_account", "Stock Adjustment - " + self.doc.abbr) + + if not self.doc.expenses_included_in_valuation and webnotes.conn.exists("Account", + "Expenses Included In Valuation - " + self.doc.abbr): + webnotes.conn.set(self.doc, "expenses_included_in_valuation", + "Expenses Included In Valuation - " + self.doc.abbr) # Create default cost center # --------------------------------------------------- diff --git a/setup/doctype/company/company.txt b/setup/doctype/company/company.txt index d8c649ff28..4d2dcdae68 100644 --- a/setup/doctype/company/company.txt +++ b/setup/doctype/company/company.txt @@ -2,7 +2,7 @@ { "creation": "2013-02-27 09:38:05", "docstatus": 0, - "modified": "2013-03-18 16:34:04", + "modified": "2013-03-19 12:52:00", "modified_by": "Administrator", "owner": "Administrator" }, @@ -194,6 +194,13 @@ "label": "Stock Adjustment Account", "options": "Account" }, + { + "doctype": "DocField", + "fieldname": "expenses_included_in_valuation", + "fieldtype": "Link", + "label": "Expenses Included In Valuation", + "options": "Account" + }, { "doctype": "DocField", "fieldname": "col_break23", diff --git a/setup/doctype/global_defaults/global_defaults.txt b/setup/doctype/global_defaults/global_defaults.txt index 960da7e231..d75f1efe88 100644 --- a/setup/doctype/global_defaults/global_defaults.txt +++ b/setup/doctype/global_defaults/global_defaults.txt @@ -1,8 +1,8 @@ [ { - "creation": "2013-02-19 12:28:27", + "creation": "2013-02-21 14:54:43", "docstatus": 0, - "modified": "2013-02-20 14:09:00", + "modified": "2013-03-19 14:46:49", "modified_by": "Administrator", "owner": "Administrator" }, @@ -403,7 +403,7 @@ "fieldname": "emp_created_by", "fieldtype": "Select", "label": "Employee Records to be created by ", - "options": "\nNaming Series\nEmployee Number" + "options": "Naming Series\nEmployee Number" }, { "doctype": "DocField", diff --git a/stock/doctype/delivery_note/delivery_note.py b/stock/doctype/delivery_note/delivery_note.py index aef79390c2..62d5c5f8b2 100644 --- a/stock/doctype/delivery_note/delivery_note.py +++ b/stock/doctype/delivery_note/delivery_note.py @@ -400,12 +400,14 @@ class DocType(SellingController): if stock_ledger_entries: for item in self.doclist.get({"parentfield": "delivery_note_details"}): - buying_amount = get_buying_amount(item.item_code, item.warehouse, -1*item.qty, - self.doc.doctype, self.doc.name, item.name, stock_ledger_entries, - item_sales_bom) - item.buying_amount = buying_amount > 0 and buying_amount or 0 - webnotes.conn.set_value("Delivery Note Item", item.name, "buying_amount", - item.buying_amount) + if item.item_code in self.stock_items or \ + (item_sales_bom and item_sales_bom.get(item.item_code)): + buying_amount = get_buying_amount(item.item_code, item.warehouse, -1*item.qty, + self.doc.doctype, self.doc.name, item.name, stock_ledger_entries, + item_sales_bom) + item.buying_amount = buying_amount > 0 and buying_amount or 0 + webnotes.conn.set_value("Delivery Note Item", item.name, "buying_amount", + item.buying_amount) self.validate_warehouse() @@ -420,7 +422,7 @@ class DocType(SellingController): if not cint(webnotes.defaults.get_global_default("auto_inventory_accounting")): return - against_stock_account = "Stock Delivered But Not Billed - %s" % (self.company_abbr,) + against_stock_account = self.get_default_account("stock_delivered_but_not_billed") total_buying_amount = self.get_total_buying_amount() super(DocType, self).make_gl_entries(against_stock_account, -1*total_buying_amount) diff --git a/stock/doctype/purchase_receipt/purchase_receipt.py b/stock/doctype/purchase_receipt/purchase_receipt.py index e26c0a6d1e..e7d030d719 100644 --- a/stock/doctype/purchase_receipt/purchase_receipt.py +++ b/stock/doctype/purchase_receipt/purchase_receipt.py @@ -318,7 +318,7 @@ class DocType(BuyingController): if not cint(webnotes.defaults.get_global_default("auto_inventory_accounting")): return - against_stock_account = "Stock Received But Not Billed - %s" % (self.company_abbr,) + against_stock_account = self.get_default_account("stock_received_but_not_billed") total_valuation_amount = self.get_total_valuation_amount() super(DocType, self).make_gl_entries(against_stock_account, total_valuation_amount) diff --git a/stock/doctype/stock_entry/stock_entry.js b/stock/doctype/stock_entry/stock_entry.js index 0a75914a62..2eb538c53d 100644 --- a/stock/doctype/stock_entry/stock_entry.js +++ b/stock/doctype/stock_entry/stock_entry.js @@ -18,6 +18,47 @@ wn.require("public/app/js/controllers/stock_controller.js"); wn.provide("erpnext.stock"); erpnext.stock.StockEntry = erpnext.stock.StockController.extend({ + onload: function() { + this.set_default_account(); + }, + + set_default_account: function() { + var me = this; + + if (sys_defaults.auto_inventory_accounting && !this.frm.doc.expense_adjustment_account) { + if (this.frm.doc.purpose == "Sales Return") + account_for = "stock_delivered_but_not_billed"; + else if (this.frm.doc.purpose == "Purchase Return") + account_for = "stock_received_but_not_billed"; + else account_for = "stock_adjustment_account"; + + this.frm.call({ + method: "controllers.accounts_controller.get_default_account", + args: { + "account_for": account_for, + "company": this.frm.doc.company + }, + callback: function(r) { + if (!r.exc) me.frm.set_value("expense_adjustment_account", r.message); + } + }); + } + }, + + setup: function() { + var me = this; + if (sys_defaults.auto_inventory_accounting) { + this.frm.add_fetch("company", "expense_adjustment_account", "stock_adjustment_account"); + + this.frm.fields_dict["expense_adjustment_account"].get_query = function() { + return { + "query": "accounts.utils.get_account_list", + "filters": { "company": me.frm.doc.company } + } + } + } + }, + onload_post_render: function() { if(this.frm.doc.__islocal && (this.frm.doc.production_order || this.frm.doc.bom_no) && !getchildren('Stock Entry Detail', this.frm.doc.name, 'mtn_details').length) { @@ -234,11 +275,4 @@ cur_frm.cscript.validate_items = function(doc) { cur_frm.fields_dict.customer.get_query = erpnext.utils.customer_query; -cur_frm.fields_dict.supplier.get_query = erpnext.utils.supplier_query; - -cur_frm.fields_dict["expense_adjustment_account"].get_query = function(doc) { - return { - "query": "accounts.utils.get_account_list", - "filters": { "company": doc.company } - } -} \ No newline at end of file +cur_frm.fields_dict.supplier.get_query = erpnext.utils.supplier_query; \ No newline at end of file diff --git a/stock/doctype/stock_reconciliation/stock_reconciliation.js b/stock/doctype/stock_reconciliation/stock_reconciliation.js index fb4053ca9e..372166eaac 100644 --- a/stock/doctype/stock_reconciliation/stock_reconciliation.js +++ b/stock/doctype/stock_reconciliation/stock_reconciliation.js @@ -18,10 +18,44 @@ wn.require("public/app/js/controllers/stock_controller.js"); wn.provide("erpnext.stock"); erpnext.stock.StockReconciliation = erpnext.stock.StockController.extend({ - setup: function() { - this.frm.add_fetch("company", "stock_adjustment_account", "expense_account"); + onload: function() { + this.set_default_expense_account(); }, + set_default_expense_account: function() { + var me = this; + + if (sys_defaults.auto_inventory_accounting && !this.frm.doc.expense_account) { + this.frm.call({ + method: "controllers.accounts_controller.get_default_account", + args: { + "account_for": "stock_adjustment_account", + "company": this.frm.doc.company + }, + callback: function(r) { + if (!r.exc) me.frm.set_value("expense_account", r.message); + } + }); + } + }, + + setup: function() { + var me = this; + + this.frm.add_fetch("company", "expense_account", "stock_adjustment_account"); + + this.frm.fields_dict["expense_account"].get_query = function() { + return { + "query": "accounts.utils.get_account_list", + "filters": { + "is_pl_account": "Yes", + "debit_or_credit": "Debit", + "company": me.frm.doc.company + } + } + } + }, + refresh: function() { if(this.frm.doc.docstatus===0) { this.show_download_template(); @@ -126,15 +160,4 @@ erpnext.stock.StockReconciliation = erpnext.stock.StockController.extend({ }, }); -cur_frm.cscript = new erpnext.stock.StockReconciliation({frm: cur_frm}); - -cur_frm.fields_dict["expense_account"].get_query = function(doc) { - return { - "query": "accounts.utils.get_account_list", - "filters": { - "is_pl_account": "Yes", - "debit_or_credit": "Debit", - "company": doc.company - } - } -} \ No newline at end of file +cur_frm.cscript = new erpnext.stock.StockReconciliation({frm: cur_frm}); \ No newline at end of file From 9bddd836045d028087d2480e299e52a29003317f Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Tue, 19 Mar 2013 18:40:35 +0530 Subject: [PATCH 24/30] fix in global defaults --- setup/doctype/global_defaults/global_defaults.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup/doctype/global_defaults/global_defaults.py b/setup/doctype/global_defaults/global_defaults.py index 6f3ab4a71d..8d94a03aa5 100644 --- a/setup/doctype/global_defaults/global_defaults.py +++ b/setup/doctype/global_defaults/global_defaults.py @@ -43,6 +43,7 @@ keydict = { 'maintain_same_rate' : 'maintain_same_rate', 'session_expiry': 'session_expiry', 'disable_rounded_total': 'disable_rounded_total', + "update_stock": "update_stock", } class DocType: From e31d64ffe1ab2845aa389ffa6fafca45fefa7ddb Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Tue, 19 Mar 2013 18:42:29 +0530 Subject: [PATCH 25/30] save global defaults --- patches/patch_list.py | 1 + 1 file changed, 1 insertion(+) diff --git a/patches/patch_list.py b/patches/patch_list.py index 236ef45fd2..9c0d9b8199 100644 --- a/patches/patch_list.py +++ b/patches/patch_list.py @@ -214,4 +214,5 @@ patch_list = [ "patches.march_2013.p04_pos_update_stock_check", "patches.march_2013.p05_payment_reconciliation", "patches.march_2013.p06_remove_sales_purchase_return_tool", + "execute:webnotes.bean('Global Defaults').save()" ] \ No newline at end of file From 8803df04ccc9ed1cf39d104d75bcd4e9f41926c1 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Tue, 19 Mar 2013 18:53:00 +0530 Subject: [PATCH 26/30] aii: get_query for default account in company --- setup/doctype/company/company.js | 40 ++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/setup/doctype/company/company.js b/setup/doctype/company/company.js index a84bbc9714..a89882347e 100644 --- a/setup/doctype/company/company.js +++ b/setup/doctype/company/company.js @@ -58,3 +58,43 @@ cur_frm.fields_dict.receivables_group.get_query = function(doc) { cur_frm.fields_dict.payables_group.get_query = function(doc) { return 'SELECT `tabAccount`.name FROM `tabAccount` WHERE `tabAccount`.company = "'+doc.name+'" AND `tabAccount`.group_or_ledger = "Group" AND `tabAccount`.docstatus != 2 AND `tabAccount`.%(key)s LIKE "%s" ORDER BY `tabAccount`.name LIMIT 50'; } + + +cur_frm.fields_dict["stock_in_hand_account"].get_query = function(doc) { + return { + "query": "accounts.utils.get_account_list", + "filters": { + "is_pl_account": "No", + "debit_or_credit": "Debit", + "company": doc.name + } + } +} + +cur_frm.fields_dict["stock_adjustment_account"].get_query = function(doc) { + return { + "query": "accounts.utils.get_account_list", + "filters": { + "is_pl_account": "Yes", + "debit_or_credit": "Debit", + "company": doc.name + } + } +} + +cur_frm.fields_dict["expenses_included_in_valuation"].get_query = + cur_frm.fields_dict["stock_adjustment_account"].get_query; + +cur_frm.fields_dict["stock_delivered_but_not_billed"].get_query = + cur_frm.fields_dict["stock_in_hand_account"].get_query; + +cur_frm.fields_dict["stock_received_but_not_billed"].get_query = function(doc) { + return { + "query": "accounts.utils.get_account_list", + "filters": { + "is_pl_account": "No", + "debit_or_credit": "Credit", + "company": doc.name + } + } +} \ No newline at end of file From 6f7531813411af3dfda736f06585dff2ef00d20c Mon Sep 17 00:00:00 2001 From: Saurabh Date: Wed, 20 Mar 2013 12:55:28 +0530 Subject: [PATCH 27/30] no -ve balance accepted in sales and purchase invoice --- controllers/accounts_controller.py | 4 ++++ controllers/buying_controller.py | 5 +++-- controllers/selling_controller.py | 1 + 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/controllers/accounts_controller.py b/controllers/accounts_controller.py index 576921a530..cd40d61956 100644 --- a/controllers/accounts_controller.py +++ b/controllers/accounts_controller.py @@ -21,6 +21,10 @@ from webnotes.utils import flt from utilities.transaction_base import TransactionBase class AccountsController(TransactionBase): + def validate(self): + if self.meta.get_field("grand_total"): + self.validate_value("grand_total", ">=", 0) + def get_gl_dict(self, args, cancel=None): """this method populates the common properties of a gl entry record""" if cancel is None: diff --git a/controllers/buying_controller.py b/controllers/buying_controller.py index 2f3128c98c..0509de0074 100644 --- a/controllers/buying_controller.py +++ b/controllers/buying_controller.py @@ -27,7 +27,8 @@ from webnotes.model.utils import round_floats_in_doc from controllers.accounts_controller import AccountsController class BuyingController(AccountsController): - def validate(self): + def validate(self): + super(BuyingController, self).validate() if self.meta.get_field("currency"): self.company_currency = get_company_currency(self.doc.company) self.validate_conversion_rate("currency", "conversion_rate") @@ -37,7 +38,7 @@ class BuyingController(AccountsController): # IMPORTANT: enable this only when client side code is similar to this one # self.calculate_taxes_and_totals() - + # set total in words self.set_total_in_words() diff --git a/controllers/selling_controller.py b/controllers/selling_controller.py index 40606c3198..9db8f4acad 100644 --- a/controllers/selling_controller.py +++ b/controllers/selling_controller.py @@ -23,6 +23,7 @@ from controllers.accounts_controller import AccountsController class SellingController(AccountsController): def validate(self): + super(SellingController, self).validate() self.set_total_in_words() def set_total_in_words(self): From 9c02b81cdd02bb32b47b45f7d6821b9ef1dc930f Mon Sep 17 00:00:00 2001 From: Saurabh Date: Wed, 20 Mar 2013 13:51:43 +0530 Subject: [PATCH 28/30] merged backup dropbox file --- setup/doctype/backup_manager/backup_dropbox.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/setup/doctype/backup_manager/backup_dropbox.py b/setup/doctype/backup_manager/backup_dropbox.py index b66880305e..2c7fda6ca9 100644 --- a/setup/doctype/backup_manager/backup_dropbox.py +++ b/setup/doctype/backup_manager/backup_dropbox.py @@ -86,8 +86,6 @@ def backup_to_dropbox(): filename = os.path.join(get_base_path(), "public", "files") for filename in os.listdir(filename): found = False - pth=path1+'/'+filename - size=os.stat(pth).st_size for file_metadata in response["contents"]: if filename==os.path.basename(file_metadata["path"]): if os.stat(filename).st_size==file_metadata["bytes"]: @@ -121,4 +119,4 @@ def upload_file_to_dropbox(filename, folder, dropbox_client): response = dropbox_client.put_file(folder + "/" + os.path.basename(filename), f, overwrite=True) if __name__=="__main__": - backup_to_dropbox() + backup_to_dropbox() \ No newline at end of file From f848b8bafc07be0d5123014fff3bc8251f50010c Mon Sep 17 00:00:00 2001 From: Saurabh Date: Wed, 20 Mar 2013 13:55:08 +0530 Subject: [PATCH 29/30] merged backup manager python file --- setup/doctype/backup_manager/backup_manager.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/setup/doctype/backup_manager/backup_manager.py b/setup/doctype/backup_manager/backup_manager.py index 69de823df1..213aa85500 100644 --- a/setup/doctype/backup_manager/backup_manager.py +++ b/setup/doctype/backup_manager/backup_manager.py @@ -30,7 +30,6 @@ def take_backups_dropbox(): backup_to_dropbox() send_email(True, "Dropbox") except Exception, e: - webnotes.errprint(e) send_email(False, "Dropbox", e) #backup to gdrive @@ -56,10 +55,9 @@ def send_email(success, service_name, error_status=None): failed.

Error message: %s

Please contact your system manager for more information.

-

Detailed Error Trace: %s

""" % \ - (service_name, error_status, getTraceback().replace("\n", "
")) + """ % (service_name, error_status) # email system managers from webnotes.utils.email_lib import sendmail sendmail(webnotes.conn.get_value("Backup Manager", None, "send_notifications_to").split(","), - subject=subject, msg=message) + subject=subject, msg=message) \ No newline at end of file From 7da72dd449670590892388d43173b65c64734dc7 Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Wed, 20 Mar 2013 17:00:41 +0530 Subject: [PATCH 30/30] unlink against voucher in jv when Purchase Invoice, Sales Invoice or Journal Voucher are cancelled --- .../journal_voucher/journal_voucher.py | 3 + .../journal_voucher/test_journal_voucher.py | 85 ++++++++++++++++++- .../purchase_invoice/purchase_invoice.py | 11 +-- .../purchase_invoice/test_purchase_invoice.py | 36 ++++++++ .../purchase_invoice_advance.txt | 6 +- .../doctype/sales_invoice/sales_invoice.py | 16 ++-- .../sales_invoice/test_sales_invoice.py | 37 ++++++++ accounts/utils.py | 18 +++- 8 files changed, 185 insertions(+), 27 deletions(-) diff --git a/accounts/doctype/journal_voucher/journal_voucher.py b/accounts/doctype/journal_voucher/journal_voucher.py index 2acf08efd6..f4bd55cdbf 100644 --- a/accounts/doctype/journal_voucher/journal_voucher.py +++ b/accounts/doctype/journal_voucher/journal_voucher.py @@ -63,6 +63,9 @@ class DocType(AccountsController): self.make_gl_entries() def on_cancel(self): + from accounts.utils import remove_against_link_from_jv + remove_against_link_from_jv(self.doc.doctype, self.doc.name, "against_jv") + self.make_gl_entries(cancel=1) def validate_debit_credit(self): diff --git a/accounts/doctype/journal_voucher/test_journal_voucher.py b/accounts/doctype/journal_voucher/test_journal_voucher.py index bb846d1634..7cfeb595d8 100644 --- a/accounts/doctype/journal_voucher/test_journal_voucher.py +++ b/accounts/doctype/journal_voucher/test_journal_voucher.py @@ -19,8 +19,34 @@ from __future__ import unicode_literals import unittest import webnotes -test_records = [[ - { +class TestJournalVoucher(unittest.TestCase): + def test_journal_voucher_with_against_jv(self): + jv_invoice = webnotes.bean(copy=test_records[2]) + jv_invoice.insert() + jv_invoice.submit() + + self.assertTrue(not webnotes.conn.sql("""select name from `tabJournal Voucher Detail` + where against_jv=%s""", jv_invoice.doc.name)) + + jv_payment = webnotes.bean(copy=test_records[0]) + jv_payment.doclist[1].against_jv = jv_invoice.doc.name + jv_payment.insert() + jv_payment.submit() + + self.assertTrue(webnotes.conn.sql("""select name from `tabJournal Voucher Detail` + where against_jv=%s""", jv_invoice.doc.name)) + + self.assertTrue(webnotes.conn.sql("""select name from `tabJournal Voucher Detail` + where against_jv=%s and credit=400""", jv_invoice.doc.name)) + + # cancel jv_invoice + jv_invoice.cancel() + + self.assertTrue(not webnotes.conn.sql("""select name from `tabJournal Voucher Detail` + where against_jv=%s""", jv_invoice.doc.name)) + +test_records = [ + [{ "company": "_Test Company", "doctype": "Journal Voucher", "fiscal_year": "_Test Fiscal Year 2013", @@ -44,8 +70,59 @@ test_records = [[ "debit": 400.0, "credit": 0.0, "parentfield": "entries" - } -]] + }], + [{ + "company": "_Test Company", + "doctype": "Journal Voucher", + "fiscal_year": "_Test Fiscal Year 2013", + "naming_series": "_T-Journal Voucher-", + "posting_date": "2013-02-14", + "user_remark": "test", + "voucher_type": "Bank Voucher", + "cheque_no": "33", + "cheque_date": "2013-02-14" + }, + { + "account": "_Test Supplier - _TC", + "doctype": "Journal Voucher Detail", + "credit": 0.0, + "debit": 400.0, + "parentfield": "entries" + }, + { + "account": "_Test Account Bank Account - _TC", + "doctype": "Journal Voucher Detail", + "debit": 0.0, + "credit": 400.0, + "parentfield": "entries" + }], + [{ + "company": "_Test Company", + "doctype": "Journal Voucher", + "fiscal_year": "_Test Fiscal Year 2013", + "naming_series": "_T-Journal Voucher-", + "posting_date": "2013-02-14", + "user_remark": "test", + "voucher_type": "Bank Voucher", + "cheque_no": "33", + "cheque_date": "2013-02-14" + }, + { + "account": "_Test Customer - _TC", + "doctype": "Journal Voucher Detail", + "credit": 0.0, + "debit": 400.0, + "parentfield": "entries" + }, + { + "account": "Sales - _TC", + "doctype": "Journal Voucher Detail", + "credit": 400.0, + "debit": 0.0, + "parentfield": "entries", + "cost_center": "_Test Cost Center - _TC" + }], +] diff --git a/accounts/doctype/purchase_invoice/purchase_invoice.py b/accounts/doctype/purchase_invoice/purchase_invoice.py index b56e2ace10..f535d56e60 100644 --- a/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -507,18 +507,13 @@ class DocType(BuyingController): if gl_entries: make_gl_entries(gl_entries, cancel=is_cancel) - def check_next_docstatus(self): - submit_jv = sql("select t1.name from `tabJournal Voucher` t1,`tabJournal Voucher Detail` t2 where t1.name = t2.parent and t2.against_voucher = '%s' and t1.docstatus = 1" % (self.doc.name)) - if submit_jv: - msgprint("Journal Voucher : " + cstr(submit_jv[0][0]) + " has been created against " + cstr(self.doc.doctype) + ". So " + cstr(self.doc.doctype) + " cannot be Cancelled.") - raise Exception, "Validation Error." - def on_cancel(self): - self.check_next_docstatus() + from accounts.utils import remove_against_link_from_jv + remove_against_link_from_jv(self.doc.doctype, self.doc.name, "against_voucher") self.make_gl_entries(is_cancel=1) get_obj(dt = 'Purchase Common').update_prevdoc_detail(self, is_submit = 0) - + def on_update(self): pass diff --git a/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/accounts/doctype/purchase_invoice/test_purchase_invoice.py index b9f7ec928b..6d9cfca048 100644 --- a/accounts/doctype/purchase_invoice/test_purchase_invoice.py +++ b/accounts/doctype/purchase_invoice/test_purchase_invoice.py @@ -115,6 +115,42 @@ class TestPurchaseInvoice(unittest.TestCase): for i, item in enumerate(wrapper.doclist.get({"parentfield": "entries"})): self.assertEqual(item.item_code, expected_values[i][0]) self.assertEqual(item.item_tax_amount, expected_values[i][1]) + + def test_purchase_invoice_with_advance(self): + from accounts.doctype.journal_voucher.test_journal_voucher \ + import test_records as jv_test_records + + jv = webnotes.bean(copy=jv_test_records[1]) + jv.insert() + jv.submit() + + pi = webnotes.bean(copy=test_records[0]) + pi.doclist.append({ + "doctype": "Purchase Invoice Advance", + "parentfield": "advance_allocation_details", + "journal_voucher": jv.doc.name, + "jv_detail_no": jv.doclist[1].name, + "advance_amount": 400, + "allocated_amount": 300, + "remarks": jv.doc.remark + }) + pi.run_method("calculate_taxes_and_totals") + pi.insert() + pi.submit() + pi.load_from_db() + + self.assertTrue(webnotes.conn.sql("""select name from `tabJournal Voucher Detail` + where against_voucher=%s""", pi.doc.name)) + + self.assertTrue(webnotes.conn.sql("""select name from `tabJournal Voucher Detail` + where against_voucher=%s and debit=300""", pi.doc.name)) + + self.assertEqual(pi.doc.outstanding_amount, 1212.30) + + pi.cancel() + + self.assertTrue(not webnotes.conn.sql("""select name from `tabJournal Voucher Detail` + where against_voucher=%s""", pi.doc.name)) test_records = [ [ diff --git a/accounts/doctype/purchase_invoice_advance/purchase_invoice_advance.txt b/accounts/doctype/purchase_invoice_advance/purchase_invoice_advance.txt index 201bb53f03..6b31684029 100644 --- a/accounts/doctype/purchase_invoice_advance/purchase_invoice_advance.txt +++ b/accounts/doctype/purchase_invoice_advance/purchase_invoice_advance.txt @@ -1,8 +1,8 @@ [ { - "creation": "2013-02-22 01:27:40", + "creation": "2013-03-08 15:36:46", "docstatus": 0, - "modified": "2013-03-07 07:03:26", + "modified": "2013-03-20 16:52:12", "modified_by": "Administrator", "owner": "Administrator" }, @@ -40,7 +40,7 @@ { "doctype": "DocField", "fieldname": "jv_detail_no", - "fieldtype": "Date", + "fieldtype": "Data", "hidden": 1, "label": "Journal Voucher Detail No", "oldfieldname": "jv_detail_no", diff --git a/accounts/doctype/sales_invoice/sales_invoice.py b/accounts/doctype/sales_invoice/sales_invoice.py index 3f32a47db0..f29c2e9b6c 100644 --- a/accounts/doctype/sales_invoice/sales_invoice.py +++ b/accounts/doctype/sales_invoice/sales_invoice.py @@ -127,11 +127,14 @@ class DocType(SellingController): sales_com_obj = get_obj(dt = 'Sales Common') sales_com_obj.check_stop_sales_order(self) - self.check_next_docstatus() + + from accounts.utils import remove_against_link_from_jv + remove_against_link_from_jv(self.doc.doctype, self.doc.name, "against_invoice") + sales_com_obj.update_prevdoc_detail(0, self) self.make_gl_entries() - + def on_update_after_submit(self): self.validate_recurring_invoice() self.convert_to_recurring() @@ -399,8 +402,7 @@ class DocType(SellingController): if lst: from accounts.utils import reconcile_against_document reconcile_against_document(lst) - - + def validate_customer(self): """ Validate customer name with SO and DN""" for d in getlist(self.doclist,'entries'): @@ -830,12 +832,6 @@ class DocType(SellingController): grand_total = %s where invoice_no = %s and parent = %s""", (self.doc.name, self.doc.amended_from, self.doc.c_form_no)) - def check_next_docstatus(self): - submit_jv = webnotes.conn.sql("select t1.name from `tabJournal Voucher` t1,`tabJournal Voucher Detail` t2 where t1.name = t2.parent and t2.against_invoice = '%s' and t1.docstatus = 1" % (self.doc.name)) - if submit_jv: - msgprint("Journal Voucher : " + cstr(submit_jv[0][0]) + " has been created against " + cstr(self.doc.doctype) + ". So " + cstr(self.doc.doctype) + " cannot be Cancelled.") - raise Exception, "Validation Error." - @property def meta(self): if not hasattr(self, "_meta"): diff --git a/accounts/doctype/sales_invoice/test_sales_invoice.py b/accounts/doctype/sales_invoice/test_sales_invoice.py index 91c0622cee..b63642c643 100644 --- a/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -281,6 +281,7 @@ class TestSalesInvoice(unittest.TestCase): return dn def _insert_pos_settings(self): + webnotes.conn.sql("""delete from `tabPOS Setting`""") ps = webnotes.bean([ { "cash_bank_account": "_Test Account Bank Account - _TC", @@ -297,6 +298,42 @@ class TestSalesInvoice(unittest.TestCase): ]) ps.insert() + def test_sales_invoice_with_advance(self): + from accounts.doctype.journal_voucher.test_journal_voucher \ + import test_records as jv_test_records + + jv = webnotes.bean(copy=jv_test_records[0]) + jv.insert() + jv.submit() + + si = webnotes.bean(copy=test_records[0]) + si.doclist.append({ + "doctype": "Sales Invoice Advance", + "parentfield": "advance_adjustment_details", + "journal_voucher": jv.doc.name, + "jv_detail_no": jv.doclist[1].name, + "advance_amount": 400, + "allocated_amount": 300, + "remarks": jv.doc.remark + }) + si.insert() + si.submit() + si.load_from_db() + + self.assertTrue(webnotes.conn.sql("""select name from `tabJournal Voucher Detail` + where against_invoice=%s""", si.doc.name)) + + self.assertTrue(webnotes.conn.sql("""select name from `tabJournal Voucher Detail` + where against_invoice=%s and credit=300""", si.doc.name)) + + self.assertEqual(si.doc.outstanding_amount, 261.8) + + si.cancel() + + self.assertTrue(not webnotes.conn.sql("""select name from `tabJournal Voucher Detail` + where against_invoice=%s""", si.doc.name)) + + test_dependencies = ["Journal Voucher", "POS Setting"] test_records = [ diff --git a/accounts/utils.py b/accounts/utils.py index 14ceb4e99e..051cdd1b24 100644 --- a/accounts/utils.py +++ b/accounts/utils.py @@ -17,7 +17,7 @@ from __future__ import unicode_literals import webnotes -from webnotes.utils import nowdate, cstr, flt +from webnotes.utils import nowdate, cstr, flt, now from webnotes.model.doc import addchild from webnotes import msgprint, _ from webnotes.utils import formatdate @@ -233,4 +233,18 @@ def get_cost_center_list(doctype, txt, searchfield, start, page_len, filters): return webnotes.conn.sql("""select name, parent_cost_center from `tabCost Center` where docstatus < 2 %s and %s like %s order by name limit %s, %s""" % (conditions, searchfield, "%s", "%s", "%s"), - tuple(filter_values + ["%%%s%%" % txt, start, page_len])) \ No newline at end of file + tuple(filter_values + ["%%%s%%" % txt, start, page_len])) + +def remove_against_link_from_jv(ref_type, ref_no, against_field): + webnotes.conn.sql("""update `tabJournal Voucher Detail` set `%s`=null, + modified=%s, modified_by=%s + where `%s`=%s and docstatus < 2""" % (against_field, "%s", "%s", against_field, "%s"), + (now(), webnotes.session.user, ref_no)) + + webnotes.conn.sql("""update `tabGL Entry` + set against_voucher_type=null, against_voucher=null, + modified=%s, modified_by=%s + where against_voucher_type=%s and against_voucher=%s + and voucher_no != ifnull(against_voucher, "") + and ifnull(is_cancelled, "No")="No" """, + (now(), webnotes.session.user, ref_type, ref_no))