This commit is contained in:
Rushabh Mehta 2013-03-21 17:40:08 +05:30
commit af578d73ef
88 changed files with 2163 additions and 1958 deletions

View File

@ -70,10 +70,10 @@
<td style="width: 3%;">{{ row.idx }}</td> <td style="width: 3%;">{{ row.idx }}</td>
<td style="width: 20%;">{{ row.item_name }}</td> <td style="width: 20%;">{{ row.item_name }}</td>
<td style="width: 37%;">{{ row.description }}</td> <td style="width: 37%;">{{ row.description }}</td>
<td style="width: 5%;">{{ row.qty }}</td> <td style="width: 5%; text-align: right;">{{ row.qty }}</td>
<td style="width: 5%;">{{ row.stock_uom }}</td> <td style="width: 5%;">{{ row.stock_uom }}</td>
<td style="width: 15%;">{{ utils.fmt_money(row.export_rate) }}</td> <td style="width: 15%; text-align: right;">{{ utils.fmt_money(row.export_rate, currency=doc.currency) }}</td>
<td style="width: 15%;">{{ utils.fmt_money(row.export_amount) }}</td> <td style="width: 15%; text-align: right;">{{ utils.fmt_money(row.export_amount, currency=doc.currency) }}</td>
</tr> </tr>
{% endfor -%} {% endfor -%}
</tbody> </tbody>
@ -101,29 +101,25 @@
<table cellspacing=0 width=100%><tbody> <table cellspacing=0 width=100%><tbody>
<tr> <tr>
<td>Net Total</td> <td>Net Total</td>
<td></td> <td width=40% style="text-align: right;">{{
<td width=38%>{{ utils.fmt_money(doc.net_total/doc.conversion_rate, currency=doc.currency)
utils.fmt_money(doc.net_total/doc.conversion_rate)
}}</td> }}</td>
</tr> </tr>
{%- for charge in doclist.get({"doctype":"Sales Taxes and Charges"}) -%} {%- for charge in doclist.get({"doctype":"Sales Taxes and Charges"}) -%}
{%- if not charge.included_in_print_rate -%} {%- if not charge.included_in_print_rate -%}
<tr> <tr>
<td>{{ charge.description }}</td> <td>{{ charge.description }}</td>
<td></td> <td style="text-align: right;">{{ utils.fmt_money(charge.tax_amount / doc.conversion_rate, currency=doc.currency) }}</td>
<td>{{ utils.fmt_money(charge.tax_amount / doc.conversion_rate) }}</td>
</tr> </tr>
{%- endif -%} {%- endif -%}
{%- endfor -%} {%- endfor -%}
<tr> <tr>
<td>Grand Total</td> <td>Grand Total</td>
<td></td> <td style="text-align: right;">{{ utils.fmt_money(doc.grand_total_export, currency=doc.currency) }}</td>
<td>{{ utils.fmt_money(doc.grand_total_export) }}</td>
</tr> </tr>
<tr style='font-weight: bold'> <tr style='font-weight: bold'>
<td>Rounded Total</td> <td>Rounded Total</td>
<td>{{ doc.currency }}</td> <td style="text-align: right;">{{ utils.fmt_money(doc.rounded_total_export, currency=doc.currency) }}</td>
<td>{{ utils.fmt_money(doc.rounded_total_export) }}</td>
</tr> </tr>
</tbody></table> </tbody></table>
<br /><b>In Words</b><br /> <br /><b>In Words</b><br />

View File

@ -32,209 +32,3 @@ def get_default_bank_account():
WHERE name=%s AND docstatus<2""", company) WHERE name=%s AND docstatus<2""", company)
if res: return res[0][0] 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

View File

@ -1,8 +1,8 @@
[ [
{ {
"creation": "2013-01-10 16:34:06", "creation": "2013-01-22 16:50:25",
"docstatus": 0, "docstatus": 0,
"modified": "2013-01-22 14:46:59", "modified": "2013-03-13 12:29:40",
"modified_by": "Administrator", "modified_by": "Administrator",
"owner": "Administrator" "owner": "Administrator"
}, },
@ -23,7 +23,6 @@
"permlevel": 0 "permlevel": 0
}, },
{ {
"amend": 0,
"cancel": 1, "cancel": 1,
"create": 1, "create": 1,
"doctype": "DocPerm", "doctype": "DocPerm",
@ -42,22 +41,6 @@
"doctype": "DocType", "doctype": "DocType",
"name": "Fiscal Year" "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", "description": "For e.g. 2012, 2012-13",
"doctype": "DocField", "doctype": "DocField",
@ -73,6 +56,7 @@
"fieldname": "year_start_date", "fieldname": "year_start_date",
"fieldtype": "Date", "fieldtype": "Date",
"label": "Year Start Date", "label": "Year Start Date",
"no_copy": 1,
"oldfieldname": "year_start_date", "oldfieldname": "year_start_date",
"oldfieldtype": "Date", "oldfieldtype": "Date",
"reqd": 1 "reqd": 1
@ -84,6 +68,7 @@
"fieldname": "is_fiscal_year_closed", "fieldname": "is_fiscal_year_closed",
"fieldtype": "Select", "fieldtype": "Select",
"label": "Year Closed", "label": "Year Closed",
"no_copy": 1,
"oldfieldname": "is_fiscal_year_closed", "oldfieldname": "is_fiscal_year_closed",
"oldfieldtype": "Select", "oldfieldtype": "Select",
"options": "\nNo\nYes", "options": "\nNo\nYes",

View File

@ -10,5 +10,15 @@ test_records = [
"doctype": "Fiscal Year", "doctype": "Fiscal Year",
"year": "_Test Fiscal Year 2014", "year": "_Test Fiscal Year 2014",
"year_start_date": "2014-01-01" "year_start_date": "2014-01-01"
}] }],
[{
"doctype": "Fiscal Year",
"year": "_Test Fiscal Year 2015",
"year_start_date": "2015-01-01"
}],
[{
"doctype": "Fiscal Year",
"year": "_Test Fiscal Year 2016",
"year_start_date": "2016-01-01"
}],
] ]

View File

@ -63,6 +63,9 @@ class DocType(AccountsController):
self.make_gl_entries() self.make_gl_entries()
def on_cancel(self): 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) self.make_gl_entries(cancel=1)
def validate_debit_credit(self): def validate_debit_credit(self):

View File

@ -19,8 +19,34 @@ from __future__ import unicode_literals
import unittest import unittest
import webnotes 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", "company": "_Test Company",
"doctype": "Journal Voucher", "doctype": "Journal Voucher",
"fiscal_year": "_Test Fiscal Year 2013", "fiscal_year": "_Test Fiscal Year 2013",
@ -44,8 +70,59 @@ test_records = [[
"debit": 400.0, "debit": 400.0,
"credit": 0.0, "credit": 0.0,
"parentfield": "entries" "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"
}],
]

View File

@ -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",
}]
]

View File

