Skip to content

Commit f3a5afc

Browse files
authored
Merge pull request #53915 from frappe/version-16-hotfix
2 parents 372fc96 + 8cb8f66 commit f3a5afc

114 files changed

Lines changed: 2944 additions & 2184 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/linters.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,6 @@ jobs:
4343

4444
- name: Run Semgrep rules
4545
run: semgrep ci --config ./frappe-semgrep-rules/rules --config r/python.lang.correctness
46+
47+
- name: Semgrep for Test Correctness
48+
run: semgrep ci --include=**/test_*.py --config ./semgrep/test-correctness.yml

erpnext/accounts/doctype/accounting_dimension/test_accounting_dimension.py

Lines changed: 0 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,6 @@
1010

1111

1212
class TestAccountingDimension(ERPNextTestSuite):
13-
def setUp(self):
14-
create_dimension()
15-
1613
def test_dimension_against_sales_invoice(self):
1714
si = create_sales_invoice(do_not_save=1)
1815

@@ -77,63 +74,3 @@ def test_mandatory(self):
7774

7875
si.save()
7976
self.assertRaises(frappe.ValidationError, si.submit)
80-
81-
82-
def create_dimension():
83-
frappe.set_user("Administrator")
84-
85-
if not frappe.db.exists("Accounting Dimension", {"document_type": "Department"}):
86-
dimension = frappe.get_doc(
87-
{
88-
"doctype": "Accounting Dimension",
89-
"document_type": "Department",
90-
}
91-
)
92-
dimension.append(
93-
"dimension_defaults",
94-
{
95-
"company": "_Test Company",
96-
"reference_document": "Department",
97-
"default_dimension": "_Test Department - _TC",
98-
},
99-
)
100-
dimension.insert()
101-
dimension.save()
102-
else:
103-
dimension = frappe.get_doc("Accounting Dimension", "Department")
104-
dimension.disabled = 0
105-
dimension.save()
106-
107-
if not frappe.db.exists("Accounting Dimension", {"document_type": "Location"}):
108-
dimension1 = frappe.get_doc(
109-
{
110-
"doctype": "Accounting Dimension",
111-
"document_type": "Location",
112-
}
113-
)
114-
115-
dimension1.append(
116-
"dimension_defaults",
117-
{
118-
"company": "_Test Company",
119-
"reference_document": "Location",
120-
"default_dimension": "Block 1",
121-
},
122-
)
123-
124-
dimension1.insert()
125-
dimension1.save()
126-
else:
127-
dimension1 = frappe.get_doc("Accounting Dimension", "Location")
128-
dimension1.disabled = 0
129-
dimension1.save()
130-
131-
132-
def disable_dimension():
133-
dimension1 = frappe.get_doc("Accounting Dimension", "Department")
134-
dimension1.disabled = 1
135-
dimension1.save()
136-
137-
dimension2 = frappe.get_doc("Accounting Dimension", "Location")
138-
dimension2.disabled = 1
139-
dimension2.save()

erpnext/accounts/doctype/accounting_dimension_filter/test_accounting_dimension_filter.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,13 @@
55

66
import frappe
77

8-
from erpnext.accounts.doctype.accounting_dimension.test_accounting_dimension import (
9-
create_dimension,
10-
disable_dimension,
11-
)
128
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
139
from erpnext.exceptions import InvalidAccountDimensionError, MandatoryAccountDimensionError
1410
from erpnext.tests.utils import ERPNextTestSuite
1511

1612

1713
class TestAccountingDimensionFilter(ERPNextTestSuite):
1814
def setUp(self):
19-
create_dimension()
2015
create_accounting_dimension_filter()
2116
self.invoice_list = []
2217

erpnext/accounts/doctype/bank_account/bank_account.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ def get_default_company_bank_account(company, party_type, party):
116116

117117
@frappe.whitelist()
118118
def get_bank_account_details(bank_account):
119+
frappe.has_permission("Bank Account", doc=bank_account, ptype="read", throw=True)
119120
return frappe.get_cached_value(
120121
"Bank Account", bank_account, ["account", "bank", "bank_account_no"], as_dict=1
121122
)

erpnext/accounts/doctype/gl_entry/gl_entry.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -489,4 +489,5 @@ def rename_temporarily_named_docs(doctype):
489489
for hook in frappe.get_hooks(hook_type):
490490
frappe.call(hook, newname=newname, oldname=oldname)
491491

492-
frappe.db.commit()
492+
if not frappe.in_test:
493+
frappe.db.commit()

