Merge branch 'master' into edge

This commit is contained in:
Anand Doshi 2013-03-22 14:16:53 +05:30
commit ceba917e86
22 changed files with 247 additions and 259 deletions

View File

@ -27,8 +27,6 @@ from webnotes.model.bean import getlist
from webnotes.model.code import get_obj from webnotes.model.code import get_obj
from webnotes import _, msgprint from webnotes import _, msgprint
from stock.utils import get_buying_amount, get_sales_bom
session = webnotes.session session = webnotes.session
month_map = {'Monthly': 1, 'Quarterly': 3, 'Half-yearly': 6, 'Yearly': 12} month_map = {'Monthly': 1, 'Quarterly': 3, 'Half-yearly': 6, 'Yearly': 12}
@ -702,18 +700,8 @@ class DocType(SellingController):
) )
def make_item_gl_entries(self, gl_entries): def make_item_gl_entries(self, gl_entries):
# item gl entries
auto_inventory_accounting = \
cint(webnotes.defaults.get_global_default("auto_inventory_accounting"))
if auto_inventory_accounting:
if cint(self.doc.is_pos) and cint(self.doc.update_stock):
stock_account = self.get_default_account("stock_in_hand_account")
else:
stock_account = self.get_default_account("stock_delivered_but_not_billed")
for item in self.doclist.get({"parentfield": "entries"}):
# income account gl entries # income account gl entries
for item in self.doclist.get({"parentfield": "entries"}):
if flt(item.amount): if flt(item.amount):
gl_entries.append( gl_entries.append(
self.get_gl_dict({ self.get_gl_dict({
@ -726,26 +714,14 @@ class DocType(SellingController):
) )
# expense account gl entries # expense account gl entries
if auto_inventory_accounting and flt(item.buying_amount): if cint(webnotes.defaults.get_global_default("auto_inventory_accounting")) \
and cint(self.doc.is_pos) and cint(self.doc.update_stock):
for item in self.doclist.get({"parentfield": "entries"}):
self.check_expense_account(item) self.check_expense_account(item)
gl_entries.append( gl_entries += self.get_gl_entries_for_stock(item.expense_account,
self.get_gl_dict({ -1*item.buying_amount, cost_center=item.cost_center)
"account": item.expense_account,
"against": stock_account,
"debit": item.buying_amount,
"remarks": self.doc.remarks or "Accounting Entry for Stock",
"cost_center": item.cost_center
})
)
gl_entries.append(
self.get_gl_dict({
"account": stock_account,
"against": item.expense_account,
"credit": item.buying_amount,
"remarks": self.doc.remarks or "Accounting Entry for Stock"
})
)
def make_pos_gl_entries(self, gl_entries): def make_pos_gl_entries(self, gl_entries):
if cint(self.doc.is_pos) and self.doc.cash_bank_account and self.doc.paid_amount: if cint(self.doc.is_pos) and self.doc.cash_bank_account and self.doc.paid_amount:
@ -790,42 +766,6 @@ class DocType(SellingController):
}) })
) )
def set_buying_amount(self):
if cint(self.doc.is_pos) and cint(self.doc.update_stock):
stock_ledger_entries = self.get_stock_ledger_entries()
item_sales_bom = get_sales_bom()
else:
stock_ledger_entries = item_sales_bom = None
for item in self.doclist.get({"parentfield": "entries"}):
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,
"buying_amount", item.buying_amount)
def get_item_buying_amount(self, item, stock_ledger_entries, item_sales_bom):
item_buying_amount = 0
if stock_ledger_entries:
# is pos and update stock
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,
["buying_amount", "qty"], as_dict=1)
item_buying_rate = flt(dn_item.buying_amount) / flt(dn_item.qty)
item_buying_amount = item_buying_rate * flt(item.qty)
return item_buying_amount
def check_expense_account(self, item):
if not item.expense_account:
msgprint(_("""Expense account is mandatory for item: """) + item.item_code,
raise_exception=1)
def update_c_form(self): def update_c_form(self):
"""Update amended id in C-form""" """Update amended id in C-form"""
if self.doc.c_form_no and self.doc.amended_from: if self.doc.c_form_no and self.doc.amended_from:

View File