@ -238,8 +238,11 @@ cur_frm.cscript.expense_head = function(doc, cdt, cdn){
refresh_field('entries'); refresh_field('entries');
} }
cur_frm.fields_dict['entries'].grid.get_field("cost_center").get_query = function(doc) { 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'; return {
query: "accounts.utils.get_cost_center_list",
filters: { company_name: doc.company}
}
} }
cur_frm.cscript.cost_center = function(doc, cdt, cdn){ cur_frm.cscript.cost_center = function(doc, cdt, cdn){

View File

@ -444,6 +444,9 @@ class DocType(BuyingController):
# item gl entries # item gl entries
stock_item_and_auto_inventory_accounting = False 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"}): for item in self.doclist.get({"parentfield": "entries"}):
if auto_inventory_accounting and item.item_code in self.stock_items: if auto_inventory_accounting and item.item_code in self.stock_items:
if flt(item.valuation_rate): if flt(item.valuation_rate):
@ -455,7 +458,7 @@ class DocType(BuyingController):
gl_entries.append( gl_entries.append(
self.get_gl_dict({ self.get_gl_dict({
"account": "Stock Received But Not Billed - %s" % (self.company_abbr,), "account": stock_acocunt,
"against": self.doc.credit_to, "against": self.doc.credit_to,
"debit": flt(item.valuation_rate) * flt(item.conversion_factor) \ "debit": flt(item.valuation_rate) * flt(item.conversion_factor) \
* flt(item.qty), * flt(item.qty),
@ -480,7 +483,7 @@ class DocType(BuyingController):
# this will balance out valuation amount included in cost of goods sold # this will balance out valuation amount included in cost of goods sold
gl_entries.append( gl_entries.append(
self.get_gl_dict({ 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, "cost_center": "Auto Inventory Accounting - %s" % self.company_abbr,
"against": self.doc.credit_to, "against": self.doc.credit_to,
"credit": valuation_tax, "credit": valuation_tax,
@ -504,14 +507,9 @@ class DocType(BuyingController):
if gl_entries: if gl_entries:
make_gl_entries(gl_entries, cancel=is_cancel) 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): 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) self.make_gl_entries(is_cancel=1)
get_obj(dt = 'Purchase Common').update_prevdoc_detail(self, is_submit = 0) get_obj(dt = 'Purchase Common').update_prevdoc_detail(self, is_submit = 0)

View File

@ -116,6 +116,42 @@ class TestPurchaseInvoice(unittest.TestCase):
self.assertEqual(item.item_code, expected_values[i][0]) self.assertEqual(item.item_code, expected_values[i][0])
self.assertEqual(item.item_tax_amount, expected_values[i][1]) 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 = [ test_records = [
[ [
# parent # parent

View File

@ -1,8 +1,8 @@
[ [
{ {
"creation": "2013-02-22 01:27:40", "creation": "2013-03-08 15:36:46",
"docstatus": 0, "docstatus": 0,
"modified": "2013-03-07 07:03:26", "modified": "2013-03-20 16:52:12",
"modified_by": "Administrator", "modified_by": "Administrator",
"owner": "Administrator" "owner": "Administrator"
}, },
@ -40,7 +40,7 @@
{ {
"doctype": "DocField", "doctype": "DocField",
"fieldname": "jv_detail_no", "fieldname": "jv_detail_no",
"fieldtype": "Date", "fieldtype": "Data",
"hidden": 1, "hidden": 1,
"label": "Journal Voucher Detail No", "label": "Journal Voucher Detail No",
"oldfieldname": "jv_detail_no", "oldfieldname": "jv_detail_no",

View File

@ -271,8 +271,6 @@ cur_frm.cscript.is_opening = function(doc, dt, dn) {
if (doc.is_opening == 'Yes') unhide_field('aging_date'); if (doc.is_opening == 'Yes') unhide_field('aging_date');
} }
/* **************************** TRIGGERS ********************************** */
// Get Items based on SO or DN Selected // Get Items based on SO or DN Selected
cur_frm.cscript.get_items = function(doc, dt, dn) { cur_frm.cscript.get_items = function(doc, dt, dn) {
var callback = function(r,rt) { 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"'; 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 // warehouse in detail table
//---------------------------- //----------------------------
cur_frm.fields_dict['entries'].grid.get_field('warehouse').get_query= function(doc, cdt, cdn) { 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 // Cost Center in Details Table
// ----------------------------- // -----------------------------
cur_frm.fields_dict.entries.grid.get_field("cost_center").get_query = function(doc) { 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'; return {
query: "accounts.utils.get_cost_center_list",
filters: { company_name: doc.company}
}
} }
// Sales Order // Sales Order

View File

@ -17,7 +17,9 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import webnotes import webnotes
from webnotes.utils import add_days, cint, cstr, date_diff, flt, getdate, nowdate from webnotes.utils import add_days, cint, cstr, date_diff, flt, getdate, nowdate, \
get_first_day, get_last_day
from webnotes.utils.email_lib import sendmail from webnotes.utils.email_lib import sendmail
from webnotes.utils import comma_and from webnotes.utils import comma_and
from webnotes.model.doc import make_autoname from webnotes.model.doc import make_autoname
@ -47,6 +49,7 @@ class DocType(SellingController):
def validate(self): def validate(self):
super(DocType, self).validate() super(DocType, self).validate()
self.validate_posting_time()
self.so_dn_required() self.so_dn_required()
self.validate_proj_cust() self.validate_proj_cust()
sales_com_obj = get_obj('Sales Common') sales_com_obj = get_obj('Sales Common')
@ -126,7 +129,10 @@ class DocType(SellingController):
sales_com_obj = get_obj(dt = 'Sales Common') sales_com_obj = get_obj(dt = 'Sales Common')
sales_com_obj.check_stop_sales_order(self) 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) sales_com_obj.update_prevdoc_detail(0, self)
self.make_gl_entries() self.make_gl_entries()
@ -399,7 +405,6 @@ class DocType(SellingController):
from accounts.utils import reconcile_against_document from accounts.utils import reconcile_against_document
reconcile_against_document(lst) reconcile_against_document(lst)
def validate_customer(self): def validate_customer(self):
""" Validate customer name with SO and DN""" """ Validate customer name with SO and DN"""
for d in getlist(self.doclist,'entries'): for d in getlist(self.doclist,'entries'):
@ -639,7 +644,6 @@ class DocType(SellingController):
get_obj('Stock Ledger', 'Stock Ledger').update_stock(self.values) get_obj('Stock Ledger', 'Stock Ledger').update_stock(self.values)
def get_actual_qty(self,args): def get_actual_qty(self,args):
args = eval(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) 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)
@ -704,9 +708,9 @@ class DocType(SellingController):
if auto_inventory_accounting: if auto_inventory_accounting:
if cint(self.doc.is_pos) and cint(self.doc.update_stock): 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: 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"}): for item in self.doclist.get({"parentfield": "entries"}):
# income account gl entries # income account gl entries
@ -794,7 +798,8 @@ class DocType(SellingController):
stock_ledger_entries = item_sales_bom = None stock_ledger_entries = item_sales_bom = None
for item in self.doclist.get({"parentfield": "entries"}): 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.buying_amount = self.get_item_buying_amount(item, stock_ledger_entries,
item_sales_bom) item_sales_bom)
webnotes.conn.set_value("Sales Invoice Item", item.name, webnotes.conn.set_value("Sales Invoice Item", item.name,
@ -804,8 +809,9 @@ class DocType(SellingController):
item_buying_amount = 0 item_buying_amount = 0
if stock_ledger_entries: if stock_ledger_entries:
# is pos and update stock # 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) 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: elif item.delivery_note and item.dn_detail:
# against delivery note # against delivery note
dn_item = webnotes.conn.get_value("Delivery Note Item", item.dn_detail, dn_item = webnotes.conn.get_value("Delivery Note Item", item.dn_detail,
@ -828,12 +834,6 @@ class DocType(SellingController):
grand_total = %s where invoice_no = %s and parent = %s""", grand_total = %s where invoice_no = %s and parent = %s""",
(self.doc.name, self.doc.amended_from, self.doc.c_form_no)) (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 @property
def meta(self): def meta(self):
if not hasattr(self, "_meta"): if not hasattr(self, "_meta"):
@ -893,25 +893,18 @@ class DocType(SellingController):
next_date = get_next_date(self.doc.posting_date, next_date = get_next_date(self.doc.posting_date,
month_map[self.doc.recurring_type], cint(self.doc.repeat_on_day_of_month)) month_map[self.doc.recurring_type], cint(self.doc.repeat_on_day_of_month))
webnotes.conn.set(self.doc, 'next_date', next_date) webnotes.conn.set(self.doc, 'next_date', next_date)
def get_next_date(dt, mcount, day=None): def get_next_date(dt, mcount, day=None):
import datetime dt = getdate(dt)
month = getdate(dt).month + mcount
year = getdate(dt).year
if not day:
day = getdate(dt).day
if month > 12:
month, year = month-12, year+1
try:
next_month_date = datetime.date(year, month, day)
except:
import calendar
last_day = calendar.monthrange(year, month)[1]
next_month_date = datetime.date(year, month, last_day)
return next_month_date.strftime("%Y-%m-%d")
def manage_recurring_invoices(next_date=None): from dateutil.relativedelta import relativedelta
dt += relativedelta(months=mcount, day=day)
return dt
def manage_recurring_invoices(next_date=None, commit=True):
""" """
Create recurring invoices on specific date by copying the original one Create recurring invoices on specific date by copying the original one
and notify the concerned people and notify the concerned people
@ -931,8 +924,10 @@ def manage_recurring_invoices(next_date=None):
ref_wrapper = webnotes.bean('Sales Invoice', ref_invoice) ref_wrapper = webnotes.bean('Sales Invoice', ref_invoice)
new_invoice_wrapper = make_new_invoice(ref_wrapper, next_date) new_invoice_wrapper = make_new_invoice(ref_wrapper, next_date)
send_notification(new_invoice_wrapper) send_notification(new_invoice_wrapper)
if commit:
webnotes.conn.commit() webnotes.conn.commit()
except: except:
if commit:
webnotes.conn.rollback() webnotes.conn.rollback()
webnotes.conn.begin() webnotes.conn.begin()
@ -943,6 +938,7 @@ def manage_recurring_invoices(next_date=None):
exception_list.append(webnotes.getTraceback()) exception_list.append(webnotes.getTraceback())
finally: finally:
if commit:
webnotes.conn.begin() webnotes.conn.begin()
if exception_list: if exception_list:
@ -956,18 +952,26 @@ def make_new_invoice(ref_wrapper, posting_date):
mcount = month_map[ref_wrapper.doc.recurring_type] mcount = month_map[ref_wrapper.doc.recurring_type]
invoice_period_from_date = get_next_date(ref_wrapper.doc.invoice_period_from_date, mcount)
# get last day of the month to maintain period if the from date is first day of its own month
# and to date is the last day of its own month
if (cstr(get_first_day(ref_wrapper.doc.invoice_period_from_date)) == \
cstr(ref_wrapper.doc.invoice_period_from_date)) and \
(cstr(get_last_day(ref_wrapper.doc.invoice_period_to_date)) == \
cstr(ref_wrapper.doc.invoice_period_to_date)):
invoice_period_to_date = get_last_day(get_next_date(ref_wrapper.doc.invoice_period_to_date,
mcount))
else:
invoice_period_to_date = get_next_date(ref_wrapper.doc.invoice_period_to_date, mcount)
new_invoice.doc.fields.update({ new_invoice.doc.fields.update({
"posting_date": posting_date, "posting_date": posting_date,
"aging_date": posting_date, "aging_date": posting_date,
"due_date": add_days(posting_date, cint(date_diff(ref_wrapper.doc.due_date, "due_date": add_days(posting_date, cint(date_diff(ref_wrapper.doc.due_date,
ref_wrapper.doc.posting_date))), ref_wrapper.doc.posting_date))),
"invoice_period_from_date": invoice_period_from_date,
"invoice_period_from_date": \ "invoice_period_to_date": invoice_period_to_date,
get_next_date(ref_wrapper.doc.invoice_period_from_date, mcount),
"invoice_period_to_date": \
get_next_date(ref_wrapper.doc.invoice_period_to_date, mcount),
"fiscal_year": get_fiscal_year(posting_date)[0], "fiscal_year": get_fiscal_year(posting_date)[0],
"owner": ref_wrapper.doc.owner, "owner": ref_wrapper.doc.owner,
}) })

View File

@ -1,8 +1,8 @@
[ [
{ {
"creation": "2013-01-29 17:54:09", "creation": "2013-03-20 17:01:58",
"docstatus": 0, "docstatus": 0,
"modified": "2013-01-29 18:22:52", "modified": "2013-03-20 19:17:38",
"modified_by": "Administrator", "modified_by": "Administrator",
"owner": "Administrator" "owner": "Administrator"
}, },
@ -77,7 +77,6 @@
"print_hide": 1 "print_hide": 1
}, },
{ {
"default": "1",
"depends_on": "eval:doc.is_pos==1", "depends_on": "eval:doc.is_pos==1",
"doctype": "DocField", "doctype": "DocField",
"fieldname": "update_stock", "fieldname": "update_stock",
@ -1094,7 +1093,7 @@
"description": "The day of the month on which auto invoice will be generated e.g. 05, 28 etc ", "description": "The day of the month on which auto invoice will be generated e.g. 05, 28 etc ",
"doctype": "DocField", "doctype": "DocField",
"fieldname": "repeat_on_day_of_month", "fieldname": "repeat_on_day_of_month",
"fieldtype": "Data", "fieldtype": "Int",
"label": "Repeat on Day of Month", "label": "Repeat on Day of Month",
"no_copy": 1, "no_copy": 1,
"print_hide": 1 "print_hide": 1

View File

@ -281,6 +281,7 @@ class TestSalesInvoice(unittest.TestCase):
return dn return dn
def _insert_pos_settings(self): def _insert_pos_settings(self):
webnotes.conn.sql("""delete from `tabPOS Setting`""")
ps = webnotes.bean([ ps = webnotes.bean([
{ {
"cash_bank_account": "_Test Account Bank Account - _TC", "cash_bank_account": "_Test Account Bank Account - _TC",
@ -297,7 +298,178 @@ class TestSalesInvoice(unittest.TestCase):
]) ])
ps.insert() ps.insert()
test_dependencies = ["Journal Voucher"] 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))
def test_recurring_invoice(self):
from webnotes.utils import now_datetime, get_first_day, get_last_day, add_to_date
today = now_datetime().date()
base_si = webnotes.bean(copy=test_records[0])
base_si.doc.fields.update({
"convert_into_recurring_invoice": 1,
"recurring_type": "Monthly",
"notification_email_address": "test@example.com, test1@example.com, test2@example.com",
"repeat_on_day_of_month": today.day,
"posting_date": today,
"invoice_period_from_date": get_first_day(today),
"invoice_period_to_date": get_last_day(today)
})
# monthly
si1 = webnotes.bean(copy=base_si.doclist)
si1.insert()
si1.submit()
self._test_recurring_invoice(si1, True)
# monthly without a first and last day period
si2 = webnotes.bean(copy=base_si.doclist)
si2.doc.fields.update({
"invoice_period_from_date": today,
"invoice_period_to_date": add_to_date(today, days=30)
})
si2.insert()
si2.submit()
self._test_recurring_invoice(si2, False)
# quarterly
si3 = webnotes.bean(copy=base_si.doclist)
si3.doc.fields.update({
"recurring_type": "Quarterly",
"invoice_period_from_date": get_first_day(today),
"invoice_period_to_date": get_last_day(add_to_date(today, months=3))
})
si3.insert()
si3.submit()
self._test_recurring_invoice(si3, True)
# quarterly without a first and last day period
si4 = webnotes.bean(copy=base_si.doclist)
si4.doc.fields.update({
"recurring_type": "Quarterly",
"invoice_period_from_date": today,
"invoice_period_to_date": add_to_date(today, months=3)
})
si4.insert()
si4.submit()
self._test_recurring_invoice(si4, False)
# yearly
si5 = webnotes.bean(copy=base_si.doclist)
si5.doc.fields.update({
"recurring_type": "Yearly",
"invoice_period_from_date": get_first_day(today),
"invoice_period_to_date": get_last_day(add_to_date(today, years=1))
})
si5.insert()
si5.submit()
self._test_recurring_invoice(si5, True)
# yearly without a first and last day period
si6 = webnotes.bean(copy=base_si.doclist)
si6.doc.fields.update({
"recurring_type": "Yearly",
"invoice_period_from_date": today,
"invoice_period_to_date": add_to_date(today, years=1)
})
si6.insert()
si6.submit()
self._test_recurring_invoice(si6, False)
# change posting date but keep recuring day to be today
si7 = webnotes.bean(copy=base_si.doclist)
si7.doc.fields.update({
"posting_date": add_to_date(today, days=-3)
})
si7.insert()
si7.submit()
# setting so that _test function works
si7.doc.posting_date = today
self._test_recurring_invoice(si7, True)
def _test_recurring_invoice(self, base_si, first_and_last_day):
from webnotes.utils import add_months, get_last_day, getdate
from accounts.doctype.sales_invoice.sales_invoice import manage_recurring_invoices
no_of_months = ({"Monthly": 1, "Quarterly": 3, "Yearly": 12})[base_si.doc.recurring_type]
def _test(i):
self.assertEquals(i+1, webnotes.conn.sql("""select count(*) from `tabSales Invoice`
where recurring_id=%s and docstatus=1""", base_si.doc.recurring_id)[0][0])
next_date = add_months(base_si.doc.posting_date, no_of_months)
manage_recurring_invoices(next_date=next_date, commit=False)
recurred_invoices = webnotes.conn.sql("""select name from `tabSales Invoice`
where recurring_id=%s and docstatus=1 order by name desc""", base_si.doc.recurring_id)
self.assertEquals(i+2, len(recurred_invoices))
new_si = webnotes.bean("Sales Invoice", recurred_invoices[0][0])
for fieldname in ["convert_into_recurring_invoice", "recurring_type",
"repeat_on_day_of_month", "notification_email_address"]:
self.assertEquals(base_si.doc.fields.get(fieldname),
new_si.doc.fields.get(fieldname))
self.assertEquals(new_si.doc.posting_date, unicode(next_date))
self.assertEquals(new_si.doc.invoice_period_from_date,
unicode(add_months(base_si.doc.invoice_period_from_date, no_of_months)))
if first_and_last_day:
self.assertEquals(new_si.doc.invoice_period_to_date,
unicode(get_last_day(add_months(base_si.doc.invoice_period_to_date,
no_of_months))))
else:
self.assertEquals(new_si.doc.invoice_period_to_date,
unicode(add_months(base_si.doc.invoice_period_to_date, no_of_months)))
self.assertEquals(getdate(new_si.doc.posting_date).day,
base_si.doc.repeat_on_day_of_month)
return new_si
# if yearly, test 3 repetitions, else test 13 repetitions
count = no_of_months == 12 and 3 or 13
for i in xrange(count):
base_si = _test(i)
test_dependencies = ["Journal Voucher", "POS Setting"]
test_records = [ 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-11 14:58:50", "modified": "2013-03-18 15:41:19",
"modified_by": "Administrator", "modified_by": "Administrator",
"owner": "Administrator" "owner": "Administrator"
}, },
@ -207,14 +207,16 @@
"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": 1, "hidden": 0,
"in_filter": 1, "in_filter": 1,
"label": "Expense Account", "label": "Expense Account",
"options": "Account", "options": "Account",
"print_hide": 1 "print_hide": 1,
"width": "120px"
}, },
{ {
"doctype": "DocField", "doctype": "DocField",

View File

@ -45,8 +45,7 @@ cur_frm.pformat.other_charges= function(doc){
var make_row = function(title,val,bold){ var make_row = function(title,val,bold){
var bstart = '<b>'; var bend = '</b>'; var bstart = '<b>'; var bend = '</b>';
return '<tr><td style="width:50%;">'+(bold?bstart:'')+title+(bold?bend:'')+'</td>' return '<tr><td style="width:50%;">'+(bold?bstart:'')+title+(bold?bend:'')+'</td>'
+'<td style="width:25%;text-align:right;"></td>' +'<td style="width:50%;text-align:right;">'+format_currency(val, doc.currency)+'</td>'
+'<td style="width:25%;text-align:right;">'+format_currency(val, doc.currency)+'</td>'
+'</tr>' +'</tr>'
} }

View File

@ -63,12 +63,6 @@ wn.module_page["Accounts"] = [
"doctype": "Period Closing Voucher", "doctype": "Period Closing Voucher",
description: "Close Balance Sheet and book Profit or Loss." 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", "page":"voucher-import-tool",
"label": wn._("Voucher Import Tool"), "label": wn._("Voucher Import Tool"),

View File

@ -24,8 +24,10 @@ def execute(filters=None):
data = [] data = []
for row in delivery_note_items: for row in delivery_note_items:
selling_amount = flt(row.amount) selling_amount = flt(row.amount)
buying_amount = get_buying_amount(row.item_code, row.warehouse, buying_amount = get_buying_amount(row.item_code, row.warehouse, -1*row.qty,
row.qty, "Delivery Note", row.name, row.item_row, stock_ledger_entries, item_sales_bom) "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: if selling_amount:
gross_profit = selling_amount - buying_amount gross_profit = selling_amount - buying_amount
gross_profit_percent = (gross_profit / selling_amount) * 100.0 gross_profit_percent = (gross_profit / selling_amount) * 100.0

View File

@ -17,7 +17,7 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import webnotes 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.model.doc import addchild
from webnotes import msgprint, _ from webnotes import msgprint, _
from webnotes.utils import formatdate from webnotes.utils import formatdate
@ -234,3 +234,17 @@ def get_cost_center_list(doctype, txt, searchfield, start, page_len, filters):
where docstatus < 2 %s and %s like %s order by name limit %s, %s""" % where docstatus < 2 %s and %s like %s order by name limit %s, %s""" %
(conditions, searchfield, "%s", "%s", "%s"), (conditions, searchfield, "%s", "%s", "%s"),
tuple(filter_values + ["%%%s%%" % txt, start, page_len])) 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))

View File

@ -80,12 +80,6 @@ wn.module_page["Buying"] = [
title: wn._("Tools"), title: wn._("Tools"),
icon: "icon-wrench", icon: "icon-wrench",
items: [ 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"
},
] ]
}, },
{ {

View File

@ -18,9 +18,14 @@ from __future__ import unicode_literals
import webnotes import webnotes
from webnotes import msgprint, _ from webnotes import msgprint, _
from webnotes.utils import flt from webnotes.utils import flt
from utilities.transaction_base import TransactionBase from utilities.transaction_base import TransactionBase
class AccountsController(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): def get_gl_dict(self, args, cancel=None):
"""this method populates the common properties of a gl entry record""" """this method populates the common properties of a gl entry record"""
if cancel is None: if cancel is None:
@ -71,15 +76,14 @@ class AccountsController(TransactionBase):
"allocate_amount": 0 "allocate_amount": 0
}) })
def get_stock_in_hand_account(self): def get_default_account(self, account_for):
stock_in_hand_account = webnotes.conn.get_value("Company", self.doc.company, "stock_in_hand_account") 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)
if not stock_in_hand_account: return 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
@property @property
def stock_items(self): def stock_items(self):
@ -97,3 +101,8 @@ class AccountsController(TransactionBase):
self._abbr = webnotes.conn.get_value("Company", self.doc.company, "abbr") self._abbr = webnotes.conn.get_value("Company", self.doc.company, "abbr")
return self._abbr return self._abbr
@webnotes.whitelist()
def get_default_account(account_for, company):
return webnotes.conn.get_value("Company", company, account_for)

View File

@ -24,10 +24,11 @@ from buying.utils import get_item_details
from setup.utils import get_company_currency from setup.utils import get_company_currency
from webnotes.model.utils import round_floats_in_doc 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): def validate(self):
super(BuyingController, self).validate()
if self.meta.get_field("currency"): if self.meta.get_field("currency"):
self.company_currency = get_company_currency(self.doc.company) self.company_currency = get_company_currency(self.doc.company)
self.validate_conversion_rate("currency", "conversion_rate") self.validate_conversion_rate("currency", "conversion_rate")

View File

@ -19,10 +19,11 @@ import webnotes
from webnotes.utils import cint from webnotes.utils import cint
from setup.utils import get_company_currency 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): def validate(self):
super(SellingController, self).validate()
self.set_total_in_words() self.set_total_in_words()
def set_total_in_words(self): def set_total_in_words(self):
@ -38,26 +39,3 @@ class SellingController(AccountsController):
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 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))

View File

@ -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 <http://www.gnu.org/licenses/>.
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_default_account("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))

View File

@ -1,4 +1,5 @@
erpnext.updates = [ 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."]], ["12th March", ["Updates to website module. Added more options in Style Settings and Website Settings."]],
["5th March", ["Refactored Upload Attendance Tool"]], ["5th March", ["Refactored Upload Attendance Tool"]],
["4th March", ["Lead organization added in Quotation classic/spartan/modern print format"]], ["4th March", ["Lead organization added in Quotation classic/spartan/modern print format"]],

View File

@ -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")

View File

@ -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")

View File

@ -211,5 +211,8 @@ patch_list = [
"patches.march_2013.p02_get_global_default", "patches.march_2013.p02_get_global_default",
"patches.march_2013.p03_rename_blog_to_blog_post", "patches.march_2013.p03_rename_blog_to_blog_post",
"execute:webnotes.reload_doc('hr', 'search_criteria', 'monthly_attendance_details')", "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.p05_payment_reconciliation",
"patches.march_2013.p06_remove_sales_purchase_return_tool",
"execute:webnotes.bean('Global Defaults').save()"
] ]

View File

@ -1 +0,0 @@
from __future__ import unicode_literals

View File

@ -1,13 +0,0 @@
[
"Selling",
"Description",
"Sales and Purchase Return Item",
"Qty",
"Serial No",
"Rate",
"Detail Name",
"Batch No",
"Returned Qty",
"Item Code",
"UOM"
]

View File

@ -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"
}

View File

@ -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"
}

View File

@ -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"
}

View File

@ -1,13 +0,0 @@
{
"Batch No": "Aucun lot",
"Description": "Description",
"Detail Name": "Nom de d\u00e9tails",
"Item Code": "Code de l&#39;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"
}

View File

@ -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"
}

View File

@ -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"
}

View File

@ -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"
}

View File

@ -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"
}

View File

@ -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"
}

View File

@ -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"
}

View File

@ -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"
}

View File

@ -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"
}

View File

@ -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 <http://www.gnu.org/licenses/>.
from __future__ import unicode_literals
import webnotes
class DocType:
def __init__(self, d, dl):
self.doc, self.doclist = d, dl

View File

@ -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
}
]

