Merge branch 'develop' of github.com:frappe/erpnext into feature-pick-list
This commit is contained in:
commit
ed4f8cf65d
@ -48,7 +48,10 @@ class BankAccount(Document):
|
||||
# Encode characters as numbers
|
||||
encoded = [encode_char(c) if ord(c) >= 65 and ord(c) <= 90 else c for c in flipped]
|
||||
|
||||
try:
|
||||
to_check = int(''.join(encoded))
|
||||
except ValueError:
|
||||
frappe.throw(_('IBAN is not valid'))
|
||||
|
||||
if to_check % 97 != 1:
|
||||
frappe.throw(_('IBAN is not valid'))
|
||||
|
@ -223,7 +223,10 @@ erpnext.accounts.JournalEntry = frappe.ui.form.Controller.extend({
|
||||
|
||||
if(in_list(["Sales Invoice", "Purchase Invoice"], jvd.reference_type)) {
|
||||
out.filters.push([jvd.reference_type, "outstanding_amount", "!=", 0]);
|
||||
|
||||
// Filter by cost center
|
||||
if(jvd.cost_center) {
|
||||
out.filters.push([jvd.reference_type, "cost_center", "in", ["", jvd.cost_center]]);
|
||||
}
|
||||
// account filter
|
||||
frappe.model.validate_missing(jvd, "account");
|
||||
var party_account_field = jvd.reference_type==="Sales Invoice" ? "debit_to": "credit_to";
|
||||
|
@ -1,751 +1,166 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_events_in_timeline": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"beta": 0,
|
||||
"creation": "2019-03-24 14:48:59.649168",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"disable",
|
||||
"column_break_2",
|
||||
"rule_description",
|
||||
"section_break_1",
|
||||
"min_qty",
|
||||
"max_qty",
|
||||
"column_break_3",
|
||||
"min_amount",
|
||||
"max_amount",
|
||||
"section_break_6",
|
||||
"same_item",
|
||||
"free_item",
|
||||
"free_qty",
|
||||
"column_break_9",
|
||||
"free_item_uom",
|
||||
"free_item_rate",
|
||||
"section_break_12",
|
||||
"warehouse",
|
||||
"threshold_percentage",
|
||||
"column_break_15",
|
||||
"priority",
|
||||
"apply_multiple_pricing_rules"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "0",
|
||||
"fieldname": "disable",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Disable",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"fieldtype": "Check",
|
||||
"label": "Disable"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "column_break_2",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "rule_description",
|
||||
"fieldtype": "Small Text",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Rule Description",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "section_break_1",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"fieldtype": "Section Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "0",
|
||||
"fieldname": "min_qty",
|
||||
"fieldtype": "Float",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Min Qty",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"label": "Min Qty"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "0",
|
||||
"fieldname": "max_qty",
|
||||
"fieldtype": "Float",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Max Qty",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"label": "Max Qty"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "column_break_3",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "0",
|
||||
"fieldname": "min_amount",
|
||||
"fieldtype": "Currency",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Min Amount",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"label": "Min Amount"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "0",
|
||||
"fieldname": "max_amount",
|
||||
"fieldtype": "Currency",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Max Amount",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"label": "Max Amount"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "section_break_6",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Free Item",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"label": "Free Item"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "0",
|
||||
"depends_on": "eval:!parent.mixed_conditions",
|
||||
"fieldname": "same_item",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Same Item",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"label": "Same Item"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "eval:!doc.same_item || parent.mixed_conditions",
|
||||
"fieldname": "free_item",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Item Code",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Item",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"options": "Item"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "free_qty",
|
||||
"fieldtype": "Float",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Qty",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"label": "Qty"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "column_break_9",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "free_item_uom",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "UOM",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "UOM",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"options": "UOM"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "free_item_rate",
|
||||
"fieldtype": "Currency",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Rate",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"label": "Rate"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "section_break_12",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"fieldtype": "Section Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "warehouse",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Warehouse",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Warehouse",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"options": "Warehouse"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "threshold_percentage",
|
||||
"fieldtype": "Percent",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Threshold for Suggestion",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"label": "Threshold for Suggestion"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "column_break_15",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "priority",
|
||||
"fieldtype": "Select",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Priority",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"options": "\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "0",
|
||||
"fieldname": "apply_multiple_pricing_rules",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Apply Multiple Pricing Rules",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"label": "Apply Multiple Pricing Rules"
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 0,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 1,
|
||||
"max_attachments": 0,
|
||||
"modified": "2019-03-24 14:48:59.649168",
|
||||
"modified": "2019-07-21 00:00:56.674284",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Promotional Scheme Product Discount",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"quick_entry": 0,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 0,
|
||||
"track_seen": 0,
|
||||
"track_views": 0
|
||||
"sort_order": "DESC"
|
||||
}
|
@ -336,6 +336,7 @@ class PurchaseInvoice(BuyingController):
|
||||
|
||||
if not self.is_return:
|
||||
self.update_against_document_in_jv()
|
||||
self.update_billing_status_for_zero_amount_refdoc("Purchase Receipt")
|
||||
self.update_billing_status_for_zero_amount_refdoc("Purchase Order")
|
||||
|
||||
self.update_billing_status_in_pr()
|
||||
@ -774,6 +775,7 @@ class PurchaseInvoice(BuyingController):
|
||||
self.update_prevdoc_status()
|
||||
|
||||
if not self.is_return:
|
||||
self.update_billing_status_for_zero_amount_refdoc("Purchase Receipt")
|
||||
self.update_billing_status_for_zero_amount_refdoc("Purchase Order")
|
||||
|
||||
self.update_billing_status_in_pr()
|
||||
|
@ -451,6 +451,10 @@ def make_customer_and_address(customers):
|
||||
|
||||
|
||||
def add_customer(data):
|
||||
customer = data.get('full_name') or data.get('customer')
|
||||
if frappe.db.exists("Customer", customer.strip()):
|
||||
return customer.strip()
|
||||
|
||||
customer_doc = frappe.new_doc('Customer')
|
||||
customer_doc.customer_name = data.get('full_name') or data.get('customer')
|
||||
customer_doc.customer_pos_id = data.get('customer_pos_id')
|
||||
|
@ -166,6 +166,7 @@ class SalesInvoice(SellingController):
|
||||
self.make_gl_entries()
|
||||
|
||||
if not self.is_return:
|
||||
self.update_billing_status_for_zero_amount_refdoc("Delivery Note")
|
||||
self.update_billing_status_for_zero_amount_refdoc("Sales Order")
|
||||
self.check_credit_limit()
|
||||
|
||||
@ -220,6 +221,7 @@ class SalesInvoice(SellingController):
|
||||
self.update_billing_status_in_dn()
|
||||
|
||||
if not self.is_return:
|
||||
self.update_billing_status_for_zero_amount_refdoc("Delivery Note")
|
||||
self.update_billing_status_for_zero_amount_refdoc("Sales Order")
|
||||
self.update_serial_no(in_cancel=True)
|
||||
|
||||
@ -395,14 +397,17 @@ class SalesInvoice(SellingController):
|
||||
if pos.get('account_for_change_amount'):
|
||||
self.account_for_change_amount = pos.get('account_for_change_amount')
|
||||
|
||||
for fieldname in ('territory', 'naming_series', 'currency', 'taxes_and_charges', 'letter_head', 'tc_name',
|
||||
'company', 'select_print_heading', 'cash_bank_account', 'company_address',
|
||||
'write_off_account', 'write_off_cost_center', 'apply_discount_on', 'cost_center'):
|
||||
for fieldname in ('territory', 'naming_series', 'currency', 'letter_head', 'tc_name',
|
||||
'company', 'select_print_heading', 'cash_bank_account', 'write_off_account', 'taxes_and_charges',
|
||||
'write_off_cost_center', 'apply_discount_on', 'cost_center'):
|
||||
if (not for_validate) or (for_validate and not self.get(fieldname)):
|
||||
self.set(fieldname, pos.get(fieldname))
|
||||
|
||||
customer_price_list = frappe.get_value("Customer", self.customer, 'default_price_list')
|
||||
|
||||
if pos.get("company_address"):
|
||||
self.company_address = pos.get("company_address")
|
||||
|
||||
if not customer_price_list:
|
||||
self.set('selling_price_list', pos.get('selling_price_list'))
|
||||
|
||||
@ -1255,9 +1260,8 @@ def validate_inter_company_party(doctype, party, company, inter_company_referenc
|
||||
frappe.throw(_("Invalid Company for Inter Company Transaction."))
|
||||
|
||||
elif frappe.db.get_value(partytype, {"name": party, internal: 1}, "name") == party:
|
||||
companies = frappe.db.sql("""select company from `tabAllowed To Transact With`
|
||||
where parenttype = '{0}' and parent = '{1}'""".format(partytype, party), as_list = 1)
|
||||
companies = [d[0] for d in companies]
|
||||
companies = frappe.get_all("Allowed To Transact With", fields=["company"], filters={"parenttype": partytype, "parent": party})
|
||||
companies = [d.company for d in companies]
|
||||
if not company in companies:
|
||||
frappe.throw(_("{0} not allowed to transact with {1}. Please change the Company.").format(partytype, company))
|
||||
|
||||
|
@ -55,9 +55,16 @@ def get_columns():
|
||||
"fieldtype": "Date",
|
||||
"width": 90
|
||||
},
|
||||
{
|
||||
"fieldname": "payment_document",
|
||||
"label": _("Payment Document Type"),
|
||||
"fieldtype": "Link",
|
||||
"options": "DocType",
|
||||
"width": 220
|
||||
},
|
||||
{
|
||||
"fieldname": "payment_entry",
|
||||
"label": _("Payment Entry"),
|
||||
"label": _("Payment Document"),
|
||||
"fieldtype": "Dynamic Link",
|
||||
"options": "payment_document",
|
||||
"width": 220
|
||||
|
@ -125,8 +125,9 @@ def get_account_type_based_data(company, account_type, period_list, accumulated_
|
||||
data["total"] = total
|
||||
return data
|
||||
|
||||
def get_account_type_based_gl_data(company, start_date, end_date, account_type, filters):
|
||||
def get_account_type_based_gl_data(company, start_date, end_date, account_type, filters={}):
|
||||
cond = ""
|
||||
filters = frappe._dict(filters)
|
||||
|
||||
if filters.finance_book:
|
||||
cond = " and finance_book = %s" %(frappe.db.escape(filters.finance_book))
|
||||
|
@ -130,7 +130,7 @@ def get_cash_flow_data(fiscal_year, companies, filters):
|
||||
section_data.append(net_profit_loss)
|
||||
|
||||
for account in cash_flow_account['account_types']:
|
||||
account_data = get_account_type_based_data(account['account_type'], companies, fiscal_year)
|
||||
account_data = get_account_type_based_data(account['account_type'], companies, fiscal_year, filters)
|
||||
account_data.update({
|
||||
"account_name": account['label'],
|
||||
"account": account['label'],
|
||||
@ -148,12 +148,12 @@ def get_cash_flow_data(fiscal_year, companies, filters):
|
||||
|
||||
return data
|
||||
|
||||
def get_account_type_based_data(account_type, companies, fiscal_year):
|
||||
def get_account_type_based_data(account_type, companies, fiscal_year, filters):
|
||||
data = {}
|
||||
total = 0
|
||||
for company in companies:
|
||||
amount = get_account_type_based_gl_data(company,
|
||||
fiscal_year.year_start_date, fiscal_year.year_end_date, account_type)
|
||||
fiscal_year.year_start_date, fiscal_year.year_end_date, account_type, filters)
|
||||
|
||||
if amount and account_type == "Depreciation":
|
||||
amount *= -1
|
||||
|
@ -121,7 +121,12 @@ def get_balance_on(account=None, date=None, party_type=None, party=None, company
|
||||
|
||||
allow_cost_center_in_entry_of_bs_account = get_allow_cost_center_in_entry_of_bs_account()
|
||||
|
||||
if cost_center and (allow_cost_center_in_entry_of_bs_account or acc.report_type =='Profit and Loss'):
|
||||
if account:
|
||||
report_type = acc.report_type
|
||||
else:
|
||||
report_type = ""
|
||||
|
||||
if cost_center and (allow_cost_center_in_entry_of_bs_account or report_type =='Profit and Loss'):
|
||||
cc = frappe.get_doc("Cost Center", cost_center)
|
||||
if cc.is_group:
|
||||
cond.append(""" exists (
|
||||
@ -138,7 +143,7 @@ def get_balance_on(account=None, date=None, party_type=None, party=None, company
|
||||
if not frappe.flags.ignore_account_permission:
|
||||
acc.check_permission("read")
|
||||
|
||||
if acc.report_type == 'Profit and Loss':
|
||||
if report_type == 'Profit and Loss':
|
||||
# for pl accounts, get balance within a fiscal year
|
||||
cond.append("posting_date >= '%s' and voucher_type != 'Period Closing Voucher'" \
|
||||
% year_start_date)
|
||||
@ -685,7 +690,7 @@ def get_outstanding_invoices(party_type, party, account, condition=None, filters
|
||||
payment_amount = pe_map.get((d.voucher_type, d.voucher_no), 0)
|
||||
outstanding_amount = flt(d.invoice_amount - payment_amount, precision)
|
||||
if outstanding_amount > 0.5 / (10**precision):
|
||||
if (filters.get("outstanding_amt_greater_than") and
|
||||
if (filters and filters.get("outstanding_amt_greater_than") and
|
||||
not (outstanding_amount >= filters.get("outstanding_amt_greater_than") and
|
||||
outstanding_amount <= filters.get("outstanding_amt_less_than"))):
|
||||
continue
|
||||
@ -730,7 +735,6 @@ def get_children(doctype, parent, company, is_root=False):
|
||||
parent_fieldname = 'parent_' + doctype.lower().replace(' ', '_')
|
||||
fields = [
|
||||
'name as value',
|
||||
'root_type',
|
||||
'is_group as expandable'
|
||||
]
|
||||
filters = [['docstatus', '<', 2]]
|
||||
@ -738,11 +742,11 @@ def get_children(doctype, parent, company, is_root=False):
|
||||
filters.append(['ifnull(`{0}`,"")'.format(parent_fieldname), '=', '' if is_root else parent])
|
||||
|
||||
if is_root:
|
||||
fields += ['report_type', 'account_currency'] if doctype == 'Account' else []
|
||||
fields += ['root_type', 'report_type', 'account_currency'] if doctype == 'Account' else []
|
||||
filters.append(['company', '=', company])
|
||||
|
||||
else:
|
||||
fields += ['account_currency'] if doctype == 'Account' else []
|
||||
fields += ['root_type', 'account_currency'] if doctype == 'Account' else []
|
||||
fields += [parent_fieldname + ' as parent']
|
||||
|
||||
acc = frappe.get_list(doctype, fields=fields, filters=filters)
|
||||
|
@ -388,7 +388,8 @@ class Asset(AccountsController):
|
||||
"remarks": self.get("remarks") or _("Accounting Entry for Asset"),
|
||||
"posting_date": self.available_for_use_date,
|
||||
"credit": self.purchase_receipt_amount,
|
||||
"credit_in_account_currency": self.purchase_receipt_amount
|
||||
"credit_in_account_currency": self.purchase_receipt_amount,
|
||||
"cost_center": self.cost_center
|
||||
}))
|
||||
|
||||
gl_entries.append(self.get_gl_dict({
|
||||
@ -397,7 +398,8 @@ class Asset(AccountsController):
|
||||
"remarks": self.get("remarks") or _("Accounting Entry for Asset"),
|
||||
"posting_date": self.available_for_use_date,
|
||||
"debit": self.purchase_receipt_amount,
|
||||
"debit_in_account_currency": self.purchase_receipt_amount
|
||||
"debit_in_account_currency": self.purchase_receipt_amount,
|
||||
"cost_center": self.cost_center
|
||||
}))
|
||||
|
||||
if gl_entries:
|
||||
|
@ -7,7 +7,7 @@
|
||||
"doctype": "Report",
|
||||
"idx": 0,
|
||||
"is_standard": "Yes",
|
||||
"modified": "2019-03-29 17:18:06.678728",
|
||||
"modified": "2019-07-21 23:24:21.094269",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Buying",
|
||||
"name": "Procurement Tracker",
|
||||
@ -16,5 +16,12 @@
|
||||
"ref_doctype": "Purchase Order",
|
||||
"report_name": "Procurement Tracker",
|
||||
"report_type": "Script Report",
|
||||
"roles": []
|
||||
"roles": [
|
||||
{
|
||||
"role": "Purchase Manager"
|
||||
},
|
||||
{
|
||||
"role": "Purchase User"
|
||||
}
|
||||
]
|
||||
}
|
@ -150,10 +150,10 @@ def get_conditions(filters):
|
||||
"""% (filters.get('cost_center'), filters.get('project'))
|
||||
|
||||
if filters.get("from_date"):
|
||||
conditions += "AND transaction_date>=%s"% filters.get('from_date')
|
||||
conditions += " AND transaction_date>=%s"% filters.get('from_date')
|
||||
|
||||
if filters.get("to_date"):
|
||||
conditions += "AND transaction_date<=%s"% filters.get('to_date')
|
||||
conditions += " AND transaction_date<=%s"% filters.get('to_date')
|
||||
return conditions
|
||||
|
||||
def get_data(filters):
|
||||
|
@ -157,6 +157,13 @@ def get_data():
|
||||
"reference_doctype": "Purchase Order",
|
||||
"onboard": 1,
|
||||
},
|
||||
{
|
||||
"type": "report",
|
||||
"is_query_report": True,
|
||||
"name": "Procurement Tracker",
|
||||
"reference_doctype": "Purchase Order",
|
||||
"onboard": 1,
|
||||
},
|
||||
{
|
||||
"type": "report",
|
||||
"is_query_report": True,
|
||||
|
@ -141,6 +141,11 @@ def get_data():
|
||||
"name": "Campaign",
|
||||
"description": _("Sales campaigns."),
|
||||
},
|
||||
{
|
||||
"type": "doctype",
|
||||
"name": "Email Campaign",
|
||||
"description": _("Sends Mails to lead or contact based on a Campaign schedule"),
|
||||
},
|
||||
{
|
||||
"type": "doctype",
|
||||
"name": "SMS Center",
|
||||
|
@ -219,6 +219,11 @@ def get_data():
|
||||
"name": "Employee Onboarding",
|
||||
"dependencies": ["Job Applicant"],
|
||||
},
|
||||
{
|
||||
"type": "doctype",
|
||||
"name": "Employee Skill Map",
|
||||
"dependencies": ["Employee"],
|
||||
},
|
||||
{
|
||||
"type": "doctype",
|
||||
"name": "Employee Promotion",
|
||||
|
@ -861,7 +861,7 @@ class AccountsController(TransactionBase):
|
||||
|
||||
if self.doctype in ("Sales Invoice", "Purchase Invoice"):
|
||||
grand_total = grand_total - flt(self.write_off_amount)
|
||||
if total != grand_total:
|
||||
if total != flt(grand_total, self.precision("grand_total")):
|
||||
frappe.throw(_("Total Payment Amount in Payment Schedule must be equal to Grand / Rounded Total"))
|
||||
|
||||
def is_rounded_total_disabled(self):
|
||||
|
@ -636,7 +636,8 @@ class BuyingController(StockController):
|
||||
asset.set_missing_values()
|
||||
asset.insert()
|
||||
|
||||
frappe.msgprint(_("Asset {0} created").format(asset.name))
|
||||
asset_link = frappe.utils.get_link_to_form('Asset', asset.name)
|
||||
frappe.msgprint(_("Asset {0} created").format(asset_link))
|
||||
return asset.name
|
||||
|
||||
def make_asset_movement(self, row):
|
||||
|
@ -207,10 +207,10 @@ def bom(doctype, txt, searchfield, start, page_len, filters):
|
||||
idx desc, name
|
||||
limit %(start)s, %(page_len)s """.format(
|
||||
fcond=get_filters_cond(doctype, filters, conditions).replace('%', '%%'),
|
||||
mcond=get_match_cond(doctype),
|
||||
key=frappe.db.escape(searchfield)),
|
||||
mcond=get_match_cond(doctype).replace('%', '%%'),
|
||||
key=searchfield),
|
||||
{
|
||||
'txt': "%"+frappe.db.escape(txt)+"%",
|
||||
'txt': '%' + txt + '%',
|
||||
'_txt': txt.replace("%", ""),
|
||||
'start': start or 0,
|
||||
'page_len': page_len or 20
|
||||
|
@ -40,7 +40,6 @@ status_map = {
|
||||
["To Bill", "eval:self.per_delivered == 100 and self.per_billed < 100 and self.docstatus == 1"],
|
||||
["To Deliver", "eval:self.per_delivered < 100 and self.per_billed == 100 and self.docstatus == 1"],
|
||||
["Completed", "eval:self.per_delivered == 100 and self.per_billed == 100 and self.docstatus == 1"],
|
||||
["Completed", "eval:self.order_type == 'Maintenance' and self.per_billed == 100 and self.docstatus == 1"],
|
||||
["Cancelled", "eval:self.docstatus==2"],
|
||||
["Closed", "eval:self.status=='Closed'"],
|
||||
["On Hold", "eval:self.status=='On Hold'"],
|
||||
@ -90,7 +89,8 @@ status_map = {
|
||||
["Transferred", "eval:self.status != 'Stopped' and self.per_ordered == 100 and self.docstatus == 1 and self.material_request_type == 'Material Transfer'"],
|
||||
["Issued", "eval:self.status != 'Stopped' and self.per_ordered == 100 and self.docstatus == 1 and self.material_request_type == 'Material Issue'"],
|
||||
["Received", "eval:self.status != 'Stopped' and self.per_received == 100 and self.docstatus == 1 and self.material_request_type == 'Purchase'"],
|
||||
["Partially Received", "eval:self.status != 'Stopped' and self.per_received > 0 and self.per_received < 100 and self.docstatus == 1 and self.material_request_type == 'Purchase'"]
|
||||
["Partially Received", "eval:self.status != 'Stopped' and self.per_received > 0 and self.per_received < 100 and self.docstatus == 1 and self.material_request_type == 'Purchase'"],
|
||||
["Manufactured", "eval:self.status != 'Stopped' and self.per_ordered == 100 and self.docstatus == 1 and self.material_request_type == 'Manufacture'"]
|
||||
],
|
||||
"Bank Transaction": [
|
||||
["Unreconciled", "eval:self.docstatus == 1 and self.unallocated_amount>0"],
|
||||
|
@ -323,7 +323,7 @@ class calculate_taxes_and_totals(object):
|
||||
self._set_in_company_currency(self.doc, ["total_taxes_and_charges", "rounding_adjustment"])
|
||||
|
||||
if self.doc.doctype in ["Quotation", "Sales Order", "Delivery Note", "Sales Invoice"]:
|
||||
self.doc.base_grand_total = flt(self.doc.grand_total * self.doc.conversion_rate) \
|
||||
self.doc.base_grand_total = flt(self.doc.grand_total * self.doc.conversion_rate, self.doc.precision("base_grand_total")) \
|
||||
if self.doc.total_taxes_and_charges else self.doc.base_net_total
|
||||
else:
|
||||
self.doc.taxes_and_charges_added = self.doc.taxes_and_charges_deducted = 0.0
|
||||
|
@ -0,0 +1,38 @@
|
||||
{
|
||||
"creation": "2019-06-30 15:56:20.306901",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"email_template",
|
||||
"send_after_days"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "send_after_days",
|
||||
"fieldtype": "Int",
|
||||
"in_list_view": 1,
|
||||
"label": "Send After (days)",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "email_template",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Email Template",
|
||||
"options": "Email Template",
|
||||
"reqd": 1
|
||||
}
|
||||
],
|
||||
"istable": 1,
|
||||
"modified": "2019-07-12 11:46:43.184123",
|
||||
"modified_by": "Administrator",
|
||||
"module": "CRM",
|
||||
"name": "Campaign Email Schedule",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"quick_entry": 1,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
# import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
class CampaignEmailSchedule(Document):
|
||||
pass
|
0
erpnext/crm/doctype/email_campaign/__init__.py
Normal file
0
erpnext/crm/doctype/email_campaign/__init__.py
Normal file
8
erpnext/crm/doctype/email_campaign/email_campaign.js
Normal file
8
erpnext/crm/doctype/email_campaign/email_campaign.js
Normal file
@ -0,0 +1,8 @@
|
||||
// Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Email Campaign', {
|
||||
email_campaign_for: function(frm) {
|
||||
frm.set_value('recipient', '');
|
||||
}
|
||||
});
|
95
erpnext/crm/doctype/email_campaign/email_campaign.json
Normal file
95
erpnext/crm/doctype/email_campaign/email_campaign.json
Normal file
@ -0,0 +1,95 @@
|
||||
{
|
||||
"autoname": "format:MAIL-CAMP-{YYYY}-{#####}",
|
||||
"creation": "2019-06-30 16:05:30.015615",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"campaign_name",
|
||||
"email_campaign_for",
|
||||
"recipient",
|
||||
"sender",
|
||||
"column_break_4",
|
||||
"start_date",
|
||||
"end_date",
|
||||
"status"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "campaign_name",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Campaign",
|
||||
"options": "Campaign",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "status",
|
||||
"fieldtype": "Select",
|
||||
"label": "Status",
|
||||
"options": "\nScheduled\nIn Progress\nCompleted\nUnsubscribed",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_4",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "start_date",
|
||||
"fieldtype": "Date",
|
||||
"label": "Start Date",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "end_date",
|
||||
"fieldtype": "Date",
|
||||
"label": "End Date",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"default": "Lead",
|
||||
"fieldname": "email_campaign_for",
|
||||
"fieldtype": "Select",
|
||||
"in_list_view": 1,
|
||||
"label": "Email Campaign For ",
|
||||
"options": "\nLead\nContact"
|
||||
},
|
||||
{
|
||||
"fieldname": "recipient",
|
||||
"fieldtype": "Dynamic Link",
|
||||
"label": "Recipient",
|
||||
"options": "email_campaign_for",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"default": "__user",
|
||||
"fieldname": "sender",
|
||||
"fieldtype": "Link",
|
||||
"label": "Sender",
|
||||
"options": "User"
|
||||
}
|
||||
],
|
||||
"modified": "2019-07-12 13:47:37.261213",
|
||||
"modified_by": "Administrator",
|
||||
"module": "CRM",
|
||||
"name": "Email Campaign",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 1,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1
|
||||
}
|
102
erpnext/crm/doctype/email_campaign/email_campaign.py
Normal file
102
erpnext/crm/doctype/email_campaign/email_campaign.py
Normal file
@ -0,0 +1,102 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe import _
|
||||
from frappe.utils import getdate, add_days, today, nowdate, cstr
|
||||
from frappe.model.document import Document
|
||||
from frappe.core.doctype.communication.email import make
|
||||
|
||||
class EmailCampaign(Document):
|
||||
def validate(self):
|
||||
self.set_date()
|
||||
#checking if email is set for lead. Not checking for contact as email is a mandatory field for contact.
|
||||
if self.email_campaign_for == "Lead":
|
||||
self.validate_lead()
|
||||
self.validate_email_campaign_already_exists()
|
||||
self.update_status()
|
||||
|
||||
def set_date(self):
|
||||
if getdate(self.start_date) < getdate(today()):
|
||||
frappe.throw(_("Start Date cannot be before the current date"))
|
||||
#set the end date as start date + max(send after days) in campaign schedule
|
||||
send_after_days = []
|
||||
campaign = frappe.get_doc("Campaign", self.campaign_name)
|
||||
for entry in campaign.get("campaign_schedules"):
|
||||
send_after_days.append(entry.send_after_days)
|
||||
try:
|
||||
end_date = add_days(getdate(self.start_date), max(send_after_days))
|
||||
except ValueError:
|
||||
frappe.throw(_("Please set up the Campaign Schedule in the Campaign {0}").format(self.campaign_name))
|
||||
|
||||
def validate_lead(self):
|
||||
lead_email_id = frappe.db.get_value("Lead", self.recipient, 'email_id')
|
||||
if not lead_email_id:
|
||||
lead_name = frappe.db.get_value("Lead", self.recipient, 'lead_name')
|
||||
frappe.throw(_("Please set an email id for the Lead {0}").format(lead_name))
|
||||
|
||||
def validate_email_campaign_already_exists(self):
|
||||
email_campaign_exists = frappe.db.exists("Email Campaign", {
|
||||
"campaign_name": self.campaign_name,
|
||||
"recipient": self.recipient,
|
||||
"status": ("in", ["In Progress", "Scheduled"])
|
||||
})
|
||||
if email_campaign_exists:
|
||||
frappe.throw(_("The Campaign '{0}' already exists for the {1} '{2}'").format(self.campaign_name, self.email_campaign_for, self.recipient))
|
||||
|
||||
def update_status(self):
|
||||
start_date = getdate(self.start_date)
|
||||
end_date = getdate(self.end_date)
|
||||
today_date = getdate(today())
|
||||
if start_date > today_date:
|
||||
self.status = "Scheduled"
|
||||
elif end_date >= today_date:
|
||||
self.status = "In Progress"
|
||||
elif end_date < today_date:
|
||||
self.status = "Completed"
|
||||
|
||||
#called through hooks to send campaign mails to leads
|
||||
def send_email_to_leads_or_contacts():
|
||||
email_campaigns = frappe.get_all("Email Campaign", filters = { 'status': ('not in', ['Unsubscribed', 'Completed', 'Scheduled']) })
|
||||
for camp in email_campaigns:
|
||||
email_campaign = frappe.get_doc("Email Campaign", camp.name)
|
||||
campaign = frappe.get_cached_doc("Campaign", email_campaign.campaign_name)
|
||||
for entry in campaign.get("campaign_schedules"):
|
||||
scheduled_date = add_days(email_campaign.get('start_date'), entry.get('send_after_days'))
|
||||
if scheduled_date == getdate(today()):
|
||||
send_mail(entry, email_campaign)
|
||||
|
||||
def send_mail(entry, email_campaign):
|
||||
recipient = frappe.db.get_value(email_campaign.email_campaign_for, email_campaign.get("recipient"), 'email_id')
|
||||
|
||||
email_template = frappe.get_doc("Email Template", entry.get("email_template"))
|
||||
sender = frappe.db.get_value("User", email_campaign.get("sender"), 'email')
|
||||
|
||||
# send mail and link communication to document
|
||||
comm = make(
|
||||
doctype = "Email Campaign",
|
||||
name = email_campaign.name,
|
||||
subject = email_template.get("subject"),
|
||||
content = email_template.get("response"),
|
||||
sender = sender,
|
||||
recipients = recipient,
|
||||
communication_medium = "Email",
|
||||
sent_or_received = "Sent",
|
||||
send_email = True,
|
||||
email_template = email_template.name
|
||||
)
|
||||
return comm
|
||||
|
||||
#called from hooks on doc_event Email Unsubscribe
|
||||
def unsubscribe_recipient(unsubscribe, method):
|
||||
if unsubscribe.reference_doctype == 'Email Campaign':
|
||||
frappe.db.set_value("Email Campaign", unsubscribe.reference_name, "status", "Unsubscribed")
|
||||
|
||||
#called through hooks to update email campaign status daily
|
||||
def set_email_campaign_status():
|
||||
email_campaigns = frappe.get_all("Email Campaign", filters = { 'status': ('!=', 'Unsubscribed')})
|
||||
for entry in email_campaigns:
|
||||
email_campaign = frappe.get_doc("Email Campaign", entry.name)
|
||||
email_campaign.update_status()
|
11
erpnext/crm/doctype/email_campaign/email_campaign_list.js
Normal file
11
erpnext/crm/doctype/email_campaign/email_campaign_list.js
Normal file
@ -0,0 +1,11 @@
|
||||
frappe.listview_settings['Email Campaign'] = {
|
||||
get_indicator: function(doc) {
|
||||
var colors = {
|
||||
"Unsubscribed": "red",
|
||||
"Scheduled": "blue",
|
||||
"In Progress": "orange",
|
||||
"Completed": "green"
|
||||
};
|
||||
return [__(doc.status), colors[doc.status], "status,=," + doc.status];
|
||||
}
|
||||
};
|
10
erpnext/crm/doctype/email_campaign/test_email_campaign.py
Normal file
10
erpnext/crm/doctype/email_campaign/test_email_campaign.py
Normal file
@ -0,0 +1,10 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# See license.txt
|
||||
from __future__ import unicode_literals
|
||||
|
||||
# import frappe
|
||||
import unittest
|
||||
|
||||
class TestEmailCampaign(unittest.TestCase):
|
||||
pass
|
@ -7,14 +7,8 @@ cur_frm.email_field = "email_id";
|
||||
erpnext.LeadController = frappe.ui.form.Controller.extend({
|
||||
setup: function () {
|
||||
this.frm.make_methods = {
|
||||
'Quotation': () => erpnext.utils.create_new_doc('Quotation', {
|
||||
'quotation_to': this.frm.doc.doctype,
|
||||
'party_name': this.frm.doc.name
|
||||
}),
|
||||
'Opportunity': () => erpnext.utils.create_new_doc('Opportunity', {
|
||||
'opportunity_from': this.frm.doc.doctype,
|
||||
'party_name': this.frm.doc.name
|
||||
})
|
||||
'Quotation': this.make_quotation,
|
||||
'Opportunity': this.create_opportunity
|
||||
}
|
||||
|
||||
this.frm.fields_dict.customer.get_query = function (doc, cdt, cdn) {
|
||||
|
@ -296,7 +296,9 @@ class TallyMigration(Document):
|
||||
else:
|
||||
function = voucher_to_journal_entry
|
||||
try:
|
||||
vouchers.append(function(voucher))
|
||||
processed_voucher = function(voucher)
|
||||
if processed_voucher:
|
||||
vouchers.append(processed_voucher)
|
||||
except:
|
||||
self.log(voucher)
|
||||
return vouchers
|
||||
@ -342,6 +344,10 @@ class TallyMigration(Document):
|
||||
account_field = "credit_to"
|
||||
account_name = encode_company_abbr(self.tally_creditors_account, self.erpnext_company)
|
||||
price_list_field = "buying_price_list"
|
||||
else:
|
||||
# Do not handle vouchers other than "Purchase", "Debit Note", "Sales" and "Credit Note"
|
||||
# Do not handle Custom Vouchers either
|
||||
return
|
||||
|
||||
invoice = {
|
||||
"doctype": doctype,
|
||||
|
@ -233,6 +233,9 @@ doc_events = {
|
||||
},
|
||||
"Contact":{
|
||||
"on_trash": "erpnext.support.doctype.issue.issue.update_issue"
|
||||
},
|
||||
"Email Unsubscribe": {
|
||||
"after_insert": "erpnext.crm.doctype.email_campaign.email_campaign.unsubscribe_recipient"
|
||||
}
|
||||
}
|
||||
|
||||
@ -272,6 +275,8 @@ scheduler_events = {
|
||||
"erpnext.projects.doctype.project.project.send_project_status_email_to_users",
|
||||
"erpnext.quality_management.doctype.quality_review.quality_review.review",
|
||||
"erpnext.support.doctype.service_level_agreement.service_level_agreement.check_agreement_status",
|
||||
"erpnext.crm.doctype.email_campaign.email_campaign.send_email_to_leads_or_contacts",
|
||||
"erpnext.crm.doctype.email_campaign.email_campaign.set_email_campaign_status"
|
||||
],
|
||||
"daily_long": [
|
||||
"erpnext.manufacturing.doctype.bom_update_tool.bom_update_tool.update_latest_price_in_all_boms"
|
||||
|
@ -4,4 +4,17 @@ from __future__ import unicode_literals
|
||||
|
||||
|
||||
import frappe
|
||||
test_records = frappe.get_test_records('Designation')
|
||||
# test_records = frappe.get_test_records('Designation')
|
||||
|
||||
def create_designation(**args):
|
||||
args = frappe._dict(args)
|
||||
if frappe.db.exists("Designation", args.designation_name or "_Test designation"):
|
||||
return frappe.get_doc("Designation", args.designation_name or "_Test designation")
|
||||
|
||||
designation = frappe.get_doc({
|
||||
"doctype": "Designation",
|
||||
"designation_name": args.designation_name or "_Test designation",
|
||||
"description": args.description or "_Test description"
|
||||
})
|
||||
designation.save()
|
||||
return designation
|
@ -1,516 +1,124 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 1,
|
||||
"allow_rename": 1,
|
||||
"autoname": "naming_series:",
|
||||
"beta": 0,
|
||||
"creation": "2017-10-17 08:21:50.489773",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "Setup",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"naming_series",
|
||||
"full_name",
|
||||
"status",
|
||||
"transporter",
|
||||
"column_break_2",
|
||||
"employee",
|
||||
"cell_number",
|
||||
"address",
|
||||
"license_details",
|
||||
"license_number",
|
||||
"column_break_8",
|
||||
"issuing_date",
|
||||
"column_break_10",
|
||||
"expiry_date",
|
||||
"driving_license_categories",
|
||||
"driving_license_category"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "",
|
||||
"fieldname": "naming_series",
|
||||
"fieldtype": "Select",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Series",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "HR-DRI-.YYYY.-",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"options": "HR-DRI-.YYYY.-"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "full_name",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Full Name",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "status",
|
||||
"fieldtype": "Select",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Status",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Active\nSuspended\nLeft",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 1,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"description": "Applicable for external driver",
|
||||
"fieldname": "transporter",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Transporter",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Supplier",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"options": "Supplier"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "column_break_2",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "employee",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Employee",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Employee",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"options": "Employee"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "cell_number",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Cellphone Number",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"label": "Cellphone Number"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "license_details",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "License Details",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"label": "License Details"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "license_number",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "License Number",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"label": "License Number"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "column_break_8",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "issuing_date",
|
||||
"fieldtype": "Date",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Issuing Date",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"label": "Issuing Date"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "column_break_10",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "expiry_date",
|
||||
"fieldtype": "Date",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Expiry Date",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"label": "Expiry Date"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "driving_license_categories",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Driving License Categories",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"label": "Driving License Categories"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "driving_license_category",
|
||||
"fieldtype": "Table",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Driving License Category",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Driving License Category",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"options": "Driving License Category"
|
||||
},
|
||||
{
|
||||
"fieldname": "address",
|
||||
"fieldtype": "Link",
|
||||
"label": "Address",
|
||||
"options": "Address"
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"icon": "fa fa-user",
|
||||
"idx": 0,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2018-10-03 19:53:50.924391",
|
||||
"modified": "2019-07-18 16:29:14.151380",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Driver",
|
||||
@ -518,72 +126,44 @@
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"amend": 0,
|
||||
"cancel": 0,
|
||||
"create": 0,
|
||||
"delete": 0,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Fleet Manager",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"write": 0
|
||||
"share": 1
|
||||
},
|
||||
{
|
||||
"amend": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "HR User",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"amend": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "HR Manager",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 1,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"search_fields": "full_name",
|
||||
"show_name_in_global_search": 1,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"title_field": "full_name",
|
||||
"track_changes": 1,
|
||||
"track_seen": 0,
|
||||
"track_views": 0
|
||||
"track_changes": 1
|
||||
}
|
@ -12,6 +12,7 @@ from frappe.permissions import add_user_permission, remove_user_permission, \
|
||||
from frappe.model.document import Document
|
||||
from erpnext.utilities.transaction_base import delete_events
|
||||
from frappe.utils.nestedset import NestedSet
|
||||
from erpnext.hr.doctype.job_offer.job_offer import get_staffing_plan_detail
|
||||
|
||||
class EmployeeUserDisabledError(frappe.ValidationError): pass
|
||||
class EmployeeLeftValidationError(frappe.ValidationError): pass
|
||||
|
@ -3,6 +3,7 @@
|
||||
"doctype": "DocType",
|
||||
"document_type": "Other",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"employee_settings",
|
||||
"retirement_age",
|
||||
@ -22,7 +23,9 @@
|
||||
"leave_status_notification_template",
|
||||
"column_break_18",
|
||||
"leave_approver_mandatory_in_leave_application",
|
||||
"show_leaves_of_all_department_members_in_calendar"
|
||||
"show_leaves_of_all_department_members_in_calendar",
|
||||
"hiring_settings",
|
||||
"check_vacancies"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
@ -44,18 +47,6 @@
|
||||
"label": "Employee Records to be created by",
|
||||
"options": "Naming Series\nEmployee Number\nFull Name"
|
||||
},
|
||||
{
|
||||
"fieldname": "leave_approval_notification_template",
|
||||
"fieldtype": "Link",
|
||||
"label": "Leave Approval Notification Template",
|
||||
"options": "Email Template"
|
||||
},
|
||||
{
|
||||
"fieldname": "leave_status_notification_template",
|
||||
"fieldtype": "Link",
|
||||
"label": "Leave Status Notification Template",
|
||||
"options": "Email Template"
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_4",
|
||||
"fieldtype": "Column Break"
|
||||
@ -67,12 +58,6 @@
|
||||
"fieldtype": "Check",
|
||||
"label": "Stop Birthday Reminders"
|
||||
},
|
||||
{
|
||||
"default": "1",
|
||||
"fieldname": "leave_approver_mandatory_in_leave_application",
|
||||
"fieldtype": "Check",
|
||||
"label": "Leave Approver Mandatory In Leave Application"
|
||||
},
|
||||
{
|
||||
"default": "1",
|
||||
"fieldname": "expense_approver_mandatory_in_expense_claim",
|
||||
@ -91,6 +76,15 @@
|
||||
"fieldtype": "Check",
|
||||
"label": "Include holidays in Total no. of Working Days"
|
||||
},
|
||||
{
|
||||
"fieldname": "max_working_hours_against_timesheet",
|
||||
"fieldtype": "Float",
|
||||
"label": "Max working hours against Timesheet"
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_11",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"default": "1",
|
||||
"description": "Emails salary slip to employee based on preferred email selected in Employee",
|
||||
@ -115,15 +109,33 @@
|
||||
"label": "Password Policy"
|
||||
},
|
||||
{
|
||||
"fieldname": "max_working_hours_against_timesheet",
|
||||
"fieldtype": "Float",
|
||||
"label": "Max working hours against Timesheet"
|
||||
},
|
||||
{
|
||||
"collapsible": 1,
|
||||
"fieldname": "leave_settings",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Leave Settings"
|
||||
},
|
||||
{
|
||||
"fieldname": "leave_approval_notification_template",
|
||||
"fieldtype": "Link",
|
||||
"label": "Leave Approval Notification Template",
|
||||
"options": "Email Template"
|
||||
},
|
||||
{
|
||||
"fieldname": "leave_status_notification_template",
|
||||
"fieldtype": "Link",
|
||||
"label": "Leave Status Notification Template",
|
||||
"options": "Email Template"
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_18",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"default": "1",
|
||||
"fieldname": "leave_approver_mandatory_in_leave_application",
|
||||
"fieldtype": "Check",
|
||||
"label": "Leave Approver Mandatory In Leave Application"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "show_leaves_of_all_department_members_in_calendar",
|
||||
@ -131,18 +143,22 @@
|
||||
"label": "Show Leaves Of All Department Members In Calendar"
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_11",
|
||||
"fieldtype": "Column Break"
|
||||
"collapsible": 1,
|
||||
"fieldname": "hiring_settings",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Hiring Settings"
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_18",
|
||||
"fieldtype": "Column Break"
|
||||
"default": "0",
|
||||
"fieldname": "check_vacancies",
|
||||
"fieldtype": "Check",
|
||||
"label": "Check Vacancies On Job Offer Creation"
|
||||
}
|
||||
],
|
||||
"icon": "fa fa-cog",
|
||||
"idx": 1,
|
||||
"issingle": 1,
|
||||
"modified": "2019-05-31 16:18:50.245872",
|
||||
"modified": "2019-07-01 18:59:55.256878",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "HR Settings",
|
||||
@ -158,5 +174,6 @@
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "ASC"
|
||||
}
|
@ -39,7 +39,7 @@
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
@ -71,7 +71,7 @@
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
@ -96,7 +96,7 @@
|
||||
"label": "Status",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Open\nReplied\nRejected\nHold",
|
||||
"options": "Open\nReplied\nRejected\nHold\nAccepted",
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
@ -346,7 +346,7 @@
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2018-08-21 16:15:43.552049",
|
||||
"modified": "2019-06-21 16:15:43.552049",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Job Applicant",
|
||||
|
@ -10,3 +10,14 @@ import unittest
|
||||
|
||||
class TestJobApplicant(unittest.TestCase):
|
||||
pass
|
||||
|
||||
def create_job_applicant(**args):
|
||||
args = frappe._dict(args)
|
||||
job_applicant = frappe.get_doc({
|
||||
"doctype": "Job Applicant",
|
||||
"applicant_name": args.applicant_name or "_Test Applicant",
|
||||
"email_id": args.email_id or "test_applicant@example.com",
|
||||
"status": args.status or "Open"
|
||||
})
|
||||
job_applicant.save()
|
||||
return job_applicant
|
@ -5,12 +5,56 @@ from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe.model.document import Document
|
||||
from frappe.model.mapper import get_mapped_doc
|
||||
from frappe import _
|
||||
from frappe.utils.data import get_link_to_form
|
||||
|
||||
class JobOffer(Document):
|
||||
def onload(self):
|
||||
employee = frappe.db.get_value("Employee", {"job_applicant": self.job_applicant}, "name") or ""
|
||||
self.set_onload("employee", employee)
|
||||
|
||||
def validate(self):
|
||||
self.validate_vacancies()
|
||||
|
||||
def validate_vacancies(self):
|
||||
staffing_plan = get_staffing_plan_detail(self.designation, self.company, self.offer_date)
|
||||
check_vacancies = frappe.get_single("HR Settings").check_vacancies
|
||||
if staffing_plan and check_vacancies:
|
||||
vacancies = frappe.db.get_value("Staffing Plan Detail", filters={"name": staffing_plan.name}, fieldname=['vacancies'])
|
||||
job_offers = len(self.get_job_offer(staffing_plan.from_date, staffing_plan.to_date))
|
||||
if vacancies - job_offers <= 0:
|
||||
frappe.throw(_("There are no vacancies under staffing plan {0}").format(get_link_to_form("Staffing Plan", staffing_plan.parent)))
|
||||
|
||||
def on_change(self):
|
||||
update_job_applicant(self.status, self.job_applicant)
|
||||
|
||||
def get_job_offer(self, from_date, to_date):
|
||||
''' Returns job offer created during a time period '''
|
||||
return frappe.get_all("Job Offer", filters={
|
||||
"offer_date": ['between', (from_date, to_date)],
|
||||
"designation": self.designation,
|
||||
"company": self.company
|
||||
}, fields=['name'])
|
||||
|
||||
def update_job_applicant(status, job_applicant):
|
||||
if status in ("Accepted", "Rejected"):
|
||||
frappe.set_value("Job Applicant", job_applicant, "status", status)
|
||||
|
||||
def get_staffing_plan_detail(designation, company, offer_date):
|
||||
detail = frappe.db.sql("""
|
||||
SELECT spd.name as name,
|
||||
sp.from_date as from_date,
|
||||
sp.to_date as to_date,
|
||||
sp.name as parent
|
||||
FROM `tabStaffing Plan Detail` spd, `tabStaffing Plan` sp
|
||||
WHERE
|
||||
sp.docstatus=1
|
||||
AND spd.designation=%s
|
||||
AND sp.company=%s
|
||||
AND %s between sp.from_date and sp.to_date
|
||||
""", (designation, company, offer_date), as_dict=1)
|
||||
return detail[0] if detail else None
|
||||
|
||||
@frappe.whitelist()
|
||||
def make_employee(source_name, target_doc=None):
|
||||
def set_missing_values(source, target):
|
||||
@ -23,4 +67,3 @@ def make_employee(source_name, target_doc=None):
|
||||
}}
|
||||
}, target_doc, set_missing_values)
|
||||
return doc
|
||||
|
||||
|
@ -4,8 +4,78 @@ from __future__ import unicode_literals
|
||||
|
||||
import frappe
|
||||
import unittest
|
||||
from frappe.utils import nowdate, add_days
|
||||
from erpnext.hr.doctype.job_applicant.test_job_applicant import create_job_applicant
|
||||
from erpnext.hr.doctype.designation.test_designation import create_designation
|
||||
from erpnext.hr.doctype.staffing_plan.test_staffing_plan import make_company
|
||||
|
||||
# test_records = frappe.get_test_records('Job Offer')
|
||||
|
||||
class TestJobOffer(unittest.TestCase):
|
||||
pass
|
||||
def test_job_offer_creation_against_vacancies(self):
|
||||
create_staffing_plan(staffing_details=[{
|
||||
"designation": "Designer",
|
||||
"vacancies": 0,
|
||||
"estimated_cost_per_position": 5000
|
||||
}])
|
||||
frappe.db.set_value("HR Settings", None, "check_vacancies", 1)
|
||||
job_applicant = create_job_applicant(email_id="test_job_offer@example.com")
|
||||
job_offer = create_job_offer(job_applicant=job_applicant.name, designation="Researcher")
|
||||
self.assertRaises(frappe.ValidationError, job_offer.submit)
|
||||
|
||||
# test creation of job offer when vacancies are not present
|
||||
frappe.db.set_value("HR Settings", None, "check_vacancies", 0)
|
||||
job_offer.submit()
|
||||
self.assertTrue(frappe.db.exists("Job Offer", job_offer.name))
|
||||
|
||||
def test_job_applicant_update(self):
|
||||
create_staffing_plan()
|
||||
job_applicant = create_job_applicant(email_id="test_job_applicants@example.com")
|
||||
job_offer = create_job_offer(job_applicant=job_applicant.name)
|
||||
job_offer.submit()
|
||||
job_applicant.reload()
|
||||
self.assertEquals(job_applicant.status, "Accepted")
|
||||
|
||||
# status update after rejection
|
||||
job_offer.status = "Rejected"
|
||||
job_offer.submit()
|
||||
job_applicant.reload()
|
||||
self.assertEquals(job_applicant.status, "Rejected")
|
||||
|
||||
def create_job_offer(**args):
|
||||
args = frappe._dict(args)
|
||||
if not args.job_applicant:
|
||||
job_applicant = create_job_applicant()
|
||||
|
||||
if not frappe.db.exists("Designation", args.designation):
|
||||
designation = create_designation(designation_name=args.designation)
|
||||
|
||||
job_offer = frappe.get_doc({
|
||||
"doctype": "Job Offer",
|
||||
"job_applicant": args.job_applicant or job_applicant.name,
|
||||
"offer_date": args.offer_date or nowdate(),
|
||||
"designation": args.designation or "Researcher",
|
||||
"status": args.status or "Accepted"
|
||||
})
|
||||
return job_offer
|
||||
|
||||
def create_staffing_plan(**args):
|
||||
args = frappe._dict(args)
|
||||
make_company()
|
||||
frappe.db.set_value("Company", "_Test Company", "is_group", 1)
|
||||
if frappe.db.exists("Staffing Plan", args.name or "Test"):
|
||||
return
|
||||
staffing_plan = frappe.get_doc({
|
||||
"doctype": "Staffing Plan",
|
||||
"name": args.name or "Test",
|
||||
"from_date": args.from_date or nowdate(),
|
||||
"to_date": args.to_date or add_days(nowdate(), 10),
|
||||
"staffing_details": args.staffing_details or [{
|
||||
"designation": "Researcher",
|
||||
"vacancies": 1,
|
||||
"estimated_cost_per_position": 50000
|
||||
}]
|
||||
})
|
||||
staffing_plan.insert()
|
||||
staffing_plan.submit()
|
||||
return staffing_plan
|
@ -30,11 +30,11 @@ class LoanApplication(Document):
|
||||
monthly_interest_rate = flt(self.rate_of_interest) / (12 *100)
|
||||
if monthly_interest_rate:
|
||||
min_repayment_amount = self.loan_amount*monthly_interest_rate
|
||||
if self.repayment_amount - min_repayment_amount < 0:
|
||||
if self.repayment_amount - min_repayment_amount <= 0:
|
||||
frappe.throw(_("Repayment Amount must be greater than " \
|
||||
+ str(flt(min_repayment_amount, 2))))
|
||||
self.repayment_periods = math.ceil(math.log(self.repayment_amount) -
|
||||
math.log(self.repayment_amount - min_repayment_amount) /(math.log(1 + monthly_interest_rate)))
|
||||
self.repayment_periods = math.ceil((math.log(self.repayment_amount) -
|
||||
math.log(self.repayment_amount - min_repayment_amount)) /(math.log(1 + monthly_interest_rate)))
|
||||
else:
|
||||
self.repayment_periods = self.loan_amount / self.repayment_amount
|
||||
|
||||
|
@ -119,6 +119,8 @@ class PayrollEntry(Document):
|
||||
frappe.enqueue(create_salary_slips_for_employees, timeout=600, employees=emp_list, args=args)
|
||||
else:
|
||||
create_salary_slips_for_employees(emp_list, args, publish_progress=False)
|
||||
# since this method is called via frm.call this doc needs to be updated manually
|
||||
self.reload()
|
||||
|
||||
def get_sal_slip_list(self, ss_status, as_dict=False):
|
||||
"""
|
||||
|
@ -5,7 +5,7 @@ frappe.ui.form.on('Staffing Plan', {
|
||||
setup: function(frm) {
|
||||
frm.set_query("designation", "staffing_details", function() {
|
||||
let designations = [];
|
||||
$.each(frm.doc.staffing_details, function(index, staff_detail) {
|
||||
(frm.doc.staffing_details || []).forEach(function(staff_detail) {
|
||||
if(staff_detail.designation){
|
||||
designations.push(staff_detail.designation)
|
||||
}
|
||||
@ -25,13 +25,37 @@ frappe.ui.form.on('Staffing Plan', {
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
frappe.ui.form.on('Staffing Plan Detail', {
|
||||
designation: function(frm, cdt, cdn) {
|
||||
let child = locals[cdt][cdn]
|
||||
if(frm.doc.company && child.designation){
|
||||
let child = locals[cdt][cdn];
|
||||
if(frm.doc.company && child.designation) {
|
||||
set_number_of_positions(frm, cdt, cdn);
|
||||
}
|
||||
},
|
||||
|
||||
vacancies: function(frm, cdt, cdn) {
|
||||
let child = locals[cdt][cdn];
|
||||
if(child.vacancies < child.current_openings) {
|
||||
frappe.throw(__("Vacancies cannot be lower than the current openings"));
|
||||
}
|
||||
set_number_of_positions(frm, cdt, cdn);
|
||||
},
|
||||
|
||||
current_count: function(frm, cdt, cdn) {
|
||||
set_number_of_positions(frm, cdt, cdn);
|
||||
},
|
||||
|
||||
estimated_cost_per_position: function(frm, cdt, cdn) {
|
||||
set_total_estimated_cost(frm, cdt, cdn);
|
||||
}
|
||||
});
|
||||
|
||||
var set_number_of_positions = function(frm, cdt, cdn) {
|
||||
let child = locals[cdt][cdn];
|
||||
if (!child.designation) frappe.throw(__("Please enter the designation"));
|
||||
frappe.call({
|
||||
"method": "erpnext.hr.doctype.staffing_plan.staffing_plan.get_designation_counts",
|
||||
args: {
|
||||
@ -42,8 +66,9 @@ frappe.ui.form.on('Staffing Plan Detail', {
|
||||
if(data.message){
|
||||
frappe.model.set_value(cdt, cdn, 'current_count', data.message.employee_count);
|
||||
frappe.model.set_value(cdt, cdn, 'current_openings', data.message.job_openings);
|
||||
if (child.number_of_positions < (data.message.employee_count + data.message.job_openings)){
|
||||
frappe.model.set_value(cdt, cdn, 'number_of_positions', data.message.employee_count + data.message.job_openings);
|
||||
let total_positions = cint(data.message.employee_count) + cint(child.vacancies);
|
||||
if (cint(child.number_of_positions) < total_positions){
|
||||
frappe.model.set_value(cdt, cdn, 'number_of_positions', total_positions);
|
||||
}
|
||||
}
|
||||
else{ // No employees for this designation
|
||||
@ -52,42 +77,11 @@ frappe.ui.form.on('Staffing Plan Detail', {
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
number_of_positions: function(frm, cdt, cdn) {
|
||||
set_vacancies(frm, cdt, cdn);
|
||||
},
|
||||
|
||||
current_count: function(frm, cdt, cdn) {
|
||||
set_vacancies(frm, cdt, cdn);
|
||||
},
|
||||
|
||||
estimated_cost_per_position: function(frm, cdt, cdn) {
|
||||
let child = locals[cdt][cdn];
|
||||
set_total_estimated_cost(frm, cdt, cdn);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
var set_vacancies = function(frm, cdt, cdn) {
|
||||
let child = locals[cdt][cdn]
|
||||
if (child.number_of_positions < (child.current_count + child.current_openings)){
|
||||
frappe.throw(__("Number of positions cannot be less then current count of employees"))
|
||||
}
|
||||
|
||||
if(child.number_of_positions > 0) {
|
||||
frappe.model.set_value(cdt, cdn, 'vacancies', child.number_of_positions - (child.current_count + child.current_openings));
|
||||
}
|
||||
else{
|
||||
frappe.model.set_value(cdt, cdn, 'vacancies', 0);
|
||||
}
|
||||
|
||||
refresh_field("staffing_details");
|
||||
set_total_estimated_cost(frm, cdt, cdn);
|
||||
}
|
||||
|
||||
// Note: Estimated Cost is calculated on number of Vacancies
|
||||
// Validate for > 0 ?
|
||||
var set_total_estimated_cost = function(frm, cdt, cdn) {
|
||||
let child = locals[cdt][cdn]
|
||||
if(child.vacancies > 0 && child.estimated_cost_per_position) {
|
||||
@ -102,7 +96,7 @@ var set_total_estimated_cost = function(frm, cdt, cdn) {
|
||||
var set_total_estimated_budget = function(frm) {
|
||||
let estimated_budget = 0.0
|
||||
if(frm.doc.staffing_details) {
|
||||
$.each(frm.doc.staffing_details, function(index, staff_detail) {
|
||||
(frm.doc.staffing_details || []).forEach(function(staff_detail) {
|
||||
if(staff_detail.total_estimated_cost){
|
||||
estimated_budget += staff_detail.total_estimated_cost
|
||||
}
|
||||
|
@ -13,41 +13,39 @@ class ParentCompanyError(frappe.ValidationError): pass
|
||||
|
||||
class StaffingPlan(Document):
|
||||
def validate(self):
|
||||
self.validate_period()
|
||||
self.validate_details()
|
||||
self.set_total_estimated_budget()
|
||||
|
||||
def validate_period(self):
|
||||
# Validate Dates
|
||||
if self.from_date and self.to_date and self.from_date > self.to_date:
|
||||
frappe.throw(_("From Date cannot be greater than To Date"))
|
||||
|
||||
self.total_estimated_budget = 0
|
||||
|
||||
def validate_details(self):
|
||||
for detail in self.get("staffing_details"):
|
||||
self.set_vacancies(detail)
|
||||
self.validate_overlap(detail)
|
||||
self.validate_with_subsidiary_plans(detail)
|
||||
self.validate_with_parent_plan(detail)
|
||||
|
||||
def set_total_estimated_budget(self):
|
||||
self.total_estimated_budget = 0
|
||||
|
||||
for detail in self.get("staffing_details"):
|
||||
#Set readonly fields
|
||||
self.set_number_of_positions(detail)
|
||||
designation_counts = get_designation_counts(detail.designation, self.company)
|
||||
detail.current_count = designation_counts['employee_count']
|
||||
detail.current_openings = designation_counts['job_openings']
|
||||
|
||||
if detail.number_of_positions < (detail.current_count + detail.current_openings):
|
||||
frappe.throw(_("Number of positions cannot be less then current count of employees"))
|
||||
elif detail.number_of_positions > 0:
|
||||
detail.vacancies = detail.number_of_positions - (detail.current_count + detail.current_openings)
|
||||
if detail.number_of_positions > 0:
|
||||
if detail.vacancies > 0 and detail.estimated_cost_per_position:
|
||||
detail.total_estimated_cost = detail.vacancies * detail.estimated_cost_per_position
|
||||
else: detail.total_estimated_cost = 0
|
||||
else: detail.vacancies = detail.number_of_positions = detail.total_estimated_cost = 0
|
||||
detail.total_estimated_cost = cint(detail.vacancies) * flt(detail.estimated_cost_per_position)
|
||||
|
||||
self.total_estimated_budget += detail.total_estimated_cost
|
||||
|
||||
def set_vacancies(self, row):
|
||||
if not row.vacancies:
|
||||
current_openings = 0
|
||||
for field in ['current_count', 'current_openings']:
|
||||
if row.get(field):
|
||||
current_openings += row.get(field)
|
||||
|
||||
row.vacancies = row.number_of_positions - current_openings
|
||||
def set_number_of_positions(self, detail):
|
||||
detail.number_of_positions = cint(detail.vacancies) + cint(detail.current_count)
|
||||
|
||||
def validate_overlap(self, staffing_plan_detail):
|
||||
# Validate if any submitted Staffing Plan exist for any Designations in this plan
|
||||
@ -132,19 +130,24 @@ def get_designation_counts(designation, company):
|
||||
if not designation:
|
||||
return False
|
||||
|
||||
employee_counts_dict = {}
|
||||
lft, rgt = frappe.get_cached_value('Company', company, ["lft", "rgt"])
|
||||
employee_counts_dict["employee_count"] = frappe.db.sql("""select count(*) from `tabEmployee`
|
||||
where designation = %s and status='Active'
|
||||
and company in (select name from tabCompany where lft>=%s and rgt<=%s)
|
||||
""", (designation, lft, rgt))[0][0]
|
||||
employee_counts = {}
|
||||
company_set = get_company_set(company)
|
||||
|
||||
employee_counts_dict['job_openings'] = frappe.db.sql("""select count(*) from `tabJob Opening` \
|
||||
where designation=%s and status='Open'
|
||||
and company in (select name from tabCompany where lft>=%s and rgt<=%s)
|
||||
""", (designation, lft, rgt))[0][0]
|
||||
employee_counts["employee_count"] = frappe.db.get_value("Employee",
|
||||
filters={
|
||||
'designation': designation,
|
||||
'status': 'Active',
|
||||
'company': ('in', company_set)
|
||||
}, fieldname=['count(name)'])
|
||||
|
||||
return employee_counts_dict
|
||||
employee_counts['job_openings'] = frappe.db.get_value("Job Opening",
|
||||
filters={
|
||||
'designation': designation,
|
||||
'status': 'Open',
|
||||
'company': ('in', company_set)
|
||||
}, fieldname=['count(name)'])
|
||||
|
||||
return employee_counts
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_active_staffing_plan_details(company, designation, from_date=getdate(nowdate()), to_date=getdate(nowdate())):
|
||||
@ -165,3 +168,13 @@ def get_active_staffing_plan_details(company, designation, from_date=getdate(now
|
||||
|
||||
# Only a single staffing plan can be active for a designation on given date
|
||||
return staffing_plan if staffing_plan else None
|
||||
|
||||
def get_company_set(company):
|
||||
return frappe.db.sql_list("""
|
||||
SELECT
|
||||
name
|
||||
FROM `tabCompany`
|
||||
WHERE
|
||||
parent_company=%(company)s
|
||||
OR name=%(company)s
|
||||
""", (dict(company=company)))
|
@ -24,7 +24,7 @@ class TestStaffingPlan(unittest.TestCase):
|
||||
staffing_plan.to_date = add_days(nowdate(), 10)
|
||||
staffing_plan.append("staffing_details", {
|
||||
"designation": "Designer",
|
||||
"number_of_positions": 6,
|
||||
"vacancies": 6,
|
||||
"estimated_cost_per_position": 50000
|
||||
})
|
||||
staffing_plan.insert()
|
||||
@ -42,7 +42,7 @@ class TestStaffingPlan(unittest.TestCase):
|
||||
staffing_plan.to_date = add_days(nowdate(), 10)
|
||||
staffing_plan.append("staffing_details", {
|
||||
"designation": "Designer",
|
||||
"number_of_positions": 3,
|
||||
"vacancies": 3,
|
||||
"estimated_cost_per_position": 45000
|
||||
})
|
||||
self.assertRaises(SubsidiaryCompanyError, staffing_plan.insert)
|
||||
@ -58,7 +58,7 @@ class TestStaffingPlan(unittest.TestCase):
|
||||
staffing_plan.to_date = add_days(nowdate(), 10)
|
||||
staffing_plan.append("staffing_details", {
|
||||
"designation": "Designer",
|
||||
"number_of_positions": 7,
|
||||
"vacancies": 7,
|
||||
"estimated_cost_per_position": 50000
|
||||
})
|
||||
staffing_plan.insert()
|
||||
@ -73,7 +73,7 @@ class TestStaffingPlan(unittest.TestCase):
|
||||
staffing_plan.to_date = add_days(nowdate(), 10)
|
||||
staffing_plan.append("staffing_details", {
|
||||
"designation": "Designer",
|
||||
"number_of_positions": 7,
|
||||
"vacancies": 7,
|
||||
"estimated_cost_per_position": 60000
|
||||
})
|
||||
staffing_plan.insert()
|
||||
|
@ -1,297 +1,79 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"beta": 0,
|
||||
"creation": "2018-04-13 18:04:20.978931",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"designation",
|
||||
"vacancies",
|
||||
"estimated_cost_per_position",
|
||||
"total_estimated_cost",
|
||||
"column_break_5",
|
||||
"current_count",
|
||||
"current_openings",
|
||||
"number_of_positions"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "designation",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Designation",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Designation",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "number_of_positions",
|
||||
"fieldtype": "Int",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Number Of Positions",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "estimated_cost_per_position",
|
||||
"fieldtype": "Currency",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Estimated Cost Per Position",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"label": "Estimated Cost Per Position"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "column_break_5",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "current_count",
|
||||
"fieldtype": "Int",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Current Count",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "current_openings",
|
||||
"fieldtype": "Int",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Current Openings",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "vacancies",
|
||||
"fieldtype": "Int",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Vacancies",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"label": "Vacancies"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "total_estimated_cost",
|
||||
"fieldtype": "Currency",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Total Estimated Cost",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"read_only": 1
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 0,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 1,
|
||||
"max_attachments": 0,
|
||||
"modified": "2018-06-01 17:03:38.020993",
|
||||
"modified": "2019-06-24 18:40:37.140178",
|
||||
"modified_by": "Administrator",
|
||||
"module": "HR",
|
||||
"name": "Staffing Plan Detail",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"quick_entry": 1,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1,
|
||||
"track_seen": 0
|
||||
"track_changes": 1
|
||||
}
|
@ -73,7 +73,7 @@ def create_columns():
|
||||
def get_record():
|
||||
data = []
|
||||
loans = frappe.get_all("Loan",
|
||||
filters=[("status", "=", "Fully Disbursed")],
|
||||
filters=[("status", "=", "Disbursed")],
|
||||
fields=["applicant", "applicant_name", "name", "loan_amount", "rate_of_interest",
|
||||
"total_payment", "monthly_repayment_amount", "total_amount_paid"]
|
||||
)
|
||||
|
@ -578,6 +578,8 @@ class BOM(WebsiteGenerator):
|
||||
for d in self.operations:
|
||||
if not d.description:
|
||||
d.description = frappe.db.get_value('Operation', d.operation, 'description')
|
||||
if not d.batch_size > 0:
|
||||
d.batch_size = 1
|
||||
|
||||
def get_list_context(context):
|
||||
context.title = _("Bill of Materials")
|
||||
|
@ -1,361 +1,119 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"beta": 0,
|
||||
"creation": "2013-02-22 01:27:49",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "Setup",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"operation",
|
||||
"workstation",
|
||||
"description",
|
||||
"col_break1",
|
||||
"hour_rate",
|
||||
"time_in_mins",
|
||||
"batch_size",
|
||||
"operating_cost",
|
||||
"base_hour_rate",
|
||||
"base_operating_cost",
|
||||
"image"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "operation",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Operation",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"oldfieldname": "operation_no",
|
||||
"oldfieldtype": "Data",
|
||||
"options": "Operation",
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "workstation",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Workstation",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"oldfieldname": "workstation",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Workstation",
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"options": "Workstation"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "description",
|
||||
"fieldtype": "Text Editor",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Description",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"oldfieldname": "opn_description",
|
||||
"oldfieldtype": "Text",
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"oldfieldtype": "Text"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "col_break1",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "hour_rate",
|
||||
"fieldtype": "Currency",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Hour Rate",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"oldfieldname": "hour_rate",
|
||||
"oldfieldtype": "Currency",
|
||||
"options": "currency",
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"options": "currency"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"description": "In minutes",
|
||||
"fieldname": "time_in_mins",
|
||||
"fieldtype": "Float",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Operation Time ",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"oldfieldname": "time_in_mins",
|
||||
"oldfieldtype": "Currency",
|
||||
"options": "",
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "operating_cost",
|
||||
"fieldtype": "Currency",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Operating Cost",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"oldfieldname": "operating_cost",
|
||||
"oldfieldtype": "Currency",
|
||||
"options": "currency",
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "base_hour_rate",
|
||||
"fieldtype": "Currency",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Base Hour Rate(Company Currency)",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Company:company:default_currency",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 1,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "5",
|
||||
"fieldname": "base_operating_cost",
|
||||
"fieldtype": "Currency",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Operating Cost(Company Currency)",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Company:company:default_currency",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 1,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "image",
|
||||
"fieldtype": "Attach",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Image",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"label": "Image"
|
||||
},
|
||||
{
|
||||
"default": "1",
|
||||
"fieldname": "batch_size",
|
||||
"fieldtype": "Int",
|
||||
"label": "Batch Size"
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 1,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 1,
|
||||
"max_attachments": 0,
|
||||
"modified": "2018-03-26 09:55:28.107451",
|
||||
"modified_by": "Administrator",
|
||||
"modified": "2019-07-16 22:35:55.374037",
|
||||
"modified_by": "govindsmenokee@gmail.com",
|
||||
"module": "Manufacturing",
|
||||
"name": "BOM Operation",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"quick_entry": 0,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"track_changes": 0,
|
||||
"track_seen": 0
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC"
|
||||
}
|
@ -505,7 +505,7 @@ def get_material_request_items(row, sales_order,
|
||||
total_qty = row['qty']
|
||||
|
||||
required_qty = 0
|
||||
if ignore_existing_ordered_qty or bin_dict.get("projected_qty") < 0:
|
||||
if ignore_existing_ordered_qty or bin_dict.get("projected_qty", 0) < 0:
|
||||
required_qty = total_qty
|
||||
elif total_qty > bin_dict.get("projected_qty"):
|
||||
required_qty = total_qty - bin_dict.get("projected_qty")
|
||||
|
@ -4,6 +4,7 @@
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
import json
|
||||
import math
|
||||
from frappe import _
|
||||
from frappe.utils import flt, get_datetime, getdate, date_diff, cint, nowdate
|
||||
from frappe.model.document import Document
|
||||
@ -323,7 +324,7 @@ class WorkOrder(Document):
|
||||
select
|
||||
operation, description, workstation, idx,
|
||||
base_hour_rate as hour_rate, time_in_mins,
|
||||
"Pending" as status, parent as bom
|
||||
"Pending" as status, parent as bom, batch_size
|
||||
from
|
||||
`tabBOM Operation`
|
||||
where
|
||||
@ -348,7 +349,7 @@ class WorkOrder(Document):
|
||||
bom_qty = frappe.db.get_value("BOM", self.bom_no, "quantity")
|
||||
|
||||
for d in self.get("operations"):
|
||||
d.time_in_mins = flt(d.time_in_mins) / flt(bom_qty) * flt(self.qty)
|
||||
d.time_in_mins = flt(d.time_in_mins) / flt(bom_qty) * math.ceil(flt(self.qty) / flt(d.batch_size))
|
||||
|
||||
self.calculate_operating_cost()
|
||||
|
||||
|
@ -1,690 +1,200 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"beta": 0,
|
||||
"creation": "2014-10-16 14:35:41.950175",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"details",
|
||||
"operation",
|
||||
"bom",
|
||||
"description",
|
||||
"col_break1",
|
||||
"completed_qty",
|
||||
"status",
|
||||
"workstation",
|
||||
"estimated_time_and_cost",
|
||||
"planned_start_time",
|
||||
"planned_end_time",
|
||||
"column_break_10",
|
||||
"time_in_mins",
|
||||
"hour_rate",
|
||||
"batch_size",
|
||||
"planned_operating_cost",
|
||||
"section_break_9",
|
||||
"actual_start_time",
|
||||
"actual_end_time",
|
||||
"column_break_11",
|
||||
"actual_operation_time",
|
||||
"actual_operating_cost"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "details",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
"fieldtype": "Section Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "operation",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Operation",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"oldfieldname": "operation_no",
|
||||
"oldfieldtype": "Data",
|
||||
"options": "Operation",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "bom",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "BOM",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"options": "BOM",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 1,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "description",
|
||||
"fieldtype": "Text Editor",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Operation Description",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"oldfieldname": "opn_description",
|
||||
"oldfieldtype": "Text",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "col_break1",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"description": "Operation completed for how many finished goods?",
|
||||
"fieldname": "completed_qty",
|
||||
"fieldtype": "Float",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Completed Qty",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "Pending",
|
||||
"fieldname": "status",
|
||||
"fieldtype": "Select",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Status",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"options": "Pending\nWork in Progress\nCompleted",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "workstation",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Workstation",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"oldfieldname": "workstation",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Workstation",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
"options": "Workstation"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "estimated_time_and_cost",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Estimated Time and Cost",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
"label": "Estimated Time and Cost"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "planned_start_time",
|
||||
"fieldtype": "Datetime",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Planned Start Time",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "planned_end_time",
|
||||
"fieldtype": "Datetime",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Planned End Time",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "column_break_10",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"description": "in Minutes",
|
||||
"fieldname": "time_in_mins",
|
||||
"fieldtype": "Float",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Operation Time",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"oldfieldname": "time_in_mins",
|
||||
"oldfieldtype": "Currency",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "hour_rate",
|
||||
"fieldtype": "Float",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Hour Rate",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"oldfieldname": "hour_rate",
|
||||
"oldfieldtype": "Currency",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "planned_operating_cost",
|
||||
"fieldtype": "Currency",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Planned Operating Cost",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Company:company:default_currency",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "section_break_9",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Actual Time and Cost",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
"label": "Actual Time and Cost"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "actual_start_time",
|
||||
"fieldtype": "Datetime",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Actual Start Time",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"description": "Updated via 'Time Log'",
|
||||
"fieldname": "actual_end_time",
|
||||
"fieldtype": "Datetime",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Actual End Time",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "column_break_11",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"description": "in Minutes\nUpdated via 'Time Log'",
|
||||
"fieldname": "actual_operation_time",
|
||||
"fieldtype": "Float",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Actual Operation Time",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"description": "(Hour Rate / 60) * Actual Operation Time",
|
||||
"fieldname": "actual_operating_cost",
|
||||
"fieldtype": "Currency",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Actual Operating Cost",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"options": "Company:company:default_currency",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "batch_size",
|
||||
"fieldtype": "Int",
|
||||
"label": "Batch Size",
|
||||
"read_only": 1
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 0,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 1,
|
||||
"max_attachments": 0,
|
||||
"modified": "2018-02-13 02:58:11.328693",
|
||||
"modified_by": "Administrator",
|
||||
"modified": "2019-07-16 23:01:07.720337",
|
||||
"modified_by": "govindsmenokee@gmail.com",
|
||||
"module": "Manufacturing",
|
||||
"name": "Work Order Operation",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"quick_entry": 0,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1,
|
||||
"track_seen": 0
|
||||
"track_changes": 1
|
||||
}
|
@ -618,8 +618,10 @@ erpnext.patches.v11_1.set_missing_opportunity_from
|
||||
erpnext.patches.v12_0.set_quotation_status
|
||||
erpnext.patches.v12_0.set_priority_for_support
|
||||
erpnext.patches.v12_0.delete_priority_property_setter
|
||||
erpnext.patches.v12_0.set_default_batch_size
|
||||
execute:frappe.delete_doc("DocType", "Project Task")
|
||||
erpnext.patches.v11_1.update_default_supplier_in_item_defaults
|
||||
erpnext.patches.v12_0.update_due_date_in_gle
|
||||
erpnext.patches.v12_0.add_default_buying_selling_terms_in_company
|
||||
erpnext.patches.v12_0.update_ewaybill_field_position
|
||||
erpnext.patches.v11_1.set_status_for_material_request_type_manufacture
|
||||
|
@ -0,0 +1,9 @@
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
|
||||
def execute():
|
||||
frappe.db.sql("""
|
||||
update `tabMaterial Request`
|
||||
set status='Manufactured'
|
||||
where docstatus=1 and material_request_type='Manufacture' and per_ordered=100 and status != 'Stopped'
|
||||
""")
|
19
erpnext/patches/v12_0/set_default_batch_size.py
Normal file
19
erpnext/patches/v12_0/set_default_batch_size.py
Normal file
@ -0,0 +1,19 @@
|
||||
import frappe
|
||||
|
||||
|
||||
def execute():
|
||||
frappe.reload_doc("manufacturing", "doctype", "bom_operation")
|
||||
frappe.reload_doc("manufacturing", "doctype", "work_order_operation")
|
||||
|
||||
frappe.db.sql("""
|
||||
UPDATE
|
||||
`tabBOM Operation` bo
|
||||
SET
|
||||
bo.batch_size = 1
|
||||
""")
|
||||
frappe.db.sql("""
|
||||
UPDATE
|
||||
`tabWork Order Operation` wop
|
||||
SET
|
||||
wop.batch_size = 1
|
||||
""")
|
@ -1,6 +1,23 @@
|
||||
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
// License: GNU General Public License v3. See license.txt
|
||||
frappe.ui.form.on("Project", {
|
||||
setup(frm) {
|
||||
frm.make_methods = {
|
||||
'Timesheet': () => {
|
||||
let doctype = 'Timesheet';
|
||||
frappe.model.with_doctype(doctype, () => {
|
||||
let new_doc = frappe.model.get_new_doc(doctype);
|
||||
|
||||
// add a new row and set the project
|
||||
let time_log = frappe.model.get_new_doc('Timesheet Detail');
|
||||
time_log.project = frm.doc.name;
|
||||
new_doc.time_logs = [time_log];
|
||||
|
||||
frappe.ui.form.make_quick_entry(doctype, null, null, new_doc);
|
||||
});
|
||||
},
|
||||
}
|
||||
},
|
||||
onload: function (frm) {
|
||||
var so = frappe.meta.get_docfield("Project", "sales_order");
|
||||
so.get_route_options_for_new_doc = function (field) {
|
||||
|
@ -6,18 +6,13 @@
|
||||
"description": "Keep Track of Sales Campaigns. Keep track of Leads, Quotations, Sales Order etc from Campaigns to gauge Return on Investment. ",
|
||||
"doctype": "DocType",
|
||||
"document_type": "Setup",
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"campaign",
|
||||
"campaign_name",
|
||||
"naming_series",
|
||||
"from_date",
|
||||
"column_break1",
|
||||
"status",
|
||||
"to_date",
|
||||
"budget_section",
|
||||
"currency",
|
||||
"column_break2",
|
||||
"budget",
|
||||
"campaign_schedules_section",
|
||||
"campaign_schedules",
|
||||
"description_section",
|
||||
"description"
|
||||
],
|
||||
@ -52,57 +47,25 @@
|
||||
"oldfieldtype": "Text",
|
||||
"width": "300px"
|
||||
},
|
||||
{
|
||||
"fieldname": "status",
|
||||
"fieldtype": "Select",
|
||||
"in_list_view": 1,
|
||||
"label": "Status",
|
||||
"options": "\nPlanned\nIn Progress\nCompleted\nCancelled",
|
||||
"reqd": 1,
|
||||
"default": "Planned"
|
||||
},
|
||||
{
|
||||
"fieldname": "from_date",
|
||||
"fieldtype": "Date",
|
||||
"label": "From Date"
|
||||
},
|
||||
{
|
||||
"fieldname": "to_date",
|
||||
"fieldtype": "Date",
|
||||
"label": "To Date"
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break1",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "budget",
|
||||
"fieldtype": "Currency",
|
||||
"label": "Budget"
|
||||
},
|
||||
{
|
||||
"fieldname": "description_section",
|
||||
"fieldtype": "Section Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "currency",
|
||||
"fieldtype": "Link",
|
||||
"label": "Currency",
|
||||
"options": "Currency"
|
||||
"fieldname": "campaign_schedules",
|
||||
"fieldtype": "Table",
|
||||
"label": "Campaign Schedules",
|
||||
"options": "Campaign Email Schedule"
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break2",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "budget_section",
|
||||
"fieldname": "campaign_schedules_section",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "BUDGET"
|
||||
"label": "Campaign Schedules"
|
||||
}
|
||||
],
|
||||
"icon": "fa fa-bullhorn",
|
||||
"idx": 1,
|
||||
"modified": "2019-04-29 22:09:39.251884",
|
||||
"modified": "2019-07-22 12:03:39.832342",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Selling",
|
||||
"name": "Campaign",
|
||||
@ -140,5 +103,7 @@
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 1
|
||||
"quick_entry": 1,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC"
|
||||
}
|
13
erpnext/selling/doctype/campaign/campaign_dashboard.py
Normal file
13
erpnext/selling/doctype/campaign/campaign_dashboard.py
Normal file
@ -0,0 +1,13 @@
|
||||
from __future__ import unicode_literals
|
||||
from frappe import _
|
||||
|
||||
def get_data():
|
||||
return {
|
||||
'fieldname': 'campaign_name',
|
||||
'transactions': [
|
||||
{
|
||||
'label': _('Email Campaigns'),
|
||||
'items': ['Email Campaign']
|
||||
}
|
||||
],
|
||||
}
|
@ -509,10 +509,12 @@ def make_material_request(source_name, target_doc=None):
|
||||
doc.material_request_type = "Purchase"
|
||||
|
||||
def update_item(source, target, source_parent):
|
||||
# qty is for packed items, because packed items don't have stock_qty field
|
||||
qty = source.get("stock_qty") or source.get("qty")
|
||||
target.project = source_parent.project
|
||||
target.qty = source.stock_qty - requested_item_qty.get(source.name, 0)
|
||||
target.qty = qty - requested_item_qty.get(source.name, 0)
|
||||
target.conversion_factor = 1
|
||||
target.stock_qty = source.stock_qty - requested_item_qty.get(source.name, 0)
|
||||
target.stock_qty = qty - requested_item_qty.get(source.name, 0)
|
||||
|
||||
doc = get_mapped_doc("Sales Order", source_name, {
|
||||
"Sales Order": {
|
||||
|
@ -69,8 +69,7 @@ class ItemGroup(NestedSet, WebsiteGenerator):
|
||||
"items": get_product_list_for_group(product_group = self.name, start=start,
|
||||
limit=context.page_length + 1, search=frappe.form_dict.get("search")),
|
||||
"parents": get_parent_item_groups(self.parent_item_group),
|
||||
"title": self.name,
|
||||
"products_as_list": cint(frappe.db.get_single_value('Products Settings', 'products_as_list'))
|
||||
"title": self.name
|
||||
})
|
||||
|
||||
if self.slideshow:
|
||||
|
@ -16,18 +16,47 @@ erpnext.stock.ItemDashboard = Class.extend({
|
||||
this.content = $(frappe.render_template('item_dashboard')).appendTo(this.parent);
|
||||
this.result = this.content.find('.result');
|
||||
|
||||
// move
|
||||
this.content.on('click', '.btn-move', function() {
|
||||
erpnext.stock.move_item(unescape($(this).attr('data-item')), $(this).attr('data-warehouse'),
|
||||
null, $(this).attr('data-actual_qty'), null, function() { me.refresh(); });
|
||||
handle_move_add($(this), "Move")
|
||||
});
|
||||
|
||||
this.content.on('click', '.btn-add', function() {
|
||||
erpnext.stock.move_item(unescape($(this).attr('data-item')), null, $(this).attr('data-warehouse'),
|
||||
$(this).attr('data-actual_qty'), $(this).attr('data-rate'),
|
||||
function() { me.refresh(); });
|
||||
handle_move_add($(this), "Add")
|
||||
});
|
||||
|
||||
function handle_move_add(element, action) {
|
||||
let item = unescape(element.attr('data-item'));
|
||||
let warehouse = unescape(element.attr('data-warehouse'));
|
||||
let actual_qty = unescape(element.attr('data-actual_qty'));
|
||||
let disable_quick_entry = Number(unescape(element.attr('data-disable_quick_entry')));
|
||||
let entry_type = action === "Move" ? "Material Transfer": null;
|
||||
|
||||
if (disable_quick_entry) {
|
||||
open_stock_entry(item, warehouse, entry_type);
|
||||
} else {
|
||||
if (action === "Add") {
|
||||
let rate = unescape($(this).attr('data-rate'));
|
||||
erpnext.stock.move_item(item, null, warehouse, actual_qty, rate, function() { me.refresh(); });
|
||||
}
|
||||
else {
|
||||
erpnext.stock.move_item(item, warehouse, null, actual_qty, null, function() { me.refresh(); });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function open_stock_entry(item, warehouse, entry_type) {
|
||||
frappe.model.with_doctype('Stock Entry', function() {
|
||||
var doc = frappe.model.get_new_doc('Stock Entry');
|
||||
if (entry_type) doc.stock_entry_type = entry_type;
|
||||
|
||||
var row = frappe.model.add_child(doc, 'items');
|
||||
row.item_code = item;
|
||||
row.s_warehouse = warehouse;
|
||||
|
||||
frappe.set_route('Form', doc.doctype, doc.name);
|
||||
})
|
||||
}
|
||||
|
||||
// more
|
||||
this.content.find('.btn-more').on('click', function() {
|
||||
me.start += 20;
|
||||
|
@ -44,7 +44,9 @@ def get_data(item_code=None, warehouse=None, item_group=None,
|
||||
|
||||
for item in items:
|
||||
item.update({
|
||||
'item_name': frappe.get_cached_value("Item", item.item_code, 'item_name')
|
||||
'item_name': frappe.get_cached_value("Item", item.item_code, 'item_name'),
|
||||
'disable_quick_entry': frappe.get_cached_value("Item", item.item_code, 'has_batch_no')
|
||||
or frappe.get_cached_value("Item", item.item_code, 'has_serial_no'),
|
||||
})
|
||||
|
||||
return items
|
||||
|
@ -43,11 +43,13 @@
|
||||
<div class="col-sm-2 text-right" style="margin-top: 8px;">
|
||||
{% if d.actual_qty %}
|
||||
<button class="btn btn-default btn-xs btn-move"
|
||||
data-disable_quick_entry="{{ d.disable_quick_entry }}"
|
||||
data-warehouse="{{ d.warehouse }}"
|
||||
data-actual_qty="{{ d.actual_qty }}"
|
||||
data-item="{{ escape(d.item_code) }}">{{ __("Move") }}</a>
|
||||
{% endif %}
|
||||
<button style="margin-left: 7px;" class="btn btn-default btn-xs btn-add"
|
||||
data-disable_quick_entry="{{ d.disable_quick_entry }}"
|
||||
data-warehouse="{{ d.warehouse }}"
|
||||
data-actual_qty="{{ d.actual_qty }}"
|
||||
data-item="{{ escape(d.item_code) }}"
|
||||
|
@ -122,8 +122,8 @@ class Batch(Document):
|
||||
self.expiry_date = add_days(self.manufacturing_date, shelf_life_in_days)
|
||||
|
||||
if has_expiry_date and not self.expiry_date:
|
||||
frappe.throw(_('Expiry date is mandatory for selected item'))
|
||||
frappe.msgprint(_('Set items shelf life in days, to set expiry based on manufacturing_date plus self life'))
|
||||
frappe.msgprint(_('Expiry date is mandatory for selected item.'))
|
||||
frappe.throw(_("Set item's shelf life in days, to set expiry based on manufacturing date plus shelf-life."))
|
||||
|
||||
def get_name_from_naming_series(self):
|
||||
"""
|
||||
|
@ -67,43 +67,34 @@ frappe.ui.form.on('Delivery Trip', {
|
||||
},
|
||||
|
||||
calculate_arrival_time: function (frm) {
|
||||
frappe.db.get_value("Google Maps Settings", { name: "Google Maps Settings" }, "enabled", (r) => {
|
||||
if (r.enabled == 0) {
|
||||
frappe.throw(__("Please enable Google Maps Settings to estimate and optimize routes"));
|
||||
} else {
|
||||
frappe.call({
|
||||
method: 'erpnext.stock.doctype.delivery_trip.delivery_trip.get_arrival_times',
|
||||
freeze: true,
|
||||
freeze_message: __("Updating estimated arrival times."),
|
||||
args: {
|
||||
delivery_trip: frm.doc.name,
|
||||
},
|
||||
callback: function (r) {
|
||||
frm.reload_doc();
|
||||
if (!frm.doc.driver_address) {
|
||||
frappe.throw(__("Cannot Calculate Arrival Time as Driver Address is Missing."));
|
||||
}
|
||||
frappe.show_alert({
|
||||
message: "Calculating Arrival Times",
|
||||
indicator: 'orange'
|
||||
});
|
||||
}
|
||||
})
|
||||
frm.call("process_route", {
|
||||
optimize: false,
|
||||
}, () => {
|
||||
frm.reload_doc();
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
optimize_route: function (frm) {
|
||||
frappe.db.get_value("Google Maps Settings", {name: "Google Maps Settings"}, "enabled", (r) => {
|
||||
if (r.enabled == 0) {
|
||||
frappe.throw(__("Please enable Google Maps Settings to estimate and optimize routes"));
|
||||
} else {
|
||||
frappe.call({
|
||||
method: 'erpnext.stock.doctype.delivery_trip.delivery_trip.optimize_route',
|
||||
freeze: true,
|
||||
freeze_message: __("Optimizing routes."),
|
||||
args: {
|
||||
delivery_trip: frm.doc.name,
|
||||
},
|
||||
callback: function (r) {
|
||||
frm.reload_doc();
|
||||
if (!frm.doc.driver_address) {
|
||||
frappe.throw(__("Cannot Optimize Route as Driver Address is Missing."));
|
||||
}
|
||||
frappe.show_alert({
|
||||
message: "Optimizing Route",
|
||||
indicator: 'orange'
|
||||
});
|
||||
frm.call("process_route", {
|
||||
optimize: true,
|
||||
}, () => {
|
||||
frm.reload_doc();
|
||||
});
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
notify_customers: function (frm) {
|
||||
|
@ -1,686 +1,180 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_events_in_timeline": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"autoname": "naming_series:",
|
||||
"beta": 0,
|
||||
"creation": "2017-10-16 16:45:48.293335",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "Document",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"naming_series",
|
||||
"company",
|
||||
"column_break_2",
|
||||
"email_notification_sent",
|
||||
"section_break_3",
|
||||
"driver",
|
||||
"driver_name",
|
||||
"driver_address",
|
||||
"total_distance",
|
||||
"uom",
|
||||
"column_break_4",
|
||||
"vehicle",
|
||||
"departure_time",
|
||||
"delivery_service_stops",
|
||||
"delivery_stops",
|
||||
"calculate_arrival_time",
|
||||
"optimize_route",
|
||||
"section_break_15",
|
||||
"status",
|
||||
"cb_more_info",
|
||||
"amended_from"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "",
|
||||
"fieldname": "naming_series",
|
||||
"fieldtype": "Select",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Series",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "MAT-DT-.YYYY.-",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"options": "MAT-DT-.YYYY.-"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "company",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Company",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Company",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "column_break_2",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 1,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "0",
|
||||
"fieldname": "email_notification_sent",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Initial Email Notification Sent",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "section_break_3",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Delivery Details",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"label": "Delivery Details"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "driver",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Driver",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Driver",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_from": "driver.full_name",
|
||||
"fieldname": "driver_name",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Driver Name",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "total_distance",
|
||||
"fieldtype": "Float",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Total Estimated Distance",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "2",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "",
|
||||
"depends_on": "eval:doc.total_distance",
|
||||
"fieldname": "uom",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Distance UOM",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "UOM",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "column_break_4",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "vehicle",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Vehicle",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Vehicle",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "departure_time",
|
||||
"fieldtype": "Datetime",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Departure Time",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "delivery_service_stops",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Delivery Stops",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"label": "Delivery Stops"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "delivery_stops",
|
||||
"fieldtype": "Table",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Delivery Stop",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Delivery Stop",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "eval:!doc.__islocal",
|
||||
"description": "Use Google Maps Direction API to calculate estimated arrival times",
|
||||
"fieldname": "calculate_arrival_time",
|
||||
"fieldtype": "Button",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Calculate Estimated Arrival Times",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"label": "Calculate Estimated Arrival Times"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "eval:!doc.__islocal",
|
||||
"description": "Use Google Maps Direction API to optimize route",
|
||||
"fieldname": "optimize_route",
|
||||
"fieldtype": "Button",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Optimize Route",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"label": "Optimize Route"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 1,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "section_break_15",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"fieldtype": "Section Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "status",
|
||||
"fieldtype": "Select",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Status",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"options": "Draft\nScheduled\nIn Transit\nCompleted\nCancelled",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 1,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "cb_more_info",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "amended_from",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Amended From",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"options": "Delivery Trip",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fetch_from": "driver.address",
|
||||
"fieldname": "driver_address",
|
||||
"fieldtype": "Link",
|
||||
"label": "Driver Address",
|
||||
"options": "Address",
|
||||
"read_only": 1
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 0,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"is_submittable": 1,
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2018-10-22 08:25:42.323147",
|
||||
"modified": "2019-07-18 16:38:44.112651",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Delivery Trip",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
@ -690,14 +184,10 @@
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Fulfillment User",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 1,
|
||||
"write": 1
|
||||
@ -709,27 +199,16 @@
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Stock User",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 0,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"title_field": "driver_name",
|
||||
"track_changes": 0,
|
||||
"track_seen": 0,
|
||||
"track_views": 0
|
||||
"title_field": "driver_name"
|
||||
}
|
@ -100,16 +100,13 @@ class DeliveryTrip(Document):
|
||||
optimize (bool): True if route needs to be optimized, else False
|
||||
"""
|
||||
|
||||
if not frappe.db.get_single_value("Google Maps Settings", "enabled"):
|
||||
frappe.throw(_("Cannot process route, since Google Maps Settings is disabled."))
|
||||
|
||||
departure_datetime = get_datetime(self.departure_time)
|
||||
route_list = self.form_route_list(optimize)
|
||||
|
||||
# For locks, maintain idx count while looping through route list
|
||||
idx = 0
|
||||
for route in route_list:
|
||||
directions = get_directions(route, optimize)
|
||||
directions = self.get_directions(route, optimize)
|
||||
|
||||
if directions:
|
||||
if optimize and len(directions.get("waypoint_order")) > 1:
|
||||
@ -157,9 +154,10 @@ class DeliveryTrip(Document):
|
||||
Returns:
|
||||
(list of list of str): List of address routes split at locks, if optimize is `True`
|
||||
"""
|
||||
if not self.driver_address:
|
||||
frappe.throw(_("Cannot Calculate Arrival Time as Driver Address is Missing."))
|
||||
|
||||
settings = frappe.get_single("Google Maps Settings")
|
||||
home_address = get_address_display(frappe.get_doc("Address", settings.home_address).as_dict())
|
||||
home_address = get_address_display(frappe.get_doc("Address", self.driver_address).as_dict())
|
||||
|
||||
route_list = []
|
||||
# Initialize first leg with origin as the home address
|
||||
@ -204,6 +202,47 @@ class DeliveryTrip(Document):
|
||||
|
||||
self.delivery_stops[start:start + len(stops_order)] = stops_order
|
||||
|
||||
def get_directions(self, route, optimize):
|
||||
"""
|
||||
Retrieve map directions for a given route and departure time.
|
||||
If optimize is `True`, Google Maps will return an optimized
|
||||
order for the intermediate waypoints.
|
||||
|
||||
NOTE: Google's API does take an additional `departure_time` key,
|
||||
but it only works for routes without any waypoints.
|
||||
|
||||
Args:
|
||||
route (list of str): Route addresses (origin -> waypoint(s), if any -> destination)
|
||||
optimize (bool): `True` if route needs to be optimized, else `False`
|
||||
|
||||
Returns:
|
||||
(dict): Route legs and, if `optimize` is `True`, optimized waypoint order
|
||||
"""
|
||||
if not frappe.db.get_single_value("Google Settings", "api_key"):
|
||||
frappe.throw(_("Enter API key in Google Settings."))
|
||||
|
||||
import googlemaps
|
||||
|
||||
try:
|
||||
maps_client = googlemaps.Client(key=frappe.db.get_single_value("Google Settings", "api_key"))
|
||||
except Exception as e:
|
||||
frappe.throw(e)
|
||||
|
||||
directions_data = {
|
||||
"origin": route[0],
|
||||
"destination": route[-1],
|
||||
"waypoints": route[1: -1],
|
||||
"optimize_waypoints": optimize
|
||||
}
|
||||
|
||||
try:
|
||||
directions = maps_client.directions(**directions_data)
|
||||
except Exception as e:
|
||||
frappe.throw(_(e.message))
|
||||
|
||||
return directions[0] if directions else False
|
||||
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_contact_and_address(name):
|
||||
@ -278,18 +317,6 @@ def get_contact_display(contact):
|
||||
return contact_info.html
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def optimize_route(delivery_trip):
|
||||
delivery_trip = frappe.get_doc("Delivery Trip", delivery_trip)
|
||||
delivery_trip.process_route(optimize=True)
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_arrival_times(delivery_trip):
|
||||
delivery_trip = frappe.get_doc("Delivery Trip", delivery_trip)
|
||||
delivery_trip.process_route(optimize=False)
|
||||
|
||||
|
||||
def sanitize_address(address):
|
||||
"""
|
||||
Remove HTML breaks in a given address
|
||||
@ -310,41 +337,6 @@ def sanitize_address(address):
|
||||
return ', '.join(address[:3])
|
||||
|
||||
|
||||
def get_directions(route, optimize):
|
||||
"""
|
||||
Retrieve map directions for a given route and departure time.
|
||||
If optimize is `True`, Google Maps will return an optimized
|
||||
order for the intermediate waypoints.
|
||||
|
||||
NOTE: Google's API does take an additional `departure_time` key,
|
||||
but it only works for routes without any waypoints.
|
||||
|
||||
Args:
|
||||
route (list of str): Route addresses (origin -> waypoint(s), if any -> destination)
|
||||
optimize (bool): `True` if route needs to be optimized, else `False`
|
||||
|
||||
Returns:
|
||||
(dict): Route legs and, if `optimize` is `True`, optimized waypoint order
|
||||
"""
|
||||
|
||||
settings = frappe.get_single("Google Maps Settings")
|
||||
maps_client = settings.get_client()
|
||||
|
||||
directions_data = {
|
||||
"origin": route[0],
|
||||
"destination": route[-1],
|
||||
"waypoints": route[1: -1],
|
||||
"optimize_waypoints": optimize
|
||||
}
|
||||
|
||||
try:
|
||||
directions = maps_client.directions(**directions_data)
|
||||
except Exception as e:
|
||||
frappe.throw(_(e.message))
|
||||
|
||||
return directions[0] if directions else False
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def notify_customers(delivery_trip):
|
||||
delivery_trip = frappe.get_doc("Delivery Trip", delivery_trip)
|
||||
|
@ -14,16 +14,13 @@ from frappe.utils import add_days, flt, now_datetime, nowdate
|
||||
|
||||
class TestDeliveryTrip(unittest.TestCase):
|
||||
def setUp(self):
|
||||
create_driver()
|
||||
driver = create_driver()
|
||||
create_vehicle()
|
||||
create_delivery_notification()
|
||||
create_test_contact_and_address()
|
||||
address = create_address(driver)
|
||||
|
||||
settings = frappe.get_single("Google Maps Settings")
|
||||
settings.home_address = frappe.get_last_doc("Address").name
|
||||
settings.save()
|
||||
|
||||
self.delivery_trip = create_delivery_trip()
|
||||
self.delivery_trip = create_delivery_trip(driver, address)
|
||||
|
||||
def tearDown(self):
|
||||
frappe.db.sql("delete from `tabDriver`")
|
||||
@ -99,17 +96,42 @@ class TestDeliveryTrip(unittest.TestCase):
|
||||
self.delivery_trip.save()
|
||||
self.assertEqual(self.delivery_trip.status, "Completed")
|
||||
|
||||
def create_address(driver):
|
||||
if not frappe.db.exists("Address", {"address_title": "_Test Address for Driver"}):
|
||||
address = frappe.get_doc({
|
||||
"doctype": "Address",
|
||||
"address_title": "_Test Address for Driver",
|
||||
"address_type": "Office",
|
||||
"address_line1": "Station Road",
|
||||
"city": "_Test City",
|
||||
"state": "Test State",
|
||||
"country": "India",
|
||||
"links":[
|
||||
{
|
||||
"link_doctype": "Driver",
|
||||
"link_name": driver.name
|
||||
}
|
||||
]
|
||||
}).insert(ignore_permissions=True)
|
||||
|
||||
frappe.db.set_value("Driver", driver.name, "address", address.name)
|
||||
|
||||
return address
|
||||
|
||||
return frappe.get_doc("Address", {"address_title": "_Test Address for Driver"})
|
||||
|
||||
def create_driver():
|
||||
if not frappe.db.exists("Driver", "Newton Scmander"):
|
||||
if not frappe.db.exists("Driver", {"full_name": "Newton Scmander"}):
|
||||
driver = frappe.get_doc({
|
||||
"doctype": "Driver",
|
||||
"full_name": "Newton Scmander",
|
||||
"cell_number": "98343424242",
|
||||
"license_number": "B809"
|
||||
})
|
||||
driver.insert()
|
||||
"license_number": "B809",
|
||||
}).insert(ignore_permissions=True)
|
||||
|
||||
return driver
|
||||
|
||||
return frappe.get_doc("Driver", {"full_name": "Newton Scmander"})
|
||||
|
||||
def create_delivery_notification():
|
||||
if not frappe.db.exists("Email Template", "Delivery Notification"):
|
||||
@ -144,16 +166,16 @@ def create_vehicle():
|
||||
vehicle.insert()
|
||||
|
||||
|
||||
def create_delivery_trip(contact=None):
|
||||
def create_delivery_trip(driver, address, contact=None):
|
||||
if not contact:
|
||||
contact = get_contact_and_address("_Test Customer")
|
||||
|
||||
delivery_trip = frappe.new_doc("Delivery Trip")
|
||||
delivery_trip.update({
|
||||
delivery_trip = frappe.get_doc({
|
||||
"doctype": "Delivery Trip",
|
||||
"company": erpnext.get_default_company(),
|
||||
"departure_time": add_days(now_datetime(), 5),
|
||||
"driver": frappe.db.get_value('Driver', {"full_name": "Newton Scmander"}),
|
||||
"driver": driver.name,
|
||||
"driver_address": address.name,
|
||||
"vehicle": "JB 007",
|
||||
"delivery_stops": [{
|
||||
"customer": "_Test Customer",
|
||||
@ -165,7 +187,6 @@ def create_delivery_trip(contact=None):
|
||||
"address": contact.shipping_address.parent,
|
||||
"contact": contact.contact_person.parent
|
||||
}]
|
||||
})
|
||||
delivery_trip.insert()
|
||||
}).insert(ignore_permissions=True)
|
||||
|
||||
return delivery_trip
|
||||
|
@ -197,6 +197,9 @@ class Item(WebsiteGenerator):
|
||||
'route')) + '/' + self.scrub((self.item_name if self.item_name else self.item_code) + '-' + random_string(5))
|
||||
|
||||
def validate_website_image(self):
|
||||
if frappe.flags.in_import:
|
||||
return
|
||||
|
||||
"""Validate if the website image is a public file"""
|
||||
auto_set_website_image = False
|
||||
if not self.website_image and self.image:
|
||||
@ -216,8 +219,7 @@ class Item(WebsiteGenerator):
|
||||
|
||||
if not file_doc:
|
||||
if not auto_set_website_image:
|
||||
frappe.msgprint(_("Website Image {0} attached to Item {1} cannot be found")
|
||||
.format(self.website_image, self.name))
|
||||
frappe.msgprint(_("Website Image {0} attached to Item {1} cannot be found").format(self.website_image, self.name))
|
||||
|
||||
self.website_image = None
|
||||
|
||||
@ -228,6 +230,9 @@ class Item(WebsiteGenerator):
|
||||
self.website_image = None
|
||||
|
||||
def make_thumbnail(self):
|
||||
if frappe.flags.in_import:
|
||||
return
|
||||
|
||||
"""Make a thumbnail of `website_image`"""
|
||||
import requests.exceptions
|
||||
|
||||
|
@ -20,6 +20,8 @@ frappe.listview_settings['Material Request'] = {
|
||||
return [__("Issued"), "green", "per_ordered,=,100"];
|
||||
} else if (doc.material_request_type == "Customer Provided") {
|
||||
return [__("Received"), "green", "per_ordered,=,100"];
|
||||
} else if (doc.material_request_type == "Manufacture") {
|
||||
return [__("Manufactured"), "green", "per_ordered,=,100"];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -264,8 +264,12 @@ frappe.ui.form.on('Purchase Receipt Item', {
|
||||
var d = locals[cdt][cdn];
|
||||
frappe.db.get_value('Item', {name: d.item_code}, 'sample_quantity', (r) => {
|
||||
frappe.model.set_value(cdt, cdn, "sample_quantity", r.sample_quantity);
|
||||
validate_sample_quantity(frm, cdt, cdn);
|
||||
});
|
||||
},
|
||||
qty: function(frm, cdt, cdn) {
|
||||
validate_sample_quantity(frm, cdt, cdn);
|
||||
},
|
||||
sample_quantity: function(frm, cdt, cdn) {
|
||||
validate_sample_quantity(frm, cdt, cdn);
|
||||
},
|
||||
@ -283,7 +287,7 @@ cur_frm.cscript['Make Stock Entry'] = function() {
|
||||
|
||||
var validate_sample_quantity = function(frm, cdt, cdn) {
|
||||
var d = locals[cdt][cdn];
|
||||
if (d.sample_quantity) {
|
||||
if (d.sample_quantity && d.qty) {
|
||||
frappe.call({
|
||||
method: 'erpnext.stock.doctype.stock_entry.stock_entry.validate_sample_quantity',
|
||||
args: {
|
||||
|
@ -222,7 +222,7 @@ def validate_serial_no(sle, item_det):
|
||||
frappe.throw(_("Serial No {0} has already been received").format(serial_no),
|
||||
SerialNoDuplicateError)
|
||||
|
||||
if (sr.delivery_document_no and sle.voucher_type != 'Stock Entry'
|
||||
if (sr.delivery_document_no and sle.voucher_type not in ['Stock Entry', 'Stock Reconciliation']
|
||||
and sle.voucher_type == sr.delivery_document_type):
|
||||
return_against = frappe.db.get_value(sle.voucher_type, sle.voucher_no, 'return_against')
|
||||
if return_against and return_against != sr.delivery_document_no:
|
||||
@ -299,7 +299,7 @@ def validate_so_serial_no(sr, sales_order,):
|
||||
be delivered""").format(sales_order, sr.item_code, sr.name))
|
||||
|
||||
def has_duplicate_serial_no(sn, sle):
|
||||
if sn.warehouse:
|
||||
if sn.warehouse and sle.voucher_type != 'Stock Reconciliation':
|
||||
return True
|
||||
|
||||
if sn.company != sle.company:
|
||||
@ -415,16 +415,20 @@ def update_serial_nos_after_submit(controller, parentfield):
|
||||
if not stock_ledger_entries: return
|
||||
|
||||
for d in controller.get(parentfield):
|
||||
if d.serial_no:
|
||||
continue
|
||||
|
||||
update_rejected_serial_nos = True if (controller.doctype in ("Purchase Receipt", "Purchase Invoice")
|
||||
and d.rejected_qty) else False
|
||||
accepted_serial_nos_updated = False
|
||||
|
||||
if controller.doctype == "Stock Entry":
|
||||
warehouse = d.t_warehouse
|
||||
qty = d.transfer_qty
|
||||
else:
|
||||
warehouse = d.warehouse
|
||||
qty = d.stock_qty
|
||||
|
||||
qty = (d.qty if controller.doctype == "Stock Reconciliation"
|
||||
else d.stock_qty)
|
||||
for sle in stock_ledger_entries:
|
||||
if sle.voucher_detail_no==d.name:
|
||||
if not accepted_serial_nos_updated and qty and abs(sle.actual_qty)==qty \
|
||||
|
@ -359,7 +359,7 @@ class StockEntry(StockController):
|
||||
d.basic_rate = 0.0
|
||||
elif d.t_warehouse and not d.basic_rate:
|
||||
d.basic_rate = get_valuation_rate(d.item_code, d.t_warehouse,
|
||||
self.doctype, d.name, d.allow_zero_valuation_rate,
|
||||
self.doctype, self.name, d.allow_zero_valuation_rate,
|
||||
currency=erpnext.get_company_currency(self.company))
|
||||
|
||||
def set_actual_qty(self):
|
||||
|
@ -38,7 +38,7 @@ class StockLedgerEntry(Document):
|
||||
self.check_stock_frozen_date()
|
||||
self.actual_amt_check()
|
||||
|
||||
if not self.get("via_landed_cost_voucher") and self.voucher_type != 'Stock Reconciliation':
|
||||
if not self.get("via_landed_cost_voucher"):
|
||||
from erpnext.stock.doctype.serial_no.serial_no import process_serial_no
|
||||
process_serial_no(self)
|
||||
|
||||
|
@ -12,8 +12,7 @@ frappe.ui.form.on("Stock Reconciliation", {
|
||||
return {
|
||||
query: "erpnext.controllers.queries.item_query",
|
||||
filters:{
|
||||
"is_stock_item": 1,
|
||||
"has_serial_no": 0
|
||||
"is_stock_item": 1
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -77,6 +76,7 @@ frappe.ui.form.on("Stock Reconciliation", {
|
||||
|
||||
set_valuation_rate_and_qty: function(frm, cdt, cdn) {
|
||||
var d = frappe.model.get_doc(cdt, cdn);
|
||||
|
||||
if(d.item_code && d.warehouse) {
|
||||
frappe.call({
|
||||
method: "erpnext.stock.doctype.stock_reconciliation.stock_reconciliation.get_stock_balance_for",
|
||||
@ -84,7 +84,8 @@ frappe.ui.form.on("Stock Reconciliation", {
|
||||
item_code: d.item_code,
|
||||
warehouse: d.warehouse,
|
||||
posting_date: frm.doc.posting_date,
|
||||
posting_time: frm.doc.posting_time
|
||||
posting_time: frm.doc.posting_time,
|
||||
batch_no: d.batch_no
|
||||
},
|
||||
callback: function(r) {
|
||||
frappe.model.set_value(cdt, cdn, "qty", r.message.qty);
|
||||
@ -93,7 +94,7 @@ frappe.ui.form.on("Stock Reconciliation", {
|
||||
frappe.model.set_value(cdt, cdn, "current_valuation_rate", r.message.rate);
|
||||
frappe.model.set_value(cdt, cdn, "current_amount", r.message.rate * r.message.qty);
|
||||
frappe.model.set_value(cdt, cdn, "amount", r.message.rate * r.message.qty);
|
||||
|
||||
frappe.model.set_value(cdt, cdn, "current_serial_no", r.message.serial_nos);
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -152,17 +153,44 @@ frappe.ui.form.on("Stock Reconciliation Item", {
|
||||
barcode: function(frm, cdt, cdn) {
|
||||
frm.events.set_item_code(frm, cdt, cdn);
|
||||
},
|
||||
|
||||
warehouse: function(frm, cdt, cdn) {
|
||||
var child = locals[cdt][cdn];
|
||||
if (child.batch_no) {
|
||||
frappe.model.set_value(child.cdt, child.cdn, "batch_no", "");
|
||||
}
|
||||
|
||||
frm.events.set_valuation_rate_and_qty(frm, cdt, cdn);
|
||||
},
|
||||
|
||||
item_code: function(frm, cdt, cdn) {
|
||||
var child = locals[cdt][cdn];
|
||||
if (child.batch_no) {
|
||||
frappe.model.set_value(cdt, cdn, "batch_no", "");
|
||||
}
|
||||
|
||||
frm.events.set_valuation_rate_and_qty(frm, cdt, cdn);
|
||||
},
|
||||
|
||||
batch_no: function(frm, cdt, cdn) {
|
||||
frm.events.set_valuation_rate_and_qty(frm, cdt, cdn);
|
||||
},
|
||||
|
||||
qty: function(frm, cdt, cdn) {
|
||||
frm.events.set_amount_quantity(frm, cdt, cdn);
|
||||
},
|
||||
|
||||
valuation_rate: function(frm, cdt, cdn) {
|
||||
frm.events.set_amount_quantity(frm, cdt, cdn);
|
||||
},
|
||||
|
||||
serial_no: function(frm, cdt, cdn) {
|
||||
var child = locals[cdt][cdn];
|
||||
|
||||
if (child.serial_no) {
|
||||
const serial_nos = child.serial_no.trim().split('\n');
|
||||
frappe.model.set_value(cdt, cdn, "qty", serial_nos.length);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
@ -9,7 +9,9 @@ from frappe.utils import cstr, flt, cint
|
||||
from erpnext.stock.stock_ledger import update_entries_after
|
||||
from erpnext.controllers.stock_controller import StockController
|
||||
from erpnext.accounts.utils import get_company_default
|
||||
from erpnext.stock.utils import get_stock_balance
|
||||
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
|
||||
from erpnext.stock.utils import get_stock_balance, get_incoming_rate, get_available_serial_nos
|
||||
from erpnext.stock.doctype.batch.batch import get_batch_qty
|
||||
|
||||
class OpeningEntryAccountError(frappe.ValidationError): pass
|
||||
class EmptyStockReconciliationItemsError(frappe.ValidationError): pass
|
||||
@ -30,10 +32,16 @@ class StockReconciliation(StockController):
|
||||
self.validate_expense_account()
|
||||
self.set_total_qty_and_amount()
|
||||
|
||||
if self._action=="submit":
|
||||
self.make_batches('warehouse')
|
||||
|
||||
def on_submit(self):
|
||||
self.update_stock_ledger()
|
||||
self.make_gl_entries()
|
||||
|
||||
from erpnext.stock.doctype.serial_no.serial_no import update_serial_nos_after_submit
|
||||
update_serial_nos_after_submit(self, "items")
|
||||
|
||||
def on_cancel(self):
|
||||
self.delete_and_repost_sle()
|
||||
self.make_gl_entries_on_cancel()
|
||||
@ -42,23 +50,28 @@ class StockReconciliation(StockController):
|
||||
"""Remove items if qty or rate is not changed"""
|
||||
self.difference_amount = 0.0
|
||||
def _changed(item):
|
||||
qty, rate = get_stock_balance(item.item_code, item.warehouse,
|
||||
self.posting_date, self.posting_time, with_valuation_rate=True)
|
||||
if (item.qty==None or item.qty==qty) and (item.valuation_rate==None or item.valuation_rate==rate):
|
||||
item_dict = get_stock_balance_for(item.item_code, item.warehouse,
|
||||
self.posting_date, self.posting_time, batch_no=item.batch_no)
|
||||
if (((item.qty is None or item.qty==item_dict.get("qty")) and
|
||||
(item.valuation_rate is None or item.valuation_rate==item_dict.get("rate")) and not item.serial_no)
|
||||
or (item.serial_no and item.serial_no == item_dict.get("serial_nos"))):
|
||||
return False
|
||||
else:
|
||||
# set default as current rates
|
||||
if item.qty==None:
|
||||
item.qty = qty
|
||||
if item.qty is None:
|
||||
item.qty = item_dict.get("qty")
|
||||
|
||||
if item.valuation_rate==None:
|
||||
item.valuation_rate = rate
|
||||
if item.valuation_rate is None:
|
||||
item.valuation_rate = item_dict.get("rate")
|
||||
|
||||
item.current_qty = qty
|
||||
item.current_valuation_rate = rate
|
||||
if item_dict.get("serial_nos"):
|
||||
item.current_serial_no = item_dict.get("serial_nos")
|
||||
|
||||
item.current_qty = item_dict.get("qty")
|
||||
item.current_valuation_rate = item_dict.get("rate")
|
||||
self.difference_amount += (flt(item.qty, item.precision("qty")) * \
|
||||
flt(item.valuation_rate or rate, item.precision("valuation_rate")) \
|
||||
- flt(qty, item.precision("qty")) * flt(rate, item.precision("valuation_rate")))
|
||||
flt(item.valuation_rate or item_dict.get("rate"), item.precision("valuation_rate")) \
|
||||
- flt(item_dict.get("qty"), item.precision("qty")) * flt(item_dict.get("rate"), item.precision("valuation_rate")))
|
||||
return True
|
||||
|
||||
items = list(filter(lambda d: _changed(d), self.items))
|
||||
@ -84,12 +97,17 @@ class StockReconciliation(StockController):
|
||||
|
||||
for row_num, row in enumerate(self.items):
|
||||
# find duplicates
|
||||
if [row.item_code, row.warehouse] in item_warehouse_combinations:
|
||||
key = [row.item_code, row.warehouse]
|
||||
for field in ['serial_no', 'batch_no']:
|
||||
if row.get(field):
|
||||
key.append(row.get(field))
|
||||
|
||||
if key in item_warehouse_combinations:
|
||||
self.validation_messages.append(_get_msg(row_num, _("Duplicate entry")))
|
||||
else:
|
||||
item_warehouse_combinations.append([row.item_code, row.warehouse])
|
||||
item_warehouse_combinations.append(key)
|
||||
|
||||
self.validate_item(row.item_code, row_num+1)
|
||||
self.validate_item(row.item_code, row)
|
||||
|
||||
# validate warehouse
|
||||
if not frappe.db.get_value("Warehouse", row.warehouse):
|
||||
@ -131,7 +149,7 @@ class StockReconciliation(StockController):
|
||||
|
||||
raise frappe.ValidationError(self.validation_messages)
|
||||
|
||||
def validate_item(self, item_code, row_num):
|
||||
def validate_item(self, item_code, row):
|
||||
from erpnext.stock.doctype.item.item import validate_end_of_life, \
|
||||
validate_is_stock_item, validate_cancelled_item
|
||||
|
||||
@ -145,31 +163,37 @@ class StockReconciliation(StockController):
|
||||
validate_is_stock_item(item_code, item.is_stock_item, verbose=0)
|
||||
|
||||
# item should not be serialized
|
||||
if item.has_serial_no == 1:
|
||||
raise frappe.ValidationError(_("Serialized Item {0} cannot be updated using Stock Reconciliation, please use Stock Entry").format(item_code))
|
||||
if item.has_serial_no and not row.serial_no and not item.serial_no_series:
|
||||
raise frappe.ValidationError(_("Serial no(s) required for serialized item {0}").format(item_code))
|
||||
|
||||
# item managed batch-wise not allowed
|
||||
if item.has_batch_no == 1:
|
||||
raise frappe.ValidationError(_("Batched Item {0} cannot be updated using Stock Reconciliation, instead use Stock Entry").format(item_code))
|
||||
if item.has_batch_no and not row.batch_no and not item.create_new_batch:
|
||||
raise frappe.ValidationError(_("Batch no is required for batched item {0}").format(item_code))
|
||||
|
||||
# docstatus should be < 2
|
||||
validate_cancelled_item(item_code, item.docstatus, verbose=0)
|
||||
|
||||
except Exception as e:
|
||||
self.validation_messages.append(_("Row # ") + ("%d: " % (row_num)) + cstr(e))
|
||||
self.validation_messages.append(_("Row # ") + ("%d: " % (row.idx)) + cstr(e))
|
||||
|
||||
def update_stock_ledger(self):
|
||||
""" find difference between current and expected entries
|
||||
and create stock ledger entries based on the difference"""
|
||||
from erpnext.stock.stock_ledger import get_previous_sle
|
||||
|
||||
sl_entries = []
|
||||
for row in self.items:
|
||||
item = frappe.get_doc("Item", row.item_code)
|
||||
if item.has_serial_no or item.has_batch_no:
|
||||
self.get_sle_for_serialized_items(row, sl_entries)
|
||||
else:
|
||||
previous_sle = get_previous_sle({
|
||||
"item_code": row.item_code,
|
||||
"warehouse": row.warehouse,
|
||||
"posting_date": self.posting_date,
|
||||
"posting_time": self.posting_time
|
||||
})
|
||||
|
||||
if previous_sle:
|
||||
if row.qty in ("", None):
|
||||
row.qty = previous_sle.get("qty_after_transaction", 0)
|
||||
@ -178,18 +202,91 @@ class StockReconciliation(StockController):
|
||||
row.valuation_rate = previous_sle.get("valuation_rate", 0)
|
||||
|
||||
if row.qty and not row.valuation_rate:
|
||||
frappe.throw(_("Valuation Rate required for Item in row {0}").format(row.idx))
|
||||
frappe.throw(_("Valuation Rate required for Item {0} at row {1}").format(row.item_code, row.idx))
|
||||
|
||||
if ((previous_sle and row.qty == previous_sle.get("qty_after_transaction")
|
||||
and (row.valuation_rate == previous_sle.get("valuation_rate") or row.qty == 0))
|
||||
or (not previous_sle and not row.qty)):
|
||||
continue
|
||||
|
||||
self.insert_entries(row)
|
||||
sl_entries.append(self.get_sle_for_items(row))
|
||||
|
||||
def insert_entries(self, row):
|
||||
if sl_entries:
|
||||
self.make_sl_entries(sl_entries)
|
||||
|
||||
def get_sle_for_serialized_items(self, row, sl_entries):
|
||||
from erpnext.stock.stock_ledger import get_previous_sle
|
||||
|
||||
serial_nos = get_serial_nos(row.serial_no)
|
||||
|
||||
|
||||
# To issue existing serial nos
|
||||
if row.current_qty and (row.current_serial_no or row.batch_no):
|
||||
args = self.get_sle_for_items(row)
|
||||
args.update({
|
||||
'actual_qty': -1 * row.current_qty,
|
||||
'serial_no': row.current_serial_no,
|
||||
'batch_no': row.batch_no,
|
||||
'valuation_rate': row.current_valuation_rate
|
||||
})
|
||||
|
||||
if row.current_serial_no:
|
||||
args.update({
|
||||
'qty_after_transaction': 0,
|
||||
})
|
||||
|
||||
sl_entries.append(args)
|
||||
|
||||
for serial_no in serial_nos:
|
||||
args = self.get_sle_for_items(row, [serial_no])
|
||||
|
||||
previous_sle = get_previous_sle({
|
||||
"item_code": row.item_code,
|
||||
"posting_date": self.posting_date,
|
||||
"posting_time": self.posting_time,
|
||||
"serial_no": serial_no
|
||||
})
|
||||
|
||||
if previous_sle and row.warehouse != previous_sle.get("warehouse"):
|
||||
# If serial no exists in different warehouse
|
||||
|
||||
new_args = args.copy()
|
||||
new_args.update({
|
||||
'actual_qty': -1,
|
||||
'qty_after_transaction': cint(previous_sle.get('qty_after_transaction')) - 1,
|
||||
'warehouse': previous_sle.get("warehouse", '') or row.warehouse,
|
||||
'valuation_rate': previous_sle.get("valuation_rate")
|
||||
})
|
||||
|
||||
sl_entries.append(new_args)
|
||||
|
||||
if row.qty:
|
||||
args = self.get_sle_for_items(row)
|
||||
|
||||
args.update({
|
||||
'actual_qty': row.qty,
|
||||
'incoming_rate': row.valuation_rate,
|
||||
'valuation_rate': row.valuation_rate
|
||||
})
|
||||
|
||||
sl_entries.append(args)
|
||||
|
||||
if serial_nos == get_serial_nos(row.current_serial_no):
|
||||
# update valuation rate
|
||||
self.update_valuation_rate_for_serial_nos(row, serial_nos)
|
||||
|
||||
def update_valuation_rate_for_serial_nos(self, row, serial_nos):
|
||||
valuation_rate = row.valuation_rate if self.docstatus == 1 else row.current_valuation_rate
|
||||
for d in serial_nos:
|
||||
frappe.db.set_value("Serial No", d, 'purchase_rate', valuation_rate)
|
||||
|
||||
def get_sle_for_items(self, row, serial_nos=None):
|
||||
"""Insert Stock Ledger Entries"""
|
||||
args = frappe._dict({
|
||||
|
||||
if not serial_nos and row.serial_no:
|
||||
serial_nos = get_serial_nos(row.serial_no)
|
||||
|
||||
data = frappe._dict({
|
||||
"doctype": "Stock Ledger Entry",
|
||||
"item_code": row.item_code,
|
||||
"warehouse": row.warehouse,
|
||||
@ -197,13 +294,19 @@ class StockReconciliation(StockController):
|
||||
"posting_time": self.posting_time,
|
||||
"voucher_type": self.doctype,
|
||||
"voucher_no": self.name,
|
||||
"voucher_detail_no": row.name,
|
||||
"company": self.company,
|
||||
"stock_uom": frappe.db.get_value("Item", row.item_code, "stock_uom"),
|
||||
"is_cancelled": "No",
|
||||
"qty_after_transaction": flt(row.qty, row.precision("qty")),
|
||||
"is_cancelled": "No" if self.docstatus != 2 else "Yes",
|
||||
"serial_no": '\n'.join(serial_nos) if serial_nos else '',
|
||||
"batch_no": row.batch_no,
|
||||
"valuation_rate": flt(row.valuation_rate, row.precision("valuation_rate"))
|
||||
})
|
||||
self.make_sl_entries([args])
|
||||
|
||||
if not row.batch_no:
|
||||
data.qty_after_transaction = flt(row.qty, row.precision("qty"))
|
||||
|
||||
return data
|
||||
|
||||
def delete_and_repost_sle(self):
|
||||
""" Delete Stock Ledger Entries related to this voucher
|
||||
@ -217,6 +320,15 @@ class StockReconciliation(StockController):
|
||||
frappe.db.sql("""delete from `tabStock Ledger Entry`
|
||||
where voucher_type=%s and voucher_no=%s""", (self.doctype, self.name))
|
||||
|
||||
sl_entries = []
|
||||
for row in self.items:
|
||||
if row.serial_no or row.batch_no or row.current_serial_no:
|
||||
self.get_sle_for_serialized_items(row, sl_entries)
|
||||
|
||||
if sl_entries:
|
||||
sl_entries.reverse()
|
||||
self.make_sl_entries(sl_entries)
|
||||
|
||||
# repost future entries for selected item_code, warehouse
|
||||
for entries in existing_entries:
|
||||
update_entries_after({
|
||||
@ -310,17 +422,52 @@ def get_items(warehouse, posting_date, posting_time, company):
|
||||
return res
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_stock_balance_for(item_code, warehouse, posting_date, posting_time):
|
||||
def get_stock_balance_for(item_code, warehouse,
|
||||
posting_date, posting_time, batch_no=None, with_valuation_rate= True):
|
||||
frappe.has_permission("Stock Reconciliation", "write", throw = True)
|
||||
|
||||
item_dict = frappe.db.get_value("Item", item_code,
|
||||
["has_serial_no", "has_batch_no"], as_dict=1)
|
||||
|
||||
serial_nos = ""
|
||||
if item_dict.get("has_serial_no"):
|
||||
qty, rate, serial_nos = get_qty_rate_for_serial_nos(item_code,
|
||||
warehouse, posting_date, posting_time, item_dict)
|
||||
else:
|
||||
qty, rate = get_stock_balance(item_code, warehouse,
|
||||
posting_date, posting_time, with_valuation_rate=True)
|
||||
posting_date, posting_time, with_valuation_rate=with_valuation_rate)
|
||||
|
||||
if item_dict.get("has_batch_no"):
|
||||
qty = get_batch_qty(batch_no, warehouse) or 0
|
||||
|
||||
return {
|
||||
'qty': qty,
|
||||
'rate': rate
|
||||
'rate': rate,
|
||||
'serial_nos': serial_nos
|
||||
}
|
||||
|
||||
def get_qty_rate_for_serial_nos(item_code, warehouse, posting_date, posting_time, item_dict):
|
||||
args = {
|
||||
"item_code": item_code,
|
||||
"warehouse": warehouse,
|
||||
"posting_date": posting_date,
|
||||
"posting_time": posting_time,
|
||||
}
|
||||
|
||||
serial_nos_list = [serial_no.get("name")
|
||||
for serial_no in get_available_serial_nos(item_code, warehouse)]
|
||||
|
||||
qty = len(serial_nos_list)
|
||||
serial_nos = '\n'.join(serial_nos_list)
|
||||
args.update({
|
||||
'qty': qty,
|
||||
"serial_nos": serial_nos
|
||||
})
|
||||
|
||||
rate = get_incoming_rate(args, raise_error_if_no_rate=False) or 0
|
||||
|
||||
return qty, rate, serial_nos
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_difference_account(purpose, company):
|
||||
if purpose == 'Stock Reconciliation':
|
||||
|
@ -13,9 +13,12 @@ from erpnext.stock.stock_ledger import get_previous_sle, update_entries_after
|
||||
from erpnext.stock.doctype.stock_reconciliation.stock_reconciliation import EmptyStockReconciliationItemsError, get_items
|
||||
from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse
|
||||
from erpnext.stock.doctype.item.test_item import create_item
|
||||
from erpnext.stock.utils import get_stock_balance, get_incoming_rate, get_available_serial_nos, get_stock_value_on
|
||||
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
|
||||
|
||||
class TestStockReconciliation(unittest.TestCase):
|
||||
def setUp(self):
|
||||
create_batch_or_serial_no_items()
|
||||
frappe.db.set_value("Stock Settings", None, "allow_negative_stock", 1)
|
||||
self.insert_existing_sle()
|
||||
|
||||
@ -106,6 +109,135 @@ class TestStockReconciliation(unittest.TestCase):
|
||||
make_stock_entry(posting_date="2013-01-05", posting_time="07:00", item_code="_Test Item",
|
||||
target="_Test Warehouse - _TC", qty=15, basic_rate=1200)
|
||||
|
||||
def test_stock_reco_for_serialized_item(self):
|
||||
set_perpetual_inventory()
|
||||
|
||||
to_delete_records = []
|
||||
to_delete_serial_nos = []
|
||||
|
||||
# Add new serial nos
|
||||
serial_item_code = "Stock-Reco-Serial-Item-1"
|
||||
serial_warehouse = "_Test Warehouse for Stock Reco1 - _TC"
|
||||
|
||||
sr = create_stock_reconciliation(item_code=serial_item_code,
|
||||
warehouse = serial_warehouse, qty=5, rate=200)
|
||||
|
||||
# print(sr.name)
|
||||
serial_nos = get_serial_nos(sr.items[0].serial_no)
|
||||
self.assertEqual(len(serial_nos), 5)
|
||||
|
||||
args = {
|
||||
"item_code": serial_item_code,
|
||||
"warehouse": serial_warehouse,
|
||||
"posting_date": nowdate(),
|
||||
"posting_time": nowtime(),
|
||||
"serial_no": sr.items[0].serial_no
|
||||
}
|
||||
|
||||
valuation_rate = get_incoming_rate(args)
|
||||
self.assertEqual(valuation_rate, 200)
|
||||
|
||||
to_delete_records.append(sr.name)
|
||||
|
||||
sr = create_stock_reconciliation(item_code=serial_item_code,
|
||||
warehouse = serial_warehouse, qty=5, rate=300, serial_no = '\n'.join(serial_nos))
|
||||
|
||||
# print(sr.name)
|
||||
serial_nos1 = get_serial_nos(sr.items[0].serial_no)
|
||||
self.assertEqual(len(serial_nos1), 5)
|
||||
|
||||
args = {
|
||||
"item_code": serial_item_code,
|
||||
"warehouse": serial_warehouse,
|
||||
"posting_date": nowdate(),
|
||||
"posting_time": nowtime(),
|
||||
"serial_no": sr.items[0].serial_no
|
||||
}
|
||||
|
||||
valuation_rate = get_incoming_rate(args)
|
||||
self.assertEqual(valuation_rate, 300)
|
||||
|
||||
to_delete_records.append(sr.name)
|
||||
to_delete_records.reverse()
|
||||
|
||||
for d in to_delete_records:
|
||||
stock_doc = frappe.get_doc("Stock Reconciliation", d)
|
||||
stock_doc.cancel()
|
||||
frappe.delete_doc("Stock Reconciliation", stock_doc.name)
|
||||
|
||||
for d in serial_nos + serial_nos1:
|
||||
if frappe.db.exists("Serial No", d):
|
||||
frappe.delete_doc("Serial No", d)
|
||||
|
||||
def test_stock_reco_for_batch_item(self):
|
||||
set_perpetual_inventory()
|
||||
|
||||
to_delete_records = []
|
||||
to_delete_serial_nos = []
|
||||
|
||||
# Add new serial nos
|
||||
item_code = "Stock-Reco-batch-Item-1"
|
||||
warehouse = "_Test Warehouse for Stock Reco2 - _TC"
|
||||
|
||||
sr = create_stock_reconciliation(item_code=item_code,
|
||||
warehouse = warehouse, qty=5, rate=200, do_not_submit=1)
|
||||
sr.save(ignore_permissions=True)
|
||||
sr.submit()
|
||||
|
||||
self.assertTrue(sr.items[0].batch_no)
|
||||
to_delete_records.append(sr.name)
|
||||
|
||||
sr1 = create_stock_reconciliation(item_code=item_code,
|
||||
warehouse = warehouse, qty=6, rate=300, batch_no=sr.items[0].batch_no)
|
||||
|
||||
args = {
|
||||
"item_code": item_code,
|
||||
"warehouse": warehouse,
|
||||
"posting_date": nowdate(),
|
||||
"posting_time": nowtime(),
|
||||
}
|
||||
|
||||
valuation_rate = get_incoming_rate(args)
|
||||
self.assertEqual(valuation_rate, 300)
|
||||
to_delete_records.append(sr1.name)
|
||||
|
||||
|
||||
sr2 = create_stock_reconciliation(item_code=item_code,
|
||||
warehouse = warehouse, qty=0, rate=0, batch_no=sr.items[0].batch_no)
|
||||
|
||||
stock_value = get_stock_value_on(warehouse, nowdate(), item_code)
|
||||
self.assertEqual(stock_value, 0)
|
||||
to_delete_records.append(sr2.name)
|
||||
|
||||
to_delete_records.reverse()
|
||||
for d in to_delete_records:
|
||||
stock_doc = frappe.get_doc("Stock Reconciliation", d)
|
||||
stock_doc.cancel()
|
||||
|
||||
frappe.delete_doc("Batch", sr.items[0].batch_no)
|
||||
for d in to_delete_records:
|
||||
frappe.delete_doc("Stock Reconciliation", d)
|
||||
|
||||
def create_batch_or_serial_no_items():
|
||||
create_warehouse("_Test Warehouse for Stock Reco1",
|
||||
{"is_group": 0, "parent_warehouse": "_Test Warehouse Group - _TC"})
|
||||
|
||||
create_warehouse("_Test Warehouse for Stock Reco2",
|
||||
{"is_group": 0, "parent_warehouse": "_Test Warehouse Group - _TC"})
|
||||
|
||||
serial_item_doc = create_item("Stock-Reco-Serial-Item-1", is_stock_item=1)
|
||||
if not serial_item_doc.has_serial_no:
|
||||
serial_item_doc.has_serial_no = 1
|
||||
serial_item_doc.serial_no_series = "SRSI.####"
|
||||
serial_item_doc.save(ignore_permissions=True)
|
||||
|
||||
batch_item_doc = create_item("Stock-Reco-batch-Item-1", is_stock_item=1)
|
||||
if not batch_item_doc.has_batch_no:
|
||||
batch_item_doc.has_batch_no = 1
|
||||
batch_item_doc.create_new_batch = 1
|
||||
serial_item_doc.batch_number_series = "BASR.#####"
|
||||
batch_item_doc.save(ignore_permissions=True)
|
||||
|
||||
def create_stock_reconciliation(**args):
|
||||
args = frappe._dict(args)
|
||||
sr = frappe.new_doc("Stock Reconciliation")
|
||||
@ -120,10 +252,13 @@ def create_stock_reconciliation(**args):
|
||||
"item_code": args.item_code or "_Test Item",
|
||||
"warehouse": args.warehouse or "_Test Warehouse - _TC",
|
||||
"qty": args.qty,
|
||||
"valuation_rate": args.rate
|
||||
"valuation_rate": args.rate,
|
||||
"serial_no": args.serial_no,
|
||||
"batch_no": args.batch_no
|
||||
})
|
||||
|
||||
try:
|
||||
if not args.do_not_submit:
|
||||
sr.submit()
|
||||
except EmptyStockReconciliationItemsError:
|
||||
pass
|
||||
@ -140,3 +275,4 @@ def set_valuation_method(item_code, valuation_method):
|
||||
}, allow_negative_stock=1)
|
||||
|
||||
test_dependencies = ["Item", "Warehouse"]
|
||||
|
||||
|
@ -1,560 +1,182 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"beta": 0,
|
||||
"creation": "2015-02-17 01:06:05.072764",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "Other",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"barcode",
|
||||
"item_code",
|
||||
"item_name",
|
||||
"warehouse",
|
||||
"column_break_6",
|
||||
"qty",
|
||||
"valuation_rate",
|
||||
"amount",
|
||||
"serial_no_and_batch_section",
|
||||
"serial_no",
|
||||
"column_break_11",
|
||||
"batch_no",
|
||||
"section_break_3",
|
||||
"current_qty",
|
||||
"current_serial_no",
|
||||
"column_break_9",
|
||||
"current_valuation_rate",
|
||||
"current_amount",
|
||||
"section_break_14",
|
||||
"quantity_difference",
|
||||
"column_break_16",
|
||||
"amount_difference"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "barcode",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Barcode",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 1,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
"print_hide": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 3,
|
||||
"fieldname": "item_code",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 1,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Item Code",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Item",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "item_name",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 1,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Item Name",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 1,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 3,
|
||||
"fieldname": "warehouse",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Warehouse",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Warehouse",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "column_break_6",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 2,
|
||||
"description": "",
|
||||
"fieldname": "qty",
|
||||
"fieldtype": "Float",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Quantity",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
"label": "Quantity"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 2,
|
||||
"description": "",
|
||||
"fieldname": "valuation_rate",
|
||||
"fieldtype": "Currency",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Valuation Rate",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Company:company:default_currency",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
"options": "Company:company:default_currency"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "amount",
|
||||
"fieldtype": "Currency",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Amount",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Company:company:default_currency",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "serial_no_and_batch_section",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Serial No and Batch"
|
||||
},
|
||||
{
|
||||
"fieldname": "serial_no",
|
||||
"fieldtype": "Small Text",
|
||||
"label": "Serial No"
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_11",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "section_break_3",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Before reconciliation",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
"label": "Before reconciliation"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"description": "",
|
||||
"default": "0",
|
||||
"fieldname": "current_qty",
|
||||
"fieldtype": "Float",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Current Qty",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "current_serial_no",
|
||||
"fieldtype": "Small Text",
|
||||
"label": "Current Serial No",
|
||||
"no_copy": 1,
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "column_break_9",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"description": "",
|
||||
"fieldname": "current_valuation_rate",
|
||||
"fieldtype": "Currency",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Current Valuation Rate",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Company:company:default_currency",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"description": "",
|
||||
"fieldname": "current_amount",
|
||||
"fieldtype": "Currency",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Current Amount",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Company:company:default_currency",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "section_break_14",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
"fieldtype": "Section Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "quantity_difference",
|
||||
"fieldtype": "Read Only",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Quantity Difference",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
"label": "Quantity Difference"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "column_break_16",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "amount_difference",
|
||||
"fieldtype": "Currency",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Amount Difference",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Company:company:default_currency",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "batch_no",
|
||||
"fieldtype": "Link",
|
||||
"label": "Batch No",
|
||||
"options": "Batch"
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 0,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 1,
|
||||
"max_attachments": 0,
|
||||
"menu_index": 0,
|
||||
"modified": "2017-08-03 00:03:40.412071",
|
||||
"modified": "2019-06-14 17:10:53.188305",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Stock Reconciliation Item",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"quick_entry": 1,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1,
|
||||
"track_seen": 0
|
||||
"track_changes": 1
|
||||
}
|
@ -55,10 +55,12 @@ def get_conditions(filters):
|
||||
#get all details
|
||||
def get_stock_ledger_entries(filters):
|
||||
conditions = get_conditions(filters)
|
||||
return frappe.db.sql("""select item_code, batch_no, warehouse,
|
||||
posting_date, actual_qty
|
||||
return frappe.db.sql("""
|
||||
select item_code, batch_no, warehouse, posting_date, sum(actual_qty) as actual_qty
|
||||
from `tabStock Ledger Entry`
|
||||
where docstatus < 2 and ifnull(batch_no, '') != '' %s order by item_code, warehouse""" %
|
||||
where docstatus < 2 and ifnull(batch_no, '') != '' %s
|
||||
group by voucher_no, batch_no, item_code, warehouse
|
||||
order by item_code, warehouse""" %
|
||||
conditions, as_dict=1)
|
||||
|
||||
def get_item_warehouse_batch_map(filters, float_precision):
|
||||
|
@ -157,9 +157,12 @@ class update_entries_after(object):
|
||||
if sle.serial_no:
|
||||
self.get_serialized_values(sle)
|
||||
self.qty_after_transaction += flt(sle.actual_qty)
|
||||
if sle.voucher_type == "Stock Reconciliation":
|
||||
self.qty_after_transaction = sle.qty_after_transaction
|
||||
|
||||
self.stock_value = flt(self.qty_after_transaction) * flt(self.valuation_rate)
|
||||
else:
|
||||
if sle.voucher_type=="Stock Reconciliation":
|
||||
if sle.voucher_type=="Stock Reconciliation" and not sle.batch_no:
|
||||
# assert
|
||||
self.valuation_rate = sle.valuation_rate
|
||||
self.qty_after_transaction = sle.qty_after_transaction
|
||||
@ -371,7 +374,7 @@ class update_entries_after(object):
|
||||
"""get Stock Ledger Entries after a particular datetime, for reposting"""
|
||||
return get_stock_ledger_entries(self.previous_sle or frappe._dict({
|
||||
"item_code": self.args.get("item_code"), "warehouse": self.args.get("warehouse") }),
|
||||
">", "asc", for_update=True)
|
||||
">", "asc", for_update=True, check_serial_no=False)
|
||||
|
||||
def raise_exceptions(self):
|
||||
deficiency = min(e["diff"] for e in self.exceptions)
|
||||
@ -412,7 +415,8 @@ def get_previous_sle(args, for_update=False):
|
||||
sle = get_stock_ledger_entries(args, "<=", "desc", "limit 1", for_update=for_update)
|
||||
return sle and sle[0] or {}
|
||||
|
||||
def get_stock_ledger_entries(previous_sle, operator=None, order="desc", limit=None, for_update=False, debug=False):
|
||||
def get_stock_ledger_entries(previous_sle, operator=None,
|
||||
order="desc", limit=None, for_update=False, debug=False, check_serial_no=True):
|
||||
"""get stock ledger entries filtered by specific posting datetime conditions"""
|
||||
conditions = " and timestamp(posting_date, posting_time) {0} timestamp(%(posting_date)s, %(posting_time)s)".format(operator)
|
||||
if previous_sle.get("warehouse"):
|
||||
@ -420,6 +424,9 @@ def get_stock_ledger_entries(previous_sle, operator=None, order="desc", limit=No
|
||||
elif previous_sle.get("warehouse_condition"):
|
||||
conditions += " and " + previous_sle.get("warehouse_condition")
|
||||
|
||||
if check_serial_no and previous_sle.get("serial_no"):
|
||||
conditions += " and serial_no like {}".format(frappe.db.escape('%{0}%'.format(previous_sle.get("serial_no"))))
|
||||
|
||||
if not previous_sle.get("posting_date"):
|
||||
previous_sle["posting_date"] = "1900-01-01"
|
||||
if not previous_sle.get("posting_time"):
|
||||
@ -479,6 +486,7 @@ def get_valuation_rate(item_code, warehouse, voucher_type, voucher_no,
|
||||
if not allow_zero_rate and not valuation_rate and raise_error_if_no_rate \
|
||||
and cint(erpnext.is_perpetual_inventory_enabled(company)):
|
||||
frappe.local.message_log = []
|
||||
frappe.throw(_("Valuation rate not found for the Item {0}, which is required to do accounting entries for {1} {2}. If the item is transacting as a zero valuation rate item in the {1}, please mention that in the {1} Item table. Otherwise, please create an incoming stock transaction for the item or mention valuation rate in the Item record, and then try submiting/cancelling this entry").format(item_code, voucher_type, voucher_no))
|
||||
frappe.throw(_("Valuation rate not found for the Item {0}, which is required to do accounting entries for {1} {2}. If the item is transacting as a zero valuation rate item in the {1}, please mention that in the {1} Item table. Otherwise, please create an incoming stock transaction for the item or mention valuation rate in the Item record, and then try submiting / cancelling this entry.")
|
||||
.format(item_code, voucher_type, voucher_no))
|
||||
|
||||
return valuation_rate
|
||||
|
@ -173,7 +173,7 @@ def get_incoming_rate(args, raise_error_if_no_rate=True):
|
||||
in_rate = get_valuation_rate(args.get('item_code'), args.get('warehouse'),
|
||||
args.get('voucher_type'), voucher_no, args.get('allow_zero_valuation'),
|
||||
currency=erpnext.get_company_currency(args.get('company')), company=args.get('company'),
|
||||
raise_error_if_no_rate=True)
|
||||
raise_error_if_no_rate=raise_error_if_no_rate)
|
||||
|
||||
return in_rate
|
||||
|
||||
@ -277,3 +277,7 @@ def update_included_uom_in_report(columns, result, include_uom, conversion_facto
|
||||
new_row.append(None)
|
||||
|
||||
result[row_idx] = new_row
|
||||
|
||||
def get_available_serial_nos(item_code, warehouse):
|
||||
return frappe.get_all("Serial No", filters = {'item_code': item_code,
|
||||
'warehouse': warehouse, 'delivery_document_no': ''}) or []
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user