erpnext/accounts/doctype/ledger_merge/ledger_merge.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,14 +71,16 @@ def start_merge(docname):
7171
ledger_merge.account,
7272
)
7373
row.db_set("merged", 1)
74-
frappe.db.commit()
74+
if not frappe.in_test:
75+
frappe.db.commit()
7576
successful_merges += 1
7677
frappe.publish_realtime(
7778
"ledger_merge_progress",
7879
{"ledger_merge": ledger_merge.name, "current": successful_merges, "total": total},
7980
)
8081
except Exception:
81-
frappe.db.rollback()
82+
if not frappe.in_test:
83+
frappe.db.rollback()
8284
ledger_merge.log_error("Ledger merge failed")
8385
finally:
8486
if successful_merges == total:

erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.js

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ frappe.ui.form.on("Opening Invoice Creation Tool", {
5050

5151
refresh: function (frm) {
5252
frm.disable_save();
53+
frm.trigger("create_missing_party");
5354
!frm.doc.import_in_progress && frm.trigger("make_dashboard");
5455
frm.page.set_primary_action(__("Create Invoices"), () => {
5556
let btn_primary = frm.page.btn_primary.get(0);
@@ -123,7 +124,8 @@ frappe.ui.form.on("Opening Invoice Creation Tool", {
123124
invoice_type: function (frm) {
124125
$.each(frm.doc.invoices, (idx, row) => {
125126
row.party_type = frm.doc.invoice_type == "Sales" ? "Customer" : "Supplier";
126-
row.party = "";
127+
frappe.model.set_value(row.doctype, row.name, "party", "");
128+
frappe.model.set_value(row.doctype, row.name, "party_name", "");
127129
});
128130
frm.refresh_fields();
129131
},
@@ -162,9 +164,35 @@ frappe.ui.form.on("Opening Invoice Creation Tool", {
162164
row.party_type = frm.doc.invoice_type == "Sales" ? "Customer" : "Supplier";
163165
});
164166
},
167+
168+
create_missing_party: function (frm) {
169+
if (frm.doc.create_missing_party) {
170+
frm.fields_dict["invoices"].grid.update_docfield_property("party", "reqd", 0);
171+
frm.fields_dict["invoices"].grid.update_docfield_property("party_name", "read_only", 0);
172+
} else {
173+
frm.fields_dict["invoices"].grid.update_docfield_property("party", "reqd", 1);
174+
frm.fields_dict["invoices"].grid.update_docfield_property("party_name", "read_only", 1);
175+
}
176+
frm.refresh_field("invoices");
177+
},
165178
});
166179

167180
frappe.ui.form.on("Opening Invoice Creation Tool Item", {
181+
party: function (frm, cdt, cdn) {
182+
let row = locals[cdt][cdn];
183+
if (!row.party) {
184+
frappe.model.set_value(cdt, cdn, "party_name", "");
185+
return;
186+
}
187+
188+
let party_type = frm.doc.invoice_type == "Sales" ? "Customer" : "Supplier";
189+
let name_field = party_type === "Customer" ? "customer_name" : "supplier_name";
190+
191+
frappe.db.get_value(party_type, row.party, name_field, (r) => {
192+
frappe.model.set_value(cdt, cdn, "party_name", r?.[name_field] || "");
193+
});
194+
},
195+
168196
invoices_add: (frm) => {
169197
frm.trigger("update_invoice_table");
170198
},

erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.json

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@
88
"engine": "InnoDB",
99
"field_order": [
1010
"company",
11-
"create_missing_party",
1211
"column_break_3",
1312
"invoice_type",
13+
"create_missing_party",
1414
"accounting_dimensions_section",
1515
"cost_center",
1616
"dimension_col_break",
@@ -29,7 +29,7 @@
2929
},
3030
{
3131
"default": "0",
32-
"description": "Create missing customer or supplier.",
32+
"description": "If party does not exist, create it using the Party Name field.",
3333
"fieldname": "create_missing_party",
3434
"fieldtype": "Check",
3535
"label": "Create Missing Party"
@@ -65,10 +65,10 @@
6565
"options": "Cost Center"
6666
},
6767
{
68-
"fieldname": "project",
69-
"fieldtype": "Link",
70-
"label": "Project",
71-
"options": "Project"
68+
"fieldname": "project",
69+
"fieldtype": "Link",
70+
"label": "Project",
71+
"options": "Project"
7272
},
7373
{
7474
"collapsible": 1,
@@ -84,7 +84,7 @@
8484
"hide_toolbar": 1,
8585
"issingle": 1,
8686
"links": [],
87-
"modified": "2024-03-27 13:10:06.564397",
87+
"modified": "2026-03-23 00:32:15.600086",
8888
"modified_by": "Administrator",
8989
"module": "Accounts",
9090
"name": "Opening Invoice Creation Tool",
@@ -101,8 +101,9 @@
101101
}
102102
],
103103
"quick_entry": 1,
104+
"row_format": "Dynamic",
104105
"sort_field": "creation",
105106
"sort_order": "DESC",
106107
"states": [],
107108
"track_changes": 1
108-
}
109+
}

erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import frappe
66
from frappe import _, scrub
77
from frappe.model.document import Document
8-
from frappe.utils import flt, nowdate
8+
from frappe.utils import escape_html, flt, nowdate
99
from frappe.utils.background_jobs import enqueue, is_job_enqueued
1010

1111
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import (
@@ -32,6 +32,7 @@ class OpeningInvoiceCreationTool(Document):
3232
create_missing_party: DF.Check
3333
invoice_type: DF.Literal["Sales", "Purchase"]
3434
invoices: DF.Table[OpeningInvoiceCreationToolItem]
35+
project: DF.Link | None
3536
# end: auto-generated types
3637

3738
def onload(self):
@@ -85,6 +86,11 @@ def prepare_invoice_summary(doctype, invoices):
8586
)
8687
prepare_invoice_summary(doctype, invoices)
8788

89+
invoices_summary_companies = list(invoices_summary.keys())
90+
91+
for company in invoices_summary_companies:
92+
invoices_summary[escape_html(company)] = invoices_summary.pop(company)
93+
8894
return invoices_summary, max_count
8995

9096
def validate_company(self):
@@ -102,18 +108,28 @@ def set_missing_values(self, row):
102108
row.due_date = row.due_date or nowdate()
103109

104110
def validate_mandatory_invoice_fields(self, row):
105-
if not frappe.db.exists(row.party_type, row.party):
106-
if self.create_missing_party:
107-
self.add_party(row.party_type, row.party)
108-
else:
111+
if self.create_missing_party:
112+
if not row.party and not row.party_name:
113+
frappe.throw(_("Row #{}: Either Party ID or Party Name is required").format(row.idx))
114+
115+
if not row.party and row.party_name:
116+
row.party = self.add_party(row.party_type, row.party_name)
117+
118+
if row.party and not frappe.db.exists(row.party_type, row.party):
119+
row.party = self.add_party(row.party_type, row.party)
120+
121+
else:
122+
if not row.party:
123+
frappe.throw(_("Row #{}: Party ID is required").format(row.idx))
124+
if not frappe.db.exists(row.party_type, row.party):
109125
frappe.throw(
110126
_("Row #{}: {} {} does not exist.").format(
111127
row.idx, frappe.bold(row.party_type), frappe.bold(row.party)
112128
)
113129
)
114130

115131
mandatory_error_msg = _("Row #{0}: {1} is required to create the Opening {2} Invoices")
116-
for d in ("Party", "Outstanding Amount", "Temporary Opening Account"):
132+
for d in ("Outstanding Amount", "Temporary Opening Account"):
117133
if not row.get(scrub(d)):
118134
frappe.throw(mandatory_error_msg.format(row.idx, d, self.invoice_type))
119135

@@ -159,6 +175,7 @@ def add_party(self, party_type, party):
159175

160176
party_doc.flags.ignore_mandatory = True
161177
party_doc.save(ignore_permissions=True)
178+
return party_doc.name
162179

163180
def get_invoice_dict(self, row=None):
164181
def get_item_dict():
@@ -262,7 +279,8 @@ def start_import(invoices):
262279
doc.flags.ignore_mandatory = True
263280
doc.insert(set_name=invoice_number)
264281
doc.submit()
265-
frappe.db.commit()
282+
if not frappe.in_test:
283+
frappe.db.commit()
266284
names.append(doc.name)
267285
except Exception:
268286
errors += 1

erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool_dashboard.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{% $.each(data, (company, summary) => { %}
2-
<h6 style="margin: 15px 0px -10px 0px;"><a class="company-link"> {{ company }}</a></h6>
2+
<div style="margin: 15px 0px -10px 0px;"> {{ company }}</div>
33

44
<table class="table table-bordered small">
55
<thead>
@@ -23,7 +23,7 @@ <h6 style="margin: 15px 0px -10px 0px;"><a class="company-link"> {{ company }}</
2323
<td class="text-right">
2424
{{ format_currency(summary[doctype].outstanding_amount, summary.currency, 2) }}
2525
</td>
26-
</div>
26+
</tr>
2727
{% endif %}
2828
{% }); %}
2929
</tbody>

0 commit comments

Comments
 (0)