Merge branch 'develop' into subcontracting
This commit is contained in:
@@ -322,9 +322,9 @@ def get_parent_account(doctype, txt, searchfield, start, page_len, filters):
|
|||||||
return frappe.db.sql(
|
return frappe.db.sql(
|
||||||
"""select name from tabAccount
|
"""select name from tabAccount
|
||||||
where is_group = 1 and docstatus != 2 and company = %s
|
where is_group = 1 and docstatus != 2 and company = %s
|
||||||
and %s like %s order by name limit %s, %s"""
|
and %s like %s order by name limit %s offset %s"""
|
||||||
% ("%s", searchfield, "%s", "%s", "%s"),
|
% ("%s", searchfield, "%s", "%s", "%s"),
|
||||||
(filters["company"], "%%%s%%" % txt, start, page_len),
|
(filters["company"], "%%%s%%" % txt, page_len, start),
|
||||||
as_list=1,
|
as_list=1,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1239,7 +1239,7 @@ def get_against_jv(doctype, txt, searchfield, start, page_len, filters):
|
|||||||
AND jv.docstatus = 1
|
AND jv.docstatus = 1
|
||||||
AND jv.`{0}` LIKE %(txt)s
|
AND jv.`{0}` LIKE %(txt)s
|
||||||
ORDER BY jv.name DESC
|
ORDER BY jv.name DESC
|
||||||
LIMIT %(offset)s, %(limit)s
|
LIMIT %(limit)s offset %(offset)s
|
||||||
""".format(
|
""".format(
|
||||||
searchfield
|
searchfield
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ def get_mop_query(doctype, txt, searchfield, start, page_len, filters):
|
|||||||
return frappe.db.sql(
|
return frappe.db.sql(
|
||||||
""" select mode_of_payment from `tabPayment Order Reference`
|
""" select mode_of_payment from `tabPayment Order Reference`
|
||||||
where parent = %(parent)s and mode_of_payment like %(txt)s
|
where parent = %(parent)s and mode_of_payment like %(txt)s
|
||||||
limit %(start)s, %(page_len)s""",
|
limit %(page_len)s offset %(start)s""",
|
||||||
{"parent": filters.get("parent"), "start": start, "page_len": page_len, "txt": "%%%s%%" % txt},
|
{"parent": filters.get("parent"), "start": start, "page_len": page_len, "txt": "%%%s%%" % txt},
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -51,7 +51,7 @@ def get_supplier_query(doctype, txt, searchfield, start, page_len, filters):
|
|||||||
""" select supplier from `tabPayment Order Reference`
|
""" select supplier from `tabPayment Order Reference`
|
||||||
where parent = %(parent)s and supplier like %(txt)s and
|
where parent = %(parent)s and supplier like %(txt)s and
|
||||||
(payment_reference is null or payment_reference='')
|
(payment_reference is null or payment_reference='')
|
||||||
limit %(start)s, %(page_len)s""",
|
limit %(page_len)s offset %(start)s""",
|
||||||
{"parent": filters.get("parent"), "start": start, "page_len": page_len, "txt": "%%%s%%" % txt},
|
{"parent": filters.get("parent"), "start": start, "page_len": page_len, "txt": "%%%s%%" % txt},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -173,7 +173,7 @@ def pos_profile_query(doctype, txt, searchfield, start, page_len, filters):
|
|||||||
where
|
where
|
||||||
pfu.parent = pf.name and pfu.user = %(user)s and pf.company = %(company)s
|
pfu.parent = pf.name and pfu.user = %(user)s and pf.company = %(company)s
|
||||||
and (pf.name like %(txt)s)
|
and (pf.name like %(txt)s)
|
||||||
and pf.disabled = 0 limit %(start)s, %(page_len)s""",
|
and pf.disabled = 0 limit %(page_len)s offset %(start)s""",
|
||||||
args,
|
args,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -211,7 +211,7 @@ def set_address_details(
|
|||||||
else:
|
else:
|
||||||
party_details.update(get_company_address(company))
|
party_details.update(get_company_address(company))
|
||||||
|
|
||||||
if doctype and doctype in ["Delivery Note", "Sales Invoice", "Sales Order"]:
|
if doctype and doctype in ["Delivery Note", "Sales Invoice", "Sales Order", "Quotation"]:
|
||||||
if party_details.company_address:
|
if party_details.company_address:
|
||||||
party_details.update(
|
party_details.update(
|
||||||
get_fetch_values(doctype, "company_address", party_details.company_address)
|
get_fetch_values(doctype, "company_address", party_details.company_address)
|
||||||
|
|||||||
@@ -197,7 +197,7 @@ class PurchaseOrder(BuyingController):
|
|||||||
if not item.fg_item:
|
if not item.fg_item:
|
||||||
frappe.throw(
|
frappe.throw(
|
||||||
_("Row #{0}: Finished Good Item is not specified for service item {1}").format(
|
_("Row #{0}: Finished Good Item is not specified for service item {1}").format(
|
||||||
item.idx, item.item_code
|
item.idx, item.item_code
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -285,7 +285,7 @@ def get_supplier_contacts(doctype, txt, searchfield, start, page_len, filters):
|
|||||||
"""select `tabContact`.name from `tabContact`, `tabDynamic Link`
|
"""select `tabContact`.name from `tabContact`, `tabDynamic Link`
|
||||||
where `tabDynamic Link`.link_doctype = 'Supplier' and (`tabDynamic Link`.link_name=%(name)s
|
where `tabDynamic Link`.link_doctype = 'Supplier' and (`tabDynamic Link`.link_name=%(name)s
|
||||||
and `tabDynamic Link`.link_name like %(txt)s) and `tabContact`.name = `tabDynamic Link`.parent
|
and `tabDynamic Link`.link_name like %(txt)s) and `tabContact`.name = `tabDynamic Link`.parent
|
||||||
limit %(start)s, %(page_len)s""",
|
limit %(page_len)s offset %(start)s""",
|
||||||
{"start": start, "page_len": page_len, "txt": "%%%s%%" % txt, "name": filters.get("supplier")},
|
{"start": start, "page_len": page_len, "txt": "%%%s%%" % txt, "name": filters.get("supplier")},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ def employee_query(doctype, txt, searchfield, start, page_len, filters):
|
|||||||
if(locate(%(_txt)s, employee_name), locate(%(_txt)s, employee_name), 99999),
|
if(locate(%(_txt)s, employee_name), locate(%(_txt)s, employee_name), 99999),
|
||||||
idx desc,
|
idx desc,
|
||||||
name, employee_name
|
name, employee_name
|
||||||
limit %(start)s, %(page_len)s""".format(
|
limit %(page_len)s offset %(start)s""".format(
|
||||||
**{
|
**{
|
||||||
"fields": ", ".join(fields),
|
"fields": ", ".join(fields),
|
||||||
"key": searchfield,
|
"key": searchfield,
|
||||||
@@ -65,7 +65,7 @@ def lead_query(doctype, txt, searchfield, start, page_len, filters):
|
|||||||
if(locate(%(_txt)s, company_name), locate(%(_txt)s, company_name), 99999),
|
if(locate(%(_txt)s, company_name), locate(%(_txt)s, company_name), 99999),
|
||||||
idx desc,
|
idx desc,
|
||||||
name, lead_name
|
name, lead_name
|
||||||
limit %(start)s, %(page_len)s""".format(
|
limit %(page_len)s offset %(start)s""".format(
|
||||||
**{"fields": ", ".join(fields), "key": searchfield, "mcond": get_match_cond(doctype)}
|
**{"fields": ", ".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},
|
||||||
@@ -100,7 +100,7 @@ def customer_query(doctype, txt, searchfield, start, page_len, filters):
|
|||||||
if(locate(%(_txt)s, customer_name), locate(%(_txt)s, customer_name), 99999),
|
if(locate(%(_txt)s, customer_name), locate(%(_txt)s, customer_name), 99999),
|
||||||
idx desc,
|
idx desc,
|
||||||
name, customer_name
|
name, customer_name
|
||||||
limit %(start)s, %(page_len)s""".format(
|
limit %(page_len)s offset %(start)s""".format(
|
||||||
**{
|
**{
|
||||||
"fields": ", ".join(fields),
|
"fields": ", ".join(fields),
|
||||||
"scond": searchfields,
|
"scond": searchfields,
|
||||||
@@ -137,7 +137,7 @@ def supplier_query(doctype, txt, searchfield, start, page_len, filters):
|
|||||||
if(locate(%(_txt)s, supplier_name), locate(%(_txt)s, supplier_name), 99999),
|
if(locate(%(_txt)s, supplier_name), locate(%(_txt)s, supplier_name), 99999),
|
||||||
idx desc,
|
idx desc,
|
||||||
name, supplier_name
|
name, supplier_name
|
||||||
limit %(start)s, %(page_len)s """.format(
|
limit %(page_len)s offset %(start)s""".format(
|
||||||
**{"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},
|
||||||
@@ -167,7 +167,7 @@ def tax_account_query(doctype, txt, searchfield, start, page_len, filters):
|
|||||||
AND `{searchfield}` LIKE %(txt)s
|
AND `{searchfield}` LIKE %(txt)s
|
||||||
{mcond}
|
{mcond}
|
||||||
ORDER BY idx DESC, name
|
ORDER BY idx DESC, name
|
||||||
LIMIT %(offset)s, %(limit)s
|
LIMIT %(limit)s offset %(offset)s
|
||||||
""".format(
|
""".format(
|
||||||
account_type_condition=account_type_condition,
|
account_type_condition=account_type_condition,
|
||||||
searchfield=searchfield,
|
searchfield=searchfield,
|
||||||
@@ -351,7 +351,7 @@ def get_project_name(doctype, txt, searchfield, start, page_len, filters):
|
|||||||
if(locate(%(_txt)s, name), locate(%(_txt)s, name), 99999),
|
if(locate(%(_txt)s, name), locate(%(_txt)s, name), 99999),
|
||||||
idx desc,
|
idx desc,
|
||||||
`tabProject`.name asc
|
`tabProject`.name asc
|
||||||
limit {start}, {page_len}""".format(
|
limit {page_len} offset {start}""".format(
|
||||||
fields=", ".join(["`tabProject`.{0}".format(f) for f in fields]),
|
fields=", ".join(["`tabProject`.{0}".format(f) for f in fields]),
|
||||||
cond=cond,
|
cond=cond,
|
||||||
scond=searchfields,
|
scond=searchfields,
|
||||||
@@ -383,7 +383,7 @@ def get_delivery_notes_to_be_billed(doctype, txt, searchfield, start, page_len,
|
|||||||
and return_against in (select name from `tabDelivery Note` where per_billed < 100)
|
and return_against in (select name from `tabDelivery Note` where per_billed < 100)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
%(mcond)s order by `tabDelivery Note`.`%(key)s` asc limit %(start)s, %(page_len)s
|
%(mcond)s order by `tabDelivery Note`.`%(key)s` asc limit %(page_len)s offset %(start)s
|
||||||
"""
|
"""
|
||||||
% {
|
% {
|
||||||
"fields": ", ".join(["`tabDelivery Note`.{0}".format(f) for f in fields]),
|
"fields": ", ".join(["`tabDelivery Note`.{0}".format(f) for f in fields]),
|
||||||
@@ -456,7 +456,7 @@ def get_batch_no(doctype, txt, searchfield, start, page_len, filters):
|
|||||||
{match_conditions}
|
{match_conditions}
|
||||||
group by batch_no {having_clause}
|
group by batch_no {having_clause}
|
||||||
order by batch.expiry_date, sle.batch_no desc
|
order by batch.expiry_date, sle.batch_no desc
|
||||||
limit %(start)s, %(page_len)s""".format(
|
limit %(page_len)s offset %(start)s""".format(
|
||||||
search_columns=search_columns,
|
search_columns=search_columns,
|
||||||
cond=cond,
|
cond=cond,
|
||||||
match_conditions=get_match_cond(doctype),
|
match_conditions=get_match_cond(doctype),
|
||||||
@@ -483,7 +483,7 @@ def get_batch_no(doctype, txt, searchfield, start, page_len, filters):
|
|||||||
{match_conditions}
|
{match_conditions}
|
||||||
|
|
||||||
order by expiry_date, name desc
|
order by expiry_date, name desc
|
||||||
limit %(start)s, %(page_len)s""".format(
|
limit %(page_len)s offset %(start)s""".format(
|
||||||
cond,
|
cond,
|
||||||
search_columns=search_columns,
|
search_columns=search_columns,
|
||||||
search_cond=search_cond,
|
search_cond=search_cond,
|
||||||
@@ -662,7 +662,7 @@ def warehouse_query(doctype, txt, searchfield, start, page_len, filters):
|
|||||||
{fcond} {mcond}
|
{fcond} {mcond}
|
||||||
order by ifnull(`tabBin`.actual_qty, 0) desc
|
order by ifnull(`tabBin`.actual_qty, 0) desc
|
||||||
limit
|
limit
|
||||||
{start}, {page_len}
|
{page_len} offset {start}
|
||||||
""".format(
|
""".format(
|
||||||
bin_conditions=get_filters_cond(
|
bin_conditions=get_filters_cond(
|
||||||
doctype, filter_dict.get("Bin"), bin_conditions, ignore_permissions=True
|
doctype, filter_dict.get("Bin"), bin_conditions, ignore_permissions=True
|
||||||
|
|||||||
@@ -35,7 +35,8 @@ status_map = {
|
|||||||
["Draft", None],
|
["Draft", None],
|
||||||
["Open", "eval:self.docstatus==1"],
|
["Open", "eval:self.docstatus==1"],
|
||||||
["Lost", "eval:self.status=='Lost'"],
|
["Lost", "eval:self.status=='Lost'"],
|
||||||
["Ordered", "has_sales_order"],
|
["Partially Ordered", "is_partially_ordered"],
|
||||||
|
["Ordered", "is_fully_ordered"],
|
||||||
["Cancelled", "eval:self.docstatus==2"],
|
["Cancelled", "eval:self.docstatus==2"],
|
||||||
],
|
],
|
||||||
"Sales Order": [
|
"Sales Order": [
|
||||||
|
|||||||
@@ -724,6 +724,57 @@ class TestSubcontractingController(FrappeTestCase):
|
|||||||
self.assertEqual(value.qty, details.qty)
|
self.assertEqual(value.qty, details.qty)
|
||||||
self.assertEqual(value.batch_no, details.batch_no)
|
self.assertEqual(value.batch_no, details.batch_no)
|
||||||
|
|
||||||
|
def test_sco_supplied_qty(self):
|
||||||
|
"""
|
||||||
|
Check if 'Supplied Qty' in SCO's Supplied Items table is reset on submit/cancel.
|
||||||
|
"""
|
||||||
|
set_backflush_based_on("Material Transferred for Subcontract")
|
||||||
|
service_items = [
|
||||||
|
{
|
||||||
|
"warehouse": "_Test Warehouse - _TC",
|
||||||
|
"item_code": "Subcontracted Service Item 1",
|
||||||
|
"qty": 5,
|
||||||
|
"rate": 100,
|
||||||
|
"fg_item": "Subcontracted Item SA1",
|
||||||
|
"fg_item_qty": 5,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"warehouse": "_Test Warehouse - _TC",
|
||||||
|
"item_code": "Subcontracted Service Item 5",
|
||||||
|
"qty": 6,
|
||||||
|
"rate": 100,
|
||||||
|
"fg_item": "Subcontracted Item SA5",
|
||||||
|
"fg_item_qty": 6,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
sco = get_subcontracting_order(service_items=service_items)
|
||||||
|
rm_items = [
|
||||||
|
{"item_code": "Subcontracted SRM Item 1", "qty": 5, "main_item_code": "Subcontracted Item SA1"},
|
||||||
|
{"item_code": "Subcontracted SRM Item 2", "qty": 5, "main_item_code": "Subcontracted Item SA1"},
|
||||||
|
{"item_code": "Subcontracted SRM Item 3", "qty": 5, "main_item_code": "Subcontracted Item SA1"},
|
||||||
|
{"item_code": "Subcontracted SRM Item 5", "qty": 6, "main_item_code": "Subcontracted Item SA5"},
|
||||||
|
{"item_code": "Subcontracted SRM Item 4", "qty": 6, "main_item_code": "Subcontracted Item SA5"},
|
||||||
|
]
|
||||||
|
itemwise_details = make_stock_in_entry(rm_items=rm_items)
|
||||||
|
|
||||||
|
for item in rm_items:
|
||||||
|
item["sco_rm_detail"] = sco.items[0].name if item.get("qty") == 5 else sco.items[1].name
|
||||||
|
|
||||||
|
se = make_stock_transfer_entry(
|
||||||
|
sco_no=sco.name,
|
||||||
|
rm_items=rm_items,
|
||||||
|
itemwise_details=copy.deepcopy(itemwise_details),
|
||||||
|
)
|
||||||
|
|
||||||
|
sco.reload()
|
||||||
|
for item in sco.get("supplied_items"):
|
||||||
|
self.assertIn(item.supplied_qty, [5.0, 6.0])
|
||||||
|
|
||||||
|
se.cancel()
|
||||||
|
sco.reload()
|
||||||
|
for item in sco.get("supplied_items"):
|
||||||
|
self.assertEqual(item.supplied_qty, 0.0)
|
||||||
|
|
||||||
|
|
||||||
def add_second_row_in_scr(scr):
|
def add_second_row_in_scr(scr):
|
||||||
item_dict = {}
|
item_dict = {}
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ def get_work_orders(doctype, txt, searchfield, start, page_len, filters):
|
|||||||
return frappe.db.sql(
|
return frappe.db.sql(
|
||||||
"""select name from `tabWork Order`
|
"""select name from `tabWork Order`
|
||||||
where name like %(name)s and {0} and produced_qty > qty and docstatus = 1
|
where name like %(name)s and {0} and produced_qty > qty and docstatus = 1
|
||||||
order by name limit {1}, {2}""".format(
|
order by name limit {2} offset {1}""".format(
|
||||||
cond, start, page_len
|
cond, start, page_len
|
||||||
),
|
),
|
||||||
{"name": "%%%s%%" % txt},
|
{"name": "%%%s%%" % txt},
|
||||||
|
|||||||
@@ -970,7 +970,7 @@ def get_payroll_entries_for_jv(doctype, txt, searchfield, start, page_len, filte
|
|||||||
and name not in
|
and name not in
|
||||||
(select reference_name from `tabJournal Entry Account`
|
(select reference_name from `tabJournal Entry Account`
|
||||||
where reference_type="Payroll Entry")
|
where reference_type="Payroll Entry")
|
||||||
order by name limit %(start)s, %(page_len)s""".format(
|
order by name limit %(page_len)s offset %(start)s""".format(
|
||||||
key=searchfield
|
key=searchfield
|
||||||
),
|
),
|
||||||
{"txt": "%%%s%%" % txt, "start": start, "page_len": page_len},
|
{"txt": "%%%s%%" % txt, "start": start, "page_len": page_len},
|
||||||
@@ -1039,7 +1039,7 @@ def employee_query(doctype, txt, searchfield, start, page_len, filters):
|
|||||||
if(locate(%(_txt)s, employee_name), locate(%(_txt)s, employee_name), 99999),
|
if(locate(%(_txt)s, employee_name), locate(%(_txt)s, employee_name), 99999),
|
||||||
idx desc,
|
idx desc,
|
||||||
name, employee_name
|
name, employee_name
|
||||||
limit %(start)s, %(page_len)s""".format(
|
limit %(page_len)s offset %(start)s""".format(
|
||||||
**{
|
**{
|
||||||
"key": searchfield,
|
"key": searchfield,
|
||||||
"fcond": get_filters_cond(doctype, filters, conditions),
|
"fcond": get_filters_cond(doctype, filters, conditions),
|
||||||
|
|||||||
@@ -391,7 +391,7 @@ def get_users_for_project(doctype, txt, searchfield, start, page_len, filters):
|
|||||||
if(locate(%(_txt)s, full_name), locate(%(_txt)s, full_name), 99999),
|
if(locate(%(_txt)s, full_name), locate(%(_txt)s, full_name), 99999),
|
||||||
idx desc,
|
idx desc,
|
||||||
name, full_name
|
name, full_name
|
||||||
limit %(start)s, %(page_len)s""".format(
|
limit %(page_len)s offset %(start)s""".format(
|
||||||
**{
|
**{
|
||||||
"key": searchfield,
|
"key": searchfield,
|
||||||
"fcond": get_filters_cond(doctype, filters, conditions),
|
"fcond": get_filters_cond(doctype, filters, conditions),
|
||||||
|
|||||||
@@ -288,7 +288,7 @@ def get_project(doctype, txt, searchfield, start, page_len, filters):
|
|||||||
%(mcond)s
|
%(mcond)s
|
||||||
{search_condition}
|
{search_condition}
|
||||||
order by name
|
order by name
|
||||||
limit %(start)s, %(page_len)s""".format(
|
limit %(page_len)s offset %(start)s""".format(
|
||||||
search_columns=search_columns, search_condition=search_cond
|
search_columns=search_columns, search_condition=search_cond
|
||||||
),
|
),
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -328,7 +328,7 @@ def get_timesheet(doctype, txt, searchfield, start, page_len, filters):
|
|||||||
ts.status in ('Submitted', 'Payslip') and tsd.parent = ts.name and
|
ts.status in ('Submitted', 'Payslip') and tsd.parent = ts.name and
|
||||||
tsd.docstatus = 1 and ts.total_billable_amount > 0
|
tsd.docstatus = 1 and ts.total_billable_amount > 0
|
||||||
and tsd.parent LIKE %(txt)s {condition}
|
and tsd.parent LIKE %(txt)s {condition}
|
||||||
order by tsd.parent limit %(start)s, %(page_len)s""".format(
|
order by tsd.parent limit %(page_len)s offset %(start)s""".format(
|
||||||
condition=condition
|
condition=condition
|
||||||
),
|
),
|
||||||
{
|
{
|
||||||
@@ -515,7 +515,7 @@ def get_timesheets_list(
|
|||||||
tsd.project IN %(projects)s
|
tsd.project IN %(projects)s
|
||||||
)
|
)
|
||||||
ORDER BY `end_date` ASC
|
ORDER BY `end_date` ASC
|
||||||
LIMIT {0}, {1}
|
LIMIT {1} offset {0}
|
||||||
""".format(
|
""".format(
|
||||||
limit_start, limit_page_length
|
limit_start, limit_page_length
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ def query_task(doctype, txt, searchfield, start, page_len, filters):
|
|||||||
case when `%s` like %s then 0 else 1 end,
|
case when `%s` like %s then 0 else 1 end,
|
||||||
`%s`,
|
`%s`,
|
||||||
subject
|
subject
|
||||||
limit %s, %s"""
|
limit %s offset %s"""
|
||||||
% (searchfield, "%s", "%s", match_conditions, "%s", searchfield, "%s", searchfield, "%s", "%s"),
|
% (searchfield, "%s", "%s", match_conditions, "%s", searchfield, "%s", searchfield, "%s", "%s"),
|
||||||
(search_string, search_string, order_by_string, order_by_string, start, page_len),
|
(search_string, search_string, order_by_string, order_by_string, page_len, start),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -287,7 +287,7 @@ def get_regional_address_details(party_details, doctype, company):
|
|||||||
return party_details
|
return party_details
|
||||||
|
|
||||||
if (
|
if (
|
||||||
doctype in ("Sales Invoice", "Delivery Note", "Sales Order")
|
doctype in ("Sales Invoice", "Delivery Note", "Sales Order", "Quotation")
|
||||||
and party_details.company_gstin
|
and party_details.company_gstin
|
||||||
and party_details.company_gstin[:2] != party_details.place_of_supply[:2]
|
and party_details.company_gstin[:2] != party_details.place_of_supply[:2]
|
||||||
) or (
|
) or (
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ def get_new_item_code(doctype, txt, searchfield, start, page_len, filters):
|
|||||||
return frappe.db.sql(
|
return frappe.db.sql(
|
||||||
"""select name, item_name, description from tabItem
|
"""select name, item_name, description from tabItem
|
||||||
where is_stock_item=0 and name not in (select name from `tabProduct Bundle`)
|
where is_stock_item=0 and name not in (select name from `tabProduct Bundle`)
|
||||||
and %s like %s %s limit %s, %s"""
|
and %s like %s %s limit %s offset %s"""
|
||||||
% (searchfield, "%s", get_match_cond(doctype), "%s", "%s"),
|
% (searchfield, "%s", get_match_cond(doctype), "%s", "%s"),
|
||||||
("%%%s%%" % txt, start, page_len),
|
("%%%s%%" % txt, page_len, start),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -20,6 +20,20 @@ frappe.ui.form.on('Quotation', {
|
|||||||
|
|
||||||
frm.set_df_property('packed_items', 'cannot_add_rows', true);
|
frm.set_df_property('packed_items', 'cannot_add_rows', true);
|
||||||
frm.set_df_property('packed_items', 'cannot_delete_rows', true);
|
frm.set_df_property('packed_items', 'cannot_delete_rows', true);
|
||||||
|
|
||||||
|
frm.set_query('company_address', function(doc) {
|
||||||
|
if(!doc.company) {
|
||||||
|
frappe.throw(__('Please set Company'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
query: 'frappe.contacts.doctype.address.address.address_query',
|
||||||
|
filters: {
|
||||||
|
link_doctype: 'Company',
|
||||||
|
link_name: doc.company
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
refresh: function(frm) {
|
refresh: function(frm) {
|
||||||
@@ -70,7 +84,7 @@ erpnext.selling.QuotationController = class QuotationController extends erpnext.
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(doc.docstatus == 1 && doc.status!=='Lost') {
|
if(doc.docstatus == 1 && !(['Lost', 'Ordered']).includes(doc.status)) {
|
||||||
if(!doc.valid_till || frappe.datetime.get_diff(doc.valid_till, frappe.datetime.get_today()) >= 0) {
|
if(!doc.valid_till || frappe.datetime.get_diff(doc.valid_till, frappe.datetime.get_today()) >= 0) {
|
||||||
cur_frm.add_custom_button(__('Sales Order'),
|
cur_frm.add_custom_button(__('Sales Order'),
|
||||||
cur_frm.cscript['Make Sales Order'], __('Create'));
|
cur_frm.cscript['Make Sales Order'], __('Create'));
|
||||||
|
|||||||
@@ -897,7 +897,7 @@
|
|||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"oldfieldname": "status",
|
"oldfieldname": "status",
|
||||||
"oldfieldtype": "Select",
|
"oldfieldtype": "Select",
|
||||||
"options": "Draft\nOpen\nReplied\nOrdered\nLost\nCancelled\nExpired",
|
"options": "Draft\nOpen\nReplied\nPartially Ordered\nOrdered\nLost\nCancelled\nExpired",
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"read_only": 1,
|
"read_only": 1,
|
||||||
"reqd": 1
|
"reqd": 1
|
||||||
@@ -986,7 +986,7 @@
|
|||||||
"idx": 82,
|
"idx": 82,
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2022-04-07 11:01:31.157084",
|
"modified": "2022-06-11 20:35:32.635804",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Selling",
|
"module": "Selling",
|
||||||
"name": "Quotation",
|
"name": "Quotation",
|
||||||
|
|||||||
@@ -70,8 +70,32 @@ class Quotation(SellingController):
|
|||||||
title=_("Unpublished Item"),
|
title=_("Unpublished Item"),
|
||||||
)
|
)
|
||||||
|
|
||||||
def has_sales_order(self):
|
def get_ordered_status(self):
|
||||||
return frappe.db.get_value("Sales Order Item", {"prevdoc_docname": self.name, "docstatus": 1})
|
ordered_items = frappe._dict(
|
||||||
|
frappe.db.get_all(
|
||||||
|
"Sales Order Item",
|
||||||
|
{"prevdoc_docname": self.name, "docstatus": 1},
|
||||||
|
["item_code", "sum(qty)"],
|
||||||
|
group_by="item_code",
|
||||||
|
as_list=1,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
status = "Open"
|
||||||
|
if ordered_items:
|
||||||
|
status = "Ordered"
|
||||||
|
|
||||||
|
for item in self.get("items"):
|
||||||
|
if item.qty > ordered_items.get(item.item_code, 0.0):
|
||||||
|
status = "Partially Ordered"
|
||||||
|
|
||||||
|
return status
|
||||||
|
|
||||||
|
def is_fully_ordered(self):
|
||||||
|
return self.get_ordered_status() == "Ordered"
|
||||||
|
|
||||||
|
def is_partially_ordered(self):
|
||||||
|
return self.get_ordered_status() == "Partially Ordered"
|
||||||
|
|
||||||
def update_lead(self):
|
def update_lead(self):
|
||||||
if self.quotation_to == "Lead" and self.party_name:
|
if self.quotation_to == "Lead" and self.party_name:
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ frappe.listview_settings['Quotation'] = {
|
|||||||
get_indicator: function(doc) {
|
get_indicator: function(doc) {
|
||||||
if(doc.status==="Open") {
|
if(doc.status==="Open") {
|
||||||
return [__("Open"), "orange", "status,=,Open"];
|
return [__("Open"), "orange", "status,=,Open"];
|
||||||
|
} else if (doc.status==="Partially Ordered") {
|
||||||
|
return [__("Partially Ordered"), "yellow", "status,=,Partially Ordered"];
|
||||||
} else if(doc.status==="Ordered") {
|
} else if(doc.status==="Ordered") {
|
||||||
return [__("Ordered"), "green", "status,=,Ordered"];
|
return [__("Ordered"), "green", "status,=,Ordered"];
|
||||||
} else if(doc.status==="Lost") {
|
} else if(doc.status==="Lost") {
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ def get_items(start, page_length, price_list, item_group, pos_profile, search_te
|
|||||||
ORDER BY
|
ORDER BY
|
||||||
item.name asc
|
item.name asc
|
||||||
LIMIT
|
LIMIT
|
||||||
{start}, {page_length}""".format(
|
{page_length} offset {start}""".format(
|
||||||
start=start,
|
start=start,
|
||||||
page_length=page_length,
|
page_length=page_length,
|
||||||
lft=lft,
|
lft=lft,
|
||||||
@@ -204,7 +204,7 @@ def item_group_query(doctype, txt, searchfield, start, page_len, filters):
|
|||||||
|
|
||||||
return frappe.db.sql(
|
return frappe.db.sql(
|
||||||
""" select distinct name from `tabItem Group`
|
""" select distinct name from `tabItem Group`
|
||||||
where {condition} and (name like %(txt)s) limit {start}, {page_len}""".format(
|
where {condition} and (name like %(txt)s) limit {page_len} offset {start}""".format(
|
||||||
condition=cond, start=start, page_len=page_len
|
condition=cond, start=start, page_len=page_len
|
||||||
),
|
),
|
||||||
{"txt": "%%%s%%" % txt},
|
{"txt": "%%%s%%" % txt},
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ def get_party_type(doctype, txt, searchfield, start, page_len, filters):
|
|||||||
return frappe.db.sql(
|
return frappe.db.sql(
|
||||||
"""select name from `tabParty Type`
|
"""select name from `tabParty Type`
|
||||||
where `{key}` LIKE %(txt)s {cond}
|
where `{key}` LIKE %(txt)s {cond}
|
||||||
order by name limit %(start)s, %(page_len)s""".format(
|
order by name limit %(page_len)s offset %(start)s""".format(
|
||||||
key=searchfield, cond=cond
|
key=searchfield, cond=cond
|
||||||
),
|
),
|
||||||
{"txt": "%" + txt + "%", "start": start, "page_len": page_len},
|
{"txt": "%" + txt + "%", "start": start, "page_len": page_len},
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ def get_alternative_items(doctype, txt, searchfield, start, page_len, filters):
|
|||||||
union
|
union
|
||||||
(select item_code from `tabItem Alternative`
|
(select item_code from `tabItem Alternative`
|
||||||
where alternative_item_code = %(item_code)s and item_code like %(txt)s
|
where alternative_item_code = %(item_code)s and item_code like %(txt)s
|
||||||
and two_way = 1) limit {0}, {1}
|
and two_way = 1) limit {1} offset {0}
|
||||||
""".format(
|
""".format(
|
||||||
start, page_len
|
start, page_len
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -203,7 +203,7 @@ def item_details(doctype, txt, searchfield, start, page_len, filters):
|
|||||||
where name in ( select item_code FROM `tabDelivery Note Item`
|
where name in ( select item_code FROM `tabDelivery Note Item`
|
||||||
where parent= %s)
|
where parent= %s)
|
||||||
and %s like "%s" %s
|
and %s like "%s" %s
|
||||||
limit %s, %s """
|
limit %s offset %s """
|
||||||
% ("%s", searchfield, "%s", get_match_cond(doctype), "%s", "%s"),
|
% ("%s", searchfield, "%s", get_match_cond(doctype), "%s", "%s"),
|
||||||
((filters or {}).get("delivery_note"), "%%%s%%" % txt, start, page_len),
|
((filters or {}).get("delivery_note"), "%%%s%%" % txt, page_len, start),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -232,7 +232,7 @@ def item_query(doctype, txt, searchfield, start, page_len, filters):
|
|||||||
FROM `tab{doc}`
|
FROM `tab{doc}`
|
||||||
WHERE parent=%(parent)s and docstatus < 2 and item_code like %(txt)s
|
WHERE parent=%(parent)s and docstatus < 2 and item_code like %(txt)s
|
||||||
{qi_condition} {cond} {mcond}
|
{qi_condition} {cond} {mcond}
|
||||||
ORDER BY item_code limit {start}, {page_len}
|
ORDER BY item_code limit {page_len} offset {start}
|
||||||
""".format(
|
""".format(
|
||||||
doc=filters.get("from"),
|
doc=filters.get("from"),
|
||||||
cond=cond,
|
cond=cond,
|
||||||
@@ -252,7 +252,7 @@ def item_query(doctype, txt, searchfield, start, page_len, filters):
|
|||||||
WHERE name = %(reference_name)s and docstatus < 2 and production_item like %(txt)s
|
WHERE name = %(reference_name)s and docstatus < 2 and production_item like %(txt)s
|
||||||
{qi_condition} {cond} {mcond}
|
{qi_condition} {cond} {mcond}
|
||||||
ORDER BY production_item
|
ORDER BY production_item
|
||||||
LIMIT {start}, {page_len}
|
limit {page_len} offset {start}
|
||||||
""".format(
|
""".format(
|
||||||
doc=filters.get("from"),
|
doc=filters.get("from"),
|
||||||
cond=cond,
|
cond=cond,
|
||||||
|
|||||||
@@ -2005,24 +2005,30 @@ class StockEntry(StockController):
|
|||||||
):
|
):
|
||||||
|
|
||||||
# Get SCO Supplied Items Details
|
# Get SCO Supplied Items Details
|
||||||
parent = frappe.qb.DocType("Subcontracting Order")
|
sco_supplied_items = frappe.db.get_all(
|
||||||
child = frappe.qb.DocType("Subcontracting Order Supplied Item")
|
"Subcontracting Order Supplied Item",
|
||||||
item_wh = (
|
filters={"parent": self.subcontracting_order},
|
||||||
frappe.qb.from_(parent)
|
fields=["name", "rm_item_code", "reserve_warehouse"],
|
||||||
.inner_join(child)
|
)
|
||||||
.on(parent.name == child.parent)
|
|
||||||
.select(child.rm_item_code, child.reserve_warehouse)
|
|
||||||
.where(parent.name == self.subcontracting_order)
|
|
||||||
).run(as_list=True)
|
|
||||||
|
|
||||||
item_wh = frappe._dict(item_wh)
|
|
||||||
|
|
||||||
|
# Get Items Supplied in Stock Entries against SCO
|
||||||
supplied_items = get_supplied_items(self.subcontracting_order)
|
supplied_items = get_supplied_items(self.subcontracting_order)
|
||||||
for name, item in supplied_items.items():
|
|
||||||
frappe.db.set_value("Subcontracting Order Supplied Item", name, item)
|
|
||||||
|
|
||||||
# Update reserved sub contracted quantity in bin based on Supplied Item Details and
|
for row in sco_supplied_items:
|
||||||
|
key, item = row.name, {}
|
||||||
|
if not supplied_items.get(key):
|
||||||
|
# no stock transferred against SCO Supplied Items row
|
||||||
|
item = {"supplied_qty": 0, "returned_qty": 0, "total_supplied_qty": 0}
|
||||||
|
else:
|
||||||
|
item = supplied_items.get(key)
|
||||||
|
|
||||||
|
frappe.db.set_value("Subcontracting Order Supplied Item", row.name, item)
|
||||||
|
|
||||||
|
# RM Item-Reserve Warehouse Dict
|
||||||
|
item_wh = {x.get("rm_item_code"): x.get("reserve_warehouse") for x in sco_supplied_items}
|
||||||
|
|
||||||
for d in self.get("items"):
|
for d in self.get("items"):
|
||||||
|
# Update reserved sub contracted quantity in bin based on Supplied Item Details and
|
||||||
item_code = d.get("original_item") or d.get("item_code")
|
item_code = d.get("original_item") or d.get("item_code")
|
||||||
reserve_warehouse = item_wh.get(item_code)
|
reserve_warehouse = item_wh.get(item_code)
|
||||||
if not (reserve_warehouse and item_code):
|
if not (reserve_warehouse and item_code):
|
||||||
|
|||||||
@@ -56,7 +56,10 @@ def get_product_data(search=None, start=0, limit=12):
|
|||||||
search = "%" + cstr(search) + "%"
|
search = "%" + cstr(search) + "%"
|
||||||
|
|
||||||
# order by
|
# order by
|
||||||
query += """ ORDER BY ranking desc, modified desc limit %s, %s""" % (cint(start), cint(limit))
|
query += """ ORDER BY ranking desc, modified desc limit %s offset %s""" % (
|
||||||
|
cint(limit),
|
||||||
|
cint(start),
|
||||||
|
)
|
||||||
|
|
||||||
return frappe.db.sql(query, {"search": search}, as_dict=1) # nosemgrep
|
return frappe.db.sql(query, {"search": search}, as_dict=1) # nosemgrep
|
||||||
|
|
||||||
|
|||||||
@@ -1,46 +0,0 @@
|
|||||||
# Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and Contributors
|
|
||||||
# See license.txt
|
|
||||||
|
|
||||||
|
|
||||||
import frappe
|
|
||||||
from frappe import _
|
|
||||||
from frappe.utils.bot import BotParser
|
|
||||||
|
|
||||||
|
|
||||||
class FindItemBot(BotParser):
|
|
||||||
def get_reply(self):
|
|
||||||
if self.startswith("where is", "find item", "locate"):
|
|
||||||
if not frappe.has_permission("Warehouse"):
|
|
||||||
raise frappe.PermissionError
|
|
||||||
|
|
||||||
item = "%{0}%".format(self.strip_words(self.query, "where is", "find item", "locate"))
|
|
||||||
items = frappe.db.sql(
|
|
||||||
"""select name from `tabItem` where item_code like %(txt)s
|
|
||||||
or item_name like %(txt)s or description like %(txt)s""",
|
|
||||||
dict(txt=item),
|
|
||||||
)
|
|
||||||
|
|
||||||
if items:
|
|
||||||
out = []
|
|
||||||
warehouses = frappe.get_all("Warehouse")
|
|
||||||
for item in items:
|
|
||||||
found = False
|
|
||||||
for warehouse in warehouses:
|
|
||||||
qty = frappe.db.get_value(
|
|
||||||
"Bin", {"item_code": item[0], "warehouse": warehouse.name}, "actual_qty"
|
|
||||||
)
|
|
||||||
if qty:
|
|
||||||
out.append(
|
|
||||||
_("{0} units of [{1}](/app/Form/Item/{1}) found in [{2}](/app/Form/Warehouse/{2})").format(
|
|
||||||
qty, item[0], warehouse.name
|
|
||||||
)
|
|
||||||
)
|
|
||||||
found = True
|
|
||||||
|
|
||||||
if not found:
|
|
||||||
out.append(_("[{0}](/app/Form/Item/{0}) is out of stock").format(item[0]))
|
|
||||||
|
|
||||||
return "\n\n".join(out)
|
|
||||||
|
|
||||||
else:
|
|
||||||
return _("Did not find any item called {0}").format(item)
|
|
||||||
Reference in New Issue
Block a user