Skip to content

Commit ec92afb

Browse files
Merge pull request #296 from BrainWise-DEV/PN-63-Customization-4-Bank-Deposits-DocType-New-Screen
feat: add bank deposit information to payments and cash control report
2 parents 7f8b3db + b1fff24 commit ec92afb

7 files changed

Lines changed: 470 additions & 4 deletions

File tree

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{
2+
"custom_fields": [
3+
{
4+
"allow_on_submit": 1,
5+
"dt": "POS Closing Shift",
6+
"fieldname": "custom_bank_deposit",
7+
"fieldtype": "Link",
8+
"insert_after": "pos_opening_shift",
9+
"label": "Bank Deposit",
10+
"module": "POS Next",
11+
"name": "POS Closing Shift-custom_bank_deposit",
12+
"no_copy": 1,
13+
"options": "Bank Deposits",
14+
"read_only": 1
15+
}
16+
],
17+
"custom_perms": [],
18+
"doctype": "POS Closing Shift",
19+
"links": [],
20+
"property_setters": [],
21+
"sync_on_migrate": 1
22+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// Copyright (c) 2026, BrainWise and contributors
2+
// For license information, please see license.txt
3+
4+
function set_pos_closing_shift_query(frm) {
5+
frm.set_query("pos_closing_shift", () => ({
6+
query: "pos_next.pos_next.doctype.bank_deposits.bank_deposits.get_pos_closing_shifts",
7+
filters: {
8+
pos_profile: frm.doc.pos_profile,
9+
},
10+
}));
11+
}
12+
13+
frappe.ui.form.on("Bank Deposits", {
14+
onload(frm) {
15+
if (frm.is_new() && !frm.doc.posting_date) {
16+
frm.set_value("posting_date", frappe.datetime.get_today());
17+
}
18+
19+
frm.set_query("pos_profile", () => ({
20+
filters: { disabled: 0 },
21+
}));
22+
23+
set_pos_closing_shift_query(frm);
24+
},
25+
26+
refresh(frm) {
27+
set_pos_closing_shift_query(frm);
28+
},
29+
30+
pos_profile(frm) {
31+
if (frm.doc.pos_closing_shift) {
32+
frm.set_value("pos_closing_shift", "");
33+
}
34+
},
35+
36+
pos_closing_shift(frm) {
37+
if (!frm.doc.pos_closing_shift) return;
38+
39+
frappe.db.get_value(
40+
"POS Closing Shift",
41+
frm.doc.pos_closing_shift,
42+
["pos_profile", "docstatus"],
43+
(r) => {
44+
if (!r) return;
45+
46+
if (r.docstatus !== 1) {
47+
frappe.msgprint({
48+
title: __("Invalid Shift"),
49+
message: __("Only submitted POS Closing Shifts can be selected."),
50+
indicator: "red",
51+
});
52+
frm.set_value("pos_closing_shift", "");
53+
return;
54+
}
55+
56+
if (r.pos_profile && r.pos_profile !== frm.doc.pos_profile) {
57+
frm.set_value("pos_profile", r.pos_profile);
58+
}
59+
},
60+
);
61+
},
62+
});
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
{
2+
"actions": [],
3+
"allow_rename": 0,
4+
"autoname": "BD-.YYYY.-.#####",
5+
"creation": "2026-06-09 10:00:00.000000",
6+
"doctype": "DocType",
7+
"editable_grid": 1,
8+
"engine": "InnoDB",
9+
"field_order": [
10+
"pos_profile",
11+
"posting_date",
12+
"column_break_1",
13+
"pos_closing_shift",
14+
"section_break_amount",
15+
"deposit_amount",
16+
"section_break_attachment",
17+
"bank_transaction_doc",
18+
"section_break_remarks",
19+
"remarks",
20+
"amended_from"
21+
],
22+
"fields": [
23+
{
24+
"fieldname": "pos_profile",
25+
"fieldtype": "Link",
26+
"in_list_view": 1,
27+
"in_standard_filter": 1,
28+
"label": "POS Profile",
29+
"options": "POS Profile",
30+
"reqd": 1
31+
},
32+
{
33+
"default": "Today",
34+
"fieldname": "posting_date",
35+
"fieldtype": "Date",
36+
"in_list_view": 1,
37+
"label": "Posting Date",
38+
"read_only": 1
39+
},
40+
{
41+
"fieldname": "column_break_1",
42+
"fieldtype": "Column Break"
43+
},
44+
{
45+
"fieldname": "pos_closing_shift",
46+
"fieldtype": "Link",
47+
"in_list_view": 1,
48+
"in_standard_filter": 1,
49+
"label": "POS Closing Shift",
50+
"options": "POS Closing Shift",
51+
"reqd": 1
52+
},
53+
{
54+
"fieldname": "section_break_amount",
55+
"fieldtype": "Section Break",
56+
"label": "Deposit Details"
57+
},
58+
{
59+
"fieldname": "deposit_amount",
60+
"fieldtype": "Currency",
61+
"in_list_view": 1,
62+
"label": "Deposit Amount",
63+
"reqd": 1
64+
},
65+
{
66+
"fieldname": "section_break_attachment",
67+
"fieldtype": "Section Break",
68+
"label": "Bank Receipt"
69+
},
70+
{
71+
"fieldname": "bank_transaction_doc",
72+
"fieldtype": "Attach",
73+
"label": "Bank Transaction Document",
74+
"reqd": 1
75+
},
76+
{
77+
"fieldname": "section_break_remarks",
78+
"fieldtype": "Section Break"
79+
},
80+
{
81+
"fieldname": "remarks",
82+
"fieldtype": "Small Text",
83+
"label": "Remarks"
84+
},
85+
{
86+
"fieldname": "amended_from",
87+
"fieldtype": "Link",
88+
"label": "Amended From",
89+
"no_copy": 1,
90+
"options": "Bank Deposits",
91+
"print_hide": 1,
92+
"read_only": 1
93+
}
94+
],
95+
"is_submittable": 1,
96+
"links": [],
97+
"modified": "2026-06-09 10:00:00.000000",
98+
"modified_by": "Administrator",
99+
"module": "POS Next",
100+
"name": "Bank Deposits",
101+
"naming_rule": "Expression",
102+
"owner": "Administrator",
103+
"permissions": [
104+
{
105+
"amend": 1,
106+
"cancel": 1,
107+
"create": 1,
108+
"delete": 1,
109+
"email": 1,
110+
"export": 1,
111+
"print": 1,
112+
"read": 1,
113+
"report": 1,
114+
"role": "System Manager",
115+
"share": 1,
116+
"submit": 1,
117+
"write": 1
118+
},
119+
{
120+
"amend": 1,
121+
"cancel": 1,
122+
"create": 1,
123+
"email": 1,
124+
"export": 1,
125+
"print": 1,
126+
"read": 1,
127+
"report": 1,
128+
"role": "Nexus POS Manager",
129+
"share": 1,
130+
"submit": 1,
131+
"write": 1
132+
},
133+
{
134+
"amend": 1,
135+
"cancel": 1,
136+
"create": 1,
137+
"export": 1,
138+
"print": 1,
139+
"read": 1,
140+
"report": 1,
141+
"role": "POSNext Cashier",
142+
"submit": 1,
143+
"write": 1
144+
},
145+
{
146+
"amend": 1,
147+
"cancel": 1,
148+
"create": 1,
149+
"delete": 1,
150+
"email": 1,
151+
"export": 1,
152+
"print": 1,
153+
"read": 1,
154+
"report": 1,
155+
"role": "Administrator",
156+
"share": 1,
157+
"submit": 1,
158+
"write": 1
159+
}
160+
],
161+
"sort_field": "modified",
162+
"sort_order": "DESC",
163+
"states": [],
164+
"track_changes": 1
165+
}
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
# Copyright (c) 2026, BrainWise and contributors
2+
# For license information, please see license.txt
3+
4+
import frappe
5+
from frappe import _
6+
from frappe.model.document import Document
7+
from frappe.utils import flt, today
8+
9+
10+
class BankDeposits(Document):
11+
def validate(self):
12+
if not self.posting_date:
13+
self.posting_date = today()
14+
15+
self.validate_pos_profile()
16+
self.validate_pos_closing_shift()
17+
self.validate_deposit_amount()
18+
self.validate_bank_receipt()
19+
20+
def validate_pos_profile(self):
21+
if frappe.db.get_value("POS Profile", self.pos_profile, "disabled"):
22+
frappe.throw(
23+
_("POS Profile {0} is not active").format(frappe.bold(self.pos_profile)),
24+
title=_("Invalid POS Profile"),
25+
)
26+
27+
def validate_pos_closing_shift(self):
28+
shift = frappe.db.get_value(
29+
"POS Closing Shift",
30+
self.pos_closing_shift,
31+
["docstatus", "pos_profile", "pos_opening_shift"],
32+
as_dict=True,
33+
)
34+
if not shift:
35+
frappe.throw(_("POS Closing Shift {0} does not exist").format(self.pos_closing_shift))
36+
37+
if shift.docstatus != 1:
38+
frappe.throw(_("POS Closing Shift must be submitted"))
39+
40+
opening_status = frappe.db.get_value("POS Opening Shift", shift.pos_opening_shift, "status")
41+
if opening_status != "Closed":
42+
frappe.throw(_("POS Closing Shift must be closed"))
43+
44+
if shift.pos_profile != self.pos_profile:
45+
frappe.throw(_("POS Closing Shift does not belong to the selected POS Profile"))
46+
47+
existing = frappe.db.exists(
48+
"Bank Deposits",
49+
{
50+
"pos_closing_shift": self.pos_closing_shift,
51+
"name": ["!=", self.name],
52+
"docstatus": ["!=", 2],
53+
},
54+
)
55+
if existing:
56+
frappe.throw(
57+
_("Bank Deposit {0} already exists for this shift").format(frappe.bold(existing)),
58+
title=_("Duplicate Bank Deposit"),
59+
)
60+
61+
def validate_deposit_amount(self):
62+
if flt(self.deposit_amount) <= 0:
63+
frappe.throw(_("Deposit Amount must be greater than zero"))
64+
65+
def validate_bank_receipt(self):
66+
if not self.bank_transaction_doc:
67+
frappe.throw(_("Bank Transaction Document is required"))
68+
69+
def on_submit(self):
70+
frappe.db.set_value(
71+
"POS Closing Shift",
72+
self.pos_closing_shift,
73+
"custom_bank_deposit",
74+
self.name,
75+
update_modified=False,
76+
)
77+
78+
def on_cancel(self):
79+
frappe.db.set_value(
80+
"POS Closing Shift",
81+
self.pos_closing_shift,
82+
"custom_bank_deposit",
83+
None,
84+
update_modified=False,
85+
)
86+
87+
88+
@frappe.whitelist()
89+
@frappe.validate_and_sanitize_search_inputs
90+
def get_pos_closing_shifts(doctype, txt, searchfield, start, page_len, filters):
91+
"""Return submitted, closed POS Closing Shifts without an existing Bank Deposit."""
92+
filters = filters or {}
93+
pos_profile = filters.get("pos_profile")
94+
profile_condition = "AND pcs.pos_profile = %(pos_profile)s" if pos_profile else ""
95+
96+
return frappe.db.sql(
97+
f"""
98+
SELECT pcs.name
99+
FROM `tabPOS Closing Shift` pcs
100+
INNER JOIN `tabPOS Opening Shift` pos ON pos.name = pcs.pos_opening_shift
101+
WHERE pcs.docstatus = 1
102+
AND pos.status = 'Closed'
103+
AND pcs.name NOT IN (
104+
SELECT bd.pos_closing_shift
105+
FROM `tabBank Deposits` bd
106+
WHERE bd.docstatus = 1
107+
AND bd.pos_closing_shift IS NOT NULL
108+
)
109+
{profile_condition}
110+
AND pcs.name LIKE %(txt)s
111+
ORDER BY pcs.period_end_date DESC
112+
LIMIT %(page_len)s OFFSET %(start)s
113+
""",
114+
{
115+
"txt": f"%{txt}%",
116+
"start": start,
117+
"page_len": page_len,
118+
"pos_profile": pos_profile,
119+
},
120+
)
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Copyright (c) 2026, BrainWise and contributors
2+
# For license information, please see license.txt
3+
4+
from frappe.tests import IntegrationTestCase
5+
6+
7+
class TestBankDeposits(IntegrationTestCase):
8+
pass

0 commit comments

Comments
 (0)