mirror of
https://github.com/frappe/erpnext.git
synced 2026-08-11 21:51:48 +00:00
Merge pull request #56062 from mihir-kandoi/pg-accounts-pos
refactor(postgres): port Accounts POS, pricing & invoicing doctype queries to the query builder
This commit is contained in:
@@ -84,10 +84,10 @@ class CostCenter(NestedSet):
|
||||
return frappe.db.get_value("GL Entry", {"cost_center": self.name})
|
||||
|
||||
def check_if_child_exists(self):
|
||||
return frappe.db.sql(
|
||||
"select name from `tabCost Center` where \
|
||||
parent_cost_center = %s and docstatus != 2",
|
||||
self.name,
|
||||
return frappe.get_all(
|
||||
"Cost Center",
|
||||
filters={"parent_cost_center": self.name, "docstatus": ["!=", 2]},
|
||||
pluck="name",
|
||||
)
|
||||
|
||||
def if_allocation_exists_against_cost_center(self):
|
||||
|
||||
@@ -72,10 +72,8 @@ class FiscalYear(Document):
|
||||
|
||||
if existing_fiscal_years:
|
||||
for existing in existing_fiscal_years:
|
||||
company_for_existing = frappe.db.sql_list(
|
||||
"""select company from `tabFiscal Year Company`
|
||||
where parent=%s""",
|
||||
existing.name,
|
||||
company_for_existing = frappe.get_all(
|
||||
"Fiscal Year Company", filters={"parent": existing.name}, pluck="company"
|
||||
)
|
||||
|
||||
overlap = False
|
||||
|
||||
@@ -39,28 +39,32 @@ def get_loyalty_point_entries(customer, loyalty_program, company, expiry_date=No
|
||||
if not expiry_date:
|
||||
expiry_date = today()
|
||||
|
||||
return frappe.db.sql(
|
||||
"""
|
||||
select name, loyalty_points, expiry_date, loyalty_program_tier, invoice_type, invoice
|
||||
from `tabLoyalty Point Entry`
|
||||
where customer=%s and loyalty_program=%s
|
||||
and expiry_date>=%s and loyalty_points>0 and company=%s
|
||||
order by expiry_date
|
||||
""",
|
||||
(customer, loyalty_program, expiry_date, company),
|
||||
as_dict=1,
|
||||
return frappe.get_all(
|
||||
"Loyalty Point Entry",
|
||||
filters={
|
||||
"customer": customer,
|
||||
"loyalty_program": loyalty_program,
|
||||
"expiry_date": [">=", expiry_date],
|
||||
"loyalty_points": [">", 0],
|
||||
"company": company,
|
||||
},
|
||||
fields=["name", "loyalty_points", "expiry_date", "loyalty_program_tier", "invoice_type", "invoice"],
|
||||
order_by="expiry_date",
|
||||
)
|
||||
|
||||
|
||||
def get_redemption_details(customer, loyalty_program, company):
|
||||
return frappe._dict(
|
||||
frappe.db.sql(
|
||||
"""
|
||||
select redeem_against, sum(loyalty_points)
|
||||
from `tabLoyalty Point Entry`
|
||||
where customer=%s and loyalty_program=%s and loyalty_points<0 and company=%s
|
||||
group by redeem_against
|
||||
""",
|
||||
(customer, loyalty_program, company),
|
||||
frappe.get_all(
|
||||
"Loyalty Point Entry",
|
||||
filters={
|
||||
"customer": customer,
|
||||
"loyalty_program": loyalty_program,
|
||||
"loyalty_points": ["<", 0],
|
||||
"company": company,
|
||||
},
|
||||
fields=["redeem_against", {"SUM": "loyalty_points", "as": "loyalty_points"}],
|
||||
group_by="redeem_against",
|
||||
as_list=True,
|
||||
)
|
||||
)
|
||||
|
||||
@@ -505,19 +505,16 @@ class POSInvoice(SalesInvoice):
|
||||
if d.get("serial_no"):
|
||||
serial_nos = get_serial_nos(d.serial_no)
|
||||
for sr in serial_nos:
|
||||
serial_no_exists = frappe.db.sql(
|
||||
"""
|
||||
SELECT name
|
||||
FROM `tabPOS Invoice Item`
|
||||
WHERE
|
||||
parent = %s
|
||||
and (serial_no = %s
|
||||
or serial_no like %s
|
||||
or serial_no like %s
|
||||
or serial_no like %s
|
||||
)
|
||||
""",
|
||||
(self.return_against, sr, sr + "\n%", "%\n" + sr, "%\n" + sr + "\n%"),
|
||||
serial_no_exists = frappe.get_all(
|
||||
"POS Invoice Item",
|
||||
filters={"parent": self.return_against},
|
||||
or_filters=[
|
||||
["serial_no", "=", sr],
|
||||
["serial_no", "like", f"{sr}\n%"],
|
||||
["serial_no", "like", f"%\n{sr}"],
|
||||
["serial_no", "like", f"%\n{sr}\n%"],
|
||||
],
|
||||
limit=1,
|
||||
)
|
||||
|
||||
if not serial_no_exists:
|
||||
@@ -963,15 +960,9 @@ def get_bundle_availability(bundle_item_code, warehouse):
|
||||
|
||||
|
||||
def get_bin_qty(item_code, warehouse):
|
||||
bin_qty = frappe.db.sql(
|
||||
"""select actual_qty from `tabBin`
|
||||
where item_code = %s and warehouse = %s
|
||||
limit 1""",
|
||||
(item_code, warehouse),
|
||||
as_dict=1,
|
||||
)
|
||||
actual_qty = frappe.db.get_value("Bin", {"item_code": item_code, "warehouse": warehouse}, "actual_qty")
|
||||
|
||||
return bin_qty[0].actual_qty or 0 if bin_qty else 0
|
||||
return actual_qty or 0
|
||||
|
||||
|
||||
def get_pos_reserved_qty(item_code, warehouse):
|
||||
|
||||
@@ -118,14 +118,21 @@ class POSProfile(Document):
|
||||
|
||||
def validate_default_profile(self):
|
||||
for row in self.applicable_for_users:
|
||||
res = frappe.db.sql(
|
||||
"""select pf.name
|
||||
from
|
||||
`tabPOS Profile User` pfu, `tabPOS Profile` pf
|
||||
where
|
||||
pf.name = pfu.parent and pfu.user = %s and pf.name != %s and pf.company = %s
|
||||
and pfu.default=1 and pf.disabled = 0""",
|
||||
(row.user, self.name, self.company),
|
||||
pfu = frappe.qb.DocType("POS Profile User")
|
||||
pf = frappe.qb.DocType("POS Profile")
|
||||
res = (
|
||||
frappe.qb.from_(pfu)
|
||||
.inner_join(pf)
|
||||
.on(pf.name == pfu.parent)
|
||||
.select(pf.name)
|
||||
.where(
|
||||
(pfu.user == row.user)
|
||||
& (pf.name != self.name)
|
||||
& (pf.company == self.company)
|
||||
& (pfu.default == 1)
|
||||
& (pf.disabled == 0)
|
||||
)
|
||||
.run()
|
||||
)
|
||||
|
||||
if row.default and res:
|
||||
@@ -265,10 +272,11 @@ def get_permitted_nodes(group_type):
|
||||
|
||||
def get_child_nodes(group_type, root):
|
||||
lft, rgt = frappe.db.get_value(group_type, root, ["lft", "rgt"])
|
||||
return frappe.db.sql(
|
||||
f""" Select name, lft, rgt from `tab{group_type}` where
|
||||
lft >= {lft} and rgt <= {rgt} order by lft""",
|
||||
as_dict=1,
|
||||
return frappe.get_all(
|
||||
group_type,
|
||||
filters={"lft": [">=", lft], "rgt": ["<=", rgt]},
|
||||
fields=["name", "lft", "rgt"],
|
||||
order_by="lft",
|
||||
)
|
||||
|
||||
|
||||
@@ -278,40 +286,33 @@ def pos_profile_query(doctype: str, txt: str, searchfield: str, start: int, page
|
||||
user = frappe.session["user"]
|
||||
company = filters.get("company") or frappe.defaults.get_user_default("company")
|
||||
|
||||
args = {
|
||||
"user": user,
|
||||
"start": start,
|
||||
"company": company,
|
||||
"page_len": page_len,
|
||||
"txt": "%%%s%%" % txt,
|
||||
}
|
||||
pf = frappe.qb.DocType("POS Profile")
|
||||
pfu = frappe.qb.DocType("POS Profile User")
|
||||
|
||||
pos_profile = frappe.db.sql(
|
||||
"""select pf.name
|
||||
from
|
||||
`tabPOS Profile` pf, `tabPOS Profile User` pfu
|
||||
where
|
||||
pfu.parent = pf.name and pfu.user = %(user)s and pf.company = %(company)s
|
||||
and (pf.name like %(txt)s)
|
||||
and pf.disabled = 0 limit %(page_len)s offset %(start)s""",
|
||||
args,
|
||||
pos_profile = (
|
||||
frappe.qb.from_(pf)
|
||||
.inner_join(pfu)
|
||||
.on(pfu.parent == pf.name)
|
||||
.select(pf.name)
|
||||
.where((pfu.user == user) & (pf.company == company) & pf.name.like(f"%{txt}%") & (pf.disabled == 0))
|
||||
.limit(page_len)
|
||||
.offset(start)
|
||||
.run()
|
||||
)
|
||||
|
||||
if not pos_profile:
|
||||
del args["user"]
|
||||
|
||||
pos_profile = frappe.db.sql(
|
||||
"""select pf.name
|
||||
from
|
||||
`tabPOS Profile` pf left join `tabPOS Profile User` pfu
|
||||
on
|
||||
pf.name = pfu.parent
|
||||
where
|
||||
ifnull(pfu.user, '') = ''
|
||||
and pf.company = %(company)s
|
||||
and pf.name like %(txt)s
|
||||
and pf.disabled = 0""",
|
||||
args,
|
||||
pos_profile = (
|
||||
frappe.qb.from_(pf)
|
||||
.left_join(pfu)
|
||||
.on(pf.name == pfu.parent)
|
||||
.select(pf.name)
|
||||
.where(
|
||||
(pfu.user.isnull() | (pfu.user == ""))
|
||||
& (pf.company == company)
|
||||
& pf.name.like(f"%{txt}%")
|
||||
& (pf.disabled == 0)
|
||||
)
|
||||
.run()
|
||||
)
|
||||
|
||||
return pos_profile
|
||||
|
||||
@@ -114,7 +114,7 @@ def _get_pricing_rules(apply_on, args, values):
|
||||
if apply_on_field == "item_code":
|
||||
if args.get("uom", None):
|
||||
item_conditions += (
|
||||
" and ({child_doc}.uom={item_uom} or IFNULL({child_doc}.uom, '')='')".format(
|
||||
" and ({child_doc}.uom={item_uom} or COALESCE({child_doc}.uom, '')='')".format(
|
||||
child_doc=child_doc, item_uom=frappe.db.escape(args.get("uom"))
|
||||
)
|
||||
)
|
||||
@@ -127,7 +127,7 @@ def _get_pricing_rules(apply_on, args, values):
|
||||
elif apply_on_field == "item_group":
|
||||
item_conditions = _get_tree_conditions(args, "Item Group", child_doc, False)
|
||||
if args.get("uom", None):
|
||||
item_conditions += " and ({child_doc}.uom={item_uom} or IFNULL({child_doc}.uom, '')='')".format(
|
||||
item_conditions += " and ({child_doc}.uom={item_uom} or COALESCE({child_doc}.uom, '')='')".format(
|
||||
child_doc=child_doc, item_uom=frappe.db.escape(args.get("uom"))
|
||||
)
|
||||
|
||||
@@ -139,7 +139,7 @@ def _get_pricing_rules(apply_on, args, values):
|
||||
if not args.price_list:
|
||||
args.price_list = None
|
||||
|
||||
conditions += " and ifnull(`tabPricing Rule`.for_price_list, '') in (%(price_list)s, '')"
|
||||
conditions += " and coalesce(`tabPricing Rule`.for_price_list, '') in (%(price_list)s, '')"
|
||||
values["price_list"] = args.get("price_list")
|
||||
|
||||
pricing_rules = (
|
||||
@@ -195,10 +195,8 @@ def _get_tree_conditions(args, parenttype, table, allow_blank=True):
|
||||
except TypeError:
|
||||
frappe.throw(_("Invalid {0}").format(args.get(field)))
|
||||
|
||||
parent_groups = frappe.db.sql_list(
|
||||
"""select name from `tab{}`
|
||||
where lft<={} and rgt>={}""".format(parenttype, "%s", "%s"),
|
||||
(lft, rgt),
|
||||
parent_groups = frappe.get_all(
|
||||
parenttype, filters={"lft": ["<=", lft], "rgt": [">=", rgt]}, pluck="name"
|
||||
)
|
||||
|
||||
if parenttype in ["Customer Group", "Item Group", "Territory"]:
|
||||
@@ -217,14 +215,14 @@ def _get_tree_conditions(args, parenttype, table, allow_blank=True):
|
||||
if parent_groups:
|
||||
if allow_blank:
|
||||
parent_groups.append("")
|
||||
condition = "ifnull({table}.{field}, '') in ({parent_groups})".format(
|
||||
condition = "coalesce({table}.{field}, '') in ({parent_groups})".format(
|
||||
table=table, field=field, parent_groups=", ".join(frappe.db.escape(d) for d in parent_groups)
|
||||
)
|
||||
|
||||
frappe.flags.tree_conditions[key] = condition
|
||||
|
||||
elif allow_blank:
|
||||
condition = f"ifnull({table}.{field}, '') = ''"
|
||||
condition = f"coalesce({table}.{field}, '') = ''"
|
||||
|
||||
return condition
|
||||
|
||||
@@ -232,10 +230,10 @@ def _get_tree_conditions(args, parenttype, table, allow_blank=True):
|
||||
def get_other_conditions(conditions, values, args):
|
||||
for field in ["company", "customer", "supplier", "campaign", "sales_partner"]:
|
||||
if args.get(field):
|
||||
conditions += f" and ifnull(`tabPricing Rule`.{field}, '') in (%({field})s, '')"
|
||||
conditions += f" and coalesce(`tabPricing Rule`.{field}, '') in (%({field})s, '')"
|
||||
values[field] = args.get(field)
|
||||
else:
|
||||
conditions += f" and ifnull(`tabPricing Rule`.{field}, '') = ''"
|
||||
conditions += f" and coalesce(`tabPricing Rule`.{field}, '') = ''"
|
||||
|
||||
for parenttype in ["Customer Group", "Territory", "Supplier Group"]:
|
||||
group_condition = _get_tree_conditions(args, parenttype, "`tabPricing Rule`")
|
||||
@@ -248,8 +246,8 @@ def get_other_conditions(conditions, values, args):
|
||||
or frappe.get_value(args.get("doctype"), args.get("name"), "posting_date", ignore=True)
|
||||
)
|
||||
if date:
|
||||
conditions += """ and %(transaction_date)s between ifnull(`tabPricing Rule`.valid_from, '2000-01-01')
|
||||
and ifnull(`tabPricing Rule`.valid_upto, '2500-12-31')"""
|
||||
conditions += """ and %(transaction_date)s between coalesce(`tabPricing Rule`.valid_from, '2000-01-01')
|
||||
and coalesce(`tabPricing Rule`.valid_upto, '2500-12-31')"""
|
||||
values["transaction_date"] = date
|
||||
|
||||
if args.get("doctype") in [
|
||||
@@ -264,9 +262,9 @@ def get_other_conditions(conditions, values, args):
|
||||
"POS Invoice",
|
||||
"POS Invoice Item",
|
||||
]:
|
||||
conditions += """ and ifnull(`tabPricing Rule`.selling, 0) = 1"""
|
||||
conditions += """ and coalesce(`tabPricing Rule`.selling, 0) = 1"""
|
||||
else:
|
||||
conditions += """ and ifnull(`tabPricing Rule`.buying, 0) = 1"""
|
||||
conditions += """ and coalesce(`tabPricing Rule`.buying, 0) = 1"""
|
||||
|
||||
return conditions
|
||||
|
||||
|
||||
@@ -524,16 +524,11 @@ class PurchaseInvoice(BuyingController):
|
||||
def check_prev_docstatus(self):
|
||||
for d in self.get("items"):
|
||||
if d.purchase_order:
|
||||
submitted = frappe.db.sql(
|
||||
"select name from `tabPurchase Order` where docstatus = 1 and name = %s", d.purchase_order
|
||||
)
|
||||
submitted = frappe.db.exists("Purchase Order", {"docstatus": 1, "name": d.purchase_order})
|
||||
if not submitted:
|
||||
frappe.throw(_("Purchase Order {0} is not submitted").format(d.purchase_order))
|
||||
if d.purchase_receipt:
|
||||
submitted = frappe.db.sql(
|
||||
"select name from `tabPurchase Receipt` where docstatus = 1 and name = %s",
|
||||
d.purchase_receipt,
|
||||
)
|
||||
submitted = frappe.db.exists("Purchase Receipt", {"docstatus": 1, "name": d.purchase_receipt})
|
||||
if not submitted:
|
||||
frappe.throw(_("Purchase Receipt {0} is not submitted").format(d.purchase_receipt))
|
||||
|
||||
@@ -801,25 +796,20 @@ class PurchaseInvoice(BuyingController):
|
||||
if cint(frappe.get_single_value("Accounts Settings", "check_supplier_invoice_uniqueness")):
|
||||
fiscal_year = get_fiscal_year(self.posting_date, company=self.company, as_dict=True)
|
||||
|
||||
pi = frappe.db.sql(
|
||||
"""select name from `tabPurchase Invoice`
|
||||
where
|
||||
bill_no = %(bill_no)s
|
||||
and supplier = %(supplier)s
|
||||
and name != %(name)s
|
||||
and docstatus < 2
|
||||
and posting_date between %(year_start_date)s and %(year_end_date)s""",
|
||||
{
|
||||
pi = frappe.get_all(
|
||||
"Purchase Invoice",
|
||||
filters={
|
||||
"bill_no": self.bill_no,
|
||||
"supplier": self.supplier,
|
||||
"name": self.name,
|
||||
"year_start_date": fiscal_year.year_start_date,
|
||||
"year_end_date": fiscal_year.year_end_date,
|
||||
"name": ["!=", self.name],
|
||||
"docstatus": ["<", 2],
|
||||
"posting_date": ["between", [fiscal_year.year_start_date, fiscal_year.year_end_date]],
|
||||
},
|
||||
pluck="name",
|
||||
)
|
||||
|
||||
if pi:
|
||||
pi = pi[0][0]
|
||||
pi = pi[0]
|
||||
|
||||
frappe.throw(
|
||||
_("Supplier Invoice No exists in Purchase Invoice {0}").format(
|
||||
|
||||
@@ -55,10 +55,13 @@ class ExpenseAccountService:
|
||||
else:
|
||||
# check if 'Stock Received But Not Billed' account is credited in Purchase receipt or not
|
||||
if item.purchase_receipt:
|
||||
negative_expense_booked_in_pr = frappe.db.sql(
|
||||
"""select name from `tabGL Entry`
|
||||
where voucher_type='Purchase Receipt' and voucher_no=%s and account = %s""",
|
||||
(item.purchase_receipt, stock_not_billed_account),
|
||||
negative_expense_booked_in_pr = frappe.db.exists(
|
||||
"GL Entry",
|
||||
{
|
||||
"voucher_type": "Purchase Receipt",
|
||||
"voucher_no": item.purchase_receipt,
|
||||
"account": stock_not_billed_account,
|
||||
},
|
||||
)
|
||||
|
||||
if negative_expense_booked_in_pr:
|
||||
|
||||
@@ -395,10 +395,14 @@ class PurchaseInvoiceGLComposer(BaseGLComposer):
|
||||
):
|
||||
# Post reverse entry for Stock-Received-But-Not-Billed if booked in Purchase Receipt
|
||||
if item.purchase_receipt and valuation_tax_accounts:
|
||||
negative_expense_booked_in_pr = frappe.db.sql(
|
||||
"""select name from `tabGL Entry`
|
||||
where voucher_type='Purchase Receipt' and voucher_no=%s and account in %s""",
|
||||
(item.purchase_receipt, valuation_tax_accounts),
|
||||
negative_expense_booked_in_pr = frappe.get_all(
|
||||
"GL Entry",
|
||||
filters={
|
||||
"voucher_type": "Purchase Receipt",
|
||||
"voucher_no": item.purchase_receipt,
|
||||
"account": ["in", valuation_tax_accounts],
|
||||
},
|
||||
pluck="name",
|
||||
)
|
||||
|
||||
(
|
||||
|
||||
@@ -56,11 +56,14 @@ def valdiate_taxes_and_charges_template(doc):
|
||||
# doc.is_default = 1
|
||||
|
||||
if doc.is_default == 1:
|
||||
frappe.db.sql(
|
||||
f"""update `tab{doc.doctype}` set is_default = 0
|
||||
where is_default = 1 and name != %s and company = %s""",
|
||||
(doc.name, doc.company),
|
||||
)
|
||||
template = frappe.qb.DocType(doc.doctype)
|
||||
(
|
||||
frappe.qb.update(template)
|
||||
.set(template.is_default, 0)
|
||||
.where(
|
||||
(template.is_default == 1) & (template.name != doc.name) & (template.company == doc.company)
|
||||
)
|
||||
).run()
|
||||
|
||||
validate_disabled(doc)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user