mirror of
https://github.com/frappe/erpnext.git
synced 2026-06-06 13:49:13 +00:00
Merge pull request #34610 from frappe/version-13-hotfix
chore: release v13
This commit is contained in:
2
.github/workflows/patch.yml
vendored
2
.github/workflows/patch.yml
vendored
@@ -14,7 +14,7 @@ concurrency:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
runs-on: ubuntu-18.04
|
runs-on: ubuntu-20.04
|
||||||
timeout-minutes: 60
|
timeout-minutes: 60
|
||||||
|
|
||||||
name: Patch Test
|
name: Patch Test
|
||||||
|
|||||||
2
.github/workflows/server-tests.yml
vendored
2
.github/workflows/server-tests.yml
vendored
@@ -18,7 +18,7 @@ concurrency:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
runs-on: ubuntu-18.04
|
runs-on: ubuntu-20.04
|
||||||
timeout-minutes: 60
|
timeout-minutes: 60
|
||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
|
|||||||
2
.github/workflows/translation_linter.yml
vendored
2
.github/workflows/translation_linter.yml
vendored
@@ -8,7 +8,7 @@ on:
|
|||||||
jobs:
|
jobs:
|
||||||
check_translation:
|
check_translation:
|
||||||
name: Translation Syntax Check
|
name: Translation Syntax Check
|
||||||
runs-on: ubuntu-18.04
|
runs-on: ubuntu-20.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- name: Setup python3
|
- name: Setup python3
|
||||||
|
|||||||
@@ -58,9 +58,8 @@ frappe.query_reports["General Ledger"] = {
|
|||||||
{
|
{
|
||||||
"fieldname":"party_type",
|
"fieldname":"party_type",
|
||||||
"label": __("Party Type"),
|
"label": __("Party Type"),
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Autocomplete",
|
||||||
"options": "Party Type",
|
options: Object.keys(frappe.boot.party_account_types),
|
||||||
"default": "",
|
|
||||||
on_change: function() {
|
on_change: function() {
|
||||||
frappe.query_report.set_filter_value('party', "");
|
frappe.query_report.set_filter_value('party', "");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ frappe.ui.form.on("Supplier", {
|
|||||||
// custom buttons
|
// custom buttons
|
||||||
frm.add_custom_button(__('Accounting Ledger'), function () {
|
frm.add_custom_button(__('Accounting Ledger'), function () {
|
||||||
frappe.set_route('query-report', 'General Ledger',
|
frappe.set_route('query-report', 'General Ledger',
|
||||||
{ party_type: 'Supplier', party: frm.doc.name });
|
{ party_type: 'Supplier', party: frm.doc.name, party_name: frm.doc.supplier_name });
|
||||||
}, __("View"));
|
}, __("View"));
|
||||||
|
|
||||||
frm.add_custom_button(__('Accounts Payable'), function () {
|
frm.add_custom_button(__('Accounts Payable'), function () {
|
||||||
|
|||||||
@@ -128,18 +128,9 @@ class Supplier(TransactionBase):
|
|||||||
|
|
||||||
def on_trash(self):
|
def on_trash(self):
|
||||||
if self.supplier_primary_contact:
|
if self.supplier_primary_contact:
|
||||||
frappe.db.sql(
|
self.db_set("supplier_primary_contact", None)
|
||||||
"""
|
if self.supplier_primary_address:
|
||||||
UPDATE `tabSupplier`
|
self.db_set("supplier_primary_address", None)
|
||||||
SET
|
|
||||||
supplier_primary_contact=null,
|
|
||||||
supplier_primary_address=null,
|
|
||||||
mobile_no=null,
|
|
||||||
email_id=null,
|
|
||||||
primary_address=null
|
|
||||||
WHERE name=%(name)s""",
|
|
||||||
{"name": self.name},
|
|
||||||
)
|
|
||||||
|
|
||||||
delete_contact_and_address("Supplier", self.name)
|
delete_contact_and_address("Supplier", self.name)
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
|
from frappe.custom.doctype.property_setter.property_setter import make_property_setter
|
||||||
from frappe.test_runner import make_test_records
|
from frappe.test_runner import make_test_records
|
||||||
from frappe.tests.utils import FrappeTestCase
|
from frappe.tests.utils import FrappeTestCase
|
||||||
|
|
||||||
@@ -151,6 +152,44 @@ class TestSupplier(FrappeTestCase):
|
|||||||
# Rollback
|
# Rollback
|
||||||
address.delete()
|
address.delete()
|
||||||
|
|
||||||
|
def test_serach_fields_for_supplier(self):
|
||||||
|
from erpnext.controllers.queries import supplier_query
|
||||||
|
|
||||||
|
frappe.db.set_value("Buying Settings", None, "supp_master_name", "Naming Series")
|
||||||
|
|
||||||
|
supplier_name = create_supplier(supplier_name="Test Supplier 1").name
|
||||||
|
|
||||||
|
make_property_setter(
|
||||||
|
"Supplier", None, "search_fields", "supplier_group", "Data", for_doctype="Doctype"
|
||||||
|
)
|
||||||
|
|
||||||
|
data = supplier_query(
|
||||||
|
"Supplier", supplier_name, "name", 0, 20, filters={"name": supplier_name}, as_dict=True
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(data[0].name, supplier_name)
|
||||||
|
self.assertEqual(data[0].supplier_group, "Services")
|
||||||
|
self.assertTrue("supplier_type" not in data[0])
|
||||||
|
|
||||||
|
make_property_setter(
|
||||||
|
"Supplier",
|
||||||
|
None,
|
||||||
|
"search_fields",
|
||||||
|
"supplier_group, supplier_type",
|
||||||
|
"Data",
|
||||||
|
for_doctype="Doctype",
|
||||||
|
)
|
||||||
|
data = supplier_query(
|
||||||
|
"Supplier", supplier_name, "name", 0, 20, filters={"name": supplier_name}, as_dict=True
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(data[0].name, supplier_name)
|
||||||
|
self.assertEqual(data[0].supplier_group, "Services")
|
||||||
|
self.assertEqual(data[0].supplier_type, "Company")
|
||||||
|
self.assertTrue("supplier_type" in data[0])
|
||||||
|
|
||||||
|
frappe.db.set_value("Buying Settings", None, "supp_master_name", "Supplier Name")
|
||||||
|
|
||||||
|
|
||||||
def create_supplier(**args):
|
def create_supplier(**args):
|
||||||
args = frappe._dict(args)
|
args = frappe._dict(args)
|
||||||
|
|||||||
@@ -78,18 +78,16 @@ def lead_query(doctype, txt, searchfield, start, page_len, filters):
|
|||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
@frappe.validate_and_sanitize_search_inputs
|
@frappe.validate_and_sanitize_search_inputs
|
||||||
def customer_query(doctype, txt, searchfield, start, page_len, filters):
|
def customer_query(doctype, txt, searchfield, start, page_len, filters, as_dict=False):
|
||||||
doctype = "Customer"
|
doctype = "Customer"
|
||||||
conditions = []
|
conditions = []
|
||||||
cust_master_name = frappe.defaults.get_user_default("cust_master_name")
|
cust_master_name = frappe.defaults.get_user_default("cust_master_name")
|
||||||
|
|
||||||
if cust_master_name == "Customer Name":
|
fields = ["name"]
|
||||||
fields = ["name", "customer_group", "territory"]
|
if cust_master_name != "Customer Name":
|
||||||
else:
|
fields.append("customer_name")
|
||||||
fields = ["name", "customer_name", "customer_group", "territory"]
|
|
||||||
|
|
||||||
fields = get_fields(doctype, fields)
|
fields = get_fields(doctype, fields)
|
||||||
|
|
||||||
searchfields = frappe.get_meta(doctype).get_search_fields()
|
searchfields = frappe.get_meta(doctype).get_search_fields()
|
||||||
searchfields = " or ".join(field + " like %(txt)s" for field in searchfields)
|
searchfields = " or ".join(field + " like %(txt)s" for field in searchfields)
|
||||||
|
|
||||||
@@ -112,20 +110,20 @@ def customer_query(doctype, txt, searchfield, start, page_len, filters):
|
|||||||
}
|
}
|
||||||
),
|
),
|
||||||
{"txt": "%%%s%%" % txt, "_txt": txt.replace("%", ""), "start": start, "page_len": page_len},
|
{"txt": "%%%s%%" % txt, "_txt": txt.replace("%", ""), "start": start, "page_len": page_len},
|
||||||
|
as_dict=as_dict,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
# searches for supplier
|
# searches for supplier
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
@frappe.validate_and_sanitize_search_inputs
|
@frappe.validate_and_sanitize_search_inputs
|
||||||
def supplier_query(doctype, txt, searchfield, start, page_len, filters):
|
def supplier_query(doctype, txt, searchfield, start, page_len, filters, as_dict=False):
|
||||||
doctype = "Supplier"
|
doctype = "Supplier"
|
||||||
supp_master_name = frappe.defaults.get_user_default("supp_master_name")
|
supp_master_name = frappe.defaults.get_user_default("supp_master_name")
|
||||||
|
|
||||||
if supp_master_name == "Supplier Name":
|
fields = ["name"]
|
||||||
fields = ["name", "supplier_group"]
|
if supp_master_name != "Supplier Name":
|
||||||
else:
|
fields.append("supplier_name")
|
||||||
fields = ["name", "supplier_name", "supplier_group"]
|
|
||||||
|
|
||||||
fields = get_fields(doctype, fields)
|
fields = get_fields(doctype, fields)
|
||||||
|
|
||||||
@@ -145,6 +143,7 @@ def supplier_query(doctype, txt, searchfield, start, page_len, filters):
|
|||||||
**{"field": ", ".join(fields), "key": searchfield, "mcond": get_match_cond(doctype)}
|
**{"field": ", ".join(fields), "key": searchfield, "mcond": get_match_cond(doctype)}
|
||||||
),
|
),
|
||||||
{"txt": "%%%s%%" % txt, "_txt": txt.replace("%", ""), "start": start, "page_len": page_len},
|
{"txt": "%%%s%%" % txt, "_txt": txt.replace("%", ""), "start": start, "page_len": page_len},
|
||||||
|
as_dict=as_dict,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -450,7 +450,7 @@ class StatusUpdater(Document):
|
|||||||
ifnull((select
|
ifnull((select
|
||||||
ifnull(sum(if(abs(%(target_ref_field)s) > abs(%(target_field)s), abs(%(target_field)s), abs(%(target_ref_field)s))), 0)
|
ifnull(sum(if(abs(%(target_ref_field)s) > abs(%(target_field)s), abs(%(target_field)s), abs(%(target_ref_field)s))), 0)
|
||||||
/ sum(abs(%(target_ref_field)s)) * 100
|
/ sum(abs(%(target_ref_field)s)) * 100
|
||||||
from `tab%(target_dt)s` where parent="%(name)s" having sum(abs(%(target_ref_field)s)) > 0), 0), 6)
|
from `tab%(target_dt)s` where parent='%(name)s' and parenttype='%(target_parent_dt)s' having sum(abs(%(target_ref_field)s)) > 0), 0), 6)
|
||||||
%(update_modified)s
|
%(update_modified)s
|
||||||
where name='%(name)s'"""
|
where name='%(name)s'"""
|
||||||
% args
|
% args
|
||||||
|
|||||||
@@ -123,7 +123,7 @@ frappe.ui.form.on("Customer", {
|
|||||||
|
|
||||||
frm.add_custom_button(__('Accounting Ledger'), function () {
|
frm.add_custom_button(__('Accounting Ledger'), function () {
|
||||||
frappe.set_route('query-report', 'General Ledger',
|
frappe.set_route('query-report', 'General Ledger',
|
||||||
{party_type: 'Customer', party: frm.doc.name});
|
{party_type: 'Customer', party: frm.doc.name, party_name: frm.doc.customer_name});
|
||||||
}, __('View'));
|
}, __('View'));
|
||||||
|
|
||||||
frm.add_custom_button(__('Pricing Rule'), function () {
|
frm.add_custom_button(__('Pricing Rule'), function () {
|
||||||
|
|||||||
@@ -275,18 +275,9 @@ class Customer(TransactionBase):
|
|||||||
|
|
||||||
def on_trash(self):
|
def on_trash(self):
|
||||||
if self.customer_primary_contact:
|
if self.customer_primary_contact:
|
||||||
frappe.db.sql(
|
self.db_set("customer_primary_contact", None)
|
||||||
"""
|
if self.customer_primary_address:
|
||||||
UPDATE `tabCustomer`
|
self.db_set("customer_primary_address", None)
|
||||||
SET
|
|
||||||
customer_primary_contact=null,
|
|
||||||
customer_primary_address=null,
|
|
||||||
mobile_no=null,
|
|
||||||
email_id=null,
|
|
||||||
primary_address=null
|
|
||||||
WHERE name=%(name)s""",
|
|
||||||
{"name": self.name},
|
|
||||||
)
|
|
||||||
|
|
||||||
delete_contact_and_address("Customer", self.name)
|
delete_contact_and_address("Customer", self.name)
|
||||||
if self.lead_name:
|
if self.lead_name:
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
|
from frappe.custom.doctype.property_setter.property_setter import make_property_setter
|
||||||
from frappe.test_runner import make_test_records
|
from frappe.test_runner import make_test_records
|
||||||
from frappe.tests.utils import FrappeTestCase
|
from frappe.tests.utils import FrappeTestCase
|
||||||
from frappe.utils import flt
|
from frappe.utils import flt
|
||||||
@@ -343,6 +344,37 @@ class TestCustomer(FrappeTestCase):
|
|||||||
due_date = get_due_date("2017-01-22", "Customer", "_Test Customer")
|
due_date = get_due_date("2017-01-22", "Customer", "_Test Customer")
|
||||||
self.assertEqual(due_date, "2017-01-22")
|
self.assertEqual(due_date, "2017-01-22")
|
||||||
|
|
||||||
|
def test_serach_fields_for_customer(self):
|
||||||
|
from erpnext.controllers.queries import customer_query
|
||||||
|
|
||||||
|
frappe.db.set_value("Selling Settings", None, "cust_master_name", "Naming Series")
|
||||||
|
|
||||||
|
make_property_setter(
|
||||||
|
"Customer", None, "search_fields", "customer_group", "Data", for_doctype="Doctype"
|
||||||
|
)
|
||||||
|
|
||||||
|
data = customer_query(
|
||||||
|
"Customer", "_Test Customer", "", 0, 20, filters={"name": "_Test Customer"}, as_dict=True
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(data[0].name, "_Test Customer")
|
||||||
|
self.assertEqual(data[0].customer_group, "_Test Customer Group")
|
||||||
|
self.assertTrue("territory" not in data[0])
|
||||||
|
|
||||||
|
make_property_setter(
|
||||||
|
"Customer", None, "search_fields", "customer_group, territory", "Data", for_doctype="Doctype"
|
||||||
|
)
|
||||||
|
data = customer_query(
|
||||||
|
"Customer", "_Test Customer", "", 0, 20, filters={"name": "_Test Customer"}, as_dict=True
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(data[0].name, "_Test Customer")
|
||||||
|
self.assertEqual(data[0].customer_group, "_Test Customer Group")
|
||||||
|
self.assertEqual(data[0].territory, "_Test Territory")
|
||||||
|
self.assertTrue("territory" in data[0])
|
||||||
|
|
||||||
|
frappe.db.set_value("Selling Settings", None, "cust_master_name", "Customer Name")
|
||||||
|
|
||||||
|
|
||||||
def get_customer_dict(customer_name):
|
def get_customer_dict(customer_name):
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ from operator import itemgetter
|
|||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
from frappe import _
|
from frappe import _
|
||||||
|
from frappe.query_builder.functions import Coalesce
|
||||||
from frappe.utils import cint, date_diff, flt, getdate
|
from frappe.utils import cint, date_diff, flt, getdate
|
||||||
from six import iteritems
|
from six import iteritems
|
||||||
|
|
||||||
@@ -276,11 +277,39 @@ def get_stock_ledger_entries(filters, items):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def get_opening_vouchers(to_date):
|
||||||
|
opening_vouchers = {"Stock Entry": [], "Stock Reconciliation": []}
|
||||||
|
|
||||||
|
se = frappe.qb.DocType("Stock Entry")
|
||||||
|
sr = frappe.qb.DocType("Stock Reconciliation")
|
||||||
|
|
||||||
|
vouchers_data = (
|
||||||
|
frappe.qb.from_(
|
||||||
|
(
|
||||||
|
frappe.qb.from_(se)
|
||||||
|
.select(se.name, Coalesce("Stock Entry").as_("voucher_type"))
|
||||||
|
.where((se.docstatus == 1) & (se.posting_date <= to_date) & (se.is_opening == "Yes"))
|
||||||
|
)
|
||||||
|
+ (
|
||||||
|
frappe.qb.from_(sr)
|
||||||
|
.select(sr.name, Coalesce("Stock Reconciliation").as_("voucher_type"))
|
||||||
|
.where((sr.docstatus == 1) & (sr.posting_date <= to_date) & (sr.purpose == "Opening Stock"))
|
||||||
|
)
|
||||||
|
).select("voucher_type", "name")
|
||||||
|
).run(as_dict=True)
|
||||||
|
|
||||||
|
if vouchers_data:
|
||||||
|
for d in vouchers_data:
|
||||||
|
opening_vouchers[d.voucher_type].append(d.name)
|
||||||
|
|
||||||
|
return opening_vouchers
|
||||||
|
|
||||||
|
|
||||||
def get_item_warehouse_map(filters, sle):
|
def get_item_warehouse_map(filters, sle):
|
||||||
iwb_map = {}
|
iwb_map = {}
|
||||||
from_date = getdate(filters.get("from_date"))
|
from_date = getdate(filters.get("from_date"))
|
||||||
to_date = getdate(filters.get("to_date"))
|
to_date = getdate(filters.get("to_date"))
|
||||||
|
opening_vouchers = get_opening_vouchers(to_date)
|
||||||
float_precision = cint(frappe.db.get_default("float_precision")) or 3
|
float_precision = cint(frappe.db.get_default("float_precision")) or 3
|
||||||
|
|
||||||
for d in sle:
|
for d in sle:
|
||||||
@@ -309,11 +338,7 @@ def get_item_warehouse_map(filters, sle):
|
|||||||
|
|
||||||
value_diff = flt(d.stock_value_difference)
|
value_diff = flt(d.stock_value_difference)
|
||||||
|
|
||||||
if d.posting_date < from_date or (
|
if d.posting_date < from_date or d.voucher_no in opening_vouchers.get(d.voucher_type, []):
|
||||||
d.posting_date == from_date
|
|
||||||
and d.voucher_type == "Stock Reconciliation"
|
|
||||||
and frappe.db.get_value("Stock Reconciliation", d.voucher_no, "purpose") == "Opening Stock"
|
|
||||||
):
|
|
||||||
qty_dict.opening_qty += qty_diff
|
qty_dict.opening_qty += qty_diff
|
||||||
qty_dict.opening_val += value_diff
|
qty_dict.opening_val += value_diff
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user