[Cleanup] Sales Common deprecated

This commit is contained in:
Nabin Hait
2013-10-18 12:29:11 +05:30
parent d05a3b3b5c
commit d1fd1e2d89
42 changed files with 219 additions and 727 deletions

View File

@@ -6,7 +6,6 @@ import webnotes
from webnotes.utils import cstr, getdate
from webnotes.model.bean import getlist
from webnotes.model.code import get_obj
from webnotes import msgprint
from stock.utils import get_valid_serial_nos
@@ -36,8 +35,9 @@ class DocType(TransactionBase):
self.validate_fiscal_year()
self.validate_installation_date()
self.check_item_table()
sales_com_obj = get_obj(dt = 'Sales Common')
sales_com_obj.check_active_sales_items(self)
from controllers.selling_controller import check_active_sales_items
check_active_sales_items(self)
def validate_fiscal_year(self):
from accounts.utils import validate_fiscal_year

View File

@@ -59,16 +59,6 @@ class DocType(TransactionBase):
msgprint("Customer : %s does not exist in system." % (name))
raise Exception
def get_contact_details(self, arg):
arg = eval(arg)
contact = webnotes.conn.sql("select contact_no, email_id from `tabContact` where contact_name = '%s' and customer_name = '%s'" %(arg['contact_person'],arg['customer']), as_dict = 1)
ret = {
'contact_no' : contact and contact[0]['contact_no'] or '',
'email_id' : contact and contact[0]['email_id'] or ''
}
return ret
def on_update(self):
self.add_calendar_event()

View File

