validate over-return of stock for sales purchase return
diff --git a/stock/doctype/stock_entry/stock_entry.js b/stock/doctype/stock_entry/stock_entry.js
index 010b270..1581844 100644
--- a/stock/doctype/stock_entry/stock_entry.js
+++ b/stock/doctype/stock_entry/stock_entry.js
@@ -66,6 +66,17 @@
if (this.frm.doc.docstatus==1) {
this.show_stock_ledger();
}
+
+ if(this.frm.doc.docstatus === 1 && wn.boot.profile.can_create("Journal Voucher")) {
+ if(this.frm.doc.purpose === "Sales Return") {
+ this.frm.add_custom_button("Make Credit Note", this.make_return_jv);
+ this.add_excise_button();
+ } else if(this.frm.doc.purpose === "Purchase Return") {
+ this.frm.add_custom_button("Make Debit Note", this.make_return_jv);
+ this.add_excise_button();
+ }
+ }
+
},
on_submit: function() {
@@ -143,6 +154,29 @@
}
}
},
+
+ add_excise_button: function() {
+ if(wn.boot.control_panel.country === "India")
+ this.frm.add_custom_button("Make Excise Invoice", function() {
+ var excise = wn.model.make_new_doc_and_get_name('Journal Voucher');
+ excise = locals['Journal Voucher'][excise];
+ excise.voucher_type = 'Excise Voucher';
+ loaddoc('Journal Voucher', excise.name);
+ });
+ },
+
+ make_return_jv: function() {
+ this.frm.call({
+ method: "make_return_jv",
+ args: {
+ stock_entry: this.frm.doc.name
+ },
+ callback: function(r) {
+ console.log(r);
+ loaddoc("Journal Voucher", r.message);
+ }
+ });
+ },
});
diff --git a/stock/doctype/stock_entry/stock_entry.py b/stock/doctype/stock_entry/stock_entry.py
index 38ab5ba..80756b4 100644
--- a/stock/doctype/stock_entry/stock_entry.py
+++ b/stock/doctype/stock_entry/stock_entry.py
@@ -29,6 +29,7 @@
sql = webnotes.conn.sql
class NotUpdateStockError(webnotes.ValidationError): pass
+class StockOverReturnError(webnotes.ValidationError): pass
from controllers.accounts_controller import AccountsController
@@ -278,32 +279,24 @@
def validate_return_reference_doc(self):
"""validate item with reference doc"""
- ref_doclist = parentfields = None
+ ref = get_return_reference_details(self.doc.fields)
- # get ref_doclist
- if self.doc.purpose in return_map:
- for fieldname, val in return_map[self.doc.purpose].items():
- if self.doc.fields.get(fieldname):
- ref_doclist = webnotes.get_doclist(val[0], self.doc.fields[fieldname])
- parentfields = val[1]
-
- if ref_doclist:
+ if ref.doclist:
# validate docstatus
- if ref_doclist[0].docstatus != 1:
- webnotes.msgprint(_(ref_doclist[0].doctype) + ' "' + ref_doclist[0].name + '": '
+ if ref.doclist[0].docstatus != 1:
+ webnotes.msgprint(_(ref.doclist[0].doctype) + ' "' + ref.doclist[0].name + '": '
+ _("Status should be Submitted"), raise_exception=webnotes.InvalidStatusError)
-
# update stock check
- if ref_doclist[0].doctype == "Sales Invoice" and (cint(ref_doclist[0].is_pos) != 1 \
- or cint(ref_doclist[0].update_stock) != 1):
- webnotes.msgprint(_(ref_doclist[0].doctype) + ' "' + ref_doclist[0].name + '": '
+ if ref.doclist[0].doctype == "Sales Invoice" and (cint(ref.doclist[0].is_pos) != 1 \
+ or cint(ref.doclist[0].update_stock) != 1):
+ webnotes.msgprint(_(ref.doclist[0].doctype) + ' "' + ref.doclist[0].name + '": '
+ _("Is POS and Update Stock should be checked."),
raise_exception=NotUpdateStockError)
# posting date check
- ref_posting_datetime = "%s %s" % (cstr(ref_doclist[0].posting_date),
- cstr(ref_doclist[0].posting_time))
+ ref_posting_datetime = "%s %s" % (cstr(ref.doclist[0].posting_date),
+ cstr(ref.doclist[0].posting_time))
this_posting_datetime = "%s %s" % (cstr(self.doc.posting_date),
cstr(self.doc.posting_time))
if this_posting_datetime < ref_posting_datetime:
@@ -312,18 +305,27 @@
+ ": " + datetime_in_user_format(ref_posting_datetime),
raise_exception=True)
- stock_items = get_stock_items_for_return(ref_doclist, parentfields)
+ stock_items = get_stock_items_for_return(ref.doclist, ref.parentfields)
+ already_returned_item_qty = self.get_already_returned_item_qty(ref.fieldname)
for item in self.doclist.get({"parentfield": "mtn_details"}):
# validate if item exists in the ref doclist and that it is a stock item
if item.item_code not in stock_items:
msgprint(_("Item") + ': "' + item.item_code + _("\" does not exist in ") +
- ref_doclist[0].doctype + ": " + ref_doclist[0].name,
+ ref.doclist[0].doctype + ": " + ref.doclist[0].name,
raise_exception=webnotes.DoesNotExistError)
- # validate quantity <= ref item's qty
- ref_item = ref_doclist.getone({"item_code": item.item_code})
- self.validate_value("transfer_qty", "<=", ref_item.qty, item)
+ # validate quantity <= ref item's qty - qty already returned
+ ref_item = ref.doclist.getone({"item_code": item.item_code})
+ returnable_qty = ref_item.qty - flt(already_returned_item_qty.get(item.item_code))
+ self.validate_value("transfer_qty", "<=", returnable_qty, item,
+ raise_exception=StockOverReturnError)
+
+ def get_already_returned_item_qty(self, ref_fieldname):
+ return dict(webnotes.conn.sql("""select item_code, sum(transfer_qty) as qty
+ from `tabStock Entry Detail` where parent in (
+ select name from `tabStock Entry` where `%s`=%s and docstatus=1)
+ group by item_code""" % (ref_fieldname, "%s"), (self.doc.fields.get(ref_fieldname),)))
def update_serial_no(self, is_submit):
"""Create / Update Serial No"""
@@ -670,7 +672,7 @@
+ " " + _("Row #") + (" %d %s " % (mreq_item.idx, _("of")))
+ _("Material Request") + (" - %s" % item.material_request),
raise_exception=webnotes.MappingMismatchError)
-
+
@webnotes.whitelist()
def get_production_order_details(production_order):
result = webnotes.conn.sql("""select bom_no,
@@ -700,16 +702,13 @@
def query_return_item(doctype, txt, searchfield, start, page_len, filters):
txt = txt.replace("%", "")
-
- for fieldname, val in return_map[filters["purpose"]].items():
- if filters.get(fieldname):
- ref_doclist = webnotes.get_doclist(val[0], filters[fieldname])
- parentfields = val[1]
+
+ ref = get_return_reference_details(filters)
- stock_items = get_stock_items_for_return(ref_doclist, parentfields)
+ stock_items = get_stock_items_for_return(ref.doclist, ref.parentfields)
result = []
- for item in ref_doclist.get({"parentfield": ["in", parentfields]}):
+ for item in ref.doclist.get({"parentfield": ["in", ref.parentfields]}):
if item.item_code in stock_items:
item.item_name = cstr(item.item_name)
item.description = cstr(item.description)
@@ -738,6 +737,20 @@
return stock_items
+def get_return_reference_details(args):
+ ref = webnotes._dict()
+
+ # get ref_doclist
+ if args["purpose"] in return_map:
+ for fieldname, val in return_map[args["purpose"]].items():
+ if args.get(fieldname):
+ ref.fieldname = fieldname
+ ref.doclist = webnotes.get_doclist(val[0], args[fieldname])
+ ref.parentfields = val[1]
+ break
+
+ return ref
+
return_map = {
"Sales Return": {
# [Ref DocType, [Item tables' parentfields]]
@@ -748,3 +761,18 @@
"purchase_receipt_no": ["Purchase Receipt", ["purchase_receipt_details"]]
}
}
+
+def make_return_jv(stock_entry):
+ jv = webnotes.bean({
+ "doctype": "Journal Voucher",
+ "__islocal": 1
+ })
+
+ se = webnotes.bean("Stock Entry", stock_entry)
+
+ if not webnotes.response.get("docs"):
+ webnotes.response["docs"] = []
+
+ webnotes.response["docs"] = jv.doclist
+
+ return jv.doc.name
\ No newline at end of file
diff --git a/stock/doctype/stock_entry/test_stock_entry.py b/stock/doctype/stock_entry/test_stock_entry.py
index caf3291..c0f8f28 100644
--- a/stock/doctype/stock_entry/test_stock_entry.py
+++ b/stock/doctype/stock_entry/test_stock_entry.py
@@ -312,6 +312,23 @@
self.assertEquals(actual_qty_1 - 5, actual_qty_2)
+ return pr.doc.name
+
+ def test_over_stock_return(self):
+ from stock.doctype.stock_entry.stock_entry import StockOverReturnError
+
+ # out of 10, 5 gets returned
+ pr_docname = self.test_purchase_receipt_return()
+
+ # submit purchase return - return another 6 qtys so that exception is raised
+ se = webnotes.bean(copy=test_records[0])
+ se.doc.purpose = "Purchase Return"
+ se.doc.purchase_receipt_no = pr_docname
+ se.doc.posting_date = "2013-03-01"
+ se.doclist[1].qty = se.doclist[1].transfer_qty = 6
+ se.doclist[1].s_warehouse = "_Test Warehouse"
+
+ self.assertRaises(StockOverReturnError, se.insert)
test_records = [
[