Removed Sales/Purchase Return option from Stock Entry

This commit is contained in:
Nabin Hait
2015-07-17 16:28:10 +05:30
parent 1d21842f68
commit 623ed57663
5 changed files with 286 additions and 814 deletions

View File

@@ -81,20 +81,19 @@ class SerialNo(StockController):
def set_status(self, last_sle): def set_status(self, last_sle):
if last_sle: if last_sle:
if last_sle.voucher_type == "Stock Entry": if last_sle.voucher_type == "Stock Entry":
document_type = frappe.db.get_value("Stock Entry", last_sle.voucher_no, document_type = frappe.db.get_value("Stock Entry", last_sle.voucher_no, "purpose")
"purpose")
else: else:
document_type = last_sle.voucher_type document_type = last_sle.voucher_type
if last_sle.actual_qty > 0: if last_sle.actual_qty > 0:
if document_type == "Sales Return": if document_type in ("Delivery Note", "Sales Invoice", "Sales Return"):
self.status = "Sales Returned" self.status = "Sales Returned"
else: else:
self.status = "Available" self.status = "Available"
else: else:
if document_type == "Purchase Return": if document_type in ("Purchase Receipt", "Purchase Invoice", "Purchase Return"):
self.status = "Purchase Returned" self.status = "Purchase Returned"
elif last_sle.voucher_type in ("Delivery Note", "Sales Invoice"): elif document_type in ("Delivery Note", "Sales Invoice"):
self.status = "Delivered" self.status = "Delivered"
else: else:
self.status = "Not Available" self.status = "Not Available"

View File

