Merge branch 'develop' into refactor-addiional-salary

This commit is contained in:
Nabin Hait 2020-05-05 14:43:07 +05:30 committed by GitHub
commit 9be11455a5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 146 additions and 29 deletions

View File

@ -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)

View File

@ -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":

View File

@ -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

View File

@ -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()

View File

@ -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()

View File

@ -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:

View File

@ -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)

View File

@ -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,

View File

@ -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

View File

@ -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)

View File

@ -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",

View File

@ -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)