Merge branch 'develop' into version-12

This commit is contained in:
Sahil Khan 2019-09-10 14:38:39 +05:30
commit d2315e5c5c
50 changed files with 990 additions and 4438 deletions

View File

@ -5,7 +5,7 @@ import frappe
from erpnext.hooks import regional_overrides
from frappe.utils import getdate
__version__ = '12.1.1'
__version__ = '12.1.2'
def get_default_company(user=None):
'''Get default company for user'''

View File

@ -12,11 +12,14 @@ from frappe.utils.nestedset import get_descendants_of
@frappe.whitelist()
@cache_source
def get(chart_name=None, from_date = None, to_date = None):
chart = frappe.get_doc('Dashboard Chart', chart_name)
def get(chart_name = None, chart = None, no_cache = None, from_date = None, to_date = None):
if chart_name:
chart = frappe.get_doc('Dashboard Chart', chart_name)
else:
chart = frappe._dict(frappe.parse_json(chart))
timespan = chart.timespan
timegrain = chart.time_interval
filters = json.loads(chart.filters_json)
filters = frappe.parse_json(chart.filters_json)
account = filters.get("account")
company = filters.get("company")

View File

@ -1,171 +1,74 @@
{
"allow_copy": 0,
"allow_import": 1,
"allow_rename": 1,
"autoname": "field:mode_of_payment",
"beta": 0,
"creation": "2012-12-04 17:49:20",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "Setup",
"editable_grid": 0,
"engine": "InnoDB",
"allow_import": 1,
"allow_rename": 1,
"autoname": "field:mode_of_payment",
"creation": "2012-12-04 17:49:20",
"doctype": "DocType",
"document_type": "Setup",
"engine": "InnoDB",
"field_order": [
"mode_of_payment",
"enabled",
"type",
"accounts"
],
"fields": [
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "mode_of_payment",
"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": "Mode of Payment",
"length": 0,
"no_copy": 0,
"oldfieldname": "mode_of_payment",
"oldfieldtype": "Data",
"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,
"unique": 0
},
"fieldname": "mode_of_payment",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Mode of Payment",
"oldfieldname": "mode_of_payment",
"oldfieldtype": "Data",
"reqd": 1,
"unique": 1
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "type",
"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": "Type",
"length": 0,
"no_copy": 0,
"options": "Cash\nBank\nGeneral",
"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
},
"fieldname": "type",
"fieldtype": "Select",
"in_standard_filter": 1,
"label": "Type",
"options": "Cash\nBank\nGeneral"
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "accounts",
"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": "Accounts",
"length": 0,
"no_copy": 0,
"options": "Mode of Payment Account",
"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
"fieldname": "accounts",
"fieldtype": "Table",
"label": "Accounts",
"options": "Mode of Payment Account"
},
{
"default": "1",
"fieldname": "enabled",
"fieldtype": "Check",
"label": "Enabled"
}
],
"hide_heading": 0,
"hide_toolbar": 0,
"icon": "fa fa-credit-card",
"idx": 1,
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2017-02-17 16:31:34.207683",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Mode of Payment",
"owner": "harshada@webnotestech.com",
],
"icon": "fa fa-credit-card",
"idx": 1,
"modified": "2019-08-14 14:58:42.079115",
"modified_by": "sammish.thundiyil@gmail.com",
"module": "Accounts",
"name": "Mode of Payment",
"owner": "harshada@webnotestech.com",
"permissions": [
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 0,
"email": 1,
"export": 0,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"create": 1,
"email": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "Accounts Manager",
"share": 1,
"write": 1
},
},
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 0,
"delete": 0,
"email": 0,
"export": 0,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 0,
"read": 1,
"report": 1,
"role": "Accounts User",
"set_user_permissions": 0,
"share": 0,
"submit": 0,
"write": 0
"read": 1,
"report": 1,
"role": "Accounts User"
}
],
"quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 1,
"sort_order": "ASC",
"track_changes": 0,
"track_seen": 0
],
"quick_entry": 1,
"show_name_in_global_search": 1,
"sort_field": "modified",
"sort_order": "ASC"
}

View File