@@ -10,7 +10,7 @@ cur_frm.cscript.sales_team_fname = "sales_team";
wn.require('app/accounts/doctype/sales_taxes_and_charges_master/sales_taxes_and_charges_master.js');
wn.require('app/utilities/doctype/sms_control/sms_control.js');
wn.require('app/selling/doctype/sales_common/sales_common.js');
wn.require('app/selling/sales_common.js');
wn.require('app/accounts/doctype/sales_invoice/pos.js');
erpnext.selling.QuotationController = erpnext.selling.SellingController.extend({

View File

@@ -19,46 +19,10 @@ class DocType(SellingController):
self.doclist = doclist
self.tname = 'Quotation Item'
self.fname = 'quotation_details'
# Get contact person details based on customer selected
# ------------------------------------------------------
def get_contact_details(self):
return get_obj('Sales Common').get_contact_details(self,0)
# Get Item Details
# -----------------
def get_item_details(self, args=None):
import json
args = args and json.loads(args) or {}
if args.get('item_code'):
return get_obj('Sales Common').get_item_details(args, self)
else:
obj = get_obj('Sales Common')
for doc in self.doclist:
if doc.fields.get('item_code'):
arg = {
'item_code': doc.fields.get('item_code'),
'income_account': doc.fields.get('income_account'),
'cost_center': doc.fields.get('cost_center'),
'warehouse': doc.fields.get('warehouse')
}
res = obj.get_item_details(arg, self) or {}
for r in res:
if not doc.fields.get(r):
doc.fields[r] = res[r]
def has_sales_order(self):
return webnotes.conn.get_value("Sales Order Item", {"prevdoc_docname": self.doc.name, "docstatus": 1})
# Re-calculates Basic Rate & amount based on Price List Selected
# --------------------------------------------------------------
def get_adj_percent(self, arg=''):
get_obj('Sales Common').get_adj_percent(self)
# Does not allow same item code to be entered twice
# -------------------------------------------------
def validate_for_items(self):
chk_dupl_itm = []
for d in getlist(self.doclist,'quotation_details'):
@@ -68,9 +32,6 @@ class DocType(SellingController):
else:
chk_dupl_itm.append([cstr(d.item_code),cstr(d.description)])
#do not allow sales item in maintenance quotation and service item in sales quotation
#-----------------------------------------------------------------------------------------------
def validate_order_type(self):
super(DocType, self).validate_order_type()
@@ -96,15 +57,8 @@ class DocType(SellingController):
self.set_status()
self.validate_order_type()
self.validate_for_items()
self.validate_uom_is_integer("stock_uom", "qty")
sales_com_obj = get_obj('Sales Common')
sales_com_obj.check_active_sales_items(self)
sales_com_obj.validate_max_discount(self,'quotation_details')
#update enquiry
#------------------
def update_opportunity(self):
for opportunity in self.doclist.get_distinct_values("prevdoc_docname"):
webnotes.bean("Opportunity", opportunity).get_controller().set_status(update=True)

View File

@@ -1 +0,0 @@
Common scripts used in Sales Cycle.

View File

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

View File

@@ -1,650 +0,0 @@
// Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
// License: GNU General Public License v3. See license.txt
// Preset
// ------
// cur_frm.cscript.tname - Details table name
// cur_frm.cscript.fname - Details fieldname
// cur_frm.cscript.other_fname - wn.require('app/accounts/doctype/sales_taxes_and_charges_master/sales_taxes_and_charges_master.js'); fieldname
// cur_frm.cscript.sales_team_fname - Sales Team fieldname
wn.provide("erpnext.selling");
wn.require("app/js/transaction.js");
wn.require("app/js/controllers/accounts.js");
erpnext.selling.SellingController = erpnext.TransactionController.extend({
onload: function() {
this._super();
this.toggle_rounded_total();
this.setup_queries();
this.toggle_editable_price_list_rate();
},
setup_queries: function() {
var me = this;
this.frm.add_fetch("sales_partner", "commission_rate", "commission_rate");
$.each([["customer_address", "customer_filter"],
["shipping_address_name", "customer_filter"],
["contact_person", "customer_filter"],
["customer", "customer"],
["lead", "lead"]],
function(i, opts) {
if(me.frm.fields_dict[opts[0]])
me.frm.set_query(opts[0], erpnext.queries[opts[1]]);
});
if(this.frm.fields_dict.charge) {
this.frm.set_query("charge", function() {
return {
filters: [
['Sales Taxes and Charges Master', 'company', '=', me.frm.doc.company],
['Sales Taxes and Charges Master', 'docstatus', '!=', 2]
]
}
});
}
if(this.frm.fields_dict.selling_price_list) {
this.frm.set_query("selling_price_list", function() {
return { filters: { buying_or_selling: "Selling" } };
});
}
if(!this.fname) {
return;
}
if(this.frm.fields_dict[this.fname].grid.get_field('item_code')) {
this.frm.set_query("item_code", this.fname, function() {
return {
query: "controllers.queries.item_query",
filters: (me.frm.doc.order_type === "Maintenance" ?
{'is_service_item': 'Yes'}:
{'is_sales_item': 'Yes' })
}
});
}
if(this.frm.fields_dict[this.fname].grid.get_field('batch_no')) {
this.frm.set_query("batch_no", this.fname, function(doc, cdt, cdn) {
var item = wn.model.get_doc(cdt, cdn);
if(!item.item_code) {
wn.throw("Please enter Item Code to get batch no");
} else {
if(item.warehouse) {
return {
query : "selling.doctype.sales_common.sales_common.get_batch_no",
filters: {
'item_code': item.item_code,
'warehouse': item.warehouse,
'posting_date': me.frm.doc.posting_date
}
}
} else {
return{
query : "selling.doctype.sales_common.sales_common.get_batch_no",
filters: {
'item_code': item.item_code,
'posting_date': me.frm.doc.posting_date
}
}
}
}
});
}
if(this.frm.fields_dict.sales_team && this.frm.fields_dict.sales_team.grid.get_field("sales_person")) {
this.frm.set_query("sales_person", "sales_team", erpnext.queries.not_a_group_filter);
}
},
refresh: function() {
this._super();
this.frm.toggle_display("customer_name",
(this.customer_name && this.frm.doc.customer_name!==this.frm.doc.customer));
if(this.frm.fields_dict.packing_details) {
var packing_list_exists = this.frm.get_doclist({parentfield: "packing_details"}).length;
this.frm.toggle_display("packing_list", packing_list_exists ? true : false);
}
},
customer: function() {
var me = this;
if(this.frm.doc.customer || this.frm.doc.debit_to) {
if(!this.frm.doc.company) {
this.frm.set_value("customer", null);
msgprint(wn._("Please specify Company"));
} else {
var selling_price_list = this.frm.doc.selling_price_list;
return this.frm.call({
doc: this.frm.doc,
method: "set_customer_defaults",
freeze: true,
callback: function(r) {
if(!r.exc) {
(me.frm.doc.selling_price_list !== selling_price_list) ?
me.selling_price_list() :
me.price_list_currency();
}
}
});
}
}
},
customer_address: function() {
var me = this;
if(this.frm.doc.customer) {
return this.frm.call({
doc: this.frm.doc,
args: {
customer: this.frm.doc.customer,
address: this.frm.doc.customer_address,
contact: this.frm.doc.contact_person
},
method: "set_customer_address",
freeze: true,
});
}
},
contact_person: function() {
this.customer_address();
},
barcode: function(doc, cdt, cdn) {
this.item_code(doc, cdt, cdn);
},
item_code: function(doc, cdt, cdn) {
var me = this;
var item = wn.model.get_doc(cdt, cdn);
if(item.item_code || item.barcode) {
if(!this.validate_company_and_party("customer")) {
cur_frm.fields_dict[me.frm.cscript.fname].grid.grid_rows[item.idx - 1].remove();
} else {
return this.frm.call({
method: "selling.utils.get_item_details",
child: item,
args: {
args: {
item_code: item.item_code,
barcode: item.barcode,
warehouse: item.warehouse,
doctype: me.frm.doc.doctype,
parentfield: item.parentfield,
customer: me.frm.doc.customer,
currency: me.frm.doc.currency,
conversion_rate: me.frm.doc.conversion_rate,
selling_price_list: me.frm.doc.selling_price_list,
price_list_currency: me.frm.doc.price_list_currency,
plc_conversion_rate: me.frm.doc.plc_conversion_rate,
company: me.frm.doc.company,
order_type: me.frm.doc.order_type,
is_pos: cint(me.frm.doc.is_pos),
}
},
callback: function(r) {
if(!r.exc) {
me.frm.script_manager.trigger("ref_rate", cdt, cdn);
}
}
});
}
}
},
selling_price_list: function() {
this.get_price_list_currency("Selling");
},
ref_rate: function(doc, cdt, cdn) {
var item = wn.model.get_doc(cdt, cdn);
wn.model.round_floats_in(item, ["ref_rate", "adj_rate"]);
item.export_rate = flt(item.ref_rate * (1 - item.adj_rate / 100.0),
precision("export_rate", item));
this.calculate_taxes_and_totals();
},
adj_rate: function(doc, cdt, cdn) {
var item = wn.model.get_doc(cdt, cdn);
if(!item.ref_rate) {
item.adj_rate = 0.0;
} else {
this.ref_rate(doc, cdt, cdn);
}
},
export_rate: function(doc, cdt, cdn) {
var item = wn.model.get_doc(cdt, cdn);
wn.model.round_floats_in(item, ["export_rate", "ref_rate"]);
if(item.ref_rate) {
item.adj_rate = flt((1 - item.export_rate / item.ref_rate) * 100.0,
precision("adj_rate", item));
} else {
item.adj_rate = 0.0;
}
this.calculate_taxes_and_totals();
},
commission_rate: function() {
this.calculate_commission();
refresh_field("total_commission");
},
total_commission: function() {
if(this.frm.doc.net_total) {
wn.model.round_floats_in(this.frm.doc, ["net_total", "total_commission"]);
if(this.frm.doc.net_total < this.frm.doc.total_commission) {
var msg = (wn._("[Error]") + " " +
wn._(wn.meta.get_label(this.frm.doc.doctype, "total_commission",
this.frm.doc.name)) + " > " +
wn._(wn.meta.get_label(this.frm.doc.doctype, "net_total", this.frm.doc.name)));
msgprint(msg);
throw msg;
}
this.frm.set_value("commission_rate",
flt(this.frm.doc.total_commission * 100.0 / this.frm.doc.net_total));
}
},
allocated_percentage: function(doc, cdt, cdn) {
var sales_person = wn.model.get_doc(cdt, cdn);
if(sales_person.allocated_percentage) {
sales_person.allocated_percentage = flt(sales_person.allocated_percentage,
precision("allocated_percentage", sales_person));
sales_person.allocated_amount = flt(this.frm.doc.net_total *
sales_person.allocated_percentage / 100.0,
precision("allocated_amount", sales_person));
refresh_field(["allocated_percentage", "allocated_amount"], sales_person.name,
sales_person.parentfield);
}
},
warehouse: function(doc, cdt, cdn) {
var item = wn.model.get_doc(cdt, cdn);
if(item.item_code && item.warehouse) {
return this.frm.call({
method: "selling.utils.get_available_qty",
child: item,
args: {
item_code: item.item_code,
warehouse: item.warehouse,
},
});
}
},
toggle_rounded_total: function() {
var me = this;
if(cint(wn.defaults.get_global_default("disable_rounded_total"))) {
$.each(["rounded_total", "rounded_total_export"], function(i, fieldname) {
me.frm.set_df_property(fieldname, "print_hide", 1);
me.frm.toggle_display(fieldname, false);
});
}
},
toggle_editable_price_list_rate: function() {
var df = wn.meta.get_docfield(this.tname, "ref_rate", this.frm.doc.name);
var editable_price_list_rate = cint(wn.defaults.get_default("editable_price_list_rate"));
if(df && editable_price_list_rate) {
df.read_only = 0;
}
},
calculate_taxes_and_totals: function() {
this._super();
this.calculate_total_advance("Sales Invoice", "advance_adjustment_details");
this.calculate_commission();
this.calculate_contribution();
// TODO check for custom_recalc in custom scripts of server
this.frm.refresh_fields();
},
calculate_item_values: function() {
var me = this;
$.each(this.frm.item_doclist, function(i, item) {
wn.model.round_floats_in(item);
item.export_amount = flt(item.export_rate * item.qty, precision("export_amount", item));
me._set_in_company_currency(item, "ref_rate", "base_ref_rate");
me._set_in_company_currency(item, "export_rate", "basic_rate");
me._set_in_company_currency(item, "export_amount", "amount");
});
},
determine_exclusive_rate: function() {
var me = this;
$.each(me.frm.item_doclist, function(n, item) {
var item_tax_map = me._load_item_tax_rate(item.item_tax_rate);
var cumulated_tax_fraction = 0.0;
$.each(me.frm.tax_doclist, function(i, tax) {
tax.tax_fraction_for_current_item = me.get_current_tax_fraction(tax, item_tax_map);
if(i==0) {
tax.grand_total_fraction_for_current_item = 1 + tax.tax_fraction_for_current_item;
} else {
tax.grand_total_fraction_for_current_item =
me.frm.tax_doclist[i-1].grand_total_fraction_for_current_item +
tax.tax_fraction_for_current_item;
}
cumulated_tax_fraction += tax.tax_fraction_for_current_item;
});
if(cumulated_tax_fraction) {
item.amount = flt(
(item.export_amount * me.frm.doc.conversion_rate) / (1 + cumulated_tax_fraction),
precision("amount", item));
item.basic_rate = flt(item.amount / item.qty, precision("basic_rate", item));
if(item.adj_rate == 100) {
item.base_ref_rate = item.basic_rate;
item.basic_rate = 0.0;
} else {
item.base_ref_rate = flt(item.basic_rate / (1 - item.adj_rate / 100.0),
precision("base_ref_rate", item));
}
}
});
},
get_current_tax_fraction: function(tax, item_tax_map) {
// Get tax fraction for calculating tax exclusive amount
// from tax inclusive amount
var current_tax_fraction = 0.0;
if(cint(tax.included_in_print_rate)) {
var tax_rate = this._get_tax_rate(tax, item_tax_map);
if(tax.charge_type == "On Net Total") {
current_tax_fraction = (tax_rate / 100.0);
} else if(tax.charge_type == "On Previous Row Amount") {
current_tax_fraction = (tax_rate / 100.0) *
this.frm.tax_doclist[cint(tax.row_id) - 1].tax_fraction_for_current_item;
} else if(tax.charge_type == "On Previous Row Total") {
current_tax_fraction = (tax_rate / 100.0) *
this.frm.tax_doclist[cint(tax.row_id) - 1].grand_total_fraction_for_current_item;
}
}
return current_tax_fraction;
},
calculate_net_total: function() {
var me = this;
this.frm.doc.net_total = this.frm.doc.net_total_export = 0.0;
$.each(this.frm.item_doclist, function(i, item) {
me.frm.doc.net_total += item.amount;
me.frm.doc.net_total_export += item.export_amount;
});
wn.model.round_floats_in(this.frm.doc, ["net_total", "net_total_export"]);
},
calculate_totals: function() {
var tax_count = this.frm.tax_doclist.length;
this.frm.doc.grand_total = flt(
tax_count ? this.frm.tax_doclist[tax_count - 1].total : this.frm.doc.net_total,
precision("grand_total"));
this.frm.doc.grand_total_export = flt(this.frm.doc.grand_total / this.frm.doc.conversion_rate,
precision("grand_total_export"));
this.frm.doc.other_charges_total = flt(this.frm.doc.grand_total - this.frm.doc.net_total,
precision("other_charges_total"));
this.frm.doc.other_charges_total_export = flt(
this.frm.doc.grand_total_export - this.frm.doc.net_total_export,
precision("other_charges_total_export"));
this.frm.doc.rounded_total = Math.round(this.frm.doc.grand_total);
this.frm.doc.rounded_total_export = Math.round(this.frm.doc.grand_total_export);
},
calculate_outstanding_amount: function() {
// NOTE:
// paid_amount and write_off_amount is only for POS Invoice
// total_advance is only for non POS Invoice
if(this.frm.doc.doctype == "Sales Invoice" && this.frm.doc.docstatus==0) {
wn.model.round_floats_in(this.frm.doc, ["grand_total", "total_advance", "write_off_amount",
"paid_amount"]);
var total_amount_to_pay = this.frm.doc.grand_total - this.frm.doc.write_off_amount - this.frm.doc.total_advance;
this.frm.doc.paid_amount = this.frm.doc.is_pos? flt(total_amount_to_pay): 0.0;
this.frm.doc.outstanding_amount = flt(total_amount_to_pay - this.frm.doc.paid_amount,
precision("outstanding_amount"));
}
},
calculate_commission: function() {
if(this.frm.fields_dict.commission_rate) {
if(this.frm.doc.commission_rate > 100) {
var msg = wn._(wn.meta.get_label(this.frm.doc.doctype, "commission_rate", this.frm.doc.name)) +
" " + wn._("cannot be greater than 100");
msgprint(msg);
throw msg;
}
this.frm.doc.total_commission = flt(this.frm.doc.net_total * this.frm.doc.commission_rate / 100.0,
precision("total_commission"));
}
},
calculate_contribution: function() {
var me = this;
$.each(wn.model.get_doclist(this.frm.doc.doctype, this.frm.doc.name,
{parentfield: "sales_team"}), function(i, sales_person) {
wn.model.round_floats_in(sales_person);
if(sales_person.allocated_percentage) {
sales_person.allocated_amount = flt(
me.frm.doc.net_total * sales_person.allocated_percentage / 100.0,
precision("allocated_amount", sales_person));
}
});
},
_cleanup: function() {
this._super();
this.frm.doc.in_words = this.frm.doc.in_words_export = "";
},
show_item_wise_taxes: function() {
if(this.frm.fields_dict.other_charges_calculation) {
$(this.get_item_wise_taxes_html())
.appendTo($(this.frm.fields_dict.other_charges_calculation.wrapper).empty());
}
},
charge: function() {
var me = this;
if(this.frm.doc.charge) {
return this.frm.call({
doc: this.frm.doc,
method: "get_other_charges",
callback: function(r) {
if(!r.exc) {
me.calculate_taxes_and_totals();
}
}
});
}
},
shipping_rule: function() {
var me = this;
if(this.frm.doc.shipping_rule) {
return this.frm.call({
doc: this.frm.doc,
method: "apply_shipping_rule",
callback: function(r) {
if(!r.exc) {
me.calculate_taxes_and_totals();
}
}
})
}
},
set_dynamic_labels: function() {
this._super();
set_sales_bom_help(this.frm.doc);
},
change_form_labels: function(company_currency) {
var me = this;
var field_label_map = {};
var setup_field_label_map = function(fields_list, currency) {
$.each(fields_list, function(i, fname) {
var docfield = wn.meta.docfield_map[me.frm.doc.doctype][fname];
if(docfield) {
var label = wn._(docfield.label || "").replace(/\([^\)]*\)/g, "");
field_label_map[fname] = label.trim() + " (" + currency + ")";
}
});
};
setup_field_label_map(["net_total", "other_charges_total", "grand_total",
"rounded_total", "in_words",
"outstanding_amount", "total_advance", "paid_amount", "write_off_amount"],
company_currency);
setup_field_label_map(["net_total_export", "other_charges_total_export", "grand_total_export",
"rounded_total_export", "in_words_export"], this.frm.doc.currency);
setup_field_label_map(["conversion_rate"], "1 " + this.frm.doc.currency
+ " = [?] " + company_currency);
if(this.frm.doc.price_list_currency && this.frm.doc.price_list_currency!=company_currency) {
setup_field_label_map(["plc_conversion_rate"], "1 " + this.frm.doc.price_list_currency
+ " = [?] " + company_currency);
}
// toggle fields
this.frm.toggle_display(["conversion_rate", "net_total", "other_charges_total",
"grand_total", "rounded_total", "in_words"],
this.frm.doc.currency != company_currency);
this.frm.toggle_display(["plc_conversion_rate"],
this.frm.doc.price_list_currency != company_currency);
// set labels
$.each(field_label_map, function(fname, label) {
me.frm.fields_dict[fname].set_label(label);
});
},
change_grid_labels: function(company_currency) {
var me = this;
var field_label_map = {};
var setup_field_label_map = function(fields_list, currency, parentfield) {
var grid_doctype = me.frm.fields_dict[parentfield].grid.doctype;
$.each(fields_list, function(i, fname) {
var docfield = wn.meta.docfield_map[grid_doctype][fname];
if(docfield) {
var label = wn._(docfield.label || "").replace(/\([^\)]*\)/g, "");
field_label_map[grid_doctype + "-" + fname] =
label.trim() + " (" + currency + ")";
}
});
}
setup_field_label_map(["basic_rate", "base_ref_rate", "amount"],
company_currency, this.fname);
setup_field_label_map(["export_rate", "ref_rate", "export_amount"],
this.frm.doc.currency, this.fname);
setup_field_label_map(["tax_amount", "total"], company_currency, "other_charges");
if(this.frm.fields_dict["advance_allocation_details"]) {
setup_field_label_map(["advance_amount", "allocated_amount"], company_currency,
"advance_allocation_details");
}
// toggle columns
var item_grid = this.frm.fields_dict[this.fname].grid;
var show = (this.frm.doc.currency != company_currency) ||
(wn.model.get_doclist(cur_frm.doctype, cur_frm.docname,
{parentfield: "other_charges", included_in_print_rate: 1}).length);
$.each(["basic_rate", "base_ref_rate", "amount"], function(i, fname) {
if(wn.meta.get_docfield(item_grid.doctype, fname))
item_grid.set_column_disp(fname, show);
});
// set labels
var $wrapper = $(this.frm.wrapper);
$.each(field_label_map, function(fname, label) {
fname = fname.split("-");
var df = wn.meta.get_docfield(fname[0], fname[1], me.frm.doc.name);
if(df) df.label = label;
});
},
shipping_address_name: function () {
var me = this;
if(this.frm.doc.shipping_address_name) {
wn.model.with_doc("Address", this.frm.doc.shipping_address_name, function(name) {
var address = wn.model.get_doc("Address", name);
var out = $.map(["address_line1", "address_line2", "city"],
function(f) { return address[f]; });
var state_pincode = $.map(["state", "pincode"], function(f) { return address[f]; }).join(" ");
if(state_pincode) out.push(state_pincode);
if(address["country"]) out.push(address["country"]);
out.concat($.map([["Phone:", address["phone"]], ["Fax:", address["fax"]]],
function(val) { return val[1] ? val.join(" ") : null; }));
me.frm.set_value("shipping_address", out.join("\n"));
});
}
}
});
// Help for Sales BOM items
var set_sales_bom_help = function(doc) {
if(!cur_frm.fields_dict.packing_list) return;
if (getchildren('Delivery Note Packing Item', doc.name, 'packing_details').length) {
$(cur_frm.fields_dict.packing_list.row.wrapper).toggle(true);
if (inList(['Delivery Note', 'Sales Invoice'], doc.doctype)) {
help_msg = "<div class='alert alert-warning'> \
For 'Sales BOM' items, warehouse, serial no and batch no \
will be considered from the 'Packing List' table. \
If warehouse and batch no are same for all packing items for any 'Sales BOM' item, \
those values can be entered in the main item table, values will be copied to 'Packing List' table. \
</div>";
wn.meta.get_docfield(doc.doctype, 'sales_bom_help', doc.name).options = help_msg;
}
} else {
$(cur_frm.fields_dict.packing_list.row.wrapper).toggle(false);
if (inList(['Delivery Note', 'Sales Invoice'], doc.doctype)) {
wn.meta.get_docfield(doc.doctype, 'sales_bom_help', doc.name).options = '';
}
}
refresh_field('sales_bom_help');
}