@@ -7,20 +7,7 @@ frappe.provide("erpnext.stock");
erpnext.stock.StockEntry = erpnext.stock.StockController.extend({ erpnext.stock.StockEntry = erpnext.stock.StockController.extend({
setup: function() { setup: function() {
var me = this; var me = this;
this.frm.fields_dict.delivery_note_no.get_query = function() {
return { query: "erpnext.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 {
filters:{ 'docstatus': 1 }
};
};
this.frm.fields_dict.bom_no.get_query = function() { this.frm.fields_dict.bom_no.get_query = function() {
return { return {
filters:{ 'docstatus': 1 } filters:{ 'docstatus': 1 }
@@ -28,20 +15,7 @@ erpnext.stock.StockEntry = erpnext.stock.StockController.extend({
}; };
this.frm.fields_dict.items.grid.get_field('item_code').get_query = function() { this.frm.fields_dict.items.grid.get_field('item_code').get_query = function() {
if(in_list(["Sales Return", "Purchase Return"], me.frm.doc.purpose) && return erpnext.queries.item({is_stock_item: "Yes"});
me.get_doctype_docname()) {
return {
query: "erpnext.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"});
}
}; };
this.frm.set_query("purchase_order", function() { this.frm.set_query("purchase_order", function() {
@@ -84,19 +58,6 @@ erpnext.stock.StockEntry = erpnext.stock.StockController.extend({
this.toggle_enable_bom(); this.toggle_enable_bom();
this.show_stock_ledger(); this.show_stock_ledger();
this.show_general_ledger(); this.show_general_ledger();
if(this.frm.doc.docstatus === 1 && frappe.boot.user.can_create.indexOf("Journal Entry")!==-1
&& this.frm.doc.__onload.credit_debit_note_exists == 0 ) {
if(this.frm.doc.purpose === "Sales Return") {
this.frm.add_custom_button(__("Make Credit Note"),
function() { me.make_return_jv(); }, frappe.boot.doctype_icons["Journal Entry"]);
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(); }, frappe.boot.doctype_icons["Journal Entry"]);
this.add_excise_button();
}
}
}, },
on_submit: function() { on_submit: function() {
@@ -111,15 +72,10 @@ erpnext.stock.StockEntry = erpnext.stock.StockController.extend({
var me = this; var me = this;
if(cint(frappe.defaults.get_default("auto_accounting_for_stock")) && this.frm.doc.company) { if(cint(frappe.defaults.get_default("auto_accounting_for_stock")) && this.frm.doc.company) {
var account_for = "stock_adjustment_account";
if (this.frm.doc.purpose == "Purchase Return")
account_for = "stock_received_but_not_billed";
return this.frm.call({ return this.frm.call({
method: "erpnext.accounts.utils.get_company_default", method: "erpnext.accounts.utils.get_company_default",
args: { args: {
"fieldname": account_for, "fieldname": "stock_adjustment_account",
"company": this.frm.doc.company "company": this.frm.doc.company
}, },
callback: function(r) { callback: function(r) {
@@ -192,35 +148,6 @@ erpnext.stock.StockEntry = erpnext.stock.StockController.extend({
this.frm.toggle_enable("bom_no", !in_list(["Manufacture", "Material Transfer for Manufacture"], this.frm.doc.purpose)); this.frm.toggle_enable("bom_no", !in_list(["Manufacture", "Material Transfer for Manufacture"], this.frm.doc.purpose));
}, },
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(__("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(__("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(__("Please enter Purchase Receipt No to proceed"));
}
}
},
add_excise_button: function() { add_excise_button: function() {
if(frappe.boot.sysdefaults.country === "India") if(frappe.boot.sysdefaults.country === "India")
this.frm.add_custom_button(__("Make Excise Invoice"), function() { this.frm.add_custom_button(__("Make Excise Invoice"), function() {
@@ -231,37 +158,16 @@ erpnext.stock.StockEntry = erpnext.stock.StockController.extend({
}, frappe.boot.doctype_icons["Journal Entry"], "btn-default"); }, frappe.boot.doctype_icons["Journal Entry"], "btn-default");
}, },
make_return_jv: function() {
if(this.get_doctype_docname()) {
return this.frm.call({
method: "make_return_jv",
args: {
stock_entry: this.frm.doc.name
},
callback: function(r) {
if(!r.exc) {
var doclist = frappe.model.sync(r.message);
frappe.set_route("Form", doclist[0].doctype, doclist[0].name);
}
}
});
}
},
items_add: function(doc, cdt, cdn) { items_add: function(doc, cdt, cdn) {
var row = frappe.get_doc(cdt, cdn); var row = frappe.get_doc(cdt, cdn);
this.frm.script_manager.copy_from_first_row("items", row, this.frm.script_manager.copy_from_first_row("items", row, ["expense_account", "cost_center"]);
["expense_account", "cost_center"]);
if(!row.s_warehouse) row.s_warehouse = this.frm.doc.from_warehouse; if(!row.s_warehouse) row.s_warehouse = this.frm.doc.from_warehouse;
if(!row.t_warehouse) row.t_warehouse = this.frm.doc.to_warehouse; if(!row.t_warehouse) row.t_warehouse = this.frm.doc.to_warehouse;
}, },
source_mandatory: ["Material Issue", "Material Transfer", "Purchase Return", "Subcontract", source_mandatory: ["Material Issue", "Material Transfer", "Subcontract", "Material Transfer for Manufacture"],
"Material Transfer for Manufacture"], target_mandatory: ["Material Receipt", "Material Transfer", "Subcontract", "Material Transfer for Manufacture"],
target_mandatory: ["Material Receipt", "Material Transfer", "Sales Return", "Subcontract",
"Material Transfer for Manufacture"],
from_warehouse: function(doc) { from_warehouse: function(doc) {
var me = this; var me = this;
@@ -295,92 +201,21 @@ erpnext.stock.StockEntry = erpnext.stock.StockController.extend({
items_on_form_rendered: function(doc, grid_row) { items_on_form_rendered: function(doc, grid_row) {
erpnext.setup_serial_no(); erpnext.setup_serial_no();
},
customer: function() {
this.get_party_details({
party: this.frm.doc.customer,
party_type:"Customer",
doctype: this.frm.doc.doctype
});
},
supplier: function() {
this.get_party_details({
party: this.frm.doc.supplier,
party_type:"Supplier",
doctype: this.frm.doc.doctype
});
},
get_party_details: function(args) {
var me = this;
frappe.call({
method: "erpnext.accounts.party.get_party_details",
args: args,
callback: function(r) {
if(r.message) {
me.frm.set_value({
"customer_name": r.message["customer_name"],
"customer_address": r.message["address_display"]
});
}
}
});
},
delivery_note_no: function() {
this.get_party_details_from_against_voucher({
ref_dt: "Delivery Note",
ref_dn: this.frm.doc.delivery_note_no
})
},
sales_invoice_no: function() {
this.get_party_details_from_against_voucher({
ref_dt: "Sales Invoice",
ref_dn: this.frm.doc.sales_invoice_no
})
},
purchase_receipt_no: function() {
this.get_party_details_from_against_voucher({
ref_dt: "Purchase Receipt",
ref_dn: this.frm.doc.purchase_receipt_no
})
},
get_party_details_from_against_voucher: function(args) {
return this.frm.call({
method: "erpnext.stock.doctype.stock_entry.stock_entry.get_party_details",
args: args,
})
} }
}); });
cur_frm.script_manager.make(erpnext.stock.StockEntry); cur_frm.script_manager.make(erpnext.stock.StockEntry);
cur_frm.cscript.toggle_related_fields = function(doc) { cur_frm.cscript.toggle_related_fields = function(doc) {
disable_from_warehouse = inList(["Material Receipt", "Sales Return"], doc.purpose); cur_frm.toggle_enable("from_warehouse", doc.purpose!='Material Receipt');
disable_to_warehouse = inList(["Material Issue", "Purchase Return"], doc.purpose); cur_frm.toggle_enable("to_warehouse", doc.purpose!='Material Issue');
cur_frm.toggle_enable("from_warehouse", !disable_from_warehouse); cur_frm.fields_dict["items"].grid.set_column_disp("s_warehouse", doc.purpose!='Material Receipt');
cur_frm.toggle_enable("to_warehouse", !disable_to_warehouse); cur_frm.fields_dict["items"].grid.set_column_disp("t_warehouse", doc.purpose!='Material Issue');
cur_frm.fields_dict["items"].grid.set_column_disp("s_warehouse", !disable_from_warehouse);
cur_frm.fields_dict["items"].grid.set_column_disp("t_warehouse", !disable_to_warehouse);
cur_frm.cscript.toggle_enable_bom(); cur_frm.cscript.toggle_enable_bom();
if(doc.purpose == 'Purchase Return') { if (doc.purpose == 'Subcontract') {
doc.customer = doc.customer_name = doc.customer_address =
doc.delivery_note_no = doc.sales_invoice_no = null;
doc.bom_no = doc.production_order = doc.fg_completed_qty = null;
} else if(doc.purpose == 'Sales Return') {
doc.supplier=doc.supplier_name = doc.supplier_address = doc.purchase_receipt_no=null;
doc.bom_no = doc.production_order = doc.fg_completed_qty = null;
} else if (doc.purpose == 'Subcontract') {
doc.customer = doc.customer_name = doc.customer_address = doc.customer = doc.customer_name = doc.customer_address =
doc.delivery_note_no = doc.sales_invoice_no = null; doc.delivery_note_no = doc.sales_invoice_no = null;
} else { } else {
@@ -388,7 +223,7 @@ cur_frm.cscript.toggle_related_fields = function(doc) {
doc.delivery_note_no = doc.sales_invoice_no = doc.supplier = doc.delivery_note_no = doc.sales_invoice_no = doc.supplier =
doc.supplier_name = doc.supplier_address = doc.purchase_receipt_no = null; doc.supplier_name = doc.supplier_address = doc.purchase_receipt_no = null;
} }
if(in_list(["Material Receipt", "Sales Return", "Purchase Return"], doc.purpose)) { if(doc.purpose == "Material Receipt") {
cur_frm.set_value("from_bom", 0); cur_frm.set_value("from_bom", 0);
} }
} }
@@ -505,8 +340,6 @@ cur_frm.cscript.uom = function(doc, cdt, cdn) {
} }
cur_frm.cscript.validate = function(doc, cdt, cdn) { cur_frm.cscript.validate = function(doc, cdt, cdn) {
if($.inArray(cur_frm.doc.purpose, ["Purchase Return", "Sales Return"])!==-1)
validated = cur_frm.cscript.get_doctype_docname() ? true : false;
cur_frm.cscript.validate_items(doc); cur_frm.cscript.validate_items(doc);
} }
@@ -526,14 +359,6 @@ cur_frm.cscript.cost_center = function(doc, cdt, cdn) {
erpnext.utils.copy_value_in_all_row(doc, cdt, cdn, "items", "cost_center"); erpnext.utils.copy_value_in_all_row(doc, cdt, cdn, "items", "cost_center");
} }
cur_frm.fields_dict.customer.get_query = function(doc, cdt, cdn) {
return { query: "erpnext.controllers.queries.customer_query" }
}
cur_frm.fields_dict.supplier.get_query = function(doc, cdt, cdn) {
return { query: "erpnext.controllers.queries.supplier_query" }
}
cur_frm.cscript.company = function(doc, cdt, cdn) { cur_frm.cscript.company = function(doc, cdt, cdn) {
if(doc.company) { if(doc.company) {
erpnext.get_fiscal_year(doc.company, doc.posting_date, function() { erpnext.get_fiscal_year(doc.company, doc.posting_date, function() {

View File

@@ -54,7 +54,7 @@
"no_copy": 0, "no_copy": 0,
"oldfieldname": "purpose", "oldfieldname": "purpose",
"oldfieldtype": "Select", "oldfieldtype": "Select",
"options": "Material Issue\nMaterial Receipt\nMaterial Transfer\nMaterial Transfer for Manufacture\nManufacture\nRepack\nSubcontract\nSales Return\nPurchase Return", "options": "Material Issue\nMaterial Receipt\nMaterial Transfer\nMaterial Transfer for Manufacture\nManufacture\nRepack\nSubcontract",
"permlevel": 0, "permlevel": 0,
"print_hide": 0, "print_hide": 0,
"read_only": 0, "read_only": 0,
@@ -678,7 +678,7 @@
"is_submittable": 1, "is_submittable": 1,
"issingle": 0, "issingle": 0,
"max_attachments": 0, "max_attachments": 0,
"modified": "2015-07-13 05:28:26.085266", "modified": "2015-07-17 15:41:00.980883",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Stock", "module": "Stock",
"name": "Stock Entry", "name": "Stock Entry",
@@ -695,7 +695,7 @@
"print": 1, "print": 1,
"read": 1, "read": 1,
"report": 1, "report": 1,
"role": "Stock User", "role": "Material User",
"share": 1, "share": 1,
"submit": 1, "submit": 1,
"write": 1 "write": 1
@@ -741,7 +741,7 @@
"print": 1, "print": 1,
"read": 1, "read": 1,
"report": 1, "report": 1,
"role": "Stock Manager", "role": "Material Manager",
"share": 1, "share": 1,
"submit": 1, "submit": 1,
"write": 1 "write": 1

View File

@@ -4,10 +4,8 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import frappe import frappe
import frappe.defaults import frappe.defaults
from frappe.utils import cstr, cint, flt, comma_or, get_datetime, getdate
from frappe import _ from frappe import _
from frappe.utils import cstr, cint, flt, comma_or, get_datetime, getdate
from erpnext.stock.utils import get_incoming_rate from erpnext.stock.utils import get_incoming_rate
from erpnext.stock.stock_ledger import get_previous_sle, NegativeStockError from erpnext.stock.stock_ledger import get_previous_sle, NegativeStockError
from erpnext.controllers.queries import get_match_cond from erpnext.controllers.queries import get_match_cond
@@ -16,7 +14,6 @@ from erpnext.manufacturing.doctype.bom.bom import validate_bom_no
from erpnext.accounts.utils import validate_fiscal_year from erpnext.accounts.utils import validate_fiscal_year
class NotUpdateStockError(frappe.ValidationError): pass class NotUpdateStockError(frappe.ValidationError): pass
class StockOverReturnError(frappe.ValidationError): pass
class IncorrectValuationRateError(frappe.ValidationError): pass class IncorrectValuationRateError(frappe.ValidationError): pass
class DuplicateEntryForProductionOrderError(frappe.ValidationError): pass class DuplicateEntryForProductionOrderError(frappe.ValidationError): pass
class OperationsNotCompleteError(frappe.ValidationError): pass class OperationsNotCompleteError(frappe.ValidationError): pass
@@ -37,13 +34,6 @@ class StockEntry(StockController):
item.update(get_available_qty(item.item_code, item.update(get_available_qty(item.item_code,
item.s_warehouse)) item.s_warehouse))
count = frappe.db.exists({
"doctype": "Journal Entry",
"stock_entry":self.name,
"docstatus":1
})
self.get("__onload").credit_debit_note_exists = 1 if count else 0
def validate(self): def validate(self):
self.pro_doc = None self.pro_doc = None
if self.production_order: if self.production_order:
@@ -84,16 +74,13 @@ class StockEntry(StockController):
def validate_purpose(self): def validate_purpose(self):
valid_purposes = ["Material Issue", "Material Receipt", "Material Transfer", "Material Transfer for Manufacture", valid_purposes = ["Material Issue", "Material Receipt", "Material Transfer", "Material Transfer for Manufacture",
"Manufacture", "Repack", "Subcontract", "Sales Return", "Purchase Return"] "Manufacture", "Repack", "Subcontract"]
if self.purpose not in valid_purposes: if self.purpose not in valid_purposes:
frappe.throw(_("Purpose must be one of {0}").format(comma_or(valid_purposes))) frappe.throw(_("Purpose must be one of {0}").format(comma_or(valid_purposes)))
if self.purpose in ("Manufacture", "Repack", "Sales Return") and not self.difference_account: if self.purpose in ("Manufacture", "Repack") and not self.difference_account:
self.difference_account = frappe.db.get_value("Company", self.company, "default_expense_account") self.difference_account = frappe.db.get_value("Company", self.company, "default_expense_account")
if self.purpose in ("Purchase Return") and not self.difference_account:
frappe.throw(_("Difference Account mandatory for purpose '{0}'").format(self.purpose))
def set_transfer_qty(self): def set_transfer_qty(self):
for item in self.get("items"): for item in self.get("items"):
if not flt(item.qty): if not flt(item.qty):
@@ -122,7 +109,7 @@ class StockEntry(StockController):
if not item.transfer_qty: if not item.transfer_qty:
item.transfer_qty = item.qty * item.conversion_factor item.transfer_qty = item.qty * item.conversion_factor
if (self.purpose in ("Material Transfer", "Sales Return", "Purchase Return", "Material Transfer for Manufacture") if (self.purpose in ("Material Transfer", "Material Transfer for Manufacture")
and not item.serial_no and not item.serial_no
and item.item_code in serialized_items): and item.item_code in serialized_items):
frappe.throw(_("Row #{0}: Please specify Serial No for Item {1}").format(item.idx, item.item_code), frappe.throw(_("Row #{0}: Please specify Serial No for Item {1}").format(item.idx, item.item_code),
@@ -131,8 +118,8 @@ class StockEntry(StockController):
def validate_warehouse(self): def validate_warehouse(self):
"""perform various (sometimes conditional) validations on warehouse""" """perform various (sometimes conditional) validations on warehouse"""
source_mandatory = ["Material Issue", "Material Transfer", "Purchase Return", "Subcontract", "Material Transfer for Manufacture"] source_mandatory = ["Material Issue", "Material Transfer", "Subcontract", "Material Transfer for Manufacture"]
target_mandatory = ["Material Receipt", "Material Transfer", "Sales Return", "Subcontract", "Material Transfer for Manufacture"] target_mandatory = ["Material Receipt", "Material Transfer", "Subcontract", "Material Transfer for Manufacture"]
validate_for_manufacture_repack = any([d.bom_no for d in self.get("items")]) validate_for_manufacture_repack = any([d.bom_no for d in self.get("items")])
@@ -291,8 +278,8 @@ class StockEntry(StockController):
# get incoming rate # get incoming rate
if not d.bom_no: if not d.bom_no:
if not flt(d.incoming_rate) or d.s_warehouse or self.purpose == "Sales Return" or force: if not flt(d.incoming_rate) or d.s_warehouse or force:
incoming_rate = flt(self.get_incoming_rate(args), self.precision("incoming_rate", d)) incoming_rate = flt(get_incoming_rate(args), self.precision("incoming_rate", d))
if incoming_rate > 0: if incoming_rate > 0:
d.incoming_rate = incoming_rate d.incoming_rate = incoming_rate
@@ -336,27 +323,6 @@ class StockEntry(StockController):
return operation_cost_per_unit + (flt(self.additional_operating_cost) / flt(qty)) return operation_cost_per_unit + (flt(self.additional_operating_cost) / flt(qty))
def get_incoming_rate(self, args):
incoming_rate = 0
if self.purpose == "Sales Return":
incoming_rate = self.get_incoming_rate_for_sales_return(args)
else:
incoming_rate = get_incoming_rate(args)
return incoming_rate
def get_incoming_rate_for_sales_return(self, args):
incoming_rate = 0.0
if (self.delivery_note_no or self.sales_invoice_no) and args.get("item_code"):
incoming_rate = frappe.db.sql("""select abs(ifnull(stock_value_difference, 0) / actual_qty)
from `tabStock Ledger Entry`
where voucher_type = %s and voucher_no = %s and item_code = %s limit 1""",
((self.delivery_note_no and "Delivery Note" or "Sales Invoice"),
self.delivery_note_no or self.sales_invoice_no, args.item_code))
incoming_rate = incoming_rate[0][0] if incoming_rate else 0.0
return incoming_rate
def validate_purchase_order(self): def validate_purchase_order(self):
"""Throw exception if more raw material is transferred against Purchase Order than in """Throw exception if more raw material is transferred against Purchase Order than in
the raw materials supplied table""" the raw materials supplied table"""
@@ -403,55 +369,6 @@ class StockEntry(StockController):
frappe.throw(_("Finished Item {0} must be entered for Manufacture type entry") frappe.throw(_("Finished Item {0} must be entered for Manufacture type entry")
.format(production_item)) .format(production_item))
def validate_return_reference_doc(self):
"""validate item with reference doc"""
ref = get_return_doc_and_details(self)
if ref.doc:
# validate docstatus
if ref.doc.docstatus != 1:
frappe.throw(_("{0} {1} must be submitted").format(ref.doc.doctype, ref.doc.name),
frappe.InvalidStatusError)
# update stock check
if ref.doc.doctype == "Sales Invoice" and cint(ref.doc.update_stock) != 1:
frappe.throw(_("'Update Stock' for Sales Invoice {0} must be set").format(ref.doc.name), NotUpdateStockError)
# posting date check
ref_posting_datetime = "%s %s" % (ref.doc.posting_date, ref.doc.posting_time or "00:00:00")
if get_datetime(ref_posting_datetime) < get_datetime(ref_posting_datetime):
from frappe.utils.dateutils import datetime_in_user_format
frappe.throw(_("Posting timestamp must be after {0}")
.format(datetime_in_user_format(ref_posting_datetime)))
stock_items = get_stock_items_for_return(ref.doc, ref.parentfields)
already_returned_item_qty = self.get_already_returned_item_qty(ref.fieldname)
for item in self.get("items"):
# validate if item exists in the ref doc and that it is a stock item
if item.item_code not in stock_items:
frappe.throw(_("Item {0} does not exist in {1} {2}").format(item.item_code, ref.doc.doctype, ref.doc.name),
frappe.DoesNotExistError)
# validate quantity <= ref item's qty - qty already returned
if self.purpose == "Purchase Return":
ref_item_qty = sum([flt(d.qty)*flt(d.conversion_factor) for d in ref.doc.get({"item_code": item.item_code})])
elif self.purpose == "Sales Return":
ref_item_qty = sum([flt(d.qty) for d in ref.doc.get({"item_code": item.item_code})])
returnable_qty = ref_item_qty - flt(already_returned_item_qty.get(item.item_code))
if not returnable_qty:
frappe.throw(_("Item {0} has already been returned").format(item.item_code), StockOverReturnError)
elif item.transfer_qty > returnable_qty:
frappe.throw(_("Cannot return more than {0} for Item {1}").format(returnable_qty, item.item_code),
StockOverReturnError)
def get_already_returned_item_qty(self, ref_fieldname):
return dict(frappe.db.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.get(ref_fieldname),)))
def update_stock_ledger(self): def update_stock_ledger(self):
sl_entries = [] sl_entries = []
for d in self.get('items'): for d in self.get('items'):
@@ -514,6 +431,7 @@ class StockEntry(StockController):
(args.get('item_code')), as_dict = 1) (args.get('item_code')), as_dict = 1)
if not item: if not item:
frappe.throw(_("Item {0} is not active or end of life has been reached").format(args.get("item_code"))) frappe.throw(_("Item {0} is not active or end of life has been reached").format(args.get("item_code")))
item = item[0] item = item[0]
ret = { ret = {
@@ -561,7 +479,7 @@ class StockEntry(StockController):
ret = { ret = {
"actual_qty" : get_previous_sle(args).get("qty_after_transaction") or 0, "actual_qty" : get_previous_sle(args).get("qty_after_transaction") or 0,
"incoming_rate" : self.get_incoming_rate(args) "incoming_rate" : get_incoming_rate(args)
} }
return ret return ret
@@ -738,15 +656,6 @@ class StockEntry(StockController):
if getdate(self.posting_date) > getdate(expiry_date): if getdate(self.posting_date) > getdate(expiry_date):
frappe.throw(_("Batch {0} of Item {1} has expired.").format(item.batch_no, item.item_code)) frappe.throw(_("Batch {0} of Item {1} has expired.").format(item.batch_no, item.item_code))
@frappe.whitelist()
def get_party_details(ref_dt, ref_dn):
if ref_dt in ["Delivery Note", "Sales Invoice"]:
res = frappe.db.get_value(ref_dt, ref_dn,
["customer", "customer_name", "address_display as customer_address"], as_dict=1)
else:
res = frappe.db.get_value(ref_dt, ref_dn,
["supplier", "supplier_name", "address_display as supplier_address"], as_dict=1)
return res or {}
@frappe.whitelist() @frappe.whitelist()
def get_production_order_details(production_order): def get_production_order_details(production_order):
@@ -756,264 +665,3 @@ def get_production_order_details(production_order):
from `tabProduction Order` where name = %s""", production_order, as_dict=1) from `tabProduction Order` where name = %s""", production_order, as_dict=1)
return res and res[0] or {} return res and res[0] or {}
def query_sales_return_doc(doctype, txt, searchfield, start, page_len, filters):
conditions = ""
if doctype == "Sales Invoice":
conditions = "and update_stock=1"
return frappe.db.sql("""select name, customer, customer_name
from `tab%s` where docstatus = 1
and (`%s` like %%(txt)s
or `customer` like %%(txt)s) %s %s
order by name, customer, customer_name
limit %s""" % (doctype, searchfield, conditions,
get_match_cond(doctype), "%(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 frappe.db.sql("""select name, supplier, supplier_name
from `tab%s` where docstatus = 1
and (`%s` like %%(txt)s
or `supplier` like %%(txt)s) %s
order by name, supplier, supplier_name
limit %s""" % (doctype, searchfield, get_match_cond(doctype),
"%(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_doc_and_details(filters)
stock_items = get_stock_items_for_return(ref.doc, ref.parentfields)
result = []
for item in ref.doc.get_all_children():
if getattr(item, "item_code", None) 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_doc, parentfields):
"""return item codes filtered from doc, which are stock items"""
if isinstance(parentfields, basestring):
parentfields = [parentfields]
all_items = list(set([d.item_code for d in
ref_doc.get_all_children() if d.get("item_code")]))
stock_items = frappe.db.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_doc_and_details(args):
ref = frappe._dict()
# get ref_doc
if args.get("purpose") in return_map:
for fieldname, val in return_map[args.get("purpose")].items():
if args.get(fieldname):
ref.fieldname = fieldname
ref.doc = frappe.get_doc(val[0], args.get(fieldname))
ref.parentfields = val[1]
break
return ref
return_map = {
"Sales Return": {
# [Ref DocType, [Item tables' parentfields]]
"delivery_note_no": ["Delivery Note", ["items", "packed_items"]],
"sales_invoice_no": ["Sales Invoice", ["items", "packed_items"]]
},
"Purchase Return": {
"purchase_receipt_no": ["Purchase Receipt", ["items"]]
}
}
@frappe.whitelist()
def make_return_jv(stock_entry):
se = frappe.get_doc("Stock Entry", stock_entry)
if not se.purpose in ["Sales Return", "Purchase Return"]:
return
ref = get_return_doc_and_details(se)
if ref.doc.doctype == "Delivery Note":
result = make_return_jv_from_delivery_note(se, ref)
elif ref.doc.doctype == "Sales Invoice":
result = make_return_jv_from_sales_invoice(se, ref)
elif ref.doc.doctype == "Purchase Receipt":
result = make_return_jv_from_purchase_receipt(se, ref)
# create jv doc and fetch balance for each unique row item
jv = frappe.new_doc("Journal Entry")
jv.update({
"posting_date": se.posting_date,
"voucher_type": se.purpose == "Sales Return" and "Credit Note" or "Debit Note",
"fiscal_year": se.fiscal_year,
"company": se.company,
"stock_entry": se.name
})
from erpnext.accounts.utils import get_balance_on
for r in result:
jv.append("accounts", {
"account": r.get("account"),
"party_type": r.get("party_type"),
"party": r.get("party"),
"balance": get_balance_on(r.get("account"), se.posting_date) if r.get("account") else 0
})
return jv
def make_return_jv_from_sales_invoice(se, ref):
# customer account entry
parent = {
"account": ref.doc.debit_to,
"party_type": "Customer",
"party": ref.doc.customer
}
# income account entries
children = []
for se_item in se.get("items"):
# find item in ref.doc
ref_item = ref.doc.get({"item_code": se_item.item_code})[0]
account = get_sales_account_from_item(ref.doc, ref_item)
if account not in children:
children.append(account)
return [parent] + [{"account": account} for account in children]
def get_sales_account_from_item(doc, ref_item):
account = None
if not getattr(ref_item, "income_account", None):
if ref_item.parent_item:
parent_item = doc.get("items", {"item_code": ref_item.parent_item})[0]
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.doc.name)
if not invoices_against_delivery:
sales_orders_against_delivery = [d.against_sales_order for d in ref.doc.get_all_children() if getattr(d, "against_sales_order", None)]
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.doc.get(ref.parentfields[1])])
parent = {}
children = []
for se_item in se.get("items"):
for sales_invoice in invoices_against_delivery:
si = frappe.get_doc("Sales Invoice", sales_invoice)
if se_item.item_code in packing_item_parent_map:
ref_item = si.get({"item_code": packing_item_parent_map[se_item.item_code]})
else:
ref_item = si.get({"item_code": se_item.item_code})
if not ref_item:
continue
ref_item = ref_item[0]
account = get_sales_account_from_item(si, ref_item)
if account not in children:
children.append(account)
if not parent:
parent = {
"account": si.debit_to,
"party_type": "Customer",
"party": si.customer
}
break
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 frappe.db.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.doc.name)
if not invoice_against_receipt:
purchase_orders_against_receipt = [d.prevdoc_docname for d in
ref.doc.get("items", {"prevdoc_doctype": "Purchase Order"})
if getattr(d, "prevdoc_docname", None)]
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.get("items"):
for purchase_invoice in invoice_against_receipt:
pi = frappe.get_doc("Purchase Invoice", purchase_invoice)
ref_item = pi.get({"item_code": se_item.item_code})
if not ref_item:
continue
ref_item = ref_item[0]
account = ref_item.expense_account
if account not in children:
children.append(account)
if not parent:
parent = {
"account": pi.credit_to,
"party_type": "Supplier",
"party": pi.supplier
}
break
result = [parent] + [{"account": account} for account in children]
return result

View File

@@ -303,262 +303,262 @@ class TestStockEntry(unittest.TestCase):
self.assertEquals(expected_gl_entries[i][1], gle[1]) self.assertEquals(expected_gl_entries[i][1], gle[1])
self.assertEquals(expected_gl_entries[i][2], gle[2]) self.assertEquals(expected_gl_entries[i][2], gle[2])
def _test_sales_invoice_return(self, item_code, delivered_qty, returned_qty): # def _test_sales_invoice_return(self, item_code, delivered_qty, returned_qty):
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice # from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
#
si = create_sales_invoice(item_code=item_code, qty=delivered_qty) # si = create_sales_invoice(item_code=item_code, qty=delivered_qty)
#
se = make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC", qty=returned_qty, # se = make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC", qty=returned_qty,
purpose="Sales Return", sales_invoice_no=si.name, do_not_save=True) # purpose="Sales Return", sales_invoice_no=si.name, do_not_save=True)
self.assertRaises(NotUpdateStockError, se.insert) # self.assertRaises(NotUpdateStockError, se.insert)
#
make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC", qty=200, incoming_rate=100) # make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC", qty=200, incoming_rate=100)
#
# check currency available qty in bin # # check currency available qty in bin
actual_qty_0 = get_qty_after_transaction() # actual_qty_0 = get_qty_after_transaction()
#
# insert a pos invoice with update stock # # insert a pos invoice with update stock
si = create_sales_invoice(update_stock=1, item_code=item_code, qty=5) # si = create_sales_invoice(update_stock=1, item_code=item_code, qty=5)
#
# check available bin qty after invoice submission # # check available bin qty after invoice submission
actual_qty_1 = get_qty_after_transaction() # actual_qty_1 = get_qty_after_transaction()
#
self.assertEquals(actual_qty_0 - delivered_qty, actual_qty_1) # self.assertEquals(actual_qty_0 - delivered_qty, actual_qty_1)
#
# check if item is validated # # check if item is validated
se = make_stock_entry(item_code="_Test Item Home Desktop 200", target="_Test Warehouse - _TC", # se = make_stock_entry(item_code="_Test Item Home Desktop 200", target="_Test Warehouse - _TC",
qty=returned_qty, purpose="Sales Return", sales_invoice_no=si.name, do_not_save=True) # qty=returned_qty, purpose="Sales Return", sales_invoice_no=si.name, do_not_save=True)
#
self.assertRaises(frappe.DoesNotExistError, se.insert) # self.assertRaises(frappe.DoesNotExistError, se.insert)
#
# try again # # try again
se = make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC", # se = make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC",
qty=returned_qty, purpose="Sales Return", sales_invoice_no=si.name) # qty=returned_qty, purpose="Sales Return", sales_invoice_no=si.name)
#
# check if available qty is increased # # check if available qty is increased
actual_qty_2 = get_qty_after_transaction() # actual_qty_2 = get_qty_after_transaction()
#
self.assertEquals(actual_qty_1 + returned_qty, actual_qty_2) # self.assertEquals(actual_qty_1 + returned_qty, actual_qty_2)
#
return se # return se
#
def test_sales_invoice_return_of_non_packing_item(self): # def test_sales_invoice_return_of_non_packing_item(self):
self._test_sales_invoice_return("_Test Item", 5, 2) # self._test_sales_invoice_return("_Test Item", 5, 2)
#
def test_sales_invoice_return_of_packing_item(self): # def test_sales_invoice_return_of_packing_item(self):
self._test_sales_invoice_return("_Test Product Bundle Item", 25, 20) # self._test_sales_invoice_return("_Test Product Bundle Item", 25, 20)
#
def _test_delivery_note_return(self, item_code, delivered_qty, returned_qty): # def _test_delivery_note_return(self, item_code, delivered_qty, returned_qty):
from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note # from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note
#
from erpnext.stock.doctype.delivery_note.delivery_note import make_sales_invoice # from erpnext.stock.doctype.delivery_note.delivery_note import make_sales_invoice
#
make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC", qty=50, incoming_rate=100) # make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC", qty=50, incoming_rate=100)
#
actual_qty_0 = get_qty_after_transaction() # actual_qty_0 = get_qty_after_transaction()
# make a delivery note based on this invoice # # make a delivery note based on this invoice
dn = create_delivery_note(item_code="_Test Item", # dn = create_delivery_note(item_code="_Test Item",
warehouse="_Test Warehouse - _TC", qty=delivered_qty) # warehouse="_Test Warehouse - _TC", qty=delivered_qty)
#
actual_qty_1 = get_qty_after_transaction() # actual_qty_1 = get_qty_after_transaction()
#
self.assertEquals(actual_qty_0 - delivered_qty, actual_qty_1) # self.assertEquals(actual_qty_0 - delivered_qty, actual_qty_1)
#
si = make_sales_invoice(dn.name) # si = make_sales_invoice(dn.name)
si.insert() # si.insert()
si.submit() # si.submit()
#
# insert and submit stock entry for sales return # # insert and submit stock entry for sales return
se = make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC", # se = make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC",
qty=returned_qty, purpose="Sales Return", delivery_note_no=dn.name) # qty=returned_qty, purpose="Sales Return", delivery_note_no=dn.name)
#
actual_qty_2 = get_qty_after_transaction() # actual_qty_2 = get_qty_after_transaction()
self.assertEquals(actual_qty_1 + returned_qty, actual_qty_2) # self.assertEquals(actual_qty_1 + returned_qty, actual_qty_2)
#
return se # return se
#
def test_delivery_note_return_of_non_packing_item(self): # def test_delivery_note_return_of_non_packing_item(self):
self._test_delivery_note_return("_Test Item", 5, 2) # self._test_delivery_note_return("_Test Item", 5, 2)
#
def test_delivery_note_return_of_packing_item(self): # def test_delivery_note_return_of_packing_item(self):
self._test_delivery_note_return("_Test Product Bundle Item", 25, 20) # self._test_delivery_note_return("_Test Product Bundle Item", 25, 20)
#
def _test_sales_return_jv(self, se): # def _test_sales_return_jv(self, se):
jv = make_return_jv(se.name) # jv = make_return_jv(se.name)
#
self.assertEqual(len(jv.get("accounts")), 2) # self.assertEqual(len(jv.get("accounts")), 2)
self.assertEqual(jv.get("voucher_type"), "Credit Note") # self.assertEqual(jv.get("voucher_type"), "Credit Note")
self.assertEqual(jv.get("posting_date"), getdate(se.posting_date)) # self.assertEqual(jv.get("posting_date"), getdate(se.posting_date))
self.assertEqual(jv.get("accounts")[0].get("account"), "Debtors - _TC") # self.assertEqual(jv.get("accounts")[0].get("account"), "Debtors - _TC")
self.assertEqual(jv.get("accounts")[0].get("party_type"), "Customer") # self.assertEqual(jv.get("accounts")[0].get("party_type"), "Customer")
self.assertEqual(jv.get("accounts")[0].get("party"), "_Test Customer") # self.assertEqual(jv.get("accounts")[0].get("party"), "_Test Customer")
self.assertEqual(jv.get("accounts")[1].get("account"), "Sales - _TC") # self.assertEqual(jv.get("accounts")[1].get("account"), "Sales - _TC")
#
def test_make_return_jv_for_sales_invoice_non_packing_item(self): # def test_make_return_jv_for_sales_invoice_non_packing_item(self):
se = self._test_sales_invoice_return("_Test Item", 5, 2) # se = self._test_sales_invoice_return("_Test Item", 5, 2)
self._test_sales_return_jv(se) # self._test_sales_return_jv(se)
#
def test_make_return_jv_for_sales_invoice_packing_item(self): # def test_make_return_jv_for_sales_invoice_packing_item(self):
se = self._test_sales_invoice_return("_Test Product Bundle Item", 25, 20) # se = self._test_sales_invoice_return("_Test Product Bundle Item", 25, 20)
self._test_sales_return_jv(se) # self._test_sales_return_jv(se)
#
def test_make_return_jv_for_delivery_note_non_packing_item(self): # def test_make_return_jv_for_delivery_note_non_packing_item(self):
se = self._test_delivery_note_return("_Test Item", 5, 2) # se = self._test_delivery_note_return("_Test Item", 5, 2)
self._test_sales_return_jv(se) # self._test_sales_return_jv(se)
#
se = self._test_delivery_note_return_against_sales_order("_Test Item", 5, 2) # se = self._test_delivery_note_return_against_sales_order("_Test Item", 5, 2)
self._test_sales_return_jv(se) # self._test_sales_return_jv(se)
#
def test_make_return_jv_for_delivery_note_packing_item(self): # def test_make_return_jv_for_delivery_note_packing_item(self):
se = self._test_delivery_note_return("_Test Product Bundle Item", 25, 20) # se = self._test_delivery_note_return("_Test Product Bundle Item", 25, 20)
self._test_sales_return_jv(se) # self._test_sales_return_jv(se)
#
se = self._test_delivery_note_return_against_sales_order("_Test Product Bundle Item", 25, 20) # se = self._test_delivery_note_return_against_sales_order("_Test Product Bundle Item", 25, 20)
self._test_sales_return_jv(se) # self._test_sales_return_jv(se)
#
def _test_delivery_note_return_against_sales_order(self, item_code, delivered_qty, returned_qty): # def _test_delivery_note_return_against_sales_order(self, item_code, delivered_qty, returned_qty):
from erpnext.selling.doctype.sales_order.sales_order import make_sales_invoice # from erpnext.selling.doctype.sales_order.sales_order import make_sales_invoice
#
actual_qty_0 = get_qty_after_transaction() # actual_qty_0 = get_qty_after_transaction()
#
so = make_sales_order(qty=50) # so = make_sales_order(qty=50)
#
dn = create_dn_against_so(so.name, delivered_qty) # dn = create_dn_against_so(so.name, delivered_qty)
#
actual_qty_1 = get_qty_after_transaction() # actual_qty_1 = get_qty_after_transaction()
self.assertEquals(actual_qty_0 - delivered_qty, actual_qty_1) # self.assertEquals(actual_qty_0 - delivered_qty, actual_qty_1)
#
si = make_sales_invoice(so.name) # si = make_sales_invoice(so.name)
si.insert() # si.insert()
si.submit() # si.submit()
#
# insert and submit stock entry for sales return # # insert and submit stock entry for sales return
se = make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC", # se = make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC",
qty=returned_qty, purpose="Sales Return", delivery_note_no=dn.name) # qty=returned_qty, purpose="Sales Return", delivery_note_no=dn.name)
#
actual_qty_2 = get_qty_after_transaction() # actual_qty_2 = get_qty_after_transaction()
self.assertEquals(actual_qty_1 + returned_qty, actual_qty_2) # self.assertEquals(actual_qty_1 + returned_qty, actual_qty_2)
#
return se # return se
#
def test_purchase_receipt_return(self): # def test_purchase_receipt_return(self):
actual_qty_0 = get_qty_after_transaction() # actual_qty_0 = get_qty_after_transaction()
#
# submit purchase receipt # # submit purchase receipt
pr = make_purchase_receipt(item_code="_Test Item", warehouse="_Test Warehouse - _TC", qty=5) # pr = make_purchase_receipt(item_code="_Test Item", warehouse="_Test Warehouse - _TC", qty=5)
#
actual_qty_1 = get_qty_after_transaction() # actual_qty_1 = get_qty_after_transaction()
#
self.assertEquals(actual_qty_0 + 5, actual_qty_1) # self.assertEquals(actual_qty_0 + 5, actual_qty_1)
#
pi_doc = make_purchase_invoice(pr.name) # pi_doc = make_purchase_invoice(pr.name)
#
pi = frappe.get_doc(pi_doc) # pi = frappe.get_doc(pi_doc)
pi.posting_date = pr.posting_date # pi.posting_date = pr.posting_date
pi.credit_to = "_Test Payable - _TC" # pi.credit_to = "_Test Payable - _TC"
for d in pi.get("items"): # for d in pi.get("items"):
d.expense_account = "_Test Account Cost for Goods Sold - _TC" # d.expense_account = "_Test Account Cost for Goods Sold - _TC"
d.cost_center = "_Test Cost Center - _TC" # d.cost_center = "_Test Cost Center - _TC"
#
for d in pi.get("taxes"): # for d in pi.get("taxes"):
d.cost_center = "_Test Cost Center - _TC" # d.cost_center = "_Test Cost Center - _TC"
#
pi.insert() # pi.insert()
pi.submit() # pi.submit()
#
# submit purchase return # # submit purchase return
se = make_stock_entry(item_code="_Test Item", source="_Test Warehouse - _TC", # se = make_stock_entry(item_code="_Test Item", source="_Test Warehouse - _TC",
qty=5, purpose="Purchase Return", purchase_receipt_no=pr.name) # qty=5, purpose="Purchase Return", purchase_receipt_no=pr.name)
#
actual_qty_2 = get_qty_after_transaction() # actual_qty_2 = get_qty_after_transaction()
#
self.assertEquals(actual_qty_1 - 5, actual_qty_2) # self.assertEquals(actual_qty_1 - 5, actual_qty_2)
#
return se, pr.name # return se, pr.name
#
def test_over_stock_return(self): # def test_over_stock_return(self):
from erpnext.stock.doctype.stock_entry.stock_entry import StockOverReturnError # from erpnext.stock.doctype.stock_entry.stock_entry import StockOverReturnError
#
# out of 10, 5 gets returned # # out of 10, 5 gets returned
prev_se, pr_docname = self.test_purchase_receipt_return() # prev_se, pr_docname = self.test_purchase_receipt_return()
#
se = make_stock_entry(item_code="_Test Item", source="_Test Warehouse - _TC", # se = make_stock_entry(item_code="_Test Item", source="_Test Warehouse - _TC",
qty=6, purpose="Purchase Return", purchase_receipt_no=pr_docname, do_not_save=True) # qty=6, purpose="Purchase Return", purchase_receipt_no=pr_docname, do_not_save=True)
#
self.assertRaises(StockOverReturnError, se.insert) # self.assertRaises(StockOverReturnError, se.insert)
#
def _test_purchase_return_jv(self, se): # def _test_purchase_return_jv(self, se):
jv = make_return_jv(se.name) # jv = make_return_jv(se.name)
#
self.assertEqual(len(jv.get("accounts")), 2) # self.assertEqual(len(jv.get("accounts")), 2)
self.assertEqual(jv.get("voucher_type"), "Debit Note") # self.assertEqual(jv.get("voucher_type"), "Debit Note")
self.assertEqual(jv.get("posting_date"), getdate(se.posting_date)) # self.assertEqual(jv.get("posting_date"), getdate(se.posting_date))
self.assertEqual(jv.get("accounts")[0].get("account"), "_Test Payable - _TC") # self.assertEqual(jv.get("accounts")[0].get("account"), "_Test Payable - _TC")
self.assertEqual(jv.get("accounts")[0].get("party"), "_Test Supplier") # self.assertEqual(jv.get("accounts")[0].get("party"), "_Test Supplier")
self.assertEqual(jv.get("accounts")[1].get("account"), "_Test Account Cost for Goods Sold - _TC") # self.assertEqual(jv.get("accounts")[1].get("account"), "_Test Account Cost for Goods Sold - _TC")
#
def test_make_return_jv_for_purchase_receipt(self): # def test_make_return_jv_for_purchase_receipt(self):
se, pr_name = self.test_purchase_receipt_return() # se, pr_name = self.test_purchase_receipt_return()
self._test_purchase_return_jv(se) # self._test_purchase_return_jv(se)
#
se, pr_name = self._test_purchase_return_return_against_purchase_order() # se, pr_name = self._test_purchase_return_return_against_purchase_order()
self._test_purchase_return_jv(se) # self._test_purchase_return_jv(se)
#
def _test_purchase_return_return_against_purchase_order(self): # def _test_purchase_return_return_against_purchase_order(self):
#
actual_qty_0 = get_qty_after_transaction() # actual_qty_0 = get_qty_after_transaction()
#
from erpnext.buying.doctype.purchase_order.test_purchase_order \ # from erpnext.buying.doctype.purchase_order.test_purchase_order \
import test_records as purchase_order_test_records # import test_records as purchase_order_test_records
#
from erpnext.buying.doctype.purchase_order.purchase_order import \ # from erpnext.buying.doctype.purchase_order.purchase_order import \
make_purchase_receipt, make_purchase_invoice # make_purchase_receipt, make_purchase_invoice
#
# submit purchase receipt # # submit purchase receipt
po = frappe.copy_doc(purchase_order_test_records[0]) # po = frappe.copy_doc(purchase_order_test_records[0])
po.transaction_date = nowdate() # po.transaction_date = nowdate()
po.is_subcontracted = None # po.is_subcontracted = None
po.get("items")[0].item_code = "_Test Item" # po.get("items")[0].item_code = "_Test Item"
po.get("items")[0].rate = 50 # po.get("items")[0].rate = 50
po.insert() # po.insert()
po.submit() # po.submit()
#
pr_doc = make_purchase_receipt(po.name) # pr_doc = make_purchase_receipt(po.name)
#
pr = frappe.get_doc(pr_doc) # pr = frappe.get_doc(pr_doc)
pr.posting_date = po.transaction_date # pr.posting_date = po.transaction_date
pr.insert() # pr.insert()
pr.submit() # pr.submit()
#
actual_qty_1 = get_qty_after_transaction() # actual_qty_1 = get_qty_after_transaction()
#
self.assertEquals(actual_qty_0 + 10, actual_qty_1) # self.assertEquals(actual_qty_0 + 10, actual_qty_1)
#
pi_doc = make_purchase_invoice(po.name) # pi_doc = make_purchase_invoice(po.name)
#
pi = frappe.get_doc(pi_doc) # pi = frappe.get_doc(pi_doc)
pi.posting_date = pr.posting_date # pi.posting_date = pr.posting_date
pi.credit_to = "_Test Payable - _TC" # pi.credit_to = "_Test Payable - _TC"
for d in pi.get("items"): # for d in pi.get("items"):
d.expense_account = "_Test Account Cost for Goods Sold - _TC" # d.expense_account = "_Test Account Cost for Goods Sold - _TC"
d.cost_center = "_Test Cost Center - _TC" # d.cost_center = "_Test Cost Center - _TC"
for d in pi.get("taxes"): # for d in pi.get("taxes"):
d.cost_center = "_Test Cost Center - _TC" # d.cost_center = "_Test Cost Center - _TC"
#
pi.run_method("calculate_taxes_and_totals") # pi.run_method("calculate_taxes_and_totals")
pi.bill_no = "NA" # pi.bill_no = "NA"
pi.insert() # pi.insert()
pi.submit() # pi.submit()
#
# submit purchase return # # submit purchase return
se = make_stock_entry(item_code="_Test Item", source="_Test Warehouse - _TC", # se = make_stock_entry(item_code="_Test Item", source="_Test Warehouse - _TC",
qty=5, purpose="Purchase Return", purchase_receipt_no=pr.name) # qty=5, purpose="Purchase Return", purchase_receipt_no=pr.name)
#
actual_qty_2 = get_qty_after_transaction() # actual_qty_2 = get_qty_after_transaction()
#
self.assertEquals(actual_qty_1 - 5, actual_qty_2) # self.assertEquals(actual_qty_1 - 5, actual_qty_2)
#
return se, pr.name # return se, pr.name
def test_serial_no_not_reqd(self): def test_serial_no_not_reqd(self):
se = frappe.copy_doc(test_records[0]) se = frappe.copy_doc(test_records[0])