@ -86,68 +86,6 @@ class TestSalesInvoice(unittest.TestCase):
self.assertEquals(gle_count[0][0], 8) self.assertEquals(gle_count[0][0], 8)
def test_sales_invoice_gl_entry_with_aii_delivery_note(self):
webnotes.conn.sql("delete from `tabStock Ledger Entry`")
webnotes.defaults.set_global_default("auto_inventory_accounting", 1)
self._insert_purchase_receipt()
dn = self._insert_delivery_note()
si_against_dn = webnotes.copy_doclist(test_records[1])
si_against_dn[1]["delivery_note"] = dn.doc.name
si_against_dn[1]["dn_detail"] = dn.doclist[1].name
si = webnotes.bean(si_against_dn)
si.insert()
si.submit()
gl_entries = webnotes.conn.sql("""select account, debit, credit
from `tabGL Entry` where voucher_type='Sales Invoice' and voucher_no=%s
order by account asc""", si.doc.name, as_dict=1)
self.assertTrue(gl_entries)
expected_values = sorted([
[si.doc.debit_to, 630.0, 0.0],
[test_records[1][1]["income_account"], 0.0, 500.0],
[test_records[1][2]["account_head"], 0.0, 80.0],
[test_records[1][3]["account_head"], 0.0, 50.0],
["Stock Delivered But Not Billed - _TC", 0.0, 375.0],
[test_records[1][1]["expense_account"], 375.0, 0.0]
])
for i, gle in enumerate(gl_entries):
self.assertEquals(expected_values[i][0], gle.account)
self.assertEquals(expected_values[i][1], gle.debit)
self.assertEquals(expected_values[i][2], gle.credit)
si.cancel()
gl_entries = webnotes.conn.sql("""select account, debit, credit
from `tabGL Entry` where voucher_type='Sales Invoice' and voucher_no=%s
and ifnull(is_cancelled, 'No') = 'No'
order by account asc, name asc""", si.doc.name, as_dict=1)
expected_values = sorted([
[si.doc.debit_to, 630.0, 0.0],
[si.doc.debit_to, 0.0, 630.0],
[test_records[1][1]["income_account"], 0.0, 500.0],
[test_records[1][1]["income_account"], 500.0, 0.0],
[test_records[1][2]["account_head"], 0.0, 80.0],
[test_records[1][2]["account_head"], 80.0, 0.0],
[test_records[1][3]["account_head"], 0.0, 50.0],
[test_records[1][3]["account_head"], 50.0, 0.0],
["Stock Delivered But Not Billed - _TC", 0.0, 375.0],
["Stock Delivered But Not Billed - _TC", 375.0, 0.0],
[test_records[1][1]["expense_account"], 375.0, 0.0],
[test_records[1][1]["expense_account"], 0.0, 375.0]
])
for i, gle in enumerate(gl_entries):
self.assertEquals(expected_values[i][0], gle.account)
self.assertEquals(expected_values[i][1], gle.debit)
self.assertEquals(expected_values[i][2], gle.credit)
webnotes.defaults.set_global_default("auto_inventory_accounting", 0)
def test_pos_gl_entry_with_aii(self): def test_pos_gl_entry_with_aii(self):
webnotes.conn.sql("delete from `tabStock Ledger Entry`") webnotes.conn.sql("delete from `tabStock Ledger Entry`")
webnotes.defaults.set_global_default("auto_inventory_accounting", 1) webnotes.defaults.set_global_default("auto_inventory_accounting", 1)
@ -262,8 +200,6 @@ class TestSalesInvoice(unittest.TestCase):
webnotes.defaults.set_global_default("auto_inventory_accounting", 0) webnotes.defaults.set_global_default("auto_inventory_accounting", 0)
def _insert_purchase_receipt(self): def _insert_purchase_receipt(self):
from stock.doctype.purchase_receipt.test_purchase_receipt import test_records \ from stock.doctype.purchase_receipt.test_purchase_receipt import test_records \
as pr_test_records as pr_test_records

View File

@ -2,7 +2,7 @@
{ {
"creation": "2013-03-07 11:42:55", "creation": "2013-03-07 11:42:55",
"docstatus": 0, "docstatus": 0,
"modified": "2013-03-18 15:41:19", "modified": "2013-03-21 18:35:47",
"modified_by": "Administrator", "modified_by": "Administrator",
"owner": "Administrator" "owner": "Administrator"
}, },
@ -207,11 +207,10 @@
"width": "120px" "width": "120px"
}, },
{ {
"depends_on": "eval:sys_defaults.auto_inventory_accounting",
"doctype": "DocField", "doctype": "DocField",
"fieldname": "expense_account", "fieldname": "expense_account",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 1,
"in_filter": 1, "in_filter": 1,
"label": "Expense Account", "label": "Expense Account",
"options": "Account", "options": "Account",

View File

@ -6,6 +6,18 @@ wn.query_reports["Gross Profit"] = {
"fieldtype": "Link", "fieldtype": "Link",
"options": "Company", "options": "Company",
"default": wn.defaults.get_user_default("company") "default": wn.defaults.get_user_default("company")
} },
{
"fieldname":"from_date",
"label": "From Date",
"fieldtype": "Date",
"default": wn.defaults.get_user_default("year_start_date")
},
{
"fieldname":"to_date",
"label": "To Date",
"fieldtype": "Date",
"default": wn.defaults.get_user_default("year_end_date")
},
] ]
} }

View File

