Fixes to Return Improvements pull request
- Added "Returned Qty" in Sales and Purchase Order - Map Expense Account in Return Delivery Note - Defined some No Copy fields - Added "Credit Note" and "Debit Note" Print Headings - Fixed patch
This commit is contained in:
parent
b719c469c8
commit
fe13bfed44
@ -127,7 +127,7 @@ class PurchaseInvoice(BuyingController):
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
if cint(frappe.db.get_single_value('Buying Settings', 'maintain_same_rate')):
|
if cint(frappe.db.get_single_value('Buying Settings', 'maintain_same_rate')) and not self.is_return:
|
||||||
self.validate_rate_with_reference_doc([
|
self.validate_rate_with_reference_doc([
|
||||||
["Purchase Order", "purchase_order", "po_detail"],
|
["Purchase Order", "purchase_order", "po_detail"],
|
||||||
["Purchase Receipt", "purchase_receipt", "pr_detail"]
|
["Purchase Receipt", "purchase_receipt", "pr_detail"]
|
||||||
|
@ -7,7 +7,7 @@ frappe.listview_settings['Purchase Invoice'] = {
|
|||||||
"currency", "is_return"],
|
"currency", "is_return"],
|
||||||
get_indicator: function(doc) {
|
get_indicator: function(doc) {
|
||||||
if(cint(doc.is_return)==1) {
|
if(cint(doc.is_return)==1) {
|
||||||
return [__("Return"), "darkgrey", "is_return,=,1"];
|
return [__("Return"), "darkgrey", "is_return,=,Yes"];
|
||||||
} else if(flt(doc.outstanding_amount) > 0 && doc.docstatus==1) {
|
} else if(flt(doc.outstanding_amount) > 0 && doc.docstatus==1) {
|
||||||
if(frappe.datetime.get_diff(doc.due_date) < 0) {
|
if(frappe.datetime.get_diff(doc.due_date) < 0) {
|
||||||
return [__("Overdue"), "red", "outstanding_amount,>,0|due_date,<,Today"];
|
return [__("Overdue"), "red", "outstanding_amount,>,0|due_date,<,Today"];
|
||||||
|
@ -64,6 +64,7 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
|
|||||||
if(doc.outstanding_amount!=0 && !cint(doc.is_return)) {
|
if(doc.outstanding_amount!=0 && !cint(doc.is_return)) {
|
||||||
cur_frm.add_custom_button(__('Payment'), cur_frm.cscript.make_bank_entry).addClass("btn-primary");
|
cur_frm.add_custom_button(__('Payment'), cur_frm.cscript.make_bank_entry).addClass("btn-primary");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Show buttons only when pos view is active
|
// Show buttons only when pos view is active
|
||||||
|
@ -82,11 +82,12 @@ class SalesInvoice(SellingController):
|
|||||||
self.check_prev_docstatus()
|
self.check_prev_docstatus()
|
||||||
|
|
||||||
if self.is_return:
|
if self.is_return:
|
||||||
|
# NOTE status updating bypassed for is_return
|
||||||
self.status_updater = []
|
self.status_updater = []
|
||||||
|
|
||||||
self.update_status_updater_args()
|
self.update_status_updater_args()
|
||||||
self.update_prevdoc_status()
|
self.update_prevdoc_status()
|
||||||
|
|
||||||
if not self.is_return:
|
if not self.is_return:
|
||||||
self.update_billing_status_for_zero_amount_refdoc("Sales Order")
|
self.update_billing_status_for_zero_amount_refdoc("Sales Order")
|
||||||
self.check_credit_limit()
|
self.check_credit_limit()
|
||||||
@ -112,11 +113,12 @@ class SalesInvoice(SellingController):
|
|||||||
remove_against_link_from_jv(self.doctype, self.name)
|
remove_against_link_from_jv(self.doctype, self.name)
|
||||||
|
|
||||||
if self.is_return:
|
if self.is_return:
|
||||||
|
# NOTE status updating bypassed for is_return
|
||||||
self.status_updater = []
|
self.status_updater = []
|
||||||
|
|
||||||
self.update_status_updater_args()
|
self.update_status_updater_args()
|
||||||
self.update_prevdoc_status()
|
self.update_prevdoc_status()
|
||||||
|
|
||||||
if not self.is_return:
|
if not self.is_return:
|
||||||
self.update_billing_status_for_zero_amount_refdoc("Sales Order")
|
self.update_billing_status_for_zero_amount_refdoc("Sales Order")
|
||||||
|
|
||||||
@ -126,7 +128,7 @@ class SalesInvoice(SellingController):
|
|||||||
|
|
||||||
def update_status_updater_args(self):
|
def update_status_updater_args(self):
|
||||||
if cint(self.update_stock):
|
if cint(self.update_stock):
|
||||||
self.status_updater.append({
|
self.status_updater.extend([{
|
||||||
'source_dt':'Sales Invoice Item',
|
'source_dt':'Sales Invoice Item',
|
||||||
'target_dt':'Sales Order Item',
|
'target_dt':'Sales Order Item',
|
||||||
'target_parent_dt':'Sales Order',
|
'target_parent_dt':'Sales Order',
|
||||||
@ -144,7 +146,21 @@ class SalesInvoice(SellingController):
|
|||||||
'overflow_type': 'delivery',
|
'overflow_type': 'delivery',
|
||||||
'extra_cond': """ and exists(select name from `tabSales Invoice`
|
'extra_cond': """ and exists(select name from `tabSales Invoice`
|
||||||
where name=`tabSales Invoice Item`.parent and ifnull(update_stock, 0) = 1)"""
|
where name=`tabSales Invoice Item`.parent and ifnull(update_stock, 0) = 1)"""
|
||||||
})
|
},
|
||||||
|
{
|
||||||
|
'source_dt': 'Sales Invoice Item',
|
||||||
|
'target_dt': 'Sales Order Item',
|
||||||
|
'join_field': 'so_detail',
|
||||||
|
'target_field': 'returned_qty',
|
||||||
|
'target_parent_dt': 'Sales Order',
|
||||||
|
# 'target_parent_field': 'per_delivered',
|
||||||
|
# 'target_ref_field': 'qty',
|
||||||
|
'source_field': '-1 * qty',
|
||||||
|
# 'percent_join_field': 'sales_order',
|
||||||
|
# 'overflow_type': 'delivery',
|
||||||
|
'extra_cond': """ and exists (select name from `tabSales Invoice` where name=`tabSales Invoice Item`.parent and update_stock=1 and is_return=1)"""
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
def set_missing_values(self, for_validate=False):
|
def set_missing_values(self, for_validate=False):
|
||||||
pos = self.set_pos_fields(for_validate)
|
pos = self.set_pos_fields(for_validate)
|
||||||
@ -281,7 +297,7 @@ class SalesInvoice(SellingController):
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
if cint(frappe.db.get_single_value('Selling Settings', 'maintain_same_sales_rate')):
|
if cint(frappe.db.get_single_value('Selling Settings', 'maintain_same_sales_rate')) and not self.is_return:
|
||||||
self.validate_rate_with_reference_doc([
|
self.validate_rate_with_reference_doc([
|
||||||
["Sales Order", "sales_order", "so_detail"],
|
["Sales Order", "sales_order", "so_detail"],
|
||||||
["Delivery Note", "delivery_note", "dn_detail"]
|
["Delivery Note", "delivery_note", "dn_detail"]
|
||||||
|
@ -7,7 +7,7 @@ frappe.listview_settings['Sales Invoice'] = {
|
|||||||
"currency", "is_return"],
|
"currency", "is_return"],
|
||||||
get_indicator: function(doc) {
|
get_indicator: function(doc) {
|
||||||
if(cint(doc.is_return)==1) {
|
if(cint(doc.is_return)==1) {
|
||||||
return [__("Return"), "darkgrey", "is_return,=,1"];
|
return [__("Return"), "darkgrey", "is_return,=,Yes"];
|
||||||
} else if(flt(doc.outstanding_amount)==0) {
|
} else if(flt(doc.outstanding_amount)==0) {
|
||||||
return [__("Paid"), "green", "outstanding_amount,=,0"]
|
return [__("Paid"), "green", "outstanding_amount,=,0"]
|
||||||
} else if (flt(doc.outstanding_amount) > 0 && doc.due_date > frappe.datetime.get_today()) {
|
} else if (flt(doc.outstanding_amount) > 0 && doc.due_date > frappe.datetime.get_today()) {
|
||||||
|
@ -1,17 +0,0 @@
|
|||||||
{
|
|
||||||
"creation": "2015-07-22 17:45:22.220567",
|
|
||||||
"custom_format": 1,
|
|
||||||
"disabled": 0,
|
|
||||||
"doc_type": "Sales Invoice",
|
|
||||||
"docstatus": 0,
|
|
||||||
"doctype": "Print Format",
|
|
||||||
"font": "Default",
|
|
||||||
"html": "<style>\n\t.print-format table, .print-format tr, \n\t.print-format td, .print-format div, .print-format p {\n\t\tfont-family: Monospace;\n\t\tline-height: 200%;\n\t\tvertical-align: middle;\n\t}\n\t@media screen {\n\t\t.print-format {\n\t\t\twidth: 4in;\n\t\t\tpadding: 0.25in;\n\t\t\tmin-height: 6in;\n\t\t}\n\t}\n</style>\n\n<p class=\"text-center\">\n\t{{ doc.company }}<br>\n\t{{ doc.select_print_heading or _(\"Credit Note\") }}<br>\n</p>\n\n<hr>\n\n{%- for label, value in (\n (_(\"Receipt No\"), doc.name),\n (_(\"Date\"), doc.get_formatted(\"posting_date\")),\n\t(_(\"Customer\"), doc.customer_name),\n (_(\"Amount\"), \"<strong>\" + doc.get_formatted(\"grand_total\", absolute_value=True) + \"</strong><br>\" + (doc.in_words or \"\")),\n\t(_(\"Against\"), doc.return_against),\n (_(\"Remarks\"), doc.remarks)\n) -%}\n\n\t\t<div class=\"row\">\n\t\t <div class=\"col-xs-4\"><label class=\"text-right\">{{ label }}</label></div>\n\t\t <div class=\"col-xs-8\">{{ value }}</div>\n\t\t</div>\n{%- endfor -%}\n\n<hr>\n<br>\n<p class=\"strong\">\n {{ _(\"For\") }} {{ doc.company }},<br>\n <br>\n <br>\n <br>\n {{ _(\"Authorized Signatory\") }}\n</p>",
|
|
||||||
"modified": "2015-07-22 17:45:22.220567",
|
|
||||||
"modified_by": "Administrator",
|
|
||||||
"name": "Credit Note - Negative Invoice",
|
|
||||||
"owner": "Administrator",
|
|
||||||
"print_format_builder": 0,
|
|
||||||
"print_format_type": "Server",
|
|
||||||
"standard": "Yes"
|
|
||||||
}
|
|
@ -1002,6 +1002,27 @@
|
|||||||
"set_only_once": 0,
|
"set_only_once": 0,
|
||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"allow_on_submit": 0,
|
||||||
|
"depends_on": "returned_qty",
|
||||||
|
"fieldname": "returned_qty",
|
||||||
|
"fieldtype": "Float",
|
||||||
|
"hidden": 0,
|
||||||
|
"ignore_user_permissions": 0,
|
||||||
|
"in_filter": 0,
|
||||||
|
"in_list_view": 0,
|
||||||
|
"label": "Returned Qty",
|
||||||
|
"no_copy": 1,
|
||||||
|
"permlevel": 0,
|
||||||
|
"precision": "",
|
||||||
|
"print_hide": 1,
|
||||||
|
"read_only": 1,
|
||||||
|
"report_hide": 0,
|
||||||
|
"reqd": 0,
|
||||||
|
"search_index": 0,
|
||||||
|
"set_only_once": 0,
|
||||||
|
"unique": 0
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"fieldname": "billed_amt",
|
"fieldname": "billed_amt",
|
||||||
@ -1074,7 +1095,7 @@
|
|||||||
"is_submittable": 0,
|
"is_submittable": 0,
|
||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"modified": "2015-08-19 12:46:32.384796",
|
"modified": "2015-08-25 06:42:00.898647",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Buying",
|
"module": "Buying",
|
||||||
"name": "Purchase Order Item",
|
"name": "Purchase Order Item",
|
||||||
|
3
erpnext/change_log/current/sales_purchase_return.md
Normal file
3
erpnext/change_log/current/sales_purchase_return.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
- Fixes in Sales and Purchase Return
|
||||||
|
- Update Delivered, Ordered and Returned Quantity based on Return transaction
|
||||||
|
- Allow different Rate in Return transaction
|
@ -11,10 +11,10 @@ class StockOverReturnError(frappe.ValidationError): pass
|
|||||||
def validate_return(doc):
|
def validate_return(doc):
|
||||||
if not doc.meta.get_field("is_return") or not doc.is_return:
|
if not doc.meta.get_field("is_return") or not doc.is_return:
|
||||||
return
|
return
|
||||||
|
|
||||||
validate_return_against(doc)
|
validate_return_against(doc)
|
||||||
validate_returned_items(doc)
|
validate_returned_items(doc)
|
||||||
|
|
||||||
def validate_return_against(doc):
|
def validate_return_against(doc):
|
||||||
if not doc.return_against:
|
if not doc.return_against:
|
||||||
frappe.throw(_("{0} is mandatory for Return").format(doc.meta.get_label("return_against")))
|
frappe.throw(_("{0} is mandatory for Return").format(doc.meta.get_label("return_against")))
|
||||||
@ -24,49 +24,49 @@ def validate_return_against(doc):
|
|||||||
filters["customer"] = doc.customer
|
filters["customer"] = doc.customer
|
||||||
elif doc.meta.get_field("supplier"):
|
elif doc.meta.get_field("supplier"):
|
||||||
filters["supplier"] = doc.supplier
|
filters["supplier"] = doc.supplier
|
||||||
|
|
||||||
if not frappe.db.exists(filters):
|
if not frappe.db.exists(filters):
|
||||||
frappe.throw(_("Invalid {0}: {1}")
|
frappe.throw(_("Invalid {0}: {1}")
|
||||||
.format(doc.meta.get_label("return_against"), doc.return_against))
|
.format(doc.meta.get_label("return_against"), doc.return_against))
|
||||||
else:
|
else:
|
||||||
ref_doc = frappe.get_doc(doc.doctype, doc.return_against)
|
ref_doc = frappe.get_doc(doc.doctype, doc.return_against)
|
||||||
|
|
||||||
# validate posting date time
|
# validate posting date time
|
||||||
return_posting_datetime = "%s %s" % (doc.posting_date, doc.get("posting_time") or "00:00:00")
|
return_posting_datetime = "%s %s" % (doc.posting_date, doc.get("posting_time") or "00:00:00")
|
||||||
ref_posting_datetime = "%s %s" % (ref_doc.posting_date, ref_doc.get("posting_time") or "00:00:00")
|
ref_posting_datetime = "%s %s" % (ref_doc.posting_date, ref_doc.get("posting_time") or "00:00:00")
|
||||||
|
|
||||||
if get_datetime(return_posting_datetime) < get_datetime(ref_posting_datetime):
|
if get_datetime(return_posting_datetime) < get_datetime(ref_posting_datetime):
|
||||||
frappe.throw(_("Posting timestamp must be after {0}").format(format_datetime(ref_posting_datetime)))
|
frappe.throw(_("Posting timestamp must be after {0}").format(format_datetime(ref_posting_datetime)))
|
||||||
|
|
||||||
# validate same exchange rate
|
# validate same exchange rate
|
||||||
if doc.conversion_rate != ref_doc.conversion_rate:
|
if doc.conversion_rate != ref_doc.conversion_rate:
|
||||||
frappe.throw(_("Exchange Rate must be same as {0} {1} ({2})")
|
frappe.throw(_("Exchange Rate must be same as {0} {1} ({2})")
|
||||||
.format(doc.doctype, doc.return_against, ref_doc.conversion_rate))
|
.format(doc.doctype, doc.return_against, ref_doc.conversion_rate))
|
||||||
|
|
||||||
# validate update stock
|
# validate update stock
|
||||||
if doc.doctype == "Sales Invoice" and doc.update_stock and not ref_doc.update_stock:
|
if doc.doctype == "Sales Invoice" and doc.update_stock and not ref_doc.update_stock:
|
||||||
frappe.throw(_("'Update Stock' can not be checked because items are not delivered via {0}")
|
frappe.throw(_("'Update Stock' can not be checked because items are not delivered via {0}")
|
||||||
.format(doc.return_against))
|
.format(doc.return_against))
|
||||||
|
|
||||||
def validate_returned_items(doc):
|
def validate_returned_items(doc):
|
||||||
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
|
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
|
||||||
|
|
||||||
valid_items = frappe._dict()
|
valid_items = frappe._dict()
|
||||||
|
|
||||||
select_fields = "item_code, sum(qty) as qty, rate" if doc.doctype=="Purchase Invoice" \
|
select_fields = "item_code, sum(qty) as qty, rate" if doc.doctype=="Purchase Invoice" \
|
||||||
else "item_code, sum(qty) as qty, rate, serial_no, batch_no"
|
else "item_code, sum(qty) as qty, rate, serial_no, batch_no"
|
||||||
|
|
||||||
for d in frappe.db.sql("""select {0} from `tab{1} Item` where parent = %s
|
for d in frappe.db.sql("""select {0} from `tab{1} Item` where parent = %s
|
||||||
group by item_code""".format(select_fields, doc.doctype), doc.return_against, as_dict=1):
|
group by item_code""".format(select_fields, doc.doctype), doc.return_against, as_dict=1):
|
||||||
valid_items.setdefault(d.item_code, d)
|
valid_items.setdefault(d.item_code, d)
|
||||||
|
|
||||||
if doc.doctype in ("Delivery Note", "Sales Invoice"):
|
if doc.doctype in ("Delivery Note", "Sales Invoice"):
|
||||||
for d in frappe.db.sql("""select item_code, sum(qty) as qty, serial_no, batch_no from `tabPacked Item`
|
for d in frappe.db.sql("""select item_code, sum(qty) as qty, serial_no, batch_no from `tabPacked Item`
|
||||||
where parent = %s group by item_code""".format(doc.doctype), doc.return_against, as_dict=1):
|
where parent = %s group by item_code""".format(doc.doctype), doc.return_against, as_dict=1):
|
||||||
valid_items.setdefault(d.item_code, d)
|
valid_items.setdefault(d.item_code, d)
|
||||||
|
|
||||||
already_returned_items = get_already_returned_items(doc)
|
already_returned_items = get_already_returned_items(doc)
|
||||||
|
|
||||||
items_returned = False
|
items_returned = False
|
||||||
for d in doc.get("items"):
|
for d in doc.get("items"):
|
||||||
if flt(d.qty) < 0:
|
if flt(d.qty) < 0:
|
||||||
@ -77,16 +77,12 @@ def validate_returned_items(doc):
|
|||||||
ref = valid_items.get(d.item_code, frappe._dict())
|
ref = valid_items.get(d.item_code, frappe._dict())
|
||||||
already_returned_qty = flt(already_returned_items.get(d.item_code))
|
already_returned_qty = flt(already_returned_items.get(d.item_code))
|
||||||
max_return_qty = flt(ref.qty) - already_returned_qty
|
max_return_qty = flt(ref.qty) - already_returned_qty
|
||||||
|
|
||||||
if already_returned_qty >= ref.qty:
|
if already_returned_qty >= ref.qty:
|
||||||
frappe.throw(_("Item {0} has already been returned").format(d.item_code), StockOverReturnError)
|
frappe.throw(_("Item {0} has already been returned").format(d.item_code), StockOverReturnError)
|
||||||
elif abs(d.qty) > max_return_qty:
|
elif abs(d.qty) > max_return_qty:
|
||||||
frappe.throw(_("Row # {0}: Cannot return more than {1} for Item {2}")
|
frappe.throw(_("Row # {0}: Cannot return more than {1} for Item {2}")
|
||||||
.format(d.idx, ref.qty, d.item_code), StockOverReturnError)
|
.format(d.idx, ref.qty, d.item_code), StockOverReturnError)
|
||||||
elif ref.rate and (doc.doctype in ("Delivery Note", "Purchase Receipt") \
|
|
||||||
or (doc.doctype=="Sales Invoice" and doc.update_stock==1)) and flt(d.rate) > ref.rate:
|
|
||||||
frappe.throw(_("Row # {0}: Rate cannot be greater than {1} {2}")
|
|
||||||
.format(d.idx, doc.doctype, doc.return_against))
|
|
||||||
elif ref.batch_no and d.batch_no != ref.batch_no:
|
elif ref.batch_no and d.batch_no != ref.batch_no:
|
||||||
frappe.throw(_("Row # {0}: Batch No must be same as {1} {2}")
|
frappe.throw(_("Row # {0}: Batch No must be same as {1} {2}")
|
||||||
.format(d.idx, doc.doctype, doc.return_against))
|
.format(d.idx, doc.doctype, doc.return_against))
|
||||||
@ -100,24 +96,24 @@ def validate_returned_items(doc):
|
|||||||
if s not in ref_serial_nos:
|
if s not in ref_serial_nos:
|
||||||
frappe.throw(_("Row # {0}: Serial No {1} does not match with {2} {3}")
|
frappe.throw(_("Row # {0}: Serial No {1} does not match with {2} {3}")
|
||||||
.format(d.idx, s, doc.doctype, doc.return_against))
|
.format(d.idx, s, doc.doctype, doc.return_against))
|
||||||
|
|
||||||
items_returned = True
|
items_returned = True
|
||||||
|
|
||||||
if not items_returned:
|
if not items_returned:
|
||||||
frappe.throw(_("Atleast one item should be entered with negative quantity in return document"))
|
frappe.throw(_("Atleast one item should be entered with negative quantity in return document"))
|
||||||
|
|
||||||
def get_already_returned_items(doc):
|
def get_already_returned_items(doc):
|
||||||
return frappe._dict(frappe.db.sql("""
|
return frappe._dict(frappe.db.sql("""
|
||||||
select
|
select
|
||||||
child.item_code, sum(abs(child.qty)) as qty
|
child.item_code, sum(abs(child.qty)) as qty
|
||||||
from
|
from
|
||||||
`tab{0} Item` child, `tab{1}` par
|
`tab{0} Item` child, `tab{1}` par
|
||||||
where
|
where
|
||||||
child.parent = par.name and par.docstatus = 1
|
child.parent = par.name and par.docstatus = 1
|
||||||
and ifnull(par.is_return, 0) = 1 and par.return_against = %s and child.qty < 0
|
and ifnull(par.is_return, 0) = 1 and par.return_against = %s and child.qty < 0
|
||||||
group by item_code
|
group by item_code
|
||||||
""".format(doc.doctype, doc.doctype), doc.return_against))
|
""".format(doc.doctype, doc.doctype), doc.return_against))
|
||||||
|
|
||||||
def make_return_doc(doctype, source_name, target_doc=None):
|
def make_return_doc(doctype, source_name, target_doc=None):
|
||||||
from frappe.model.mapper import get_mapped_doc
|
from frappe.model.mapper import get_mapped_doc
|
||||||
def set_missing_values(source, target):
|
def set_missing_values(source, target):
|
||||||
@ -127,13 +123,21 @@ def make_return_doc(doctype, source_name, target_doc=None):
|
|||||||
doc.ignore_pricing_rule = 1
|
doc.ignore_pricing_rule = 1
|
||||||
if doctype == "Sales Invoice":
|
if doctype == "Sales Invoice":
|
||||||
doc.is_pos = 0
|
doc.is_pos = 0
|
||||||
|
|
||||||
|
# look for Print Heading "Credit Note"
|
||||||
|
if not doc.select_print_heading:
|
||||||
|
doc.select_print_heading = frappe.db.get_value("Print Heading", _("Credit Note"))
|
||||||
|
|
||||||
|
elif doctype == "Purchase Invoice":
|
||||||
|
# look for Print Heading "Debit Note"
|
||||||
|
doc.select_print_heading = frappe.db.get_value("Print Heading", _("Debit Note"))
|
||||||
|
|
||||||
for tax in doc.get("taxes"):
|
for tax in doc.get("taxes"):
|
||||||
if tax.charge_type == "Actual":
|
if tax.charge_type == "Actual":
|
||||||
tax.tax_amount = -1 * tax.tax_amount
|
tax.tax_amount = -1 * tax.tax_amount
|
||||||
|
|
||||||
doc.run_method("calculate_taxes_and_totals")
|
doc.run_method("calculate_taxes_and_totals")
|
||||||
|
|
||||||
def update_item(source_doc, target_doc, source_parent):
|
def update_item(source_doc, target_doc, source_parent):
|
||||||
target_doc.qty = -1* source_doc.qty
|
target_doc.qty = -1* source_doc.qty
|
||||||
if doctype == "Purchase Receipt":
|
if doctype == "Purchase Receipt":
|
||||||
@ -151,16 +155,18 @@ def make_return_doc(doctype, source_name, target_doc=None):
|
|||||||
target_doc.against_sales_invoice = source_doc.against_sales_invoice
|
target_doc.against_sales_invoice = source_doc.against_sales_invoice
|
||||||
target_doc.so_detail = source_doc.so_detail
|
target_doc.so_detail = source_doc.so_detail
|
||||||
target_doc.si_detail = source_doc.si_detail
|
target_doc.si_detail = source_doc.si_detail
|
||||||
|
target_doc.expense_account = source_doc.expense_account
|
||||||
elif doctype == "Sales Invoice":
|
elif doctype == "Sales Invoice":
|
||||||
target_doc.sales_order = source_doc.sales_order
|
target_doc.sales_order = source_doc.sales_order
|
||||||
target_doc.delivery_note = source_doc.delivery_note
|
target_doc.delivery_note = source_doc.delivery_note
|
||||||
target_doc.so_detail = source_doc.so_detail
|
target_doc.so_detail = source_doc.so_detail
|
||||||
target_doc.dn_detail = source_doc.dn_detail
|
target_doc.dn_detail = source_doc.dn_detail
|
||||||
|
target_doc.expense_account = source_doc.expense_account
|
||||||
|
|
||||||
doclist = get_mapped_doc(doctype, source_name, {
|
doclist = get_mapped_doc(doctype, source_name, {
|
||||||
doctype: {
|
doctype: {
|
||||||
"doctype": doctype,
|
"doctype": doctype,
|
||||||
|
|
||||||
"validation": {
|
"validation": {
|
||||||
"docstatus": ["=", 1],
|
"docstatus": ["=", 1],
|
||||||
}
|
}
|
||||||
|
@ -90,6 +90,10 @@ class StatusUpdater(Document):
|
|||||||
self.global_tolerance = None
|
self.global_tolerance = None
|
||||||
|
|
||||||
for args in self.status_updater:
|
for args in self.status_updater:
|
||||||
|
if "target_ref_field" not in args:
|
||||||
|
# if target_ref_field is not specified, the programmer does not want to validate qty / amount
|
||||||
|
continue
|
||||||
|
|
||||||
# get unique transactions to update
|
# get unique transactions to update
|
||||||
for d in self.get_all_children():
|
for d in self.get_all_children():
|
||||||
if d.doctype == args['source_dt'] and d.get(args["join_field"]):
|
if d.doctype == args['source_dt'] and d.get(args["join_field"]):
|
||||||
@ -140,8 +144,9 @@ class StatusUpdater(Document):
|
|||||||
.format(_(item["target_ref_field"].title()), item["reduce_by"]))
|
.format(_(item["target_ref_field"].title()), item["reduce_by"]))
|
||||||
|
|
||||||
def update_qty(self, change_modified=True):
|
def update_qty(self, change_modified=True):
|
||||||
"""
|
"""Updates qty or amount at row level
|
||||||
Updates qty at row level
|
|
||||||
|
:param change_modified: If true, updates `modified` and `modified_by` for target parent doc
|
||||||
"""
|
"""
|
||||||
for args in self.status_updater:
|
for args in self.status_updater:
|
||||||
# condition to include current record (if submit or no if cancel)
|
# condition to include current record (if submit or no if cancel)
|
||||||
@ -150,58 +155,74 @@ class StatusUpdater(Document):
|
|||||||
else:
|
else:
|
||||||
args['cond'] = ' and parent!="%s"' % self.name.replace('"', '\"')
|
args['cond'] = ' and parent!="%s"' % self.name.replace('"', '\"')
|
||||||
|
|
||||||
args['modified_cond'] = ''
|
args['set_modified'] = ''
|
||||||
if change_modified:
|
if change_modified:
|
||||||
args['modified_cond'] = ', modified = now()'
|
args['set_modified'] = ', modified = now(), modified_by = "{0}"'\
|
||||||
|
.format(frappe.db.escape(frappe.session.user))
|
||||||
|
|
||||||
# update quantities in child table
|
self._update_children(args)
|
||||||
for d in self.get_all_children():
|
|
||||||
if d.doctype == args['source_dt']:
|
|
||||||
# updates qty in the child table
|
|
||||||
args['detail_id'] = d.get(args['join_field'])
|
|
||||||
|
|
||||||
args['second_source_condition'] = ""
|
if "percent_join_field" in args:
|
||||||
if args.get('second_source_dt') and args.get('second_source_field') \
|
self._update_percent_field(args)
|
||||||
and args.get('second_join_field'):
|
|
||||||
if not args.get("second_source_extra_cond"):
|
|
||||||
args["second_source_extra_cond"] = ""
|
|
||||||
|
|
||||||
args['second_source_condition'] = """ + ifnull((select sum(%(second_source_field)s)
|
def _update_children(self, args):
|
||||||
from `tab%(second_source_dt)s`
|
"""Update quantities or amount in child table"""
|
||||||
where `%(second_join_field)s`="%(detail_id)s"
|
for d in self.get_all_children():
|
||||||
and (`tab%(second_source_dt)s`.docstatus=1) %(second_source_extra_cond)s), 0) """ % args
|
if d.doctype != args['source_dt']:
|
||||||
|
continue
|
||||||
|
|
||||||
if args['detail_id']:
|
# updates qty in the child table
|
||||||
if not args.get("extra_cond"): args["extra_cond"] = ""
|
args['detail_id'] = d.get(args['join_field'])
|
||||||
|
|
||||||
frappe.db.sql("""update `tab%(target_dt)s`
|
args['second_source_condition'] = ""
|
||||||
set %(target_field)s = (select sum(%(source_field)s)
|
if args.get('second_source_dt') and args.get('second_source_field') \
|
||||||
from `tab%(source_dt)s` where `%(join_field)s`="%(detail_id)s"
|
and args.get('second_join_field'):
|
||||||
and (docstatus=1 %(cond)s) %(extra_cond)s) %(second_source_condition)s
|
if not args.get("second_source_extra_cond"):
|
||||||
where name='%(detail_id)s'""" % args)
|
args["second_source_extra_cond"] = ""
|
||||||
|
|
||||||
# get unique transactions to update
|
args['second_source_condition'] = """ + ifnull((select sum(%(second_source_field)s)
|
||||||
for name in set([d.get(args['percent_join_field']) for d in self.get_all_children(args['source_dt'])]):
|
from `tab%(second_source_dt)s`
|
||||||
if name:
|
where `%(second_join_field)s`="%(detail_id)s"
|
||||||
args['name'] = name
|
and (`tab%(second_source_dt)s`.docstatus=1) %(second_source_extra_cond)s), 0) """ % args
|
||||||
|
|
||||||
# update percent complete in the parent table
|
if args['detail_id']:
|
||||||
if args.get('target_parent_field'):
|
if not args.get("extra_cond"): args["extra_cond"] = ""
|
||||||
frappe.db.sql("""update `tab%(target_parent_dt)s`
|
|
||||||
set %(target_parent_field)s = (select sum(if(%(target_ref_field)s >
|
|
||||||
ifnull(%(target_field)s, 0), %(target_field)s,
|
|
||||||
%(target_ref_field)s))/sum(%(target_ref_field)s)*100
|
|
||||||
from `tab%(target_dt)s` where parent="%(name)s") %(modified_cond)s
|
|
||||||
where name='%(name)s'""" % args)
|
|
||||||
|
|
||||||
# update field
|
frappe.db.sql("""update `tab%(target_dt)s`
|
||||||
if args.get('status_field'):
|
set %(target_field)s = (select sum(%(source_field)s)
|
||||||
frappe.db.sql("""update `tab%(target_parent_dt)s`
|
from `tab%(source_dt)s` where `%(join_field)s`="%(detail_id)s"
|
||||||
set %(status_field)s = if(ifnull(%(target_parent_field)s,0)<0.001,
|
and (docstatus=1 %(cond)s) %(extra_cond)s) %(second_source_condition)s
|
||||||
'Not %(keyword)s', if(%(target_parent_field)s>=99.99,
|
where name='%(detail_id)s'""" % args)
|
||||||
'Fully %(keyword)s', 'Partly %(keyword)s'))
|
|
||||||
where name='%(name)s'""" % args)
|
|
||||||
|
|
||||||
|
def _update_percent_field(self, args):
|
||||||
|
"""Update percent field in parent transaction"""
|
||||||
|
unique_transactions = set([d.get(args['percent_join_field']) for d in self.get_all_children(args['source_dt'])])
|
||||||
|
|
||||||
|
for name in unique_transactions:
|
||||||
|
if not name:
|
||||||
|
continue
|
||||||
|
|
||||||
|
args['name'] = name
|
||||||
|
|
||||||
|
# update percent complete in the parent table
|
||||||
|
if args.get('target_parent_field'):
|
||||||
|
frappe.db.sql("""update `tab%(target_parent_dt)s`
|
||||||
|
set %(target_parent_field)s = (select sum(if(%(target_ref_field)s >
|
||||||
|
ifnull(%(target_field)s, 0), %(target_field)s,
|
||||||
|
%(target_ref_field)s))/sum(%(target_ref_field)s)*100
|
||||||
|
from `tab%(target_dt)s` where parent="%(name)s") %(set_modified)s
|
||||||
|
where name='%(name)s'""" % args)
|
||||||
|
|
||||||
|
# update field
|
||||||
|
if args.get('status_field'):
|
||||||
|
frappe.db.sql("""update `tab%(target_parent_dt)s`
|
||||||
|
set %(status_field)s = if(ifnull(%(target_parent_field)s,0)<0.001,
|
||||||
|
'Not %(keyword)s', if(%(target_parent_field)s>=99.99,
|
||||||
|
'Fully %(keyword)s', 'Partly %(keyword)s'))
|
||||||
|
where name='%(name)s'""" % args)
|
||||||
|
|
||||||
|
if args.get("set_modified"):
|
||||||
|
frappe.get_doc(args["target_parent_dt"], name).notify_modified()
|
||||||
|
|
||||||
def update_billing_status_for_zero_amount_refdoc(self, ref_dt):
|
def update_billing_status_for_zero_amount_refdoc(self, ref_dt):
|
||||||
ref_fieldname = ref_dt.lower().replace(" ", "_")
|
ref_fieldname = ref_dt.lower().replace(" ", "_")
|
||||||
|
@ -191,6 +191,10 @@ erpnext.patches.v5_4.stock_entry_additional_costs
|
|||||||
erpnext.patches.v5_4.cleanup_journal_entry #2015-08-14
|
erpnext.patches.v5_4.cleanup_journal_entry #2015-08-14
|
||||||
execute:frappe.db.sql("update `tabProduction Order` pro set description = (select description from tabItem where name=pro.production_item) where ifnull(description, '') = ''")
|
execute:frappe.db.sql("update `tabProduction Order` pro set description = (select description from tabItem where name=pro.production_item) where ifnull(description, '') = ''")
|
||||||
erpnext.patches.v5_7.item_template_attributes
|
erpnext.patches.v5_7.item_template_attributes
|
||||||
|
execute:frappe.delete_doc_if_exists("DocType", "Manage Variants")
|
||||||
|
execute:frappe.delete_doc_if_exists("DocType", "Manage Variants Item")
|
||||||
erpnext.patches.v4_2.repost_reserved_qty #2015-08-20
|
erpnext.patches.v4_2.repost_reserved_qty #2015-08-20
|
||||||
erpnext.patches.v5_4.update_purchase_cost_against_project
|
erpnext.patches.v5_4.update_purchase_cost_against_project
|
||||||
erpnext.patches.v5_7.update_order_reference_in_return_entries
|
erpnext.patches.v5_8.update_order_reference_in_return_entries
|
||||||
|
erpnext.patches.v5_8.add_credit_note_print_heading
|
||||||
|
execute:frappe.delete_doc_if_exists("Print Format", "Credit Note - Negative Invoice")
|
||||||
|
@ -55,9 +55,6 @@ def migrate_manage_variants():
|
|||||||
template.set('attributes', attributes)
|
template.set('attributes', attributes)
|
||||||
template.save()
|
template.save()
|
||||||
|
|
||||||
frappe.delete_doc("DocType", "Manage Variants")
|
|
||||||
frappe.delete_doc("DocType", "Manage Variants Item")
|
|
||||||
|
|
||||||
# patch old style
|
# patch old style
|
||||||
def migrate_item_variants():
|
def migrate_item_variants():
|
||||||
for item in frappe.get_all("Item", filters={"has_variants": 1}):
|
for item in frappe.get_all("Item", filters={"has_variants": 1}):
|
||||||
|
1
erpnext/patches/v5_8/__init__.py
Normal file
1
erpnext/patches/v5_8/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
from __future__ import unicode_literals
|
14
erpnext/patches/v5_8/add_credit_note_print_heading.py
Normal file
14
erpnext/patches/v5_8/add_credit_note_print_heading.py
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
|
||||||
|
# License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
import frappe
|
||||||
|
from frappe import _
|
||||||
|
|
||||||
|
def execute():
|
||||||
|
for print_heading in (_("Credit Note"), _("Debit Note")):
|
||||||
|
if not frappe.db.exists("Print Heading", print_heading):
|
||||||
|
frappe.get_doc({
|
||||||
|
"doctype": "Print Heading",
|
||||||
|
"print_heading": print_heading
|
||||||
|
}).insert()
|
@ -7,43 +7,50 @@ import frappe
|
|||||||
def execute():
|
def execute():
|
||||||
# sales return
|
# sales return
|
||||||
return_entries = list(frappe.db.sql("""
|
return_entries = list(frappe.db.sql("""
|
||||||
select dn.name as name, dn_item.name as row_id, dn.return_against,
|
select dn.name as name, dn_item.name as row_id, dn.return_against,
|
||||||
dn_item.item_code, "Delivery Note" as doctype
|
dn_item.item_code, "Delivery Note" as doctype
|
||||||
from `tabDelivery Note Item` dn_item, `tabDelivery Note` dn
|
from `tabDelivery Note Item` dn_item, `tabDelivery Note` dn
|
||||||
where dn_item.parent=dn.name and dn.is_return=1 and dn.docstatus < 2
|
where dn_item.parent=dn.name and dn.is_return=1 and dn.docstatus < 2
|
||||||
""", as_dict=1))
|
""", as_dict=1))
|
||||||
|
|
||||||
return_entries += list(frappe.db.sql("""
|
return_entries += list(frappe.db.sql("""
|
||||||
select si.name as name, si_item.name as row_id, si.return_against,
|
select si.name as name, si_item.name as row_id, si.return_against,
|
||||||
si_item.item_code, "Sales Invoice" as doctype
|
si_item.item_code, "Sales Invoice" as doctype, update_stock
|
||||||
from `tabSales Invoice Item` si_item, `tabSales Invoice` si
|
from `tabSales Invoice Item` si_item, `tabSales Invoice` si
|
||||||
where si_item.parent=si.name and si.is_return=1 and si.update_stock=1 and si.docstatus < 2
|
where si_item.parent=si.name and si.is_return=1 and si.docstatus < 2
|
||||||
""", as_dict=1))
|
""", as_dict=1))
|
||||||
|
|
||||||
for d in return_entries:
|
for d in return_entries:
|
||||||
ref_field = "against_sales_order" if d.doctype == "Delivery Note" else "sales_order"
|
ref_field = "against_sales_order" if d.doctype == "Delivery Note" else "sales_order"
|
||||||
order_details = frappe.db.sql("""
|
order_details = frappe.db.sql("""
|
||||||
select {0} as sales_order, so_detail
|
select {ref_field} as sales_order, so_detail,
|
||||||
from `tab{1} Item` item
|
(select transaction_date from `tabSales Order` where name=item.{ref_field}) as sales_order_date
|
||||||
where
|
from `tab{doctype} Item` item
|
||||||
parent=%s and item_code=%s
|
where
|
||||||
|
parent=%s
|
||||||
|
and item_code=%s
|
||||||
and ifnull(so_detail, '') !=''
|
and ifnull(so_detail, '') !=''
|
||||||
order by
|
order by sales_order_date DESC limit 1
|
||||||
(select transaction_date from `tabSales Order` where name=item.{3}) DESC
|
""".format(ref_field=ref_field, doctype=d.doctype), (d.return_against, d.item_code), as_dict=1)
|
||||||
""".format(ref_field, d.doctype, ref_field, ref_field), (d.return_against, d.item_code), as_dict=1)
|
|
||||||
|
|
||||||
if order_details:
|
if order_details:
|
||||||
frappe.db.sql("""
|
frappe.db.sql("""
|
||||||
update `tab{0} Item`
|
update `tab{doctype} Item`
|
||||||
set {1}=%s, so_detail=%s
|
set {ref_field}=%s, so_detail=%s
|
||||||
where name=%s
|
where name=%s
|
||||||
""".format(d.doctype, ref_field),
|
""".format(doctype=d.doctype, ref_field=ref_field),
|
||||||
(order_details[0].sales_order, order_details[0].so_detail, d.row_id))
|
(order_details[0].sales_order, order_details[0].so_detail, d.row_id))
|
||||||
|
|
||||||
doc = frappe.get_doc(d.doctype, d.name)
|
if (d.doctype=="Sales Invoice" and d.update_stock) or d.doctype=="Delivery Note":
|
||||||
doc.update_reserved_qty()
|
doc = frappe.get_doc(d.doctype, d.name)
|
||||||
|
doc.update_reserved_qty()
|
||||||
|
|
||||||
|
if d.doctype=="Sales Invoice":
|
||||||
|
doc.status_updater = []
|
||||||
|
doc.update_status_updater_args()
|
||||||
|
|
||||||
|
doc.update_prevdoc_status()
|
||||||
|
|
||||||
#--------------------------
|
#--------------------------
|
||||||
# purchase return
|
# purchase return
|
||||||
return_entries = frappe.db.sql("""
|
return_entries = frappe.db.sql("""
|
||||||
@ -51,26 +58,28 @@ def execute():
|
|||||||
from `tabPurchase Receipt Item` pr_item, `tabPurchase Receipt` pr
|
from `tabPurchase Receipt Item` pr_item, `tabPurchase Receipt` pr
|
||||||
where pr_item.parent=pr.name and pr.is_return=1 and pr.docstatus < 2
|
where pr_item.parent=pr.name and pr.is_return=1 and pr.docstatus < 2
|
||||||
""", as_dict=1)
|
""", as_dict=1)
|
||||||
|
|
||||||
for d in return_entries:
|
for d in return_entries:
|
||||||
order_details = frappe.db.sql("""
|
order_details = frappe.db.sql("""
|
||||||
select prevdoc_docname as purchase_order, prevdoc_detail_docname as po_detail
|
select prevdoc_docname as purchase_order, prevdoc_detail_docname as po_detail,
|
||||||
|
(select transaction_date from `tabPurchase Order` where name=item.prevdoc_detail_docname) as purchase_order_date
|
||||||
from `tabPurchase Receipt Item` item
|
from `tabPurchase Receipt Item` item
|
||||||
where
|
where
|
||||||
parent=%s and item_code=%s
|
parent=%s
|
||||||
and ifnull(prevdoc_detail_docname, '') !=''
|
and item_code=%s
|
||||||
|
and ifnull(prevdoc_detail_docname, '') !=''
|
||||||
and ifnull(prevdoc_doctype, '') = 'Purchase Order' and ifnull(prevdoc_detail_docname, '') != ''
|
and ifnull(prevdoc_doctype, '') = 'Purchase Order' and ifnull(prevdoc_detail_docname, '') != ''
|
||||||
order by
|
order by purchase_order_date DESC limit 1
|
||||||
(select transaction_date from `tabPurchase Order` where name=item.prevdoc_detail_docname) DESC
|
|
||||||
""", (d.return_against, d.item_code), as_dict=1)
|
""", (d.return_against, d.item_code), as_dict=1)
|
||||||
|
|
||||||
if order_details:
|
if order_details:
|
||||||
frappe.db.sql("""
|
frappe.db.sql("""
|
||||||
update `tabPurchase Receipt Item`
|
update `tabPurchase Receipt Item`
|
||||||
set prevdoc_doctype='Purchase Order', prevdoc_docname=%s, prevdoc_detail_docname=%s
|
set prevdoc_doctype='Purchase Order', prevdoc_docname=%s, prevdoc_detail_docname=%s
|
||||||
where name=%s
|
where name=%s
|
||||||
""", (order_details[0].purchase_order, order_details[0].po_detail, d.row_id))
|
""", (order_details[0].purchase_order, order_details[0].po_detail, d.row_id))
|
||||||
|
|
||||||
pr = frappe.get_doc("Purchase Receipt", d.name)
|
pr = frappe.get_doc("Purchase Receipt", d.name)
|
||||||
pr.update_ordered_qty()
|
pr.update_ordered_qty()
|
||||||
|
pr.update_prevdoc_status()
|
||||||
|
|
@ -88,6 +88,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
|||||||
this.set_dynamic_labels();
|
this.set_dynamic_labels();
|
||||||
erpnext.pos.make_pos_btn(this.frm);
|
erpnext.pos.make_pos_btn(this.frm);
|
||||||
this.setup_sms();
|
this.setup_sms();
|
||||||
|
this.make_show_payments_btn();
|
||||||
},
|
},
|
||||||
|
|
||||||
apply_default_taxes: function() {
|
apply_default_taxes: function() {
|
||||||
@ -123,6 +124,22 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
|||||||
var sms_man = new SMSManager(this.frm.doc);
|
var sms_man = new SMSManager(this.frm.doc);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
make_show_payments_btn: function() {
|
||||||
|
var me = this;
|
||||||
|
if (in_list(["Purchase Invoice", "Sales Invoice"], this.frm.doctype)) {
|
||||||
|
if(this.frm.doc.outstanding_amount !== this.frm.doc.base_grand_total) {
|
||||||
|
this.frm.add_custom_button(__("Show Payments"), function() {
|
||||||
|
frappe.route_options = {
|
||||||
|
"Journal Entry Account.reference_type": me.frm.doc.doctype,
|
||||||
|
"Journal Entry Account.reference_name": me.frm.doc.name
|
||||||
|
};
|
||||||
|
|
||||||
|
frappe.set_route("List", "Journal Entry");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
hide_currency_and_price_list: function() {
|
hide_currency_and_price_list: function() {
|
||||||
if(this.frm.doc.conversion_rate == 1 && this.frm.doc.docstatus > 0) {
|
if(this.frm.doc.conversion_rate == 1 && this.frm.doc.docstatus > 0) {
|
||||||
hide_field("currency_and_price_list");
|
hide_field("currency_and_price_list");
|
||||||
|
@ -840,6 +840,27 @@
|
|||||||
"unique": 0,
|
"unique": 0,
|
||||||
"width": "100px"
|
"width": "100px"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"allow_on_submit": 0,
|
||||||
|
"depends_on": "returned_qty",
|
||||||
|
"fieldname": "returned_qty",
|
||||||
|
"fieldtype": "Float",
|
||||||
|
"hidden": 0,
|
||||||
|
"ignore_user_permissions": 0,
|
||||||
|
"in_filter": 0,
|
||||||
|
"in_list_view": 0,
|
||||||
|
"label": "Returned Qty",
|
||||||
|
"no_copy": 1,
|
||||||
|
"permlevel": 0,
|
||||||
|
"precision": "",
|
||||||
|
"print_hide": 1,
|
||||||
|
"read_only": 1,
|
||||||
|
"report_hide": 0,
|
||||||
|
"reqd": 0,
|
||||||
|
"search_index": 0,
|
||||||
|
"set_only_once": 0,
|
||||||
|
"unique": 0
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"fieldname": "billed_amt",
|
"fieldname": "billed_amt",
|
||||||
@ -960,7 +981,7 @@
|
|||||||
"is_submittable": 0,
|
"is_submittable": 0,
|
||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"modified": "2015-08-19 12:46:32.930498",
|
"modified": "2015-08-25 06:42:11.062909",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Selling",
|
"module": "Selling",
|
||||||
"name": "Sales Order Item",
|
"name": "Sales Order Item",
|
||||||
|
@ -41,15 +41,15 @@ def install(country=None):
|
|||||||
{'doctype': 'Expense Claim Type', 'name': _('Travel'), 'expense_type': _('Travel')},
|
{'doctype': 'Expense Claim Type', 'name': _('Travel'), 'expense_type': _('Travel')},
|
||||||
|
|
||||||
# leave type
|
# leave type
|
||||||
{'doctype': 'Leave Type', 'leave_type_name': _('Casual Leave'), 'name': _('Casual Leave'),
|
{'doctype': 'Leave Type', 'leave_type_name': _('Casual Leave'), 'name': _('Casual Leave'),
|
||||||
'is_encash': 1, 'is_carry_forward': 1, 'max_days_allowed': '3', 'include_holiday': 1},
|
'is_encash': 1, 'is_carry_forward': 1, 'max_days_allowed': '3', 'include_holiday': 1},
|
||||||
{'doctype': 'Leave Type', 'leave_type_name': _('Compensatory Off'), 'name': _('Compensatory Off'),
|
{'doctype': 'Leave Type', 'leave_type_name': _('Compensatory Off'), 'name': _('Compensatory Off'),
|
||||||
'is_encash': 0, 'is_carry_forward': 0, 'include_holiday': 1},
|
'is_encash': 0, 'is_carry_forward': 0, 'include_holiday': 1},
|
||||||
{'doctype': 'Leave Type', 'leave_type_name': _('Sick Leave'), 'name': _('Sick Leave'),
|
{'doctype': 'Leave Type', 'leave_type_name': _('Sick Leave'), 'name': _('Sick Leave'),
|
||||||
'is_encash': 0, 'is_carry_forward': 0, 'include_holiday': 1},
|
'is_encash': 0, 'is_carry_forward': 0, 'include_holiday': 1},
|
||||||
{'doctype': 'Leave Type', 'leave_type_name': _('Privilege Leave'), 'name': _('Privilege Leave'),
|
{'doctype': 'Leave Type', 'leave_type_name': _('Privilege Leave'), 'name': _('Privilege Leave'),
|
||||||
'is_encash': 0, 'is_carry_forward': 0, 'include_holiday': 1},
|
'is_encash': 0, 'is_carry_forward': 0, 'include_holiday': 1},
|
||||||
{'doctype': 'Leave Type', 'leave_type_name': _('Leave Without Pay'), 'name': _('Leave Without Pay'),
|
{'doctype': 'Leave Type', 'leave_type_name': _('Leave Without Pay'), 'name': _('Leave Without Pay'),
|
||||||
'is_encash': 0, 'is_carry_forward': 0, 'is_lwp':1, 'include_holiday': 1},
|
'is_encash': 0, 'is_carry_forward': 0, 'is_lwp':1, 'include_holiday': 1},
|
||||||
|
|
||||||
# Employment Type
|
# Employment Type
|
||||||
@ -173,6 +173,8 @@ def install(country=None):
|
|||||||
{"doctype": "Offer Term", "offer_term": _("Notice Period")},
|
{"doctype": "Offer Term", "offer_term": _("Notice Period")},
|
||||||
{"doctype": "Offer Term", "offer_term": _("Incentives")},
|
{"doctype": "Offer Term", "offer_term": _("Incentives")},
|
||||||
|
|
||||||
|
{'doctype': "Print Heading", 'print_heading': _("Credit Note")},
|
||||||
|
{'doctype': "Print Heading", 'print_heading': _("Debit Note")}
|
||||||
]
|
]
|
||||||
|
|
||||||
from erpnext.setup.page.setup_wizard.fixtures import industry_type
|
from erpnext.setup.page.setup_wizard.fixtures import industry_type
|
||||||
|
@ -47,6 +47,19 @@ class DeliveryNote(SellingController):
|
|||||||
'source_field': 'qty',
|
'source_field': 'qty',
|
||||||
'percent_join_field': 'against_sales_invoice',
|
'percent_join_field': 'against_sales_invoice',
|
||||||
'overflow_type': 'delivery'
|
'overflow_type': 'delivery'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'source_dt': 'Delivery Note Item',
|
||||||
|
'target_dt': 'Sales Order Item',
|
||||||
|
'join_field': 'so_detail',
|
||||||
|
'target_field': 'returned_qty',
|
||||||
|
'target_parent_dt': 'Sales Order',
|
||||||
|
# 'target_parent_field': 'per_delivered',
|
||||||
|
# 'target_ref_field': 'qty',
|
||||||
|
'source_field': '-1 * qty',
|
||||||
|
# 'percent_join_field': 'against_sales_order',
|
||||||
|
# 'overflow_type': 'delivery',
|
||||||
|
'extra_cond': """ and exists (select name from `tabDelivery Note` where name=`tabDelivery Note Item`.parent and is_return=1)"""
|
||||||
}]
|
}]
|
||||||
|
|
||||||
def onload(self):
|
def onload(self):
|
||||||
@ -118,7 +131,7 @@ class DeliveryNote(SellingController):
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
if cint(frappe.db.get_single_value('Selling Settings', 'maintain_same_sales_rate')):
|
if cint(frappe.db.get_single_value('Selling Settings', 'maintain_same_sales_rate')) and not self.is_return:
|
||||||
self.validate_rate_with_reference_doc([["Sales Order", "sales_order", "so_detail"],
|
self.validate_rate_with_reference_doc([["Sales Order", "sales_order", "so_detail"],
|
||||||
["Sales Invoice", "sales_invoice", "si_detail"]])
|
["Sales Invoice", "sales_invoice", "si_detail"]])
|
||||||
|
|
||||||
@ -176,7 +189,7 @@ class DeliveryNote(SellingController):
|
|||||||
|
|
||||||
# update delivered qty in sales order
|
# update delivered qty in sales order
|
||||||
self.update_prevdoc_status()
|
self.update_prevdoc_status()
|
||||||
|
|
||||||
if not self.is_return:
|
if not self.is_return:
|
||||||
self.check_credit_limit()
|
self.check_credit_limit()
|
||||||
|
|
||||||
@ -354,8 +367,8 @@ def make_packing_slip(source_name, target_doc=None):
|
|||||||
|
|
||||||
return doclist
|
return doclist
|
||||||
|
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def make_sales_return(source_name, target_doc=None):
|
def make_sales_return(source_name, target_doc=None):
|
||||||
from erpnext.controllers.sales_and_purchase_return import make_return_doc
|
from erpnext.controllers.sales_and_purchase_return import make_return_doc
|
||||||
return make_return_doc("Delivery Note", source_name, target_doc)
|
return make_return_doc("Delivery Note", source_name, target_doc)
|
||||||
|
@ -3,7 +3,7 @@ frappe.listview_settings['Delivery Note'] = {
|
|||||||
"transporter_name", "grand_total", "is_return"],
|
"transporter_name", "grand_total", "is_return"],
|
||||||
get_indicator: function(doc) {
|
get_indicator: function(doc) {
|
||||||
if(cint(doc.is_return)==1) {
|
if(cint(doc.is_return)==1) {
|
||||||
return [__("Return"), "darkgrey", "is_return,=,1"];
|
return [__("Return"), "darkgrey", "is_return,=,Yes"];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -912,7 +912,7 @@
|
|||||||
"in_filter": 0,
|
"in_filter": 0,
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"label": "Against Sales Order",
|
"label": "Against Sales Order",
|
||||||
"no_copy": 0,
|
"no_copy": 1,
|
||||||
"options": "Sales Order",
|
"options": "Sales Order",
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
@ -932,7 +932,7 @@
|
|||||||
"in_filter": 0,
|
"in_filter": 0,
|
||||||
"in_list_view": 0,
|
"in_list_view": 0,
|
||||||
"label": "Against Sales Invoice",
|
"label": "Against Sales Invoice",
|
||||||
"no_copy": 0,
|
"no_copy": 1,
|
||||||
"options": "Sales Invoice",
|
"options": "Sales Invoice",
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
@ -1039,7 +1039,7 @@
|
|||||||
"is_submittable": 0,
|
"is_submittable": 0,
|
||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"modified": "2015-08-19 12:46:31.447022",
|
"modified": "2015-08-25 07:15:19.811365",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Stock",
|
"module": "Stock",
|
||||||
"name": "Delivery Note Item",
|
"name": "Delivery Note Item",
|
||||||
|
@ -29,6 +29,19 @@ class PurchaseReceipt(BuyingController):
|
|||||||
'source_field': 'qty',
|
'source_field': 'qty',
|
||||||
'percent_join_field': 'prevdoc_docname',
|
'percent_join_field': 'prevdoc_docname',
|
||||||
'overflow_type': 'receipt'
|
'overflow_type': 'receipt'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'source_dt': 'Purchase Receipt Item',
|
||||||
|
'target_dt': 'Purchase Order Item',
|
||||||
|
'join_field': 'prevdoc_detail_docname',
|
||||||
|
'target_field': 'returned_qty',
|
||||||
|
'target_parent_dt': 'Purchase Order',
|
||||||
|
# 'target_parent_field': 'per_received',
|
||||||
|
# 'target_ref_field': 'qty',
|
||||||
|
'source_field': '-1 * qty',
|
||||||
|
# 'percent_join_field': 'prevdoc_docname',
|
||||||
|
# 'overflow_type': 'receipt',
|
||||||
|
'extra_cond': """ and exists (select name from `tabPurchase Receipt` where name=`tabPurchase Receipt Item`.parent and is_return=1)"""
|
||||||
}]
|
}]
|
||||||
|
|
||||||
def onload(self):
|
def onload(self):
|
||||||
@ -68,12 +81,12 @@ class PurchaseReceipt(BuyingController):
|
|||||||
from `tabLanded Cost Item`
|
from `tabLanded Cost Item`
|
||||||
where docstatus = 1 and purchase_receipt_item = %s""", d.name)
|
where docstatus = 1 and purchase_receipt_item = %s""", d.name)
|
||||||
d.landed_cost_voucher_amount = lc_voucher_amount[0][0] if lc_voucher_amount else 0.0
|
d.landed_cost_voucher_amount = lc_voucher_amount[0][0] if lc_voucher_amount else 0.0
|
||||||
|
|
||||||
def validate_purchase_return(self):
|
def validate_purchase_return(self):
|
||||||
for d in self.get("items"):
|
for d in self.get("items"):
|
||||||
if self.is_return and flt(d.rejected_qty) != 0:
|
if self.is_return and flt(d.rejected_qty) != 0:
|
||||||
frappe.throw(_("Row #{0}: Rejected Qty can not be entered in Purchase Return").format(d.idx))
|
frappe.throw(_("Row #{0}: Rejected Qty can not be entered in Purchase Return").format(d.idx))
|
||||||
|
|
||||||
# validate rate with ref PR
|
# validate rate with ref PR
|
||||||
|
|
||||||
def validate_rejected_warehouse(self):
|
def validate_rejected_warehouse(self):
|
||||||
@ -113,7 +126,7 @@ class PurchaseReceipt(BuyingController):
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
if cint(frappe.db.get_single_value('Buying Settings', 'maintain_same_rate')):
|
if cint(frappe.db.get_single_value('Buying Settings', 'maintain_same_rate')) and not self.is_return:
|
||||||
self.validate_rate_with_reference_doc([["Purchase Order", "prevdoc_docname", "prevdoc_detail_docname"]])
|
self.validate_rate_with_reference_doc([["Purchase Order", "prevdoc_docname", "prevdoc_detail_docname"]])
|
||||||
|
|
||||||
def po_required(self):
|
def po_required(self):
|
||||||
@ -223,7 +236,7 @@ class PurchaseReceipt(BuyingController):
|
|||||||
|
|
||||||
self.update_prevdoc_status()
|
self.update_prevdoc_status()
|
||||||
self.update_ordered_qty()
|
self.update_ordered_qty()
|
||||||
|
|
||||||
if not self.is_return:
|
if not self.is_return:
|
||||||
purchase_controller.update_last_purchase_rate(self, 1)
|
purchase_controller.update_last_purchase_rate(self, 1)
|
||||||
|
|
||||||
@ -261,7 +274,7 @@ class PurchaseReceipt(BuyingController):
|
|||||||
self.update_prevdoc_status()
|
self.update_prevdoc_status()
|
||||||
# Must be called after updating received qty in PO
|
# Must be called after updating received qty in PO
|
||||||
self.update_ordered_qty()
|
self.update_ordered_qty()
|
||||||
|
|
||||||
if not self.is_return:
|
if not self.is_return:
|
||||||
pc_obj.update_last_purchase_rate(self, 0)
|
pc_obj.update_last_purchase_rate(self, 0)
|
||||||
|
|
||||||
@ -291,7 +304,7 @@ class PurchaseReceipt(BuyingController):
|
|||||||
if warehouse_account.get(d.warehouse):
|
if warehouse_account.get(d.warehouse):
|
||||||
|
|
||||||
val_rate_db_precision = 6 if cint(d.precision("valuation_rate")) <= 6 else 9
|
val_rate_db_precision = 6 if cint(d.precision("valuation_rate")) <= 6 else 9
|
||||||
|
|
||||||
# warehouse account
|
# warehouse account
|
||||||
gl_entries.append(self.get_gl_dict({
|
gl_entries.append(self.get_gl_dict({
|
||||||
"account": warehouse_account[d.warehouse],
|
"account": warehouse_account[d.warehouse],
|
||||||
@ -466,4 +479,4 @@ def get_invoiced_qty_map(purchase_receipt):
|
|||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def make_purchase_return(source_name, target_doc=None):
|
def make_purchase_return(source_name, target_doc=None):
|
||||||
from erpnext.controllers.sales_and_purchase_return import make_return_doc
|
from erpnext.controllers.sales_and_purchase_return import make_return_doc
|
||||||
return make_return_doc("Purchase Receipt", source_name, target_doc)
|
return make_return_doc("Purchase Receipt", source_name, target_doc)
|
||||||
|
@ -3,7 +3,7 @@ frappe.listview_settings['Purchase Receipt'] = {
|
|||||||
"transporter_name", "is_return"],
|
"transporter_name", "is_return"],
|
||||||
get_indicator: function(doc) {
|
get_indicator: function(doc) {
|
||||||
if(cint(doc.is_return)==1) {
|
if(cint(doc.is_return)==1) {
|
||||||
return [__("Return"), "darkgrey", "is_return,=,1"];
|
return [__("Return"), "darkgrey", "is_return,=,Yes"];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -33,7 +33,7 @@ class SerialNo(StockController):
|
|||||||
self.validate_warehouse()
|
self.validate_warehouse()
|
||||||
self.validate_item()
|
self.validate_item()
|
||||||
self.on_stock_ledger_entry()
|
self.on_stock_ledger_entry()
|
||||||
|
|
||||||
def set_maintenance_status(self):
|
def set_maintenance_status(self):
|
||||||
if not self.warranty_expiry_date and not self.amc_expiry_date:
|
if not self.warranty_expiry_date and not self.amc_expiry_date:
|
||||||
self.maintenance_status = None
|
self.maintenance_status = None
|
||||||
@ -209,7 +209,7 @@ def validate_serial_no(sle, item_det):
|
|||||||
frappe.throw(_("Serial No {0} quantity {1} cannot be a fraction").format(sle.item_code, sle.actual_qty))
|
frappe.throw(_("Serial No {0} quantity {1} cannot be a fraction").format(sle.item_code, sle.actual_qty))
|
||||||
|
|
||||||
if len(serial_nos) and len(serial_nos) != abs(cint(sle.actual_qty)):
|
if len(serial_nos) and len(serial_nos) != abs(cint(sle.actual_qty)):
|
||||||
frappe.throw(_("{0} Serial Numbers required for Item {0}. Only {0} provided.").format(sle.actual_qty, sle.item_code, len(serial_nos)),
|
frappe.throw(_("{0} Serial Numbers required for Item {1}. You have provided {2}.").format(sle.actual_qty, sle.item_code, len(serial_nos)),
|
||||||
SerialNoQtyError)
|
SerialNoQtyError)
|
||||||
|
|
||||||
if len(serial_nos) != len(set(serial_nos)):
|
if len(serial_nos) != len(set(serial_nos)):
|
||||||
|
@ -257,6 +257,10 @@ def validate_price_list(args):
|
|||||||
def validate_conversion_rate(args, meta):
|
def validate_conversion_rate(args, meta):
|
||||||
from erpnext.controllers.accounts_controller import validate_conversion_rate
|
from erpnext.controllers.accounts_controller import validate_conversion_rate
|
||||||
|
|
||||||
|
if (not args.conversion_rate
|
||||||
|
and args.currency==frappe.db.get_value("Company", args.company, "default_currency")):
|
||||||
|
args.conversion_rate = 1.0
|
||||||
|
|
||||||
# validate currency conversion rate
|
# validate currency conversion rate
|
||||||
validate_conversion_rate(args.currency, args.conversion_rate,
|
validate_conversion_rate(args.currency, args.conversion_rate,
|
||||||
meta.get_label("conversion_rate"), args.company)
|
meta.get_label("conversion_rate"), args.company)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user