View File

@ -120,12 +120,6 @@ wn.module_page["Selling"] = [
title: wn._("Tools"), title: wn._("Tools"),
icon: "icon-wrench", icon: "icon-wrench",
items: [ 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", "route":"Form/SMS Center/SMS Center",
"label":wn._("SMS Center"), "label":wn._("SMS Center"),

View File

@ -58,3 +58,43 @@ cur_frm.fields_dict.receivables_group.get_query = function(doc) {
cur_frm.fields_dict.payables_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'; 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
}
}
}

View File

@ -17,7 +17,7 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import webnotes import webnotes
from webnotes.utils import cstr, set_default from webnotes.utils import cstr
from webnotes.model.doc import Document from webnotes.model.doc import Document
from webnotes.model.code import get_obj from webnotes.model.code import get_obj
import webnotes.defaults import webnotes.defaults
@ -47,10 +47,11 @@ class DocType:
['Loans and Advances (Assets)','Current Assets','Group','No','','Debit',self.doc.name,''], ['Loans and Advances (Assets)','Current Assets','Group','No','','Debit',self.doc.name,''],
['Securities and Deposits','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,''], ['Earnest Money','Securities and Deposits','Ledger','No','','Debit',self.doc.name,''],
['Stock In Hand','Current Assets','Group','No','','Debit',self.doc.name,''], ['Stock Assets','Current Assets','Group','No','','Debit',self.doc.name,''],
['Stock','Stock In Hand','Ledger','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,''], ['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,''], ['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,''], ['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,''], ['Computers','Fixed Assets','Ledger','No','Fixed Asset Account','Debit',self.doc.name,''],
@ -62,9 +63,10 @@ class DocType:
['Temporary Account (Assets)','Temporary Accounts (Assets)','Ledger','No','','Debit',self.doc.name,''], ['Temporary Account (Assets)','Temporary Accounts (Assets)','Ledger','No','','Debit',self.doc.name,''],
['Expenses','','Group','Yes','Expense Account','Debit',self.doc.name,''], ['Expenses','','Group','Yes','Expense Account','Debit',self.doc.name,''],
['Direct Expenses','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,''], ['Stock Expenses','Direct Expenses','Group','Yes','Expense Account','Debit',self.doc.name,''],
['Expenses Included In Valuation','Direct Expenses','Ledger','Yes','Expense Account','Debit',self.doc.name,''], ['Cost of Goods Sold','Stock Expenses','Ledger','Yes','Expense Account','Debit',self.doc.name,''],
['Stock Adjustment','Direct 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,''], ['Indirect Expenses','Expenses','Group','Yes','Expense Account','Debit',self.doc.name,''],
['Advertising and Publicity','Indirect Expenses','Ledger','Yes','Chargeable','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,''], ['Bad Debts Written Off','Indirect Expenses','Ledger','Yes','Expense Account','Debit',self.doc.name,''],
@ -101,12 +103,14 @@ class DocType:
['Shareholders Funds','Capital Account','Group','No','','Credit',self.doc.name,''], ['Shareholders Funds','Capital Account','Group','No','','Credit',self.doc.name,''],
['Current Liabilities','Source of Funds (Liabilities)','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,''], ['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,''], ['Duties and Taxes','Current Liabilities','Group','No','','Credit',self.doc.name,''],
['Loans (Liabilities)','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,''], ['Secured Loans','Loans (Liabilities)','Group','No','','Credit',self.doc.name,''],
['Unsecured 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,''], ['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 Accounts (Liabilities)','Source of Funds (Liabilities)','Group','No','','Credit',self.doc.name,''],
['Temporary Account (Liabilities)','Temporary Accounts (Liabilities)','Ledger','No','','Credit',self.doc.name,''] ['Temporary Account (Liabilities)','Temporary Accounts (Liabilities)','Ledger','No','','Credit',self.doc.name,'']
] ]
@ -186,14 +190,35 @@ class DocType:
self.doc.letter_head = header self.doc.letter_head = header
# Set default AR and AP group def set_default_accounts(self):
# --------------------------------------------------- if not self.doc.receivables_group and webnotes.conn.exists('Account',
def set_default_groups(self): 'Accounts Receivable - ' + self.doc.abbr):
if not self.doc.receivables_group: webnotes.conn.set(self.doc, 'receivables_group', 'Accounts Receivable - ' +
webnotes.conn.set(self.doc, 'receivables_group', 'Accounts Receivable - '+self.doc.abbr) self.doc.abbr)
if not self.doc.payables_group:
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) 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)
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 # Create default cost center
# --------------------------------------------------- # ---------------------------------------------------
@ -228,7 +253,7 @@ class DocType:
self.doc.name) self.doc.name)
if not ac: if not ac:
self.create_default_accounts() 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)) cc = sql("select name from `tabCost Center` where cost_center_name = 'Root' and company_name = '%s'"%(self.doc.name))
if not cc: if not cc:
self.create_default_cost_center() self.create_default_cost_center()
@ -258,9 +283,6 @@ class DocType:
#update value as blank for tabSingles Global Defaults #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) 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): def on_rename(self,newdn,olddn):
sql("update `tabCompany` set company_name = '%s' where name = '%s'" %(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)) sql("update `tabSingles` set value = %s where doctype='Global Defaults' and field = 'default_company' and value = %s", (newdn, olddn))