@ -1,31 +1,29 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import webnotes import webnotes
from webnotes.utils import flt from webnotes.utils import flt
from stock.utils import get_buying_amount, get_sales_bom from stock.utils import get_buying_amount
def execute(filters=None): def execute(filters=None):
if not filters: filters = {} if not filters: filters = {}
stock_ledger_entries = get_stock_ledger_entries(filters) stock_ledger_entries = get_stock_ledger_entries(filters)
item_sales_bom = get_sales_bom()
delivery_note_items = webnotes.conn.sql("""select dn.name, dn.posting_date, dn.posting_time, source = get_source_data(filters)
dn.project_name, item.item_code, item.item_name, item.description, item.warehouse,
item.qty, item.basic_rate, item.amount, item.name as "item_row"
from `tabDelivery Note` dn, `tabDelivery Note Item` item
where item.parent = dn.name and dn.docstatus = 1
order by dn.posting_date desc, dn.posting_time desc""", as_dict=1)
columns = ["Delivery Note:Link/Delivery Note", "Posting Date:Date", "Posting Time", item_sales_bom = get_item_sales_bom()
columns = ["Delivery Note/Sales Invoice::120", "Posting Date:Date", "Posting Time",
"Item Code:Link/Item", "Item Name", "Description", "Warehouse:Link/Warehouse", "Item Code:Link/Item", "Item Name", "Description", "Warehouse:Link/Warehouse",
"Qty:Float", "Selling Rate:Currency", "Selling Amount:Currency", "Buying Amount:Currency", "Qty:Float", "Selling Rate:Currency", "Selling Amount:Currency", "Buying Amount:Currency",
"Gross Profit:Currency", "Gross Profit %:Percent", "Project:Link/Project"] "Gross Profit:Currency", "Gross Profit %:Percent", "Project:Link/Project"]
data = [] data = []
for row in delivery_note_items: for row in source:
selling_amount = flt(row.amount) selling_amount = flt(row.amount)
buying_amount = get_buying_amount(row.item_code, row.warehouse, -1*row.qty, 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) row.parenttype, row.name, row.item_row, stock_ledger_entries,
item_sales_bom.get(row.parenttype, {}).get(row.name, webnotes._dict()))
buying_amount = buying_amount > 0 and buying_amount or 0 buying_amount = buying_amount > 0 and buying_amount or 0
if selling_amount: if selling_amount:
@ -34,7 +32,8 @@ def execute(filters=None):
else: else:
gross_profit = gross_profit_percent = 0.0 gross_profit = gross_profit_percent = 0.0
data.append([row.name, row.posting_date, row.posting_time, row.item_code, row.item_name, name = """<a href="%s">%s</a>""" % ("/".join(["#Form", row.parenttype, row.name]), row.name)
data.append([name, row.posting_date, row.posting_time, row.item_code, row.item_name,
row.description, row.warehouse, row.qty, row.basic_rate, row.amount, buying_amount, row.description, row.warehouse, row.qty, row.basic_rate, row.amount, buying_amount,
gross_profit, gross_profit_percent, row.project]) gross_profit, gross_profit_percent, row.project])
@ -44,7 +43,8 @@ def get_stock_ledger_entries(filters):
query = """select item_code, voucher_type, voucher_no, query = """select item_code, voucher_type, voucher_no,
voucher_detail_no, posting_date, posting_time, stock_value, voucher_detail_no, posting_date, posting_time, stock_value,
warehouse, actual_qty as qty warehouse, actual_qty as qty
from `tabStock Ledger Entry` where ifnull(`is_cancelled`, "No") = "No" """ from `tabStock Ledger Entry`
where ifnull(`is_cancelled`, "No") = "No" """
if filters.get("company"): if filters.get("company"):
query += """ and company=%(company)s""" query += """ and company=%(company)s"""
@ -52,3 +52,48 @@ def get_stock_ledger_entries(filters):
query += " order by item_code desc, warehouse desc, posting_date desc, posting_time desc, name desc" query += " order by item_code desc, warehouse desc, posting_date desc, posting_time desc, name desc"
return webnotes.conn.sql(query, filters, as_dict=True) return webnotes.conn.sql(query, filters, as_dict=True)
def get_item_sales_bom():
item_sales_bom = {}
for d in webnotes.conn.sql("""select parenttype, parent, parent_item,
item_code, warehouse, -1*qty as total_qty
from `tabDelivery Note Packing Item` where docstatus=1""", as_dict=True):
item_sales_bom.setdefault(d.parenttype, webnotes._dict()).setdefault(d.parent,
webnotes._dict()).setdefault(d.parent_item, []).append(d)
return item_sales_bom
def get_source_data(filters):
conditions = ""
if filters.get("company"):
conditions += " and company=%(company)s"
if filters.get("from_date"):
conditions += " and posting_date>=%(from_date)s"
if filters.get("to_date"):
conditions += " and posting_date<=%(to_date)s"
delivery_note_items = webnotes.conn.sql("""select item.parenttype, dn.name,
dn.posting_date, dn.posting_time, dn.project_name,
item.item_code, item.item_name, item.description, item.warehouse,
item.qty, item.basic_rate, item.amount, item.name as "item_row",
timestamp(dn.posting_date, dn.posting_time) as posting_datetime
from `tabDelivery Note` dn, `tabDelivery Note Item` item
where item.parent = dn.name and dn.docstatus = 1 %s
order by dn.posting_date desc, dn.posting_time desc""" % (conditions,), filters, as_dict=1)
sales_invoice_items = webnotes.conn.sql("""select item.parenttype, si.name,
si.posting_date, si.posting_time, si.project_name,
item.item_code, item.item_name, item.description, item.warehouse,
item.qty, item.basic_rate, item.amount, item.name as "item_row",
timestamp(si.posting_date, si.posting_time) as posting_datetime
from `tabSales Invoice` si, `tabSales Invoice Item` item
where item.parent = si.name and si.docstatus = 1 %s
and si.is_pos = 1 and si.update_stock = 1
order by si.posting_date desc, si.posting_time desc""" % (conditions,), filters, as_dict=1)
source = delivery_note_items + sales_invoice_items
if len(source) > len(delivery_note_items):
source.sort(key=lambda d: d.posting_datetime, reverse=True)
return source

View File

