Merge branch '4.0.0-cleanup' of github.com:webnotes/erpnext into 4.0.0-cleanup
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
index a9950ca..1cc64cb 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
@@ -33,6 +33,9 @@
}]
def validate(self):
+ if not self.doc.is_opening:
+ self.doc.is_opening = 'No'
+
super(DocType, self).validate()
self.po_required()
@@ -46,15 +49,8 @@
self.check_for_stopped_status()
self.validate_with_previous_doc()
self.validate_uom_is_integer("uom", "qty")
-
- if not self.doc.is_opening:
- self.doc.is_opening = 'No'
-
self.set_aging_date()
-
- #set against account for credit to
self.set_against_expense_account()
-
self.validate_write_off_account()
self.update_raw_material_cost()
self.update_valuation_rate("entries")
@@ -201,7 +197,8 @@
against_accounts = []
stock_items = self.get_stock_items()
for item in self.doclist.get({"parentfield": "entries"}):
- if auto_accounting_for_stock and item.item_code in stock_items:
+ if auto_accounting_for_stock and item.item_code in stock_items \
+ and self.doc.is_opening == 'No':
# in case of auto inventory accounting, against expense account is always
# Stock Received But Not Billed for a stock item
item.expense_head = stock_not_billed_account
diff --git a/erpnext/accounts/doctype/purchase_taxes_and_charges_master/purchase_taxes_and_charges_master.txt b/erpnext/accounts/doctype/purchase_taxes_and_charges_master/purchase_taxes_and_charges_master.txt
index bdaf00c..797b875 100644
--- a/erpnext/accounts/doctype/purchase_taxes_and_charges_master/purchase_taxes_and_charges_master.txt
+++ b/erpnext/accounts/doctype/purchase_taxes_and_charges_master/purchase_taxes_and_charges_master.txt
@@ -2,12 +2,13 @@
{
"creation": "2013-01-10 16:34:08",
"docstatus": 0,
- "modified": "2014-01-20 17:49:14",
+ "modified": "2014-01-28 12:28:56",
"modified_by": "Administrator",
"owner": "wasim@webnotestech.com"
},
{
"allow_import": 1,
+ "allow_rename": 1,
"autoname": "field:title",
"description": "Standard tax template that can be applied to all Purchase Transactions. This template can contain list of tax heads and also other expense heads like \"Shipping\", \"Insurance\", \"Handling\" etc.\n\n#### Note\n\nThe tax rate you define here will be the standard tax rate for all **Items**. If there are **Items** that have different rates, they must be added in the **Item Tax** table in the **Item** master.\n\n#### Description of Columns\n\n1. Calculation Type: \n - This can be on **Net Total** (that is the sum of basic amount).\n - **On Previous Row Total / Amount** (for cumulative taxes or charges). If you select this option, the tax will be applied as a percentage of the previous row (in the tax table) amount or total.\n - **Actual** (as mentioned).\n2. Account Head: The Account ledger under which this tax will be booked\n3. Cost Center: If the tax / charge is an income (like shipping) or expense it needs to be booked against a Cost Center.\n4. Description: Description of the tax (that will be printed in invoices / quotes).\n5. Rate: Tax rate.\n6. Amount: Tax amount.\n7. Total: Cumulative total to this point.\n8. Enter Row: If based on \"Previous Row Total\" you can select the row number which will be taken as a base for this calculation (default is the previous row).\n9. Consider Tax or Charge for: In this section you can specify if the tax / charge is only for valuation (not a part of total) or only for total (does not add value to the item) or for both.\n10. Add or Deduct: Whether you want to add or deduct the tax.",
"doctype": "DocType",
diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
index 3092477..2ed9847 100644
--- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
@@ -756,16 +756,18 @@
def _test_recurring_invoice(self, base_si, first_and_last_day):
from webnotes.utils import add_months, get_last_day
- from erpnext.accounts.doctype.sales_invoice.sales_invoice import manage_recurring_invoices
+ from erpnext.accounts.doctype.sales_invoice.sales_invoice \
+ import manage_recurring_invoices, get_next_date
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)
+ next_date = get_next_date(base_si.doc.posting_date, no_of_months,
+ base_si.doc.repeat_on_day_of_month)
+
manage_recurring_invoices(next_date=next_date, commit=False)
recurred_invoices = webnotes.conn.sql("""select name from `tabSales Invoice`
diff --git a/erpnext/accounts/doctype/sales_taxes_and_charges_master/sales_taxes_and_charges_master.txt b/erpnext/accounts/doctype/sales_taxes_and_charges_master/sales_taxes_and_charges_master.txt
index 11e3b31..db83cce 100644
--- a/erpnext/accounts/doctype/sales_taxes_and_charges_master/sales_taxes_and_charges_master.txt
+++ b/erpnext/accounts/doctype/sales_taxes_and_charges_master/sales_taxes_and_charges_master.txt
@@ -2,12 +2,13 @@
{
"creation": "2013-01-10 16:34:09",
"docstatus": 0,
- "modified": "2014-01-20 17:49:25",
+ "modified": "2014-01-28 12:28:27",
"modified_by": "Administrator",
"owner": "Administrator"
},
{
"allow_import": 1,
+ "allow_rename": 1,
"autoname": "field:title",
"description": "Standard tax template that can be applied to all Sales Transactions. This template can contain list of tax heads and also other expense / income heads like \"Shipping\", \"Insurance\", \"Handling\" etc.\n\n#### Note\n\nThe tax rate you define here will be the standard tax rate for all **Items**. If there are **Items** that have different rates, they must be added in the **Item Tax** table in the **Item** master.\n\n#### Description of Columns\n\n1. Calculation Type: \n - This can be on **Net Total** (that is the sum of basic amount).\n - **On Previous Row Total / Amount** (for cumulative taxes or charges). If you select this option, the tax will be applied as a percentage of the previous row (in the tax table) amount or total.\n - **Actual** (as mentioned).\n2. Account Head: The Account ledger under which this tax will be booked\n3. Cost Center: If the tax / charge is an income (like shipping) or expense it needs to be booked against a Cost Center.\n4. Description: Description of the tax (that will be printed in invoices / quotes).\n5. Rate: Tax rate.\n6. Amount: Tax amount.\n7. Total: Cumulative total to this point.\n8. Enter Row: If based on \"Previous Row Total\" you can select the row number which will be taken as a base for this calculation (default is the previous row).\n9. Is this Tax included in Basic Rate?: If you check this, it means that this tax will not be shown below the item table, but will be included in the Basic Rate in your main item table. This is useful where you want give a flat price (inclusive of all taxes) price to customers.",
"doctype": "DocType",
diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
index 085595e..19fda8e 100644
--- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
+++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
@@ -132,7 +132,7 @@
if not hasattr(self, "gl_entries"):
conditions, values = self.prepare_conditions()
self.gl_entries = webnotes.conn.sql("""select * from `tabGL Entry`
- where docstatus < 2 {} order by posting_date, account""".format(conditions),
+ where docstatus < 2 {0} order by posting_date, account""".format(conditions),
values, as_dict=True)
return self.gl_entries
@@ -153,8 +153,8 @@
if not account_map:
webnotes.throw(_("No Customer Accounts found."))
else:
- accounts_list = ['"{}"'.format(ac) for ac in account_map]
- conditions.append("account in ({})".format(", ".join(accounts_list)))
+ accounts_list = ['"{0}"'.format(ac) for ac in account_map]
+ conditions.append("account in ({0})".format(", ".join(accounts_list)))
return " and ".join(conditions), values
diff --git a/erpnext/patches/patch_list.py b/erpnext/patches/patch_list.py
index 6e27628..5c83ce1 100644
--- a/erpnext/patches/patch_list.py
+++ b/erpnext/patches/patch_list.py
@@ -271,4 +271,6 @@
"execute:webnotes.reload_doc('selling', 'doctype', 'quotation') # 2013-12-26",
"execute:webnotes.reload_doc('stock', 'doctype', 'delivery_note') # 2013-12-26",
"patches.1401.enable_all_price_list",
+ "patches.1401.fix_serial_no_status_and_warehouse",
+ "patches.1401.fix_planned_qty",
]
\ No newline at end of file
diff --git a/erpnext/public/js/queries.js b/erpnext/public/js/queries.js
index dbaa27d..19207e7 100644
--- a/erpnext/public/js/queries.js
+++ b/erpnext/public/js/queries.js
@@ -7,35 +7,35 @@
profile: function() {
return { query: "webnotes.core.doctype.profile.profile.profile_query" };
},
-
+
lead: function() {
return { query: "erpnext.controllers.queries.lead_query" };
},
-
+
customer: function() {
return { query: "erpnext.controllers.queries.customer_query" };
},
-
+
supplier: function() {
return { query: "erpnext.controllers.queries.supplier_query" };
},
-
+
account: function() {
return { query: "erpnext.controllers.queries.account_query" };
},
-
+
item: function() {
return { query: "erpnext.controllers.queries.item_query" };
},
-
+
bom: function() {
return { query: "erpnext.controllers.queries.bom" };
},
-
+
task: function() {
return { query: "projects.utils.query_task" };
},
-
+
customer_filter: function(doc) {
if(!doc.customer) {
wn.throw(wn._("Please specify a") + " " +
@@ -44,7 +44,7 @@
return { filters: { customer: doc.customer } };
},
-
+
supplier_filter: function(doc) {
if(!doc.supplier) {
wn.throw(wn._("Please specify a") + " " +
@@ -53,9 +53,17 @@
return { filters: { supplier: doc.supplier } };
},
-
+
+ lead_filter: function(doc) {
+ if(!doc.lead) {
+ wn.throw(wn._("Please specify a") + " " +
+ wn._(wn.meta.get_label(doc.doctype, "lead", doc.name)));
+ }
+
+ return { filters: { lead: doc.lead } };
+ },
+
not_a_group_filter: function() {
return { filters: { is_group: "No" } };
},
-
});
\ No newline at end of file
diff --git a/erpnext/public/js/utils/party.js b/erpnext/public/js/utils/party.js
index c068ff2..bda44ce 100644
--- a/erpnext/public/js/utils/party.js
+++ b/erpnext/public/js/utils/party.js
@@ -48,24 +48,29 @@
address_field = "supplier_address";
}
}
- wn.call({
- method: "erpnext.utilities.doctype.address.address.get_address_display",
- args: {address: frm.doc[address_field] },
- callback: function(r) {
- if(r.message)
- frm.set_value("address_display", r.message)
- }
- })
+ if(frm.doc[address_field]) {
+ wn.call({
+ method: "erpnext.utilities.doctype.address.address.get_address_display",
+ args: {address: frm.doc[address_field] },
+ callback: function(r) {
+ if(r.message)
+ frm.set_value("address_display", r.message)
+ }
+ })
+ }
}
erpnext.utils.get_contact_details = function(frm) {
if(frm.updating_party_details) return;
- wn.call({
- method: "erpnext.utilities.doctype.contact.contact.get_contact_details",
- args: {address: frm.doc.contact_person },
- callback: function(r) {
- if(r.message)
- frm.set_value(r.message);
- }
- })
+
+ if(frm.doc[address_field]) {
+ wn.call({
+ method: "erpnext.utilities.doctype.contact.contact.get_contact_details",
+ args: {contact: frm.doc.contact_person },
+ callback: function(r) {
+ if(r.message)
+ frm.set_value(r.message);
+ }
+ })
+ }
}
\ No newline at end of file
diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py
index aa28a19..c182c94 100644
--- a/erpnext/selling/doctype/customer/customer.py
+++ b/erpnext/selling/doctype/customer/customer.py
@@ -196,13 +196,14 @@
out[f] = customer.get("default_" + f)
# price list
- out.selling_price_list = webnotes.conn.get_defaults("selling_price_list", webnotes.session.user)
+ from webnotes.defaults import get_defaults_for
+ out.selling_price_list = get_defaults_for(webnotes.session.user).get(price_list)
if isinstance(out.selling_price_list, list):
out.selling_price_list = None
out.selling_price_list = out.selling_price_list or customer.price_list \
- or webnotes.conn.get_value("Customer Group", customer.customer_group, "default_price_list")
- or price_list
+ or webnotes.conn.get_value("Customer Group",
+ customer.customer_group, "default_price_list") or price_list
if out.selling_price_list:
out.price_list_currency = webnotes.conn.get_value("Price List", out.selling_price_list, "currency")
diff --git a/erpnext/selling/doctype/opportunity/opportunity.js b/erpnext/selling/doctype/opportunity/opportunity.js
index 8731f2e..3de7f1e 100644
--- a/erpnext/selling/doctype/opportunity/opportunity.js
+++ b/erpnext/selling/doctype/opportunity/opportunity.js
@@ -19,13 +19,13 @@
this.frm.doc.enquiry_from = "Lead";
if(!this.frm.doc.status)
- set_multiple(cdt,cdn,{status:'Draft'});
+ set_multiple(cdt, cdn, { status:'Draft' });
if(!this.frm.doc.date)
this.frm.doc.transaction_date = date.obj_to_str(new Date());
if(!this.frm.doc.company && wn.defaults.get_default("company"))
- set_multiple(cdt,cdn,{company:wn.defaults.get_default("company")});
- if(!this.frm.doc.fiscal_year && sys_defaults.fiscal_year)
- set_multiple(cdt,cdn,{fiscal_year:sys_defaults.fiscal_year});
+ set_multiple(cdt, cdn, { company:wn.defaults.get_default("company") });
+ if(!this.frm.doc.fiscal_year && sys_defaults.fiscal_year)
+ set_multiple(cdt, cdn, { fiscal_year:sys_defaults.fiscal_year });
if(!this.frm.doc.__islocal) {
@@ -80,44 +80,41 @@
$.extend(cur_frm.cscript, new erpnext.selling.Opportunity({frm: cur_frm}));
-cur_frm.cscript.refresh = function(doc, cdt, cdn){
+cur_frm.cscript.refresh = function(doc, cdt, cdn) {
erpnext.hide_naming_series();
cur_frm.clear_custom_buttons();
if(doc.docstatus === 1 && doc.status!=="Lost") {
cur_frm.add_custom_button(wn._('Create Quotation'), cur_frm.cscript.create_quotation);
- if(doc.status!=="Quotation") {
+ if(doc.status!=="Quotation")
cur_frm.add_custom_button(wn._('Opportunity Lost'), cur_frm.cscript['Declare Opportunity Lost']);
- }
+
cur_frm.add_custom_button(wn._('Send SMS'), cur_frm.cscript.send_sms, "icon-mobile-phone");
}
}
cur_frm.cscript.onload_post_render = function(doc, cdt, cdn) {
- if(doc.enquiry_from == 'Lead' && doc.lead) {
- cur_frm.cscript.lead(doc,cdt,cdn);
- }
+ if(doc.enquiry_from == 'Lead' && doc.lead)
+ cur_frm.cscript.lead(doc, cdt, cdn);
}
cur_frm.cscript.item_code = function(doc, cdt, cdn) {
var d = locals[cdt][cdn];
if (d.item_code) {
- return get_server_fields('get_item_details',d.item_code, 'enquiry_details',doc, cdt,cdn,1);
+ return get_server_fields('get_item_details', d.item_code,
+ 'enquiry_details', doc, cdt, cdn, 1);
}
}
-
cur_frm.cscript.lead = function(doc, cdt, cdn) {
cur_frm.toggle_display("contact_info", doc.customer || doc.lead);
wn.model.map_current_doc({
method: "erpnext.selling.doctype.lead.lead.make_opportunity",
source_name: cur_frm.doc.lead
- })
+ });
}
-
-
-cur_frm.cscript['Declare Opportunity Lost'] = function(){
+cur_frm.cscript['Declare Opportunity Lost'] = function() {
var dialog = new wn.ui.Dialog({
title: wn._("Set as Lost"),
fields: [
@@ -145,5 +142,4 @@
})
});
dialog.show();
-
}
\ No newline at end of file
diff --git a/erpnext/selling/doctype/quotation/quotation.js b/erpnext/selling/doctype/quotation/quotation.js
index bb2ce8c..b1f4394 100644
--- a/erpnext/selling/doctype/quotation/quotation.js
+++ b/erpnext/selling/doctype/quotation/quotation.js
@@ -15,12 +15,21 @@
erpnext.selling.QuotationController = erpnext.selling.SellingController.extend({
onload: function(doc, dt, dn) {
+ var me = this;
this._super(doc, dt, dn);
if(doc.customer && !doc.quotation_to)
doc.quotation_to = "Customer";
else if(doc.lead && !doc.quotation_to)
doc.quotation_to = "Lead";
-
+
+ // to overwrite the customer_filter trigger from queries.js
+ if (doc.lead) {
+ $.each(["customer_address", "shipping_address_name"],
+ function(i, opts) {
+ me.frm.set_query(opts, erpnext.queries["lead_filter"]);
+ }
+ );
+ }
},
refresh: function(doc, dt, dn) {
this._super(doc, dt, dn);
@@ -68,6 +77,12 @@
quotation_to: function() {
this.frm.toggle_reqd("lead", this.frm.doc.quotation_to == "Lead");
this.frm.toggle_reqd("customer", this.frm.doc.quotation_to == "Customer");
+ if (this.frm.doc.quotation_to == "Lead") {
+ this.frm.set_value("customer", null);
+ this.frm.set_value("contact_person", null);
+ }
+ else if (this.frm.doc.quotation_to == "Customer")
+ this.frm.set_value("lead", null);
},
tc_name: function() {
@@ -90,7 +105,8 @@
cur_frm.script_manager.make(erpnext.selling.QuotationController);
cur_frm.fields_dict.lead.get_query = function(doc,cdt,cdn) {
- return{ query: "erpnext.controllers.queries.lead_query" } }
+ return{ query: "erpnext.controllers.queries.lead_query" }
+}
cur_frm.cscript.lead = function(doc, cdt, cdn) {
if(doc.lead) {
@@ -152,7 +168,6 @@
}
cur_frm.cscript.on_submit = function(doc, cdt, cdn) {
- if(cint(wn.boot.notification_settings.quotation)) {
+ if(cint(wn.boot.notification_settings.quotation))
cur_frm.email_doc(wn.boot.notification_settings.quotation_message);
- }
}
\ No newline at end of file
diff --git a/erpnext/selling/doctype/quotation/quotation.py b/erpnext/selling/doctype/quotation/quotation.py
index 6a030b9..ba571ae 100644
--- a/erpnext/selling/doctype/quotation/quotation.py
+++ b/erpnext/selling/doctype/quotation/quotation.py
@@ -3,14 +3,11 @@
from __future__ import unicode_literals
import webnotes
-
from webnotes.utils import cstr
from webnotes.model.bean import getlist
from webnotes.model.code import get_obj
from webnotes import _, msgprint
-
-
from erpnext.controllers.selling_controller import SellingController
class DocType(SellingController):
diff --git a/erpnext/selling/doctype/quotation/quotation.txt b/erpnext/selling/doctype/quotation/quotation.txt
index f12a2a7..edcd929 100644
--- a/erpnext/selling/doctype/quotation/quotation.txt
+++ b/erpnext/selling/doctype/quotation/quotation.txt
@@ -2,7 +2,7 @@
{
"creation": "2013-05-24 19:29:08",
"docstatus": 0,
- "modified": "2014-01-20 17:49:16",
+ "modified": "2014-01-29 19:42:32",
"modified_by": "Administrator",
"owner": "Administrator"
},
@@ -674,6 +674,7 @@
"read_only": 0
},
{
+ "depends_on": "eval:doc.customer",
"doctype": "DocField",
"fieldname": "contact_person",
"fieldtype": "Link",
diff --git a/erpnext/setup/doctype/company/company.txt b/erpnext/setup/doctype/company/company.txt
index 4159c51..4832ae0 100644
--- a/erpnext/setup/doctype/company/company.txt
+++ b/erpnext/setup/doctype/company/company.txt
@@ -2,7 +2,7 @@
{
"creation": "2013-04-10 08:35:39",
"docstatus": 0,
- "modified": "2014-01-20 17:48:28",
+ "modified": "2014-01-30 16:32:41",
"modified_by": "Administrator",
"owner": "Administrator"
},
@@ -110,6 +110,7 @@
"fieldname": "default_cash_account",
"fieldtype": "Link",
"label": "Default Cash Account",
+ "no_copy": 1,
"options": "Account",
"read_only": 0
},
@@ -142,6 +143,7 @@
"fieldname": "default_expense_account",
"fieldtype": "Link",
"label": "Default Expense Account",
+ "no_copy": 1,
"options": "Account"
},
{
@@ -149,6 +151,7 @@
"fieldname": "default_income_account",
"fieldtype": "Link",
"label": "Default Income Account",
+ "no_copy": 1,
"options": "Account"
},
{
diff --git a/erpnext/stock/doctype/price_list/price_list.txt b/erpnext/stock/doctype/price_list/price_list.txt
index 7f8b3a1..253dce7 100644
--- a/erpnext/stock/doctype/price_list/price_list.txt
+++ b/erpnext/stock/doctype/price_list/price_list.txt
@@ -2,7 +2,7 @@
{
"creation": "2013-01-25 11:35:09",
"docstatus": 0,
- "modified": "2014-01-20 17:50:00",
+ "modified": "2014-01-27 11:11:08",
"modified_by": "Administrator",
"owner": "Administrator"
},
@@ -10,6 +10,9 @@
"allow_attach": 0,
"allow_copy": 0,
"allow_import": 1,
+ "allow_email": 1,
+ "allow_print": 1,
+ "allow_rename": 1,
"autoname": "field:price_list_name",
"description": "Price List Master",
"doctype": "DocType",
diff --git a/erpnext/stock/doctype/serial_no/serial_no.py b/erpnext/stock/doctype/serial_no/serial_no.py
index 9c1da65..45cc89c 100644
--- a/erpnext/stock/doctype/serial_no/serial_no.py
+++ b/erpnext/stock/doctype/serial_no/serial_no.py
@@ -94,6 +94,8 @@
self.doc.status = "Delivered"
else:
self.doc.status = "Not Available"
+ else:
+ self.doc.status = "Not Available"
def set_purchase_details(self, purchase_sle):
if purchase_sle:
@@ -185,10 +187,9 @@
def on_stock_ledger_entry(self):
if self.via_stock_ledger and not self.doc.fields.get("__islocal"):
last_sle = self.get_last_sle()
- if last_sle:
- self.set_status(last_sle.get("last_sle"))
- self.set_purchase_details(last_sle.get("purchase_sle"))
- self.set_sales_details(last_sle.get("delivery_sle"))
+ self.set_status(last_sle.get("last_sle"))
+ self.set_purchase_details(last_sle.get("purchase_sle"))
+ self.set_sales_details(last_sle.get("delivery_sle"))
def on_communication(self):
return
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.js b/erpnext/stock/doctype/stock_entry/stock_entry.js
index 6bd9564..5dbcef8 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.js
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.js
@@ -93,9 +93,8 @@
if(cint(wn.defaults.get_default("auto_accounting_for_stock"))) {
var account_for = "stock_adjustment_account";
- if (this.frm.doc.purpose == "Sales Return")
- account_for = "stock_in_hand_account";
- else if (this.frm.doc.purpose == "Purchase Return")
+
+ if (this.frm.doc.purpose == "Purchase Return")
account_for = "stock_received_but_not_billed";
return this.frm.call({
@@ -236,7 +235,50 @@
mtn_details_on_form_rendered: function(doc, grid_row) {
erpnext.setup_serial_no(grid_row)
+ },
+
+ customer: function() {
+ return this.frm.call({
+ method: "erpnext.selling.doctype.customer.customer.get_customer_details",
+ args: { customer: this.frm.doc.customer }
+ });
+ },
+
+ supplier: function() {
+ return this.frm.call({
+ method: "erpnext.buying.doctype.supplier.supplier.get_supplier_details",
+ args: { supplier: this.frm.doc.supplier }
+ });
+ },
+
+ delivery_note_no: function() {
+ this.get_party_details({
+ ref_dt: "Delivery Note",
+ ref_dn: this.frm.doc.delivery_note_no
+ })
+ },
+
+ sales_invoice_no: function() {
+ this.get_party_details({
+ ref_dt: "Sales Invoice",
+ ref_dn: this.frm.doc.sales_invoice_no
+ })
+ },
+
+ purchase_receipt_no: function() {
+ this.get_party_details({
+ ref_dt: "Purchase Receipt",
+ ref_dn: this.frm.doc.purchase_receipt_no
+ })
+ },
+
+ get_party_details: 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);
@@ -265,32 +307,6 @@
}
}
-cur_frm.cscript.delivery_note_no = function(doc, cdt, cdn) {
- if(doc.delivery_note_no)
- return get_server_fields('get_cust_values', '', '', doc, cdt, cdn, 1);
-}
-
-cur_frm.cscript.sales_invoice_no = function(doc, cdt, cdn) {
- if(doc.sales_invoice_no)
- return get_server_fields('get_cust_values', '', '', doc, cdt, cdn, 1);
-}
-
-cur_frm.cscript.customer = function(doc, cdt, cdn) {
- if(doc.customer)
- return get_server_fields('get_cust_addr', '', '', doc, cdt, cdn, 1);
-}
-
-cur_frm.cscript.purchase_receipt_no = function(doc, cdt, cdn) {
- if(doc.purchase_receipt_no)
- return get_server_fields('get_supp_values', '', '', doc, cdt, cdn, 1);
-}
-
-cur_frm.cscript.supplier = function(doc, cdt, cdn) {
- if(doc.supplier)
- return get_server_fields('get_supp_addr', '', '', doc, cdt, cdn, 1);
-
-}
-
cur_frm.fields_dict['production_order'].get_query = function(doc) {
return{
filters:[
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py
index f1485f3..161a3ad 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.py
@@ -344,7 +344,8 @@
pro_bean = webnotes.bean("Production Order", self.doc.production_order)
_validate_production_order(pro_bean)
self.update_produced_qty(pro_bean)
- self.update_planned_qty(pro_bean)
+ if self.doc.purpose == "Manufacture/Repack":
+ self.update_planned_qty(pro_bean)
def update_produced_qty(self, pro_bean):
if self.doc.purpose == "Manufacture/Repack":
@@ -589,56 +590,6 @@
# increment idx by 1
idx += 1
return idx
-
- def get_cust_values(self):
- """fetches customer details"""
- if self.doc.delivery_note_no:
- doctype = "Delivery Note"
- name = self.doc.delivery_note_no
- else:
- doctype = "Sales Invoice"
- name = self.doc.sales_invoice_no
-
- result = webnotes.conn.sql("""select customer, customer_name,
- address_display as customer_address
- from `tab%s` where name=%s""" % (doctype, "%s"), (name,), as_dict=1)
-
- return result and result[0] or {}
-
- def get_cust_addr(self):
- from erpnext.utilities.transaction_base import get_default_address, get_address_display
- res = webnotes.conn.sql("select customer_name from `tabCustomer` where name = '%s'"%self.doc.customer)
- address_display = None
- customer_address = get_default_address("customer", self.doc.customer)
- if customer_address:
- address_display = get_address_display(customer_address)
- ret = {
- 'customer_name' : res and res[0][0] or '',
- 'customer_address' : address_display}
-
- return ret
-
- def get_supp_values(self):
- result = webnotes.conn.sql("""select supplier, supplier_name,
- address_display as supplier_address
- from `tabPurchase Receipt` where name=%s""", (self.doc.purchase_receipt_no,),
- as_dict=1)
-
- return result and result[0] or {}
-
- def get_supp_addr(self):
- from erpnext.utilities.transaction_base import get_default_address, get_address_display
- res = webnotes.conn.sql("""select supplier_name from `tabSupplier`
- where name=%s""", self.doc.supplier)
- address_display = None
- supplier_address = get_default_address("customer", self.doc.customer)
- if supplier_address:
- address_display = get_address_display(supplier_address)
-
- ret = {
- 'supplier_name' : res and res[0][0] or '',
- 'supplier_address' : address_display }
- return ret
def validate_with_material_request(self):
for item in self.doclist.get({"parentfield": "mtn_details"}):
@@ -652,6 +603,17 @@
+ _("Material Request") + (" - %s" % item.material_request),
raise_exception=webnotes.MappingMismatchError)
+@webnotes.whitelist()
+def get_party_details(ref_dt, ref_dn):
+ if ref_dt in ["Delivery Note", "Sales Invoice"]:
+ res = webnotes.conn.get_value(ref_dt, ref_dn,
+ ["customer", "customer_name", "address_display as customer_address"], as_dict=1)
+ else:
+ res = webnotes.conn.get_value(ref_dt, ref_dn,
+ ["supplier", "supplier_name", "address_display as supplier_address"], as_dict=1)
+ print ref_dt, ref_dn, res
+ return res or {}
+
@webnotes.whitelist()
def get_production_order_details(production_order):
result = webnotes.conn.sql("""select bom_no,
@@ -964,5 +926,4 @@
result = [parent] + [{"account": account} for account in children]
- return result
-
+ return result
\ No newline at end of file
diff --git a/erpnext/stock/doctype/stock_entry/test_stock_entry.py b/erpnext/stock/doctype/stock_entry/test_stock_entry.py
index 1d7c2e4..4410b84 100644
--- a/erpnext/stock/doctype/stock_entry/test_stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/test_stock_entry.py
@@ -6,6 +6,7 @@
from webnotes.utils import flt
from erpnext.stock.doctype.serial_no.serial_no import *
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory
+from erpnext.stock.doctype.stock_ledger_entry.stock_ledger_entry import StockFreezeError
class TestStockEntry(unittest.TestCase):
def tearDown(self):
@@ -18,7 +19,7 @@
webnotes.conn.sql("""delete from `tabMaterial Request Item`""")
webnotes.conn.sql("""delete from `tabMaterial Request`""")
self._clear_stock_account_balance()
-
+
webnotes.conn.set_value("Stock Settings", None, "auto_indent", True)
st1 = webnotes.bean(copy=test_records[0])
@@ -28,119 +29,120 @@
st2 = webnotes.bean(copy=test_records[1])
st2.insert()
st2.submit()
-
+
from erpnext.stock.utils import reorder_item
+
reorder_item()
-
+
mr_name = webnotes.conn.sql("""select parent from `tabMaterial Request Item`
where item_code='_Test Item'""")
-
+
self.assertTrue(mr_name)
-
+
webnotes.conn.set_default("company", self.old_default_company)
def test_material_receipt_gl_entry(self):
self._clear_stock_account_balance()
set_perpetual_inventory()
-
+
mr = webnotes.bean(copy=test_records[0])
mr.insert()
mr.submit()
-
- stock_in_hand_account = webnotes.conn.get_value("Account", {"account_type": "Warehouse",
+
+ stock_in_hand_account = webnotes.conn.get_value("Account", {"account_type": "Warehouse",
"master_name": mr.doclist[1].t_warehouse})
-
- self.check_stock_ledger_entries("Stock Entry", mr.doc.name,
+
+ self.check_stock_ledger_entries("Stock Entry", mr.doc.name,
[["_Test Item", "_Test Warehouse - _TC", 50.0]])
-
- self.check_gl_entries("Stock Entry", mr.doc.name,
+
+ self.check_gl_entries("Stock Entry", mr.doc.name,
sorted([
- [stock_in_hand_account, 5000.0, 0.0],
+ [stock_in_hand_account, 5000.0, 0.0],
["Stock Adjustment - _TC", 0.0, 5000.0]
])
)
-
+
mr.cancel()
-
- self.assertFalse(webnotes.conn.sql("""select * from `tabStock Ledger Entry`
- where voucher_type='Stock Entry' and voucher_no=%s""", mr.doc.name))
-
- self.assertFalse(webnotes.conn.sql("""select * from `tabGL Entry`
+
+ self.assertFalse(webnotes.conn.sql("""select * from `tabStock Ledger Entry`
where voucher_type='Stock Entry' and voucher_no=%s""", mr.doc.name))
-
+
+ self.assertFalse(webnotes.conn.sql("""select * from `tabGL Entry`
+ where voucher_type='Stock Entry' and voucher_no=%s""", mr.doc.name))
+
def test_material_issue_gl_entry(self):
self._clear_stock_account_balance()
set_perpetual_inventory()
-
+
self._insert_material_receipt()
-
+
mi = webnotes.bean(copy=test_records[1])
mi.insert()
mi.submit()
-
- self.check_stock_ledger_entries("Stock Entry", mi.doc.name,
+
+ self.check_stock_ledger_entries("Stock Entry", mi.doc.name,
[["_Test Item", "_Test Warehouse - _TC", -40.0]])
-
- stock_in_hand_account = webnotes.conn.get_value("Account", {"account_type": "Warehouse",
+
+ stock_in_hand_account = webnotes.conn.get_value("Account", {"account_type": "Warehouse",
"master_name": mi.doclist[1].s_warehouse})
- self.check_gl_entries("Stock Entry", mi.doc.name,
+ self.check_gl_entries("Stock Entry", mi.doc.name,
sorted([
- [stock_in_hand_account, 0.0, 4000.0],
+ [stock_in_hand_account, 0.0, 4000.0],
["Stock Adjustment - _TC", 4000.0, 0.0]
])
)
-
+
mi.cancel()
- self.assertFalse(webnotes.conn.sql("""select * from `tabStock Ledger Entry`
- where voucher_type='Stock Entry' and voucher_no=%s""", mi.doc.name))
-
- self.assertFalse(webnotes.conn.sql("""select * from `tabGL Entry`
+ self.assertFalse(webnotes.conn.sql("""select * from `tabStock Ledger Entry`
where voucher_type='Stock Entry' and voucher_no=%s""", mi.doc.name))
-
- self.assertEquals(webnotes.conn.get_value("Bin", {"warehouse": mi.doclist[1].s_warehouse,
+
+ self.assertFalse(webnotes.conn.sql("""select * from `tabGL Entry`
+ where voucher_type='Stock Entry' and voucher_no=%s""", mi.doc.name))
+
+ self.assertEquals(webnotes.conn.get_value("Bin", {"warehouse": mi.doclist[1].s_warehouse,
"item_code": mi.doclist[1].item_code}, "actual_qty"), 50)
-
- self.assertEquals(webnotes.conn.get_value("Bin", {"warehouse": mi.doclist[1].s_warehouse,
+
+ self.assertEquals(webnotes.conn.get_value("Bin", {"warehouse": mi.doclist[1].s_warehouse,
"item_code": mi.doclist[1].item_code}, "stock_value"), 5000)
-
+
def test_material_transfer_gl_entry(self):
self._clear_stock_account_balance()
set_perpetual_inventory()
self._insert_material_receipt()
-
+
mtn = webnotes.bean(copy=test_records[2])
mtn.insert()
mtn.submit()
- self.check_stock_ledger_entries("Stock Entry", mtn.doc.name,
+ self.check_stock_ledger_entries("Stock Entry", mtn.doc.name,
[["_Test Item", "_Test Warehouse - _TC", -45.0], ["_Test Item", "_Test Warehouse 1 - _TC", 45.0]])
- stock_in_hand_account = webnotes.conn.get_value("Account", {"account_type": "Warehouse",
+ stock_in_hand_account = webnotes.conn.get_value("Account", {"account_type": "Warehouse",
"master_name": mtn.doclist[1].s_warehouse})
- fixed_asset_account = webnotes.conn.get_value("Account", {"account_type": "Warehouse",
+ fixed_asset_account = webnotes.conn.get_value("Account", {"account_type": "Warehouse",
"master_name": mtn.doclist[1].t_warehouse})
-
- self.check_gl_entries("Stock Entry", mtn.doc.name,
+
+ self.check_gl_entries("Stock Entry", mtn.doc.name,
sorted([
- [stock_in_hand_account, 0.0, 4500.0],
+ [stock_in_hand_account, 0.0, 4500.0],
[fixed_asset_account, 4500.0, 0.0],
])
)
-
+
mtn.cancel()
- self.assertFalse(webnotes.conn.sql("""select * from `tabStock Ledger Entry`
- where voucher_type='Stock Entry' and voucher_no=%s""", mtn.doc.name))
-
- self.assertFalse(webnotes.conn.sql("""select * from `tabGL Entry`
+ self.assertFalse(webnotes.conn.sql("""select * from `tabStock Ledger Entry`
where voucher_type='Stock Entry' and voucher_no=%s""", mtn.doc.name))
-
-
+
+ self.assertFalse(webnotes.conn.sql("""select * from `tabGL Entry`
+ where voucher_type='Stock Entry' and voucher_no=%s""", mtn.doc.name))
+
+
def test_repack_no_change_in_valuation(self):
self._clear_stock_account_balance()
set_perpetual_inventory()
@@ -150,47 +152,47 @@
repack = webnotes.bean(copy=test_records[3])
repack.insert()
repack.submit()
-
- self.check_stock_ledger_entries("Stock Entry", repack.doc.name,
- [["_Test Item", "_Test Warehouse - _TC", -50.0],
+
+ self.check_stock_ledger_entries("Stock Entry", repack.doc.name,
+ [["_Test Item", "_Test Warehouse - _TC", -50.0],
["_Test Item Home Desktop 100", "_Test Warehouse - _TC", 1]])
-
+
gl_entries = webnotes.conn.sql("""select account, debit, credit
from `tabGL Entry` where voucher_type='Stock Entry' and voucher_no=%s
order by account desc""", repack.doc.name, as_dict=1)
self.assertFalse(gl_entries)
-
+
set_perpetual_inventory(0)
-
+
def test_repack_with_change_in_valuation(self):
self._clear_stock_account_balance()
set_perpetual_inventory()
self._insert_material_receipt()
-
+
repack = webnotes.bean(copy=test_records[3])
repack.doclist[2].incoming_rate = 6000
repack.insert()
repack.submit()
-
- stock_in_hand_account = webnotes.conn.get_value("Account", {"account_type": "Warehouse",
+
+ stock_in_hand_account = webnotes.conn.get_value("Account", {"account_type": "Warehouse",
"master_name": repack.doclist[2].t_warehouse})
-
- self.check_gl_entries("Stock Entry", repack.doc.name,
+
+ self.check_gl_entries("Stock Entry", repack.doc.name,
sorted([
- [stock_in_hand_account, 1000.0, 0.0],
+ [stock_in_hand_account, 1000.0, 0.0],
["Stock Adjustment - _TC", 0.0, 1000.0],
])
)
set_perpetual_inventory(0)
-
+
def check_stock_ledger_entries(self, voucher_type, voucher_no, expected_sle):
expected_sle.sort(key=lambda x: x[0])
-
+
# check stock ledger entries
- sle = webnotes.conn.sql("""select item_code, warehouse, actual_qty
- from `tabStock Ledger Entry` where voucher_type = %s
- and voucher_no = %s order by item_code, warehouse, actual_qty""",
+ sle = webnotes.conn.sql("""select item_code, warehouse, actual_qty
+ from `tabStock Ledger Entry` where voucher_type = %s
+ and voucher_no = %s order by item_code, warehouse, actual_qty""",
(voucher_type, voucher_no), as_list=1)
self.assertTrue(sle)
sle.sort(key=lambda x: x[0])
@@ -199,61 +201,61 @@
self.assertEquals(expected_sle[i][0], sle[0])
self.assertEquals(expected_sle[i][1], sle[1])
self.assertEquals(expected_sle[i][2], sle[2])
-
+
def check_gl_entries(self, voucher_type, voucher_no, expected_gl_entries):
expected_gl_entries.sort(key=lambda x: x[0])
-
+
gl_entries = webnotes.conn.sql("""select account, debit, credit
- from `tabGL Entry` where voucher_type=%s and voucher_no=%s
+ from `tabGL Entry` where voucher_type=%s and voucher_no=%s
order by account asc, debit asc""", (voucher_type, voucher_no), as_list=1)
self.assertTrue(gl_entries)
gl_entries.sort(key=lambda x: x[0])
-
+
for i, gle in enumerate(gl_entries):
self.assertEquals(expected_gl_entries[i][0], gle[0])
self.assertEquals(expected_gl_entries[i][1], gle[1])
self.assertEquals(expected_gl_entries[i][2], gle[2])
-
+
def _insert_material_receipt(self):
self._clear_stock_account_balance()
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()
-
+
webnotes.conn.set_default("company", self.old_default_company)
-
+
def _get_actual_qty(self):
- return flt(webnotes.conn.get_value("Bin", {"item_code": "_Test Item",
+ return flt(webnotes.conn.get_value("Bin", {"item_code": "_Test Item",
"warehouse": "_Test Warehouse - _TC"}, "actual_qty"))
-
+
def _test_sales_invoice_return(self, item_code, delivered_qty, returned_qty):
from erpnext.stock.doctype.stock_entry.stock_entry import NotUpdateStockError
from erpnext.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
@@ -262,12 +264,12 @@
si.doclist[1].qty = 5.0
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"
@@ -277,10 +279,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"
@@ -291,45 +293,45 @@
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._clear_stock_account_balance()
self._test_sales_invoice_return("_Test Item", 5, 2)
-
+
def test_sales_invoice_return_of_packing_item(self):
self._clear_stock_account_balance()
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 erpnext.stock.doctype.delivery_note.test_delivery_note \
import test_records as delivery_note_test_records
from erpnext.stock.doctype.delivery_note.delivery_note import make_sales_invoice
-
+
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 = make_sales_invoice(dn.doc.name)
-
+
si = webnotes.bean(si_doclist)
si.doc.posting_date = dn.doc.posting_date
si.doc.debit_to = "_Test Customer - _TC"
@@ -338,7 +340,7 @@
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"
@@ -346,60 +348,60 @@
se.doc.posting_date = "2013-03-10"
se.doc.fiscal_year = "_Test Fiscal Year 2013"
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._clear_stock_account_balance()
self._test_delivery_note_return("_Test Item", 5, 2)
-
+
def test_delivery_note_return_of_packing_item(self):
self._clear_stock_account_balance()
self._test_delivery_note_return("_Test Sales BOM Item", 25, 20)
-
+
def _test_sales_return_jv(self, se):
from erpnext.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):
self._clear_stock_account_balance()
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):
self._clear_stock_account_balance()
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):
self._clear_stock_account_balance()
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):
self._clear_stock_account_balance()
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()
@@ -407,13 +409,13 @@
from erpnext.selling.doctype.sales_order.sales_order import make_sales_invoice, make_delivery_note
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 = make_delivery_note(so.doc.name)
dn = webnotes.bean(dn_doclist)
@@ -421,7 +423,7 @@
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)
@@ -452,12 +454,12 @@
self.assertEquals(actual_qty_1 + returned_qty, actual_qty_2)
return se
-
+
def test_purchase_receipt_return(self):
self._clear_stock_account_balance()
-
+
actual_qty_0 = self._get_actual_qty()
-
+
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt \
import test_records as purchase_receipt_test_records
@@ -467,28 +469,28 @@
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 + 5, actual_qty_1)
-
+
pi_doclist = make_purchase_invoice(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.doc.bill_no = "NA"
pi.insert()
pi.submit()
-
+
# submit purchase return
se = webnotes.bean(copy=test_records[0])
se.doc.purpose = "Purchase Return"
@@ -499,22 +501,22 @@
se.doclist[1].s_warehouse = "_Test Warehouse - _TC"
se.insert()
se.submit()
-
+
actual_qty_2 = self._get_actual_qty()
-
+
self.assertEquals(actual_qty_1 - 5, actual_qty_2)
-
+
webnotes.conn.set_default("company", self.old_default_company)
-
+
return se, pr.doc.name
-
+
def test_over_stock_return(self):
from erpnext.stock.doctype.stock_entry.stock_entry import StockOverReturnError
self._clear_stock_account_balance()
-
+
# 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"
@@ -523,20 +525,20 @@
se.doc.fiscal_year = "_Test Fiscal Year 2013"
se.doclist[1].qty = se.doclist[1].transfer_qty = 6
se.doclist[1].s_warehouse = "_Test Warehouse - _TC"
-
+
self.assertRaises(StockOverReturnError, se.insert)
-
+
def _test_purchase_return_jv(self, se):
from erpnext.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):
self._clear_stock_account_balance()
se, pr_name = self.test_purchase_receipt_return()
@@ -544,10 +546,10 @@
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_account_balance()
-
+
actual_qty_0 = self._get_actual_qty()
from erpnext.buying.doctype.purchase_order.test_purchase_order \
@@ -555,7 +557,7 @@
from erpnext.buying.doctype.purchase_order.purchase_order import \
make_purchase_receipt, make_purchase_invoice
-
+
# submit purchase receipt
po = webnotes.bean(copy=purchase_order_test_records[0])
po.doc.is_subcontracted = None
@@ -563,20 +565,20 @@
po.doclist[1].import_rate = 50
po.insert()
po.submit()
-
+
pr_doclist = make_purchase_receipt(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 = make_purchase_invoice(po.doc.name)
-
+
pi = webnotes.bean(pi_doclist)
pi.doc.posting_date = pr.doc.posting_date
pi.doc.credit_to = "_Test Supplier - _TC"
@@ -585,12 +587,12 @@
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.doc.bill_no = "NA"
pi.insert()
pi.submit()
-
+
# submit purchase return
se = webnotes.bean(copy=test_records[0])
se.doc.purpose = "Purchase Return"
@@ -601,23 +603,23 @@
se.doclist[1].s_warehouse = "_Test Warehouse - _TC"
se.insert()
se.submit()
-
+
actual_qty_2 = self._get_actual_qty()
-
+
self.assertEquals(actual_qty_1 - 5, actual_qty_2)
-
+
webnotes.conn.set_default("company", self.old_default_company)
-
+
return se, pr.doc.name
-
+
def _clear_stock_account_balance(self):
webnotes.conn.sql("delete from `tabStock Ledger Entry`")
webnotes.conn.sql("""delete from `tabBin`""")
webnotes.conn.sql("""delete from `tabGL Entry`""")
-
+
self.old_default_company = webnotes.conn.get_default("company")
webnotes.conn.set_default("company", "_Test Company")
-
+
def test_serial_no_not_reqd(self):
se = webnotes.bean(copy=test_records[0])
se.doclist[1].serial_no = "ABCD"
@@ -649,7 +651,7 @@
se.doclist[1].transfer_qty = 2
se.insert()
self.assertRaises(SerialNoQtyError, se.submit)
-
+
def test_serial_no_transfer_in(self):
self._clear_stock_account_balance()
se = webnotes.bean(copy=test_records[0])
@@ -659,13 +661,13 @@
se.doclist[1].transfer_qty = 2
se.insert()
se.submit()
-
+
self.assertTrue(webnotes.conn.exists("Serial No", "ABCD"))
self.assertTrue(webnotes.conn.exists("Serial No", "EFGH"))
-
+
se.cancel()
self.assertFalse(webnotes.conn.get_value("Serial No", "ABCD", "warehouse"))
-
+
def test_serial_no_not_exists(self):
self._clear_stock_account_balance()
se = webnotes.bean(copy=test_records[0])
@@ -678,11 +680,11 @@
se.doclist[1].transfer_qty = 2
se.insert()
self.assertRaises(SerialNoNotExistsError, se.submit)
-
+
def test_serial_duplicate(self):
self._clear_stock_account_balance()
self.test_serial_by_series()
-
+
se = webnotes.bean(copy=test_records[0])
se.doclist[1].item_code = "_Test Serialized Item With Series"
se.doclist[1].qty = 1
@@ -690,22 +692,22 @@
se.doclist[1].transfer_qty = 1
se.insert()
self.assertRaises(SerialNoDuplicateError, se.submit)
-
+
def test_serial_by_series(self):
self._clear_stock_account_balance()
se = make_serialized_item()
serial_nos = get_serial_nos(se.doclist[1].serial_no)
-
+
self.assertTrue(webnotes.conn.exists("Serial No", serial_nos[0]))
self.assertTrue(webnotes.conn.exists("Serial No", serial_nos[1]))
-
+
return se
def test_serial_item_error(self):
self._clear_stock_account_balance()
self.test_serial_by_series()
-
+
se = webnotes.bean(copy=test_records[0])
se.doc.purpose = "Material Transfer"
se.doclist[1].item_code = "_Test Serialized Item"
@@ -721,7 +723,7 @@
self._clear_stock_account_balance()
se = make_serialized_item()
serial_no = get_serial_nos(se.doclist[1].serial_no)[0]
-
+
se = webnotes.bean(copy=test_records[0])
se.doc.purpose = "Material Transfer"
se.doclist[1].item_code = "_Test Serialized Item With Series"
@@ -733,14 +735,14 @@
se.insert()
se.submit()
self.assertTrue(webnotes.conn.get_value("Serial No", serial_no, "warehouse"), "_Test Warehouse 1 - _TC")
-
+
se.cancel()
self.assertTrue(webnotes.conn.get_value("Serial No", serial_no, "warehouse"), "_Test Warehouse - _TC")
def test_serial_warehouse_error(self):
self._clear_stock_account_balance()
make_serialized_item()
-
+
se = webnotes.bean(copy=test_records[0])
se.doc.purpose = "Material Transfer"
se.doclist[1].item_code = "_Test Serialized Item With Series"
@@ -751,12 +753,12 @@
se.doclist[1].t_warehouse = "_Test Warehouse - _TC"
se.insert()
self.assertRaises(SerialNoWarehouseError, se.submit)
-
+
def test_serial_cancel(self):
self._clear_stock_account_balance()
se = self.test_serial_by_series()
se.cancel()
-
+
serial_no = get_serial_nos(se.doclist[1].serial_no)[0]
self.assertFalse(webnotes.conn.get_value("Serial No", serial_no, "warehouse"))
@@ -802,6 +804,23 @@
webnotes.defaults.clear_default("Warehouse", "_Test Warehouse 1 - _TC1", "test@example.com", parenttype="Restriction")
webnotes.defaults.clear_default("Warehouse", "_Test Warehouse 2 - _TC1", "test2@example.com", parenttype="Restriction")
+ def test_freeze_stocks (self):
+ self._clear_stock_account_balance()
+ webnotes.conn.set_value('Stock Settings', None,'stock_auth_role', '')
+
+ # test freeze_stocks_upto
+ date_newer_than_test_records = add_days(getdate(test_records[0][0]['posting_date']), 5)
+ webnotes.conn.set_value("Stock Settings", None, "stock_frozen_upto", date_newer_than_test_records)
+ se = webnotes.bean(copy=test_records[0]).insert()
+ self.assertRaises (StockFreezeError, se.submit)
+ webnotes.conn.set_value("Stock Settings", None, "stock_frozen_upto", '')
+
+ # test freeze_stocks_upto_days
+ webnotes.conn.set_value("Stock Settings", None, "stock_frozen_upto_days", 7)
+ se = webnotes.bean(copy=test_records[0]).insert()
+ self.assertRaises (StockFreezeError, se.submit)
+ webnotes.conn.set_value("Stock Settings", None, "stock_frozen_upto_days", 0)
+
def make_serialized_item():
se = webnotes.bean(copy=test_records[0])
se.doclist[1].item_code = "_Test Serialized Item With Series"
@@ -814,70 +833,70 @@
test_records = [
[
{
- "company": "_Test Company",
- "doctype": "Stock Entry",
- "posting_date": "2013-01-01",
- "posting_time": "17:14:24",
+ "company": "_Test Company",
+ "doctype": "Stock Entry",
+ "posting_date": "2013-01-01",
+ "posting_time": "17:14:24",
"purpose": "Material Receipt",
- "fiscal_year": "_Test Fiscal Year 2013",
- },
+ "fiscal_year": "_Test Fiscal Year 2013",
+ },
{
- "conversion_factor": 1.0,
- "doctype": "Stock Entry Detail",
- "item_code": "_Test Item",
- "parentfield": "mtn_details",
+ "conversion_factor": 1.0,
+ "doctype": "Stock Entry Detail",
+ "item_code": "_Test Item",
+ "parentfield": "mtn_details",
"incoming_rate": 100,
- "qty": 50.0,
- "stock_uom": "_Test UOM",
- "transfer_qty": 50.0,
+ "qty": 50.0,
+ "stock_uom": "_Test UOM",
+ "transfer_qty": 50.0,
"uom": "_Test UOM",
"t_warehouse": "_Test Warehouse - _TC",
"expense_account": "Stock Adjustment - _TC",
"cost_center": "_Test Cost Center - _TC"
- },
+ },
],
[
{
- "company": "_Test Company",
- "doctype": "Stock Entry",
- "posting_date": "2013-01-25",
- "posting_time": "17:15",
+ "company": "_Test Company",
+ "doctype": "Stock Entry",
+ "posting_date": "2013-01-25",
+ "posting_time": "17:15",
"purpose": "Material Issue",
- "fiscal_year": "_Test Fiscal Year 2013",
- },
+ "fiscal_year": "_Test Fiscal Year 2013",
+ },
{
- "conversion_factor": 1.0,
- "doctype": "Stock Entry Detail",
- "item_code": "_Test Item",
- "parentfield": "mtn_details",
+ "conversion_factor": 1.0,
+ "doctype": "Stock Entry Detail",
+ "item_code": "_Test Item",
+ "parentfield": "mtn_details",
"incoming_rate": 100,
- "qty": 40.0,
- "stock_uom": "_Test UOM",
- "transfer_qty": 40.0,
+ "qty": 40.0,
+ "stock_uom": "_Test UOM",
+ "transfer_qty": 40.0,
"uom": "_Test UOM",
"s_warehouse": "_Test Warehouse - _TC",
"expense_account": "Stock Adjustment - _TC",
"cost_center": "_Test Cost Center - _TC"
- },
+ },
],
[
{
- "company": "_Test Company",
- "doctype": "Stock Entry",
- "posting_date": "2013-01-25",
- "posting_time": "17:14:24",
+ "company": "_Test Company",
+ "doctype": "Stock Entry",
+ "posting_date": "2013-01-25",
+ "posting_time": "17:14:24",
"purpose": "Material Transfer",
- "fiscal_year": "_Test Fiscal Year 2013",
- },
+ "fiscal_year": "_Test Fiscal Year 2013",
+ },
{
- "conversion_factor": 1.0,
- "doctype": "Stock Entry Detail",
- "item_code": "_Test Item",
- "parentfield": "mtn_details",
+ "conversion_factor": 1.0,
+ "doctype": "Stock Entry Detail",
+ "item_code": "_Test Item",
+ "parentfield": "mtn_details",
"incoming_rate": 100,
- "qty": 45.0,
- "stock_uom": "_Test UOM",
- "transfer_qty": 45.0,
+ "qty": 45.0,
+ "stock_uom": "_Test UOM",
+ "transfer_qty": 45.0,
"uom": "_Test UOM",
"s_warehouse": "_Test Warehouse - _TC",
"t_warehouse": "_Test Warehouse 1 - _TC",
@@ -887,40 +906,40 @@
],
[
{
- "company": "_Test Company",
- "doctype": "Stock Entry",
- "posting_date": "2013-01-25",
- "posting_time": "17:14:24",
+ "company": "_Test Company",
+ "doctype": "Stock Entry",
+ "posting_date": "2013-01-25",
+ "posting_time": "17:14:24",
"purpose": "Manufacture/Repack",
- "fiscal_year": "_Test Fiscal Year 2013",
- },
+ "fiscal_year": "_Test Fiscal Year 2013",
+ },
{
- "conversion_factor": 1.0,
- "doctype": "Stock Entry Detail",
- "item_code": "_Test Item",
- "parentfield": "mtn_details",
+ "conversion_factor": 1.0,
+ "doctype": "Stock Entry Detail",
+ "item_code": "_Test Item",
+ "parentfield": "mtn_details",
"incoming_rate": 100,
- "qty": 50.0,
- "stock_uom": "_Test UOM",
- "transfer_qty": 50.0,
+ "qty": 50.0,
+ "stock_uom": "_Test UOM",
+ "transfer_qty": 50.0,
"uom": "_Test UOM",
"s_warehouse": "_Test Warehouse - _TC",
"expense_account": "Stock Adjustment - _TC",
"cost_center": "_Test Cost Center - _TC"
- },
+ },
{
- "conversion_factor": 1.0,
- "doctype": "Stock Entry Detail",
- "item_code": "_Test Item Home Desktop 100",
- "parentfield": "mtn_details",
+ "conversion_factor": 1.0,
+ "doctype": "Stock Entry Detail",
+ "item_code": "_Test Item Home Desktop 100",
+ "parentfield": "mtn_details",
"incoming_rate": 5000,
- "qty": 1,
- "stock_uom": "_Test UOM",
- "transfer_qty": 1,
+ "qty": 1,
+ "stock_uom": "_Test UOM",
+ "transfer_qty": 1,
"uom": "_Test UOM",
"t_warehouse": "_Test Warehouse - _TC",
"expense_account": "Stock Adjustment - _TC",
"cost_center": "_Test Cost Center - _TC"
},
],
-]
\ No newline at end of file
+]
diff --git a/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py
index e43761c..d6217dc 100644
--- a/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py
+++ b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py
@@ -1,11 +1,15 @@
+
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
import webnotes
from webnotes import msgprint
-from webnotes.utils import flt, getdate
+from webnotes.utils import flt, getdate, add_days
from webnotes.model.controller import DocListController
+from datetime import date
+
+class StockFreezeError(webnotes.ValidationError): pass
class DocType(DocListController):
def __init__(self, doc, doclist=[]):
@@ -20,28 +24,29 @@
self.scrub_posting_time()
from erpnext.accounts.utils import validate_fiscal_year
- validate_fiscal_year(self.doc.posting_date, self.doc.fiscal_year, self.meta.get_label("posting_date"))
-
+ validate_fiscal_year(self.doc.posting_date, self.doc.fiscal_year,
+ self.meta.get_label("posting_date"))
+
def on_submit(self):
self.check_stock_frozen_date()
self.actual_amt_check()
from erpnext.stock.doctype.serial_no.serial_no import process_serial_no
process_serial_no(self.doc)
-
+
#check for item quantity available in stock
def actual_amt_check(self):
if self.doc.batch_no:
- batch_bal_after_transaction = flt(webnotes.conn.sql("""select sum(actual_qty)
- from `tabStock Ledger Entry`
- where warehouse=%s and item_code=%s and batch_no=%s""",
+ batch_bal_after_transaction = flt(webnotes.conn.sql("""select sum(actual_qty)
+ from `tabStock Ledger Entry`
+ where warehouse=%s and item_code=%s and batch_no=%s""",
(self.doc.warehouse, self.doc.item_code, self.doc.batch_no))[0][0])
-
+
if batch_bal_after_transaction < 0:
self.doc.fields.update({
'batch_bal': batch_bal_after_transaction - self.doc.actual_qty
})
-
+
webnotes.throw("""Not enough quantity (requested: %(actual_qty)s, \
current: %(batch_bal)s in Batch <b>%(batch_no)s</b> for Item \
<b>%(item_code)s</b> at Warehouse <b>%(warehouse)s</b> \
@@ -59,41 +64,49 @@
msgprint("Warehouse: '%s' does not exist in the system. Please check." % self.doc.fields.get(k), raise_exception = 1)
def validate_item(self):
- item_det = webnotes.conn.sql("""select name, has_batch_no, docstatus,
- is_stock_item, has_serial_no, serial_no_series
- from tabItem where name=%s""",
+ item_det = webnotes.conn.sql("""select name, has_batch_no, docstatus,
+ is_stock_item, has_serial_no, serial_no_series
+ from tabItem where name=%s""",
self.doc.item_code, as_dict=True)[0]
if item_det.is_stock_item != 'Yes':
webnotes.throw("""Item: "%s" is not a Stock Item.""" % self.doc.item_code)
-
+
# check if batch number is required
if item_det.has_batch_no =='Yes' and self.doc.voucher_type != 'Stock Reconciliation':
if not self.doc.batch_no:
webnotes.throw("Batch number is mandatory for Item '%s'" % self.doc.item_code)
-
+
# check if batch belongs to item
- if not webnotes.conn.sql("""select name from `tabBatch`
+ if not webnotes.conn.sql("""select name from `tabBatch`
where item='%s' and name ='%s' and docstatus != 2""" % (self.doc.item_code, self.doc.batch_no)):
webnotes.throw("'%s' is not a valid Batch Number for Item '%s'" % (self.doc.batch_no, self.doc.item_code))
-
+
if not self.doc.stock_uom:
self.doc.stock_uom = item_det.stock_uom
-
+
def check_stock_frozen_date(self):
stock_frozen_upto = webnotes.conn.get_value('Stock Settings', None, 'stock_frozen_upto') or ''
if stock_frozen_upto:
stock_auth_role = webnotes.conn.get_value('Stock Settings', None,'stock_auth_role')
if getdate(self.doc.posting_date) <= getdate(stock_frozen_upto) and not stock_auth_role in webnotes.user.get_roles():
- msgprint("You are not authorized to do / modify back dated stock entries before %s" % getdate(stock_frozen_upto).strftime('%d-%m-%Y'), raise_exception=1)
+ msgprint("You are not authorized to do / modify back dated stock entries before %s" % getdate(stock_frozen_upto).strftime('%d-%m-%Y'), raise_exception=StockFreezeError)
+
+ stock_frozen_upto_days = int(webnotes.conn.get_value('Stock Settings', None, 'stock_frozen_upto_days') or 0)
+ if stock_frozen_upto_days:
+ stock_auth_role = webnotes.conn.get_value('Stock Settings', None,'stock_auth_role')
+ older_than_x_days_ago = (add_days(getdate(self.doc.posting_date), stock_frozen_upto_days) <= date.today())
+ if older_than_x_days_ago and not stock_auth_role in webnotes.user.get_roles():
+ msgprint("You are not authorized to do / modify back dated stock entries older than %d days ago" %stock_frozen_upto_days, raise_exception=StockFreezeError)
+
def scrub_posting_time(self):
if not self.doc.posting_time or self.doc.posting_time == '00:0':
self.doc.posting_time = '00:00'
def on_doctype_update():
- if not webnotes.conn.sql("""show index from `tabStock Ledger Entry`
+ if not webnotes.conn.sql("""show index from `tabStock Ledger Entry`
where Key_name="posting_sort_index" """):
webnotes.conn.commit()
- webnotes.conn.sql("""alter table `tabStock Ledger Entry`
+ webnotes.conn.sql("""alter table `tabStock Ledger Entry`
add index posting_sort_index(posting_date, posting_time, name)""")
\ No newline at end of file
diff --git a/erpnext/stock/doctype/stock_settings/stock_settings.py b/erpnext/stock/doctype/stock_settings/stock_settings.py
index e3e29b9..30a9490 100644
--- a/erpnext/stock/doctype/stock_settings/stock_settings.py
+++ b/erpnext/stock/doctype/stock_settings/stock_settings.py
@@ -5,18 +5,23 @@
from __future__ import unicode_literals
import webnotes
-
+from webnotes import _
class DocType:
def __init__(self, d, dl):
self.doc, self.doclist = d, dl
-
+
def validate(self):
- for key in ["item_naming_by", "item_group", "stock_uom",
+ for key in ["item_naming_by", "item_group", "stock_uom",
"allow_negative_stock"]:
webnotes.conn.set_default(key, self.doc.fields.get(key, ""))
from erpnext.setup.doctype.naming_series.naming_series import set_by_naming_series
set_by_naming_series("Item", "item_code",
self.doc.get("item_naming_by")=="Naming Series", hide_name_field=True)
-
+
+ stock_frozen_limit = 356
+ submitted_stock_frozen = self.doc.stock_frozen_upto_days
+ if submitted_stock_frozen > stock_frozen_limit:
+ self.doc.stock_frozen_upto_days = stock_frozen_limit
+ webnotes.msgprint (_("`Freeze Stocks Older Than` should be smaller than %d days.") %stock_frozen_limit)
diff --git a/erpnext/stock/doctype/stock_settings/stock_settings.txt b/erpnext/stock/doctype/stock_settings/stock_settings.txt
index de8c864..09e5ca4 100644
--- a/erpnext/stock/doctype/stock_settings/stock_settings.txt
+++ b/erpnext/stock/doctype/stock_settings/stock_settings.txt
@@ -1,25 +1,25 @@
[
{
- "creation": "2013-06-24 16:37:54",
- "docstatus": 0,
- "modified": "2013-12-20 19:21:48",
- "modified_by": "Administrator",
+ "creation": "2013-06-24 16:37:54",
+ "docstatus": 0,
+ "modified": "2014-01-27 20:00:56",
+ "modified_by": "Administrator",
"owner": "Administrator"
- },
+ },
{
- "description": "Settings",
- "doctype": "DocType",
- "icon": "icon-cog",
- "issingle": 1,
- "module": "Stock",
+ "description": "Settings",
+ "doctype": "DocType",
+ "icon": "icon-cog",
+ "issingle": 1,
+ "module": "Stock",
"name": "__common__"
- },
+ },
{
- "doctype": "DocField",
- "name": "__common__",
- "parent": "Stock Settings",
- "parentfield": "fields",
- "parenttype": "DocType",
+ "doctype": "DocField",
+ "name": "__common__",
+ "parent": "Stock Settings",
+ "parentfield": "fields",
+ "parenttype": "DocType",
"permlevel": 0
},
{
@@ -35,96 +35,102 @@
"read": 1,
"role": "Material Manager",
"write": 1
- },
+ },
{
- "doctype": "DocType",
+ "doctype": "DocType",
"name": "Stock Settings"
- },
+ },
{
- "doctype": "DocField",
- "fieldname": "item_naming_by",
- "fieldtype": "Select",
- "label": "Item Naming By",
+ "doctype": "DocField",
+ "fieldname": "item_naming_by",
+ "fieldtype": "Select",
+ "label": "Item Naming By",
"options": "Item Code\nNaming Series"
- },
+ },
{
- "description": "<a href=\"#Sales Browser/Item Group\">Add / Edit</a>",
- "doctype": "DocField",
- "fieldname": "item_group",
- "fieldtype": "Link",
- "label": "Default Item Group",
+ "description": "<a href=\"#Sales Browser/Item Group\">Add / Edit</a>",
+ "doctype": "DocField",
+ "fieldname": "item_group",
+ "fieldtype": "Link",
+ "label": "Default Item Group",
"options": "Item Group"
- },
+ },
{
- "doctype": "DocField",
- "fieldname": "stock_uom",
- "fieldtype": "Link",
- "label": "Default Stock UOM",
+ "doctype": "DocField",
+ "fieldname": "stock_uom",
+ "fieldtype": "Link",
+ "label": "Default Stock UOM",
"options": "UOM"
- },
+ },
{
- "doctype": "DocField",
- "fieldname": "column_break_4",
+ "doctype": "DocField",
+ "fieldname": "column_break_4",
"fieldtype": "Column Break"
- },
+ },
{
- "doctype": "DocField",
- "fieldname": "allow_negative_stock",
- "fieldtype": "Check",
+ "doctype": "DocField",
+ "fieldname": "allow_negative_stock",
+ "fieldtype": "Check",
"label": "Allow Negative Stock"
- },
+ },
{
- "doctype": "DocField",
- "fieldname": "valuation_method",
- "fieldtype": "Select",
- "label": "Default Valuation Method",
+ "doctype": "DocField",
+ "fieldname": "valuation_method",
+ "fieldtype": "Select",
+ "label": "Default Valuation Method",
"options": "FIFO\nMoving Average"
- },
+ },
{
- "description": "Percentage you are allowed to receive or deliver more against the quantity ordered. For example: If you have ordered 100 units. and your Allowance is 10% then you are allowed to receive 110 units.",
- "doctype": "DocField",
- "fieldname": "tolerance",
- "fieldtype": "Float",
+ "description": "Percentage you are allowed to receive or deliver more against the quantity ordered. For example: If you have ordered 100 units. and your Allowance is 10% then you are allowed to receive 110 units.",
+ "doctype": "DocField",
+ "fieldname": "tolerance",
+ "fieldtype": "Float",
"label": "Allowance Percent"
- },
+ },
{
- "doctype": "DocField",
- "fieldname": "auto_material_request",
- "fieldtype": "Section Break",
+ "doctype": "DocField",
+ "fieldname": "auto_material_request",
+ "fieldtype": "Section Break",
"label": "Auto Material Request"
- },
+ },
{
- "doctype": "DocField",
- "fieldname": "auto_indent",
- "fieldtype": "Check",
+ "doctype": "DocField",
+ "fieldname": "auto_indent",
+ "fieldtype": "Check",
"label": "Raise Material Request when stock reaches re-order level"
- },
+ },
{
- "doctype": "DocField",
- "fieldname": "reorder_email_notify",
- "fieldtype": "Check",
+ "doctype": "DocField",
+ "fieldname": "reorder_email_notify",
+ "fieldtype": "Check",
"label": "Notify by Email on creation of automatic Material Request"
- },
+ },
{
- "doctype": "DocField",
- "fieldname": "freeze_stock_entries",
- "fieldtype": "Section Break",
+ "doctype": "DocField",
+ "fieldname": "freeze_stock_entries",
+ "fieldtype": "Section Break",
"label": "Freeze Stock Entries"
- },
+ },
{
- "doctype": "DocField",
- "fieldname": "stock_frozen_upto",
- "fieldtype": "Date",
+ "doctype": "DocField",
+ "fieldname": "stock_frozen_upto",
+ "fieldtype": "Date",
"label": "Stock Frozen Upto"
- },
+ },
{
- "doctype": "DocField",
- "fieldname": "stock_auth_role",
- "fieldtype": "Link",
- "label": "Role Allowed to edit frozen stock",
+ "doctype": "DocField",
+ "fieldname": "stock_frozen_upto_days",
+ "fieldtype": "Int",
+ "label": "Freeze Stocks Older Than [Days]"
+ },
+ {
+ "doctype": "DocField",
+ "fieldname": "stock_auth_role",
+ "fieldtype": "Link",
+ "label": "Role Allowed to edit frozen stock",
"options": "Role"
- },
+ },
{
"doctype": "DocPerm"
}
-]
\ No newline at end of file
+]
diff --git a/erpnext/utilities/doctype/address/address.py b/erpnext/utilities/doctype/address/address.py
index ea21c21..e450d84 100644
--- a/erpnext/utilities/doctype/address/address.py
+++ b/erpnext/utilities/doctype/address/address.py
@@ -4,7 +4,7 @@
from __future__ import unicode_literals
import webnotes
-from webnotes import msgprint
+from webnotes import msgprint, throw, _
from webnotes.utils import cstr, cint
class DocType:
@@ -16,11 +16,11 @@
if not self.doc.address_title:
self.doc.address_title = self.doc.customer \
or self.doc.supplier or self.doc.sales_partner or self.doc.lead
-
+
if self.doc.address_title:
self.doc.name = cstr(self.doc.address_title).strip() + "-" + cstr(self.doc.address_type).strip()
else:
- webnotes.msgprint("""Address Title is mandatory.""" + self.doc.customer, raise_exception=True)
+ throw(_("Address Title is mandatory."))
def validate(self):
self.validate_primary_address()
diff --git a/erpnext/utilities/doctype/contact/contact.py b/erpnext/utilities/doctype/contact/contact.py
index 9dcb30d..2abd0dc 100644
--- a/erpnext/utilities/doctype/contact/contact.py
+++ b/erpnext/utilities/doctype/contact/contact.py
@@ -64,5 +64,4 @@
"contact_department": contact.get("department")
}
- return out
-
\ No newline at end of file
+ return out
\ No newline at end of file
diff --git a/erpnext/utilities/transaction_base.py b/erpnext/utilities/transaction_base.py
index 0241629..098a4bd 100644
--- a/erpnext/utilities/transaction_base.py
+++ b/erpnext/utilities/transaction_base.py
@@ -2,28 +2,14 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import webnotes, json
+import webnotes
from webnotes import msgprint, _
from webnotes.utils import cstr, flt, now_datetime, cint
-from webnotes.model.doc import addchild
from erpnext.controllers.status_updater import StatusUpdater
-class TransactionBase(StatusUpdater):
- def set_address_fields(self):
- party_type, party_name = self.get_party_type_and_name()
-
- if party_type in ("Customer", "Lead"):
- if self.doc.customer_address:
- self.doc.address_display = get_address_display(self.doc.customer_address)
-
- if self.doc.shipping_address_name:
- self.doc.shipping_address = get_address_display(self.doc.shipping_address_name)
-
- elif self.doc.supplier_address:
- self.doc.address_display = get_address_display(self.doc.supplier_address)
-
+class TransactionBase(StatusUpdater):
def set_contact_fields(self):
party_type, party_name = self.get_party_type_and_name()
@@ -59,74 +45,6 @@
def set_lead_defaults(self):
self.doc.fields.update(self.get_lead_defaults())
-
- # TODO deprecate this - used only in sales_order.js
- def get_shipping_address(self, name):
- shipping_address = get_default_address("customer", name, is_shipping_address=True)
- return {
- 'shipping_address_name' : shipping_address,
- 'shipping_address' : get_address_display(shipping_address) if shipping_address else None
- }
-
- # Get Supplier Default Primary Address - first load
- # -----------------------
- def get_default_supplier_address(self, args):
- if isinstance(args, basestring):
- args = json.loads(args)
-
- address_name = get_default_address("supplier", args["supplier"])
- ret = {
- 'supplier_address' : address_name,
- 'address_display' : get_address_display(address_name),
- }
- ret.update(map_party_contact_details(None, "supplier", args["supplier"]))
- ret.update(self.get_supplier_details(args['supplier']))
- return ret
-
- # Get Supplier Address
- # -----------------------
- def get_supplier_address(self, args):
- args = json.loads(args)
- ret = {
- 'supplier_address' : args['address'],
- 'address_display' : get_address_display(args["address"]),
- }
- ret.update(map_party_contact_details(contact_name=args['contact']))
- return ret
-
- def set_supplier_address(self, args):
- self.doc.fields.update(self.get_supplier_address(args))
-
- # Get Supplier Details
- # -----------------------
- def get_supplier_details(self, name):
- supplier_details = webnotes.conn.sql("""\
- select supplier_name, default_currency
- from `tabSupplier`
- where name = %s and docstatus < 2""", name, as_dict=1)
- if supplier_details:
- return {
- 'supplier_name': (supplier_details[0]['supplier_name']
- or self.doc.fields.get('supplier_name')),
- 'currency': (supplier_details[0]['default_currency']
- or self.doc.fields.get('currency')),
- }
- else:
- return {}
-
- # Get Sales Person Details of Customer
- # ------------------------------------
- def get_sales_person(self, name):
- self.doclist = self.doc.clear_table(self.doclist,'sales_team')
- idx = 0
- for d in webnotes.conn.sql("select sales_person, allocated_percentage, allocated_amount, incentives from `tabSales Team` where parent = '%s'" % name):
- ch = addchild(self.doc, 'sales_team', 'Sales Team', self.doclist)
- ch.sales_person = d and cstr(d[0]) or ''
- ch.allocated_percentage = d and flt(d[1]) or 0
- ch.allocated_amount = d and flt(d[2]) or 0
- ch.incentives = d and flt(d[3]) or 0
- ch.idx = idx
- idx += 1
def load_notification_message(self):
dt = self.doc.doctype.lower().replace(" ", "_")
@@ -208,17 +126,6 @@
for field, condition in fields:
if prevdoc_values[field] is not None:
self.validate_value(field, condition, prevdoc_values[field], doc)
-
-def get_default_address(party_field, party_name, is_shipping_address=False):
- if is_shipping_address:
- order_by = "is_shipping_address desc, is_primary_address desc, name asc"
- else:
- order_by = "is_primary_address desc, name asc"
-
- address = webnotes.conn.sql("""select name from `tabAddress` where `%s`=%s order by %s
- limit 1""" % (party_field, "%s", order_by), party_name)
-
- return address[0][0] if address else None
def get_default_contact(party_field, party_name):
contact = webnotes.conn.sql("""select name from `tabContact` where `%s`=%s
diff --git a/patches/1401/fix_planned_qty.py b/patches/1401/fix_planned_qty.py
new file mode 100644
index 0000000..979d949
--- /dev/null
+++ b/patches/1401/fix_planned_qty.py
@@ -0,0 +1,13 @@
+# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
+# License: GNU General Public License v3. See license.txt
+
+import webnotes
+
+def execute():
+ webnotes.conn.auto_commit_on_many_writes = 1
+ from utilities.repost_stock import repost_stock
+ for d in webnotes.conn.sql("""select distinct production_item, fg_warehouse
+ from `tabProduction Order` where docstatus>0""", as_dict=1):
+ repost_stock(d.production_item, d.fg_warehouse)
+
+ webnotes.conn.auto_commit_on_many_writes = 0
\ No newline at end of file
diff --git a/patches/1401/fix_serial_no_status_and_warehouse.py b/patches/1401/fix_serial_no_status_and_warehouse.py
new file mode 100644
index 0000000..9e5579c
--- /dev/null
+++ b/patches/1401/fix_serial_no_status_and_warehouse.py
@@ -0,0 +1,19 @@
+# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+import webnotes
+
+
+def execute():
+ serial_nos = webnotes.conn.sql("""select name from `tabSerial No` where docstatus=0
+ and status in ('Available', 'Sales Returned') and ifnull(warehouse, '') = ''""")
+ for sr in serial_nos:
+ try:
+ last_sle = webnotes.bean("Serial No", sr[0]).make_controller().get_last_sle()
+ if last_sle.actual_qty > 0:
+ webnotes.conn.set_value("Serial No", sr[0], "warehouse", last_sle.warehouse)
+
+ webnotes.conn.commit()
+ except:
+ pass
\ No newline at end of file