Merge branch 'develop' into refactor-addiional-salary
This commit is contained in:
commit
9be11455a5
@ -162,7 +162,7 @@ def get_default_price_list(party):
|
||||
def set_price_list(party_details, party, party_type, given_price_list, pos=None):
|
||||
# price list
|
||||
price_list = get_permitted_documents('Price List')
|
||||
|
||||
|
||||
# if there is only one permitted document based on user permissions, set it
|
||||
if price_list and len(price_list) == 1:
|
||||
price_list = price_list[0]
|
||||
@ -465,23 +465,25 @@ def get_timeline_data(doctype, name):
|
||||
from frappe.desk.form.load import get_communication_data
|
||||
|
||||
out = {}
|
||||
fields = 'date(creation), count(name)'
|
||||
fields = 'creation, count(*)'
|
||||
after = add_years(None, -1).strftime('%Y-%m-%d')
|
||||
group_by='group by date(creation)'
|
||||
group_by='group by Date(creation)'
|
||||
|
||||
data = get_communication_data(doctype, name, after=after, group_by='group by date(creation)',
|
||||
fields='date(C.creation) as creation, count(C.name)',as_dict=False)
|
||||
data = get_communication_data(doctype, name, after=after, group_by='group by creation',
|
||||
fields='C.creation as creation, count(C.name)',as_dict=False)
|
||||
|
||||
# fetch and append data from Activity Log
|
||||
data += frappe.db.sql("""select {fields}
|
||||
from `tabActivity Log`
|
||||
where (reference_doctype="{doctype}" and reference_name="{name}")
|
||||
or (timeline_doctype in ("{doctype}") and timeline_name="{name}")
|
||||
or (reference_doctype in ("Quotation", "Opportunity") and timeline_name="{name}")
|
||||
where (reference_doctype=%(doctype)s and reference_name=%(name)s)
|
||||
or (timeline_doctype in (%(doctype)s) and timeline_name=%(name)s)
|
||||
or (reference_doctype in ("Quotation", "Opportunity") and timeline_name=%(name)s)
|
||||
and status!='Success' and creation > {after}
|
||||
{group_by} order by creation desc
|
||||
""".format(doctype=frappe.db.escape(doctype), name=frappe.db.escape(name), fields=fields,
|
||||
group_by=group_by, after=after), as_dict=False)
|
||||
""".format(fields=fields, group_by=group_by, after=after), {
|
||||
"doctype": doctype,
|
||||
"name": name
|
||||
}, as_dict=False)
|
||||
|
||||
timeline_items = dict(data)
|
||||
|
||||
|
@ -74,7 +74,7 @@ def validate_returned_items(doc):
|
||||
for d in doc.get("items"):
|
||||
if d.item_code and (flt(d.qty) < 0 or flt(d.get('received_qty')) < 0):
|
||||
if d.item_code not in valid_items:
|
||||
frappe.throw(_("Row # {0}: Returned Item {1} does not exists in {2} {3}")
|
||||
frappe.throw(_("Row # {0}: Returned Item {1} does not exist in {2} {3}")
|
||||
.format(d.idx, d.item_code, doc.doctype, doc.return_against))
|
||||
else:
|
||||
ref = valid_items.get(d.item_code, frappe._dict())
|
||||
@ -266,6 +266,8 @@ def make_return_doc(doctype, source_name, target_doc=None):
|
||||
target_doc.purchase_order = source_doc.purchase_order
|
||||
target_doc.purchase_order_item = source_doc.purchase_order_item
|
||||
target_doc.rejected_warehouse = source_doc.rejected_warehouse
|
||||
target_doc.purchase_receipt_item = source_doc.name
|
||||
|
||||
elif doctype == "Purchase Invoice":
|
||||
target_doc.received_qty = -1* source_doc.received_qty
|
||||
target_doc.rejected_qty = -1* source_doc.rejected_qty
|
||||
@ -282,6 +284,7 @@ def make_return_doc(doctype, source_name, target_doc=None):
|
||||
target_doc.so_detail = source_doc.so_detail
|
||||
target_doc.si_detail = source_doc.si_detail
|
||||
target_doc.expense_account = source_doc.expense_account
|
||||
target_doc.dn_detail = source_doc.name
|
||||
if default_warehouse_for_sales_return:
|
||||
target_doc.warehouse = default_warehouse_for_sales_return
|
||||
elif doctype == "Sales Invoice":
|
||||
|
@ -662,6 +662,7 @@ erpnext.patches.v12_0.create_irs_1099_field_united_states
|
||||
erpnext.patches.v12_0.move_bank_account_swift_number_to_bank
|
||||
erpnext.patches.v12_0.rename_bank_reconciliation
|
||||
erpnext.patches.v12_0.rename_bank_reconciliation_fields # 2020-01-22
|
||||
erpnext.patches.v12_0.set_purchase_receipt_delivery_note_detail
|
||||
erpnext.patches.v12_0.add_permission_in_lower_deduction
|
||||
erpnext.patches.v12_0.set_received_qty_in_material_request_as_per_stock_uom
|
||||
erpnext.patches.v12_0.rename_account_type_doctype
|
||||
|
@ -7,4 +7,5 @@ def execute():
|
||||
return
|
||||
|
||||
frappe.reload_doc("regional", "doctype", "lower_deduction_certificate")
|
||||
add_permissions()
|
||||
frappe.reload_doc("regional", "doctype", "gstr_3b_report")
|
||||
add_permissions()
|
||||
|
@ -0,0 +1,84 @@
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from collections import defaultdict
|
||||
|
||||
def execute():
|
||||
def map_rows(doc_row, return_doc_row, detail_field, doctype):
|
||||
"""Map rows after identifying similar ones."""
|
||||
|
||||
frappe.db.sql(""" UPDATE `tab{doctype} Item` set {detail_field} = '{doc_row_name}'
|
||||
where name = '{return_doc_row_name}'""" \
|
||||
.format(doctype=doctype,
|
||||
detail_field=detail_field,
|
||||
doc_row_name=doc_row.get('name'),
|
||||
return_doc_row_name=return_doc_row.get('name'))) #nosec
|
||||
|
||||
def row_is_mappable(doc_row, return_doc_row, detail_field):
|
||||
"""Checks if two rows are similar enough to be mapped."""
|
||||
|
||||
if doc_row.item_code == return_doc_row.item_code and not return_doc_row.get(detail_field):
|
||||
if doc_row.get('batch_no') and return_doc_row.get('batch_no') and doc_row.batch_no == return_doc_row.batch_no:
|
||||
return True
|
||||
|
||||
elif doc_row.get('serial_no') and return_doc_row.get('serial_no'):
|
||||
doc_sn = doc_row.serial_no.split('\n')
|
||||
return_doc_sn = return_doc_row.serial_no.split('\n')
|
||||
|
||||
if set(doc_sn) & set(return_doc_sn):
|
||||
# if two rows have serial nos in common, map them
|
||||
return True
|
||||
|
||||
elif doc_row.rate == return_doc_row.rate:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def make_return_document_map(doctype, return_document_map):
|
||||
"""Returns a map of documents and it's return documents.
|
||||
Format => { 'document' : ['return_document_1','return_document_2'] }"""
|
||||
|
||||
return_against_documents = frappe.db.sql("""
|
||||
SELECT
|
||||
return_against as document, name as return_document
|
||||
FROM `tab{doctype}`
|
||||
WHERE
|
||||
is_return = 1 and docstatus = 1""".format(doctype=doctype),as_dict=1) #nosec
|
||||
|
||||
for entry in return_against_documents:
|
||||
return_document_map[entry.document].append(entry.return_document)
|
||||
|
||||
return return_document_map
|
||||
|
||||
def set_document_detail_in_return_document(doctype):
|
||||
"""Map each row of the original document in the return document."""
|
||||
mapped = []
|
||||
return_document_map = defaultdict(list)
|
||||
detail_field = "purchase_receipt_item" if doctype=="Purchase Receipt" else "dn_detail"
|
||||
|
||||
child_doc = frappe.scrub("{0} Item".format(doctype))
|
||||
frappe.reload_doc("stock", "doctype", child_doc)
|
||||
|
||||
return_document_map = make_return_document_map(doctype, return_document_map)
|
||||
|
||||
#iterate through original documents and its return documents
|
||||
for docname in return_document_map:
|
||||
doc_items = frappe.get_doc(doctype, docname).get("items")
|
||||
for return_doc in return_document_map[docname]:
|
||||
return_doc_items = frappe.get_doc(doctype, return_doc).get("items")
|
||||
|
||||
#iterate through return document items and original document items for mapping
|
||||
for return_item in return_doc_items:
|
||||
for doc_item in doc_items:
|
||||
if row_is_mappable(doc_item, return_item, detail_field) and doc_item.get('name') not in mapped:
|
||||
map_rows(doc_item, return_item, detail_field, doctype)
|
||||
mapped.append(doc_item.get('name'))
|
||||
break
|
||||
else:
|
||||
continue
|
||||
|
||||
set_document_detail_in_return_document("Purchase Receipt")
|
||||
set_document_detail_in_return_document("Delivery Note")
|
||||
frappe.db.commit()
|
||||
|
||||
|
||||
|
@ -388,13 +388,12 @@ def get_invoiced_qty_map(delivery_note):
|
||||
|
||||
def get_returned_qty_map(delivery_note):
|
||||
"""returns a map: {so_detail: returned_qty}"""
|
||||
returned_qty_map = frappe._dict(frappe.db.sql("""select dn_item.item_code, sum(abs(dn_item.qty)) as qty
|
||||
returned_qty_map = frappe._dict(frappe.db.sql("""select dn_item.dn_detail, abs(dn_item.qty) as qty
|
||||
from `tabDelivery Note Item` dn_item, `tabDelivery Note` dn
|
||||
where dn.name = dn_item.parent
|
||||
and dn.docstatus = 1
|
||||
and dn.is_return = 1
|
||||
and dn.return_against = %s
|
||||
group by dn_item.item_code
|
||||
""", delivery_note))
|
||||
|
||||
return returned_qty_map
|
||||
@ -413,7 +412,7 @@ def make_sales_invoice(source_name, target_doc=None):
|
||||
target.run_method("set_po_nos")
|
||||
|
||||
if len(target.get("items")) == 0:
|
||||
frappe.throw(_("All these items have already been invoiced"))
|
||||
frappe.throw(_("All these items have already been Invoiced/Returned"))
|
||||
|
||||
target.run_method("calculate_taxes_and_totals")
|
||||
|
||||
@ -438,9 +437,9 @@ def make_sales_invoice(source_name, target_doc=None):
|
||||
pending_qty = item_row.qty - invoiced_qty_map.get(item_row.name, 0)
|
||||
|
||||
returned_qty = 0
|
||||
if returned_qty_map.get(item_row.item_code, 0) > 0:
|
||||
returned_qty = flt(returned_qty_map.get(item_row.item_code, 0))
|
||||
returned_qty_map[item_row.item_code] -= pending_qty
|
||||
if returned_qty_map.get(item_row.name, 0) > 0:
|
||||
returned_qty = flt(returned_qty_map.get(item_row.name, 0))
|
||||
returned_qty_map[item_row.name] -= pending_qty
|
||||
|
||||
if returned_qty:
|
||||
if returned_qty >= pending_qty:
|
||||
|
@ -612,6 +612,7 @@ class TestDeliveryNote(unittest.TestCase):
|
||||
dn1 = create_delivery_note(is_return=1, return_against=dn.name, qty=-1, do_not_submit=True)
|
||||
dn1.items[0].against_sales_order = so.name
|
||||
dn1.items[0].so_detail = so.items[0].name
|
||||
dn1.items[0].dn_detail = dn.items[0].name
|
||||
dn1.submit()
|
||||
|
||||
si = make_sales_invoice(dn.name)
|
||||
@ -638,7 +639,9 @@ class TestDeliveryNote(unittest.TestCase):
|
||||
si1.save()
|
||||
si1.submit()
|
||||
|
||||
create_delivery_note(is_return=1, return_against=dn.name, qty=-2)
|
||||
dn1 = create_delivery_note(is_return=1, return_against=dn.name, qty=-2, do_not_submit=True)
|
||||
dn1.items[0].dn_detail = dn.items[0].name
|
||||
dn1.submit()
|
||||
|
||||
si2 = make_sales_invoice(dn.name)
|
||||
self.assertEquals(si2.items[0].qty, 2)
|
||||
|
@ -67,6 +67,7 @@
|
||||
"so_detail",
|
||||
"against_sales_invoice",
|
||||
"si_detail",
|
||||
"dn_detail",
|
||||
"section_break_40",
|
||||
"batch_no",
|
||||
"serial_no",
|
||||
@ -699,6 +700,15 @@
|
||||
{
|
||||
"fieldname": "dimension_col_break",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "dn_detail",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 1,
|
||||
"label": "Against Delivery Note Item",
|
||||
"no_copy": 1,
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
}
|
||||
],
|
||||
"idx": 1,
|
||||
|
@ -504,7 +504,7 @@ def make_purchase_invoice(source_name, target_doc=None):
|
||||
|
||||
def set_missing_values(source, target):
|
||||
if len(target.get("items")) == 0:
|
||||
frappe.throw(_("All items have already been invoiced"))
|
||||
frappe.throw(_("All items have already been Invoiced/Returned"))
|
||||
|
||||
doc = frappe.get_doc(target)
|
||||
doc.ignore_pricing_rule = 1
|
||||
@ -514,11 +514,11 @@ def make_purchase_invoice(source_name, target_doc=None):
|
||||
|
||||
def update_item(source_doc, target_doc, source_parent):
|
||||
target_doc.qty, returned_qty = get_pending_qty(source_doc)
|
||||
returned_qty_map[source_doc.item_code] = returned_qty
|
||||
returned_qty_map[source_doc.name] = returned_qty
|
||||
|
||||
def get_pending_qty(item_row):
|
||||
pending_qty = item_row.qty - invoiced_qty_map.get(item_row.name, 0)
|
||||
returned_qty = flt(returned_qty_map.get(item_row.item_code, 0))
|
||||
returned_qty = flt(returned_qty_map.get(item_row.name, 0))
|
||||
if returned_qty:
|
||||
if returned_qty >= pending_qty:
|
||||
pending_qty = 0
|
||||
@ -576,13 +576,12 @@ def get_invoiced_qty_map(purchase_receipt):
|
||||
|
||||
def get_returned_qty_map(purchase_receipt):
|
||||
"""returns a map: {so_detail: returned_qty}"""
|
||||
returned_qty_map = frappe._dict(frappe.db.sql("""select pr_item.item_code, sum(abs(pr_item.qty)) as qty
|
||||
returned_qty_map = frappe._dict(frappe.db.sql("""select pr_item.purchase_receipt_item, abs(pr_item.qty) as qty
|
||||
from `tabPurchase Receipt Item` pr_item, `tabPurchase Receipt` pr
|
||||
where pr.name = pr_item.parent
|
||||
and pr.docstatus = 1
|
||||
and pr.is_return = 1
|
||||
and pr.return_against = %s
|
||||
group by pr_item.item_code
|
||||
""", purchase_receipt))
|
||||
|
||||
return returned_qty_map
|
||||
|
@ -475,6 +475,7 @@ class TestPurchaseReceipt(unittest.TestCase):
|
||||
pr1 = make_purchase_receipt(is_return=1, return_against=pr.name, qty=-1, do_not_submit=True)
|
||||
pr1.items[0].purchase_order = po.name
|
||||
pr1.items[0].purchase_order_item = po.items[0].name
|
||||
pr1.items[0].purchase_receipt_item = pr.items[0].name
|
||||
pr1.submit()
|
||||
|
||||
pi = make_purchase_invoice(pr.name)
|
||||
@ -498,7 +499,9 @@ class TestPurchaseReceipt(unittest.TestCase):
|
||||
pi1.save()
|
||||
pi1.submit()
|
||||
|
||||
make_purchase_receipt(is_return=1, return_against=pr1.name, qty=-2)
|
||||
pr2 = make_purchase_receipt(is_return=1, return_against=pr1.name, qty=-2, do_not_submit=True)
|
||||
pr2.items[0].purchase_receipt_item = pr1.items[0].name
|
||||
pr2.submit()
|
||||
|
||||
pi2 = make_purchase_invoice(pr1.name)
|
||||
self.assertEquals(pi2.items[0].qty, 2)
|
||||
|
@ -71,6 +71,7 @@
|
||||
"quality_inspection",
|
||||
"purchase_order_item",
|
||||
"material_request_item",
|
||||
"purchase_receipt_item",
|
||||
"section_break_45",
|
||||
"allow_zero_valuation_rate",
|
||||
"bom",
|
||||
@ -820,6 +821,15 @@
|
||||
"label": "Supplier Warehouse",
|
||||
"options": "Warehouse"
|
||||
},
|
||||
{
|
||||
"fieldname": "purchase_receipt_item",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 1,
|
||||
"label": "Purchase Receipt Item",
|
||||
"no_copy": 1,
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"collapsible": 1,
|
||||
"fieldname": "image_column",
|
||||
@ -829,7 +839,7 @@
|
||||
"idx": 1,
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-04-10 19:01:21.154963",
|
||||
"modified": "2020-04-28 19:01:21.154963",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Purchase Receipt Item",
|
||||
|
@ -4,11 +4,13 @@ import frappe
|
||||
from frappe.contacts.address_and_contact import filter_dynamic_link_doctypes
|
||||
|
||||
class TestSearch(unittest.TestCase):
|
||||
#Search for the word "cond", part of the word "conduire" (Lead) in french.
|
||||
# Search for the word "cond", part of the word "conduire" (Lead) in french.
|
||||
def test_contact_search_in_foreign_language(self):
|
||||
frappe.local.lang = 'fr'
|
||||
output = filter_dynamic_link_doctypes("DocType", "prospect", "name", 0, 20, {'fieldtype': 'HTML', 'fieldname': 'contact_html'})
|
||||
|
||||
output = filter_dynamic_link_doctypes("DocType", "cond", "name", 0, 20, {
|
||||
'fieldtype': 'HTML',
|
||||
'fieldname': 'contact_html'
|
||||
})
|
||||
result = [['found' for x in y if x=="Lead"] for y in output]
|
||||
self.assertTrue(['found'] in result)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user