Merge branch 'master' of github.com:webnotes/erpnext into wsgi

Conflicts:
	accounts/doctype/purchase_invoice/purchase_invoice.py
	accounts/doctype/sales_invoice/sales_invoice.txt
	selling/doctype/lead/lead.txt
	selling/doctype/opportunity/opportunity.txt
	stock/doctype/warehouse/warehouse.py
This commit is contained in:
Anand Doshi 2013-10-02 16:52:52 +05:30
commit fa228e9c9b
68 changed files with 1296 additions and 384 deletions

View File

@ -8,6 +8,7 @@ cur_frm.cscript.other_fname = "purchase_tax_details";
wn.provide("erpnext.accounts");
wn.require('app/accounts/doctype/purchase_taxes_and_charges_master/purchase_taxes_and_charges_master.js');
wn.require('app/buying/doctype/purchase_common/purchase_common.js');
wn.require('app/accounts/doctype/sales_invoice/pos.js');
erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
onload: function() {

View File

@ -61,19 +61,23 @@ class DocType(BuyingController):
"purchase_receipt_details")
def get_credit_to(self):
acc_head = webnotes.conn.sql("""select name, credit_days from `tabAccount`
where (name = %s or (master_name = %s and master_type = 'supplier'))
and docstatus != 2 and company = %s""",
(cstr(self.doc.supplier) + " - " + self.company_abbr,
self.doc.supplier, self.doc.company))
ret = {}
if acc_head and acc_head[0][0]:
ret['credit_to'] = acc_head[0][0]
if not self.doc.due_date:
ret['due_date'] = add_days(cstr(self.doc.posting_date), acc_head and cint(acc_head[0][1]) or 0)
elif not acc_head:
msgprint("%s does not have an Account Head in %s. You must first create it from the Supplier Master" % (self.doc.supplier, self.doc.company))
if self.doc.supplier:
acc_head = webnotes.conn.sql("""select name, credit_days from `tabAccount`
where (name = %s or (master_name = %s and master_type = 'supplier'))
and docstatus != 2 and company = %s""",
(cstr(self.doc.supplier) + " - " + self.company_abbr,
self.doc.supplier, self.doc.company))
if acc_head and acc_head[0][0]:
ret['credit_to'] = acc_head[0][0]
if not self.doc.due_date:
ret['due_date'] = add_days(cstr(self.doc.posting_date),
acc_head and cint(acc_head[0][1]) or 0)
elif not acc_head:
msgprint("%s does not have an Account Head in %s. \
You must first create it from the Supplier Master" % \
(self.doc.supplier, self.doc.company))
return ret
def set_supplier_defaults(self):

View File