@ -16,6 +16,7 @@
report.customize_filters = function() { report.customize_filters = function() {
this.hide_all_filters(); this.hide_all_filters();
this.dt.set_no_limit(1);
// hide transaction based on permissions // hide transaction based on permissions
var all_transactions = ["Quotation", "Sales Order", "Delivery Note", "Sales Invoice", var all_transactions = ["Quotation", "Sales Order", "Delivery Note", "Sales Invoice",

View File

@ -39,3 +39,24 @@ class SellingController(StockController):
if self.meta.get_field("in_words_export"): if self.meta.get_field("in_words_export"):
self.doc.in_words_export = money_in_words(disable_rounded_total and 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) self.doc.grand_total_export or self.doc.rounded_total_export, self.doc.currency)
def set_buying_amount(self):
from stock.utils import get_buying_amount
stock_ledger_entries = self.get_stock_ledger_entries()
item_sales_bom = {}
for d in self.doclist.get({"parentfield": "packing_details"}):
new_d = webnotes._dict(d.fields.copy())
new_d.total_qty = -1 * d.qty
item_sales_bom.setdefault(d.parent_item, []).append(new_d)
if stock_ledger_entries:
for item in self.doclist.get({"parentfield": self.fname}):
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(self.tname, item.name, "buying_amount",
item.buying_amount)

View File

@ -16,10 +16,13 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import webnotes import webnotes
from webnotes import msgprint, _
from controllers.accounts_controller import AccountsController from controllers.accounts_controller import AccountsController
class StockController(AccountsController): class StockController(AccountsController):
def make_gl_entries(self, against_stock_account, amount, cost_center=None): def get_gl_entries_for_stock(self, against_stock_account, amount,
stock_in_hand_account=None, cost_center=None):
if not stock_in_hand_account:
stock_in_hand_account = self.get_default_account("stock_in_hand_account") stock_in_hand_account = self.get_default_account("stock_in_hand_account")
if amount: if amount:
@ -41,9 +44,14 @@ class StockController(AccountsController):
"remarks": self.doc.remarks or "Accounting Entry for Stock", "remarks": self.doc.remarks or "Accounting Entry for Stock",
}, self.doc.docstatus == 2), }, self.doc.docstatus == 2),
] ]
from accounts.general_ledger import make_gl_entries
make_gl_entries(gl_entries, cancel=self.doc.docstatus == 2)
return gl_entries
def check_expense_account(self, item):
if not item.expense_account:
msgprint(_("""Expense account is mandatory for item: """) + item.item_code,
raise_exception=1)
def get_stock_ledger_entries(self, item_list=None, warehouse_list=None): def get_stock_ledger_entries(self, item_list=None, warehouse_list=None):
if not (item_list and warehouse_list): if not (item_list and warehouse_list):

View File

@ -109,9 +109,9 @@ erpnext.StockGridReport = wn.views.TreeGridReport.extend({
var value_diff = 0.0; var value_diff = 0.0;
$.each(sl.serial_no.trim().split("\n"), function(i, serial_no) { $.each(sl.serial_no.trim().split("\n"), function(i, sr) {
if(serial_no) { if(sr) {
value_diff += flt(me.serialized_buying_rates[serial_no]); value_diff += flt(me.serialized_buying_rates[sr.trim()]);
} }
}); });
@ -125,7 +125,7 @@ erpnext.StockGridReport = wn.views.TreeGridReport.extend({
if(sle.qty > 0 && sle.serial_no) { if(sle.qty > 0 && sle.serial_no) {
$.each(sle.serial_no.trim().split("\n"), function(i, sr) { $.each(sle.serial_no.trim().split("\n"), function(i, sr) {
if(sr && sle.incoming_rate !== undefined) { if(sr && sle.incoming_rate !== undefined) {
serialized_buying_rates[sr] = flt(sle.incoming_rate); serialized_buying_rates[sr.trim()] = flt(sle.incoming_rate);
} }
}); });
} }

View File

@ -309,3 +309,23 @@ cur_frm.cscript.on_submit = function(doc, cdt, cdn) {
cur_frm.email_doc(wn.boot.notification_settings.delivery_note_message); cur_frm.email_doc(wn.boot.notification_settings.delivery_note_message);
} }
} }
// expense account
cur_frm.fields_dict['delivery_note_details'].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
}
}
}
// cost center
cur_frm.fields_dict["delivery_note_details"].grid.get_field("cost_center").get_query = function(doc) {
return {
query: "accounts.utils.get_cost_center_list",
filters: { company_name: doc.company}
}
}

View File

@ -144,6 +144,8 @@ class DocType(SellingController):
self.validate_mandatory() self.validate_mandatory()
self.validate_reference_value() self.validate_reference_value()
self.validate_for_items() self.validate_for_items()
self.validate_warehouse()
sales_com_obj.validate_max_discount(self, 'delivery_note_details') sales_com_obj.validate_max_discount(self, 'delivery_note_details')
sales_com_obj.get_allocated_sum(self) sales_com_obj.get_allocated_sum(self)
sales_com_obj.check_conversion_rate(self) sales_com_obj.check_conversion_rate(self)
@ -203,6 +205,12 @@ class DocType(SellingController):
else: else:
chk_dupl_itm.append(f) chk_dupl_itm.append(f)
def validate_warehouse(self):
for d in self.get_item_list():
if webnotes.conn.get_value("Item", d['item_code'], "is_stock_item") == "Yes":
if not d['warehouse']:
msgprint("Please enter Warehouse for item %s as it is stock item"
% d['item_code'], raise_exception=1)
def validate_items_with_prevdoc(self, d): def validate_items_with_prevdoc(self, d):
"""check if same item, warehouse present in prevdoc""" """check if same item, warehouse present in prevdoc"""
@ -393,41 +401,17 @@ class DocType(SellingController):
total = (amount/self.doc.net_total)*self.doc.grand_total total = (amount/self.doc.net_total)*self.doc.grand_total
get_obj('Sales Common').check_credit(self, total) get_obj('Sales Common').check_credit(self, total)
def set_buying_amount(self):
from stock.utils import get_buying_amount, get_sales_bom
stock_ledger_entries = self.get_stock_ledger_entries()
item_sales_bom = get_sales_bom()
if stock_ledger_entries:
for item in self.doclist.get({"parentfield": "delivery_note_details"}):
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()
def validate_warehouse(self):
for d in self.get_item_list():
if webnotes.conn.get_value("Item", d['item_code'], "is_stock_item") == "Yes":
if not d['warehouse']:
msgprint("Please enter Warehouse for item %s as it is stock item"
% d['item_code'], raise_exception=1)
def make_gl_entries(self): def make_gl_entries(self):
if not cint(webnotes.defaults.get_global_default("auto_inventory_accounting")): if not cint(webnotes.defaults.get_global_default("auto_inventory_accounting")):
return return
against_stock_account = self.get_default_account("stock_delivered_but_not_billed") gl_entries = []
total_buying_amount = self.get_total_buying_amount() for item in self.doclist.get({"parentfield": "delivery_note_details"}):
self.check_expense_account(item)
super(DocType, self).make_gl_entries(against_stock_account, -1*total_buying_amount) gl_entries += self.get_gl_entries_for_stock(item.expense_account, -1*item.buying_amount,
cost_center=item.cost_center)
def get_total_buying_amount(self): if gl_entries:
total_buying_amount = sum([item.buying_amount for item in from accounts.general_ledger import make_gl_entries
self.doclist.get({"parentfield": "delivery_note_details"})]) make_gl_entries(gl_entries)
return total_buying_amount

