diff --git a/erpnext/accounts/doctype/pos_profile/test_pos_profile.py b/erpnext/accounts/doctype/pos_profile/test_pos_profile.py index d99386567a..c1b033cdda 100644 --- a/erpnext/accounts/doctype/pos_profile/test_pos_profile.py +++ b/erpnext/accounts/doctype/pos_profile/test_pos_profile.py @@ -51,4 +51,6 @@ def make_pos_profile(): }) if not frappe.db.exists("POS Profile", "_Test POS Profile"): - pos_profile.insert() \ No newline at end of file + pos_profile.insert() + + return pos_profile diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index 3364727967..3e8881c109 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -691,6 +691,7 @@ class TestSalesInvoice(unittest.TestCase): item = make_item("_Test POS Item") pos = copy.deepcopy(test_records[1]) pos['items'][0]['item_code'] = item.name + pos['items'][0]['warehouse'] = "_Test Warehouse - _TC" pos["is_pos"] = 1 pos["offline_pos_name"] = timestamp pos["update_stock"] = 1 diff --git a/erpnext/controllers/selling_controller.py b/erpnext/controllers/selling_controller.py index 1fcd11dd60..3451c6209e 100644 --- a/erpnext/controllers/selling_controller.py +++ b/erpnext/controllers/selling_controller.py @@ -363,4 +363,4 @@ def check_active_sales_items(obj): "company": obj.company, "income_account": d.income_account }) - doc.save() \ No newline at end of file + doc.save(ignore_permissions=True) diff --git a/erpnext/controllers/taxes_and_totals.py b/erpnext/controllers/taxes_and_totals.py index 6c0347f7a0..6f9db34416 100644 --- a/erpnext/controllers/taxes_and_totals.py +++ b/erpnext/controllers/taxes_and_totals.py @@ -166,6 +166,7 @@ class calculate_taxes_and_totals(object): def calculate_net_total(self): self.doc.total_qty = self.doc.total = self.doc.base_total = self.doc.net_total = self.doc.base_net_total = 0.0 + for item in self.doc.get("items"): self.doc.total += item.amount self.doc.total_qty += item.qty @@ -175,6 +176,9 @@ class calculate_taxes_and_totals(object): self.doc.round_floats_in(self.doc, ["total", "base_total", "net_total", "base_net_total"]) + if self.doc.doctype == 'Sales Invoice' and self.doc.is_pos: + self.doc.pos_total_qty = self.doc.total_qty + def calculate_taxes(self): self.doc.rounding_adjustment = 0 # maintain actual tax rate based on idx diff --git a/erpnext/selling/doctype/pos_closing_voucher/pos_closing_voucher.py b/erpnext/selling/doctype/pos_closing_voucher/pos_closing_voucher.py index 2b66419c89..a4a6e86849 100644 --- a/erpnext/selling/doctype/pos_closing_voucher/pos_closing_voucher.py +++ b/erpnext/selling/doctype/pos_closing_voucher/pos_closing_voucher.py @@ -9,7 +9,6 @@ from collections import defaultdict from erpnext.controllers.taxes_and_totals import get_itemised_tax_breakup_data import json - class POSClosingVoucher(Document): def get_closing_voucher_details(self): filters = { @@ -21,7 +20,6 @@ class POSClosingVoucher(Document): 'user': self.user, 'is_pos': 1 } - frappe.log_error(filters) invoice_list = get_invoices(filters) self.set_invoice_list(invoice_list) @@ -29,8 +27,9 @@ class POSClosingVoucher(Document): sales_summary = get_sales_summary(invoice_list) self.set_sales_summary_values(sales_summary) - mop = get_mode_of_payment_details(invoice_list) - self.set_mode_of_payments(mop) + if not self.get('payment_reconciliation'): + mop = get_mode_of_payment_details(invoice_list) + self.set_mode_of_payments(mop) taxes = get_tax_details(invoice_list) self.set_taxes(taxes) @@ -67,11 +66,10 @@ class POSClosingVoucher(Document): 'amount': tax['amount'] }) - def get_payment_reconciliation_details(self): currency = get_company_currency(self) - return frappe.render_template("erpnext/selling/doctype/pos_closing_voucher/closing_voucher_details.html", {"data": self, "currency": currency}) - + return frappe.render_template("erpnext/selling/doctype/pos_closing_voucher/closing_voucher_details.html", + {"data": self, "currency": currency}) @frappe.whitelist() def get_cashiers(doctype, txt, searchfield, start, page_len, filters): @@ -151,7 +149,6 @@ def get_tax_details(invoice_list): return tax_breakup - def get_sales_summary(invoice_list): net_total = sum(item['net_total'] for item in invoice_list) grand_total = sum(item['grand_total'] for item in invoice_list) @@ -163,7 +160,6 @@ def get_company_currency(doc): currency = frappe.db.get_value("Company", doc.company, "default_currency") return frappe.get_doc('Currency', currency) - def get_invoices(filters): return frappe.db.sql("""select a.name, a.base_grand_total as grand_total, a.base_net_total as net_total, a.pos_total_qty diff --git a/erpnext/selling/doctype/pos_closing_voucher/test_pos_closing_voucher.py b/erpnext/selling/doctype/pos_closing_voucher/test_pos_closing_voucher.py index 12ddbc2e58..8899aaff41 100644 --- a/erpnext/selling/doctype/pos_closing_voucher/test_pos_closing_voucher.py +++ b/erpnext/selling/doctype/pos_closing_voucher/test_pos_closing_voucher.py @@ -2,8 +2,82 @@ # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # See license.txt from __future__ import unicode_literals - +import frappe import unittest +from frappe.utils import nowdate +from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice +from erpnext.accounts.doctype.pos_profile.test_pos_profile import make_pos_profile class TestPOSClosingVoucher(unittest.TestCase): - pass + def test_pos_closing_voucher(self): + old_user = frappe.session.user + user = 'test@example.com' + test_user = frappe.get_doc('User', user) + + roles = ("Accounts Manager", "Accounts User", "Sales Manager") + test_user.add_roles(*roles) + frappe.set_user(user) + + pos_profile = make_pos_profile() + pos_profile.append('applicable_for_users', { + 'default': 1, + 'user': user + }) + + pos_profile.save() + + si1 = create_sales_invoice(is_pos=1, rate=3500, do_not_submit=1) + si1.append('payments', { + 'mode_of_payment': 'Cash', 'account': 'Cash - _TC', 'amount': 3500 + }) + si1.submit() + + si2 = create_sales_invoice(is_pos=1, rate=3200, do_not_submit=1) + si2.append('payments', { + 'mode_of_payment': 'Cash', 'account': 'Cash - _TC', 'amount': 3200 + }) + si2.submit() + + pcv_doc = create_pos_closing_voucher(user=user, + pos_profile=pos_profile.name, collected_amount=6700) + + pcv_doc.get_closing_voucher_details() + + self.assertEqual(pcv_doc.total_quantity, 2) + self.assertEqual(pcv_doc.net_total, 6700) + + payment = pcv_doc.payment_reconciliation[0] + self.assertEqual(payment.mode_of_payment, 'Cash') + + si1.load_from_db() + si1.cancel() + + si2.load_from_db() + si2.cancel() + + test_user.load_from_db() + test_user.remove_roles(*roles) + + frappe.set_user(old_user) + frappe.db.sql("delete from `tabPOS Profile`") + +def create_pos_closing_voucher(**args): + args = frappe._dict(args) + + doc = frappe.get_doc({ + 'doctype': 'POS Closing Voucher', + 'period_start_date': args.period_start_date or nowdate(), + 'period_end_date': args.period_end_date or nowdate(), + 'posting_date': args.posting_date or nowdate(), + 'company': args.company or "_Test Company", + 'pos_profile': args.pos_profile, + 'user': args.user or "Administrator", + }) + + doc.get_closing_voucher_details() + if doc.get('payment_reconciliation'): + doc.payment_reconciliation[0].collected_amount = (args.collected_amount or + doc.payment_reconciliation[0].expected_amount) + + doc.save() + return doc \ No newline at end of file