View File

@ -1,8 +1,8 @@
[ [
{ {
"creation": "2013-02-22 01:27:54", "creation": "2013-02-27 09:38:05",
"docstatus": 0, "docstatus": 0,
"modified": "2013-02-26 10:57:39", "modified": "2013-03-19 12:52:00",
"modified_by": "Administrator", "modified_by": "Administrator",
"owner": "Administrator" "owner": "Administrator"
}, },
@ -124,17 +124,6 @@
"oldfieldtype": "Link", "oldfieldtype": "Link",
"options": "Account" "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", "doctype": "DocField",
"fieldname": "column_break0", "fieldname": "column_break0",
@ -181,6 +170,57 @@
"oldfieldtype": "Select", "oldfieldtype": "Select",
"options": "\nWarn\nIgnore\nStop" "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": "expenses_included_in_valuation",
"fieldtype": "Link",
"label": "Expenses Included In Valuation",
"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.", "description": "For reference only.",
"doctype": "DocField", "doctype": "DocField",

View File

@ -44,6 +44,7 @@ keydict = {
'maintain_same_rate' : 'maintain_same_rate', 'maintain_same_rate' : 'maintain_same_rate',
'session_expiry': 'session_expiry', 'session_expiry': 'session_expiry',
'disable_rounded_total': 'disable_rounded_total', 'disable_rounded_total': 'disable_rounded_total',
"update_stock": "update_stock",
} }
class DocType: class DocType:

View File

@ -260,6 +260,13 @@
"fieldname": "column_break4", "fieldname": "column_break4",
"fieldtype": "Column Break" "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", "doctype": "DocField",
"fieldname": "account_info", "fieldname": "account_info",
@ -414,7 +421,7 @@
"fieldname": "emp_created_by", "fieldname": "emp_created_by",
"fieldtype": "Select", "fieldtype": "Select",
"label": "Employee Records to be created by ", "label": "Employee Records to be created by ",
"options": "\nNaming Series\nEmployee Number" "options": "Naming Series\nEmployee Number"
}, },
{ {
"doctype": "DocField", "doctype": "DocField",

View File

@ -16,15 +16,8 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import webnotes import webnotes
from webnotes import _ from webnotes.utils import add_days, cint,flt, nowdate, get_url_to_form, formatdate
from webnotes import msgprint, _
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
sql = webnotes.conn.sql sql = webnotes.conn.sql
import webnotes.defaults import webnotes.defaults
@ -61,7 +54,7 @@ class DocType:
from stock.stock_ledger import update_entries_after from stock.stock_ledger import update_entries_after
if not args.get("posting_date"): if not args.get("posting_date"):
posting_date = nowdate() args["posting_date"] = nowdate()
# update valuation and qty after transaction for post dated entry # update valuation and qty after transaction for post dated entry
update_entries_after({ update_entries_after({
@ -108,11 +101,10 @@ class DocType:
#check if re-order is required #check if re-order is required
item_reorder = webnotes.conn.get("Item Reorder", item_reorder = webnotes.conn.get("Item Reorder",
{"parent": self.doc.item_code, "warehouse": self.doc.warehouse}) {"parent": self.doc.item_code, "warehouse": self.doc.warehouse})
if item_reorder: if item_reorder:
reorder_level = item_reorder.warehouse_reorder_level reorder_level = item_reorder.warehouse_reorder_level
reorder_qty = item_reorder.warehouse_reorder_qty 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: else:
reorder_level, reorder_qty = webnotes.conn.get_value("Item", self.doc.item_code, reorder_level, reorder_qty = webnotes.conn.get_value("Item", self.doc.item_code,
["re_order_level", "re_order_qty"]) ["re_order_level", "re_order_qty"])
@ -123,7 +115,7 @@ class DocType:
material_request_type) material_request_type)
def create_material_request(self, doc_type, doc_name, reorder_level, reorder_qty, 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 """ """ Create indent on reaching reorder level """
defaults = webnotes.defaults.get_defaults() defaults = webnotes.defaults.get_defaults()
item = webnotes.doc("Item", self.doc.item_code) item = webnotes.doc("Item", self.doc.item_code)
@ -151,7 +143,6 @@ class DocType:
"qty": reorder_qty, "qty": reorder_qty,
"brand": item.brand, "brand": item.brand,
}]) }])
mr.insert() mr.insert()
mr.submit() mr.submit()

View File

@ -24,7 +24,6 @@ from webnotes import msgprint
sql = webnotes.conn.sql sql = webnotes.conn.sql
from controllers.selling_controller import SellingController from controllers.selling_controller import SellingController
class DocType(SellingController): class DocType(SellingController):
@ -133,7 +132,7 @@ class DocType(SellingController):
super(DocType, self).validate() super(DocType, self).validate()
import utilities import utilities
utilities.validate_status(self.doc.status, ["Draft", "submitted", "Cancelled"]) utilities.validate_status(self.doc.status, ["Draft", "Submitted", "Cancelled"])
self.so_required() self.so_required()
self.validate_fiscal_year() self.validate_fiscal_year()
@ -401,9 +400,12 @@ class DocType(SellingController):
if stock_ledger_entries: if stock_ledger_entries:
for item in self.doclist.get({"parentfield": "delivery_note_details"}): for item in self.doclist.get({"parentfield": "delivery_note_details"}):
item.buying_amount = get_buying_amount(item.item_code, item.warehouse, item.qty, 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, self.doc.doctype, self.doc.name, item.name, stock_ledger_entries,
item_sales_bom) 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", webnotes.conn.set_value("Delivery Note Item", item.name, "buying_amount",
item.buying_amount) item.buying_amount)
@ -420,31 +422,10 @@ class DocType(SellingController):
if not cint(webnotes.defaults.get_global_default("auto_inventory_accounting")): if not cint(webnotes.defaults.get_global_default("auto_inventory_accounting")):
return return
abbr = webnotes.conn.get_value("Company", self.doc.company, "abbr") against_stock_account = self.get_default_account("stock_delivered_but_not_billed")
stock_delivered_account = "Stock Delivered But Not Billed - %s" % (abbr,)
stock_in_hand_account = self.get_stock_in_hand_account()
total_buying_amount = self.get_total_buying_amount() 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 super(DocType, self).make_gl_entries(against_stock_account, -1*total_buying_amount)
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)
def get_total_buying_amount(self): def get_total_buying_amount(self):
total_buying_amount = sum([item.buying_amount for item in total_buying_amount = sum([item.buying_amount for item in

View File

@ -1,8 +1,8 @@
[ [
{ {
"creation": "2013-02-22 01:28:01", "creation": "2013-03-07 11:42:59",
"docstatus": 0, "docstatus": 0,
"modified": "2013-03-07 07:03:22", "modified": "2013-03-19 12:22:44",
"modified_by": "Administrator", "modified_by": "Administrator",
"owner": "Administrator" "owner": "Administrator"
}, },
@ -20,7 +20,8 @@
"parent": "Item Reorder", "parent": "Item Reorder",
"parentfield": "fields", "parentfield": "fields",
"parenttype": "DocType", "parenttype": "DocType",
"permlevel": 0 "permlevel": 0,
"read_only": 0
}, },
{ {
"doctype": "DocType", "doctype": "DocType",
@ -38,7 +39,8 @@
"doctype": "DocField", "doctype": "DocField",
"fieldname": "warehouse_reorder_level", "fieldname": "warehouse_reorder_level",
"fieldtype": "Float", "fieldtype": "Float",
"label": "Re-order Level" "label": "Re-order Level",
"reqd": 1
}, },
{ {
"doctype": "DocField", "doctype": "DocField",
@ -51,6 +53,7 @@
"fieldname": "material_request_type", "fieldname": "material_request_type",
"fieldtype": "Select", "fieldtype": "Select",
"label": "Material Request Type", "label": "Material Request Type",
"options": "Purchase\nTransfer" "options": "Purchase\nTransfer",
"reqd": 1
} }
] ]

View File

@ -28,18 +28,10 @@ cur_frm.fields_dict['item_details'].grid.get_field('item_code').get_query = func
// Fetch item details // Fetch item details
cur_frm.cscript.item_code = function(doc, cdt, cdn) { cur_frm.add_fetch("item_code", "item_name", "item_name");
if(locals[cdt][cdn].item_code) { cur_frm.add_fetch("item_code", "stock_uom", "stock_uom");
$c_obj(make_doclist(cdt, cdn), 'get_item_details', doc.delivery_note, function(r, rt) { cur_frm.add_fetch("item_code", "net_weight", "net_weight");
if(r.exc) { cur_frm.add_fetch("item_code", "weight_uom", "weight_uom");
msgprint(r.exc);
} else {
refresh_field('item_details');
}
});
}
}
cur_frm.cscript.onload_post_render = function(doc, cdt, cdn) { cur_frm.cscript.onload_post_render = function(doc, cdt, cdn) {
if(doc.delivery_note && doc.__islocal) { if(doc.delivery_note && doc.__islocal) {

View File

@ -20,8 +20,7 @@ import webnotes
from webnotes.utils import cstr, flt, cint from webnotes.utils import cstr, flt, cint
from webnotes.model.bean import getlist from webnotes.model.bean import getlist
from webnotes.model.code import get_obj 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 sql = webnotes.conn.sql
@ -319,32 +318,10 @@ 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
abbr = webnotes.conn.get_value("Company", self.doc.company, "abbr") against_stock_account = self.get_default_account("stock_received_but_not_billed")
stock_received_account = "Stock Received But Not Billed - %s" % (abbr,)
stock_in_hand_account = self.get_stock_in_hand_account()
total_valuation_amount = self.get_total_valuation_amount() total_valuation_amount = self.get_total_valuation_amount()
if total_valuation_amount: super(DocType, self).make_gl_entries(against_stock_account, 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)
def get_total_valuation_amount(self): def get_total_valuation_amount(self):
total_valuation_amount = 0.0 total_valuation_amount = 0.0

View File

@ -1 +0,0 @@
from __future__ import unicode_literals

View File

@ -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"
]

View File

@ -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"
}

View File

@ -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"
}

View File

@ -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"
}

View File

@ -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&#39;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&#39;achat",
"Sales and Purchase Return Tool": "Outil de vente et de retour d&#39;achat",
"Stock": "Stock"
}

View File

@ -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"
}

View File

@ -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"
}

View File

@ -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"
}

View File

@ -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"
}

View File

@ -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"
}

View File

@ -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"
}

View File

@ -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"
}

View File

@ -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"
}

View File

@ -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 <http://www.gnu.org/licenses/>.
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.length; i++){
if(cl[i].returned_qty > 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<cl.length; i++){
if (cl[i].returned_qty) {
var d1 = wn.model.add_child(se, 'Stock Entry Detail', 'mtn_details');
d1.detail_name = cl[i].detail_name;
d1.item_code = cl[i].item_code;
d1.description = cl[i].description;
d1.transfer_qty = cl[i].returned_qty;
d1.qty = cl[i].returned_qty;
d1.stock_uom = cl[i].uom;
d1.uom = cl[i].uom;
d1.conversion_factor = 1;
d1.incoming_rate = cl[i].rate;
d1.serial_no = cl[i].serial_no;
d1.batch_no = cl[i].batch_no;
}
}
}
// Make excise voucher
//-------------------------------
cur_frm.cscript.make_excise_invoice = function(doc) {
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 debit note
//------------------------------
cur_frm.cscript.make_debit_note = function(doc) {
var doclist = make_doclist(doc.doctype, doc.name);
$c('accounts.get_new_jv_details', {
doclist: JSON.stringify(doclist),
fiscal_year: sys_defaults.fiscal_year
}, function(r, rt) {
if(!r.exc) {
cur_frm.cscript.make_jv(doc, 'Debit Note', r.message);
}
});
}
// Make credit note
//------------------------------
cur_frm.cscript.make_credit_note = function(doc) {
var doclist = make_doclist(doc.doctype, doc.name);
$c('accounts.get_new_jv_details', {
doclist: JSON.stringify(doclist),
fiscal_year: sys_defaults.fiscal_year,
}, function(r, rt) {
if(!r.exc) {
cur_frm.cscript.make_jv(doc, 'Credit Note', r.message);
}
});
}
// Make JV
//--------------------------------
cur_frm.cscript.make_jv = function(doc, dr_or_cr, children) {
var jv = wn.model.make_new_doc_and_get_name('Journal Voucher');
jv = locals['Journal Voucher'][jv];
jv.voucher_type = dr_or_cr;
jv.company = sys_defaults.company;
jv.fiscal_year = sys_defaults.fiscal_year;
jv.is_opening = 'No';
jv.posting_date = doc.return_date;
// Add children
if(children) {
for(var i=0; i<children.length; i++) {
var ch = wn.model.add_child(jv, 'Journal Voucher Detail', 'entries');
$.extend(ch, children[i]);
ch.balance = flt(ch.balance);
}
}
loaddoc('Journal Voucher', jv.name);
}

View File

@ -1,71 +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 <http://www.gnu.org/licenses/>.
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()

View File

@ -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"
}
]

View File

@ -18,6 +18,76 @@ wn.require("public/app/js/controllers/stock_controller.js");
wn.provide("erpnext.stock"); wn.provide("erpnext.stock");
erpnext.stock.StockEntry = erpnext.stock.StockController.extend({ 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;
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"});
}
};
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() { onload_post_render: function() {
if(this.frm.doc.__islocal && (this.frm.doc.production_order || this.frm.doc.bom_no) 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) { && !getchildren('Stock Entry Detail', this.frm.doc.name, 'mtn_details').length) {
@ -27,12 +97,25 @@ erpnext.stock.StockEntry = erpnext.stock.StockController.extend({
}, },
refresh: function() { refresh: function() {
var me = this;
erpnext.hide_naming_series(); erpnext.hide_naming_series();
this.toggle_related_fields(this.frm.doc); this.toggle_related_fields(this.frm.doc);
this.toggle_enable_bom(); this.toggle_enable_bom();
if (this.frm.doc.docstatus==1) { if (this.frm.doc.docstatus==1) {
this.show_stock_ledger(); this.show_stock_ledger();
} }
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", 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", function() { me.make_return_jv(); });
this.add_excise_button();
}
}
}, },
on_submit: function() { on_submit: function() {
@ -81,6 +164,68 @@ erpnext.stock.StockEntry = erpnext.stock.StockController.extend({
this.frm.toggle_enable("bom_no", !this.frm.doc.production_order); 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"));
}
}
},
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) {
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);
}
}
});
},
}); });
cur_frm.cscript = new erpnext.stock.StockEntry({frm: cur_frm}); cur_frm.cscript = new erpnext.stock.StockEntry({frm: cur_frm});
@ -140,15 +285,6 @@ cur_frm.cscript.purpose = function(doc, cdt, cdn) {
cur_frm.cscript.toggle_related_fields(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 // copy over source and target warehouses
cur_frm.fields_dict['mtn_details'].grid.onrowadd = function(doc, cdt, cdn){ cur_frm.fields_dict['mtn_details'].grid.onrowadd = function(doc, cdt, cdn){
var d = locals[cdt][cdn]; var d = locals[cdt][cdn];

View File

@ -26,18 +26,21 @@ from stock.utils import get_incoming_rate
from stock.stock_ledger import get_previous_sle from stock.stock_ledger import get_previous_sle
import json import json
sql = webnotes.conn.sql sql = webnotes.conn.sql
from controllers.accounts_controller import AccountsController class NotUpdateStockError(webnotes.ValidationError): pass
class StockOverReturnError(webnotes.ValidationError): pass
class DocType(AccountsController): from controllers.stock_controller import StockController
class DocType(StockController):
def __init__(self, doc, doclist=[]): def __init__(self, doc, doclist=[]):
self.doc = doc self.doc = doc
self.doclist = doclist self.doclist = doclist
self.fname = 'mtn_details' self.fname = 'mtn_details'
def validate(self): def validate(self):
self.validate_posting_time()
self.validate_purpose() self.validate_purpose()
self.validate_serial_nos() self.validate_serial_nos()
pro_obj = self.doc.production_order and \ pro_obj = self.doc.production_order and \
@ -168,31 +171,14 @@ class DocType(AccountsController):
if not cint(webnotes.defaults.get_global_default("auto_inventory_accounting")): if not cint(webnotes.defaults.get_global_default("auto_inventory_accounting")):
return return
abbr = webnotes.conn.get_value("Company", self.doc.company, "abbr") if not self.doc.expense_adjustment_account:
stock_in_hand_account = self.get_stock_in_hand_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() total_valuation_amount = self.get_total_valuation_amount()
if total_valuation_amount: super(DocType, self).make_gl_entries(self.doc.expense_adjustment_account,
gl_entries = [ total_valuation_amount, cost_center)
# 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)
def get_total_valuation_amount(self): def get_total_valuation_amount(self):
total_valuation_amount = 0 total_valuation_amount = 0
@ -276,24 +262,53 @@ class DocType(AccountsController):
def validate_return_reference_doc(self): def validate_return_reference_doc(self):
"""validate item with reference doc""" """validate item with reference doc"""
ref_doctype = ref_docname = "" ref = get_return_doclist_and_details(self.doc.fields)
if self.doc.purpose == "Sales Return" and \
(self.doc.delivery_note_no or self.doc.sales_invoice_no): if ref.doclist:
ref_doctype = self.doc.delivery_note_no and "Delivery Note" or "Sales Invoice" # validate docstatus
ref_docname = self.doc.delivery_note_no or self.doc.sales_invoice_no if ref.doclist[0].docstatus != 1:
elif self.doc.purpose == "Purchase Return" and self.doc.purchase_receipt_no: webnotes.msgprint(_(ref.doclist[0].doctype) + ' "' + ref.doclist[0].name + '": '
ref_doctype = "Purchase Receipt" + _("Status should be Submitted"), raise_exception=webnotes.InvalidStatusError)
ref_docname = self.doc.purchase_receipt_no
# 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) 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:
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, ref.parentfields)
already_returned_item_qty = self.get_already_returned_item_qty(ref.fieldname)
if ref_doctype and ref_docname:
for item in self.doclist.get({"parentfield": "mtn_details"}): for item in self.doclist.get({"parentfield": "mtn_details"}):
ref_exists = webnotes.conn.sql("""select name from `tab%s` # validate if item exists in the ref doclist and that it is a stock item
where parent = %s and item_code = %s and docstatus=1""" % if item.item_code not in stock_items:
(ref_doctype + " Item", '%s', '%s'), (ref_docname, item.item_code)) msgprint(_("Item") + ': "' + item.item_code + _("\" does not exist in ") +
ref.doclist[0].doctype + ": " + ref.doclist[0].name,
raise_exception=webnotes.DoesNotExistError)
if not ref_exists: # validate quantity <= ref item's qty - qty already returned
msgprint(_("Item: '") + item.item_code + _("' does not exists in ") + ref_item = ref.doclist.getone({"item_code": item.item_code})
ref_doctype + ": " + ref_docname, raise_exception=1) 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): def update_serial_no(self, is_submit):
"""Create / Update Serial No""" """Create / Update Serial No"""
@ -326,6 +341,7 @@ class DocType(AccountsController):
self.add_to_values(d, cstr(d.s_warehouse), -flt(d.transfer_qty), is_cancelled) self.add_to_values(d, cstr(d.s_warehouse), -flt(d.transfer_qty), is_cancelled)
if cstr(d.t_warehouse): if cstr(d.t_warehouse):
self.add_to_values(d, cstr(d.t_warehouse), flt(d.transfer_qty), is_cancelled) 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, get_obj('Stock Ledger', 'Stock Ledger').update_stock(self.values,
self.doc.amended_from and 'Yes' or 'No') self.doc.amended_from and 'Yes' or 'No')
@ -646,3 +662,263 @@ def get_production_order_details(production_order):
ifnull(qty, 0) - ifnull(produced_qty, 0) as fg_completed_qty, use_multi_level_bom 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) from `tabProduction Order` where name = %s""", production_order, as_dict=1)
return result and result[0] or {} 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("%", "")
ref = get_return_doclist_and_details(filters)
stock_items = get_stock_items_for_return(ref.doclist, ref.parentfields)
result = []
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)
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
def get_return_doclist_and_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]]
"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"]]
}
}
@webnotes.whitelist()
def make_return_jv(stock_entry):
se = webnotes.bean("Stock Entry", stock_entry)
if not se.doc.purpose in ["Sales Return", "Purchase Return"]:
return
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)
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
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
}]
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",
"parentfield": "entries",
"account": r.get("account"),
"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
parent = {
"account": ref.doclist[0].debit_to,
"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 = get_sales_account_from_item(ref.doclist, ref_item)
if account not in children:
children.append(account)
return [parent] + [{"account": account} for account in children]
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})
account = parent_item.income_account
else:
account = ref_item.income_account
return account
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:
sales_orders_against_delivery = [d.prevdoc_docname for d in
ref.doclist.get({"prevdoc_doctype": "Sales Order"}) if d.prevdoc_docname]
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 []
packing_item_parent_map = dict([[d.item_code, d.parent_item] for d in ref.doclist.get(
{"parentfield": ref.parentfields[1]})])
parent = {}
children = []
for se_item in se.doclist.get({"parentfield": "mtn_details"}):
for sales_invoice in invoices_against_delivery:
si = webnotes.bean("Sales Invoice", sales_invoice)
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
ref_item = ref_item[0]
account = get_sales_account_from_item(si.doclist, ref_item)
if account not in children:
children.append(account)
if not parent:
parent = {"account": si.doc.debit_to}
break
if len(invoices_against_delivery) == 1:
parent["against_invoice"] = invoices_against_delivery[0]
result = [parent] + [{"account": account} for account in 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):
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]
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 []
parent = {}
children = []
for se_item in se.doclist.get({"parentfield": "mtn_details"}):
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]
account = ref_item.expense_head
if account not in children:
children.append(account)
if not parent:
parent = {"account": pi.doc.credit_to}
break
if len(invoice_against_receipt) == 1:
parent["against_voucher"] = invoice_against_receipt[0]
result = [parent] + [{"account": account} for account in children]
return result