View File

@ -56,6 +56,9 @@ class TestDeliveryNote(unittest.TestCase):
self._insert_purchase_receipt() self._insert_purchase_receipt()
dn = webnotes.bean(copy=test_records[0]) dn = webnotes.bean(copy=test_records[0])
dn.doclist[1].expense_account = "Cost of Goods Sold - _TC"
dn.doclist[1].cost_center = "Auto Inventory Accounting - _TC"
stock_in_hand_account = webnotes.conn.get_value("Company", dn.doc.company, stock_in_hand_account = webnotes.conn.get_value("Company", dn.doc.company,
"stock_in_hand_account") "stock_in_hand_account")
@ -65,6 +68,7 @@ class TestDeliveryNote(unittest.TestCase):
dn.insert() dn.insert()
dn.submit() dn.submit()
gl_entries = webnotes.conn.sql("""select account, debit, credit gl_entries = webnotes.conn.sql("""select account, debit, credit
from `tabGL Entry` where voucher_type='Delivery Note' and voucher_no=%s from `tabGL Entry` where voucher_type='Delivery Note' and voucher_no=%s
order by account asc""", dn.doc.name, as_dict=1) order by account asc""", dn.doc.name, as_dict=1)
@ -72,9 +76,8 @@ class TestDeliveryNote(unittest.TestCase):
expected_values = sorted([ expected_values = sorted([
[stock_in_hand_account, 0.0, 375.0], [stock_in_hand_account, 0.0, 375.0],
["Stock Delivered But Not Billed - _TC", 375.0, 0.0] ["Cost of Goods Sold - _TC", 375.0, 0.0]
]) ])
for i, gle in enumerate(gl_entries): for i, gle in enumerate(gl_entries):
self.assertEquals(expected_values[i][0], gle.account) self.assertEquals(expected_values[i][0], gle.account)
self.assertEquals(expected_values[i][1], gle.debit) self.assertEquals(expected_values[i][1], gle.debit)

View File

