diff --git a/erpnext/accounts/doctype/pos_profile/pos_profile.json b/erpnext/accounts/doctype/pos_profile/pos_profile.json index 8882491866d..0ab48e283f8 100644 --- a/erpnext/accounts/doctype/pos_profile/pos_profile.json +++ b/erpnext/accounts/doctype/pos_profile/pos_profile.json @@ -118,6 +118,32 @@ "set_only_once": 0, "unique": 0 }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "campaign", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Campaign", + "length": 0, + "no_copy": 0, + "options": "Campaign", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, { "allow_on_submit": 0, "bold": 0, @@ -859,7 +885,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2016-08-06 17:05:59.990031", + "modified": "2016-08-09 02:36:07.316464", "modified_by": "Administrator", "module": "Accounts", "name": "POS Profile", diff --git a/erpnext/accounts/doctype/sales_invoice/pos.py b/erpnext/accounts/doctype/sales_invoice/pos.py index 53144cbf2be..5cb9f765dda 100644 --- a/erpnext/accounts/doctype/sales_invoice/pos.py +++ b/erpnext/accounts/doctype/sales_invoice/pos.py @@ -35,7 +35,6 @@ def get_pos_data(): 'customers': get_customers(pos_profile, doc), 'pricing_rules': get_pricing_rules(doc), 'print_template': print_template, - 'write_off_account': pos_profile.get('write_off_account'), 'meta': { 'invoice': frappe.get_meta('Sales Invoice'), 'items': frappe.get_meta('Sales Invoice Item'), @@ -45,7 +44,12 @@ def get_pos_data(): def update_pos_profile_data(doc, pos_profile): company_data = frappe.db.get_value('Company', doc.company, '*', as_dict=1) + doc.campaign = pos_profile.get('campaign') + doc.write_off_account = pos_profile.get('write_off_account') or \ + company_data.write_off_account + doc.change_amount_account = pos_profile.get('change_amount_account') or \ + company_data.default_cash_account doc.taxes_and_charges = pos_profile.get('taxes_and_charges') if doc.taxes_and_charges: update_tax_table(doc) @@ -54,7 +58,8 @@ def update_pos_profile_data(doc, pos_profile): doc.conversion_rate = 1.0 if doc.currency != company_data.default_currency: doc.conversion_rate = get_exchange_rate(doc.currency, company_data.default_currency) - doc.selling_price_list = pos_profile.get('selling_price_list') or frappe.db.get_value('Selling Settings', None, 'selling_price_list') + doc.selling_price_list = pos_profile.get('selling_price_list') or \ + frappe.db.get_value('Selling Settings', None, 'selling_price_list') doc.naming_series = pos_profile.get('naming_series') or 'SINV-' doc.letter_head = pos_profile.get('letter_head') or company_data.default_letter_head doc.ignore_pricing_rule = pos_profile.get('ignore_pricing_rule') or 0 @@ -157,10 +162,11 @@ def get_customers(pos_profile, doc): def get_pricing_rules(doc): pricing_rules = "" if doc.ignore_pricing_rule == 0: - pricing_rules = frappe.db.sql(""" Select * from `tabPricing Rule` where docstatus < 2 and disable = 0 - and selling = 1 and ifnull(company, '') in (%(company)s, '') and - ifnull(for_price_list, '') in (%(price_list)s, '') and %(date)s between - ifnull(valid_from, '2000-01-01') and ifnull(valid_upto, '2500-12-31') order by priority desc, name desc""", + pricing_rules = frappe.db.sql(""" Select * from `tabPricing Rule` where docstatus < 2 + and ifnull(for_price_list, '') in (%(price_list)s, '') and selling = 1 + and ifnull(company, '') in (%(company)s, '') and disable = 0 and %(date)s + between ifnull(valid_from, '2000-01-01') and ifnull(valid_upto, '2500-12-31') + order by priority desc, name desc""", {'company': doc.company, 'price_list': doc.selling_price_list, 'date': nowdate()}, as_dict=1) return pricing_rules @@ -173,9 +179,9 @@ def make_invoice(doc_list): for docs in doc_list: for name, doc in docs.items(): - if not frappe.db.exists('Sales Invoice', {'offline_pos_name': name}): - validate_customer(doc) - validate_item(doc) + if not frappe.db.exists('Sales Invoice', + {'offline_pos_name': name, 'docstatus': ("<", "2")}): + validate_records(doc) si_doc = frappe.new_doc('Sales Invoice') si_doc.offline_pos_name = name si_doc.update(doc) @@ -184,6 +190,10 @@ def make_invoice(doc_list): return name_list +def validate_records(doc): + validate_customer(doc) + validate_item(doc) + def validate_customer(doc): if not frappe.db.exists('Customer', doc.get('customer')): customer_doc = frappe.new_doc('Customer') @@ -195,8 +205,6 @@ def validate_customer(doc): frappe.db.commit() doc['customer'] = customer_doc.name - return doc - def validate_item(doc): for item in doc.get('items'): if not frappe.db.exists('Item', item.get('item_code')): diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js index 417d3468f24..11918711347 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js @@ -275,6 +275,7 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte frappe.msgprint(__("You can not return change amount, limit has been exceeded")) }else{ this.calculate_write_off_amount() + this.frm.refresh_fields(); } } }); @@ -467,7 +468,7 @@ frappe.ui.form.on('Sales Invoice', { ] } } - }, + } }) frappe.ui.form.on('Sales Invoice Timesheet', { diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index 994579f5b1e..cdf9bd8029d 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -237,12 +237,18 @@ class SalesInvoice(SellingController): pos_profile = frappe.get_doc('POS Profile', pos.name) if pos else None update_multi_mode_option(self, pos_profile) + if not self.change_amount_account: + self.change_amount_account = frappe.db.get_value('Company', self.company, 'default_cash_account') + if pos: if not for_validate and not self.customer: self.customer = pos.customer self.mode_of_payment = pos.mode_of_payment # self.set_customer_defaults() + if not self.change_amount_account: + self.change_amount_account = pos.get('change_amount_account') + for fieldname in ('territory', 'naming_series', 'currency', 'taxes_and_charges', 'letter_head', 'tc_name', 'selling_price_list', 'company', 'select_print_heading', 'cash_bank_account', 'write_off_account', 'write_off_cost_center'): @@ -268,7 +274,6 @@ class SalesInvoice(SellingController): # fetch charges if self.taxes_and_charges and not len(self.get("taxes")): self.set_taxes() - self.change_amount_account = pos.change_amount_account return pos @@ -503,7 +508,7 @@ class SalesInvoice(SellingController): gl_entries = merge_similar_entries(gl_entries) self.make_pos_gl_entries(gl_entries) - self.make_gle_for_change(gl_entries) + self.make_gle_for_change_amount(gl_entries) self.make_write_off_gl_entry(gl_entries) @@ -607,7 +612,7 @@ class SalesInvoice(SellingController): }, payment_mode_account_currency) ) - def make_gle_for_change(self, gl_entries): + def make_gle_for_change_amount(self, gl_entries): if cint(self.is_pos) and self.change_amount: if self.change_amount_account: gl_entries.append( diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index dd28059c43c..db129de6bc8 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -455,6 +455,25 @@ class TestSalesInvoice(unittest.TestCase): self.pos_gl_entry(si, pos, 300) + def test_pos_chnage_amount(self): + set_perpetual_inventory() + self.make_pos_profile() + + self._insert_purchase_receipt() + pos = copy.deepcopy(test_records[1]) + pos["is_pos"] = 1 + pos["update_stock"] = 1 + pos["payments"] = [{'mode_of_payment': 'Bank Draft', 'account': '_Test Bank - _TC', 'amount': 300}, + {'mode_of_payment': 'Cash', 'account': 'Cash - _TC', 'amount': 340}] + + si = frappe.copy_doc(pos) + si.change_amount = 5.0 + si.insert() + si.submit() + + self.assertEquals(si.grand_total, 630.0) + self.assertEquals(si.write_off_amount, -5) + def test_make_pos_invoice(self): from erpnext.accounts.doctype.sales_invoice.pos import make_invoice diff --git a/erpnext/accounts/page/pos/pos.js b/erpnext/accounts/page/pos/pos.js index 8444dbe91f7..fd76d510b53 100644 --- a/erpnext/accounts/page/pos/pos.js +++ b/erpnext/accounts/page/pos/pos.js @@ -183,6 +183,14 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ if(this.frm.doc.customer){ this.party_field.$input.val(this.frm.doc.customer); } + + if(!this.frm.doc.write_off_account){ + this.frm.doc.write_off_account = doc.write_off_account + } + + if(!this.frm.doc.change_amount_account){ + this.frm.doc.change_amount_account = doc.change_amount_account + } }, get_invoice_doc: function(si_docs){ @@ -209,7 +217,6 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ window.meta = r.message.meta; window.print_template = r.message.print_template; me.default_customer = r.message.default_customer || null; - me.write_off_account = r.message.write_off_account; localStorage.setItem('doc', JSON.stringify(r.message.doc)); if(callback){ callback(); @@ -717,49 +724,6 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ }, 1000) }, - write_off_amount: function(){ - var me = this; - var value = 0.0; - - if(this.frm.doc.outstanding_amount > 0){ - dialog = new frappe.ui.Dialog({ - title: 'Write Off Amount', - fields: [ - {fieldtype: "Check", fieldname: "write_off_amount", label: __("Write off Outstanding Amount")}, - {fieldtype: "Link", options:"Account", default:this.write_off_account, fieldname: "write_off_account", - label: __("Write off Account"), get_query: function() { - return { - filters: {'is_group': 0, 'report_type': 'Profit and Loss'} - } - }} - ] - }); - - dialog.show(); - - dialog.fields_dict.write_off_amount.$input.change(function(){ - write_off_amount = dialog.get_values().write_off_amount; - me.frm.doc.write_off_outstanding_amount_automatically = write_off_amount; - me.frm.doc.base_write_off_amount = (write_off_amount==1) ? flt(me.frm.doc.grand_total - me.frm.doc.paid_amount, precision("outstanding_amount")) : 0; - me.frm.doc.write_off_account = (write_off_amount==1) ? dialog.get_values().write_off_account : ''; - me.frm.doc.write_off_amount = flt(me.frm.doc.base_write_off_amount * me.frm.doc.conversion_rate, precision("write_off_amount")) - me.calculate_outstanding_amount(); - me.set_primary_action(); - }) - - dialog.fields_dict.write_off_account.$input.change(function(){ - me.frm.doc.write_off_account = dialog.get_values().write_off_account; - }) - - dialog.set_primary_action(__("Submit"), function(){ - dialog.hide() - me.submit_invoice() - }) - }else{ - this.submit_invoice() - } - }, - submit_invoice: function(){ var me = this; frappe.confirm(__("Do you really want to submit the invoice?"), function () { @@ -970,11 +934,13 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ get_pricing_rule: function(item){ var me = this; return $.grep(this.pricing_rules, function(data){ - if(data.item_code == item.item_code || in_list(['All Item Groups', item.item_group], data.item_group)) { - if(in_list(['Customer', 'Customer Group', 'Territory'], data.applicable_for)){ - return me.validate_condition(data) - }else{ - return true + if(item.qty >= data.min_qty && (item.qty <= (data.max_qty ? data.max_qty : item.qty)) ){ + if(data.item_code == item.item_code || in_list(['All Item Groups', item.item_group], data.item_group)) { + if(in_list(['Customer', 'Customer Group', 'Territory', 'Campaign'], data.applicable_for)){ + return me.validate_condition(data) + }else{ + return true + } } } }) @@ -993,6 +959,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ 'Customer': [data.customer, [this.frm.doc.customer]], 'Customer Group': [data.customer_group, [this.frm.doc.customer_group, 'All Customer Groups']], 'Territory': [data.territory, [this.frm.doc.territory, 'All Territories']], + 'Campaign': [data.campaign, [this.frm.doc.campaign]], } }, diff --git a/erpnext/controllers/taxes_and_totals.py b/erpnext/controllers/taxes_and_totals.py index afb3befcfc0..125f4fedb62 100644 --- a/erpnext/controllers/taxes_and_totals.py +++ b/erpnext/controllers/taxes_and_totals.py @@ -470,7 +470,10 @@ class calculate_taxes_and_totals(object): self.doc.precision("base_change_amount")) def calculate_write_off_amount(self): - self.doc.write_off_amount = self.doc.grand_total - self.doc.paid_amount + self.doc.change_amount + if flt(self.doc.change_amount) > 0: + self.doc.write_off_amount = self.doc.grand_total - self.doc.paid_amount + self.doc.change_amount + self.doc.base_write_off_amount = flt(self.doc.write_off_amount * self.doc.conversion_rate, + self.doc.precision("base_write_off_amount")) def calculate_margin(self, item): total_margin = 0.0 diff --git a/erpnext/public/js/controllers/taxes_and_totals.js b/erpnext/public/js/controllers/taxes_and_totals.js index ad6f0ed4f9f..c3f4b700438 100644 --- a/erpnext/public/js/controllers/taxes_and_totals.js +++ b/erpnext/public/js/controllers/taxes_and_totals.js @@ -617,8 +617,16 @@ erpnext.taxes_and_totals = erpnext.payments.extend({ }, calculate_write_off_amount: function(){ - this.frm.set_value("write_off_amount", - flt(this.frm.doc.grand_total - this.frm.doc.paid_amount + this.frm.doc.change_amount, - precision("write_off_amount"))); + if(this.frm.doc.paid_amount > this.frm.doc.grand_total){ + this.frm.doc.write_off_amount = flt(this.frm.doc.grand_total - this.frm.doc.paid_amount + this.frm.doc.change_amount, + precision("write_off_amount")) + + this.frm.doc.base_write_off_amount = flt(this.frm.doc.write_off_amount * this.frm.doc.conversion_rate, + precision("base_write_off_amount")); + }else{ + this.frm.doc.paid_amount = 0.0 + } + + this.calculate_outstanding_amount(false) } }) diff --git a/erpnext/public/js/payment/payment_details.html b/erpnext/public/js/payment/payment_details.html index 18f9d038856..596f139ea0b 100644 --- a/erpnext/public/js/payment/payment_details.html +++ b/erpnext/public/js/payment/payment_details.html @@ -1,5 +1,5 @@
Total
Paid
Outstanding
Change
Change +
+Write off