672 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			672 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| // Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
 | |
| // License: GNU General Public License v3. See license.txt
 | |
| 
 | |
| wn.provide("erpnext");
 | |
| wn.require("app/js/controllers/stock_controller.js");
 | |
| 
 | |
| erpnext.TransactionController = erpnext.stock.StockController.extend({
 | |
| 	onload: function() {
 | |
| 		var me = this;
 | |
| 		if(this.frm.doc.__islocal) {
 | |
| 			var today = get_today(),
 | |
| 				currency = wn.defaults.get_default("currency");
 | |
| 			
 | |
| 			$.each({
 | |
| 				posting_date: today,
 | |
| 				due_date: today,
 | |
| 				transaction_date: today,
 | |
| 				currency: currency,
 | |
| 				price_list_currency: currency,
 | |
| 				status: "Draft",
 | |
| 				company: wn.defaults.get_default("company"),
 | |
| 				fiscal_year: wn.defaults.get_default("fiscal_year"),
 | |
| 				is_subcontracted: "No",
 | |
| 			}, function(fieldname, value) {
 | |
| 				if(me.frm.fields_dict[fieldname] && !me.frm.doc[fieldname])
 | |
| 					me.frm.set_value(fieldname, value);
 | |
| 			});			
 | |
| 		}
 | |
| 
 | |
| 		if(this.other_fname) {
 | |
| 			this[this.other_fname + "_remove"] = this.calculate_taxes_and_totals;
 | |
| 		}
 | |
| 		
 | |
| 		if(this.fname) {
 | |
| 			this[this.fname + "_remove"] = this.calculate_taxes_and_totals;
 | |
| 		}
 | |
| 	},
 | |
| 	
 | |
| 	onload_post_render: function() {
 | |
| 		var me = this;
 | |
| 		if(this.frm.doc.__islocal && this.frm.doc.company && !this.frm.doc.is_pos) {
 | |
| 			if(!this.frm.doc.customer || !this.frm.doc.supplier) {
 | |
| 				return this.frm.call({
 | |
| 					doc: this.frm.doc,
 | |
| 					method: "onload_post_render",
 | |
| 					freeze: true,
 | |
| 					callback: function(r) {
 | |
| 						// remove this call when using client side mapper
 | |
| 						me.set_default_values();
 | |
| 						me.set_dynamic_labels();
 | |
| 						me.calculate_taxes_and_totals();
 | |
| 					}
 | |
| 				});
 | |
| 			} else {
 | |
| 				this.calculate_taxes_and_totals();
 | |
| 			}
 | |
| 		}
 | |
| 	},
 | |
| 	
 | |
| 	refresh: function() {
 | |
| 		this.frm.clear_custom_buttons();
 | |
| 		erpnext.hide_naming_series();
 | |
| 		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.make_pos_btn();
 | |
| 	},
 | |
| 
 | |
| 	make_pos_btn: function() {
 | |
| 		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.appframe.add_button(btn_label, function() {
 | |
| 			me.toggle_pos();
 | |
| 		}, 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();
 | |
| 		}
 | |
| 	},
 | |
| 
 | |
| 	serial_no: function(doc, cdt, cdn) {
 | |
| 		var me = this;
 | |
| 		var item = wn.model.get_doc(cdt, cdn);
 | |
| 
 | |
| 		if (item.serial_no) {
 | |
| 			if (!item.item_code) {
 | |
| 				this.frm.script_manager.trigger("item_code", cdt, cdn);
 | |
| 			}
 | |
| 			else {
 | |
| 				var sr_no = [];
 | |
| 
 | |
| 				// Replacing all occurences of comma with carriage return
 | |
| 				var serial_nos = item.serial_no.trim().replace(/,/g, '\n');
 | |
| 
 | |
| 				serial_nos = serial_nos.trim().split('\n');
 | |
| 				
 | |
| 				// Trim each string and push unique string to new list
 | |
| 				for (var x=0; x<=serial_nos.length - 1; x++) {
 | |
| 					if (serial_nos[x].trim() != "" && sr_no.indexOf(serial_nos[x].trim()) == -1) {
 | |
| 						sr_no.push(serial_nos[x].trim());
 | |
| 					}
 | |
| 				}
 | |
| 
 | |
| 				// Add the new list to the serial no. field in grid with each in new line
 | |
| 				item.serial_no = "";
 | |
| 				for (var x=0; x<=sr_no.length - 1; x++)
 | |
| 					item.serial_no += sr_no[x] + '\n';
 | |
| 
 | |
| 				refresh_field("serial_no", item.name, item.parentfield);
 | |
| 				wn.model.set_value(item.doctype, item.name, "qty", sr_no.length);
 | |
| 			}
 | |
| 		}
 | |
| 	},
 | |
| 	
 | |
| 	validate: function() {
 | |
| 		this.calculate_taxes_and_totals();
 | |
| 	},
 | |
| 	
 | |
| 	set_default_values: function() {
 | |
| 		$.each(wn.model.get_doclist(this.frm.doctype, this.frm.docname), function(i, doc) {
 | |
| 			var updated = wn.model.set_default_values(doc);
 | |
| 			if(doc.parentfield) {
 | |
| 				refresh_field(doc.parentfield);
 | |
| 			} else {
 | |
| 				refresh_field(updated);
 | |
| 			}
 | |
| 		});
 | |
| 	},
 | |
| 	
 | |
| 	company: function() {
 | |
| 		if(this.frm.doc.company && this.frm.fields_dict.currency) {
 | |
| 			var company_currency = this.get_company_currency();
 | |
| 			if (!this.frm.doc.currency) {
 | |
| 				this.frm.set_value("currency", company_currency);
 | |
| 			}
 | |
| 			
 | |
| 			if (this.frm.doc.currency == company_currency) {
 | |
| 				this.frm.set_value("conversion_rate", 1.0);
 | |
| 			}
 | |
| 			if (this.frm.doc.price_list_currency == company_currency) {
 | |
| 				this.frm.set_value('plc_conversion_rate', 1.0);
 | |
| 			}
 | |
| 
 | |
| 			this.frm.script_manager.trigger("currency");
 | |
| 		}
 | |
| 	},
 | |
| 	
 | |
| 	get_company_currency: function() {
 | |
| 		return erpnext.get_currency(this.frm.doc.company);
 | |
| 	},
 | |
| 	
 | |
| 	currency: function() {
 | |
| 		var me = this;
 | |
| 		this.set_dynamic_labels();
 | |
| 
 | |
| 		var company_currency = this.get_company_currency();
 | |
| 		if(this.frm.doc.currency !== company_currency) {
 | |
| 			this.get_exchange_rate(this.frm.doc.currency, company_currency, 
 | |
| 				function(exchange_rate) {
 | |
| 					me.frm.set_value("conversion_rate", exchange_rate);
 | |
| 					me.conversion_rate();
 | |
| 				});
 | |
| 		} else {
 | |
| 			this.conversion_rate();		
 | |
| 		}
 | |
| 	},
 | |
| 	
 | |
| 	conversion_rate: function() {
 | |
| 		if(this.frm.doc.currency === this.get_company_currency()) {
 | |
| 			this.frm.set_value("conversion_rate", 1.0);
 | |
| 		}
 | |
| 		if(this.frm.doc.currency === this.frm.doc.price_list_currency &&
 | |
| 			this.frm.doc.plc_conversion_rate !== this.frm.doc.conversion_rate) {
 | |
| 				this.frm.set_value("plc_conversion_rate", this.frm.doc.conversion_rate);
 | |
| 		}
 | |
| 		if(flt(this.frm.doc.conversion_rate)>0.0) this.calculate_taxes_and_totals();
 | |
| 	},
 | |
| 	
 | |
| 	get_price_list_currency: function(buying_or_selling) {
 | |
| 		var me = this;
 | |
| 		var fieldname = buying_or_selling.toLowerCase() + "_price_list";
 | |
| 		if(this.frm.doc[fieldname]) {
 | |
| 			return this.frm.call({
 | |
| 				method: "setup.utils.get_price_list_currency",
 | |
| 				args: { 
 | |
| 					price_list: this.frm.doc[fieldname],
 | |
| 				},
 | |
| 				callback: function(r) {
 | |
| 					if(!r.exc) {
 | |
| 						me.price_list_currency();
 | |
| 					}
 | |
| 				}
 | |
| 			});
 | |
| 		}
 | |
| 	},
 | |
| 	
 | |
| 	get_exchange_rate: function(from_currency, to_currency, callback) {
 | |
| 		var exchange_name = from_currency + "-" + to_currency;
 | |
| 		wn.model.with_doc("Currency Exchange", exchange_name, function(name) {
 | |
| 			var exchange_doc = wn.model.get_doc("Currency Exchange", exchange_name);
 | |
| 			callback(exchange_doc ? flt(exchange_doc.exchange_rate) : 0);
 | |
| 		});
 | |
| 	},
 | |
| 	
 | |
| 	price_list_currency: function() {
 | |
| 		var me=this;
 | |
| 		this.set_dynamic_labels();
 | |
| 		
 | |
| 		var company_currency = this.get_company_currency();
 | |
| 		if(this.frm.doc.price_list_currency !== company_currency) {
 | |
| 			this.get_exchange_rate(this.frm.doc.price_list_currency, company_currency, 
 | |
| 				function(exchange_rate) {
 | |
| 					if(exchange_rate) {
 | |
| 						me.frm.set_value("plc_conversion_rate", exchange_rate);
 | |
| 						me.plc_conversion_rate();
 | |
| 					}
 | |
| 				});
 | |
| 		} else {
 | |
| 			this.plc_conversion_rate();
 | |
| 		}
 | |
| 	},
 | |
| 	
 | |
| 	plc_conversion_rate: function() {
 | |
| 		if(this.frm.doc.price_list_currency === this.get_company_currency()) {
 | |
| 			this.frm.set_value("plc_conversion_rate", 1.0);
 | |
| 		}
 | |
| 		if(this.frm.doc.price_list_currency === this.frm.doc.currency) {
 | |
| 			this.frm.set_value("conversion_rate", this.frm.doc.plc_conversion_rate);
 | |
| 			this.calculate_taxes_and_totals();
 | |
| 		}
 | |
| 	},
 | |
| 	
 | |
| 	qty: function(doc, cdt, cdn) {
 | |
| 		this.calculate_taxes_and_totals();
 | |
| 	},
 | |
| 	
 | |
| 	tax_rate: function(doc, cdt, cdn) {
 | |
| 		this.calculate_taxes_and_totals();
 | |
| 	},
 | |
| 
 | |
| 	row_id: function(doc, cdt, cdn) {
 | |
| 		var tax = wn.model.get_doc(cdt, cdn);
 | |
| 		try {
 | |
| 			this.validate_on_previous_row(tax);
 | |
| 			this.calculate_taxes_and_totals();
 | |
| 		} catch(e) {
 | |
| 			tax.row_id = null;
 | |
| 			refresh_field("row_id", tax.name, tax.parentfield);
 | |
| 			throw e;
 | |
| 		}
 | |
| 	},
 | |
| 	
 | |
| 	set_dynamic_labels: function() {
 | |
| 		// What TODO? should we make price list system non-mandatory?
 | |
| 		this.frm.toggle_reqd("plc_conversion_rate",
 | |
| 			!!(this.frm.doc.price_list_name && this.frm.doc.price_list_currency));
 | |
| 			
 | |
| 		var company_currency = this.get_company_currency();
 | |
| 		this.change_form_labels(company_currency);
 | |
| 		this.change_grid_labels(company_currency);
 | |
| 		this.frm.refresh_fields();
 | |
| 	},
 | |
| 	
 | |
| 	recalculate: function() {
 | |
| 		this.calculate_taxes_and_totals();
 | |
| 	},
 | |
| 	
 | |
| 	recalculate_values: function() {
 | |
| 		this.calculate_taxes_and_totals();
 | |
| 	},
 | |
| 	
 | |
| 	calculate_charges: function() {
 | |
| 		this.calculate_taxes_and_totals();
 | |
| 	},
 | |
| 	
 | |
| 	included_in_print_rate: function(doc, cdt, cdn) {
 | |
| 		var tax = wn.model.get_doc(cdt, cdn);
 | |
| 		try {
 | |
| 			this.validate_on_previous_row(tax);
 | |
| 			this.validate_inclusive_tax(tax);
 | |
| 			this.calculate_taxes_and_totals();
 | |
| 		} catch(e) {
 | |
| 			tax.included_in_print_rate = 0;
 | |
| 			refresh_field("included_in_print_rate", tax.name, tax.parentfield);
 | |
| 			throw e;
 | |
| 		}
 | |
| 	},
 | |
| 	
 | |
| 	validate_on_previous_row: function(tax) {
 | |
| 		// validate if a valid row id is mentioned in case of
 | |
| 		// On Previous Row Amount and On Previous Row Total
 | |
| 		if(([wn._("On Previous Row Amount"), wn._("On Previous Row Total")].indexOf(tax.charge_type) != -1) &&
 | |
| 			(!tax.row_id || cint(tax.row_id) >= tax.idx)) {
 | |
| 				var msg = repl(wn._("Row") + " # %(idx)s [%(doctype)s]: " +
 | |
| 					wn._("Please specify a valid") + " %(row_id_label)s", {
 | |
| 						idx: tax.idx,
 | |
| 						doctype: tax.doctype,
 | |
| 						row_id_label: wn.meta.get_label(tax.doctype, "row_id", tax.name)
 | |
| 					});
 | |
| 				msgprint(msg);
 | |
| 				throw msg;
 | |
| 			}
 | |
| 	},
 | |
| 	
 | |
| 	validate_inclusive_tax: function(tax) {
 | |
| 		if(!this.frm.tax_doclist) this.frm.tax_doclist = this.get_tax_doclist();
 | |
| 		
 | |
| 		var actual_type_error = function() {
 | |
| 			var msg = repl(wn._("For row") + " # %(idx)s [%(doctype)s]: " + 
 | |
| 				"%(charge_type_label)s = \"%(charge_type)s\" " +
 | |
| 				wn._("cannot be included in Item's rate"), {
 | |
| 					idx: tax.idx,
 | |
| 					doctype: tax.doctype,
 | |
| 					charge_type_label: wn.meta.get_label(tax.doctype, "charge_type", tax.name),
 | |
| 					charge_type: tax.charge_type
 | |
| 				});
 | |
| 			msgprint(msg);
 | |
| 			throw msg;
 | |
| 		};
 | |
| 		
 | |
| 		var on_previous_row_error = function(row_range) {
 | |
| 			var msg = repl(wn._("For row") + " # %(idx)s [%(doctype)s]: " + 
 | |
| 				wn._("to be included in Item's rate, it is required that: ") + 
 | |
| 				" [" + wn._("Row") + " # %(row_range)s] " + wn._("also be included in Item's rate"), {
 | |
| 					idx: tax.idx,
 | |
| 					doctype: tax.doctype,
 | |
| 					charge_type_label: wn.meta.get_label(tax.doctype, "charge_type", tax.name),
 | |
| 					charge_type: tax.charge_type,
 | |
| 					inclusive_label: wn.meta.get_label(tax.doctype, "included_in_print_rate", tax.name),
 | |
| 					row_range: row_range,
 | |
| 				});
 | |
| 			
 | |
| 			msgprint(msg);
 | |
| 			throw msg;
 | |
| 		};
 | |
| 		
 | |
| 		if(cint(tax.included_in_print_rate)) {
 | |
| 			if(tax.charge_type == "Actual") {
 | |
| 				// inclusive tax cannot be of type Actual
 | |
| 				actual_type_error();
 | |
| 			} else if(tax.charge_type == "On Previous Row Amount" &&
 | |
| 				!cint(this.frm.tax_doclist[tax.row_id - 1].included_in_print_rate)) {
 | |
| 					// referred row should also be an inclusive tax
 | |
| 					on_previous_row_error(tax.row_id);
 | |
| 			} else if(tax.charge_type == "On Previous Row Total") {
 | |
| 				var taxes_not_included = $.map(this.frm.tax_doclist.slice(0, tax.row_id), 
 | |
| 					function(t) { return cint(t.included_in_print_rate) ? null : t; });
 | |
| 				if(taxes_not_included.length > 0) {
 | |
| 					// all rows above this tax should be inclusive
 | |
| 					on_previous_row_error(tax.row_id == 1 ? "1" : "1 - " + tax.row_id);
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	},
 | |
| 	
 | |
| 	_load_item_tax_rate: function(item_tax_rate) {
 | |
| 		return item_tax_rate ? JSON.parse(item_tax_rate) : {};
 | |
| 	},
 | |
| 	
 | |
| 	_get_tax_rate: function(tax, item_tax_map) {
 | |
| 		return (keys(item_tax_map).indexOf(tax.account_head) != -1) ?
 | |
| 			flt(item_tax_map[tax.account_head], precision("rate", tax)) :
 | |
| 			tax.rate;
 | |
| 	},
 | |
| 	
 | |
| 	get_item_wise_taxes_html: function() {
 | |
| 		var item_tax = {};
 | |
| 		var tax_accounts = [];
 | |
| 		var company_currency = this.get_company_currency();
 | |
| 		
 | |
| 		$.each(this.get_tax_doclist(), function(i, tax) {
 | |
| 			var tax_amount_precision = precision("tax_amount", tax);
 | |
| 			var tax_rate_precision = precision("rate", tax);
 | |
| 			$.each(JSON.parse(tax.item_wise_tax_detail || '{}'), 
 | |
| 				function(item_code, tax_data) {
 | |
| 					if(!item_tax[item_code]) item_tax[item_code] = {};
 | |
| 					if($.isArray(tax_data)) {
 | |
| 						var tax_rate = "";
 | |
| 						if(tax_data[0] != null) {
 | |
| 							tax_rate = (tax.charge_type === "Actual") ?
 | |
| 								format_currency(flt(tax_data[0], tax_amount_precision), company_currency, tax_amount_precision) :
 | |
| 								(flt(tax_data[0], tax_rate_precision) + "%");
 | |
| 						}
 | |
| 						var tax_amount = format_currency(flt(tax_data[1], tax_amount_precision), company_currency,
 | |
| 							tax_amount_precision);
 | |
| 						
 | |
| 						item_tax[item_code][tax.name] = [tax_rate, tax_amount];
 | |
| 					} else {
 | |
| 						item_tax[item_code][tax.name] = [flt(tax_data, tax_rate_precision) + "%", ""];
 | |
| 					}
 | |
| 				});
 | |
| 			tax_accounts.push([tax.name, tax.account_head]);
 | |
| 		});
 | |
| 		
 | |
| 		var headings = $.map([wn._("Item Name")].concat($.map(tax_accounts, function(head) { return head[1]; })), 
 | |
| 			function(head) { return '<th style="min-width: 100px;">' + (head || "") + "</th>" }).join("\n");
 | |
| 			
 | |
| 		var distinct_item_names = [];
 | |
| 		var distinct_items = [];
 | |
| 		$.each(this.get_item_doclist(), function(i, item) {
 | |
| 			if(distinct_item_names.indexOf(item.item_code || item.item_name)===-1) {
 | |
| 				distinct_item_names.push(item.item_code || item.item_name);
 | |
| 				distinct_items.push(item);
 | |
| 			}
 | |
| 		});
 | |
| 		
 | |
| 		var rows = $.map(distinct_items, function(item) {
 | |
| 			var item_tax_record = item_tax[item.item_code || item.item_name];
 | |
| 			if(!item_tax_record) { return null; }
 | |
| 			return repl("<tr><td>%(item_name)s</td>%(taxes)s</tr>", {
 | |
| 				item_name: item.item_name,
 | |
| 				taxes: $.map(tax_accounts, function(head) {
 | |
| 					return item_tax_record[head[0]] ?
 | |
| 						"<td>(" + item_tax_record[head[0]][0] + ") " + item_tax_record[head[0]][1] + "</td>" :
 | |
| 						"<td></td>";
 | |
| 				}).join("\n")
 | |
| 			});
 | |
| 		}).join("\n");
 | |
| 		
 | |
| 		if(!rows) return "";
 | |
| 		return '<p><a href="#" onclick="$(\'.tax-break-up\').toggleClass(\'hide\'); return false;">Show / Hide tax break-up</a><br><br></p>\
 | |
| 		<div class="tax-break-up hide" style="overflow-x: auto;"><table class="table table-bordered table-hover">\
 | |
| 			<thead><tr>' + headings + '</tr></thead> \
 | |
| 			<tbody>' + rows + '</tbody> \
 | |
| 		</table></div>';
 | |
| 	},
 | |
| 	
 | |
| 	_validate_before_fetch: function(fieldname) {
 | |
| 		var me = this;
 | |
| 		if(!me.frm.doc[fieldname]) {
 | |
| 			return (wn._("Please specify") + ": " + 
 | |
| 				wn.meta.get_label(me.frm.doc.doctype, fieldname, me.frm.doc.name) + 
 | |
| 				". " + wn._("It is needed to fetch Item Details."));
 | |
| 		}
 | |
| 		return null;
 | |
| 	},
 | |
| 	
 | |
| 	validate_company_and_party: function(party_field) {
 | |
| 		var me = this;
 | |
| 		var valid = true;
 | |
| 		var msg = "";
 | |
| 		$.each(["company", party_field], function(i, fieldname) {
 | |
| 			var msg_for_fieldname = me._validate_before_fetch(fieldname);
 | |
| 			if(msg_for_fieldname) {
 | |
| 				msgprint(msg_for_fieldname);
 | |
| 				valid = false;
 | |
| 			}
 | |
| 		});
 | |
| 		return valid;
 | |
| 	},
 | |
| 	
 | |
| 	get_item_doclist: function() {
 | |
| 		return wn.model.get_doclist(this.frm.doc.doctype, this.frm.doc.name,
 | |
| 			{parentfield: this.fname});
 | |
| 	},
 | |
| 	
 | |
| 	get_tax_doclist: function() {
 | |
| 		return wn.model.get_doclist(this.frm.doc.doctype, this.frm.doc.name,
 | |
| 			{parentfield: this.other_fname});
 | |
| 	},
 | |
| 	
 | |
| 	validate_conversion_rate: function() {
 | |
| 		this.frm.doc.conversion_rate = flt(this.frm.doc.conversion_rate, precision("conversion_rate"));
 | |
| 		var conversion_rate_label = wn.meta.get_label(this.frm.doc.doctype, "conversion_rate", 
 | |
| 			this.frm.doc.name);
 | |
| 		var company_currency = this.get_company_currency();
 | |
| 		
 | |
| 		if(!this.frm.doc.conversion_rate) {
 | |
| 			wn.throw(repl('%(conversion_rate_label)s' + 
 | |
| 				wn._(' is mandatory. Maybe Currency Exchange record is not created for ') + 
 | |
| 				'%(from_currency)s' + wn._(" to ") + '%(to_currency)s', 
 | |
| 				{
 | |
| 					"conversion_rate_label": conversion_rate_label,
 | |
| 					"from_currency": this.frm.doc.currency,
 | |
| 					"to_currency": company_currency
 | |
| 				}));
 | |
| 		}
 | |
| 	},
 | |
| 	
 | |
| 	calculate_taxes_and_totals: function() {
 | |
| 		this.validate_conversion_rate();
 | |
| 		this.frm.item_doclist = this.get_item_doclist();
 | |
| 		this.frm.tax_doclist = this.get_tax_doclist();
 | |
| 		
 | |
| 		this.calculate_item_values();
 | |
| 		this.initialize_taxes();
 | |
| 		this.determine_exclusive_rate && this.determine_exclusive_rate();
 | |
| 		this.calculate_net_total();
 | |
| 		this.calculate_taxes();
 | |
| 		this.calculate_totals();
 | |
| 		this._cleanup();
 | |
| 		
 | |
| 		this.show_item_wise_taxes();
 | |
| 	},
 | |
| 	
 | |
| 	initialize_taxes: function() {
 | |
| 		var me = this;
 | |
| 		$.each(this.frm.tax_doclist, function(i, tax) {
 | |
| 			tax.item_wise_tax_detail = {};
 | |
| 			$.each(["tax_amount", "total",
 | |
| 				"tax_amount_for_current_item", "grand_total_for_current_item",
 | |
| 				"tax_fraction_for_current_item", "grand_total_fraction_for_current_item"],
 | |
| 				function(i, fieldname) { tax[fieldname] = 0.0 });
 | |
| 			
 | |
| 			me.validate_on_previous_row(tax);
 | |
| 			me.validate_inclusive_tax(tax);
 | |
| 			wn.model.round_floats_in(tax);
 | |
| 		});
 | |
| 	},
 | |
| 	
 | |
| 	calculate_taxes: function() {
 | |
| 		var me = this;
 | |
| 		
 | |
| 		$.each(this.frm.item_doclist, function(n, item) {
 | |
| 			var item_tax_map = me._load_item_tax_rate(item.item_tax_rate);
 | |
| 			
 | |
| 			$.each(me.frm.tax_doclist, function(i, tax) {
 | |
| 				// tax_amount represents the amount of tax for the current step
 | |
| 				var current_tax_amount = me.get_current_tax_amount(item, tax, item_tax_map);
 | |
| 
 | |
| 				me.set_item_tax_amount && me.set_item_tax_amount(item, tax, current_tax_amount);
 | |
| 				
 | |
| 				// case when net total is 0 but there is an actual type charge
 | |
| 				// in this case add the actual amount to tax.tax_amount
 | |
| 				// and tax.grand_total_for_current_item for the first such iteration
 | |
| 				if(tax.charge_type == "Actual" && 
 | |
| 					!(current_tax_amount || me.frm.doc.net_total || tax.tax_amount)) {
 | |
| 						var zero_net_total_adjustment = flt(tax.rate, precision("tax_amount", tax));
 | |
| 						current_tax_amount += zero_net_total_adjustment;
 | |
| 					}
 | |
| 				
 | |
| 				// store tax_amount for current item as it will be used for
 | |
| 				// charge type = 'On Previous Row Amount'
 | |
| 				tax.tax_amount_for_current_item = current_tax_amount;
 | |
| 				
 | |
| 				// accumulate tax amount into tax.tax_amount
 | |
| 				tax.tax_amount += current_tax_amount;
 | |
| 				
 | |
| 				// for buying
 | |
| 				if(tax.category) {
 | |
| 					// if just for valuation, do not add the tax amount in total
 | |
| 					// hence, setting it as 0 for further steps
 | |
| 					current_tax_amount = (tax.category == "Valuation") ? 0.0 : current_tax_amount;
 | |
| 					
 | |
| 					current_tax_amount *= (tax.add_deduct_tax == "Deduct") ? -1.0 : 1.0;
 | |
| 				}
 | |
| 				
 | |
| 				// Calculate tax.total viz. grand total till that step
 | |
| 				// note: grand_total_for_current_item contains the contribution of 
 | |
| 				// item's amount, previously applied tax and the current tax on that item
 | |
| 				if(i==0) {
 | |
| 					tax.grand_total_for_current_item = flt(item.amount + current_tax_amount,
 | |
| 						precision("total", tax));
 | |
| 				} else {
 | |
| 					tax.grand_total_for_current_item = 
 | |
| 						flt(me.frm.tax_doclist[i-1].grand_total_for_current_item + current_tax_amount,
 | |
| 							precision("total", tax));
 | |
| 				}
 | |
| 				
 | |
| 				// in tax.total, accumulate grand total for each item
 | |
| 				tax.total += tax.grand_total_for_current_item;
 | |
| 			});
 | |
| 		});
 | |
| 	},
 | |
| 	
 | |
| 	get_current_tax_amount: function(item, tax, item_tax_map) {
 | |
| 		var tax_rate = this._get_tax_rate(tax, item_tax_map);
 | |
| 		var current_tax_amount = 0.0;
 | |
| 		
 | |
| 		if(tax.charge_type == "Actual") {
 | |
| 			// distribute the tax amount proportionally to each item row
 | |
| 			var actual = flt(tax.rate, precision("tax_amount", tax));
 | |
| 			current_tax_amount = this.frm.doc.net_total ?
 | |
| 				((item.amount / this.frm.doc.net_total) * actual) :
 | |
| 				0.0;
 | |
| 			
 | |
| 		} else if(tax.charge_type == "On Net Total") {
 | |
| 			current_tax_amount = (tax_rate / 100.0) * item.amount;
 | |
| 			
 | |
| 		} else if(tax.charge_type == "On Previous Row Amount") {
 | |
| 			current_tax_amount = (tax_rate / 100.0) *
 | |
| 				this.frm.tax_doclist[cint(tax.row_id) - 1].tax_amount_for_current_item;
 | |
| 			
 | |
| 		} else if(tax.charge_type == "On Previous Row Total") {
 | |
| 			current_tax_amount = (tax_rate / 100.0) *
 | |
| 				this.frm.tax_doclist[cint(tax.row_id) - 1].grand_total_for_current_item;
 | |
| 			
 | |
| 		}
 | |
| 		
 | |
| 		current_tax_amount = flt(current_tax_amount, precision("tax_amount", tax));
 | |
| 		
 | |
| 		// store tax breakup for each item
 | |
| 		tax.item_wise_tax_detail[item.item_code || item.item_name] = [tax_rate, current_tax_amount];
 | |
| 		
 | |
| 		return current_tax_amount;
 | |
| 	},
 | |
| 	
 | |
| 	_cleanup: function() {
 | |
| 		$.each(this.frm.tax_doclist, function(i, tax) {
 | |
| 			$.each(["tax_amount_for_current_item", "grand_total_for_current_item",
 | |
| 				"tax_fraction_for_current_item", "grand_total_fraction_for_current_item"], 
 | |
| 				function(i, fieldname) { delete tax[fieldname]; });
 | |
| 			
 | |
| 			tax.item_wise_tax_detail = JSON.stringify(tax.item_wise_tax_detail);
 | |
| 		});
 | |
| 	},
 | |
| 
 | |
| 	calculate_total_advance: function(parenttype, advance_parentfield) {
 | |
| 		if(this.frm.doc.doctype == parenttype && this.frm.doc.docstatus < 2) {
 | |
| 			var advance_doclist = wn.model.get_doclist(this.frm.doc.doctype, this.frm.doc.name, 
 | |
| 				{parentfield: advance_parentfield});
 | |
| 			this.frm.doc.total_advance = flt(wn.utils.sum(
 | |
| 				$.map(advance_doclist, function(adv) { return adv.allocated_amount })
 | |
| 			), precision("total_advance"));
 | |
| 			
 | |
| 			this.calculate_outstanding_amount();
 | |
| 		}
 | |
| 	},
 | |
| 	
 | |
| 	_set_in_company_currency: function(item, print_field, base_field) {
 | |
| 		// set values in base currency
 | |
| 		item[base_field] = flt(item[print_field] * this.frm.doc.conversion_rate,
 | |
| 			precision(base_field, item));
 | |
| 	},
 | |
| 	
 | |
| 	get_terms: function() {
 | |
| 		var me = this;
 | |
| 		if(this.frm.doc.tc_name) {
 | |
| 			return this.frm.call({
 | |
| 				method: "webnotes.client.get_value",
 | |
| 				args: {
 | |
| 					doctype: "Terms and Conditions",
 | |
| 					fieldname: "terms",
 | |
| 					filters: { name: this.frm.doc.tc_name },
 | |
| 				},
 | |
| 			});
 | |
| 		}
 | |
| 	},
 | |
| }); |