diff --git a/accounts/doctype/sales_invoice/sales_invoice.js b/accounts/doctype/sales_invoice/sales_invoice.js index ca4ca9241c..0ac1b5e4e5 100644 --- a/accounts/doctype/sales_invoice/sales_invoice.js +++ b/accounts/doctype/sales_invoice/sales_invoice.js @@ -188,11 +188,18 @@ cur_frm.cscript.is_opening = function(doc, dt, dn) { // Get Items based on SO or DN Selected cur_frm.cscript.get_items = function(doc, dt, dn) { - var callback = function(r,rt) { - unhide_field(['customer_address','contact_person', 'territory','customer_group']); - cur_frm.refresh_fields(); + if(doc.delivery_note_main) { + wn.model.map_current_doc({ + method: "selling.doctype.delivery_note.delivery_note.make_sales_invoice", + source_name: cur_frm.doc.delivery_note_main, + }) + } + else if(doc.sales_order_main) { + wn.model.map_current_doc({ + method: "selling.doctype.sales_order.sales_order.make_sales_invoice", + source_name: cur_frm.doc.sales_order_main, + }) } - get_server_fields('pull_details','','',doc, dt, dn,1,callback); } diff --git a/accounts/doctype/sales_invoice/sales_invoice.py b/accounts/doctype/sales_invoice/sales_invoice.py index 59c84d4927..5ebbd0e7b0 100644 --- a/accounts/doctype/sales_invoice/sales_invoice.py +++ b/accounts/doctype/sales_invoice/sales_invoice.py @@ -293,33 +293,25 @@ class DocType(SellingController): if self.doc.debit_to: self.doc.customer = webnotes.conn.get_value('Account',self.doc.debit_to,'master_name') + + def update_accounts(self): + if not self.doc.debit_to: + self.doc.debit_to = self.get_debit_to().get("debit_to") + self.get_income_expense_account('entries') - def pull_details(self): - """Pull Details of Delivery Note or Sales Order Selected""" - if self.doc.delivery_note_main: - self.validate_prev_docname('delivery note') - self.doclist = self.doc.clear_table(self.doclist,'other_charges') - self.doclist = get_obj('DocType Mapper', 'Delivery Note-Sales Invoice').dt_map( - 'Delivery Note', 'Sales Invoice', self.doc.delivery_note_main, self.doc, - self.doclist, """[['Delivery Note', 'Sales Invoice'], - ['Delivery Note Item', 'Sales Invoice Item'], - ['Sales Taxes and Charges','Sales Taxes and Charges'], - ['Sales Team','Sales Team']]""") - self.get_income_expense_account('entries') - - elif self.doc.sales_order_main: - self.validate_prev_docname('sales order') - self.doclist = self.doc.clear_table(self.doclist,'other_charges') - get_obj('DocType Mapper', 'Sales Order-Sales Invoice').dt_map('Sales Order', - 'Sales Invoice', self.doc.sales_order_main, self.doc, self.doclist, - """[['Sales Order', 'Sales Invoice'],['Sales Order Item', 'Sales Invoice Item'], - ['Sales Taxes and Charges','Sales Taxes and Charges'], - ['Sales Team', 'Sales Team']]""") - self.get_income_expense_account('entries') - - ret = self.get_debit_to() - self.doc.debit_to = ret.get('debit_to') + def get_income_expense_account(self,doctype): + auto_inventory_accounting = cint(webnotes.defaults.get_global_default("auto_inventory_accounting")) + default_cost_center = webnotes.conn.get_value("Company", self.doc.company, "cost_center") + for d in getlist(self.doclist, doctype): + if d.item_code: + item = webnotes.conn.get_value("Item", d.item_code, ["default_income_account", + "default_sales_cost_center", "purchase_account"], as_dict=True) + d.income_account = item['default_income_account'] or "" + d.cost_center = item['default_sales_cost_center'] or default_cost_center + + if auto_inventory_accounting and cint(self.doc.update_stock): + d.expense_account = item['purchase_account'] or "" def get_barcode_details(self, barcode): return get_obj('Sales Common').get_barcode_details(barcode) @@ -345,18 +337,6 @@ class DocType(SellingController): def get_company_abbr(self): return webnotes.conn.sql("select abbr from tabCompany where name=%s", self.doc.company)[0][0] - - - def validate_prev_docname(self,doctype): - """Check whether sales order / delivery note items already pulled""" - for d in getlist(self.doclist, 'entries'): - if doctype == 'delivery note' and self.doc.delivery_note_main == d.delivery_note: - msgprint(cstr(self.doc.delivery_note_main) + " delivery note details have already been pulled.") - raise Exception , "Validation Error. Delivery note details have already been pulled." - elif doctype == 'sales order' and self.doc.sales_order_main == d.sales_order and not d.delivery_note: - msgprint(cstr(self.doc.sales_order_main) + " sales order details have already been pulled.") - raise Exception , "Validation Error. Sales order details have already been pulled." - def update_against_document_in_jv(self): """ diff --git a/selling/doctype/sales_order/sales_order.js b/selling/doctype/sales_order/sales_order.js index daedfab564..4bb2fa36e9 100644 --- a/selling/doctype/sales_order/sales_order.js +++ b/selling/doctype/sales_order/sales_order.js @@ -211,19 +211,10 @@ cur_frm.cscript['Make Delivery Note'] = function() { cur_frm.cscript['Make Sales Invoice'] = function() { - var doc = cur_frm.doc; - - n = wn.model.make_new_doc_and_get_name('Sales Invoice'); - $c('dt_map', args={ - 'docs':wn.model.compress([locals['Sales Invoice'][n]]), - 'from_doctype':doc.doctype, - 'to_doctype':'Sales Invoice', - 'from_docname':doc.name, - 'from_to_list':"[['Sales Order','Sales Invoice'],['Sales Order Item','Sales Invoice Item'],['Sales Taxes and Charges','Sales Taxes and Charges'],['Sales Team','Sales Team']]" - }, function(r,rt) { - loaddoc('Sales Invoice', n); - } - ); + wn.model.open_mapped_doc({ + method: "selling.doctype.sales_order.sales_order.make_sales_invoice", + source_name: cur_frm.doc.name + }) } diff --git a/selling/doctype/sales_order/sales_order.py b/selling/doctype/sales_order/sales_order.py index 019b699c7e..b8362b573f 100644 --- a/selling/doctype/sales_order/sales_order.py +++ b/selling/doctype/sales_order/sales_order.py @@ -84,9 +84,6 @@ class DocType(SellingController): def validate_fiscal_year(self): get_obj('Sales Common').validate_fiscal_year(self.doc.fiscal_year,self.doc.transaction_date,'Sales Order Date') - def validate_reference_value(self): - get_obj('DocType Mapper', 'Quotation-Sales Order', with_children = 1).validate_reference_value(self, self.doc.name) - def validate_mandatory(self): # validate transaction date v/s delivery date if self.doc.delivery_date: @@ -190,7 +187,6 @@ class DocType(SellingController): self.validate_mandatory() self.validate_proj_cust() self.validate_po() - #self.validate_reference_value() if self.doc.docstatus == 1: self.validate_for_items() @@ -447,3 +443,43 @@ def make_delivery_note(source_name, target_doclist=None): }, target_doclist) return [d.fields for d in doclist] + +@webnotes.whitelist() +def make_sales_invoice(source_name, target_doclist=None): + from webnotes.model.mapper import get_mapped_doclist + + def update_item(obj, target): + target.export_amount = (flt(obj.amount) - flt(obj.billed_amt))* flt(obj.export_rate)/flt(obj.basic_rate) + target.qty = obj.basic_rate and (flt(obj.amount) - flt(obj.billed_amt))/flt(obj.basic_rate) or obj.qty + target.amount = flt(obj.amount) - flt(obj.billed_amt) + + def update_accounts(source, target): + si = webnotes.bean(target) + si.run_method("update_accounts") + + doclist = get_mapped_doclist("Sales Order", source_name, { + "Sales Order": { + "doctype": "Sales Invoice", + "validation": { + "docstatus": ["=", 1] + } + }, + "Sales Order Item": { + "doctype": "Sales Invoice Item", + "field_map": { + "name": "so_detail", + "parent": "sales_order", + "reserved_warehouse": "warehouse" + }, + "postprocess": update_item, + "condition": lambda doc: doc.amount==0 or doc.billed_amt < doc.amount + }, + "Sales Taxes and Charges": { + "doctype": "Sales Taxes and Charges", + }, + "Sales Team": { + "doctype": "Sales Team", + } + }, target_doclist, update_accounts) + + return [d.fields for d in doclist] diff --git a/selling/doctype/sales_order/test_sales_order.py b/selling/doctype/sales_order/test_sales_order.py index 00af81f6d0..dd0cd44486 100644 --- a/selling/doctype/sales_order/test_sales_order.py +++ b/selling/doctype/sales_order/test_sales_order.py @@ -33,6 +33,30 @@ class TestSalesOrder(unittest.TestCase): self.assertEquals(dn[0]["doctype"], "Delivery Note") self.assertEquals(len(dn), len(sales_order.doclist)) + def test_make_sales_invoice(self): + from selling.doctype.sales_order.sales_order import make_sales_invoice + + so = webnotes.bean(copy=test_records[0]).insert() + + self.assertRaises(webnotes.ValidationError, make_sales_invoice, + so.doc.name) + + sales_order = webnotes.bean("Sales Order", so.doc.name) + sales_order.submit() + si = make_sales_invoice(so.doc.name) + + self.assertEquals(si[0]["doctype"], "Sales Invoice") + self.assertEquals(len(si), len(sales_order.doclist)) + self.assertEquals(len([d for d in si if d["doctype"]=="Sales Invoice Item"]), 1) + + si = webnotes.bean(si) + si.insert() + si.submit() + + si1 = make_sales_invoice(so.doc.name) + self.assertEquals(len([d for d in si1 if d["doctype"]=="Sales Invoice Item"]), 0) + + def create_so(self, so_doclist = None): if not so_doclist: so_doclist =test_records[0] diff --git a/stock/doctype/delivery_note/delivery_note.py b/stock/doctype/delivery_note/delivery_note.py index 38cf7bc264..8b2b55933c 100644 --- a/stock/doctype/delivery_note/delivery_note.py +++ b/stock/doctype/delivery_note/delivery_note.py @@ -111,7 +111,6 @@ class DocType(SellingController): sales_com_obj.check_stop_sales_order(self) sales_com_obj.check_active_sales_items(self) sales_com_obj.get_prevdoc_date(self) - self.validate_reference_value() self.validate_for_items() self.validate_warehouse() @@ -134,17 +133,6 @@ class DocType(SellingController): msgprint("Customer - %s does not belong to project - %s. \n\nIf you want to use project for multiple customers then please make customer details blank in project - %s."%(self.doc.customer,self.doc.project_name,self.doc.project_name)) raise Exception - - def validate_reference_value(self): - """Validate values with reference document with previous document""" - validate_ref = any([d.prevdoc_docname for d in self.doclist.get({"parentfield": self.fname}) - if d.prevdoc_doctype == "Sales Order"]) - - if validate_ref: - get_obj('DocType Mapper', 'Sales Order-Delivery Note', - with_children = 1).validate_reference_value(self, self.doc.name) - - def validate_for_items(self): check_list, chk_dupl_itm = [], [] for d in getlist(self.doclist,'delivery_note_details'): diff --git a/stock/doctype/item/item.js b/stock/doctype/item/item.js index 2cc0b07971..7a731d28ec 100644 --- a/stock/doctype/item/item.js +++ b/stock/doctype/item/item.js @@ -40,7 +40,7 @@ cur_frm.cscript.refresh = function(doc) { cur_frm.cscript.make_dashboard = function() { cur_frm.dashboard.reset(); - if(doc.__islocal) + if(cur_frm.doc.__islocal) return; } diff --git a/stock/doctype/item/test_item.py b/stock/doctype/item/test_item.py index 35cad9d211..38f1d970ec 100644 --- a/stock/doctype/item/test_item.py +++ b/stock/doctype/item/test_item.py @@ -62,7 +62,8 @@ test_records = [ "is_pro_applicable": "No", "is_sub_contracted_item": "No", "stock_uom": "_Test UOM", - "default_warehouse": "_Test Warehouse" + "default_income_account": "Sales - _TC", + "default_warehouse": "_Test Warehouse", }, { "doctype": "Item Reorder", "parentfield": "item_reorder", @@ -85,6 +86,7 @@ test_records = [ "description": "_Test Item Home Desktop 100", "item_group": "_Test Item Group Desktops", "default_warehouse": "_Test Warehouse", + "default_income_account": "Sales - _TC", "is_stock_item": "Yes", "is_asset_item": "No", "has_batch_no": "No", @@ -110,6 +112,7 @@ test_records = [ "description": "_Test Item Home Desktop 200", "item_group": "_Test Item Group Desktops", "default_warehouse": "_Test Warehouse", + "default_income_account": "Sales - _TC", "is_stock_item": "Yes", "is_asset_item": "No", "has_batch_no": "No", @@ -129,6 +132,7 @@ test_records = [ "item_name": "_Test Sales BOM Item", "description": "_Test Sales BOM Item", "item_group": "_Test Item Group Desktops", + "default_income_account": "Sales - _TC", "is_stock_item": "No", "is_asset_item": "No", "has_batch_no": "No", @@ -150,6 +154,7 @@ test_records = [ "item_group": "_Test Item Group Desktops", "is_stock_item": "Yes", "default_warehouse": "_Test Warehouse", + "default_income_account": "Sales - _TC", "is_asset_item": "No", "has_batch_no": "No", "has_serial_no": "No",