@ -158,7 +158,7 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
cur_frm.meta._default_print_format = cur_frm.meta.default_print_format;
cur_frm.meta.default_print_format = cur_frm.pos_print_format;
}
} else if(cur_frm.doc.is_return) {
} else if(cur_frm.doc.is_return && !cur_frm.meta.default_print_format) {
if(cur_frm.return_print_format) {
cur_frm.meta._default_print_format = cur_frm.meta.default_print_format;
cur_frm.meta.default_print_format = cur_frm.return_print_format;

View File

@ -304,8 +304,10 @@ class SalesInvoice(SellingController):
from erpnext.selling.doctype.customer.customer import check_credit_limit
validate_against_credit_limit = False
bypass_credit_limit_check_at_sales_order = cint(frappe.get_cached_value("Customer", self.customer,
"bypass_credit_limit_check_at_sales_order"))
bypass_credit_limit_check_at_sales_order = frappe.db.get_value("Customer Credit Limit",
filters={'parent': self.customer, 'parenttype': 'Customer', 'company': self.company},
fieldname=["bypass_credit_limit_check"])
if bypass_credit_limit_check_at_sales_order:
validate_against_credit_limit = True

View File

@ -292,12 +292,6 @@ class Asset(AccountsController):
if self.status not in ("Submitted", "Partially Depreciated", "Fully Depreciated"):
frappe.throw(_("Asset cannot be cancelled, as it is already {0}").format(self.status))
if self.purchase_invoice:
frappe.throw(_("Please cancel Purchase Invoice {0} first").format(self.purchase_invoice))
if self.purchase_receipt:
frappe.throw(_("Please cancel Purchase Receipt {0} first").format(self.purchase_receipt))
def delete_depreciation_entries(self):
for d in self.get("schedules"):
if d.journal_entry:

View File

@ -337,7 +337,7 @@ class BuyingController(StockController):
if self.doctype in ["Purchase Receipt", "Purchase Invoice"]:
rm.consumed_qty = required_qty
rm.description = bom_item.description
if item.batch_no and not rm.batch_no:
if item.batch_no and frappe.db.get_value("Item", rm.rm_item_code, "has_batch_no") and not rm.batch_no:
rm.batch_no = item.batch_no
# get raw materials rate

View File

@ -71,7 +71,7 @@ def remove_empty(d):
Helper function that removes all keys from a dictionary (d),
that have an empty value.
"""
for key in d.keys():
for key in list(d):
if not d[key]:
del d[key]
return d

View File

@ -7,6 +7,7 @@
"doctype": "DocType",
"document_type": "Setup",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"basic_information",
"employee",
@ -54,6 +55,7 @@
"column_break_44",
"holiday_list",
"default_shift",
"leave_approver",
"salary_information",
"salary_mode",
"bank_name",
@ -767,12 +769,18 @@
"fieldtype": "Link",
"label": "Default Shift",
"options": "Shift Type"
},
{
"fieldname": "leave_approver",
"fieldtype": "Link",
"label": "Leave Approver",
"options": "User"
}
],
"icon": "fa fa-user",
"idx": 24,
"image_field": "image",
"modified": "2019-06-01 16:05:55.132180",
"modified": "2019-09-06 15:54:36.735147",
"modified_by": "Administrator",
"module": "HR",
"name": "Employee",

View File

@ -34,10 +34,11 @@ class LeaveAllocation(Document):
if max_leaves_allowed > 0:
leave_allocated = 0
if leave_period:
leave_allocated = get_leave_allocation_for_period(self.employee, self.leave_type, leave_period[0].from_date, leave_period[0].to_date)
leave_allocated = get_leave_allocation_for_period(self.employee, self.leave_type,
leave_period[0].from_date, leave_period[0].to_date)
leave_allocated += self.new_leaves_allocated
if leave_allocated > max_leaves_allowed:
frappe.throw(_("Total allocated leaves are more days than maximum allocation of {0} leave type for employee {1} in the period")\
frappe.throw(_("Total allocated leaves are more days than maximum allocation of {0} leave type for employee {1} in the period")
.format(self.leave_type, self.employee))
def on_submit(self):
@ -96,27 +97,31 @@ class LeaveAllocation(Document):
self.total_leaves_allocated = flt(self.unused_leaves) + flt(self.new_leaves_allocated)
self.limit_carry_forward_based_on_max_allowed_leaves()
if self.carry_forward:
self.maintain_carry_forwarded_leaves()
self.set_carry_forwarded_leaves_in_previous_allocation()
if not self.total_leaves_allocated and not frappe.db.get_value("Leave Type", self.leave_type, "is_earned_leave") and not frappe.db.get_value("Leave Type", self.leave_type, "is_compensatory"):
frappe.throw(_("Total leaves allocated is mandatory for Leave Type {0}").format(self.leave_type))
if not self.total_leaves_allocated \
and not frappe.db.get_value("Leave Type", self.leave_type, "is_earned_leave") \
and not frappe.db.get_value("Leave Type", self.leave_type, "is_compensatory"):
frappe.throw(_("Total leaves allocated is mandatory for Leave Type {0}")
.format(self.leave_type))
def maintain_carry_forwarded_leaves(self):
''' Reduce the carry forwarded leaves to be within the maximum allowed leaves '''
def limit_carry_forward_based_on_max_allowed_leaves(self):
max_leaves_allowed = frappe.db.get_value("Leave Type", self.leave_type, "max_leaves_allowed")
if self.new_leaves_allocated <= max_leaves_allowed <= self.total_leaves_allocated:
self.unused_leaves = max_leaves_allowed - flt(self.new_leaves_allocated)
if max_leaves_allowed and self.total_leaves_allocated > flt(max_leaves_allowed):
self.total_leaves_allocated = flt(max_leaves_allowed)
self.unused_leaves = max_leaves_allowed - flt(self.new_leaves_allocated)
def set_carry_forwarded_leaves_in_previous_allocation(self, on_cancel=False):
''' Set carry forwarded leaves in previous allocation '''
previous_allocation = get_previous_allocation(self.from_date, self.leave_type, self.employee)
if on_cancel:
self.unused_leaves = 0.0
frappe.db.set_value("Leave Allocation", previous_allocation.name, 'carry_forwarded_leaves_count', self.unused_leaves)
if previous_allocation:
frappe.db.set_value("Leave Allocation", previous_allocation.name,
'carry_forwarded_leaves_count', self.unused_leaves)
def validate_total_leaves_allocated(self):
# Adding a day to include To Date in the difference
@ -186,7 +191,13 @@ def get_carry_forwarded_leaves(employee, leave_type, date, carry_forward=None):
previous_allocation = get_previous_allocation(date, leave_type, employee)
if carry_forward and previous_allocation:
validate_carry_forward(leave_type)
unused_leaves = get_unused_leaves(employee, leave_type, previous_allocation.from_date, previous_allocation.to_date)
unused_leaves = get_unused_leaves(employee, leave_type,
previous_allocation.from_date, previous_allocation.to_date)
if unused_leaves:
max_carry_forwarded_leaves = frappe.db.get_value("Leave Type",
leave_type, "maximum_carry_forwarded_leaves")
if max_carry_forwarded_leaves and unused_leaves > flt(max_carry_forwarded_leaves):
unused_leaves = flt(max_carry_forwarded_leaves)
return unused_leaves

View File

@ -73,9 +73,11 @@ class TestLeaveAllocation(unittest.TestCase):
frappe.db.sql("delete from `tabLeave Allocation`")
frappe.db.sql("delete from `tabLeave Ledger Entry`")
leave_type = create_leave_type(leave_type_name="_Test_CF_leave", is_carry_forward=1)
leave_type.submit()
leave_type.maximum_carry_forwarded_leaves = 10
leave_type.max_leaves_allowed = 30
leave_type.save()
# initial leave allocation
# initial leave allocation = 15
leave_allocation = create_leave_allocation(
leave_type="_Test_CF_leave",
from_date=add_months(nowdate(), -12),
@ -83,13 +85,26 @@ class TestLeaveAllocation(unittest.TestCase):
carry_forward=0)
leave_allocation.submit()
# leave allocation with carry forward from previous allocation
# carry forwarded leaves considering maximum_carry_forwarded_leaves
# new_leaves = 15, carry_forwarded = 10
leave_allocation_1 = create_leave_allocation(
leave_type="_Test_CF_leave",
carry_forward=1)
leave_allocation_1.submit()
self.assertEquals(leave_allocation.total_leaves_allocated, leave_allocation_1.unused_leaves)
self.assertEquals(leave_allocation_1.unused_leaves, 10)
leave_allocation_1.cancel()
# carry forwarded leaves considering max_leave_allowed
# max_leave_allowed = 30, new_leaves = 25, carry_forwarded = 5
leave_allocation_2 = create_leave_allocation(
leave_type="_Test_CF_leave",
carry_forward=1,
new_leaves_allocated=25)
leave_allocation_2.submit()
self.assertEquals(leave_allocation_2.unused_leaves, 5)
def test_carry_forward_leaves_expiry(self):
frappe.db.sql("delete from `tabLeave Allocation`")
@ -98,7 +113,7 @@ class TestLeaveAllocation(unittest.TestCase):
leave_type_name="_Test_CF_leave_expiry",
is_carry_forward=1,
expire_carry_forwarded_leaves_after_days=90)
leave_type.submit()
leave_type.save()
# initial leave allocation
leave_allocation = create_leave_allocation(
@ -156,7 +171,7 @@ def create_leave_allocation(**args):
"employee_name": args.employee_name or employee.employee_name,
"leave_type": args.leave_type or "_Test Leave Type",
"from_date": args.from_date or nowdate(),
"new_leaves_allocated": args.new_leaves_created or 15,
"new_leaves_allocated": args.new_leaves_allocated or 15,
"carry_forward": args.carry_forward or 0,
"to_date": args.to_date or add_months(nowdate(), 12)
})

View File

@ -745,10 +745,12 @@ def get_approved_leaves_for_period(employee, leave_type, from_date, to_date):
return leave_days
@frappe.whitelist()
def get_leave_approver(employee, department=None):
if not department:
department = frappe.db.get_value('Employee', employee, 'department')
def get_leave_approver(employee):
leave_approver, department = frappe.db.get_value("Employee",
employee, ["leave_approver", "department"])
if department:
return frappe.db.get_value('Department Approver', {'parent': department,
'parentfield': 'leave_approvers', 'idx': 1}, 'approver')
if not leave_approver and department:
leave_approver = frappe.db.get_value('Department Approver', {'parent': department,
'parentfield': 'leave_approvers', 'idx': 1}, 'approver')
return leave_approver

View File

@ -8,7 +8,6 @@ from frappe import _
from frappe.utils import getdate, cstr, add_days, date_diff, getdate, ceil
from frappe.model.document import Document
from erpnext.hr.utils import validate_overlap, get_employee_leave_policy
from erpnext.hr.doctype.leave_allocation.leave_allocation import get_carry_forwarded_leaves
from frappe.utils.background_jobs import enqueue
from six import iteritems

View File

@ -1,801 +1,214 @@
{
"allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 1,
"allow_rename": 1,
"autoname": "field:leave_type_name",
"beta": 0,
"creation": "2013-02-21 09:55:58",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "Setup",
"editable_grid": 0,
"engine": "InnoDB",
"field_order": [
"leave_type_name",
"max_leaves_allowed",
"applicable_after",
"max_continuous_days_allowed",
"column_break_3",
"is_carry_forward",
"is_lwp",
"is_optional_leave",
"allow_negative",
"include_holiday",
"is_compensatory",
"carry_forward_section",
"maximum_carry_forwarded_leaves",
"expire_carry_forwarded_leaves_after_days",
"encashment",
"allow_encashment",
"encashment_threshold_days",
"earning_component",
"earned_leave",
"is_earned_leave",
"earned_leave_frequency",
"rounding"
],
"fields": [
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "leave_type_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": "Leave Type Name",
"length": 0,
"no_copy": 0,
"oldfieldname": "leave_type_name",
"oldfieldtype": "Data",
"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": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "",
"fetch_if_empty": 0,
"fieldname": "max_leaves_allowed",
"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": "Max Leaves Allowed",
"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 Leaves Allowed"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "applicable_after",
"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": "Applicable After (Working Days)",
"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": "Applicable After (Working Days)"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "max_continuous_days_allowed",
"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": "Maximum Continuous Days Applicable",
"length": 0,
"no_copy": 0,
"oldfieldname": "max_days_allowed",
"oldfieldtype": "Data",
"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": "Data"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 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,
"fetch_if_empty": 0,
"default": "0",
"fieldname": "is_carry_forward",
"fieldtype": "Check",
"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": "Is Carry Forward",
"length": 0,
"no_copy": 0,
"oldfieldname": "is_carry_forward",
"oldfieldtype": "Check",
"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": "Check"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "",
"fetch_if_empty": 0,
"default": "0",
"fieldname": "is_lwp",
"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": "Is Leave Without Pay",
"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
"label": "Is Leave Without Pay"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"default": "0",
"fieldname": "is_optional_leave",
"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": "Is Optional Leave",
"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": "Is Optional Leave"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"default": "0",
"fieldname": "allow_negative",
"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": "Allow Negative Balance",
"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
"label": "Allow Negative Balance"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"default": "0",
"fieldname": "include_holiday",
"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": "Include holidays within leaves as leaves",
"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
"label": "Include holidays within leaves as leaves"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"default": "0",
"fieldname": "is_compensatory",
"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": "Is Compensatory",
"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": "Is Compensatory"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
"columns": 0,
"depends_on": "eval: doc.is_carry_forward == 1",
"fetch_if_empty": 0,
"fieldname": "carry_forward_section",
"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": "Carry Forward",
"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": "Carry Forward"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "",
"description": "Calculated in days",
"fetch_if_empty": 0,
"fieldname": "expire_carry_forwarded_leaves_after_days",
"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": "Expire Carry Forwarded Leaves (Days)",
"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": "Expire Carry Forwarded Leaves (Days)"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "encashment",
"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": "Encashment",
"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": "Encashment"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"default": "0",
"fieldname": "allow_encashment",
"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": "Allow Encashment",
"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": "Allow Encashment"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "allow_encashment",
"fetch_if_empty": 0,
"fieldname": "encashment_threshold_days",
"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": "Encashment Threshold Days",
"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": "Encashment Threshold Days"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "allow_encashment",
"fetch_if_empty": 0,
"fieldname": "earning_component",
"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": "Earning Component",
"length": 0,
"no_copy": 0,
"options": "Salary Component",
"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": "Salary Component"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "earned_leave",
"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": "Earned Leave",
"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": "Earned Leave"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"default": "0",
"fieldname": "is_earned_leave",
"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": "Is Earned Leave",
"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": "Is Earned Leave"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "is_earned_leave",
"fetch_if_empty": 0,
"fieldname": "earned_leave_frequency",
"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": "Earned Leave Frequency",
"length": 0,
"no_copy": 0,
"options": "Monthly\nQuarterly\nHalf-Yearly\nYearly",
"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": "Monthly\nQuarterly\nHalf-Yearly\nYearly"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "0.5",
"depends_on": "is_earned_leave",
"fetch_if_empty": 0,
"fieldname": "rounding",
"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": "Rounding",
"length": 0,
"no_copy": 0,
"options": "0.5\n1.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
"options": "0.5\n1.0"
},
{
"depends_on": "is_carry_forward",
"fieldname": "maximum_carry_forwarded_leaves",
"fieldtype": "Float",
"label": "Maximum Carry Forwarded Leaves"
}
],
"has_web_view": 0,
"hide_toolbar": 0,
"icon": "fa fa-flag",
"idx": 1,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2019-08-02 15:38:39.334283",
"modified": "2019-09-06 18:48:48.946074",
"modified_by": "Administrator",
"module": "HR",
"name": "Leave Type",
"owner": "Administrator",
"permissions": [
{
"amend": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 0,
"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": 0,
"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
},
{
"amend": 0,
"cancel": 0,
"create": 0,
"delete": 0,
"email": 0,
"export": 0,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 0,
"read": 1,
"report": 0,
"role": "Employee",
"set_user_permissions": 0,
"share": 0,
"submit": 0,
"write": 0
"role": "Employee"
}
],
"quick_entry": 0,
"read_only": 0,
"show_name_in_global_search": 0,
"track_changes": 0,
"track_seen": 0,
"track_views": 0
"sort_field": "modified",
"sort_order": "DESC"
}

View File

@ -0,0 +1,36 @@
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
/* eslint-disable */
frappe.query_reports['Employee Leave Balance Summary'] = {
filters: [
{
fieldname:'company',
label: __('Company'),
fieldtype: 'Link',
options: 'Company',
reqd: 1,
default: frappe.defaults.get_user_default('Company')
},
{
fieldname:'employee',
label: __('Employee'),
fieldtype: 'Link',
options: 'Employee',
},
{
fieldname:'from_date',
label: __('From Date'),
fieldtype: 'Date',
reqd: 1,
default: frappe.defaults.get_default('year_start_date')
},
{
fieldname:'to_date',
label: __('To Date'),
fieldtype: 'Date',
reqd: 1,
default: frappe.defaults.get_default('year_end_date')
}
]
};

View File

@ -0,0 +1,34 @@
{
"add_total_row": 0,
"creation": "2019-09-05 11:18:06.209397",
"disable_prepared_report": 0,
"disabled": 0,
"docstatus": 0,
"doctype": "Report",
"idx": 0,
"is_standard": "Yes",
"letter_head": "sapcon-old",
"modified": "2019-09-05 11:18:06.209397",
"modified_by": "Administrator",
"module": "HR",
"name": "Employee Leave Balance Summary",
"owner": "Administrator",
"prepared_report": 0,
"ref_doctype": "Employee",
"report_name": "Employee Leave Balance Summary",
"report_type": "Script Report",
"roles": [
{
"role": "Employee"
},
{
"role": "HR Manager"
},
{
"role": "HR User"
},
{
"role": "Leave Approver"
}
]
}

View File

@ -0,0 +1,96 @@
# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
from frappe.utils import flt
from frappe import _
from erpnext.hr.doctype.leave_application.leave_application import get_leaves_for_period
from erpnext.hr.report.employee_leave_balance.employee_leave_balance import get_total_allocated_leaves
def execute(filters=None):
if filters.to_date <= filters.from_date:
frappe.throw(_('From date can not be greater than than To date'))
columns = get_columns()
data = get_data(filters)
return columns, data
def get_columns():
columns = [{
'label': _('Leave Type'),
'fieldtype': 'Link',
'fieldname': 'leave_type',
'width': 300,
'options': 'Leave Type'
}, {
'label': _('Employee'),
'fieldtype': 'Link',
'fieldname': 'employee',
'width': 100,
'options': 'Employee'
}, {
'label': _('Employee Name'),
'fieldtype': 'Data',
'fieldname': 'employee_name',
'width': 100,
}, {
'label': _('Opening Balance'),
'fieldtype': 'float',
'fieldname': 'opening_balance',
'width': 160,
}, {
'label': _('Leaves Taken'),
'fieldtype': 'float',
'fieldname': 'leaves_taken',
'width': 160,
}, {
'label': _('Closing Balance'),
'fieldtype': 'float',
'fieldname': 'closing_balance',
'width': 160,
}]
return columns
def get_data(filters):
leave_types = frappe.db.sql_list("SELECT `name` FROM `tabLeave Type` ORDER BY `name` ASC")
conditions = {
'status': 'Active',
}
if filters.get('employee'):
conditions['name'] = filters.get('employee')
active_employees = frappe.get_all('Employee',
filters=conditions,
fields=['name', 'employee_name', 'department', 'user_id'])
data = []
for leave_type in leave_types:
data.append({
'leave_type': leave_type
})
for employee in active_employees:
row = frappe._dict({
'employee': employee.name,
'employee_name': employee.employee_name
})
leaves_taken = get_leaves_for_period(employee.name, leave_type,
filters.from_date, filters.to_date) * -1
opening = get_total_allocated_leaves(employee.name, leave_type, filters.from_date, filters.to_date)
closing = flt(opening) - flt(leaves_taken)
row.opening_balance = opening
row.leaves_taken = leaves_taken
row.closing_balance = closing
row.indent = 1
data.append(row)
return data

View File

@ -1,648 +0,0 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
import frappe
import json
from six import text_type
from frappe import _
from frappe.utils import flt, get_datetime, getdate, date_diff, cint, nowdate
from frappe.model.document import Document
from erpnext.manufacturing.doctype.bom.bom import validate_bom_no, get_bom_items_as_dict
from dateutil.relativedelta import relativedelta
from erpnext.stock.doctype.item.item import validate_end_of_life
from erpnext.manufacturing.doctype.workstation.workstation import WorkstationHolidayError
from erpnext.projects.doctype.timesheet.timesheet import OverlapError
from erpnext.stock.doctype.stock_entry.stock_entry import get_additional_costs
from erpnext.manufacturing.doctype.manufacturing_settings.manufacturing_settings import get_mins_between_operations
from erpnext.stock.stock_balance import get_planned_qty, update_bin_qty
from frappe.utils.csvutils import getlink
from erpnext.stock.utils import get_bin, validate_warehouse_company, get_latest_stock_qty
from erpnext.utilities.transaction_base import validate_uom_is_integer
class OverProductionError(frappe.ValidationError): pass
class StockOverProductionError(frappe.ValidationError): pass
class OperationTooLongError(frappe.ValidationError): pass
class ItemHasVariantError(frappe.ValidationError): pass
form_grid_templates = {
"operations": "templates/form_grid/production_order_grid.html"
}
class ProductionOrder(Document):
def validate(self):
self.validate_production_item()
if self.bom_no:
validate_bom_no(self.production_item, self.bom_no)
self.validate_sales_order()
self.set_default_warehouse()
self.validate_warehouse_belongs_to_company()
self.calculate_operating_cost()
self.validate_qty()
self.validate_operation_time()
self.status = self.get_status()
validate_uom_is_integer(self, "stock_uom", ["qty", "produced_qty"])
self.set_required_items(reset_only_qty = len(self.get("required_items")))
def validate_sales_order(self):
if self.sales_order:
so = frappe.db.sql("""
select so.name, so_item.delivery_date, so.project
from `tabSales Order` so
inner join `tabSales Order Item` so_item on so_item.parent = so.name
left join `tabProduct Bundle Item` pk_item on so_item.item_code = pk_item.parent
where so.name=%s and so.docstatus = 1 and (
so_item.item_code=%s or
pk_item.item_code=%s )
""", (self.sales_order, self.production_item, self.production_item), as_dict=1)
if not so:
so = frappe.db.sql("""
select
so.name, so_item.delivery_date, so.project
from
`tabSales Order` so, `tabSales Order Item` so_item, `tabPacked Item` packed_item
where so.name=%s
and so.name=so_item.parent
and so.name=packed_item.parent
and so_item.item_code = packed_item.parent_item
and so.docstatus = 1 and packed_item.item_code=%s
""", (self.sales_order, self.production_item), as_dict=1)
if len(so):
if not self.expected_delivery_date:
self.expected_delivery_date = so[0].delivery_date
if so[0].project:
self.project = so[0].project
if not self.material_request:
self.validate_production_order_against_so()
else:
frappe.throw(_("Sales Order {0} is not valid").format(self.sales_order))
def set_default_warehouse(self):
if not self.wip_warehouse:
self.wip_warehouse = frappe.db.get_single_value("Manufacturing Settings", "default_wip_warehouse")
if not self.fg_warehouse:
self.fg_warehouse = frappe.db.get_single_value("Manufacturing Settings", "default_fg_warehouse")
def validate_warehouse_belongs_to_company(self):
warehouses = [self.fg_warehouse, self.wip_warehouse]
for d in self.get("required_items"):
if d.source_warehouse not in warehouses:
warehouses.append(d.source_warehouse)
for wh in warehouses:
validate_warehouse_company(wh, self.company)
def calculate_operating_cost(self):
self.planned_operating_cost, self.actual_operating_cost = 0.0, 0.0
for d in self.get("operations"):
d.planned_operating_cost = flt(d.hour_rate) * (flt(d.time_in_mins) / 60.0)
d.actual_operating_cost = flt(d.hour_rate) * (flt(d.actual_operation_time) / 60.0)
self.planned_operating_cost += flt(d.planned_operating_cost)
self.actual_operating_cost += flt(d.actual_operating_cost)
variable_cost = self.actual_operating_cost if self.actual_operating_cost \
else self.planned_operating_cost
self.total_operating_cost = flt(self.additional_operating_cost) + flt(variable_cost)
def validate_production_order_against_so(self):
# already ordered qty
ordered_qty_against_so = frappe.db.sql("""select sum(qty) from `tabProduction Order`
where production_item = %s and sales_order = %s and docstatus < 2 and name != %s""",
(self.production_item, self.sales_order, self.name))[0][0]
total_qty = flt(ordered_qty_against_so) + flt(self.qty)
# get qty from Sales Order Item table
so_item_qty = frappe.db.sql("""select sum(stock_qty) from `tabSales Order Item`
where parent = %s and item_code = %s""",
(self.sales_order, self.production_item))[0][0]
# get qty from Packing Item table
dnpi_qty = frappe.db.sql("""select sum(qty) from `tabPacked Item`
where parent = %s and parenttype = 'Sales Order' and item_code = %s""",
(self.sales_order, self.production_item))[0][0]
# total qty in SO
so_qty = flt(so_item_qty) + flt(dnpi_qty)
allowance_percentage = flt(frappe.db.get_single_value("Manufacturing Settings",
"over_production_allowance_percentage"))
if total_qty > so_qty + (allowance_percentage/100 * so_qty):
frappe.throw(_("Cannot produce more Item {0} than Sales Order quantity {1}")
.format(self.production_item, so_qty), OverProductionError)
def update_status(self, status=None):
'''Update status of production order if unknown'''
if status != "Stopped":
status = self.get_status(status)
if status != self.status:
self.db_set("status", status)
self.update_required_items()
return status
def get_status(self, status=None):
'''Return the status based on stock entries against this production order'''
if not status:
status = self.status
if self.docstatus==0:
status = 'Draft'
elif self.docstatus==1:
if status != 'Stopped':
stock_entries = frappe._dict(frappe.db.sql("""select purpose, sum(fg_completed_qty)
from `tabStock Entry` where production_order=%s and docstatus=1
group by purpose""", self.name))
status = "Not Started"
if stock_entries:
status = "In Process"
produced_qty = stock_entries.get("Manufacture")
if flt(produced_qty) == flt(self.qty):
status = "Completed"
else:
status = 'Cancelled'
return status
def update_production_order_qty(self):
"""Update **Manufactured Qty** and **Material Transferred for Qty** in Production Order
based on Stock Entry"""
for purpose, fieldname in (("Manufacture", "produced_qty"),
("Material Transfer for Manufacture", "material_transferred_for_manufacturing")):
qty = flt(frappe.db.sql("""select sum(fg_completed_qty)
from `tabStock Entry` where production_order=%s and docstatus=1
and purpose=%s""", (self.name, purpose))[0][0])
if qty > self.qty:
frappe.throw(_("{0} ({1}) cannot be greater than planned quanitity ({2}) in Production Order {3}").format(\
self.meta.get_label(fieldname), qty, self.qty, self.name), StockOverProductionError)
self.db_set(fieldname, qty)
def before_submit(self):
self.make_time_logs()
def on_submit(self):
if not self.wip_warehouse:
frappe.throw(_("Work-in-Progress Warehouse is required before Submit"))
if not self.fg_warehouse:
frappe.throw(_("For Warehouse is required before Submit"))
self.update_reserved_qty_for_production()
self.update_completed_qty_in_material_request()
self.update_planned_qty()
def on_cancel(self):
self.validate_cancel()
frappe.db.set(self,'status', 'Cancelled')
self.delete_timesheet()
self.update_completed_qty_in_material_request()
self.update_planned_qty()
self.update_reserved_qty_for_production()
def validate_cancel(self):
if self.status == "Stopped":
frappe.throw(_("Stopped Production Order cannot be cancelled, Unstop it first to cancel"))
# Check whether any stock entry exists against this Production Order
stock_entry = frappe.db.sql("""select name from `tabStock Entry`
where production_order = %s and docstatus = 1""", self.name)
if stock_entry:
frappe.throw(_("Cannot cancel because submitted Stock Entry {0} exists").format(stock_entry[0][0]))
def update_planned_qty(self):
update_bin_qty(self.production_item, self.fg_warehouse, {
"planned_qty": get_planned_qty(self.production_item, self.fg_warehouse)
})
if self.material_request:
mr_obj = frappe.get_doc("Material Request", self.material_request)
mr_obj.update_requested_qty([self.material_request_item])
def update_completed_qty_in_material_request(self):
if self.material_request:
frappe.get_doc("Material Request", self.material_request).update_completed_qty([self.material_request_item])
def set_production_order_operations(self):
"""Fetch operations from BOM and set in 'Production Order'"""
self.set('operations', [])
if not self.bom_no \
or cint(frappe.db.get_single_value("Manufacturing Settings", "disable_capacity_planning")):
return
if self.use_multi_level_bom:
bom_list = frappe.get_doc("BOM", self.bom_no).traverse_tree()
else:
bom_list = [self.bom_no]
operations = frappe.db.sql("""
select
operation, description, workstation, idx,
base_hour_rate as hour_rate, time_in_mins,
"Pending" as status, parent as bom
from
`tabBOM Operation`
where
parent in (%s) order by idx
""" % ", ".join(["%s"]*len(bom_list)), tuple(bom_list), as_dict=1)
self.set('operations', operations)
self.calculate_time()
def calculate_time(self):
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)
self.calculate_operating_cost()
def get_holidays(self, workstation):
holiday_list = frappe.db.get_value("Workstation", workstation, "holiday_list")
holidays = {}
if holiday_list not in holidays:
holiday_list_days = [getdate(d[0]) for d in frappe.get_all("Holiday", fields=["holiday_date"],
filters={"parent": holiday_list}, order_by="holiday_date", limit_page_length=0, as_list=1)]
holidays[holiday_list] = holiday_list_days
return holidays[holiday_list]
def make_time_logs(self, open_new=False):
"""Capacity Planning. Plan time logs based on earliest availablity of workstation after
Planned Start Date. Time logs will be created and remain in Draft mode and must be submitted
before manufacturing entry can be made."""
if not self.operations:
return
timesheets = []
plan_days = frappe.db.get_single_value("Manufacturing Settings", "capacity_planning_for_days") or 30
timesheet = make_timesheet(self.name, self.company)
timesheet.set('time_logs', [])
for i, d in enumerate(self.operations):
if d.status != 'Completed':
self.set_start_end_time_for_workstation(d, i)
args = self.get_operations_data(d)
add_timesheet_detail(timesheet, args)
original_start_time = d.planned_start_time
# validate operating hours if workstation [not mandatory] is specified
try:
timesheet.validate_time_logs()
except OverlapError:
if frappe.message_log: frappe.message_log.pop()
timesheet.schedule_for_production_order(d.idx)
except WorkstationHolidayError:
if frappe.message_log: frappe.message_log.pop()
timesheet.schedule_for_production_order(d.idx)
from_time, to_time = self.get_start_end_time(timesheet, d.name)
if date_diff(from_time, original_start_time) > cint(plan_days):
frappe.throw(_("Unable to find Time Slot in the next {0} days for Operation {1}").format(plan_days, d.operation))
break
d.planned_start_time = from_time
d.planned_end_time = to_time
d.db_update()
if timesheet and open_new:
return timesheet
if timesheet and timesheet.get("time_logs"):
timesheet.save()
timesheets.append(getlink("Timesheet", timesheet.name))
self.planned_end_date = self.operations[-1].planned_end_time
if timesheets:
frappe.local.message_log = []
frappe.msgprint(_("Timesheet created:") + "\n" + "\n".join(timesheets))
def get_operations_data(self, data):
return {
'from_time': get_datetime(data.planned_start_time),
'hours': data.time_in_mins / 60.0,
'to_time': get_datetime(data.planned_end_time),
'project': self.project,
'operation': data.operation,
'operation_id': data.name,
'workstation': data.workstation,
'completed_qty': flt(self.qty) - flt(data.completed_qty)
}
def set_start_end_time_for_workstation(self, data, index):
"""Set start and end time for given operation. If first operation, set start as
`planned_start_date`, else add time diff to end time of earlier operation."""
if index == 0:
data.planned_start_time = self.planned_start_date
else:
data.planned_start_time = get_datetime(self.operations[index-1].planned_end_time)\
+ get_mins_between_operations()
data.planned_end_time = get_datetime(data.planned_start_time) + relativedelta(minutes = data.time_in_mins)
if data.planned_start_time == data.planned_end_time:
frappe.throw(_("Capacity Planning Error"))
def get_start_end_time(self, timesheet, operation_id):
for data in timesheet.time_logs:
if data.operation_id == operation_id:
return data.from_time, data.to_time
def check_operation_fits_in_working_hours(self, d):
"""Raises expection if operation is longer than working hours in the given workstation."""
from erpnext.manufacturing.doctype.workstation.workstation import check_if_within_operating_hours
check_if_within_operating_hours(d.workstation, d.operation, d.planned_start_time, d.planned_end_time)
def update_operation_status(self):
for d in self.get("operations"):
if not d.completed_qty:
d.status = "Pending"
elif flt(d.completed_qty) < flt(self.qty):
d.status = "Work in Progress"
elif flt(d.completed_qty) == flt(self.qty):
d.status = "Completed"
else:
frappe.throw(_("Completed Qty can not be greater than 'Qty to Manufacture'"))
def set_actual_dates(self):
self.actual_start_date = None
self.actual_end_date = None
if self.get("operations"):
actual_start_dates = [d.actual_start_time for d in self.get("operations") if d.actual_start_time]
if actual_start_dates:
self.actual_start_date = min(actual_start_dates)
actual_end_dates = [d.actual_end_time for d in self.get("operations") if d.actual_end_time]
if actual_end_dates:
self.actual_end_date = max(actual_end_dates)
def delete_timesheet(self):
for timesheet in frappe.get_all("Timesheet", ["name"], {"production_order": self.name}):
frappe.delete_doc("Timesheet", timesheet.name)
def validate_production_item(self):
if frappe.db.get_value("Item", self.production_item, "has_variants"):
frappe.throw(_("Production Order cannot be raised against a Item Template"), ItemHasVariantError)
if self.production_item:
validate_end_of_life(self.production_item)
def validate_qty(self):
if not self.qty > 0:
frappe.throw(_("Quantity to Manufacture must be greater than 0."))
def validate_operation_time(self):
for d in self.operations:
if not d.time_in_mins > 0:
frappe.throw(_("Operation Time must be greater than 0 for Operation {0}".format(d.operation)))
def update_required_items(self):
'''
update bin reserved_qty_for_production
called from Stock Entry for production, after submit, cancel
'''
if self.docstatus==1:
# calculate transferred qty based on submitted stock entries
self.update_transaferred_qty_for_required_items()
# update in bin
self.update_reserved_qty_for_production()
def update_reserved_qty_for_production(self, items=None):
'''update reserved_qty_for_production in bins'''
for d in self.required_items:
if d.source_warehouse:
stock_bin = get_bin(d.item_code, d.source_warehouse)
stock_bin.update_reserved_qty_for_production()
def get_items_and_operations_from_bom(self):
self.set_required_items()
self.set_production_order_operations()
return check_if_scrap_warehouse_mandatory(self.bom_no)
def set_available_qty(self):
for d in self.get("required_items"):
if d.source_warehouse:
d.available_qty_at_source_warehouse = get_latest_stock_qty(d.item_code, d.source_warehouse)
if self.wip_warehouse:
d.available_qty_at_wip_warehouse = get_latest_stock_qty(d.item_code, self.wip_warehouse)
def set_required_items(self, reset_only_qty=False):
'''set required_items for production to keep track of reserved qty'''
if not reset_only_qty:
self.required_items = []
if self.bom_no and self.qty:
item_dict = get_bom_items_as_dict(self.bom_no, self.company, qty=self.qty,
fetch_exploded = self.use_multi_level_bom)
if reset_only_qty:
for d in self.get("required_items"):
if item_dict.get(d.item_code):
d.required_qty = item_dict.get(d.item_code).get("qty")
else:
for item in sorted(item_dict.values(), key=lambda d: d['idx']):
self.append('required_items', {
'item_code': item.item_code,
'item_name': item.item_name,
'description': item.description,
'required_qty': item.qty,
'source_warehouse': item.source_warehouse or item.default_warehouse
})
self.set_available_qty()
def update_transaferred_qty_for_required_items(self):
'''update transferred qty from submitted stock entries for that item against
the production order'''
for d in self.required_items:
transferred_qty = frappe.db.sql('''select sum(qty)
from `tabStock Entry` entry, `tabStock Entry Detail` detail
where
entry.production_order = %s
and entry.purpose = "Material Transfer for Manufacture"
and entry.docstatus = 1
and detail.parent = entry.name
and detail.item_code = %s''', (self.name, d.item_code))[0][0]
d.db_set('transferred_qty', flt(transferred_qty), update_modified = False)
@frappe.whitelist()
def get_item_details(item, project = None):
res = frappe.db.sql("""
select stock_uom, description
from `tabItem`
where disabled=0
and (end_of_life is null or end_of_life='0000-00-00' or end_of_life > %s)
and name=%s
""", (nowdate(), item), as_dict=1)
if not res:
return {}
res = res[0]
filters = {"item": item, "is_default": 1}
if project:
filters = {"item": item, "project": project}
res["bom_no"] = frappe.db.get_value("BOM", filters = filters)
if not res["bom_no"]:
variant_of= frappe.db.get_value("Item", item, "variant_of")
if variant_of:
res["bom_no"] = frappe.db.get_value("BOM", filters={"item": variant_of, "is_default": 1})
if not res["bom_no"]:
if project:
res = get_item_details(item)
frappe.msgprint(_("Default BOM not found for Item {0} and Project {1}").format(item, project), alert=1)
else:
frappe.throw(_("Default BOM for {0} not found").format(item))
res['project'] = project or frappe.db.get_value('BOM', res['bom_no'], 'project')
res.update(check_if_scrap_warehouse_mandatory(res["bom_no"]))
return res
@frappe.whitelist()
def check_if_scrap_warehouse_mandatory(bom_no):
res = {"set_scrap_wh_mandatory": False }
if bom_no:
bom = frappe.get_doc("BOM", bom_no)
if len(bom.scrap_items) > 0:
res["set_scrap_wh_mandatory"] = True
return res
@frappe.whitelist()
def set_production_order_ops(name):
po = frappe.get_doc('Production Order', name)
po.set_production_order_operations()
po.save()
@frappe.whitelist()
def make_stock_entry(production_order_id, purpose, qty=None):
production_order = frappe.get_doc("Production Order", production_order_id)
if not frappe.db.get_value("Warehouse", production_order.wip_warehouse, "is_group") \
and not production_order.skip_transfer:
wip_warehouse = production_order.wip_warehouse
else:
wip_warehouse = None
stock_entry = frappe.new_doc("Stock Entry")
stock_entry.purpose = purpose
stock_entry.production_order = production_order_id
stock_entry.company = production_order.company
stock_entry.from_bom = 1
stock_entry.bom_no = production_order.bom_no
stock_entry.use_multi_level_bom = production_order.use_multi_level_bom
stock_entry.fg_completed_qty = qty or (flt(production_order.qty) - flt(production_order.produced_qty))
stock_entry.set_stock_entry_type()
if purpose=="Material Transfer for Manufacture":
stock_entry.to_warehouse = wip_warehouse
stock_entry.project = production_order.project
else:
stock_entry.from_warehouse = wip_warehouse
stock_entry.to_warehouse = production_order.fg_warehouse
additional_costs = get_additional_costs(production_order, fg_qty=stock_entry.fg_completed_qty)
stock_entry.project = production_order.project
stock_entry.set("additional_costs", additional_costs)
stock_entry.get_items()
return stock_entry.as_dict()
@frappe.whitelist()
def make_timesheet(production_order, company):
timesheet = frappe.new_doc("Timesheet")
timesheet.employee = ""
timesheet.production_order = production_order
timesheet.company = company
return timesheet
@frappe.whitelist()
def add_timesheet_detail(timesheet, args):
if isinstance(timesheet, text_type):
timesheet = frappe.get_doc('Timesheet', timesheet)
if isinstance(args, text_type):
args = json.loads(args)
timesheet.append('time_logs', args)
return timesheet
@frappe.whitelist()
def get_default_warehouse():
wip_warehouse = frappe.db.get_single_value("Manufacturing Settings",
"default_wip_warehouse")
fg_warehouse = frappe.db.get_single_value("Manufacturing Settings",
"default_fg_warehouse")
return {"wip_warehouse": wip_warehouse, "fg_warehouse": fg_warehouse}
@frappe.whitelist()
def make_new_timesheet(source_name, target_doc=None):
po = frappe.get_doc('Production Order', source_name)
ts = po.make_time_logs(open_new=True)
if not ts or not ts.get('time_logs'):
frappe.throw(_("Already completed"))
return ts
@frappe.whitelist()
def stop_unstop(production_order, status):
""" Called from client side on Stop/Unstop event"""
if not frappe.has_permission("Production Order", "write"):
frappe.throw(_("Not permitted"), frappe.PermissionError)
pro_order = frappe.get_doc("Production Order", production_order)
pro_order.update_status(status)
pro_order.update_planned_qty()
frappe.msgprint(_("Production Order has been {0}").format(status))
pro_order.notify_update()
return pro_order.status
@frappe.whitelist()
def query_sales_order(production_item):
out = frappe.db.sql_list("""
select distinct so.name from `tabSales Order` so, `tabSales Order Item` so_item
where so_item.parent=so.name and so_item.item_code=%s and so.docstatus=1
union
select distinct so.name from `tabSales Order` so, `tabPacked Item` pi_item
where pi_item.parent=so.name and pi_item.item_code=%s and so.docstatus=1
""", (production_item, production_item))
return out

View File

@ -632,3 +632,5 @@ execute:frappe.reload_doc('desk', 'doctype','dashboard_chart')
erpnext.patches.v12_0.add_default_dashboards
erpnext.patches.v12_0.remove_bank_remittance_custom_fields
erpnext.patches.v12_0.generate_leave_ledger_entries
erpnext.patches.v12_0.move_credit_limit_to_customer_credit_limit
erpnext.patches.v12_0.add_variant_of_in_item_attribute_table

View File

@ -1,8 +1,9 @@
import frappe
def execute():
frappe.db.sql('''
UPDATE `tabItem Variant Attribute` t1
INNER JOIN `tabItem` t2 ON t2.name = t1.parent
SET t1.variant_of = t2.variant_of
''')
frappe.reload_doc('stock', 'doctype', 'item_variant_attribute')
frappe.db.sql('''
UPDATE `tabItem Variant Attribute` t1
INNER JOIN `tabItem` t2 ON t2.name = t1.parent
SET t1.variant_of = t2.variant_of
''')

View File

@ -0,0 +1,46 @@
# Copyright (c) 2019, Frappe and Contributors
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
import frappe
def execute():
''' Move credit limit and bypass credit limit to the child table of customer credit limit '''
frappe.reload_doc("Selling", "doctype", "Customer Credit Limit")
frappe.reload_doc("Selling", "doctype", "Customer")
frappe.reload_doc("Setup", "doctype", "Customer Group")
if frappe.db.a_row_exists("Customer Credit Limit"):
return
move_credit_limit_to_child_table()
def move_credit_limit_to_child_table():
''' maps data from old field to the new field in the child table '''
companies = frappe.get_all("Company", 'name')
for doctype in ("Customer", "Customer Group"):
fields = ""
if doctype == "Customer" \
and frappe.db.has_column('Customer', 'bypass_credit_limit_check_at_sales_order'):
fields = ", bypass_credit_limit_check_at_sales_order"
credit_limit_records = frappe.db.sql('''
SELECT name, credit_limit {0}
FROM `tab{1}` where credit_limit > 0
'''.format(fields, doctype), as_dict=1) #nosec
for record in credit_limit_records:
doc = frappe.get_doc(doctype, record.name)
for company in companies:
row = frappe._dict({
'credit_limit': record.credit_limit,
'company': company.name
})
if doctype == "Customer":
row.bypass_credit_limit_check = record.bypass_credit_limit_check_at_sales_order
doc.append("credit_limits", row)
for row in doc.credit_limits:
row.db_insert()

View File

@ -37,7 +37,8 @@ frappe.ui.form.CustomerQuickEntryForm = frappe.ui.form.QuickEntryForm.extend({
{
label: __("Address Line 1"),
fieldname: "address_line1",
fieldtype: "Data"
fieldtype: "Data",
reqd: 1
},
{
label: __("Address Line 2"),
@ -55,7 +56,8 @@ frappe.ui.form.CustomerQuickEntryForm = frappe.ui.form.QuickEntryForm.extend({
{
label: __("City"),
fieldname: "city",
fieldtype: "Data"
fieldtype: "Data",
reqd: 1,
},
{
label: __("State"),
@ -66,7 +68,8 @@ frappe.ui.form.CustomerQuickEntryForm = frappe.ui.form.QuickEntryForm.extend({
label: __("Country"),
fieldname: "country",
fieldtype: "Link",
options: "Country"
options: "Country",
reqd: 1
},
{
label: __("Customer POS Id"),

View File

@ -1,5 +1,5 @@
{%- macro format_float(value) -%}
{{ "%.2f" % value|abs }}
{%- macro format_float(value, precision=2) -%}
{{ value|round(frappe.utils.cint(precision)) }}
{%- endmacro -%}
{%- macro render_address(address) %}
@ -182,10 +182,10 @@
<Descrizione>{{ html2text(item.description or '') or item.item_name }}</Descrizione>
<Quantita>{{ format_float(item.qty) }}</Quantita>
<UnitaMisura>{{ item.stock_uom }}</UnitaMisura>
<PrezzoUnitario>{{ format_float(item.price_list_rate or item.rate) }}</PrezzoUnitario>
<PrezzoUnitario>{{ format_float(item.price_list_rate or item.rate, item_meta.get_field("rate").precision) }}</PrezzoUnitario>
{{ render_discount_or_margin(item) }}
<PrezzoTotale>{{ format_float(item.amount) }}</PrezzoTotale>
<AliquotaIVA>{{ format_float(item.tax_rate) }}</AliquotaIVA>
<PrezzoTotale>{{ format_float(item.amount, item_meta.get_field("amount").precision) }}</PrezzoTotale>
<AliquotaIVA>{{ format_float(item.tax_rate, item_meta.get_field("tax_rate").precision) }}</AliquotaIVA>
{%- if item.tax_exemption_reason %}
<Natura>{{ item.tax_exemption_reason.split("-")[0] }}</Natura>
{%- endif %}
@ -197,8 +197,8 @@
{%- if data.tax_exemption_reason %}
<Natura>{{ data.tax_exemption_reason.split("-")[0] }}</Natura>
{%- endif %}
<ImponibileImporto>{{ format_float(data.taxable_amount) }}</ImponibileImporto>
<Imposta>{{ format_float(data.tax_amount) }}</Imposta>
<ImponibileImporto>{{ format_float(data.taxable_amount, item_meta.get_field("tax_amount").precision) }}</ImponibileImporto>
<Imposta>{{ format_float(data.tax_amount, item_meta.get_field("tax_amount").precision) }}</Imposta>
<EsigibilitaIVA>{{ doc.vat_collectability.split("-")[0] }}</EsigibilitaIVA>
{%- if data.tax_exemption_law %}
<RiferimentoNormativo>{{ data.tax_exemption_law }}</RiferimentoNormativo>

View File

@ -151,7 +151,8 @@ def get_invoice_summary(items, taxes):
tax_rate=tax.rate,
tax_amount=(reference_row.tax_amount * tax.rate) / 100,
net_amount=reference_row.tax_amount,
taxable_amount=reference_row.tax_amount,
taxable_amount=(reference_row.tax_amount if tax.charge_type == 'On Previous Row Amount'
else reference_row.total),
item_tax_rate={tax.account_head: tax.rate},
charges=True
)
@ -278,7 +279,11 @@ def prepare_and_attach_invoice(doc, replace=False):
progressive_name, progressive_number = get_progressive_name_and_number(doc, replace)
invoice = prepare_invoice(doc, progressive_number)
invoice_xml = frappe.render_template('erpnext/regional/italy/e-invoice.xml', context={"doc": invoice}, is_path=True)
item_meta = frappe.get_meta("Sales Invoice Item")
invoice_xml = frappe.render_template('erpnext/regional/italy/e-invoice.xml',
context={"doc": invoice, "item_meta": item_meta}, is_path=True)
invoice_xml = invoice_xml.replace("&", "&amp;")
xml_filename = progressive_name + ".xml"

View File

@ -163,15 +163,14 @@ class Gstr1Report(object):
if not b2c_limit:
frappe.throw(_("Please set B2C Limit in GST Settings."))
if self.filters.get("type_of_business") == "B2C Large" and customers:
if self.filters.get("type_of_business") == "B2C Large":
conditions += """ and SUBSTR(place_of_supply, 1, 2) != SUBSTR(company_gstin, 1, 2)
and grand_total > {0} and is_return != 1 and gst_category ='Unregistered' """.\
format(flt(b2c_limit), ", ".join([frappe.db.escape(c.name) for c in customers]))
elif self.filters.get("type_of_business") == "B2C Small" and customers:
and grand_total > {0} and is_return != 1 and gst_category ='Unregistered' """.format(flt(b2c_limit))
elif self.filters.get("type_of_business") == "B2C Small":
conditions += """ and (
SUBSTR(place_of_supply, 1, 2) = SUBSTR(company_gstin, 1, 2)
or grand_total <= {0}) and is_return != 1 and gst_category ='Unregistered' """.\
format(flt(b2c_limit), ", ".join([frappe.db.escape(c.name) for c in customers]))
or grand_total <= {0}) and is_return != 1 and gst_category ='Unregistered' """.format(flt(b2c_limit))
elif self.filters.get("type_of_business") == "CDNR":
conditions += """ and is_return = 1 """

File diff suppressed because it is too large Load Diff

View File

@ -167,13 +167,18 @@ class Customer(TransactionBase):
frappe.throw(_("A Customer Group exists with same name please change the Customer name or rename the Customer Group"), frappe.NameError)
def validate_credit_limit_on_change(self):
if self.get("__islocal") or not self.credit_limit \
or self.credit_limit == frappe.db.get_value("Customer", self.name, "credit_limit"):
if self.get("__islocal") or not self.credit_limits:
return
for company in frappe.get_all("Company"):
outstanding_amt = get_customer_outstanding(self.name, company.name)
if flt(self.credit_limit) < outstanding_amt:
company_record = []
for limit in self.credit_limits:
if limit.company in company_record:
frappe.throw(_("Credit limit is already defined for the Company {0}").format(limit.company, self.name))
else:
company_record.append(limit.company)
outstanding_amt = get_customer_outstanding(self.name, limit.company)
if flt(limit.credit_limit) < outstanding_amt:
frappe.throw(_("""New credit limit is less than current outstanding amount for the customer. Credit limit has to be atleast {0}""").format(outstanding_amt))
def on_trash(self):
@ -322,11 +327,13 @@ def get_credit_limit(customer, company):
credit_limit = None
if customer:
credit_limit, customer_group = frappe.get_cached_value("Customer",
customer, ["credit_limit", "customer_group"])
credit_limit = frappe.db.get_value("Customer Credit Limit",
{'parent': customer, 'parenttype': 'Customer', 'company': company}, 'credit_limit')
if not credit_limit:
credit_limit = frappe.get_cached_value("Customer Group", customer_group, "credit_limit")
customer_group = frappe.get_cached_value("Customer", customer, 'customer_group')
credit_limit = frappe.db.get_value("Customer Credit Limit",
{'parent': customer_group, 'parenttype': 'Customer Group', 'company': company}, 'credit_limit')
if not credit_limit:
credit_limit = frappe.get_cached_value('Company', company, "credit_limit")

View File

@ -25,7 +25,7 @@ class TestCustomer(unittest.TestCase):
make_test_records('Item')
def tearDown(self):
frappe.db.set_value("Customer", '_Test Customer', 'credit_limit', 0.0)
set_credit_limit('_Test Customer', '_Test Company', 0)
def test_party_details(self):
from erpnext.accounts.party import get_party_details
@ -225,8 +225,8 @@ class TestCustomer(unittest.TestCase):
item_qty = int((abs(outstanding_amt) + 200)/100)
make_sales_order(qty=item_qty)
if credit_limit == 0.0:
frappe.db.set_value("Customer", '_Test Customer', 'credit_limit', outstanding_amt - 50.0)
if not credit_limit:
set_credit_limit('_Test Customer', '_Test Company', outstanding_amt - 50)
# Sales Order
so = make_sales_order(do_not_submit=True)
@ -241,7 +241,7 @@ class TestCustomer(unittest.TestCase):
self.assertRaises(frappe.ValidationError, si.submit)
if credit_limit > outstanding_amt:
frappe.db.set_value("Customer", '_Test Customer', 'credit_limit', credit_limit)
set_credit_limit('_Test Customer', '_Test Company', credit_limit)
# Makes Sales invoice from Sales Order
so.save(ignore_permissions=True)
@ -252,7 +252,10 @@ class TestCustomer(unittest.TestCase):
def test_customer_credit_limit_on_change(self):
outstanding_amt = self.get_customer_outstanding_amount()
customer = frappe.get_doc("Customer", '_Test Customer')
customer.credit_limit = flt(outstanding_amt - 100)
customer.append('credit_limits', {'credit_limit': flt(outstanding_amt - 100), 'company': '_Test Company'})
''' define new credit limit for same company '''
customer.append('credit_limits', {'credit_limit': flt(outstanding_amt - 100), 'company': '_Test Company'})
self.assertRaises(frappe.ValidationError, customer.save)
def test_customer_payment_terms(self):
@ -292,3 +295,20 @@ def get_customer_dict(customer_name):
"doctype": "Customer",
"territory": "_Test Territory"
}
def set_credit_limit(customer, company, credit_limit):
customer = frappe.get_doc("Customer", customer)
existing_row = None
for d in customer.credit_limits:
if d.company == company:
existing_row = d
d.credit_limit = credit_limit
d.db_update()
break
if not existing_row:
customer.append('credit_limits', {
'company': company,
'credit_limit': credit_limit
})
customer.credit_limits[-1].db_insert()

View File

@ -0,0 +1,50 @@
{
"creation": "2019-08-28 17:29:42.115592",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"company",
"column_break_2",
"credit_limit",
"bypass_credit_limit_check"
],
"fields": [
{
"columns": 4,
"fieldname": "credit_limit",
"fieldtype": "Currency",
"in_list_view": 1,
"label": "Credit Limit"
},
{
"fieldname": "column_break_2",
"fieldtype": "Column Break"
},
{
"columns": 4,
"fieldname": "company",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Company",
"options": "Company"
},
{
"default": "0",
"fieldname": "bypass_credit_limit_check",
"fieldtype": "Check",
"in_list_view": 1,
"label": "Bypass credit limit_check"
}
],
"istable": 1,
"modified": "2019-08-29 20:46:36.073953",
"modified_by": "Administrator",
"module": "Selling",
"name": "Customer Credit Limit",
"owner": "Administrator",
"permissions": [],
"quick_entry": 1,
"sort_field": "modified",
"sort_order": "DESC"
}

View File

@ -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 CustomerCreditLimit(Document):
pass

View File

@ -208,7 +208,9 @@ class SalesOrder(SellingController):
def check_credit_limit(self):
# if bypass credit limit check is set to true (1) at sales order level,
# then we need not to check credit limit and vise versa
if not cint(frappe.get_cached_value("Customer", self.customer, "bypass_credit_limit_check_at_sales_order")):
if not cint(frappe.db.get_value("Customer Credit Limit",
{'parent': self.customer, 'parenttype': 'Customer', 'company': self.company},
"bypass_credit_limit_check")):
check_credit_limit(self.customer, self.company)
def check_nextdoc_docstatus(self):

View File

@ -1,7 +1,7 @@
QUnit.module('Sales Order');
QUnit.test("test_sales_order_with_bypass_credit_limit_check", function(assert) {
//#PR : 10861, Author : ashish-greycube & jigneshpshah, Email:mr.ashish.shah@gmail.com
//#PR : 10861, Author : ashish-greycube & jigneshpshah, Email:mr.ashish.shah@gmail.com
assert.expect(2);
let done = assert.async();
frappe.run_serially([
@ -10,8 +10,10 @@ QUnit.test("test_sales_order_with_bypass_credit_limit_check", function(assert) {
() => frappe.quick_entry.dialog.$wrapper.find('.edit-full').click(),
() => frappe.timeout(1),
() => cur_frm.set_value("customer_name", "Test Customer 10"),
() => cur_frm.set_value("credit_limit", 100.00),
() => cur_frm.set_value("bypass_credit_limit_check_at_sales_order", 1),
() => cur_frm.add_child('credit_limits', {
'company': cur_frm.doc.company || '_Test Company'
'credit_limit': 1000,
'bypass_credit_limit_check': 1}),
// save form
() => cur_frm.save(),
() => frappe.timeout(1),
@ -22,10 +24,10 @@ QUnit.test("test_sales_order_with_bypass_credit_limit_check", function(assert) {
() => frappe.timeout(1),
() => cur_frm.set_value("item_code", "Test Product 10"),
() => cur_frm.set_value("item_group", "Products"),
() => cur_frm.set_value("standard_rate", 100),
() => cur_frm.set_value("standard_rate", 100),
// save form
() => cur_frm.save(),
() => frappe.timeout(1),
() => frappe.timeout(1),
() => {
return frappe.tests.make('Sales Order', [
@ -46,11 +48,11 @@ QUnit.test("test_sales_order_with_bypass_credit_limit_check", function(assert) {
() => frappe.tests.click_button('Yes'),
() => frappe.timeout(3),
() => {
assert.ok(cur_frm.doc.status=="To Deliver and Bill", "It is submited. Credit limit is NOT checked for sales order");
},
},
() => done()
]);
});

View File

@ -1,7 +1,7 @@
QUnit.module('Sales Order');
QUnit.test("test_sales_order_without_bypass_credit_limit_check", function(assert) {
//#PR : 10861, Author : ashish-greycube & jigneshpshah, Email:mr.ashish.shah@gmail.com
//#PR : 10861, Author : ashish-greycube & jigneshpshah, Email:mr.ashish.shah@gmail.com
assert.expect(2);
let done = assert.async();
frappe.run_serially([
@ -10,8 +10,10 @@ QUnit.test("test_sales_order_without_bypass_credit_limit_check", function(assert
() => frappe.quick_entry.dialog.$wrapper.find('.edit-full').click(),
() => frappe.timeout(1),
() => cur_frm.set_value("customer_name", "Test Customer 11"),
() => cur_frm.set_value("credit_limit", 100.00),
() => cur_frm.set_value("bypass_credit_limit_check_at_sales_order", 0),
() => cur_frm.add_child('credit_limits', {
'credit_limit': 1000,
'company': '_Test Company',
'bypass_credit_limit_check': 1}),
// save form
() => cur_frm.save(),
() => frappe.timeout(1),
@ -21,10 +23,10 @@ QUnit.test("test_sales_order_without_bypass_credit_limit_check", function(assert
() => frappe.click_link('Edit in full page'),
() => cur_frm.set_value("item_code", "Test Product 11"),
() => cur_frm.set_value("item_group", "Products"),
() => cur_frm.set_value("standard_rate", 100),
() => cur_frm.set_value("standard_rate", 100),
// save form
() => cur_frm.save(),
() => frappe.timeout(1),
() => frappe.timeout(1),
() => {
return frappe.tests.make('Sales Order', [
@ -45,14 +47,14 @@ QUnit.test("test_sales_order_without_bypass_credit_limit_check", function(assert
() => frappe.tests.click_button('Yes'),
() => frappe.timeout(3),
() => {
if (cur_dialog.body.innerText.match(/^Credit limit has been crossed for customer.*$/))
{
if (cur_dialog.body.innerText.match(/^Credit limit has been crossed for customer.*$/))
{
/*Match found */
assert.ok(true, "Credit Limit crossed message received");
}
},
() => cur_dialog.cancel(),
() => done()

View File

@ -29,7 +29,7 @@ def execute(filters=None):
if customer_naming_type == "Naming Series":
row = [d.name, d.customer_name, credit_limit, outstanding_amt, bal,
d.bypass_credit_limit_check_at_sales_order, d.is_frozen,
d.bypass_credit_limit_check, d.is_frozen,
d.disabled]
else:
row = [d.name, credit_limit, outstanding_amt, bal,
@ -60,9 +60,15 @@ def get_details(filters):
conditions = ""
if filters.get("customer"):
conditions += " where name = %(customer)s"
return frappe.db.sql("""select name, customer_name,
bypass_credit_limit_check_at_sales_order, is_frozen, disabled from `tabCustomer` %s
""" % conditions, filters, as_dict=1)
conditions += " AND c.name = " + filters.get("customer")
return frappe.db.sql("""SELECT
c.name, c.customer_name,
ccl.bypass_credit_limit_check,
c.is_frozen, c.disabled
FROM `tabCustomer` c, `tabCustomer Credit Limit` ccl
WHERE
c.name = ccl.parent
AND ccl.company = %s
{0}
""".format(conditions), (filters.get("company")), as_dict=1) #nosec

View File

@ -1,553 +1,194 @@
{
"allow_copy": 0,
"allow_guest_to_view": 0,
"_comments": "[]",
"allow_import": 1,
"allow_rename": 1,
"autoname": "field:customer_group_name",
"beta": 0,
"creation": "2013-01-10 16:34:23",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "Setup",
"editable_grid": 0,
"field_order": [
"customer_group_name",
"parent_customer_group",
"is_group",
"cb0",
"default_price_list",
"payment_terms",
"lft",
"rgt",
"old_parent",
"default_receivable_account",
"accounts",
"credit_limit_section",
"credit_limits"
],
"fields": [
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "customer_group_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": "Customer Group Name",
"length": 0,
"no_copy": 1,
"oldfieldname": "customer_group_name",
"oldfieldtype": "Data",
"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": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 1,
"collapsible": 0,
"columns": 0,
"description": "",
"fieldname": "parent_customer_group",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 1,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Parent Customer Group",
"length": 0,
"no_copy": 0,
"oldfieldname": "parent_customer_group",
"oldfieldtype": "Link",
"options": "Customer Group",
"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": "Customer Group"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 1,
"collapsible": 0,
"columns": 0,
"default": "0",
"description": "Only leaf nodes are allowed in transaction",
"fieldname": "is_group",
"fieldtype": "Check",
"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": "Is Group",
"length": 0,
"no_copy": 0,
"oldfieldname": "is_group",
"oldfieldtype": "Select",
"options": "",
"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": "Select"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "cb0",
"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_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "default_price_list",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 1,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Default Price List",
"length": 0,
"no_copy": 0,
"options": "Price List",
"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": "Price List"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "",
"fieldname": "payment_terms",
"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": "Default Payment Terms Template",
"length": 0,
"no_copy": 0,
"options": "Payment Terms Template",
"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": "Payment Terms Template"
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "credit_limit",
"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": "Credit Limit",
"length": 0,
"no_copy": 0,
"permlevel": 1,
"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
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "lft",
"fieldtype": "Int",
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "lft",
"length": 0,
"no_copy": 1,
"oldfieldname": "lft",
"oldfieldtype": "Int",
"permlevel": 0,
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 1,
"reqd": 0,
"search_index": 1,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"search_index": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "rgt",
"fieldtype": "Int",
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "rgt",
"length": 0,
"no_copy": 1,
"oldfieldname": "rgt",
"oldfieldtype": "Int",
"permlevel": 0,
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 1,
"reqd": 0,
"search_index": 1,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"search_index": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"description": "",
"fieldname": "old_parent",
"fieldtype": "Link",
"hidden": 1,
"ignore_user_permissions": 1,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "old_parent",
"length": 0,
"no_copy": 1,
"oldfieldname": "old_parent",
"oldfieldtype": "Data",
"options": "Customer Group",
"permlevel": 0,
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 1,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"report_hide": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "default_receivable_account",
"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": "Default Receivable Account",
"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
"label": "Default Receivable Account"
},
{
"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": "Mention if non-standard receivable account applicable",
"fieldname": "accounts",
"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": "Accounts",
"length": 0,
"no_copy": 0,
"options": "Party Account",
"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": "Party Account"
},
{
"fieldname": "credit_limit_section",
"fieldtype": "Section Break",
"label": "Credit Limits"
},
{
"fieldname": "credit_limits",
"fieldtype": "Table",
"label": "Credit Limit",
"options": "Customer Credit Limit"
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"icon": "fa fa-sitemap",
"idx": 1,
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2018-08-29 06:26:05.935871",
"modified": "2019-09-06 12:40:14.954697",
"modified_by": "Administrator",
"module": "Setup",
"name": "Customer Group",
"owner": "Administrator",
"permissions": [
{
"amend": 0,
"cancel": 0,
"create": 0,
"delete": 0,
"email": 1,
"export": 0,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Sales Manager",
"set_user_permissions": 0,
"share": 0,
"submit": 0,
"write": 0
"role": "Sales Manager"
},
{
"amend": 0,
"cancel": 0,
"create": 0,
"delete": 0,
"email": 1,
"export": 0,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Sales User",
"set_user_permissions": 0,
"share": 0,
"submit": 0,
"write": 0
"role": "Sales User"
},
{
"amend": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 1,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Sales Master Manager",
"set_user_permissions": 1,
"share": 1,
"submit": 0,
"write": 1
},
{
"amend": 0,
"cancel": 0,
"create": 0,
"delete": 0,
"email": 0,
"export": 0,
"if_owner": 0,
"import": 0,
"permlevel": 1,
"print": 0,
"read": 1,
"report": 0,
"role": "Sales Master Manager",
"set_user_permissions": 0,
"share": 0,
"submit": 0,
"write": 1
},
{
"amend": 0,
"cancel": 0,
"create": 0,
"delete": 0,
"email": 0,
"export": 0,
"if_owner": 0,
"import": 0,
"permlevel": 1,
"print": 0,
"read": 1,
"report": 0,
"role": "Sales User",
"set_user_permissions": 0,
"share": 0,
"submit": 0,
"write": 0
"role": "Sales User"
},
{
"amend": 0,
"cancel": 0,
"create": 0,
"delete": 0,
"email": 0,
"export": 0,
"if_owner": 0,
"import": 0,
"permlevel": 1,
"print": 0,
"read": 1,
"report": 0,
"role": "Sales Manager",
"set_user_permissions": 0,
"share": 0,
"submit": 0,
"write": 0
"role": "Sales Manager"
}
],
"quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
"search_fields": "parent_customer_group",
"show_name_in_global_search": 1,
"sort_order": "DESC",
"track_changes": 0,
"track_seen": 0,
"track_views": 0
"sort_order": "DESC"
}

View File

@ -4,6 +4,7 @@
from __future__ import unicode_literals
import frappe
import copy
from frappe import _
from frappe.utils import nowdate, cint, cstr
from frappe.utils.nestedset import NestedSet
from frappe.website.website_generator import WebsiteGenerator
@ -28,7 +29,8 @@ class ItemGroup(NestedSet, WebsiteGenerator):
super(ItemGroup, self).validate()
if not self.parent_item_group and not frappe.flags.in_test:
self.parent_item_group = 'All Item Groups'
if frappe.db.exists("Item Group", _('All Item Groups'), cache=True):
self.parent_item_group = _('All Item Groups')
self.make_route()

View File

@ -3,8 +3,18 @@ from frappe import _
import frappe
import json
def get_company_for_dashboards():
company = frappe.defaults.get_defaults().company
if company:
return company
else:
company_list = frappe.get_list("Company")
if company_list:
return company_list[0].name
return None
def get_default_dashboards():
company = frappe.get_doc("Company", frappe.defaults.get_defaults().company)
company = frappe.get_doc("Company", get_company_for_dashboards())
income_account = company.default_income_account or get_account("Income Account", company.name)
expense_account = company.default_expense_account or get_account("Expense Account", company.name)
bank_account = company.default_bank_account or get_account("Bank", company.name)
@ -104,4 +114,4 @@ def get_default_dashboards():
def get_account(account_type, company):
accounts = frappe.get_list("Account", filters={"account_type": account_type, "company": company})
if accounts:
return accounts[0].name
return accounts[0].name

View File

@ -501,9 +501,23 @@ def install_defaults(args=None):
make_records(records)
def add_dashboards():
from erpnext.setup.setup_wizard.data.dashboard_charts import get_company_for_dashboards
if not get_company_for_dashboards():
return
from erpnext.setup.setup_wizard.data.dashboard_charts import get_default_dashboards
from frappe.modules.import_file import import_file_by_path
dashboard_data = get_default_dashboards()
# create account balance timeline before creating dashbaord charts
doctype = "dashboard_chart_source"
docname = "account_balance_timeline"
folder = os.path.dirname(frappe.get_module("erpnext.accounts").__file__)
doc_path = os.path.join(folder, doctype, docname, docname) + ".json"
import_file_by_path(doc_path, force=0, for_sync=True)
make_records(dashboard_data["Charts"])
make_records(dashboard_data["Dashboards"])

View File

@ -234,8 +234,10 @@ class DeliveryNote(SellingController):
extra_amount = 0
validate_against_credit_limit = False
bypass_credit_limit_check_at_sales_order = cint(frappe.db.get_value("Customer", self.customer,
"bypass_credit_limit_check_at_sales_order"))
bypass_credit_limit_check_at_sales_order = cint(frappe.db.get_value("Customer Credit Limit",
filters={'parent': self.customer, 'parenttype': 'Customer', 'company': self.company},
fieldname="bypass_credit_limit_check"))
if bypass_credit_limit_check_at_sales_order:
validate_against_credit_limit = True
extra_amount = self.base_grand_total

View File

@ -904,7 +904,7 @@
"description": "Item Image (if not slideshow)",
"fieldname": "website_image",
"fieldtype": "Attach",
"label": "Image"
"label": "Website Image"
},
{
"fieldname": "thumbnail",
@ -1040,7 +1040,7 @@
"idx": 2,
"image_field": "image",
"max_attachments": 1,
"modified": "2019-07-12 12:18:13.977931",
"modified": "2019-09-03 18:34:13.977931",
"modified_by": "Administrator",
"module": "Stock",
"name": "Item",

View File

@ -32,10 +32,16 @@ class ItemPrice(Document):
def update_price_list_details(self):
if self.price_list:
self.buying, self.selling, self.currency = \
frappe.db.get_value("Price List",
{"name": self.price_list, "enabled": 1},
["buying", "selling", "currency"])
price_list_details = frappe.db.get_value("Price List",
{"name": self.price_list, "enabled": 1},
["buying", "selling", "currency"])
if not price_list_details:
link = frappe.utils.get_link_to_form('Price List', self.price_list)
frappe.throw("The price list {0} does not exists or disabled".
format(link))
self.buying, self.selling, self.currency = price_list_details
def update_item_details(self):
if self.item_code:

View File

@ -1,685 +1,203 @@
{
"allow_copy": 0,
"allow_import": 0,
"allow_rename": 0,
"beta": 0,
"creation": "2013-02-22 01:28:00",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"creation": "2013-02-22 01:28:00",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"parent_item",
"item_code",
"item_name",
"column_break_5",
"description",
"section_break_6",
"warehouse",
"target_warehouse",
"column_break_9",
"qty",
"section_break_9",
"serial_no",
"column_break_11",
"batch_no",
"section_break_13",
"actual_qty",
"projected_qty",
"column_break_16",
"uom",
"page_break",
"prevdoc_doctype",
"parent_detail_docname"
],
"fields": [
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "parent_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": "Parent Item",
"length": 0,
"no_copy": 0,
"oldfieldname": "parent_item",
"oldfieldtype": "Link",
"options": "Item",
"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,
"unique": 0
},
"fieldname": "parent_item",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Parent Item",
"oldfieldname": "parent_item",
"oldfieldtype": "Link",
"options": "Item",
"read_only": 1
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"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,
"oldfieldname": "item_code",
"oldfieldtype": "Link",
"options": "Item",
"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,
"unique": 0
},
"fieldname": "item_code",
"fieldtype": "Link",
"in_global_search": 1,
"in_list_view": 1,
"label": "Item Code",
"oldfieldname": "item_code",
"oldfieldtype": "Link",
"options": "Item",
"read_only": 1
},
{
"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": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Item Name",
"length": 0,
"no_copy": 0,
"oldfieldname": "item_name",
"oldfieldtype": "Data",
"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,
"unique": 0
},
"fieldname": "item_name",
"fieldtype": "Data",
"label": "Item Name",
"oldfieldname": "item_name",
"oldfieldtype": "Data",
"read_only": 1
},
{
"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,
"unique": 0
},
"fieldname": "column_break_5",
"fieldtype": "Column Break"
},
{
"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": "description",
"oldfieldtype": "Text",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"print_width": "300px",
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0,
"fieldname": "description",
"fieldtype": "Text Editor",
"in_list_view": 1,
"label": "Description",
"oldfieldname": "description",
"oldfieldtype": "Text",
"print_width": "300px",
"width": "300px"
},
},
{
"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,
"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
},
"fieldname": "section_break_6",
"fieldtype": "Section Break"
},
{
"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": "From Warehouse",
"length": 0,
"no_copy": 0,
"oldfieldname": "warehouse",
"oldfieldtype": "Link",
"options": "Warehouse",
"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,
"unique": 0
},
"fieldname": "warehouse",
"fieldtype": "Link",
"label": "From Warehouse",
"oldfieldname": "warehouse",
"oldfieldtype": "Link",
"options": "Warehouse"
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "target_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": "To Warehouse (Optional)",
"length": 0,
"no_copy": 0,
"options": "Warehouse",
"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
},
"fieldname": "target_warehouse",
"fieldtype": "Link",
"label": "To Warehouse (Optional)",
"options": "Warehouse",
"print_hide": 1
},
{
"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
},
"fieldname": "column_break_9",
"fieldtype": "Column Break"
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"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": "Qty",
"length": 0,
"no_copy": 0,
"oldfieldname": "qty",
"oldfieldtype": "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,
"unique": 0
},
"fieldname": "qty",
"fieldtype": "Float",
"in_list_view": 1,
"label": "Qty",
"oldfieldname": "qty",
"oldfieldtype": "Currency",
"read_only": 1
},
{
"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,
"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
},
"fieldname": "section_break_9",
"fieldtype": "Section Break"
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "serial_no",
"fieldtype": "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": "Serial No",
"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,
"unique": 0
},
"fieldname": "serial_no",
"fieldtype": "Text",
"label": "Serial No"
},
{
"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
},
"fieldname": "column_break_11",
"fieldtype": "Column Break"
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "batch_no",
"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": "Batch No",
"length": 0,
"no_copy": 0,
"options": "Batch",
"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,
"unique": 0
},
"fieldname": "batch_no",
"fieldtype": "Link",
"label": "Batch No",
"options": "Batch"
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "section_break_13",
"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
},
"fieldname": "section_break_13",
"fieldtype": "Section Break"
},
{
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "actual_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": "Actual Qty",
"length": 0,
"no_copy": 1,
"oldfieldname": "actual_qty",
"oldfieldtype": "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,
"unique": 0
},
"allow_on_submit": 1,
"fieldname": "actual_qty",
"fieldtype": "Float",
"label": "Actual Qty",
"no_copy": 1,
"oldfieldname": "actual_qty",
"oldfieldtype": "Currency",
"read_only": 1
},
{
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "projected_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": "Projected Qty",
"length": 0,
"no_copy": 1,
"oldfieldname": "projected_qty",
"oldfieldtype": "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,
"unique": 0
},
"allow_on_submit": 1,
"fieldname": "projected_qty",
"fieldtype": "Float",
"label": "Projected Qty",
"no_copy": 1,
"oldfieldname": "projected_qty",
"oldfieldtype": "Currency",
"read_only": 1
},
{
"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
},
"fieldname": "column_break_16",
"fieldtype": "Column Break"
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"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": "UOM",
"length": 0,
"no_copy": 0,
"oldfieldname": "uom",
"oldfieldtype": "Link",
"options": "UOM",
"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,
"unique": 0
},
"fieldname": "uom",
"fieldtype": "Link",
"label": "UOM",
"oldfieldname": "uom",
"oldfieldtype": "Link",
"options": "UOM",
"read_only": 1
},
{
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "page_break",
"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": "Page Break",
"length": 0,
"no_copy": 0,
"oldfieldname": "page_break",
"oldfieldtype": "Check",
"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,
"unique": 0
},
"allow_on_submit": 1,
"default": "0",
"fieldname": "page_break",
"fieldtype": "Check",
"label": "Page Break",
"oldfieldname": "page_break",
"oldfieldtype": "Check",
"read_only": 1
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "prevdoc_doctype",
"fieldtype": "Data",
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Prevdoc DocType",
"length": 0,
"no_copy": 0,
"oldfieldname": "prevdoc_doctype",
"oldfieldtype": "Data",
"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,
"unique": 0
},
"fieldname": "prevdoc_doctype",
"fieldtype": "Data",
"hidden": 1,
"label": "Prevdoc DocType",
"oldfieldname": "prevdoc_doctype",
"oldfieldtype": "Data",
"print_hide": 1,
"read_only": 1
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "parent_detail_docname",
"fieldtype": "Data",
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Parent Detail docname",
"length": 0,
"no_copy": 1,
"oldfieldname": "parent_detail_docname",
"oldfieldtype": "Data",
"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,
"unique": 0
"fieldname": "parent_detail_docname",
"fieldtype": "Data",
"hidden": 1,
"label": "Parent Detail docname",
"no_copy": 1,
"oldfieldname": "parent_detail_docname",
"oldfieldtype": "Data",
"print_hide": 1,
"read_only": 1
}
],
"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": "2017-02-20 13:27:37.569945",
"modified_by": "Administrator",
"module": "Stock",
"name": "Packed Item",
"owner": "Administrator",
"permissions": [],
"quick_entry": 0,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 0,
"track_changes": 1,
"track_seen": 0
}
],
"idx": 1,
"istable": 1,
"modified": "2019-08-27 18:17:37.167512",
"modified_by": "Administrator",
"module": "Stock",
"name": "Packed Item",
"owner": "Administrator",
"permissions": [],
"track_changes": 1
}

View File

@ -30,14 +30,14 @@ def get_bin_qty(item, warehouse):
where item_code = %s and warehouse = %s""", (item, warehouse), as_dict = 1)
return det and det[0] or frappe._dict()
def update_packing_list_item(doc, packing_item_code, qty, main_item_row, description):
def update_packing_list_item(doc, packing_item_code, qty, main_item_row, description):
item = get_packing_item_details(packing_item_code, doc.company)
# check if exists
exists = 0
for d in doc.get("packed_items"):
if d.parent_item == main_item_row.item_code and d.item_code == packing_item_code and\
d.parent_detail_docname == main_item_row.name and d.description == description:
d.parent_detail_docname == main_item_row.name:
pi, exists = d, 1
break
@ -48,10 +48,10 @@ def update_packing_list_item(doc, packing_item_code, qty, main_item_row, descrip
pi.item_code = packing_item_code
pi.item_name = item.item_name
pi.parent_detail_docname = main_item_row.name
pi.description = item.description
pi.uom = item.stock_uom
pi.qty = flt(qty)
pi.description = description
if description and not pi.description:
pi.description = description
if not pi.warehouse:
pi.warehouse = (main_item_row.warehouse if ((doc.get('is_pos')
or not item.default_warehouse) and main_item_row.warehouse) else item.default_warehouse)
@ -112,4 +112,4 @@ def get_items_from_product_bundle(args):
return items
def on_doctype_update():
frappe.db.add_index("Packed Item", ["item_code", "warehouse"])
frappe.db.add_index("Packed Item", ["item_code", "warehouse"])

View File

@ -10,7 +10,7 @@ cur_frm.fields_dict['delivery_note'].get_query = function(doc, cdt, cdn) {
cur_frm.fields_dict['items'].grid.get_field('item_code').get_query = function(doc, cdt, cdn) {
if(!doc.delivery_note) {
frappe.throw(__("Please Delivery Note first"))
frappe.throw(__("Please select a Delivery Note"));
} else {
return {
query: "erpnext.stock.doctype.packing_slip.packing_slip.item_details",
@ -125,4 +125,4 @@ cur_frm.pformat.gross_weight_pkg= function(doc){
return '<table style="width:100%">' + make_row('Gross Weight', doc.gross_weight_pkg) + '</table>'
}
// TODO: validate gross weight field
// TODO: validate gross weight field

View File

@ -74,7 +74,7 @@
{
"description": "Identification of the package for the delivery (for print)",
"fieldname": "from_case_no",
"fieldtype": "Data",
"fieldtype": "Int",
"in_list_view": 1,
"label": "From Package No.",
"no_copy": 1,
@ -88,7 +88,7 @@
{
"description": "If more than one package of the same type (for print)",
"fieldname": "to_case_no",
"fieldtype": "Data",
"fieldtype": "Int",
"in_list_view": 1,
"label": "To Package No.",
"no_copy": 1,
@ -180,7 +180,7 @@
"icon": "fa fa-suitcase",
"idx": 1,
"is_submittable": 1,
"modified": "2019-05-31 04:45:08.082862",
"modified": "2019-09-09 04:45:08.082862",
"modified_by": "Administrator",
"module": "Stock",
"name": "Packing Slip",
@ -261,4 +261,4 @@
"show_name_in_global_search": 1,
"sort_field": "modified",
"sort_order": "DESC"
}
}

View File

@ -53,7 +53,6 @@ class PackingSlip(Document):
frappe.msgprint(_("'To Case No.' cannot be less than 'From Case No.'"),
raise_exception=1)
res = frappe.db.sql("""SELECT name FROM `tabPacking Slip`
WHERE delivery_note = %(delivery_note)s AND docstatus = 1 AND
((from_case_no BETWEEN %(from_case_no)s AND %(to_case_no)s)

View File

@ -355,6 +355,7 @@
"label": "Scan Barcode"
},
{
"allow_bulk_edit": 1,
"fieldname": "items",
"fieldtype": "Table",
"label": "Items",
@ -626,7 +627,7 @@
"icon": "fa fa-file-text",
"idx": 1,
"is_submittable": 1,
"modified": "2019-08-22 17:11:42.074154",
"modified": "2019-09-09 11:40:05.762003",
"modified_by": "Administrator",
"module": "Stock",
"name": "Stock Entry",

View File

@ -1,3 +1,3 @@
{% set domains = frappe.get_doc("Domain Settings").active_domains %}
<a href="https://erpnext.com?source=website_footer" target="_blank" class="text-muted">Powered by ERPNext - {{ domains[0].domain if domains else 'Open Source' }} ERP Software</a>
<a href="https://erpnext.com?source=website_footer" target="_blank" class="text-muted">Powered by ERPNext - ERP Software {{ ('for ' + domains[0].domain + ' Companies') if domains else '' }}</a>