View File

@ -1,8 +1,8 @@
[ [
{ {
"creation": "2013-01-23 19:57:20", "creation": "2013-03-11 12:34:40",
"docstatus": 0, "docstatus": 0,
"modified": "2013-01-28 17:59:20", "modified": "2013-03-19 17:48:29",
"modified_by": "Administrator", "modified_by": "Administrator",
"owner": "Administrator" "owner": "Administrator"
}, },
@ -60,6 +60,7 @@
"fieldtype": "Column Break", "fieldtype": "Column Break",
"oldfieldtype": "Column Break", "oldfieldtype": "Column Break",
"print_width": "50%", "print_width": "50%",
"read_only": 0,
"width": "50%" "width": "50%"
}, },
{ {
@ -76,6 +77,7 @@
"oldfieldtype": "Select", "oldfieldtype": "Select",
"options": "\nSTE", "options": "\nSTE",
"print_hide": 1, "print_hide": 1,
"read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 1, "reqd": 1,
"search_index": 0 "search_index": 0
@ -95,184 +97,11 @@
"oldfieldtype": "Select", "oldfieldtype": "Select",
"options": "Material Issue\nMaterial Receipt\nMaterial Transfer\nManufacture/Repack\nSubcontract\nSales Return\nPurchase Return", "options": "Material Issue\nMaterial Receipt\nMaterial Transfer\nManufacture/Repack\nSubcontract\nSales Return\nPurchase Return",
"print_hide": 0, "print_hide": 0,
"read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 1, "reqd": 1,
"search_index": 0 "search_index": 0
}, },
{
"doctype": "DocField",
"fieldname": "col2",
"fieldtype": "Column Break",
"oldfieldtype": "Column Break",
"print_width": "50%",
"width": "50%"
},
{
"allow_on_submit": 0,
"default": "Today",
"description": "The date at which current entry will get or has actually executed.",
"doctype": "DocField",
"fieldname": "posting_date",
"fieldtype": "Date",
"hidden": 0,
"in_filter": 1,
"in_list_view": 0,
"label": "Posting Date",
"no_copy": 1,
"oldfieldname": "posting_date",
"oldfieldtype": "Date",
"print_hide": 1,
"report_hide": 0,
"reqd": 1,
"search_index": 1
},
{
"allow_on_submit": 0,
"doctype": "DocField",
"fieldname": "posting_time",
"fieldtype": "Time",
"hidden": 0,
"in_filter": 0,
"label": "Posting Time",
"no_copy": 1,
"oldfieldname": "posting_time",
"oldfieldtype": "Time",
"print_hide": 1,
"report_hide": 0,
"reqd": 1,
"search_index": 0
},
{
"doctype": "DocField",
"fieldname": "items_section",
"fieldtype": "Section Break",
"label": "Items",
"oldfieldtype": "Section Break"
},
{
"allow_on_submit": 0,
"doctype": "DocField",
"fieldname": "from_warehouse",
"fieldtype": "Link",
"hidden": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Default Source Warehouse",
"no_copy": 1,
"oldfieldname": "from_warehouse",
"oldfieldtype": "Link",
"options": "Warehouse",
"print_hide": 1,
"report_hide": 0,
"reqd": 0,
"search_index": 0
},
{
"doctype": "DocField",
"fieldname": "cb0",
"fieldtype": "Column Break"
},
{
"allow_on_submit": 0,
"doctype": "DocField",
"fieldname": "to_warehouse",
"fieldtype": "Link",
"hidden": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Default Target Warehouse",
"no_copy": 1,
"oldfieldname": "to_warehouse",
"oldfieldtype": "Link",
"options": "Warehouse",
"print_hide": 1,
"report_hide": 0,
"reqd": 0,
"search_index": 0
},
{
"doctype": "DocField",
"fieldname": "sb0",
"fieldtype": "Section Break",
"options": "Simple"
},
{
"allow_on_submit": 0,
"doctype": "DocField",
"fieldname": "mtn_details",
"fieldtype": "Table",
"hidden": 0,
"in_filter": 0,
"label": "MTN Details",
"no_copy": 0,
"oldfieldname": "mtn_details",
"oldfieldtype": "Table",
"options": "Stock Entry Detail",
"print_hide": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0
},
{
"description": "Get valuation rate and available stock at source/target warehouse on mentioned posting date-time. If serialized item, please press this button after entering serial nos.",
"doctype": "DocField",
"fieldname": "get_stock_and_rate",
"fieldtype": "Button",
"label": "Get Stock and Rate",
"oldfieldtype": "Button",
"options": "get_stock_and_rate",
"print_hide": 1
},
{
"doctype": "DocField",
"fieldname": "sb1",
"fieldtype": "Section Break",
"label": "Reference"
},
{
"allow_on_submit": 0,
"depends_on": "eval:inList([\"Material Transfer\", \"Manufacture/Repack\"], doc.purpose)",
"doctype": "DocField",
"fieldname": "production_order",
"fieldtype": "Link",
"hidden": 1,
"in_filter": 1,
"label": "Production Order",
"no_copy": 0,
"oldfieldname": "production_order",
"oldfieldtype": "Link",
"options": "Production Order",
"print_hide": 1,
"report_hide": 0,
"reqd": 0,
"search_index": 1
},
{
"depends_on": "eval:!inList([\"Sales Return\", \"Purchase Return\"], doc.purpose)",
"doctype": "DocField",
"fieldname": "bom_no",
"fieldtype": "Link",
"label": "BOM No",
"options": "BOM"
},
{
"allow_on_submit": 0,
"depends_on": "eval:!inList([\"Sales Return\", \"Purchase Return\"], doc.purpose)",
"description": "As per Stock UOM",
"doctype": "DocField",
"fieldname": "fg_completed_qty",
"fieldtype": "Float",
"hidden": 0,
"in_filter": 0,
"label": "Manufacturing Quantity",
"no_copy": 0,
"oldfieldname": "fg_completed_qty",
"oldfieldtype": "Currency",
"print_hide": 1,
"report_hide": 0,
"reqd": 0,
"search_index": 0
},
{ {
"allow_on_submit": 0, "allow_on_submit": 0,
"depends_on": "eval:doc.purpose==\"Sales Return\"", "depends_on": "eval:doc.purpose==\"Sales Return\"",
@ -291,6 +120,17 @@
"reqd": 0, "reqd": 0,
"search_index": 1 "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, "allow_on_submit": 0,
"depends_on": "eval:doc.purpose==\"Purchase Return\"", "depends_on": "eval:doc.purpose==\"Purchase Return\"",
@ -309,10 +149,208 @@
"reqd": 0, "reqd": 0,
"search_index": 1 "search_index": 1
}, },
{
"doctype": "DocField",
"fieldname": "col2",
"fieldtype": "Column Break",
"oldfieldtype": "Column Break",
"print_width": "50%",
"read_only": 0,
"width": "50%"
},
{
"allow_on_submit": 0,
"default": "Today",
"description": "The date at which current entry will get or has actually executed.",
"doctype": "DocField",
"fieldname": "posting_date",
"fieldtype": "Date",
"hidden": 0,
"in_filter": 1,
"in_list_view": 0,
"label": "Posting Date",
"no_copy": 1,
"oldfieldname": "posting_date",
"oldfieldtype": "Date",
"print_hide": 1,
"read_only": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 1
},
{
"allow_on_submit": 0,
"doctype": "DocField",
"fieldname": "posting_time",
"fieldtype": "Time",
"hidden": 0,
"in_filter": 0,
"label": "Posting Time",
"no_copy": 1,
"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",
"read_only": 0
},
{
"allow_on_submit": 0,
"doctype": "DocField",
"fieldname": "from_warehouse",
"fieldtype": "Link",
"hidden": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Default Source Warehouse",
"no_copy": 1,
"oldfieldname": "from_warehouse",
"oldfieldtype": "Link",
"options": "Warehouse",
"print_hide": 1,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0
},
{
"doctype": "DocField",
"fieldname": "cb0",
"fieldtype": "Column Break",
"read_only": 0
},
{
"allow_on_submit": 0,
"doctype": "DocField",
"fieldname": "to_warehouse",
"fieldtype": "Link",
"hidden": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Default Target Warehouse",
"no_copy": 1,
"oldfieldname": "to_warehouse",
"oldfieldtype": "Link",
"options": "Warehouse",
"print_hide": 1,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0
},
{
"doctype": "DocField",
"fieldname": "sb0",
"fieldtype": "Section Break",
"options": "Simple",
"read_only": 0
},
{
"allow_on_submit": 0,
"doctype": "DocField",
"fieldname": "mtn_details",
"fieldtype": "Table",
"hidden": 0,
"in_filter": 0,
"label": "MTN Details",
"no_copy": 0,
"oldfieldname": "mtn_details",
"oldfieldtype": "Table",
"options": "Stock Entry Detail",
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0
},
{
"description": "Get valuation rate and available stock at source/target warehouse on mentioned posting date-time. If serialized item, please press this button after entering serial nos.",
"doctype": "DocField",
"fieldname": "get_stock_and_rate",
"fieldtype": "Button",
"label": "Get Stock and Rate",
"oldfieldtype": "Button",
"options": "get_stock_and_rate",
"print_hide": 1,
"read_only": 0
},
{
"depends_on": "eval:(doc.purpose!==\"Sales Return\" || doc.purpose!==\"Purchase Return\")",
"doctype": "DocField",
"fieldname": "sb1",
"fieldtype": "Section Break",
"label": "Reference",
"read_only": 0
},
{
"allow_on_submit": 0,
"depends_on": "eval:inList([\"Material Transfer\", \"Manufacture/Repack\"], doc.purpose)",
"doctype": "DocField",
"fieldname": "production_order",
"fieldtype": "Link",
"hidden": 1,
"in_filter": 1,
"label": "Production Order",
"no_copy": 0,
"oldfieldname": "production_order",
"oldfieldtype": "Link",
"options": "Production Order",
"print_hide": 1,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 1
},
{
"depends_on": "eval:!inList([\"Sales Return\", \"Purchase Return\"], doc.purpose)",
"doctype": "DocField",
"fieldname": "bom_no",
"fieldtype": "Link",
"label": "BOM No",
"options": "BOM",
"read_only": 0
},
{
"allow_on_submit": 0,
"depends_on": "eval:!inList([\"Sales Return\", \"Purchase Return\"], doc.purpose)",
"description": "As per Stock UOM",
"doctype": "DocField",
"fieldname": "fg_completed_qty",
"fieldtype": "Float",
"hidden": 0,
"in_filter": 0,
"label": "Manufacturing Quantity",
"no_copy": 0,
"oldfieldname": "fg_completed_qty",
"oldfieldtype": "Currency",
"print_hide": 1,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0
},
{ {
"doctype": "DocField", "doctype": "DocField",
"fieldname": "cb1", "fieldname": "cb1",
"fieldtype": "Column Break" "fieldtype": "Column Break",
"read_only": 0
}, },
{ {
"default": "1", "default": "1",
@ -321,7 +359,8 @@
"doctype": "DocField", "doctype": "DocField",
"fieldname": "use_multi_level_bom", "fieldname": "use_multi_level_bom",
"fieldtype": "Check", "fieldtype": "Check",
"label": "Use Multi-Level BOM" "label": "Use Multi-Level BOM",
"read_only": 0
}, },
{ {
"allow_on_submit": 0, "allow_on_submit": 0,
@ -335,27 +374,18 @@
"no_copy": 0, "no_copy": 0,
"oldfieldtype": "Button", "oldfieldtype": "Button",
"print_hide": 1, "print_hide": 1,
"read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
"search_index": 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\")", "depends_on": "eval:(doc.purpose==\"Sales Return\" || doc.purpose==\"Purchase Return\")",
"doctype": "DocField", "doctype": "DocField",
"fieldname": "contact_section", "fieldname": "contact_section",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"label": "Contact Info" "label": "Contact Info",
"read_only": 0
}, },
{ {
"allow_on_submit": 0, "allow_on_submit": 0,
@ -371,6 +401,7 @@
"oldfieldtype": "Link", "oldfieldtype": "Link",
"options": "Supplier", "options": "Supplier",
"print_hide": 1, "print_hide": 1,
"read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
"search_index": 0 "search_index": 0
@ -406,6 +437,7 @@
"oldfieldname": "supplier_address", "oldfieldname": "supplier_address",
"oldfieldtype": "Small Text", "oldfieldtype": "Small Text",
"print_hide": 0, "print_hide": 0,
"read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
"search_index": 0 "search_index": 0
@ -424,6 +456,7 @@
"oldfieldtype": "Link", "oldfieldtype": "Link",
"options": "Customer", "options": "Customer",
"print_hide": 1, "print_hide": 1,
"read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
"search_index": 0 "search_index": 0
@ -459,6 +492,7 @@
"oldfieldname": "customer_address", "oldfieldname": "customer_address",
"oldfieldtype": "Small Text", "oldfieldtype": "Small Text",
"print_hide": 0, "print_hide": 0,
"read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
"search_index": 0 "search_index": 0
@ -468,13 +502,15 @@
"fieldname": "more_info", "fieldname": "more_info",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"label": "More Info", "label": "More Info",
"oldfieldtype": "Section Break" "oldfieldtype": "Section Break",
"read_only": 0
}, },
{ {
"doctype": "DocField", "doctype": "DocField",
"fieldname": "col4", "fieldname": "col4",
"fieldtype": "Column Break", "fieldtype": "Column Break",
"print_width": "50%", "print_width": "50%",
"read_only": 0,
"width": "50%" "width": "50%"
}, },
{ {
@ -485,7 +521,8 @@
"label": "Project Name", "label": "Project Name",
"oldfieldname": "project_name", "oldfieldname": "project_name",
"oldfieldtype": "Link", "oldfieldtype": "Link",
"options": "Project" "options": "Project",
"read_only": 0
}, },
{ {
"allow_on_submit": 0, "allow_on_submit": 0,
@ -500,6 +537,7 @@
"oldfieldtype": "Link", "oldfieldtype": "Link",
"options": "Print Heading", "options": "Print Heading",
"print_hide": 0, "print_hide": 0,
"read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
"search_index": 0 "search_index": 0
@ -517,6 +555,7 @@
"oldfieldtype": "Link", "oldfieldtype": "Link",
"options": "Company", "options": "Company",
"print_hide": 1, "print_hide": 1,
"read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 1, "reqd": 1,
"search_index": 0 "search_index": 0
@ -526,6 +565,7 @@
"fieldname": "col5", "fieldname": "col5",
"fieldtype": "Column Break", "fieldtype": "Column Break",
"print_width": "50%", "print_width": "50%",
"read_only": 0,
"width": "50%" "width": "50%"
}, },
{ {
@ -558,6 +598,7 @@
"oldfieldname": "remarks", "oldfieldname": "remarks",
"oldfieldtype": "Text", "oldfieldtype": "Text",
"print_hide": 1, "print_hide": 1,
"read_only": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
"search_index": 0 "search_index": 0
@ -569,5 +610,13 @@
{ {
"doctype": "DocPerm", "doctype": "DocPerm",
"role": "Manufacturing User" "role": "Manufacturing User"
},
{
"doctype": "DocPerm",
"role": "Manufacturing Manager"
},
{
"doctype": "DocPerm",
"role": "Material Manager"
} }
] ]