View File

@@ -1,317 +0,0 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
import webnotes
from webnotes.utils import cint, cstr, flt
from webnotes.model.doc import addchild
from webnotes.model.bean import getlist
from webnotes.model.code import get_obj
from webnotes import msgprint, _
get_value = webnotes.conn.get_value
from utilities.transaction_base import TransactionBase
class DocType(TransactionBase):
def __init__(self,d,dl):
self.doc, self.doclist = d, dl
def get_contact_details(self, obj = '', primary = 0):
cond = " and contact_name = '"+cstr(obj.doc.contact_person)+"'"
if primary: cond = " and is_primary_contact = 'Yes'"
contact = webnotes.conn.sql("select contact_name, contact_no, email_id, contact_address from `tabContact` where customer = '%s' and docstatus != 2 %s" %(obj.doc.customer, cond), as_dict = 1)
if not contact:
return
c = contact[0]
obj.doc.contact_person = c['contact_name'] or ''
obj.doc.contact_no = c['contact_no'] or ''
obj.doc.email_id = c['email_id'] or ''
obj.doc.customer_mobile_no = c['contact_no'] or ''
if c['contact_address']:
obj.doc.customer_address = c['contact_address']
def get_invoice_details(self, obj = ''):
if obj.doc.company:
acc_head = webnotes.conn.sql("select name from `tabAccount` where name = '%s' and docstatus != 2" % (cstr(obj.doc.customer) + " - " + webnotes.conn.get_value('Company', obj.doc.company, 'abbr')))
obj.doc.debit_to = acc_head and acc_head[0][0] or ''
def get_tax_details(self, item_code, obj):
import json
tax = webnotes.conn.sql("select tax_type, tax_rate from `tabItem Tax` where parent = %s" , item_code)
t = {}
for x in tax: t[x[0]] = flt(x[1])
ret = {
'item_tax_rate' : tax and json.dumps(t) or ''
}
return ret
def get_serial_details(self, serial_no, obj):
import json
item = webnotes.conn.sql("select item_code, make, label,brand, description from `tabSerial No` where name = '%s' and docstatus != 2" %(serial_no), as_dict=1)
tax = webnotes.conn.sql("select tax_type, tax_rate from `tabItem Tax` where parent = %s" , item[0]['item_code'])
t = {}
for x in tax: t[x[0]] = flt(x[1])
ret = {
'item_code' : item and item[0]['item_code'] or '',
'make' : item and item[0]['make'] or '',
'label' : item and item[0]['label'] or '',
'brand' : item and item[0]['brand'] or '',
'description' : item and item[0]['description'] or '',
'item_tax_rate' : json.dumps(t)
}
return ret
# To verify whether rate entered in details table does not exceed max discount %
# =======================================================================================
def validate_max_discount(self,obj, detail_table):
for d in getlist(obj.doclist, detail_table):
discount = webnotes.conn.sql("select max_discount from tabItem where name = '%s'" %(d.item_code),as_dict = 1)
if discount and discount[0]['max_discount'] and (flt(d.adj_rate)>flt(discount[0]['max_discount'])):
msgprint("You cannot give more than " + cstr(discount[0]['max_discount']) + " % discount on Item Code : "+cstr(d.item_code))
raise Exception
def get_item_list(self, obj, is_stopped=0):
"""get item list"""
il = []
for d in getlist(obj.doclist, obj.fname):
reserved_warehouse = ""
reserved_qty_for_main_item = 0
if obj.doc.doctype == "Sales Order":
if (webnotes.conn.get_value("Item", d.item_code, "is_stock_item") == 'Yes' or
self.has_sales_bom(d.item_code)) and not d.reserved_warehouse:
webnotes.throw(_("Please enter Reserved Warehouse for item ") +
d.item_code + _(" as it is stock Item or packing item"))
reserved_warehouse = d.reserved_warehouse
if flt(d.qty) > flt(d.delivered_qty):
reserved_qty_for_main_item = flt(d.qty) - flt(d.delivered_qty)
if obj.doc.doctype == "Delivery Note" and d.against_sales_order:
# if SO qty is 10 and there is tolerance of 20%, then it will allow DN of 12.
# But in this case reserved qty should only be reduced by 10 and not 12
already_delivered_qty = self.get_already_delivered_qty(obj.doc.name,
d.against_sales_order, d.prevdoc_detail_docname)
so_qty, reserved_warehouse = self.get_so_qty_and_warehouse(d.prevdoc_detail_docname)
if already_delivered_qty + d.qty > so_qty:
reserved_qty_for_main_item = -(so_qty - already_delivered_qty)
else:
reserved_qty_for_main_item = -flt(d.qty)
if self.has_sales_bom(d.item_code):
for p in getlist(obj.doclist, 'packing_details'):
if p.parent_detail_docname == d.name and p.parent_item == d.item_code:
# the packing details table's qty is already multiplied with parent's qty
il.append(webnotes._dict({
'warehouse': p.warehouse,
'reserved_warehouse': reserved_warehouse,
'item_code': p.item_code,
'qty': flt(p.qty),
'reserved_qty': (flt(p.qty)/flt(d.qty)) * reserved_qty_for_main_item,
'uom': p.uom,
'batch_no': cstr(p.batch_no).strip(),
'serial_no': cstr(p.serial_no).strip(),
'name': d.name
}))
else:
il.append(webnotes._dict({
'warehouse': d.warehouse,
'reserved_warehouse': reserved_warehouse,
'item_code': d.item_code,
'qty': d.qty,
'reserved_qty': reserved_qty_for_main_item,
'uom': d.stock_uom,
'batch_no': cstr(d.batch_no).strip(),
'serial_no': cstr(d.serial_no).strip(),
'name': d.name
}))
return il
def get_already_delivered_qty(self, dn, so, so_detail):
qty = webnotes.conn.sql("""select sum(qty) from `tabDelivery Note Item`
where prevdoc_detail_docname = %s and docstatus = 1
and against_sales_order = %s
and parent != %s""", (so_detail, so, dn))
return qty and flt(qty[0][0]) or 0.0
def get_so_qty_and_warehouse(self, so_detail):
so_item = webnotes.conn.sql("""select qty, reserved_warehouse from `tabSales Order Item`
where name = %s and docstatus = 1""", so_detail, as_dict=1)
so_qty = so_item and flt(so_item[0]["qty"]) or 0.0
so_warehouse = so_item and so_item[0]["reserved_warehouse"] or ""
return so_qty, so_warehouse
def has_sales_bom(self, item_code):
return webnotes.conn.sql("select name from `tabSales BOM` where new_item_code=%s and docstatus != 2", item_code)
def get_sales_bom_items(self, item_code):
return webnotes.conn.sql("""select t1.item_code, t1.qty, t1.uom
from `tabSales BOM Item` t1, `tabSales BOM` t2
where t2.new_item_code=%s and t1.parent = t2.name""", item_code, as_dict=1)
def get_packing_item_details(self, item):
return webnotes.conn.sql("select item_name, description, stock_uom from `tabItem` where name = %s", item, as_dict = 1)[0]
def get_bin_qty(self, item, warehouse):
det = webnotes.conn.sql("select actual_qty, projected_qty from `tabBin` where item_code = '%s' and warehouse = '%s'" % (item, warehouse), as_dict = 1)
return det and det[0] or ''
def update_packing_list_item(self,obj, packing_item_code, qty, warehouse, line):
bin = self.get_bin_qty(packing_item_code, warehouse)
item = self.get_packing_item_details(packing_item_code)
# check if exists
exists = 0
for d in getlist(obj.doclist, 'packing_details'):
if d.parent_item == line.item_code and d.item_code == packing_item_code and d.parent_detail_docname == line.name:
pi, exists = d, 1
break
if not exists:
pi = addchild(obj.doc, 'packing_details', 'Delivery Note Packing Item',
obj.doclist)
pi.parent_item = line.item_code
pi.item_code = packing_item_code
pi.item_name = item['item_name']
pi.parent_detail_docname = line.name
pi.description = item['description']
pi.uom = item['stock_uom']
pi.qty = flt(qty)
pi.actual_qty = bin and flt(bin['actual_qty']) or 0
pi.projected_qty = bin and flt(bin['projected_qty']) or 0
if not pi.warehouse:
pi.warehouse = warehouse
if not pi.batch_no:
pi.batch_no = cstr(line.batch_no)
pi.idx = self.packing_list_idx
# saved, since this function is called on_update of delivery note
pi.save()
self.packing_list_idx += 1
def make_packing_list(self, obj, fname):
"""make packing list for sales bom item"""
self.packing_list_idx = 0
parent_items = []
for d in getlist(obj.doclist, fname):
warehouse = fname == "sales_order_details" and d.reserved_warehouse or d.warehouse
if self.has_sales_bom(d.item_code):
for i in self.get_sales_bom_items(d.item_code):
self.update_packing_list_item(obj, i['item_code'], flt(i['qty'])*flt(d.qty), warehouse, d)
if [d.item_code, d.name] not in parent_items:
parent_items.append([d.item_code, d.name])
obj.doclist = self.cleanup_packing_list(obj, parent_items)
return obj.doclist
def cleanup_packing_list(self, obj, parent_items):
"""Remove all those child items which are no longer present in main item table"""
delete_list = []
for d in getlist(obj.doclist, 'packing_details'):
if [d.parent_item, d.parent_detail_docname] not in parent_items:
# mark for deletion from doclist
delete_list.append(d.name)
if not delete_list:
return obj.doclist
# delete from doclist
obj.doclist = webnotes.doclist(filter(lambda d: d.name not in delete_list, obj.doclist))
# delete from db
webnotes.conn.sql("""\
delete from `tabDelivery Note Packing Item`
where name in (%s)"""
% (", ".join(["%s"] * len(delete_list))),
tuple(delete_list))
return obj.doclist
def get_month(self,date):
"""Get month based on date (required in sales person and sales partner)"""
month_list = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']
month_idx = cint(cstr(date).split('-')[1])-1
return month_list[month_idx]
# **** Check for Stop SO as no transactions can be made against Stopped SO. Need to unstop it. ***
def check_stop_sales_order(self,obj):
for d in getlist(obj.doclist,obj.fname):
ref_doc_name = ''
if d.fields.has_key('against_sales_order') and d.against_sales_order:
ref_doc_name = d.against_sales_order
elif d.fields.has_key('sales_order') and d.sales_order and not d.delivery_note:
ref_doc_name = d.sales_order
if ref_doc_name:
so_status = webnotes.conn.sql("select status from `tabSales Order` where name = %s",ref_doc_name)
so_status = so_status and so_status[0][0] or ''
if so_status == 'Stopped':
msgprint("You cannot do any transaction against Sales Order : '%s' as it is Stopped." %(ref_doc_name))
raise Exception
def check_active_sales_items(self,obj):
for d in getlist(obj.doclist, obj.fname):
if d.item_code:
item = webnotes.conn.sql("""select docstatus, is_sales_item,
is_service_item, default_income_account from tabItem where name = %s""",
d.item_code, as_dict=True)[0]
if item.is_sales_item == 'No' and item.is_service_item == 'No':
msgprint("Item : '%s' is neither Sales nor Service Item" % (d.item_code))
raise Exception
if d.income_account and not item.default_income_account:
webnotes.conn.set_value("Item", d.item_code, "default_income_account", d.income_account)
def check_credit(self,obj,grand_total):
acc_head = webnotes.conn.sql("select name from `tabAccount` where company = '%s' and master_name = '%s'"%(obj.doc.company, obj.doc.customer))
if acc_head:
tot_outstanding = 0
dbcr = webnotes.conn.sql("""select sum(debit), sum(credit) from `tabGL Entry`
where account = %s""", acc_head[0][0])
if dbcr:
tot_outstanding = flt(dbcr[0][0])-flt(dbcr[0][1])
exact_outstanding = flt(tot_outstanding) + flt(grand_total)
get_obj('Account',acc_head[0][0]).check_credit_limit(acc_head[0][0], obj.doc.company, exact_outstanding)
def get_batch_no(doctype, txt, searchfield, start, page_len, filters):
from controllers.queries import get_match_cond
if filters.has_key('warehouse'):
return webnotes.conn.sql("""select batch_no from `tabStock Ledger Entry` sle
where item_code = '%(item_code)s'
and warehouse = '%(warehouse)s'
and batch_no like '%(txt)s'
and exists(select * from `tabBatch`
where name = sle.batch_no
and (ifnull(expiry_date, '')='' or expiry_date >= '%(posting_date)s')
and docstatus != 2)
%(mcond)s
group by batch_no having sum(actual_qty) > 0
order by batch_no desc
limit %(start)s, %(page_len)s """ % {'item_code': filters['item_code'],
'warehouse': filters['warehouse'], 'posting_date': filters['posting_date'],
'txt': "%%%s%%" % txt, 'mcond':get_match_cond(doctype, searchfield),
'start': start, 'page_len': page_len})
else:
return webnotes.conn.sql("""select name from tabBatch
where docstatus != 2
and item = '%(item_code)s'
and (ifnull(expiry_date, '')='' or expiry_date >= '%(posting_date)s')
and name like '%(txt)s'
%(mcond)s
order by name desc
limit %(start)s, %(page_len)s""" % {'item_code': filters['item_code'],
'posting_date': filters['posting_date'], 'txt': "%%%s%%" % txt,
'mcond':get_match_cond(doctype, searchfield),'start': start,
'page_len': page_len})

