Merge pull request #36492 from RitvikSardana/develop-ritvik-POS-runtime-effect

fix: POS runtime effect
This commit is contained in:
Deepesh Garg 2023-08-17 10:54:48 +05:30 committed by GitHub
commit 98adfb4c9a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 63 additions and 9 deletions

View File

@ -185,6 +185,7 @@ function refresh_payments(d, frm) {
} }
if (payment) { if (payment) {
payment.expected_amount += flt(p.amount); payment.expected_amount += flt(p.amount);
payment.closing_amount = payment.expected_amount;
payment.difference = payment.closing_amount - payment.expected_amount; payment.difference = payment.closing_amount - payment.expected_amount;
} else { } else {
frm.add_child("payment_reconciliation", { frm.add_child("payment_reconciliation", {

View File

@ -221,6 +221,7 @@
"read_only": 1 "read_only": 1
}, },
{ {
"default": "Now",
"fieldname": "posting_time", "fieldname": "posting_time",
"fieldtype": "Time", "fieldtype": "Time",
"label": "Posting Time", "label": "Posting Time",
@ -235,7 +236,7 @@
"link_fieldname": "pos_closing_entry" "link_fieldname": "pos_closing_entry"
} }
], ],
"modified": "2022-08-01 11:37:14.991228", "modified": "2023-08-10 16:25:49.322697",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "POS Closing Entry", "name": "POS Closing Entry",

View File

@ -8,9 +8,11 @@ import frappe
from erpnext.accounts.doctype.pos_closing_entry.pos_closing_entry import ( from erpnext.accounts.doctype.pos_closing_entry.pos_closing_entry import (
make_closing_entry_from_opening, make_closing_entry_from_opening,
) )
from erpnext.accounts.doctype.pos_invoice.pos_invoice import make_sales_return
from erpnext.accounts.doctype.pos_invoice.test_pos_invoice import create_pos_invoice from erpnext.accounts.doctype.pos_invoice.test_pos_invoice import create_pos_invoice
from erpnext.accounts.doctype.pos_opening_entry.test_pos_opening_entry import create_opening_entry from erpnext.accounts.doctype.pos_opening_entry.test_pos_opening_entry import create_opening_entry
from erpnext.accounts.doctype.pos_profile.test_pos_profile import make_pos_profile from erpnext.accounts.doctype.pos_profile.test_pos_profile import make_pos_profile
from erpnext.selling.page.point_of_sale.point_of_sale import get_items
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
@ -67,6 +69,36 @@ class TestPOSClosingEntry(unittest.TestCase):
self.assertTrue(pcv_doc.name) self.assertTrue(pcv_doc.name)
def test_pos_qty_for_item(self):
"""
Test if quantity is calculated correctly for an item in POS Closing Entry
"""
test_user, pos_profile = init_user_and_profile()
opening_entry = create_opening_entry(pos_profile, test_user.name)
test_item_qty = get_test_item_qty(pos_profile)
pos_inv1 = create_pos_invoice(rate=3500, do_not_submit=1)
pos_inv1.append("payments", {"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 3500})
pos_inv1.submit()
pos_inv2 = create_pos_invoice(rate=3200, do_not_submit=1)
pos_inv2.append("payments", {"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 3200})
pos_inv2.submit()
# make return entry of pos_inv2
pos_return = make_sales_return(pos_inv2.name)
pos_return.paid_amount = pos_return.grand_total
pos_return.save()
pos_return.submit()
pcv_doc = make_closing_entry_from_opening(opening_entry)
pcv_doc.submit()
opening_entry = create_opening_entry(pos_profile, test_user.name)
test_item_qty_after_sales = get_test_item_qty(pos_profile)
self.assertEqual(test_item_qty_after_sales, test_item_qty - 1)
def test_cancelling_of_pos_closing_entry(self): def test_cancelling_of_pos_closing_entry(self):
test_user, pos_profile = init_user_and_profile() test_user, pos_profile = init_user_and_profile()
opening_entry = create_opening_entry(pos_profile, test_user.name) opening_entry = create_opening_entry(pos_profile, test_user.name)
@ -123,3 +155,19 @@ def init_user_and_profile(**args):
pos_profile.save() pos_profile.save()
return test_user, pos_profile return test_user, pos_profile
def get_test_item_qty(pos_profile):
test_item_pos = get_items(
start=0,
page_length=5,
price_list="Standard Selling",
pos_profile=pos_profile.name,
search_term="_Test Item",
item_group="All Item Groups",
)
test_item_qty = [item for item in test_item_pos["items"] if item["item_code"] == "_Test Item"][
0
].get("actual_qty")
return test_item_qty

View File

@ -542,6 +542,7 @@ def get_stock_availability(item_code, warehouse):
is_stock_item = True is_stock_item = True
bin_qty = get_bin_qty(item_code, warehouse) bin_qty = get_bin_qty(item_code, warehouse)
pos_sales_qty = get_pos_reserved_qty(item_code, warehouse) pos_sales_qty = get_pos_reserved_qty(item_code, warehouse)
return bin_qty - pos_sales_qty, is_stock_item return bin_qty - pos_sales_qty, is_stock_item
else: else:
is_stock_item = True is_stock_item = True
@ -595,7 +596,6 @@ def get_pos_reserved_qty(item_code, warehouse):
.where( .where(
(p_inv.name == p_item.parent) (p_inv.name == p_item.parent)
& (IfNull(p_inv.consolidated_invoice, "") == "") & (IfNull(p_inv.consolidated_invoice, "") == "")
& (p_inv.is_return == 0)
& (p_item.docstatus == 1) & (p_item.docstatus == 1)
& (p_item.item_code == item_code) & (p_item.item_code == item_code)
& (p_item.warehouse == warehouse) & (p_item.warehouse == warehouse)

View File

@ -95,7 +95,6 @@ class POSInvoiceMergeLog(Document):
sales_invoice = self.process_merging_into_sales_invoice(sales) sales_invoice = self.process_merging_into_sales_invoice(sales)
self.save() # save consolidated_sales_invoice & consolidated_credit_note ref in merge log self.save() # save consolidated_sales_invoice & consolidated_credit_note ref in merge log
self.update_pos_invoices(pos_invoice_docs, sales_invoice, credit_note) self.update_pos_invoices(pos_invoice_docs, sales_invoice, credit_note)
def on_cancel(self): def on_cancel(self):
@ -108,7 +107,6 @@ class POSInvoiceMergeLog(Document):
def process_merging_into_sales_invoice(self, data): def process_merging_into_sales_invoice(self, data):
sales_invoice = self.get_new_sales_invoice() sales_invoice = self.get_new_sales_invoice()
sales_invoice = self.merge_pos_invoice_into(sales_invoice, data) sales_invoice = self.merge_pos_invoice_into(sales_invoice, data)
sales_invoice.is_consolidated = 1 sales_invoice.is_consolidated = 1
@ -165,8 +163,7 @@ class POSInvoiceMergeLog(Document):
for i in items: for i in items:
if ( if (
i.item_code == item.item_code i.item_code == item.item_code
and not i.serial_no and not i.serial_and_batch_bundle
and not i.batch_no
and i.uom == item.uom and i.uom == item.uom
and i.net_rate == item.net_rate and i.net_rate == item.net_rate
and i.warehouse == item.warehouse and i.warehouse == item.warehouse
@ -385,6 +382,7 @@ def split_invoices(invoices):
for d in invoices for d in invoices
if d.is_return and d.return_against if d.is_return and d.return_against
] ]
for pos_invoice in pos_return_docs: for pos_invoice in pos_return_docs:
for item in pos_invoice.items: for item in pos_invoice.items:
if not item.serial_no and not item.serial_and_batch_bundle: if not item.serial_no and not item.serial_and_batch_bundle:

View File

@ -225,6 +225,7 @@ erpnext.PointOfSale.Controller = class {
voucher.pos_opening_entry = this.pos_opening; voucher.pos_opening_entry = this.pos_opening;
voucher.period_end_date = frappe.datetime.now_datetime(); voucher.period_end_date = frappe.datetime.now_datetime();
voucher.posting_date = frappe.datetime.now_date(); voucher.posting_date = frappe.datetime.now_date();
voucher.posting_time = frappe.datetime.now_time();
frappe.set_route('Form', 'POS Closing Entry', voucher.name); frappe.set_route('Form', 'POS Closing Entry', voucher.name);
} }

View File

@ -3,7 +3,7 @@
import collections import collections
import csv import csv
from collections import defaultdict from collections import Counter, defaultdict
from typing import Dict, List from typing import Dict, List
import frappe import frappe
@ -1197,6 +1197,7 @@ def get_reserved_serial_nos_for_pos(kwargs):
filters=[ filters=[
["POS Invoice", "consolidated_invoice", "is", "not set"], ["POS Invoice", "consolidated_invoice", "is", "not set"],
["POS Invoice", "docstatus", "=", 1], ["POS Invoice", "docstatus", "=", 1],
["POS Invoice", "is_return", "=", 0],
["POS Invoice Item", "item_code", "=", kwargs.item_code], ["POS Invoice Item", "item_code", "=", kwargs.item_code],
["POS Invoice", "name", "!=", kwargs.ignore_voucher_no], ["POS Invoice", "name", "!=", kwargs.ignore_voucher_no],
], ],
@ -1214,7 +1215,6 @@ def get_reserved_serial_nos_for_pos(kwargs):
for d in get_serial_batch_ledgers(kwargs.item_code, docstatus=1, name=ids): for d in get_serial_batch_ledgers(kwargs.item_code, docstatus=1, name=ids):
ignore_serial_nos.append(d.serial_no) ignore_serial_nos.append(d.serial_no)
# Will be deprecated in v16
returned_serial_nos = [] returned_serial_nos = []
for pos_invoice in pos_invoices: for pos_invoice in pos_invoices:
if pos_invoice.serial_no: if pos_invoice.serial_no:
@ -1242,8 +1242,13 @@ def get_reserved_serial_nos_for_pos(kwargs):
child_doc, parent_doc, ignore_voucher_detail_no=kwargs.get("ignore_voucher_detail_no") child_doc, parent_doc, ignore_voucher_detail_no=kwargs.get("ignore_voucher_detail_no")
) )
) )
# Counter is used to create a hashmap of serial nos, which contains count of each serial no
# so we subtract returned serial nos from ignore serial nos after creating a counter of each to get the items which we need to ignore(which are sold)
return list(set(ignore_serial_nos) - set(returned_serial_nos)) ignore_serial_nos_counter = Counter(ignore_serial_nos)
returned_serial_nos_counter = Counter(returned_serial_nos)
return list(ignore_serial_nos_counter - returned_serial_nos_counter)
def get_reserved_batches_for_pos(kwargs): def get_reserved_batches_for_pos(kwargs):