View File

@ -3,11 +3,15 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import webnotes, unittest import webnotes, unittest
from webnotes.utils import flt
class TestStockEntry(unittest.TestCase): class TestStockEntry(unittest.TestCase):
def test_auto_material_request(self): def test_auto_material_request(self):
webnotes.conn.sql("""delete from `tabMaterial Request Item`""") webnotes.conn.sql("""delete from `tabMaterial Request Item`""")
webnotes.conn.sql("""delete from `tabMaterial Request`""") 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 = webnotes.bean(copy=test_records[0])
st1.insert() st1.insert()
@ -22,7 +26,7 @@ class TestStockEntry(unittest.TestCase):
self.assertTrue(mr_name) 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.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)
@ -59,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 test_material_issue_gl_entry(self): def atest_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)
@ -147,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 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 # check gl entries
gl_entries = webnotes.conn.sql("""select account, debit, credit gl_entries = webnotes.conn.sql("""select account, debit, credit
@ -159,6 +163,394 @@ class TestStockEntry(unittest.TestCase):
self.assertEquals(expected_gl_entries[i][1], gle.debit) self.assertEquals(expected_gl_entries[i][1], gle.debit)
self.assertEquals(expected_gl_entries[i][2], gle.credit) self.assertEquals(expected_gl_entries[i][2], gle.credit)
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()
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",
"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 \
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 = returned_qty
se.doclist[1].transfer_qty = returned_qty
self.assertRaises(NotUpdateStockError, se.insert)
self._insert_material_receipt()
# check currency available qty in bin
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 = 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 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)
# 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 = 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 = 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)
def test_sales_invoice_return_of_packing_item(self):
self._test_sales_invoice_return("_Test Sales BOM Item", 25, 20)
def _test_delivery_note_return(self, item_code, delivered_qty, returned_qty):
self._insert_material_receipt()
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()
dn.submit()
actual_qty_1 = self._get_actual_qty()
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-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_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):
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"))
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)
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)
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)
se = self._test_delivery_note_return_against_sales_order("_Test Item", 5, 2)
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)
se = self._test_delivery_note_return_against_sales_order("_Test Sales BOM Item", 25, 20)
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()
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()
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)
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"
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
def test_over_stock_return(self):
from stock.doctype.stock_entry.stock_entry import StockOverReturnError
# out of 10, 5 gets returned
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])
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)
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)
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"))
def test_make_return_jv_for_purchase_receipt(self):
se, pr_name = self.test_purchase_receipt_return()
self._test_purchase_return_jv(se)
se, pr_name = self._test_purchase_return_return_against_purchase_order()
self._test_purchase_return_jv(se)
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 = [ test_records = [
[ [
{ {
@ -168,6 +560,7 @@ test_records = [
"posting_time": "17:14:24", "posting_time": "17:14:24",
"purpose": "Material Receipt", "purpose": "Material Receipt",
"fiscal_year": "_Test Fiscal Year 2013", "fiscal_year": "_Test Fiscal Year 2013",
"expense_adjustment_account": "Stock Adjustment - _TC"
}, },
{ {
"conversion_factor": 1.0, "conversion_factor": 1.0,
@ -190,6 +583,7 @@ test_records = [
"posting_time": "17:15", "posting_time": "17:15",
"purpose": "Material Issue", "purpose": "Material Issue",
"fiscal_year": "_Test Fiscal Year 2013", "fiscal_year": "_Test Fiscal Year 2013",
"expense_adjustment_account": "Stock Adjustment - _TC"
}, },
{ {
"conversion_factor": 1.0, "conversion_factor": 1.0,
@ -212,6 +606,7 @@ test_records = [
"posting_time": "17:14:24", "posting_time": "17:14:24",
"purpose": "Material Transfer", "purpose": "Material Transfer",
"fiscal_year": "_Test Fiscal Year 2013", "fiscal_year": "_Test Fiscal Year 2013",
"expense_adjustment_account": "Stock Adjustment - _TC"
}, },
{ {
"conversion_factor": 1.0, "conversion_factor": 1.0,

View File

@ -215,6 +215,7 @@ class DocType:
"sle_id": sle_id, "sle_id": sle_id,
"is_amended": is_amended "is_amended": is_amended
}) })
get_obj('Warehouse', v["warehouse"]).update_bin(args) get_obj('Warehouse', v["warehouse"]).update_bin(args)

View File

@ -18,6 +18,44 @@ wn.require("public/app/js/controllers/stock_controller.js");
wn.provide("erpnext.stock"); wn.provide("erpnext.stock");
erpnext.stock.StockReconciliation = erpnext.stock.StockController.extend({ erpnext.stock.StockReconciliation = erpnext.stock.StockController.extend({
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() { refresh: function() {
if(this.frm.doc.docstatus===0) { if(this.frm.doc.docstatus===0) {
this.show_download_template(); this.show_download_template();

View File

@ -18,22 +18,26 @@ from __future__ import unicode_literals
import webnotes import webnotes
import json import json
from webnotes import msgprint, _ from webnotes import msgprint, _
from webnotes.utils import cstr, flt from webnotes.utils import cstr, flt, cint
from webnotes.model.controller import DocListController
from stock.stock_ledger import update_entries_after from stock.stock_ledger import update_entries_after
from controllers.stock_controller import StockController
class DocType(DocListController): class DocType(StockController):
def setup(self): def setup(self):
self.head_row = ["Item Code", "Warehouse", "Quantity", "Valuation Rate"] self.head_row = ["Item Code", "Warehouse", "Quantity", "Valuation Rate"]
self.entries = []
def validate(self): def validate(self):
self.validate_data() self.validate_data()
def on_submit(self): def on_submit(self):
self.insert_stock_ledger_entries() self.insert_stock_ledger_entries()
self.set_stock_value_difference()
self.make_gl_entries()
def on_cancel(self): def on_cancel(self):
self.delete_stock_ledger_entries() self.delete_stock_ledger_entries()
self.make_gl_entries()
def validate_data(self): def validate_data(self):
if not self.doc.reconciliation_json: if not self.doc.reconciliation_json:
@ -134,6 +138,7 @@ class DocType(DocListController):
data = json.loads(self.doc.reconciliation_json) data = json.loads(self.doc.reconciliation_json)
for row_num, row in enumerate(data[data.index(self.head_row)+1:]): for row_num, row in enumerate(data[data.index(self.head_row)+1:]):
row = webnotes._dict(zip(row_template, row)) row = webnotes._dict(zip(row_template, row))
row["row_num"] = row_num
previous_sle = get_previous_sle({ previous_sle = get_previous_sle({
"item_code": row.item_code, "item_code": row.item_code,
"warehouse": row.warehouse, "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): def sle_for_moving_avg(self, row, previous_sle, change_in_qty, change_in_rate):
"""Insert Stock Ledger Entries for Moving Average valuation""" """Insert Stock Ledger Entries for Moving Average valuation"""
def _get_incoming_rate(qty, valuation_rate, previous_qty, def _get_incoming_rate(qty, valuation_rate, previous_qty, previous_valuation_rate):
previous_valuation_rate):
if previous_valuation_rate == 0: if previous_valuation_rate == 0:
return flt(valuation_rate) return flt(valuation_rate)
else: else:
@ -178,8 +182,8 @@ class DocType(DocListController):
flt(previous_sle.get("qty_after_transaction")), flt(previous_sle.get("qty_after_transaction")),
flt(previous_sle.get("valuation_rate"))) flt(previous_sle.get("valuation_rate")))
self.insert_entries({"actual_qty": change_in_qty, row["voucher_detail_no"] = "Row: " + cstr(row.row_num) + "/Actual Entry"
"incoming_rate": incoming_rate}, row) 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: elif change_in_rate and flt(previous_sle.get("qty_after_transaction")) > 0:
# if no change in qty, but change in rate # if no change in qty, but change in rate
@ -190,9 +194,11 @@ class DocType(DocListController):
flt(previous_sle.get("valuation_rate"))) flt(previous_sle.get("valuation_rate")))
# +1 entry # +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) self.insert_entries({"actual_qty": 1, "incoming_rate": incoming_rate}, row)
# -1 entry # -1 entry
row["voucher_detail_no"] = "Row: " + cstr(row.row_num) + "/Valuation Adjustment -1"
self.insert_entries({"actual_qty": -1}, row) self.insert_entries({"actual_qty": -1}, row)
def sle_for_fifo(self, row, previous_sle, change_in_qty, change_in_rate): def sle_for_fifo(self, row, previous_sle, change_in_qty, change_in_rate):
@ -206,13 +212,15 @@ class DocType(DocListController):
if previous_stock_queue != [[row.qty, row.valuation_rate]]: if previous_stock_queue != [[row.qty, row.valuation_rate]]:
# make entry as per attachment # make entry as per attachment
if row.qty: if row.qty:
row["voucher_detail_no"] = "Row: " + cstr(row.row_num) + "/Actual Entry"
self.insert_entries({"actual_qty": row.qty, self.insert_entries({"actual_qty": row.qty,
"incoming_rate": flt(row.valuation_rate)}, row) "incoming_rate": flt(row.valuation_rate)}, row)
# Make reverse entry # Make reverse entry
if previous_stock_qty: if previous_stock_qty:
row["voucher_detail_no"] = "Row: " + cstr(row.row_num) + "/Reverse Entry"
self.insert_entries({"actual_qty": -1 * previous_stock_qty, self.insert_entries({"actual_qty": -1 * previous_stock_qty,
"incoming_rate": previous_stock_qty < 0 and \ "incoming_rate": previous_stock_qty < 0 and
flt(row.valuation_rate) or 0}, row) flt(row.valuation_rate) or 0}, row)
@ -221,8 +229,7 @@ class DocType(DocListController):
# dont want change in valuation # dont want change in valuation
if previous_stock_qty > 0: if previous_stock_qty > 0:
# set valuation_rate as previous valuation_rate # set valuation_rate as previous valuation_rate
row.valuation_rate = \ row.valuation_rate = previous_stock_value / flt(previous_stock_qty)
previous_stock_value / flt(previous_stock_qty)
_insert_entries() _insert_entries()
@ -235,7 +242,7 @@ class DocType(DocListController):
def insert_entries(self, opts, row): def insert_entries(self, opts, row):
"""Insert Stock Ledger Entries""" """Insert Stock Ledger Entries"""
args = { args = webnotes._dict({
"doctype": "Stock Ledger Entry", "doctype": "Stock Ledger Entry",
"item_code": row.item_code, "item_code": row.item_code,
"warehouse": row.warehouse, "warehouse": row.warehouse,
@ -243,9 +250,10 @@ class DocType(DocListController):
"posting_time": self.doc.posting_time, "posting_time": self.doc.posting_time,
"voucher_type": self.doc.doctype, "voucher_type": self.doc.doctype,
"voucher_no": self.doc.name, "voucher_no": self.doc.name,
"company": webnotes.conn.get_default("company"), "company": self.doc.company,
"is_cancelled": "No", "is_cancelled": "No",
} "voucher_detail_no": row.voucher_detail_no
})
args.update(opts) args.update(opts)
# create stock ledger entry # create stock ledger entry
sle_wrapper = webnotes.bean([args]) sle_wrapper = webnotes.bean([args])
@ -255,7 +263,8 @@ class DocType(DocListController):
# update bin # update bin
webnotes.get_obj('Warehouse', row.warehouse).update_bin(args) 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): def delete_stock_ledger_entries(self):
""" Delete Stock Ledger Entries related to this Stock Reconciliation """ Delete Stock Ledger Entries related to this Stock Reconciliation
@ -278,6 +287,32 @@ class DocType(DocListController):
"posting_time": self.doc.posting_time "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() @webnotes.whitelist()
def upload(): def upload():

View File

@ -1,8 +1,8 @@
[ [
{ {
"creation": "2013-01-19 10:23:35", "creation": "2013-01-22 16:50:41",
"docstatus": 0, "docstatus": 0,
"modified": "2013-01-22 14:57:24", "modified": "2013-03-18 12:48:42",
"modified_by": "Administrator", "modified_by": "Administrator",
"owner": "Administrator" "owner": "Administrator"
}, },
@ -30,6 +30,7 @@
"permlevel": 0 "permlevel": 0
}, },
{ {
"amend": 1,
"cancel": 1, "cancel": 1,
"create": 1, "create": 1,
"doctype": "DocPerm", "doctype": "DocPerm",
@ -40,6 +41,7 @@
"permlevel": 0, "permlevel": 0,
"read": 1, "read": 1,
"report": 1, "report": 1,
"role": "Material Manager",
"submit": 1, "submit": 1,
"write": 1 "write": 1
}, },
@ -79,6 +81,22 @@
"print_hide": 1, "print_hide": 1,
"read_only": 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", "doctype": "DocField",
"fieldname": "col1", "fieldname": "col1",
@ -119,12 +137,14 @@
"read_only": 1 "read_only": 1
}, },
{ {
"amend": 0, "doctype": "DocField",
"doctype": "DocPerm", "fieldname": "stock_value_difference",
"role": "Material Manager" "fieldtype": "Currency",
"hidden": 1,
"label": "Stock Value Difference",
"print_hide": 1
}, },
{ {
"doctype": "DocPerm", "doctype": "DocPerm"
"role": "System Manager"
} }
] ]

View File

@ -1,40 +1,15 @@
# ERPNext - web based ERP (http://erpnext.com) # ERPNext - web based ERP (http://erpnext.com)
# Copyright (C) 2012 Web Notes Technologies Pvt Ltd # For license information, please see license.txt
#
# 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 <http://www.gnu.org/licenses/>.
from __future__ import unicode_literals from __future__ import unicode_literals
import unittest import webnotes, unittest
import webnotes
from webnotes.tests import insert_test_data
from webnotes.utils import flt from webnotes.utils import flt
import json import json
from accounts.utils import get_fiscal_year
company = webnotes.conn.get_default("company")
class TestStockReconciliation(unittest.TestCase): 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): def test_reco_for_fifo(self):
webnotes.defaults.set_global_default("auto_inventory_accounting", 0)
# [[qty, valuation_rate, posting_date, # [[qty, valuation_rate, posting_date,
# posting_time, expected_stock_value, bin_qty, bin_valuation]] # posting_time, expected_stock_value, bin_qty, bin_valuation]]
input_data = [ input_data = [
@ -53,28 +28,32 @@ class TestStockReconciliation(unittest.TestCase):
] ]
for d in input_data: for d in input_data:
self.cleanup_data()
self.insert_existing_sle("FIFO") self.insert_existing_sle("FIFO")
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
res = webnotes.conn.sql("""select stock_value from `tabStock Ledger Entry` 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""", and posting_date = %s and posting_time = %s order by name desc limit 1""",
(d[2], d[3])) (d[2], d[3]))
self.assertEqual(res and flt(res[0][0]) or 0, d[4]) 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` 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]]) self.assertEqual(bin and [flt(bin[0][0]), flt(bin[0][1])] or [], [d[5], d[6]])
# no gl entries
self.tearDown() gl_entries = webnotes.conn.sql("""select name from `tabGL Entry`
self.setUp() where voucher_type = 'Stock Reconciliation' and voucher_no = %s""",
stock_reco.doc.name)
self.assertFalse(gl_entries)
def test_reco_for_moving_average(self): def test_reco_for_moving_average(self):
webnotes.defaults.set_global_default("auto_inventory_accounting", 0)
# [[qty, valuation_rate, posting_date, # [[qty, valuation_rate, posting_date,
# posting_time, expected_stock_value, bin_qty, bin_valuation]] # posting_time, expected_stock_value, bin_qty, bin_valuation]]
input_data = [ input_data = [
@ -94,95 +73,194 @@ class TestStockReconciliation(unittest.TestCase):
] ]
for d in input_data: for d in input_data:
self.cleanup_data()
self.insert_existing_sle("Moving Average") 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` 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""", and posting_date = %s and posting_time = %s order by name desc limit 1""",
(d[2], d[3])) (d[2], d[3]))
self.assertEqual(res and flt(res[0][0], 4) or 0, d[4]) 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` 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 [], self.assertEqual(bin and [flt(bin[0][0]), flt(bin[0][1], 4)] or [],
[flt(d[5]), flt(d[6])]) [flt(d[5]), flt(d[6])])
self.tearDown() # no gl entries
self.setUp() 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): def submit_stock_reconciliation(self, qty, rate, posting_date, posting_time):
return webnotes.bean([{ stock_reco = webnotes.bean([{
"doctype": "Stock Reconciliation", "doctype": "Stock Reconciliation",
"name": "RECO-001",
"__islocal": 1,
"posting_date": posting_date, "posting_date": posting_date,
"posting_time": posting_time, "posting_time": posting_time,
"fiscal_year": get_fiscal_year(posting_date)[0],
"company": "_Test Company",
"expense_account": "Stock Adjustment - _TC",
"reconciliation_json": json.dumps([ "reconciliation_json": json.dumps([
["Item Code", "Warehouse", "Quantity", "Valuation Rate"], ["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): def check_gl_entries(self, voucher_no, stock_value_diff, cancel=None):
# create default warehouse stock_in_hand_account = webnotes.conn.get_value("Company", "_Test Company",
if not webnotes.conn.exists("Warehouse", "Default Warehouse"): "stock_in_hand_account")
webnotes.insert({"doctype": "Warehouse", debit_amount = stock_value_diff > 0 and stock_value_diff or 0.0
"warehouse_name": "Default Warehouse", credit_amount = stock_value_diff < 0 and abs(stock_value_diff) or 0.0
"warehouse_type": "Stores"})
# create UOM: Nos. expected_gl_entries = sorted([
if not webnotes.conn.exists("UOM", "Nos"): [stock_in_hand_account, debit_amount, credit_amount],
webnotes.insert({"doctype": "UOM", "uom_name": "Nos"}) ["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]
])
# create item groups and items gl_entries = webnotes.conn.sql("""select account, debit, credit
insert_test_data("Item Group", from `tabGL Entry` where voucher_type='Stock Reconciliation' and voucher_no=%s
sort_fn=lambda ig: (ig[0].get('parent_item_group'), ig[0].get('name'))) order by account asc, debit asc""", voucher_no, as_dict=1)
insert_test_data("Item") 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): 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) webnotes.conn.set_default("allow_negative_stock", 1)
existing_ledgers = [ existing_ledgers = [
{ {
"doctype": "Stock Ledger Entry", "__islocal": 1, "doctype": "Stock Ledger Entry", "__islocal": 1,
"voucher_type": "Stock Entry", "voucher_no": "TEST", "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", "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, "doctype": "Stock Ledger Entry", "__islocal": 1,
"voucher_type": "Stock Entry", "voucher_no": "TEST", "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", "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, "doctype": "Stock Ledger Entry", "__islocal": 1,
"voucher_type": "Stock Entry", "voucher_no": "TEST", "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", "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, "doctype": "Stock Ledger Entry", "__islocal": 1,
"voucher_type": "Stock Entry", "voucher_no": "TEST", "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", "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, "doctype": "Stock Ledger Entry", "__islocal": 1,
"voucher_type": "Stock Entry", "voucher_no": "TEST", "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", "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) webnotes.get_obj("Stock Ledger").update_stock(existing_ledgers)
test_dependencies = ["Item", "Warehouse"]

View File

@ -95,12 +95,6 @@ wn.module_page["Stock"] = [
description: wn._("Change UOM for an Item."), description: wn._("Change UOM for an Item."),
"doctype": "Stock UOM Replace Utility" "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")
},
] ]
}, },
{ {

View File

@ -36,6 +36,7 @@ def update_entries_after(args, verbose=1):
} }
""" """
previous_sle = get_sle_before_datetime(args) previous_sle = get_sle_before_datetime(args)
qty_after_transaction = flt(previous_sle.get("qty_after_transaction")) qty_after_transaction = flt(previous_sle.get("qty_after_transaction"))
valuation_rate = flt(previous_sle.get("valuation_rate")) valuation_rate = flt(previous_sle.get("valuation_rate"))
stock_queue = json.loads(previous_sle.get("stock_queue") or "[]") stock_queue = json.loads(previous_sle.get("stock_queue") or "[]")
@ -71,7 +72,7 @@ def update_entries_after(args, verbose=1):
(qty_after_transaction * valuation_rate) or 0 (qty_after_transaction * valuation_rate) or 0
else: else:
stock_value = sum((flt(batch[0]) * flt(batch[1]) for batch in stock_queue)) 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 # update current sle
webnotes.conn.sql("""update `tabStock Ledger Entry` webnotes.conn.sql("""update `tabStock Ledger Entry`
set qty_after_transaction=%s, valuation_rate=%s, stock_queue=%s, set qty_after_transaction=%s, valuation_rate=%s, stock_queue=%s,
@ -127,7 +128,7 @@ def get_stock_ledger_entries(args, conditions=None, order="desc", limit=None, fo
if not args.get("posting_date"): if not args.get("posting_date"):
args["posting_date"] = "1900-01-01" args["posting_date"] = "1900-01-01"
if not args.get("posting_time"): 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` return webnotes.conn.sql("""select * from `tabStock Ledger Entry`
where item_code = %%(item_code)s where item_code = %%(item_code)s

View File

@ -165,8 +165,8 @@ def get_warehouse_list(doctype, txt, searchfield, start, page_len, filters):
return wlist return wlist
def get_buying_amount(item_code, warehouse, qty, voucher_type, voucher_no, voucher_detail_no, def get_buying_amount(item_code, warehouse, qty, voucher_type, voucher_no, voucher_detail_no,
stock_ledger_entries, item_sales_bom): stock_ledger_entries, item_sales_bom=None):
if item_sales_bom.get(item_code): if item_sales_bom and item_sales_bom.get(item_code):
# sales bom item # sales bom item
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]:
@ -182,12 +182,14 @@ def _get_buying_amount(voucher_type, voucher_no, item_row, item_code, warehouse,
stock_ledger_entries): stock_ledger_entries):
for i, sle in enumerate(stock_ledger_entries): for i, sle in enumerate(stock_ledger_entries):
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 \
len(stock_ledger_entries) > i+1: (sle.voucher_detail_no == item_row or (sle.voucher_type != "Stock Reconciliation"
if (sle.voucher_detail_no == item_row) or \ and sle.item_code == item_code and sle.warehouse == warehouse and flt(sle.qty) == qty)):
(sle.item_code == item_code and sle.warehouse == warehouse and \ # print "previous_sle", stock_ledger_entries[i+1]
abs(flt(sle.qty)) == qty): # print "current sle", sle
buying_amount = flt(stock_ledger_entries[i+1].stock_value) - \ previous_stock_value = len(stock_ledger_entries) > i+1 and \
flt(sle.stock_value) flt(stock_ledger_entries[i+1].stock_value) or 0.0
buying_amount = previous_stock_value - flt(sle.stock_value)
return buying_amount return buying_amount
return 0.0 return 0.0

View File

@ -16,7 +16,7 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import webnotes 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.doc import addchild
from webnotes.model.controller import DocListController from webnotes.model.controller import DocListController
@ -247,3 +247,7 @@ class TransactionBase(DocListController):
self.doclist.extend(webnotes.doclist([webnotes.doc(fielddata=d) \ self.doclist.extend(webnotes.doclist([webnotes.doc(fielddata=d) \
for d in comm_list])) 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')