View File

@@ -1,19 +0,0 @@
[
{
"creation": "2012-03-27 14:36:14",
"docstatus": 0,
"modified": "2013-07-10 14:54:19",
"modified_by": "Administrator",
"owner": "Administrator"
},
{
"doctype": "DocType",
"issingle": 1,
"module": "Selling",
"name": "__common__"
},
{
"doctype": "DocType",
"name": "Sales Common"
}
]

View File

@@ -9,7 +9,7 @@ cur_frm.cscript.other_fname = "other_charges";
cur_frm.cscript.sales_team_fname = "sales_team";
wn.require('app/selling/doctype/sales_common/sales_common.js');
wn.require('app/selling/sales_common.js');
wn.require('app/accounts/doctype/sales_taxes_and_charges_master/sales_taxes_and_charges_master.js');
wn.require('app/utilities/doctype/sms_control/sms_control.js');
wn.require('app/accounts/doctype/sales_invoice/pos.js');

View File

@@ -11,8 +11,6 @@ from webnotes.model.code import get_obj
from webnotes import msgprint
from webnotes.model.mapper import get_mapped_doclist
from controllers.selling_controller import SellingController
class DocType(SellingController):
@@ -26,18 +24,6 @@ class DocType(SellingController):
self.partner_tname = 'Partner Target Detail'
self.territory_tname = 'Territory Target Detail'
def get_contact_details(self):
get_obj('Sales Common').get_contact_details(self,0)
def get_comm_rate(self, sales_partner):
return get_obj('Sales Common').get_comm_rate(sales_partner, self)
def get_adj_percent(self, arg=''):
get_obj('Sales Common').get_adj_percent(self)
def get_available_qty(self,args):
return get_obj('Sales Common').get_available_qty(eval(args))
def validate_mandatory(self):
# validate transaction date v/s delivery date
if self.doc.delivery_date:
@@ -124,12 +110,9 @@ class DocType(SellingController):
self.validate_uom_is_integer("stock_uom", "qty")
self.validate_for_items()
self.validate_warehouse()
sales_com_obj = get_obj(dt = 'Sales Common')
sales_com_obj.check_active_sales_items(self)
sales_com_obj.validate_max_discount(self,'sales_order_details')
self.doclist = sales_com_obj.make_packing_list(self,'sales_order_details')
from stock.doctype.packed_item.packed_item import make_packing_list
self.doclist = make_packing_list(self,'sales_order_details')
self.validate_with_previous_doc()
@@ -172,14 +155,14 @@ class DocType(SellingController):
for quotation in self.doclist.get_distinct_values("prevdoc_docname"):
bean = webnotes.bean("Quotation", quotation)
if bean.doc.docstatus==2:
webnotes.throw(d.prevdoc_docname + ": " + webnotes._("Quotation is cancelled."))
webnotes.throw(quotation + ": " + webnotes._("Quotation is cancelled."))
bean.get_controller().set_status(update=True)
def on_submit(self):
self.update_stock_ledger(update_stock = 1)
get_obj('Sales Common').check_credit(self,self.doc.grand_total)
self.check_credit(self.doc.grand_total)
get_obj('Authorization Control').validate_approving_authority(self.doc.doctype, self.doc.grand_total, self)
@@ -235,21 +218,21 @@ class DocType(SellingController):
def stop_sales_order(self):
self.check_modified_date()
self.update_stock_ledger(update_stock = -1,is_stopped = 1)
self.update_stock_ledger(-1)
webnotes.conn.set(self.doc, 'status', 'Stopped')
msgprint("""%s: %s has been Stopped. To make transactions against this Sales Order
you need to Unstop it.""" % (self.doc.doctype, self.doc.name))
def unstop_sales_order(self):
self.check_modified_date()
self.update_stock_ledger(update_stock = 1,is_stopped = 1)
self.update_stock_ledger(1)
webnotes.conn.set(self.doc, 'status', 'Submitted')
msgprint("%s: %s has been Unstopped" % (self.doc.doctype, self.doc.name))
def update_stock_ledger(self, update_stock, is_stopped = 0):
def update_stock_ledger(self, update_stock):
from stock.utils import update_bin
for d in self.get_item_list(is_stopped):
for d in self.get_item_list():
if webnotes.conn.get_value("Item", d['item_code'], "is_stock_item") == "Yes":
args = {
"item_code": d['item_code'],
@@ -261,10 +244,6 @@ class DocType(SellingController):
"is_amended": self.doc.amended_from and 'Yes' or 'No'
}
update_bin(args)
def get_item_list(self, is_stopped):
return get_obj('Sales Common').get_item_list( self, is_stopped)
def on_update(self):
pass
@@ -438,4 +417,4 @@ def make_maintenance_visit(source_name, target_doclist=None):
}
}, target_doclist)
return [d.fields for d in doclist]
return [d.fields for d in doclist]

View File

@@ -361,7 +361,7 @@
"label": "Packing Details",
"oldfieldname": "packing_details",
"oldfieldtype": "Table",
"options": "Delivery Note Packing Item",
"options": "Packed Item",
"print_hide": 1,
"read_only": 1
},