@ -2,7 +2,7 @@
{ {
"creation": "2013-03-07 11:42:59", "creation": "2013-03-07 11:42:59",
"docstatus": 0, "docstatus": 0,
"modified": "2013-03-07 15:46:43", "modified": "2013-03-21 18:36:22",
"modified_by": "Administrator", "modified_by": "Administrator",
"owner": "Administrator" "owner": "Administrator"
}, },
@ -236,6 +236,7 @@
"doctype": "DocField", "doctype": "DocField",
"fieldname": "batch_no", "fieldname": "batch_no",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0,
"label": "Batch No", "label": "Batch No",
"oldfieldname": "batch_no", "oldfieldname": "batch_no",
"oldfieldtype": "Link", "oldfieldtype": "Link",
@ -243,6 +244,28 @@
"print_hide": 1, "print_hide": 1,
"read_only": 0 "read_only": 0
}, },
{
"doctype": "DocField",
"fieldname": "expense_account",
"fieldtype": "Link",
"hidden": 1,
"label": "Expense Account",
"no_copy": 1,
"options": "Account",
"print_hide": 1,
"width": "120px"
},
{
"doctype": "DocField",
"fieldname": "cost_center",
"fieldtype": "Link",
"hidden": 1,
"label": "Cost Center",
"no_copy": 1,
"options": "Cost Center",
"print_hide": 1,
"width": "120px"
},
{ {
"doctype": "DocField", "doctype": "DocField",
"fieldname": "item_group", "fieldname": "item_group",

View File

@ -1,8 +1,8 @@
[ [
{ {
"creation": "2013-02-22 01:28:01", "creation": "2013-03-08 15:37:16",
"docstatus": 0, "docstatus": 0,
"modified": "2013-03-07 07:03:22", "modified": "2013-03-21 17:29:45",
"modified_by": "Administrator", "modified_by": "Administrator",
"owner": "Administrator" "owner": "Administrator"
}, },
@ -10,7 +10,7 @@
"autoname": "ITEMCUST/.#####", "autoname": "ITEMCUST/.#####",
"description": "For the convenience of customers, these codes can be used in print formats like Invoices and Delivery Notes", "description": "For the convenience of customers, these codes can be used in print formats like Invoices and Delivery Notes",
"doctype": "DocType", "doctype": "DocType",
"in_create": 1, "in_create": 0,
"istable": 1, "istable": 1,
"module": "Stock", "module": "Stock",
"name": "__common__", "name": "__common__",

View File

@ -1,15 +1,15 @@
[ [
{ {
"creation": "2013-02-22 01:28:01", "creation": "2013-03-08 15:37:16",
"docstatus": 0, "docstatus": 0,
"modified": "2013-03-07 07:03:22", "modified": "2013-03-21 17:29:15",
"modified_by": "Administrator", "modified_by": "Administrator",
"owner": "Administrator" "owner": "Administrator"
}, },
{ {
"autoname": "RFD/.#####", "autoname": "RFD/.#####",
"doctype": "DocType", "doctype": "DocType",
"in_create": 1, "in_create": 0,
"istable": 1, "istable": 1,
"module": "Stock", "module": "Stock",
"name": "__common__", "name": "__common__",

View File

@ -19,7 +19,8 @@ cur_frm.fields_dict['delivery_note'].get_query = function(doc, cdt, cdn) {
} }
cur_frm.fields_dict['item_details'].grid.get_field('item_code').get_query = function(doc, cdt, cdn) { cur_frm.fields_dict['item_details'].grid.get_field('item_code').get_query =
function(doc, cdt, cdn) {
var query = 'SELECT name, item_name, description FROM `tabItem` WHERE name IN ( \ var query = 'SELECT name, item_name, description FROM `tabItem` WHERE name IN ( \
SELECT item_code FROM `tabDelivery Note Item` dnd \ SELECT item_code FROM `tabDelivery Note Item` dnd \
WHERE parent="' + doc.delivery_note + '" AND IFNULL(qty, 0) > IFNULL(packed_qty, 0)) AND %(key)s LIKE "%s" LIMIT 50'; WHERE parent="' + doc.delivery_note + '" AND IFNULL(qty, 0) > IFNULL(packed_qty, 0)) AND %(key)s LIKE "%s" LIMIT 50';
@ -34,9 +35,10 @@ cur_frm.add_fetch("item_code", "net_weight", "net_weight");
cur_frm.add_fetch("item_code", "weight_uom", "weight_uom"); cur_frm.add_fetch("item_code", "weight_uom", "weight_uom");
cur_frm.cscript.onload_post_render = function(doc, cdt, cdn) { cur_frm.cscript.onload_post_render = function(doc, cdt, cdn) {
console.log(make_doclist(cdt, cdn));
if(doc.delivery_note && doc.__islocal) { if(doc.delivery_note && doc.__islocal) {
var ps_detail = getchildren('Packing Slip Item', doc.name, 'item_details'); var ps_detail = getchildren('Packing Slip Item', doc.name, 'item_details');
if(!(flt(ps_detail[0].net_weight) && cstr(ps_detail[0].weight_uom))) { if(!(flt(ps_detail.net_weight) && cstr(ps_detail.weight_uom))) {
cur_frm.cscript.update_item_details(doc); cur_frm.cscript.update_item_details(doc);
} }
} }

View File

@ -40,15 +40,12 @@ class DocType:
""" """
Validates if delivery note has status as submitted Validates if delivery note has status as submitted
""" """
res = webnotes.conn.sql("""\ res = webnotes.conn.sql("""SELECT docstatus FROM `tabDelivery Note`
SELECT docstatus FROM `tabDelivery Note` WHERE name=%(delivery_note)s""", self.doc.fields)
WHERE name=%(delivery_note)s
""", self.doc.fields)
if not(res and res[0][0]==0): if not(res and res[0][0]==0):
webnotes.msgprint("""Invalid Delivery Note. Delivery Note should exist webnotes.msgprint("""Invalid Delivery Note. Delivery Note should exist
and should be in draft state. Please rectify and try again.""", and should be in draft state. Please rectify and try again.""", raise_exception=1)
raise_exception=1)
def validate_case_nos(self): def validate_case_nos(self):
@ -65,11 +62,10 @@ class DocType:
raise_exception=1) raise_exception=1)
res = webnotes.conn.sql("""\ res = webnotes.conn.sql("""SELECT name FROM `tabPacking Slip`
SELECT name FROM `tabPacking Slip`
WHERE delivery_note = %(delivery_note)s AND docstatus = 1 AND WHERE delivery_note = %(delivery_note)s AND docstatus = 1 AND
(from_case_no BETWEEN %(from_case_no)s AND %(to_case_no)s (from_case_no BETWEEN %(from_case_no)s AND %(to_case_no)s
OR to_case_no BETWEEN %(from_case_no)s AND %(to_case_no)s)\ OR to_case_no BETWEEN %(from_case_no)s AND %(to_case_no)s)
""", self.doc.fields) """, self.doc.fields)
if res: if res:
@ -133,10 +129,10 @@ class DocType:
item['recommended_qty'] = (flt(item['qty']) - flt(item['packed_qty'])) / no_of_cases item['recommended_qty'] = (flt(item['qty']) - flt(item['packed_qty'])) / no_of_cases
item['specified_qty'] = flt(ps_item_qty[item['item_code']]) item['specified_qty'] = flt(ps_item_qty[item['item_code']])
webnotes.msgprint("""\ webnotes.msgprint("""
Invalid Quantity specified (%(specified_qty)s %(stock_uom)s). Invalid Quantity specified (%(specified_qty)s %(stock_uom)s).
%(packed_qty)s out of %(qty)s %(stock_uom)s already packed for %(item_code)s. %(packed_qty)s out of %(qty)s %(stock_uom)s already packed for %(item_code)s.
<b>Recommended quantity for %(item_code)s = %(recommended_qty)s \ <b>Recommended quantity for %(item_code)s = %(recommended_qty)s
%(stock_uom)s</b>""" % item, raise_exception=1) %(stock_uom)s</b>""" % item, raise_exception=1)
@ -167,16 +163,15 @@ class DocType:
for item in dn_details: for item in dn_details:
new_packed_qty = flt(item['packed_qty']) new_packed_qty = flt(item['packed_qty'])
if (new_packed_qty < 0) or (new_packed_qty > flt(item['qty'])): if (new_packed_qty < 0) or (new_packed_qty > flt(item['qty'])):
webnotes.msgprint("Invalid new packed quantity for item %s. \ webnotes.msgprint("""Invalid new packed quantity for item %s.
Please try again or contact support@erpnext.com" % item['item_code'], raise_exception=1) Please try again or contact support@erpnext.com""" %
item['item_code'], raise_exception=1)
webnotes.conn.sql("""\ webnotes.conn.sql("""UPDATE `tabDelivery Note Item`
UPDATE `tabDelivery Note Item` SET packed_qty = %s WHERE parent = %s AND item_code = %s""",
SET packed_qty = %s
WHERE parent = %s AND item_code = %s""",
(new_packed_qty, self.doc.delivery_note, item['item_code'])) (new_packed_qty, self.doc.delivery_note, item['item_code']))
webnotes.conn.set_value("Delivery Note", self.doc.delivery_note,
"modified", now()) webnotes.conn.set_value("Delivery Note", self.doc.delivery_note, "modified", now())
def update_item_details(self): def update_item_details(self):
@ -191,8 +186,7 @@ class DocType:
def set_item_details(self, row): def set_item_details(self, row):
res = webnotes.conn.sql("""\ res = webnotes.conn.sql("""SELECT item_name, SUM(IFNULL(qty, 0)) as total_qty,
SELECT item_name, SUM(IFNULL(qty, 0)) as total_qty,
IFNULL(packed_qty, 0) as packed_qty, stock_uom IFNULL(packed_qty, 0) as packed_qty, stock_uom
FROM `tabDelivery Note Item` FROM `tabDelivery Note Item`
WHERE parent=%s AND item_code=%s GROUP BY item_code""", WHERE parent=%s AND item_code=%s GROUP BY item_code""",
@ -203,9 +197,8 @@ class DocType:
if not row.qty: if not row.qty:
row.qty = qty >= 0 and qty or 0 row.qty = qty >= 0 and qty or 0
res = webnotes.conn.sql("""\ res = webnotes.conn.sql("""SELECT net_weight, weight_uom FROM `tabItem`
SELECT net_weight, weight_uom FROM `tabItem` WHERE name=%s""", row.item_code, as_dict=1)
WHERE name=%s""", self.doc.item_code, as_dict=1)
if res and len(res)>0: if res and len(res)>0:
row.net_weight = res[0]["net_weight"] row.net_weight = res[0]["net_weight"]
@ -217,8 +210,7 @@ class DocType:
Returns the next case no. for a new packing slip for a delivery Returns the next case no. for a new packing slip for a delivery
note note
""" """
recommended_case_no = webnotes.conn.sql("""\ recommended_case_no = webnotes.conn.sql("""SELECT MAX(to_case_no) FROM `tabPacking Slip`
SELECT MAX(to_case_no) FROM `tabPacking Slip`
WHERE delivery_note = %(delivery_note)s AND docstatus=1""", self.doc.fields) WHERE delivery_note = %(delivery_note)s AND docstatus=1""", self.doc.fields)
return cint(recommended_case_no[0][0]) + 1 return cint(recommended_case_no[0][0]) + 1

View File

@ -318,10 +318,14 @@ class DocType(BuyingController):
if not cint(webnotes.defaults.get_global_default("auto_inventory_accounting")): if not cint(webnotes.defaults.get_global_default("auto_inventory_accounting")):
return return
from accounts.general_ledger import make_gl_entries
against_stock_account = self.get_default_account("stock_received_but_not_billed") against_stock_account = self.get_default_account("stock_received_but_not_billed")
total_valuation_amount = self.get_total_valuation_amount() total_valuation_amount = self.get_total_valuation_amount()
gl_entries = self.get_gl_entries_for_stock(against_stock_account, total_valuation_amount)
super(DocType, self).make_gl_entries(against_stock_account, total_valuation_amount) if gl_entries:
make_gl_entries(gl_entries, cancel=self.doc.docstatus == 2)
def get_total_valuation_amount(self): def get_total_valuation_amount(self):
total_valuation_amount = 0.0 total_valuation_amount = 0.0

View File

@ -174,11 +174,15 @@ class DocType(StockController):
if not self.doc.expense_adjustment_account: if not self.doc.expense_adjustment_account:
webnotes.msgprint(_("Please enter Expense/Adjustment Account"), raise_exception=1) webnotes.msgprint(_("Please enter Expense/Adjustment Account"), raise_exception=1)
from accounts.general_ledger import make_gl_entries
cost_center = "Auto Inventory Accounting - %s" % (self.company_abbr,) cost_center = "Auto Inventory Accounting - %s" % (self.company_abbr,)
total_valuation_amount = self.get_total_valuation_amount() total_valuation_amount = self.get_total_valuation_amount()
super(DocType, self).make_gl_entries(self.doc.expense_adjustment_account, gl_entries = self.get_gl_entries_for_stock(self.doc.expense_adjustment_account,
total_valuation_amount, cost_center) total_valuation_amount, cost_center=cost_center)
if gl_entries:
make_gl_entries(gl_entries, cancel=self.doc.docstatus == 2)
def get_total_valuation_amount(self): def get_total_valuation_amount(self):
total_valuation_amount = 0 total_valuation_amount = 0

View File

@ -26,7 +26,7 @@ class TestStockEntry(unittest.TestCase):
self.assertTrue(mr_name) self.assertTrue(mr_name)
def atest_material_receipt_gl_entry(self): def test_material_receipt_gl_entry(self):
webnotes.conn.sql("delete from `tabStock Ledger Entry`") webnotes.conn.sql("delete from `tabStock Ledger Entry`")
webnotes.defaults.set_global_default("auto_inventory_accounting", 1) webnotes.defaults.set_global_default("auto_inventory_accounting", 1)
@ -63,7 +63,7 @@ class TestStockEntry(unittest.TestCase):
webnotes.defaults.set_global_default("auto_inventory_accounting", 0) webnotes.defaults.set_global_default("auto_inventory_accounting", 0)
def atest_material_issue_gl_entry(self): def test_material_issue_gl_entry(self):
webnotes.conn.sql("delete from `tabStock Ledger Entry`") webnotes.conn.sql("delete from `tabStock Ledger Entry`")
webnotes.defaults.set_global_default("auto_inventory_accounting", 1) webnotes.defaults.set_global_default("auto_inventory_accounting", 1)
@ -151,7 +151,7 @@ class TestStockEntry(unittest.TestCase):
self.assertEquals(expected_sle[i][1], sle.warehouse) self.assertEquals(expected_sle[i][1], sle.warehouse)
self.assertEquals(expected_sle[i][2], sle.actual_qty) self.assertEquals(expected_sle[i][2], sle.actual_qty)
def acheck_gl_entries(self, voucher_type, voucher_no, expected_gl_entries): def check_gl_entries(self, voucher_type, voucher_no, expected_gl_entries):
# check gl entries # check gl entries
gl_entries = webnotes.conn.sql("""select account, debit, credit gl_entries = webnotes.conn.sql("""select account, debit, credit

View File

@ -309,10 +309,14 @@ class DocType(StockController):
if not self.doc.expense_account: if not self.doc.expense_account:
msgprint(_("Please enter Expense Account"), raise_exception=1) msgprint(_("Please enter Expense Account"), raise_exception=1)
from accounts.general_ledger import make_gl_entries
cost_center = "Auto Inventory Accounting - %s" % (self.company_abbr,) cost_center = "Auto Inventory Accounting - %s" % (self.company_abbr,)
super(DocType, self).make_gl_entries(self.doc.expense_account, gl_entries = self.get_gl_entries_for_stock(self.doc.expense_account,
self.doc.stock_value_difference, cost_center) self.doc.stock_value_difference, cost_center=cost_center)
if gl_entries:
make_gl_entries(gl_entries, cancel=self.doc.docstatus == 2)
@webnotes.whitelist() @webnotes.whitelist()
def upload(): def upload():

View File

@ -171,7 +171,8 @@ def get_buying_amount(item_code, warehouse, qty, voucher_type, voucher_no, vouch
buying_amount = 0.0 buying_amount = 0.0
for bom_item in item_sales_bom[item_code]: for bom_item in item_sales_bom[item_code]:
buying_amount += _get_buying_amount(voucher_type, voucher_no, "[** No Item Row **]", buying_amount += _get_buying_amount(voucher_type, voucher_no, "[** No Item Row **]",
bom_item.item_code, warehouse, bom_item.qty * qty, stock_ledger_entries) bom_item.item_code, bom_item.warehouse or warehouse,
bom_item.total_qty or (bom_item.qty * qty), stock_ledger_entries)
return buying_amount return buying_amount
else: else:
# doesn't have sales bom # doesn't have sales bom
@ -184,21 +185,10 @@ def _get_buying_amount(voucher_type, voucher_no, item_row, item_code, warehouse,
if sle.voucher_type == voucher_type and sle.voucher_no == voucher_no and \ if sle.voucher_type == voucher_type and sle.voucher_no == voucher_no and \
(sle.voucher_detail_no == item_row or (sle.voucher_type != "Stock Reconciliation" (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)): 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 \ previous_stock_value = len(stock_ledger_entries) > i+1 and \
flt(stock_ledger_entries[i+1].stock_value) or 0.0 flt(stock_ledger_entries[i+1].stock_value) or 0.0
buying_amount = previous_stock_value - flt(sle.stock_value) buying_amount = previous_stock_value - flt(sle.stock_value)
return buying_amount return buying_amount
return 0.0 return 0.0
def get_sales_bom():
item_sales_bom = {}
# for r in webnotes.conn.sql("""select parent_item, item_code, qty, warehouse, voucher_detail_no
# from `tabDelivery Note Packing Item` where docstatus = 1""", as_dict=1):
for r in webnotes.conn.sql("""select parent, item_code, qty from `tabSales BOM Item`""",
as_dict=1):
item_sales_bom.setdefault(r.parent, []).append(r)
return item_sales_bom