@ -7,7 +7,7 @@ erpnext.POS = Class.extend({
this.frm = frm;
this.wrapper.html('<div class="container">\
<div class="row">\
<div class="customer-area col-sm-3 col-xs-6"></div>\
<div class="party-area col-sm-3 col-xs-6"></div>\
<div class="barcode-area col-sm-3 col-xs-6"></div>\
<div class="search-area col-sm-3 col-xs-6"></div>\
<div class="item-group-area col-sm-3 col-xs-6"></div>\
@ -72,6 +72,17 @@ erpnext.POS = Class.extend({
</div>\
</div></div>');
if (wn.meta.has_field(cur_frm.doc.doctype, "customer")) {
this.party = "Customer";
this.price_list = this.frm.doc.selling_price_list;
this.sales_or_purchase = "Sales";
}
else if (wn.meta.has_field(cur_frm.doc.doctype, "supplier")) {
this.party = "Supplier";
this.price_list = this.frm.doc.buying_price_list;
this.sales_or_purchase = "Purchase";
}
this.make();
var me = this;
@ -88,28 +99,29 @@ erpnext.POS = Class.extend({
});
},
make: function() {
this.make_customer();
this.make_party();
this.make_item_group();
this.make_search();
this.make_barcode();
this.make_item_list();
},
make_customer: function() {
make_party: function() {
var me = this;
this.customer = wn.ui.form.make_control({
this.party_field = wn.ui.form.make_control({
df: {
"fieldtype": "Link",
"options": "Customer",
"label": "Customer",
"fieldname": "pos_customer",
"placeholder": "Customer"
"options": this.party,
"label": this.party,
"fieldname": "pos_party",
"placeholder": this.party
},
parent: this.wrapper.find(".customer-area")
parent: this.wrapper.find(".party-area")
});
this.customer.make_input();
this.customer.$input.on("change", function() {
if(!me.customer.autocomplete_open)
wn.model.set_value("Sales Invoice", me.frm.docname, "customer", this.value);
this.party_field.make_input();
this.party_field.$input.on("change", function() {
if(!me.party_field.autocomplete_open)
wn.model.set_value(me.frm.doctype, me.frm.docname,
me.party.toLowerCase(), this.value);
});
},
make_item_group: function() {
@ -120,7 +132,7 @@ erpnext.POS = Class.extend({
"options": "Item Group",
"label": "Item Group",
"fieldname": "pos_item_group",
"placeholder": "Filter by Item Group"
"placeholder": "Item Group"
},
parent: this.wrapper.find(".item-group-area")
});
@ -138,7 +150,7 @@ erpnext.POS = Class.extend({
"options": "Item",
"label": "Item",
"fieldname": "pos_item",
"placeholder": "Select Item"
"placeholder": "Item"
},
parent: this.wrapper.find(".search-area")
});
@ -155,7 +167,7 @@ erpnext.POS = Class.extend({
"fieldtype": "Data",
"label": "Barcode",
"fieldname": "pos_barcode",
"placeholder": "Select Barcode"
"placeholder": "Barcode"
},
parent: this.wrapper.find(".barcode-area")
});
@ -171,7 +183,8 @@ erpnext.POS = Class.extend({
wn.call({
method: 'accounts.doctype.sales_invoice.pos.get_items',
args: {
price_list: cur_frm.doc.selling_price_list,
sales_or_purchase: this.sales_or_purchase,
price_list: this.price_list,
item_group: this.item_group.$input.val(),
item: this.search.$input.val()
},
@ -200,15 +213,18 @@ erpnext.POS = Class.extend({
});
// if form is local then allow this function
if (cur_frm.doc.docstatus===0) {
$("div.pos-item").on("click", function() {
if(!cur_frm.doc.customer) {
msgprint("Please select customer first.");
$(me.wrapper).find("div.pos-item").on("click", function() {
if(me.frm.doc.docstatus==0) {
if(!me.frm.doc[me.party.toLowerCase()] && ((me.frm.doctype == "Quotation" &&
me.frm.doc.quotation_to == "Customer")
|| me.frm.doctype != "Quotation")) {
msgprint("Please select " + me.party + " first.");
return;
}
me.add_to_cart($(this).attr("data-item_code"));
});
}
else
me.add_to_cart($(this).attr("data-item_code"));
}
});
}
});
},
@ -217,12 +233,12 @@ erpnext.POS = Class.extend({
var caught = false;
// get no_of_items
no_of_items = me.wrapper.find("#cart tbody").length;
var no_of_items = me.wrapper.find("#cart tbody tr").length;
// check whether the item is already added
if (no_of_items != 0) {
$.each(wn.model.get_children("Sales Invoice Item", this.frm.doc.name, "entries",
"Sales Invoice"), function(i, d) {
$.each(wn.model.get_children(this.frm.doctype + " Item", this.frm.doc.name,
this.frm.cscript.fname, this.frm.doctype), function(i, d) {
if (d.item_code == item_code)
caught = true;
});
@ -233,15 +249,16 @@ erpnext.POS = Class.extend({
me.update_qty(item_code, 1);
}
else {
var child = wn.model.add_child(me.frm.doc, "Sales Invoice Item", "entries");
var child = wn.model.add_child(me.frm.doc, this.frm.doctype + " Item",
this.frm.cscript.fname);
child.item_code = item_code;
me.frm.cscript.item_code(me.frm.doc, child.doctype, child.name);
}
},
update_qty: function(item_code, qty, textbox_qty) {
var me = this;
$.each(wn.model.get_children("Sales Invoice Item", this.frm.doc.name, "entries",
"Sales Invoice"), function(i, d) {
$.each(wn.model.get_children(this.frm.doctype + " Item", this.frm.doc.name,
this.frm.cscript.fname, this.frm.doctype), function(i, d) {
if (d.item_code == item_code) {
if (textbox_qty) {
if (qty == 0 && d.item_code == item_code)
@ -259,14 +276,24 @@ erpnext.POS = Class.extend({
},
refresh: function() {
var me = this;
this.customer.set_input(this.frm.doc.customer);
this.party_field.set_input(this.frm.doc[this.party.toLowerCase()]);
this.barcode.set_input("");
// add items
var $items = me.wrapper.find("#cart tbody").empty();
$.each(wn.model.get_children("Sales Invoice Item", this.frm.doc.name, "entries",
"Sales Invoice"), function(i, d) {
$.each(wn.model.get_children(this.frm.doctype + " Item", this.frm.doc.name,
this.frm.cscript.fname, this.frm.doctype), function(i, d) {
if (me.sales_or_purchase == "Sales") {
item_amount = d.export_amount;
rate = d.export_rate;
}
else {
item_amount = d.import_amount;
rate = d.import_rate;
}
$(repl('<tr id="%(item_code)s" data-selected="false">\
<td>%(item_code)s%(item_name)s</td>\
<td><input type="text" value="%(qty)s" \
@ -277,16 +304,16 @@ erpnext.POS = Class.extend({
item_code: d.item_code,
item_name: d.item_name===d.item_code ? "" : ("<br>" + d.item_name),
qty: d.qty,
rate: format_currency(d.ref_rate, cur_frm.doc.price_list_currency),
amount: format_currency(d.export_amount, cur_frm.doc.price_list_currency)
rate: format_currency(rate, me.frm.doc.currency),
amount: format_currency(item_amount, me.frm.doc.currency)
}
)).appendTo($items);
});
// taxes
var taxes = wn.model.get_children("Sales Taxes and Charges", this.frm.doc.name, "other_charges",
"Sales Invoice");
$(".tax-table")
var taxes = wn.model.get_children(this.sales_or_purchase + " Taxes and Charges",
this.frm.doc.name, this.frm.cscript.other_fname, this.frm.doctype);
$(this.wrapper).find(".tax-table")
.toggle((taxes && taxes.length) ? true : false)
.find("tbody").empty();
@ -297,30 +324,39 @@ erpnext.POS = Class.extend({
<tr>', {
description: d.description,
rate: d.rate,
tax_amount: format_currency(d.tax_amount, me.frm.doc.price_list_currency)
tax_amount: format_currency(flt(d.tax_amount)/flt(me.frm.doc.conversion_rate),
me.frm.doc.currency)
})).appendTo(".tax-table tbody");
});
// set totals
this.wrapper.find(".net-total").text(format_currency(this.frm.doc.net_total_export,
cur_frm.doc.price_list_currency));
this.wrapper.find(".grand-total").text(format_currency(this.frm.doc.grand_total_export,
cur_frm.doc.price_list_currency));
if (this.sales_or_purchase == "Sales") {
this.wrapper.find(".net-total").text(format_currency(this.frm.doc.net_total_export,
me.frm.doc.currency));
this.wrapper.find(".grand-total").text(format_currency(this.frm.doc.grand_total_export,
me.frm.doc.currency));
}
else {
this.wrapper.find(".net-total").text(format_currency(this.frm.doc.net_total_import,
me.frm.doc.currency));
this.wrapper.find(".grand-total").text(format_currency(this.frm.doc.grand_total_import,
me.frm.doc.currency));
}
// if form is local then only run all these functions
if (cur_frm.doc.docstatus===0) {
$("input.qty").on("focus", function() {
if (this.frm.doc.docstatus===0) {
$(this.wrapper).find("input.qty").on("focus", function() {
$(this).select();
});
// append quantity to the respective item after change from input box
$("input.qty").on("change", function() {
$(this.wrapper).find("input.qty").on("change", function() {
var item_code = $(this).closest("tr")[0].id;
me.update_qty(item_code, $(this).val(), true);
});
// on td click toggle the highlighting of row
$("#cart tbody tr td").on("click", function() {
$(this.wrapper).find("#cart tbody tr td").on("click", function() {
var row = $(this).closest("tr");
if (row.attr("data-selected") == "false") {
row.attr("class", "warning");
@ -335,20 +371,37 @@ erpnext.POS = Class.extend({
});
me.refresh_delete_btn();
cur_frm.pos.barcode.$input.focus();
this.barcode.$input.focus();
}
// if form is submitted & cancelled then disable all input box & buttons
if (cur_frm.doc.docstatus>=1 && cint(cur_frm.doc.is_pos)) {
me.wrapper.find('input, button').each(function () {
if (this.frm.doc.docstatus>=1) {
$(this.wrapper).find('input, button').each(function () {
$(this).prop('disabled', true);
});
$(".delete-items").hide();
$(".make-payment").hide();
$(this.wrapper).find(".delete-items").hide();
$(this.wrapper).find(".make-payment").hide();
}
else {
$(this.wrapper).find('input, button').each(function () {
$(this).prop('disabled', false);
});
$(this.wrapper).find(".make-payment").show();
}
// Show Make Payment button only in Sales Invoice
if (this.frm.doctype != "Sales Invoice")
$(this.wrapper).find(".make-payment").hide();
// If quotation to is not Customer then remove party
if (this.frm.doctype == "Quotation") {
this.party_field.$wrapper.remove();
if (this.frm.doc.quotation_to == "Customer")
this.make_party();
}
},
refresh_delete_btn: function() {
$(".delete-items").toggle($(".item-cart .warning").length ? true : false);
$(this.wrapper).find(".delete-items").toggle($(".item-cart .warning").length ? true : false);
},
add_item_thru_barcode: function() {
var me = this;
@ -370,32 +423,32 @@ erpnext.POS = Class.extend({
remove_selected_item: function() {
var me = this;
var selected_items = [];
var no_of_items = $("#cart tbody tr").length;
var no_of_items = $(this.wrapper).find("#cart tbody tr").length;
for(var x=0; x<=no_of_items - 1; x++) {
var row = $("#cart tbody tr:eq(" + x + ")");
var row = $(this.wrapper).find("#cart tbody tr:eq(" + x + ")");
if(row.attr("data-selected") == "true") {
selected_items.push(row.attr("id"));
}
}
var child = wn.model.get_children("Sales Invoice Item", this.frm.doc.name, "entries",
"Sales Invoice");
var child = wn.model.get_children(this.frm.doctype + " Item", this.frm.doc.name,
this.frm.cscript.fname, this.frm.doctype);
$.each(child, function(i, d) {
for (var i in selected_items) {
if (d.item_code == selected_items[i]) {
// cur_frm.fields_dict["entries"].grid.grid_rows[d.idx].remove();
wn.model.clear_doc(d.doctype, d.name);
}
}
});
cur_frm.fields_dict["entries"].grid.refresh();
cur_frm.script_manager.trigger("calculate_taxes_and_totals");
this.frm.fields_dict[this.frm.cscript.fname].grid.refresh();
this.frm.script_manager.trigger("calculate_taxes_and_totals");
me.frm.dirty();
me.refresh();
},
make_payment: function() {
var me = this;
var no_of_items = $("#cart tbody tr").length;
var no_of_items = $(this.wrapper).find("#cart tbody tr").length;
var mode_of_payment = [];
if (no_of_items == 0)
@ -423,15 +476,15 @@ erpnext.POS = Class.extend({
"total_amount": $(".grand-total").text()
});
dialog.show();
cur_frm.pos.barcode.$input.focus();
me.barcode.$input.focus();
dialog.get_input("total_amount").prop("disabled", true);
dialog.fields_dict.pay.input.onclick = function() {
cur_frm.set_value("mode_of_payment", dialog.get_values().mode_of_payment);
cur_frm.set_value("paid_amount", dialog.get_values().total_amount);
cur_frm.cscript.mode_of_payment(cur_frm.doc);
cur_frm.save();
me.frm.set_value("mode_of_payment", dialog.get_values().mode_of_payment);
me.frm.set_value("paid_amount", dialog.get_values().total_amount);
me.frm.cscript.mode_of_payment(me.frm.doc);
me.frm.save();
dialog.hide();
me.refresh();
};

View File

@ -3,17 +3,21 @@
from __future__ import unicode_literals
import webnotes
from webnotes import msgprint
@webnotes.whitelist()
def get_items(price_list, item=None, item_group=None):
def get_items(price_list, sales_or_purchase, item=None, item_group=None):
condition = ""
if sales_or_purchase == "Sales":
condition = "i.is_sales_item='Yes'"
else:
condition = "i.is_purchase_item='Yes'"
if item_group and item_group != "All Item Groups":
condition = "and i.item_group='%s'" % item_group
condition += " and i.item_group='%s'" % item_group
if item:
condition = "and i.name='%s'" % item
condition += " and i.name='%s'" % item
return webnotes.conn.sql("""select i.name, i.item_name, i.image,
pl_items.ref_rate, pl_items.currency
@ -24,13 +28,18 @@ def get_items(price_list, item=None, item_group=None):
ON
pl_items.item_code=i.name
where
i.is_sales_item='Yes'%s""" % ('%s', condition), (price_list), as_dict=1)
%s""" % ('%s', condition), (price_list), as_dict=1)
@webnotes.whitelist()
def get_item_from_barcode(barcode):
return webnotes.conn.sql("""select name from `tabItem` where barcode=%s""",
(barcode), as_dict=1)
@webnotes.whitelist()
def get_item_from_serial_no(serial_no):
return webnotes.conn.sql("""select name, item_code from `tabSerial No` where
name=%s""", (serial_no), as_dict=1)
@webnotes.whitelist()
def get_mode_of_payment():
return webnotes.conn.sql("""select name from `tabMode of Payment`""", as_dict=1)

View File

@ -1,15 +0,0 @@
.pos-item {
height: 200px;
overflow: hidden;
cursor: pointer;
padding-left: 5px !important;
padding-right: 5px !important;
}
.pos-bill {
padding: 20px 5px;
font-family: Monospace;
border: 1px solid #eee;
-webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
}

View File

@ -29,9 +29,10 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
// toggle to pos view if is_pos is 1 in user_defaults
if ((cint(wn.defaults.get_user_defaults("is_pos"))===1 || cur_frm.doc.is_pos) &&
cint(wn.defaults.get_user_defaults("fs_pos_view"))===1) {
this.frm.set_value("is_pos", 1);
this.is_pos();
cur_frm.cscript.toggle_pos(true);
if(this.frm.doc.__islocal && !this.frm.doc.amended_from) {
this.frm.set_value("is_pos", 1);
this.is_pos(function() {cur_frm.cscript.toggle_pos(true);});
}
}
// if document is POS then change default print format to "POS Invoice"
@ -78,14 +79,11 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
cur_frm.add_custom_button('Make Payment Entry', cur_frm.cscript.make_bank_voucher);
}
if (doc.docstatus===0) {
// Show buttons only when pos view is active
if (doc.docstatus===0 && !this.pos_active) {
cur_frm.cscript.sales_order_btn();
cur_frm.cscript.delivery_note_btn();
}
// Show POS button only if it enabled from features setup
if(cint(sys_defaults.fs_pos_view)===1)
cur_frm.cscript.pos_btn();
},
sales_order_btn: function() {
@ -125,61 +123,12 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
});
},
pos_btn: function() {
if(cur_frm.$pos_btn)
cur_frm.$pos_btn.remove();
if(!cur_frm.pos_active) {
var btn_label = wn._("POS View"),
icon = "icon-desktop";
cur_frm.cscript.sales_order_btn();
cur_frm.cscript.delivery_note_btn();
} else {
var btn_label = wn._("Invoice View"),
icon = "icon-file-text";
if (cur_frm.doc.docstatus===0) {
this.$delivery_note_btn.remove();
this.$sales_order_btn.remove();
}
}
cur_frm.$pos_btn = cur_frm.add_custom_button(btn_label, function() {
cur_frm.cscript.toggle_pos();
cur_frm.cscript.pos_btn();
}, icon);
},
toggle_pos: function(show) {
if (!this.frm.doc.selling_price_list)
msgprint(wn._("Please select Price List"))
else {
if((show===true && cur_frm.pos_active) || (show===false && !cur_frm.pos_active)) return;
// make pos
if(!cur_frm.pos) {
cur_frm.layout.add_view("pos");
cur_frm.pos = new erpnext.POS(cur_frm.layout.views.pos, cur_frm);
}
// toggle view
cur_frm.layout.set_view(cur_frm.pos_active ? "" : "pos");
cur_frm.pos_active = !cur_frm.pos_active;
// refresh
if(cur_frm.pos_active)
cur_frm.pos.refresh();
}
},
tc_name: function() {
this.get_terms();
},
is_pos: function() {
is_pos: function(callback_fn) {
cur_frm.cscript.hide_fields(this.frm.doc);
if(cint(this.frm.doc.is_pos)) {
if(!this.frm.doc.company) {
this.frm.set_value("is_pos", 0);
@ -192,11 +141,13 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
callback: function(r) {
if(!r.exc) {
me.frm.script_manager.trigger("update_stock");
if(callback_fn) callback_fn()
}
}
});
}
}
},
debit_to: function() {

View File

@ -195,7 +195,7 @@ class DocType(SellingController):
pos = get_pos_settings(self.doc.company)
if pos:
if not for_validate:
if not for_validate and not self.doc.customer:
self.doc.customer = pos.customer
self.set_customer_defaults()

View File

@ -2,7 +2,7 @@
{
"creation": "2013-05-24 19:29:05",
"docstatus": 0,
"modified": "2013-10-02 14:24:52",
"modified": "2013-10-02 14:24:50",
"modified_by": "Administrator",
"owner": "Administrator"
},
@ -181,6 +181,7 @@
"search_index": 1
},
{
"default": "Today",
"description": "Enter the date by which payments from customer is expected against this invoice.",
"doctype": "DocField",
"fieldname": "due_date",
@ -412,7 +413,7 @@
"doctype": "DocField",
"fieldname": "other_charges",
"fieldtype": "Table",
"label": "Taxes and Charges1",
"label": "Sales Taxes and Charges",
"oldfieldname": "other_charges",
"oldfieldtype": "Table",
"options": "Sales Taxes and Charges",

View File

@ -55,7 +55,7 @@ def get_stock_ledger_entries(filters):
from `tabStock Ledger Entry`"""
if filters.get("company"):
query += """ and company=%(company)s"""
query += """ where company=%(company)s"""
query += " order by item_code desc, warehouse desc, posting_date desc, posting_time desc, name desc"

View File

@ -108,8 +108,7 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({
var item = wn.model.get_doc(cdt, cdn);
if(item.item_code) {
if(!this.validate_company_and_party("supplier")) {
item.item_code = null;
refresh_field("item_code", item.name, item.parentfield);
cur_frm.fields_dict[me.frm.cscript.fname].grid.grid_rows[item.idx - 1].remove();
} else {
return this.frm.call({
method: "buying.utils.get_item_details",

View File

@ -10,6 +10,7 @@ cur_frm.cscript.other_fname = "purchase_tax_details";
wn.require('app/accounts/doctype/purchase_taxes_and_charges_master/purchase_taxes_and_charges_master.js');
wn.require('app/utilities/doctype/sms_control/sms_control.js');
wn.require('app/buying/doctype/purchase_common/purchase_common.js');
wn.require('app/accounts/doctype/sales_invoice/pos.js');
erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend({
refresh: function(doc, cdt, cdn) {

View File

@ -6,6 +6,7 @@ from __future__ import unicode_literals
import unittest
import webnotes
import webnotes.defaults
from webnotes.utils import flt
class TestPurchaseOrder(unittest.TestCase):
def test_make_purchase_receipt(self):
@ -18,6 +19,7 @@ class TestPurchaseOrder(unittest.TestCase):
po = webnotes.bean("Purchase Order", po.doc.name)
po.submit()
pr = make_purchase_receipt(po.doc.name)
pr[0]["supplier_warehouse"] = "_Test Warehouse 1 - _TC"
@ -25,7 +27,52 @@ class TestPurchaseOrder(unittest.TestCase):
self.assertEquals(len(pr), len(test_records[0]))
pr[0].naming_series = "_T-Purchase Receipt-"
webnotes.bean(pr).insert()
pr_bean = webnotes.bean(pr)
pr_bean.insert()
def test_ordered_qty(self):
webnotes.conn.sql("delete from tabBin")
from buying.doctype.purchase_order.purchase_order import make_purchase_receipt
po = webnotes.bean(copy=test_records[0]).insert()
self.assertRaises(webnotes.ValidationError, make_purchase_receipt,
po.doc.name)
po = webnotes.bean("Purchase Order", po.doc.name)
po.doc.is_subcontracted = "No"
po.doclist[1].item_code = "_Test Item"
po.submit()
self.assertEquals(webnotes.conn.get_value("Bin", {"item_code": "_Test Item",
"warehouse": "_Test Warehouse - _TC"}, "ordered_qty"), 10)
pr = make_purchase_receipt(po.doc.name)
self.assertEquals(pr[0]["doctype"], "Purchase Receipt")
self.assertEquals(len(pr), len(test_records[0]))
pr[0].naming_series = "_T-Purchase Receipt-"
pr[1].qty = 4.0
pr_bean = webnotes.bean(pr)
pr_bean.insert()
pr_bean.submit()
self.assertEquals(flt(webnotes.conn.get_value("Bin", {"item_code": "_Test Item",
"warehouse": "_Test Warehouse - _TC"}, "ordered_qty")), 6.0)
webnotes.conn.set_value('Item', '_Test Item', 'tolerance', 50)
pr1 = make_purchase_receipt(po.doc.name)
pr1[0].naming_series = "_T-Purchase Receipt-"
pr1[1].qty = 8
pr1_bean = webnotes.bean(pr1)
pr1_bean.insert()
pr1_bean.submit()
self.assertEquals(flt(webnotes.conn.get_value("Bin", {"item_code": "_Test Item",
"warehouse": "_Test Warehouse - _TC"}, "ordered_qty")), 0.0)
def test_make_purchase_invocie(self):
from buying.doctype.purchase_order.purchase_order import make_purchase_invoice

View File

@ -9,6 +9,7 @@ cur_frm.cscript.other_fname = "purchase_tax_details";
// attach required files
wn.require('app/accounts/doctype/purchase_taxes_and_charges_master/purchase_taxes_and_charges_master.js');
wn.require('app/buying/doctype/purchase_common/purchase_common.js');
wn.require('app/accounts/doctype/sales_invoice/pos.js');
erpnext.buying.SupplierQuotationController = erpnext.buying.BuyingController.extend({
refresh: function() {

View File

@ -65,7 +65,7 @@ def _get_basic_details(args, item_bean):
out = webnotes._dict({
"description": item.description_html or item.description,
"qty": 0.0,
"qty": 1.0,
"uom": item.stock_uom,
"conversion_factor": 1.0,
"warehouse": args.warehouse or item.default_warehouse,

View File

@ -17,5 +17,28 @@ To make a Stock Reconciliation, go to:
and follow the steps mentioned on the page.
![Stock Reconciliation](img/stock-reconciliation1.png)
#### Step 1: Download Template
![Stock Reconciliation](img/stock-reconciliation-1.png)
#### Step 2: Enter Data in csv file.
![Stock Reconciliation](img/stock-reconciliation-csv-1.png)
The csv format is case-sensitive. Thus special care should be taken to avoid spelling errors or wrong names. Even if you do not list some quantities or valuation rates, the file will still process the data.
#### Step 3: Upload the csv file with data
![Stock Reconciliation](img/stock-reconciliation-2.png)
<br>
#### Step 4: Attach the uploaded file.
![Stock Reconciliation](img/stock-reconciliation-3.png)
After reviewing saved Reconciliation Data, submit the Stock Reconciliation. On successful submission, the data will be updated in the system. To check the uploaded data go to Stock and view Stock Level Report.

View File

@ -20,7 +20,15 @@ You can create a new Supplier via:
> Tip: When you select a Supplier in any transaction, one Contact and Address gets pre-selected. This is the “Default Contact or Address”. So make sure you set your defaults correctly!
### Integration with Accounts
In ERPNext, there is a separate Account record for each Supplier, of Each company.
When you create a new Supplier, ERPNext will automatically create an Account Ledger for the Supplier under “Accounts Receivable” in the Company set in the Supplier record.
> Advanced Tip: If you want to change the Account Group under which the Supplier Account is created, you can set it in the Company master.
If you want to create an Account in another Company, just change the Company value and “Save” the Supplier again.
> Buying > Contact > New Contact

View File

@ -3,9 +3,11 @@
"_label": "Supplier Type"
}
---
A supplier may be distinguished from a contractor or subcontractor, who commonly adds specialized input to deliverables. A supplier is also known as a vendor. There are different types of suppliers based on their goods and products.
Based on what the suppliers supply, they are classified into different categories called Supplier Type.
There can be different types of suppliers. You can create your own category of Supplier Type.
ERPNext allows you to create your own categories of suppliers. These categories are known as Supplier Type. For Example, if your suppliers are mainly pharmaceutical companies and FMCG distributors, You can create a new Type for them and name them accordingly.
Based on what the suppliers supply, they are classified into different categories called Supplier Type. There can be different types of suppliers. You can create your own category of Supplier Type.
> Buying > Supplier Type > New Supplier Type

View File

@ -85,6 +85,7 @@ Contents
1. [Purchase Receipt](docs.user.stock.purchase_receipt.html)
1. [Delivery Note](docs.user.stock.delivery_note.html)
1. [Stock Entry / Material Transfer](docs.user.stock.stock_entry.html)
1. [Opening Stock](docs.user.accounts.opening_stock.html)
1. [Material Issue](docs.user.stock.material_issue.html)
1. [Sales Return](docs.user.stock.sales_return.html)
1. [Purchase Return](docs.user.stock.purchase_return.html)
@ -100,7 +101,6 @@ Contents
1. [Payment Entry](docs.user.accounts.payments.html)
1. [Journal Voucher](docs.user.accounts.journal_voucher.html)
1. [Opening Entry](docs.user.accounts.opening_entry.html)
1. [Opening Stock](docs.user.accounts.opening_stock.html)
1. [Period Closing](docs.user.accounts.closing.html)
1. [Accounting Reports](docs.user.accounts.reports.html)
1. [Point of Sale (POS) Invoice](docs.user.accounts.pos.html)
@ -151,3 +151,7 @@ Contents
1. [Fiscal Year](docs.user.knowledge.fiscal_year.html)
1. [Accounting Knowledge](docs.user.knowledge.accounting.html)
1. [Accounting Entries](docs.user.knowledge.accounting_entries.html)
1. [DocType Definitions](docs.user.knowledge.doctype.html)
1. [Attachment and CSV Files](docs.user.knowledge.attachment_csv.html)
1. [Format using Markdown](docs.user.knowledge.markdown.html)

View File

@ -22,34 +22,34 @@ Accounting Entries
The balance of account can be increased / decreased, depending on account type and transaction type.
<table class="table table-bordered">
<table class="table table-bordered text-center">
<thead>
<tr class="active">
<td style="text-align: center;">Account Type</td>
<td style="text-align: center;">Transaction Type</td>
<td style="text-align: center;">Effect on account balance</td>
<td>Account Type</td>
<td>Transaction Type</td>
<td>Effect on account balance</td>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: center;">Debit</td>
<td style="text-align: center;">Debit</td>
<td style="text-align: center;">Increases</td>
<td>Debit</td>
<td>Debit</td>
<td>Increases</td>
</tr>
<tr>
<td style="text-align: center;">Debit</td>
<td style="text-align: center;">Credit</td>
<td style="text-align: center;">Decreases</td>
<td>Debit</td>
<td>Credit</td>
<td>Decreases</td>
</tr>
<tr>
<td style="text-align: center;">Credit</td>
<td style="text-align: center;">Credit</td>
<td style="text-align: center;">Increases</td>
<td>Credit</td>
<td>Credit</td>
<td>Increases</td>
</tr>
<tr>
<td style="text-align: center;">Credit</td>
<td style="text-align: center;">Debit</td>
<td style="text-align: center;">Decreases</td>
<td>Credit</td>
<td>Debit</td>
<td>Decreases</td>
</tr>
</tbody>
</table>
@ -62,48 +62,48 @@ This means that every accounting entry has two parts, one debit and one credit a
As the company will receive a payment from customer, the customer is considered as an asset account. For booking income, company maintains an account called "Sales of Laptop". So, entries will be done in the following manner:
<table class="table table-bordered">
<table class="table table-bordered text-center">
<thead>
<tr class="active">
<td style="text-align: center;">Account</td>
<td style="text-align: center;">Debit</td>
<td style="text-align: center;">Credit</td>
<td>Account</td>
<td>Debit</td>
<td>Credit</td>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: center;">Customer A</td>
<td style="text-align: center;">50000</td>
<td style="text-align: center;"></td>
<td>Customer A</td>
<td>50000</td>
<td></td>
</tr>
<tr>
<td style="text-align: center;">Sales of Laptop</td>
<td style="text-align: center;"></td>
<td style="text-align: center;">50000</td>
<td>Sales of Laptop</td>
<td></td>
<td>50000</td>
</tr>
</tbody>
</table>
Customer A has made the payment, so customer balance should decreased based on the paid amount, which will increase "Cash" balance.
<table class="table table-bordered">
<table class="table table-bordered text-center">
<thead>
<tr class="active">
<td style="text-align: center;">Account</td>
<td style="text-align: center;">Debit</td>
<td style="text-align: center;">Credit</td>
<td>Account</td>
<td>Debit</td>
<td>Credit</td>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: center;">Customer A</td>
<td style="text-align: center;"></td>
<td style="text-align: center;">50000</td>
<td>Customer A</td>
<td></td>
<td>50000</td>
</tr>
<tr>
<td style="text-align: center;">Cash</td>
<td style="text-align: center;">50000</td>
<td style="text-align: center;"></td>
<td>Cash</td>
<td>50000</td>
<td></td>
</tr>
</tbody>
</table>

View File

@ -0,0 +1,16 @@
---
{
"_label": "Attachement and CSV files"
}
---
#### How to Attach files?
When you open a form, on the right sidebar, you will see a section to attach files. Click on “Add” and select the file you want to attach. Click on “Upload” and you are set.
#### What is a CSV file?
A CSV (Comma Separated Value) file is a data file that you can upload into ERPNext to update various data. Any spreadsheet file from popular spreadsheet applications like MS Excel or Open Office Spreadsheet can be saved as a CSV file.
If you are using Microsoft Excel and using non-English characters, make sure to save your file encoded as UTF-8. For older versions of Excel, there is no clear way of saving as UTF-8. So save your file as a CSV, then open it in Notepad, and save as “UTF-8”. (Sorry blame Microsoft for this!)

View File

@ -0,0 +1,267 @@
---
{
"_label": "DocType"
}
---
ERPNext is a based on a “metadata” (data about data) framework that helps define all the different types of documents in the system. The basic building block of ERPNext is a DocType.
A DocType represents both a table in the database and a form from which a user can enter data.
Many DocTypes are single tables, but some work in groups. For example, Quotation has a “Quotation” DocType and a “Quotation Item” doctype for the Items table, among others. DocTypes contain a collection of fields called DocFields that form the basis of the columns in the database and the layout of the form.
<table class="table table-bordered text-left">
<thead>
<tr class="active">
<td width="30%">Column</td>
<td>Description</td>
</tr>
</thead>
<tbody>
<tr>
<td>Name</td>
<td>Name of the record</td>
</tr>
<tr>
<td>Owner</td>
<td>Creator and Owner of the record</td>
</tr>
<tr>
<td>Created on</td>
<td>Date and Time of Creation</td>
</tr>
<tr>
<td>Modified On </td>
<td>Date and Time of Modification</td>
</tr>
<tr>
<td>Docstatus</td>
<td>Status of the record<br>
0 = Saved/Draft<br>
1 = Submitted<br>
2 = Cancelled/Deleted
</td>
</tr>
<tr>
<td>Parent</td>
<td>Name of the Parent</td>
</tr>
<tr>
<td>Parent Type</td>
<td>Type of Parent</td>
</tr>
<tr>
<td>Parent Field</td>
<td>Specifying the relationship with the parent (there can be multiple child relationships with the same DocType).</td>
</tr>
<tr>
<td>Index(idx)</td>
<td>Index (sequence) of the record in the child table.</td>
</tr>
</tbody>
</table>
#### Single DocType
There are a certain type of DocTypes that are “Single”, i.e. they have no table associated and have only one record of its fields. DocTypes such as Global Defaults, Production Planning Tool are “Single” DocTypes.
#### Field Columns
In the fields table, there are many columns, here is an explanation of the columns of the field table.
<table class="table table-bordered text-left">
<thead>
<tr class="active">
<td width="30%">Column</td>
<td>Description</td>
</tr>
</thead>
<tbody>
<tr>
<td>Label</td>
<td>Field Label (that appears in the form).</td>
</tr>
<tr>
<td>Type</td>
<td>Field Type</td>
</tr>
<tr>
<td>Name</td>
<td>Column name in the database, must be code friendly with no white spaces, special characters and capital letters.</td>
</tr>
<tr>
<td>options</td>
<td>Field settings:<br>
For Select: List of options (each on a new line).<br>
For Link: DocType that is “linked”.<br>
For HTML: HTML Content
</tr>
<tr>
<td>Perm Level</td>
<td>Permission level (number) of the field. You can group fields by numbers, called levels, and apply rules on the levels.</td>
</tr>
<tr>
<td>Width</td>
<td>Width of the field (in pixels) - useful for “Table” types.</td>
</tr>
<tr>
<td>Reqd</td>
<td>Checked if field is mandatory (required).</td>
</tr>
<tr>
<td>In Filter</td>
<td>Checked if field appears as a standard filter in old style reports.</td>
</tr>
<tr>
<td>Hidden</td>
<td>Checked if field is hidden.</td>
</tr>
<tr>
<td>Print Hide</td>
<td>Checked if field is hidden in Print Formats.</td>
</tr>
<tr>
<td>Report Hide</td>
<td>Checked if field is hidden in old style reports.</td>
</tr>
<tr>
<td>Allow on Submit</td>
<td>Checked if this field can be edited after the document is “Submitted”.</td>
</tr>
<tr>
<td>Depends On</td>
<td>The fieldname of the field that will decide whether this field will be shown or hidden. It is useful to hide un-necessary fields.</td>
</tr>
<tr>
<td>Description</td>
<td>Description of the field</td>
</tr>
<tr>
<td>Default</td>
<td>Default value when a new record is created.<br>
Note: “user” will set the current user as default and “today” will set todays date (if the field is a Date field).</td>
</tr>
<tbody>
<table>
#### Field Types and Options
Here is a list of the different types of fields used to make / customize forms in ERPNext.
<table class="table table-bordered text-left">
<thead>
<tr class="active">
<td width="30%">Type</td>
<td>Description</td>
<td>Options/Setting</td>
</tr>
</thead>
<tbody>
<tr>
<td>Data</td>
<td>Single line text field with 180 characters</td>
<td> </td>
</tr>
<tr>
<td>Select</td>
<td>Select from a pre-determined items in a drop-down.</td>
<td>The “Options” contains the drop-down items, each on a new row</td>
</tr>
<tr>
<td>Link</td>
<td>Link an existing document / record</td>
<td>Options contains the name of the type of document (DocType)</td>
</tr>
<tr>
<td>Currency</td>
<td>Number with 2 decimal places, that will be shown separated by commas for thousands etc. in Print.</td>
<td>e.g. 1,000,000.00</td>
</tr>
<tr>
<td>Float</td>
<td>Number with 6 decimal places.</td>
<td>e.g. 3.141593</td>
</tr>
<tr>
<td>Int</td>
<td>Integer (no decimals)</td>
<td>e.g. 100</td>
</tr>
<tr>
<td>Date</td>
<td>Date</td>
<td>Format can be selected in Global Defaults</td>
</tr>
<tr>
<td>Time</td>
<td>Time</td>
<td></td>
</tr>
<tr>
<td colspan="3" class="active">Text</td>
</tr>
<tr>
<td>Text</td>
<td>Multi-line text box without formatting features</td>
<td></td>
</tr>
<tr>
<td>Text editor</td>
<td>Multi-line text box with formatting toolbar etc</td>
<td></td>
</tr>
<tr>
<td>Code</td>
<td>Code Editor</td>
<td>Options can include the type of language for syntax formatting.
Eg JS / Python / HTML</td>
</tr>
<tr>
<td colspan="3" class="active">Table (Grid)</td>
</tr>
<tr>
<td>Table</td>
<td>Table of child items linked to the record.</td>
<td>Options contains the name of the DocType of the child table. For example “Sales Invoice Item” for “Sales Invoice”</td>
</tr>
<tr>
<td colspan="3" class="active">Layout</td>
</tr>
<tr>
<td>Section Break</td>
<td>Break into a new horizontal section.</td>
<td>The layout in ERPNext is evaluated from top to bottom.</td>
</tr>
<tr>
<td>Column Break</td>
<td>Break into a new vertical column.</td>
<td></td>
</tr>
<tr>
<td>HTML</td>
<td>Add a static text / help / link etc in HTML</td>
<td>Options contains the HTML.</td>
</tr>
<tr>
<td colspan="3" class="active">Action</td>
</tr>
<tr>
<td>Button</td>
<td>Button</td>
<td>[for developers only]</td>
</tr>
<tbody>
<table>

View File

@ -0,0 +1,84 @@
---
{
"_label": "Format Using Markdown"
}
---
Markdown is a simple way of writing text to format your content. Markdown allows you easy ways to format.
1. Headings (h1 (largest), h2, h3, h4 and so on)
1. Paragraphs
1. Lists (numbered or bulleted)
1. Hyper links (links to other pages)
1. Images
1. Code
1. Embed HTML (HTML tags within your text)
#### Headings
Headings are specified by adding a `#` (hash) at the beginning of the line. The more the number of hashes, the smaller the heading:
# This is a large heading.
### This is a smaller heading.
#### Paragraphs
To start a new paragraph, just make sure that there is an empty line at the beginning and end of the paragraph.
To format text as **bold** or with _italics_ format as follows:
**This text** is **bold** and _this one_ is with _italics_
#### Lists
To define numbered lists, start your link with a number and a dot (.) and ensure there is a blank line before and after the list. The numbers are automatically generated so it does not matter what number you put:
1. list 1st item
1. second item
1. and so on
1. and so forth
To define bulleted lists, start your items with a hyphen (-)
- item 1
- item 2
- item 3
To nest lists within one another, put four spaces to indent your inner list as follows:
1. item 1
1. item 2
- sub item 1
- sub item 2
1. item 3
#### Links (to other pages)
Links to other pages can be defined by adding your text in box brackets [] followed by the link in round brackets ()
[This is an external link](http://example.com)
[A link within the site](my-page.html)
#### Images
Images can be added by adding an exclamation ! before the link.
![A flower](files/flower.gif)
#### Code
To add a code block, just leave a blank line before and after the block and make sure all code line are indented by four spaces:
This is normal text
This is a code block
#### HTML
You can embed any kind of HTML tags within your code. Any content written within HTML tags will not be formatted.
[Detailed description of the markdown format](http://daringfireball.net/projects/markdown/syntax)

View File

@ -4,8 +4,12 @@
"_toc": [
"docs.user.knowledge.fiscal_year",
"docs.user.knowledge.accounting",
"docs.user.knowledge.accounting_entries"
"docs.user.knowledge.accounting_entries",
"docs.user.knowledge.doctype",
"docs.user.knowledge.attachment_csv",
"docs.user.knowledge.markdown"
]
}
---
Knowledge Library contains definitions and explanations of various management concepts. This page is created for users who wish to elaborate their conceptual knowledge.

View File

@ -4,7 +4,9 @@
"_title_image": "img/customers.png"
}
---
You can either directly create your Customers via
A customer, who is sometimes known as a client, buyer, or purchaser is the one who receives goods, services, products, or ideas, from a seller for a monetary consideration. A customer can also receive goods or services from a vendor or a supplier for other valuable considerations.
You can either directly create your Customers via
> Selling > Customer

View File

@ -3,7 +3,7 @@
"_label": "Data Import Tool"
}
---
The Data Import Tool is a great way to upload (or edit) bulk data, specially master data, into the system. To start the tool go to:
The Data Import Tool is a great way to upload (or edit) bulk data, specially master data, into the system.
To Open the data import tool, you either go to Setup or go to the Transaction you want to Import. If Data Import is allowed, you will see an Import Button:
@ -15,7 +15,7 @@ The tool has two sections, one to download a template and the second to upload t
### 1. Downloading The Template
Data in ERPNext is stored in tables, much like a spreadsheet with columns and rows of data. Each entity in ERPNext can have multiple child tables associated with it too. The child tables are linked to the parent tables and are implemented where are multiple values for any property. For example an Item can have multiple prices, An Invoice has multiple Items and so on.
Data in ERPNext is stored in tables, much like a spreadsheet with columns and rows of data. Each entity in ERPNext can have multiple child tables associated with it too. The child tables are linked to the parent tables and are implemented where there are multiple values for any property. For example an Item can have multiple prices, An Invoice has multiple Items and so on.
You can import each table separately, or all at a time. In the child table, you must mention the parent of the row in the “parent” column so that ERPNext knows which Items price or tax you are trying to set if you are importing separately.
@ -36,7 +36,7 @@ Then export your template or save it as a **Comma Separated Values** (CSV) file.
### 3. Upload the .csv File
Finally attach the .csv file in the section section click on the "Upload and Import" button.
Finally attach the .csv file in the section. Click on the "Upload and Import" button.
![Attach and Upload](img/import-5.png)

View File

@ -27,11 +27,7 @@ To upload an image for your icon that will appear in all transactions, save the
![Item Properties](img/item-add-image.png)
### Item Pricing
Item Price and Price Lists: ERPNext lets you maintain multiple selling prices for an Item using Price Lists. A Price List is a place where different rate plans can be stored. Its a name you can give to a set of Item prices. In case you have different zones (based on the shipping costs), for different currencies etc, you can maintain different Price Lists. A Price List is formed when you create different Item Prices. To import Item Price see [Importing Data](docs.user.data_import.md).
## Inventory : Warehouse and Stock Setting
### Inventory : Warehouse and Stock Setting
In ERPNext, you can select different type of Warehouses to stock your different Items. This can be selected based on Item types. It could be Fixed Asset Item, Stock Item or even Manufacturing Item.

View File

@ -9,6 +9,7 @@
"docs.user.stock.purchase_receipt",
"docs.user.stock.delivery_note",
"docs.user.stock.stock_entry",
"docs.user.stock.opening_stock",
"docs.user.stock.material_issue",
"docs.user.stock.sales_return",
"docs.user.stock.purchase_return",

View File

@ -14,6 +14,7 @@ erpnext.hr.EmployeeController = wn.ui.form.Controller.extend({
onload: function() {
this.frm.toggle_display(["esic_card_no", "gratuity_lic_id", "pan_number", "pf_number"],
wn.control_panel.country==="India");
if(this.frm.doc.__islocal) this.frm.set_value("employee_name", "");
},
refresh: function() {

View File

@ -58,11 +58,12 @@ cur_frm.cscript.onload = function(doc,cdt,cdn) {
query:"controllers.queries.employee_query"
}
}
var exp_approver = doc.exp_approver;
return cur_frm.call({
method:"hr.utils.get_expense_approver_list",
callback: function(r) {
cur_frm.set_df_property("exp_approver", "options", r.message);
if(exp_approver) cur_frm.set_value("exp_approver", exp_approver);
}
});
}
@ -79,26 +80,39 @@ cur_frm.cscript.clear_sanctioned = function(doc) {
}
cur_frm.cscript.refresh = function(doc,cdt,cdn){
cur_frm.cscript.set_help(doc);
if(!doc.__islocal) {
cur_frm.toggle_enable("exp_approver", (doc.owner==user && doc.approval_status=="Draft"));
cur_frm.toggle_enable("approval_status", (doc.exp_approver==user && doc.docstatus==0));
if(!doc.__islocal && user!=doc.exp_approver && cur_frm.frm_head.appframe.buttons.Submit)
cur_frm.frm_head.appframe.buttons.Submit.toggle(false);
if(doc.docstatus==0 && doc.exp_approver==user && doc.approval_status=="Approved")
cur_frm.savesubmit();
if(doc.docstatus==1 && wn.model.can_create("Journal Voucher"))
cur_frm.add_custom_button("Make Bank Voucher", cur_frm.cscript.make_bank_voucher);
}
}
cur_frm.cscript.set_help = function(doc) {
cur_frm.set_intro("");
if(doc.__islocal && !in_list(user_roles, "HR User")) {
cur_frm.set_intro("Fill the form and save it")
} else {
if(doc.docstatus==0 && doc.approval_status=="Draft") {
if(user==doc.exp_approver) {
cur_frm.set_intro("You are the Expense Approver for this record. Please Update the 'Status' and Save");
cur_frm.toggle_enable("approval_status", true);
cur_frm.set_intro("You are the Expense Approver for this record. \
Please Update the 'Status' and Save");
} else {
cur_frm.set_intro("Expense Claim is pending approval. Only the Expense Approver can update status.");
cur_frm.toggle_enable("approval_status", false);
if(!doc.__islocal && cur_frm.frm_head.appframe.buttons.Submit)
cur_frm.frm_head.appframe.buttons.Submit.toggle(false);
cur_frm.set_intro("Expense Claim is pending approval. \
Only the Expense Approver can update status.");
}
} else {
if(doc.approval_status=="Approved") {
cur_frm.set_intro("Expense Claim has been approved.");
if(doc.docstatus==0) cur_frm.savesubmit();
if(doc.docstatus==1) cur_frm.add_custom_button("Make Bank Voucher",
cur_frm.cscript.make_bank_voucher);
} else if(doc.approval_status=="Rejected") {
cur_frm.set_intro("Expense Claim has been rejected.");
}

View File

@ -10,6 +10,8 @@ cur_frm.cscript.onload = function(doc, dt, dn) {
cur_frm.set_value("status", "Open");
cur_frm.cscript.calculate_total_days(doc, dt, dn);
}
var leave_approver = doc.leave_approver;
return cur_frm.call({
method:"hr.utils.get_leave_approver_list",
callback: function(r) {
@ -17,6 +19,7 @@ cur_frm.cscript.onload = function(doc, dt, dn) {
function(profile) {
return {value: profile, label: wn.user_info(profile).fullname};
}));
if(leave_approver) cur_frm.set_value("leave_approver", leave_approver);
cur_frm.cscript.get_leave_balance(cur_frm.doc);
}
});

View File

@ -6,6 +6,7 @@ import webnotes
def execute():
webnotes.reload_doc("selling", "doctype", "shopping_cart_price_list")
webnotes.reload_doc("setup", "doctype", "item_price")
for t in [
("Supplier Quotation", "price_list_name", "buying_price_list"),

View File

View File

@ -0,0 +1,13 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
import webnotes
def execute():
webnotes.conn.sql("""update `tabStock Ledger Entry` set is_cancelled = 'No'
where ifnull(is_cancelled, '') = ''""")
webnotes.conn.sql("""update tabBin b set b.stock_uom =
(select i.stock_uom from tabItem i where i.name = b.item_code)
where b.creation>='2013-09-01'""")

View File

@ -218,4 +218,6 @@ patch_list = [
"execute:webnotes.bean('Style Settings').save() #2013-09-19",
"execute:webnotes.conn.set_value('Accounts Settings', None, 'frozen_accounts_modifier', 'Accounts Manager') # 2013-09-24",
"patches.september_2013.p04_unsubmit_serial_nos",
"patches.september_2013.p05_fix_customer_in_pos",
"patches.october_2013.fix_is_cancelled_in_sle",
]

View File

@ -0,0 +1,22 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
import webnotes
def execute():
si_list = webnotes.conn.sql("""select name, debit_to from `tabSales Invoice`
where ifnull(is_pos, 1)=1 and docstatus=1 and modified > '2013-09-03'""", as_dict=1)
for si in si_list:
if not webnotes.conn.get_value("GL Entry", {"voucher_type": "Sales Invoice",
"voucher_no": si.name, "account": si.debit_to}):
debit_to = webnotes.conn.sql("""select account from `tabGL Entry` gle
where voucher_type='Sales Invoice' and voucher_no=%s
and (select master_type from tabAccount where name=gle.account)='Customer'
""", si.name)
if debit_to:
si_bean = webnotes.bean("Sales Invoice", si.name)
si_bean.doc.debit_to = debit_to[0][0]
si_bean.doc.customer = None
si_bean.run_method("set_customer_defaults")
si_bean.update_after_submit()

View File

@ -9,7 +9,6 @@ $(document).ready(function() {
type: "POST",
method: "selling.utils.cart.get_cart_quotation",
callback: function(r) {
console.log(r);
$("#cart-container").removeClass("hide");
$(".progress").remove();
if(r.exc) {
@ -126,8 +125,8 @@ $.extend(erpnext.cart, {
},
render_item_row: function($cart_items, doc) {
doc.image_html = doc.image ?
'<div style="height: 120px; overflow: hidden;"><img src="' + doc.image + '" /></div>' :
doc.image_html = doc.website_image ?
'<div style="height: 120px; overflow: hidden;"><img src="' + doc.website_image + '" /></div>' :
'{% include "app/stock/doctype/item/templates/includes/product_missing_image.html" %}';
if(doc.description === doc.item_name) doc.description = "";

View File

@ -10,3 +10,5 @@ erpnext.projects.TimeLog = wn.ui.form.Controller.extend({
});
cur_frm.cscript = new erpnext.projects.TimeLog({frm: cur_frm});
cur_frm.add_fetch('task','project','project');

View File

@ -30,3 +30,20 @@ span, div, td, input, textarea, button, select {
height: 32px;
margin: -10px auto;
}
/* pos */
.pos-item {
height: 200px;
overflow: hidden;
cursor: pointer;
padding-left: 5px !important;
padding-right: 5px !important;
}
.pos-bill {
padding: 20px 5px;
font-family: Monospace;
border: 1px solid #eee;
-webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
}

View File

@ -29,6 +29,8 @@ erpnext.StockGridReport = wn.views.TreeGridReport.extend({
if(add_qty)
wh.fifo_stack.push([add_qty, sl.incoming_rate, sl.posting_date]);
if(sl.serial_no) value_diff = this.get_serialized_value_diff(sl);
} else {
// outgoing
if(sl.serial_no) {
@ -98,7 +100,7 @@ erpnext.StockGridReport = wn.views.TreeGridReport.extend({
$.each(sl.serial_no.trim().split("\n"), function(i, sr) {
if(sr) {
value_diff += flt(me.serialized_buying_rates[sr.trim()]);
value_diff += flt(me.serialized_buying_rates[sr.trim().toLowerCase()]);
}
});
@ -112,7 +114,7 @@ erpnext.StockGridReport = wn.views.TreeGridReport.extend({
if(sle.qty > 0 && sle.serial_no) {
$.each(sle.serial_no.trim().split("\n"), function(i, sr) {
if(sr && sle.incoming_rate !== undefined) {
serialized_buying_rates[sr.trim()] = flt(sle.incoming_rate);
serialized_buying_rates[sr.trim().toLowerCase()] = flt(sle.incoming_rate);
}
});
}

View File

@ -62,6 +62,56 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({
erpnext.hide_company();
this.show_item_wise_taxes();
this.set_dynamic_labels();
// Show POS button only if it is enabled from features setup
if(cint(sys_defaults.fs_pos_view)===1 && this.frm.doctype!="Material Request")
this.pos_btn();
},
pos_btn: function() {
if(this.$pos_btn)
this.$pos_btn.remove();
if(!this.pos_active) {
var btn_label = wn._("POS View"),
icon = "icon-desktop";
} else {
var btn_label = wn._(this.frm.doctype) + wn._(" View"),
icon = "icon-file-text";
}
var me = this;
this.$pos_btn = this.frm.add_custom_button(btn_label, function() {
me.toggle_pos();
me.pos_btn();
}, icon);
},
toggle_pos: function(show) {
// Check whether it is Selling or Buying cycle
var price_list = wn.meta.has_field(cur_frm.doc.doctype, "selling_price_list") ?
this.frm.doc.selling_price_list : this.frm.doc.buying_price_list;
if (!price_list)
msgprint(wn._("Please select Price List"))
else {
if((show===true && this.pos_active) || (show===false && !this.pos_active)) return;
// make pos
if(!this.frm.pos) {
this.frm.layout.add_view("pos");
this.frm.pos = new erpnext.POS(this.frm.layout.views.pos, this.frm);
}
// toggle view
this.frm.layout.set_view(this.pos_active ? "" : "pos");
this.pos_active = !this.pos_active;
// refresh
if(this.pos_active)
this.frm.pos.refresh();
this.frm.refresh();
}
},
validate: function() {
@ -183,6 +233,29 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({
this.calculate_taxes_and_totals();
},
// serial_no: function(doc, cdt, cdn) {
// var me = this;
// var item = wn.model.get_doc(cdt, cdn);
// if (!item.item_code) {
// wn.call({
// method: 'accounts.doctype.sales_invoice.pos.get_item_from_serial_no',
// args: {serial_no: this.serial_no.$input.val()},
// callback: function(r) {
// if (r.message) {
// var item_code = r.message[0].item_code;
// var child = wn.model.add_child(me.frm.doc, this.frm.doctype + " Item",
// this.frm.cscript.fname);
// child.item_code = item_code;
// me.frm.cscript.item_code(me.frm.doc, child.doctype, child.name);
// }
// else
// msgprint(wn._("Invalid Serial No."));
// me.refresh();
// }
// });
// }
// },
row_id: function(doc, cdt, cdn) {
var tax = wn.model.get_doc(cdt, cdn);
try {
@ -418,10 +491,10 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({
(this.frm.doc.currency != company_currency && this.frm.doc.conversion_rate != 1.0)) :
false;
// if(!valid_conversion_rate) {
// wn.throw(wn._("Please enter valid") + " " + wn._(conversion_rate_label) +
// " 1 " + this.frm.doc.currency + " = [?] " + company_currency);
// }
if(!valid_conversion_rate) {
wn.throw(wn._("Please enter valid") + " " + wn._(conversion_rate_label) +
" 1 " + this.frm.doc.currency + " = [?] " + company_currency);
}
},
calculate_taxes_and_totals: function() {

View File

@ -45,7 +45,7 @@ cur_frm.cscript.setup_dashboard = function(doc) {
cur_frm.dashboard.reset(doc);
if(doc.__islocal)
return;
cur_frm.dashboard.set_headline('<span class="text-muted">Loading...</span>')
cur_frm.dashboard.set_headline('<span class="text-muted">'+ wn._('Loading...')+ '</span>')
cur_frm.dashboard.add_doctype_badge("Opportunity", "customer");
cur_frm.dashboard.add_doctype_badge("Quotation", "customer");
@ -99,7 +99,7 @@ cur_frm.cscript.make_contact = function() {
return "select name, first_name, last_name, email_id, phone, mobile_no, department, designation, is_primary_contact from tabContact where customer='"+cur_frm.docname+"' and docstatus != 2 order by is_primary_contact desc"
},
as_dict: 1,
no_results_message: 'No contacts created',
no_results_message: wn._('No contacts created'),
render_row: cur_frm.cscript.render_contact_row,
});
// note: render_contact_row is defined in contact_control.js

View File

@ -34,15 +34,6 @@ erpnext.LeadController = wn.ui.form.Controller.extend({
erpnext.hide_naming_series();
this.frm.clear_custom_buttons();
this.frm.dashboard.reset(doc);
if(!doc.__islocal) {
if(doc.status=="Converted") {
this.frm.dashboard.set_headline_alert(wn._("Converted"), "alert-success", "icon-ok-sign");
} else {
this.frm.dashboard.set_headline_alert(wn._(doc.status), "alert-info", "icon-exclamation-sign");
}
}
this.frm.__is_customer = this.frm.__is_customer || this.frm.doc.__is_customer;
if(!this.frm.doc.__islocal && !this.frm.__is_customer) {
this.frm.add_custom_button("Create Customer", this.create_customer);

View File

@ -125,6 +125,10 @@ def make_opportunity(source_name, target_doclist=None):
"campaign_name": "campaign",
"doctype": "enquiry_from",
"name": "lead",
"lead_name": "contact_display",
"company_name": "customer_name",
"email_id": "contact_email",
"mobile_no": "contact_mobile"
}
}}, target_doclist)

View File

@ -2,7 +2,7 @@
{
"creation": "2013-04-10 11:45:37",
"docstatus": 0,
"modified": "2013-10-02 14:24:34",
"modified": "2013-10-02 14:24:30",
"modified_by": "Administrator",
"owner": "Administrator"
},
@ -112,7 +112,7 @@
"no_copy": 1,
"oldfieldname": "status",
"oldfieldtype": "Select",
"options": "\nOpen\nReplied\nAttempted to Contact\nContact in Future\nContacted\nInterested\nNot interested\nLead Lost\nConverted\nPassive",
"options": "\nOpen\nReplied\nAttempted to Contact\nContact in Future\nContacted\nOpportunity Made\nInterested\nNot interested\nLead Lost\nConverted\nPassive",
"reqd": 1,
"search_index": 1
},

View File

@ -53,6 +53,11 @@ erpnext.selling.Opportunity = wn.ui.form.Controller.extend({
this.frm.set_query("contact_by", erpnext.queries.profile);
}
this.frm.set_query("customer_address", function() {
if(me.frm.doc.lead) return {filters: { lead: me.frm.doc.lead } };
else if(me.frm.doc.customer) return {filters: { customer: me.frm.doc.customer } };
});
this.frm.set_query("item_code", "enquiry_details", function() {
return {
query: "controllers.queries.item_query",
@ -63,7 +68,6 @@ erpnext.selling.Opportunity = wn.ui.form.Controller.extend({
$.each([["lead", "lead"],
["customer", "customer"],
["customer_address", "customer_filter"],
["contact_person", "customer_filter"],
["territory", "not_a_group_filter"]], function(i, opts) {
me.frm.set_query(opts[0], erpnext.queries[opts[1]]);
@ -151,8 +155,14 @@ cur_frm.cscript.lead_cust_show = function(doc,cdt,cdn){
}
}
cur_frm.cscript.customer_address = cur_frm.cscript.contact_person = function(doc,dt,dn) {
if(doc.customer) return get_server_fields('get_customer_address', JSON.stringify({customer: doc.customer, address: doc.customer_address, contact: doc.contact_person}),'', doc, dt, dn, 1);
cur_frm.cscript.customer_address = cur_frm.cscript.contact_person = function(doc, dt, dn) {
args = {
address: doc.customer_address,
contact: doc.contact_person
}
if(doc.customer) args.update({customer: doc.customer});
return get_server_fields('get_customer_address', JSON.stringify(args),'', doc, dt, dn, 1);
}
cur_frm.cscript.lead = function(doc, cdt, cdn) {
@ -163,7 +173,7 @@ cur_frm.cscript.lead = function(doc, cdt, cdn) {
source_name: cur_frm.doc.lead
})
unhide_field(['customer_name', 'address_display','contact_mobile',
unhide_field(['customer_name', 'address_display','contact_mobile', 'customer_address',
'contact_email', 'territory']);
}

View File

@ -127,12 +127,12 @@ class DocType(TransactionBase):
from accounts.utils import validate_fiscal_year
validate_fiscal_year(self.doc.transaction_date, self.doc.fiscal_year, "Opportunity Date")
if not self.doc.status:
self.doc.status = "Draft"
self.doc.status = "Draft"
def on_submit(self):
webnotes.conn.set(self.doc, 'status', 'Submitted')
if self.doc.lead and webnotes.conn.get_value("Lead", self.doc.lead, "status")!="Converted":
webnotes.conn.set_value("Lead", self.doc.lead, "status", "Opportunity Made")
def on_cancel(self):
chk = webnotes.conn.sql("select t1.name from `tabQuotation` t1, `tabQuotation Item` t2 where t2.parent = t1.name and t1.docstatus=1 and (t1.status!='Order Lost' and t1.status!='Cancelled') and t2.prevdoc_docname = %s",self.doc.name)
@ -141,6 +141,14 @@ class DocType(TransactionBase):
raise Exception
else:
webnotes.conn.set(self.doc, 'status', 'Cancelled')
if self.doc.lead and webnotes.conn.get_value("Lead", self.doc.lead,
"status")!="Converted":
if webnotes.conn.get_value("Communication", {"parent": self.doc.lead}):
status = "Contacted"
else:
status = "Open"
webnotes.conn.set_value("Lead", self.doc.lead, "status", status)
def declare_enquiry_lost(self,arg):
chk = webnotes.conn.sql("select t1.name from `tabQuotation` t1, `tabQuotation Item` t2 where t2.parent = t1.name and t1.docstatus=1 and (t1.status!='Order Lost' and t1.status!='Cancelled') and t2.prevdoc_docname = %s",self.doc.name)

View File

@ -2,7 +2,7 @@
{
"creation": "2013-03-07 18:50:30",
"docstatus": 0,
"modified": "2013-10-02 14:24:35",
"modified": "2013-10-02 14:24:30",
"modified_by": "Administrator",
"owner": "Administrator"
},
@ -189,34 +189,16 @@
"options": "icon-bullhorn",
"read_only": 0
},
{
"doctype": "DocField",
"fieldname": "contact_person",
"fieldtype": "Link",
"in_filter": 1,
"label": "Contact Person",
"options": "Contact",
"print_hide": 1,
"read_only": 0
},
{
"doctype": "DocField",
"fieldname": "customer_address",
"fieldtype": "Link",
"in_filter": 1,
"label": "Customer Address",
"label": "Customer / Lead Address",
"options": "Address",
"print_hide": 1,
"read_only": 0
},
{
"doctype": "DocField",
"fieldname": "customer_name",
"fieldtype": "Data",
"label": "Customer Name",
"print_hide": 0,
"read_only": 1
},
{
"doctype": "DocField",
"fieldname": "address_display",
@ -227,12 +209,60 @@
"oldfieldtype": "Small Text",
"read_only": 1
},
{
"description": "<a href=\"#Sales Browser/Territory\">To manage Territory, click here</a>",
"doctype": "DocField",
"fieldname": "territory",
"fieldtype": "Link",
"in_filter": 1,
"label": "Territory",
"options": "Territory",
"print_hide": 1,
"read_only": 0,
"reqd": 0,
"search_index": 1
},
{
"depends_on": "eval:doc.enquiry_from==\"Customer\"",
"description": "<a href=\"#Sales Browser/Customer Group\">To manage Territory, click here</a>",
"doctype": "DocField",
"fieldname": "customer_group",
"fieldtype": "Link",
"hidden": 0,
"in_filter": 1,
"label": "Customer Group",
"oldfieldname": "customer_group",
"oldfieldtype": "Link",
"options": "Customer Group",
"print_hide": 1,
"read_only": 0,
"reqd": 0,
"search_index": 1
},
{
"doctype": "DocField",
"fieldname": "column_break3",
"fieldtype": "Column Break",
"read_only": 0
},
{
"doctype": "DocField",
"fieldname": "customer_name",
"fieldtype": "Data",
"label": "Customer Name",
"print_hide": 0,
"read_only": 1
},
{
"doctype": "DocField",
"fieldname": "contact_person",
"fieldtype": "Link",
"in_filter": 1,
"label": "Contact Person",
"options": "Contact",
"print_hide": 1,
"read_only": 0
},
{
"doctype": "DocField",
"fieldname": "contact_display",
@ -254,36 +284,6 @@
"label": "Contact Mobile No",
"read_only": 1
},
{
"depends_on": "eval:doc.enquiry_from==\"Customer\"",
"description": "<a href=\"#Sales Browser/Customer Group\">To manage Territory, click here</a>",
"doctype": "DocField",
"fieldname": "customer_group",
"fieldtype": "Link",
"hidden": 0,
"in_filter": 1,
"label": "Customer Group",
"oldfieldname": "customer_group",
"oldfieldtype": "Link",
"options": "Customer Group",
"print_hide": 1,
"read_only": 0,
"reqd": 0,
"search_index": 1
},
{
"description": "<a href=\"#Sales Browser/Territory\">To manage Territory, click here</a>",
"doctype": "DocField",
"fieldname": "territory",
"fieldtype": "Link",
"in_filter": 1,
"label": "Territory",
"options": "Territory",
"print_hide": 1,
"read_only": 0,
"reqd": 0,
"search_index": 1
},
{
"description": "Filing in Additional Information about the Opportunity will help you analyze your data better.",
"doctype": "DocField",

View File

@ -11,6 +11,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/accounts/doctype/sales_invoice/pos.js');
erpnext.selling.QuotationController = erpnext.selling.SellingController.extend({
onload: function(doc, dt, dn) {
@ -82,12 +83,12 @@ erpnext.selling.QuotationController = erpnext.selling.SellingController.extend({
},
validate_company_and_party: function(party_field) {
if(this.frm.doc.quotation_to == "Lead") {
return true;
} else if(!this.frm.doc.quotation_to) {
if(!this.frm.doc.quotation_to) {
msgprint(wn._("Please select a value for" + " " + wn.meta.get_label(this.frm.doc.doctype,
"quotation_to", this.frm.doc.name)));
return false;
} else if (this.frm.doc.quotation_to == "Lead") {
return true;
} else {
return this._super(party_field);
}

View File

@ -162,8 +162,7 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({
var item = wn.model.get_doc(cdt, cdn);
if(item.item_code || item.barcode) {
if(!this.validate_company_and_party("customer")) {
item.item_code = null;
refresh_field("item_code", item.name, item.parentfield);
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",

View File

@ -12,6 +12,7 @@ cur_frm.cscript.sales_team_fname = "sales_team";
wn.require('app/selling/doctype/sales_common/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');
erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend({
refresh: function(doc, dt, dn) {
@ -26,34 +27,34 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
cur_frm.dashboard.add_progress(cint(doc.per_billed) + wn._("% Billed"),
doc.per_billed);
cur_frm.add_custom_button('Send SMS', cur_frm.cscript.send_sms);
cur_frm.add_custom_button(wn._('Send SMS'), cur_frm.cscript.send_sms);
// delivery note
if(flt(doc.per_delivered, 2) < 100 && doc.order_type=='Sales')
cur_frm.add_custom_button('Make Delivery', this.make_delivery_note);
cur_frm.add_custom_button(wn._('Make Delivery'), this.make_delivery_note);
// maintenance
if(flt(doc.per_delivered, 2) < 100 && (doc.order_type !='Sales')) {
cur_frm.add_custom_button('Make Maint. Visit', this.make_maintenance_visit);
cur_frm.add_custom_button('Make Maint. Schedule',
cur_frm.add_custom_button(wn._('Make Maint. Visit'), this.make_maintenance_visit);
cur_frm.add_custom_button(wn._('Make Maint. Schedule'),
this.make_maintenance_schedule);
}
// indent
if(!doc.order_type || (doc.order_type == 'Sales'))
cur_frm.add_custom_button('Make ' + wn._('Material Request'),
cur_frm.add_custom_button(wn._('Make ') + wn._('Material Request'),
this.make_material_request);
// sales invoice
if(flt(doc.per_billed, 2) < 100)
cur_frm.add_custom_button('Make Invoice', this.make_sales_invoice);
cur_frm.add_custom_button(wn._('Make Invoice'), this.make_sales_invoice);
// stop
if(flt(doc.per_delivered, 2) < 100 || doc.per_billed < 100)
cur_frm.add_custom_button('Stop!', cur_frm.cscript['Stop Sales Order']);
cur_frm.add_custom_button(wn._('Stop!'), cur_frm.cscript['Stop Sales Order']);
} else {
// un-stop
cur_frm.dashboard.set_headline_alert("Stopped", "alert-danger", "icon-stop");
cur_frm.add_custom_button('Unstop', cur_frm.cscript['Unstop Sales Order']);
cur_frm.dashboard.set_headline_alert(wn._("Stopped"), "alert-danger", "icon-stop");
cur_frm.add_custom_button(wn._('Unstop'), cur_frm.cscript['Unstop Sales Order']);
}
}
@ -157,7 +158,7 @@ cur_frm.fields_dict['project_name'].get_query = function(doc, cdt, cdn) {
cur_frm.cscript['Stop Sales Order'] = function() {
var doc = cur_frm.doc;
var check = confirm("Are you sure you want to STOP " + doc.name);
var check = confirm(wn._("Are you sure you want to STOP ") + doc.name);
if (check) {
return $c('runserverobj', {
@ -172,7 +173,7 @@ cur_frm.cscript['Stop Sales Order'] = function() {
cur_frm.cscript['Unstop Sales Order'] = function() {
var doc = cur_frm.doc;
var check = confirm("Are you sure you want to UNSTOP " + doc.name);
var check = confirm(wn._("Are you sure you want to UNSTOP ") + doc.name);
if (check) {
return $c('runserverobj', {

View File

@ -34,6 +34,7 @@ def get_item_details(args):
"plc_conversion_rate": 1.0
}
"""
if isinstance(args, basestring):
args = json.loads(args)
args = webnotes._dict(args)

View File

@ -286,7 +286,7 @@ def apply_cart_settings(party=None, quotation=None):
cart_settings = webnotes.get_obj("Shopping Cart Settings")
billing_territory = get_address_territory(quotation.doc.customer_address) or \
party.territory
party.territory or "All Territories"
set_price_list_and_rate(quotation, cart_settings, billing_territory)

View File

@ -96,6 +96,7 @@ def backup_to_dropbox():
error_log = []
path = os.path.join(get_base_path(), "public", "files")
for filename in os.listdir(path):
filename = cstr(filename)
if filename in ignore_list:
continue

View File

@ -85,6 +85,7 @@ def backup_to_gdrive():
webnotes.conn.close()
path = os.path.join(get_base_path(), "public", "files")
for filename in os.listdir(path):
filename = cstr(filename)
found = False
filepath = os.path.join(path, filename)
ext = filename.split('.')[-1]

View File

@ -9,6 +9,7 @@ from __future__ import unicode_literals
import os, json
from xml.etree import ElementTree as ET
from webnotes.utils.datautils import read_csv_content
from webnotes.utils import cstr
path = "/Users/rmehta/Downloads/openerp/openerp/addons"
chart_roots = []
@ -108,6 +109,7 @@ def find_charts():
basename = os.path.basename(basepath)
if basename.startswith("l10n"):
for fname in files:
fname = cstr(fname)
filepath = os.path.join(basepath, fname)
if fname.endswith(".xml"):
tree = ET.parse(filepath)

View File

@ -0,0 +1,7 @@
.table-grid tbody tr {
cursor: pointer;
}
.table-grid thead tr {
height: 50px;
}

View File

@ -6,3 +6,252 @@ $.extend(cur_frm.cscript, {
erpnext.add_for_territory();
},
});
cur_frm.cscript.refresh = function(doc, cdt, cdn) {
cur_frm.cscript.show_item_prices();
}
cur_frm.cscript.show_item_prices = function() {
var item_price = wn.model.get("Item Price", {parent: cur_frm.doc.name});
$(cur_frm.fields_dict.item_prices_html.wrapper).empty();
new wn.ui.form.TableGrid({
parent: cur_frm.fields_dict.item_prices_html.wrapper,
frm: cur_frm,
table_field: wn.meta.get_docfield("Price List", "item_prices", cur_frm.doc.name)
});
}
wn.ui.form.TableGrid = Class.extend({
init: function(opts) {
$.extend(this, opts);
this.fields = wn.meta.get_docfields("Item Price", cur_frm.doc.name);
this.make_table();
},
make_table: function() {
var me = this;
// Creating table & assigning attributes
var grid_table = document.createElement("table");
grid_table.className = "table table-hover table-bordered table-grid";
// Appending header & rows to table
grid_table.appendChild(this.make_table_headers());
grid_table.appendChild(this.make_table_rows());
// Creating button to add new row
var btn_div = document.createElement("div");
var new_row_btn = document.createElement("button");
new_row_btn.className = "btn btn-success table-new-row";
new_row_btn.title = "Add new row";
var btn_icon = document.createElement("i");
btn_icon.className = "icon-plus";
new_row_btn.appendChild(btn_icon);
new_row_btn.innerHTML += " Add new row";
btn_div.appendChild(new_row_btn);
// Appending table & button to parent
var $grid_table = $(grid_table).appendTo($(this.parent));
var $btn_div = $(btn_div).appendTo($(this.parent));
$btn_div.on("click", ".table-new-row", function() {
me.make_dialog();
return false;
});
$grid_table.on("click", ".table-row", function() {
me.make_dialog(this);
return false;
});
},
make_table_headers: function() {
var me = this;
var header = document.createElement("thead");
// Creating header row
var row = document.createElement("tr");
row.className = "active";
// Creating head first cell
var th = document.createElement("th");
th.width = "8%";
th.className = "text-center";
th.innerHTML = "#";
row.appendChild(th);
// Make other headers with label as heading
for(var i=0, l=this.fields.length; i<l; i++) {
var df = this.fields[i];
if(!!!df.hidden && df.in_list_view === 1) {
var th = document.createElement("th");
// If currency then move header to right
if(["Int", "Currency", "Float"].indexOf(df.fieldtype) !== -1) th.className = "text-right";
th.innerHTML = wn._(df.label);
row.appendChild(th);
}
}
header.appendChild(row);
return header;
},
make_table_rows: function() {
var me = this;
// Creating table body
var table_body = document.createElement("tbody");
var item_prices = wn.model.get_children(this.table_field.options, this.frm.doc.name,
this.table_field.fieldname, this.frm.doctype);
for(var i=0, l=item_prices.length; i<l; i++) {
var d = item_prices[i];
// Creating table row
var tr = this.add_new_row(d);
// append row to table body
table_body.appendChild(tr);
}
this.table_body = table_body;
return table_body;
},
make_dialog: function(row) {
var me = this;
this.dialog = new wn.ui.Dialog({
title: this.table_field.options,
fields: this.fields
});
if (row)
this.dialog.set_values(this.make_dialog_values(row));
$a(this.dialog.body, 'div', '', '', this.make_dialog_buttons(row));
this.dialog.show();
this.dialog.$wrapper.find('button.update').on('click', function() {
me.update_row(row);
});
this.dialog.$wrapper.find('button.delete').on('click', function() {
me.delete_row(row);
});
return row;
},
make_dialog_values: function(row) {
var me = this;
var dialog_values = {};
$.each(this.fields, function(i, item) {
dialog_values[item.fieldname] = $(row).find('td[data-fieldname="'+ item.fieldname +'"]').attr('data-fieldvalue');
});
return dialog_values;
},
make_dialog_buttons: function(row) {
var me = this;
var buttons = '<button class="btn btn-primary update">Update</button>';
// if user can delete then only add the delete button in dialog
if (wn.model.can_delete(me.frm.doc.doctype) && row)
buttons += ' <button class="btn btn-default delete">Delete</button>';
return buttons;
},
update_row: function(row) {
var me = this;
if (!row) {
var d = wn.model.add_child(this.frm.doc, this.table_field.options,
this.table_field.fieldname);
refresh_field(this.table_field.fieldname);
this.update_item_price(d.name);
var tr = this.add_new_row(d);
this.table_body.appendChild(tr);
}
else {
this.update_item_price(null, row);
}
this.dialog.hide();
},
update_item_price: function(docname, row) {
var me = this;
if(!docname && row) docname = $(row).attr("data-docname");
$.each(me.fields, function(i, df) {
var val = me.dialog.get_values()[df.fieldname];
if(["Currency", "Float"].indexOf(df.fieldtype)!==-1) {
val = flt(val);
} else if(["Int", "Check"].indexOf(df.fieldtype)!==-1) {
val = cint(val);
}
wn.model.set_value(me.table_field.options, docname,
df.fieldname, val);
if(row) {
var $td = $(row).find('td[data-fieldname="'+ df.fieldname +'"]');
$td.attr('data-fieldvalue', val);
// If field type is currency the update with format currency
$td.html(wn.format(val, df));
}
});
},
delete_row: function(row) {
var me = this;
var docname = $(row).find('td:last').attr('data-docname');
wn.model.clear_doc(me.table_field.options, docname);
$(row).remove();
// Re-assign idx
$.each($(this.parent).find("tbody tr"), function(idx, data) {
var $td = $(data).find('td:first');
$td.html(idx + 1);
});
this.dialog.hide();
},
add_new_row: function(d) {
var tr = document.createElement("tr");
tr.className = "table-row";
tr.setAttribute("data-docname", d.name);
// Creating table data & appending to row
var td = document.createElement("td");
td.className = "text-center";
td.innerHTML = d.idx;
tr.appendChild(td);
for(var f=0, lf=this.fields.length; f<lf; f++) {
var df = this.fields[f];
if(!!!df.hidden && df.in_list_view===1) {
var td = document.createElement("td");
td.setAttribute("data-fieldname", df.fieldname);
td.setAttribute("data-fieldvalue", d[df.fieldname]);
td.setAttribute("data-docname", d.name);
// If currency then move header to right
if(["Int", "Currency", "Float"].indexOf(df.fieldtype) !== -1) {
td.className = "text-right";
}
// format and set display
td.innerHTML = wn.format(d[df.fieldname], df);
// append column to tabel row
tr.appendChild(td);
}
}
return tr;
}
});

View File

@ -2,7 +2,7 @@
{
"creation": "2013-01-25 11:35:09",
"docstatus": 0,
"modified": "2013-09-06 15:03:38",
"modified": "2013-10-02 11:36:09",
"modified_by": "Administrator",
"owner": "Administrator"
},
@ -85,16 +85,23 @@
"reqd": 1
},
{
"description": "To change row values, click on the respective row",
"doctype": "DocField",
"fieldname": "item_prices_section",
"fieldtype": "Section Break",
"hidden": 0,
"label": "Item Prices"
},
{
"doctype": "DocField",
"fieldname": "item_prices_html",
"fieldtype": "HTML"
},
{
"doctype": "DocField",
"fieldname": "item_prices",
"fieldtype": "Table",
"hidden": 1,
"label": "Item Prices",
"options": "Item Price"
},

View File

@ -15,7 +15,7 @@ class DocType:
self.doclist = doclist
def validate(self):
if not self.doc.stock_uom:
if self.doc.fields.get("__islocal") or not self.doc.stock_uom:
self.doc.stock_uom = webnotes.conn.get_value('Item', self.doc.item_code, 'stock_uom')
self.validate_mandatory()

View File

@ -10,6 +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/accounts/doctype/sales_invoice/pos.js');
wn.provide("erpnext.stock");
erpnext.stock.DeliveryNoteController = erpnext.selling.SellingController.extend({

View File

@ -348,8 +348,15 @@ def make_supplier_quotation(source_name, target_doclist=None):
def make_stock_entry(source_name, target_doclist=None):
from webnotes.model.mapper import get_mapped_doclist
def set_purpose(source, target):
def update_item(obj, target, source_parent):
target.conversion_factor = 1
target.qty = flt(obj.qty) - flt(obj.ordered_qty)
target.transfer_qty = flt(obj.qty) - flt(obj.ordered_qty)
def set_missing_values(source, target):
target[0].purpose = "Material Transfer"
se = webnotes.bean(target)
se.run_method("get_stock_and_rate")
doclist = get_mapped_doclist("Material Request", source_name, {
"Material Request": {
@ -369,6 +376,6 @@ def make_stock_entry(source_name, target_doclist=None):
},
"postprocess": update_item
}
}, target_doclist, set_purpose)
}, target_doclist, set_missing_values)
return [d.fields for d in doclist]

View File

@ -8,6 +8,7 @@ cur_frm.cscript.other_fname = "purchase_tax_details";
wn.require('app/accounts/doctype/purchase_taxes_and_charges_master/purchase_taxes_and_charges_master.js');
wn.require('app/utilities/doctype/sms_control/sms_control.js');
wn.require('app/buying/doctype/purchase_common/purchase_common.js');
wn.require('app/accounts/doctype/sales_invoice/pos.js');
wn.provide("erpnext.stock");
erpnext.stock.PurchaseReceiptController = erpnext.buying.BuyingController.extend({

View File

@ -117,8 +117,7 @@ class DocType(BuyingController):
},
"Purchase Order Item": {
"ref_dn_field": "prevdoc_detail_docname",
"compare_fields": [["project_name", "="], ["warehouse", "="],
["uom", "="], ["item_code", "="]],
"compare_fields": [["project_name", "="], ["uom", "="], ["item_code", "="]],
"is_child_table": True
}
})
@ -166,33 +165,42 @@ class DocType(BuyingController):
self.bk_flush_supp_wh(sl_entries)
self.make_sl_entries(sl_entries)
def update_ordered_qty(self, is_cancelled="No"):
pc_obj = get_obj('Purchase Common')
def update_ordered_qty(self):
stock_items = self.get_stock_items()
for d in getlist(self.doclist, 'purchase_receipt_details'):
for d in self.doclist.get({"parentfield": "purchase_receipt_details"}):
if d.item_code in stock_items and d.warehouse \
and cstr(d.prevdoc_doctype) == 'Purchase Order':
pr_qty = flt(d.qty) * flt(d.conversion_factor)
# get qty and pending_qty of prevdoc
curr_ref_qty = pc_obj.get_qty(d.doctype, 'prevdoc_detail_docname',
d.prevdoc_detail_docname, 'Purchase Order Item',
'Purchase Order - Purchase Receipt', self.doc.name)
max_qty, qty, curr_qty = flt(curr_ref_qty.split('~~~')[1]), \
flt(curr_ref_qty.split('~~~')[0]), 0
already_received_qty = self.get_already_received_qty(d.prevdoc_docname,
d.prevdoc_detail_docname)
po_qty, ordered_warehouse = self.get_po_qty_and_warehouse(d.prevdoc_detail_docname)
if flt(qty) + flt(pr_qty) > flt(max_qty):
curr_qty = (flt(max_qty) - flt(qty)) * flt(d.conversion_factor)
if not ordered_warehouse:
webnotes.throw(_("Warehouse is missing in Purchase Order"))
if already_received_qty + d.qty > po_qty:
ordered_qty = - (po_qty - already_received_qty) * flt(d.conversion_factor)
else:
curr_qty = flt(pr_qty)
ordered_qty = - flt(d.qty) * flt(d.conversion_factor)
args = {
update_bin({
"item_code": d.item_code,
"warehouse": d.warehouse,
"warehouse": ordered_warehouse,
"posting_date": self.doc.posting_date,
"ordered_qty": (is_cancelled=="Yes" and -1 or 1)*flt(curr_qty)
}
update_bin(args)
"ordered_qty": flt(ordered_qty) if self.doc.docstatus==1 else -flt(ordered_qty)
})
def get_already_received_qty(self, po, po_detail):
qty = webnotes.conn.sql("""select sum(qty) from `tabPurchase Receipt Item`
where prevdoc_detail_docname = %s and docstatus = 1
and prevdoc_doctype='Purchase Order' and prevdoc_docname=%s
and parent != %s""", (po_detail, po, self.doc.name))
return qty and flt(qty[0][0]) or 0.0
def get_po_qty_and_warehouse(self, po_detail):
po_qty, po_warehouse = webnotes.conn.get_value("Purchase Order Item", po_detail,
["qty", "warehouse"])
return po_qty, po_warehouse
def bk_flush_supp_wh(self, sl_entries):
for d in getlist(self.doclist, 'pr_raw_material_details'):
@ -201,7 +209,7 @@ class DocType(BuyingController):
sl_entries.append(self.get_sl_entries(d, {
"item_code": d.rm_item_code,
"warehouse": self.doc.supplier_warehouse,
"actual_qty": -1*flt(consumed_qty),
"actual_qty": -1*flt(d.consumed_qty),
"incoming_rate": 0
}))
@ -281,7 +289,7 @@ class DocType(BuyingController):
webnotes.conn.set(self.doc,'status','Cancelled')
self.update_ordered_qty(is_cancelled="Yes")
self.update_ordered_qty()
self.update_stock()
self.update_serial_nos(cancel=True)

View File

@ -246,6 +246,7 @@ class DocType(StockController):
"stock_uom": webnotes.conn.get_value("Item", row.item_code, "stock_uom"),
"voucher_detail_no": row.voucher_detail_no,
"fiscal_year": self.doc.fiscal_year,
"is_cancelled": "No"
})
args.update(opts)
self.make_sl_entries([args])

View File

@ -210,4 +210,3 @@ class DocType:
exists for this warehouse.""", raise_exception=1)
else:
webnotes.conn.sql("delete from `tabStock Ledger Entry` where warehouse = %s", self.doc.name)

View File

@ -126,10 +126,11 @@ erpnext.StockBalance = erpnext.StockAnalytics.extend({
} else {
item.inflow_value += value_diff;
}
item.closing_qty += qty_diff;
item.closing_value += value_diff;
}
item.closing_qty += qty_diff;
item.closing_value += value_diff;
} else {
break;
}

View File

@ -14,29 +14,31 @@ _exceptions = webnotes.local('stockledger_exceptions')
# _exceptions = []
def make_sl_entries(sl_entries, is_amended=None):
from stock.utils import update_bin
if sl_entries:
from stock.utils import update_bin
cancel = True if sl_entries[0].get("is_cancelled") == "Yes" else False
if cancel:
set_as_cancel(sl_entries[0].get('voucher_no'), sl_entries[0].get('voucher_type'))
cancel = True if sl_entries[0].get("is_cancelled") == "Yes" else False
if cancel:
set_as_cancel(sl_entries[0].get('voucher_no'), sl_entries[0].get('voucher_type'))
for sle in sl_entries:
sle_id = None
if sle.get('is_cancelled') == 'Yes':
sle['actual_qty'] = -flt(sle['actual_qty'])
for sle in sl_entries:
sle_id = None
if sle.get('is_cancelled') == 'Yes':
sle['actual_qty'] = -flt(sle['actual_qty'])
if sle.get("actual_qty"):
sle_id = make_entry(sle)
if sle.get("actual_qty"):
sle_id = make_entry(sle)
args = sle.copy()
args.update({
"sle_id": sle_id,
"is_amended": is_amended
})
update_bin(args)
args = sle.copy()
args.update({
"sle_id": sle_id,
"is_amended": is_amended
})
update_bin(args)
if cancel:
delete_cancelled_entry(sl_entries[0].get('voucher_type'), sl_entries[0].get('voucher_no'))
if cancel:
delete_cancelled_entry(sl_entries[0].get('voucher_type'),
sl_entries[0].get('voucher_no'))
def set_as_cancel(voucher_type, voucher_no):
webnotes.conn.sql("""update `tabStock Ledger Entry` set is_cancelled='Yes',

View File

@ -144,6 +144,7 @@ class TransactionBase(StatusUpdater):
def get_customer_address(self, args):
args = load_json(args)
webnotes.errprint(args)
ret = {
'customer_address' : args["address"],
'address_display' : get_address_display(args["address"]),
@ -425,6 +426,7 @@ def get_address_territory(address_doc):
def validate_conversion_rate(currency, conversion_rate, conversion_rate_label, company):
"""common validation for currency and price list currency"""
if conversion_rate == 0:
msgprint(conversion_rate_label + _(' cannot be 0'), raise_exception=True)