Merge branch 'develop' into rename-doc-fix
diff --git a/.travis.yml b/.travis.yml
index 40afeee..365eb67 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -63,6 +63,7 @@
- tar -xf /tmp/wkhtmltox.tar.xz -C /tmp
- sudo mv /tmp/wkhtmltox/bin/wkhtmltopdf /usr/local/bin/wkhtmltopdf
- sudo chmod o+x /usr/local/bin/wkhtmltopdf
+ - sudo apt-get install libcups2-dev
- cd ~/frappe-bench
diff --git a/README.md b/README.md
index 64f8d67..ed57a17 100644
--- a/README.md
+++ b/README.md
@@ -13,9 +13,26 @@
</div>
-Includes: Accounting, Inventory, Manufacturing, CRM, Sales, Purchase, Project Management, HRMS. Requires MariaDB.
+ERPNext as a monolith includes the following areas for managing businesses:
-ERPNext is built on the [Frappe](https://github.com/frappe/frappe) Framework, a full-stack web app framework in Python & JavaScript.
+1. [Accounting](https://erpnext.com/docs/user/manual/en/accounts)
+1. [Inventory](https://erpnext.com/docs/user/manual/en/stock)
+1. [CRM](https://erpnext.com/docs/user/manual/en/CRM)
+1. [Sales](https://erpnext.com/docs/user/manual/en/selling)
+1. [Purchase](https://erpnext.com/docs/user/manual/en/buying)
+1. [HRMS](https://erpnext.com/docs/user/manual/en/human-resources)
+1. [Project Management](https://erpnext.com/docs/user/manual/en/projects)
+1. [Support](https://erpnext.com/docs/user/manual/en/support)
+1. [Asset Management](https://erpnext.com/docs/user/manual/en/asset)
+1. [Quality Management](https://erpnext.com/docs/user/manual/en/quality-management)
+1. [Manufacturing](https://erpnext.com/docs/user/manual/en/manufacturing)
+1. [Website Management](https://erpnext.com/docs/user/manual/en/website)
+1. [Customize ERPNext](https://erpnext.com/docs/user/manual/en/customize-erpnext)
+1. [And More](https://erpnext.com/docs/user/manual/en/)
+
+ERPNext requires MariaDB.
+
+ERPNext is built on the [Frappe Framework](https://github.com/frappe/frappe), a full-stack web app framework built with Python & JavaScript.
- [User Guide](https://erpnext.com/docs/user)
- [Discussion Forum](https://discuss.erpnext.com/)
diff --git a/erpnext/__init__.py b/erpnext/__init__.py
index d031bc5..f40b957 100644
--- a/erpnext/__init__.py
+++ b/erpnext/__init__.py
@@ -5,7 +5,7 @@
from erpnext.hooks import regional_overrides
from frappe.utils import getdate
-__version__ = '12.1.8'
+__version__ = '12.2.0'
def get_default_company(user=None):
'''Get default company for user'''
diff --git a/erpnext/accounts/dashboard_chart_source/account_balance_timeline/account_balance_timeline.py b/erpnext/accounts/dashboard_chart_source/account_balance_timeline/account_balance_timeline.py
index d098d84..43acded 100644
--- a/erpnext/accounts/dashboard_chart_source/account_balance_timeline/account_balance_timeline.py
+++ b/erpnext/accounts/dashboard_chart_source/account_balance_timeline/account_balance_timeline.py
@@ -19,6 +19,11 @@
else:
chart = frappe._dict(frappe.parse_json(chart))
timespan = chart.timespan
+
+ if chart.timespan == 'Select Date Range':
+ from_date = chart.from_date
+ to_date = chart.to_date
+
timegrain = chart.time_interval
filters = frappe.parse_json(chart.filters_json)
@@ -88,7 +93,8 @@
fields = ['posting_date', 'debit', 'credit'],
filters = [
dict(posting_date = ('<', to_date)),
- dict(account = ('in', child_accounts))
+ dict(account = ('in', child_accounts)),
+ dict(voucher_type = ('!=', 'Period Closing Voucher'))
],
order_by = 'posting_date asc')
diff --git a/erpnext/accounts/deferred_revenue.py b/erpnext/accounts/deferred_revenue.py
index 32485a3..62a8f05 100644
--- a/erpnext/accounts/deferred_revenue.py
+++ b/erpnext/accounts/deferred_revenue.py
@@ -174,6 +174,8 @@
# GL Entry for crediting the amount in the deferred expense
from erpnext.accounts.general_ledger import make_gl_entries
+ if amount == 0: return
+
gl_entries = []
gl_entries.append(
doc.get_gl_dict({
diff --git a/erpnext/accounts/doctype/account/account.py b/erpnext/accounts/doctype/account/account.py
index 7cca8d2..cf1748f 100644
--- a/erpnext/accounts/doctype/account/account.py
+++ b/erpnext/accounts/doctype/account/account.py
@@ -109,15 +109,16 @@
if not descendants: return
parent_acc_name_map = {}
- parent_acc_name = frappe.db.get_value('Account', self.parent_account, "account_name")
+ parent_acc_name, parent_acc_number = frappe.db.get_value('Account', self.parent_account, \
+ ["account_name", "account_number"])
for d in frappe.db.get_values('Account',
- {"company": ["in", descendants], "account_name": parent_acc_name},
+ { "company": ["in", descendants], "account_name": parent_acc_name,
+ "account_number": parent_acc_number },
["company", "name"], as_dict=True):
parent_acc_name_map[d["company"]] = d["name"]
-
if not parent_acc_name_map: return
- self.create_account_for_child_company(parent_acc_name_map, descendants)
+ self.create_account_for_child_company(parent_acc_name_map, descendants, parent_acc_name)
def validate_group_or_ledger(self):
if self.get("__islocal"):
@@ -159,7 +160,7 @@
if frappe.db.get_value("GL Entry", {"account": self.name}):
frappe.throw(_("Currency can not be changed after making entries using some other currency"))
- def create_account_for_child_company(self, parent_acc_name_map, descendants):
+ def create_account_for_child_company(self, parent_acc_name_map, descendants, parent_acc_name):
for company in descendants:
if not parent_acc_name_map.get(company):
frappe.throw(_("While creating account for child Company {0}, parent account {1} not found. Please create the parent account in corresponding COA")
diff --git a/erpnext/accounts/doctype/account/chart_of_accounts/verified/ae_uae_chart_template_standard.json b/erpnext/accounts/doctype/account/chart_of_accounts/verified/ae_uae_chart_template_standard.json
index 8856c8c..a8afb55 100644
--- a/erpnext/accounts/doctype/account/chart_of_accounts/verified/ae_uae_chart_template_standard.json
+++ b/erpnext/accounts/doctype/account/chart_of_accounts/verified/ae_uae_chart_template_standard.json
@@ -1,465 +1,466 @@
{
- "country_code": "ae",
- "name": "U.A.E - Chart of Accounts",
+ "country_code": "ae",
+ "name": "U.A.E - Chart of Accounts",
"tree": {
"Assets": {
"Current Assets": {
"Accounts Receivable": {
"Corporate Credit Cards": {
"account_type": "Receivable"
- },
+ },
"Other Receivable": {
"Accrued Rebates Due from Suppliers": {
"account_type": "Receivable"
- },
+ },
"Accrued Income from Suppliers": {
"account_type": "Receivable"
- },
+ },
"Other Debtors": {
"account_type": "Receivable"
- },
+ },
"account_type": "Receivable"
- },
+ },
"Post Dated Cheques Received": {
"account_type": "Receivable"
- },
+ },
"Staff Receivable": {
"account_type": "Receivable"
- },
+ },
"Trade Receivable": {
"account_type": "Receivable"
- },
+ },
"Trade in Opening Fees": {
"account_type": "Receivable"
- },
+ },
"account_type": "Receivable"
- },
+ },
"Cash in Hand & Banks": {
"Banks": {
- "Bank Margin On LC & LG": {},
- "Banks Blocked Deposits": {},
- "Banks Call Deposit Accounts": {},
+ "Bank Margin On LC & LG": {},
+ "Banks Blocked Deposits": {},
+ "Banks Call Deposit Accounts": {},
"Banks Current Accounts": {
"account_type": "Bank"
- },
+ },
"account_type": "Bank"
- },
+ },
"Cash in Hand": {
"Cash in Safe": {
"Main Safe": {
"account_type": "Cash"
- },
+ },
"Main Safe - Foreign Currency": {
"account_type": "Cash"
}
- },
+ },
"Petty Cash": {
"Petty Cash - Administration": {
"account_type": "Cash"
- },
+ },
"Petty Cash - Others": {
"account_type": "Cash"
}
- },
+ },
"account_type": "Cash"
- },
+ },
"Cash in Transit": {
"Credit Cards": {
"Gateway Credit Cards": {
"account_type": "Bank"
- },
+ },
"Manual Visa & Master Cards": {
"account_type": "Bank"
- },
+ },
"PayPal Account": {
"account_type": "Bank"
- },
+ },
"Visa & Master Credit Cards": {
"account_type": "Bank"
}
}
}
- },
+ },
"Inventory": {
"Consigned Stock": {
- "Handling Difference in Inventory": {
- "account_type": "Stock Adjustment"
- },
+ "Handling Difference in Inventory": {},
"Items Delivered to Customs on temporary Base": {}
- },
+ },
"Stock in Hand": {
"account_type": "Stock"
}
- },
+ },
"Preliminary and Preoperating Expenses": {
"Preoperating Expenses": {}
- },
+ },
"Prepayments & Deposits": {
"Deposits": {
- "Deposit - Office Rent": {},
- "Deposit Others": {},
- "Deposit to Immigration (Visa)": {},
+ "Deposit - Office Rent": {},
+ "Deposit Others": {},
+ "Deposit to Immigration (Visa)": {},
"Deposits - Customs": {}
- },
+ },
"Prepaid Taxes": {
- "Sales Taxes Receivables": {},
+ "Sales Taxes Receivables": {},
"Withholding Tax Receivables": {}
- },
+ },
"Prepayments": {
- "Other Prepayments": {},
- "PrePaid Advertisement Expenses": {},
- "Prepaid Bank Guarantee": {},
- "Prepaid Consultancy Fees": {},
- "Prepaid Employees Housing": {},
- "Prepaid Finance charge for Loans": {},
- "Prepaid Legal Fees": {},
- "Prepaid License Fees": {},
- "Prepaid Life Insurance": {},
- "Prepaid Maintenance": {},
- "Prepaid Medical Insurance": {},
- "Prepaid Office Rent": {},
- "Prepaid Other Insurance": {},
- "Prepaid Schooling Fees": {},
- "Prepaid Site Hosting Fees": {},
+ "Other Prepayments": {},
+ "PrePaid Advertisement Expenses": {},
+ "Prepaid Bank Guarantee": {},
+ "Prepaid Consultancy Fees": {},
+ "Prepaid Employees Housing": {},
+ "Prepaid Finance charge for Loans": {},
+ "Prepaid Legal Fees": {},
+ "Prepaid License Fees": {},
+ "Prepaid Life Insurance": {},
+ "Prepaid Maintenance": {},
+ "Prepaid Medical Insurance": {},
+ "Prepaid Office Rent": {},
+ "Prepaid Other Insurance": {},
+ "Prepaid Schooling Fees": {},
+ "Prepaid Site Hosting Fees": {},
"Prepaid Sponsorship Fees": {}
}
}
- },
+ },
"Long Term Assets": {
"Fixed Assets": {
"Accumulated Depreciation": {
"Acc. Depreciation of Motor Vehicles": {
"account_type": "Accumulated Depreciation"
- },
+ },
"Acc. Deprn.Computer Hardware & Software": {
"account_type": "Accumulated Depreciation"
- },
+ },
"Acc.Deprn.of Furniture & Office Equipment": {
"account_type": "Accumulated Depreciation"
- },
+ },
"Amortisation on Leasehold Improvement": {
"account_type": "Accumulated Depreciation"
- },
+ },
"account_type": "Accumulated Depreciation"
- },
+ },
"Fixed Assets (Cost Price)": {
"Computer Hardware & Software": {
"account_type": "Fixed Asset"
- },
+ },
"Furniture and Equipment": {
"account_type": "Fixed Asset"
- },
- "Leasehold Improvement": {},
+ },
+ "Leasehold Improvement": {},
"Motor Vehicles": {
"account_type": "Fixed Asset"
- },
- "Work In Progress": {},
+ },
+ "Work In Progress": {},
"account_type": "Fixed Asset"
}
- },
+ },
"Intangible Assets": {
- "Computer Card Renewal": {},
- "Disposal of Outlets": {},
+ "Computer Card Renewal": {},
+ "Disposal of Outlets": {},
"Registration of Trademarks": {}
- },
- "Intercompany Accounts": {},
+ },
+ "Intercompany Accounts": {},
"Investments": {
"Investments in Subsidiaries": {}
}
- },
+ },
"root_type": "Asset"
- },
+ },
"Closing And Temporary Accounts": {
"Closing Accounts": {
"Closing Account": {}
- },
+ },
"root_type": "Liability"
- },
+ },
"Expenses": {
"Commercial Expenses": {
- "Consultancy Fees": {},
+ "Consultancy Fees": {},
"Provision for Doubtful Debts": {}
- },
+ },
"Cost of Sale": {
"Cost Of Goods Sold": {
- "Cost Of Goods Sold I/C Sales": {},
+ "Cost Of Goods Sold I/C Sales": {},
"Cost of Goods Sold in Trading": {
"account_type": "Cost of Goods Sold"
- },
+ },
"account_type": "Cost of Goods Sold"
- },
+ },
"Expenses Included In Valuation": {
"account_type": "Expenses Included In Valuation"
+ },
+ "Stock Adjustment": {
+ "account_type": "Stock Adjustment"
}
- },
+ },
"Depreciation": {
"Depreciation & Amortization": {
- "Amortization on Leasehold Improvement": {},
+ "Amortization on Leasehold Improvement": {},
"Depreciation Of Computer Hard & Soft": {
"account_type": "Depreciation"
- },
+ },
"Depreciation Of Furniture & Office Equipment\n\t\t\t": {
"account_type": "Depreciation"
- },
+ },
"Depreciation Of Motor Vehicles": {
"account_type": "Depreciation"
}
}
- },
+ },
"Direct Expenses": {
"Financial Charges": {
- "Air Miles Card Charges": {},
- "Amex Credit Cards Charges": {},
- "Bank Finance & Loan Charges": {},
- "Credit Card Charges": {},
- "Credit Card Swipe Charges": {},
+ "Air Miles Card Charges": {},
+ "Amex Credit Cards Charges": {},
+ "Bank Finance & Loan Charges": {},
+ "Credit Card Charges": {},
+ "Credit Card Swipe Charges": {},
"PayPal Charges": {}
}
- },
+ },
"MISC Charges": {
"Other Charges": {
"Capital Loss": {
- "Disposal of Business Branch": {},
- "Loss On Fixed Assets Disposal": {},
+ "Disposal of Business Branch": {},
+ "Loss On Fixed Assets Disposal": {},
"Loss on Difference on Exchange": {}
- },
+ },
"Other Non Operating Exp": {
"Other Non Operating Expenses": {}
- },
+ },
"Previous Year Adjustments": {
"Previous Year Adjustments Account": {}
- },
+ },
"Royalty Fees": {
"Royalty to Parent Co.": {}
- },
+ },
"Tax / Zakat Expenses": {
"Income Tax": {
"account_type": "Tax"
- },
- "Zakat": {},
+ },
+ "Zakat": {},
"account_type": "Tax"
}
}
- },
+ },
"Share Resources": {
"Share Resource Expenses Account": {}
- },
+ },
"Store Operating Expenses": {
"Selling, General & Admin Expenses": {
"Advertising Expenses": {
"Other - Advertising Expenses": {}
- },
+ },
"Bank & Finance Charges": {
"Other Bank Charges": {}
- },
+ },
"Communications": {
- "Courier": {},
- "Others - Communication": {},
- "Telephone": {},
+ "Courier": {},
+ "Others - Communication": {},
+ "Telephone": {},
"Web Site Hosting Fees": {}
- },
+ },
"Office & Various Expenses": {
- "Cleaning": {},
- "Conveyance Expenses": {},
- "Gifts & Donations": {},
- "Insurance": {},
- "Kitchen and Buffet Expenses": {},
- "Maintenance": {},
- "Others - Office Various Expenses": {},
- "Security & Guard": {},
- "Stationary From Suppliers": {},
- "Stationary Out Of Stock": {},
- "Subscriptions": {},
- "Training": {},
+ "Cleaning": {},
+ "Conveyance Expenses": {},
+ "Gifts & Donations": {},
+ "Insurance": {},
+ "Kitchen and Buffet Expenses": {},
+ "Maintenance": {},
+ "Others - Office Various Expenses": {},
+ "Security & Guard": {},
+ "Stationary From Suppliers": {},
+ "Stationary Out Of Stock": {},
+ "Subscriptions": {},
+ "Training": {},
"Vehicle Expenses": {}
- },
+ },
"Personnel Cost": {
- "Basic Salary": {},
- "End Of Service Indemnity": {},
- "Housing Allowance": {},
- "Leave Salary": {},
- "Leave Ticket": {},
- "Life Insurance": {},
- "Medical Insurance": {},
- "Personnel Cost Others": {},
- "Sales Commission": {},
- "Staff School Allowances": {},
- "Transportation Allowance": {},
- "Uniform": {},
+ "Basic Salary": {},
+ "End Of Service Indemnity": {},
+ "Housing Allowance": {},
+ "Leave Salary": {},
+ "Leave Ticket": {},
+ "Life Insurance": {},
+ "Medical Insurance": {},
+ "Personnel Cost Others": {},
+ "Sales Commission": {},
+ "Staff School Allowances": {},
+ "Transportation Allowance": {},
+ "Uniform": {},
"Visa Expenses": {}
- },
+ },
"Professional & Legal Fees": {
- "Audit Fees": {},
- "Legal fees": {},
- "Others - Professional Fees": {},
- "Sponsorship Fees": {},
+ "Audit Fees": {},
+ "Legal fees": {},
+ "Others - Professional Fees": {},
+ "Sponsorship Fees": {},
"Trade License Fees": {}
- },
+ },
"Provision & Write Off": {
- "Amortisation of Preoperating Expenses": {},
- "Cash Shortage": {},
- "Others - Provision & Write off": {},
- "Write Off Inventory": {},
+ "Amortisation of Preoperating Expenses": {},
+ "Cash Shortage": {},
+ "Others - Provision & Write off": {},
+ "Write Off Inventory": {},
"Write Off Receivables & Payables": {}
- },
+ },
"Rent Expenses": {
- "Office Rent": {},
+ "Office Rent": {},
"Warehouse Rent": {}
- },
+ },
"Travel Expenses": {
- "Air tickets": {},
- "Hotel": {},
- "Meals": {},
- "Others": {},
+ "Air tickets": {},
+ "Hotel": {},
+ "Meals": {},
+ "Others": {},
"Per Diem": {}
- },
+ },
"Utilities": {
- "Other Utility Cahrges": {},
+ "Other Utility Cahrges": {},
"Water & Electricity": {}
}
}
- },
+ },
"root_type": "Expense"
- },
+ },
"Liabilities": {
"Current Liabilities": {
"Accounts Payable": {
"Payables": {
"Advance Payable to Suppliers": {
"account_type": "Payable"
- },
+ },
"Consigned Payable": {
"account_type": "Payable"
- },
+ },
"Other Payable": {
"account_type": "Payable"
- },
+ },
"Post Dated Cheques Paid": {
"account_type": "Payable"
- },
- "Staff Payable": {},
+ },
+ "Staff Payable": {},
"Suppliers Price Protection": {
"account_type": "Payable"
- },
+ },
"Trade Payable": {
"account_type": "Payable"
- },
+ },
"account_type": "Payable"
}
- },
+ },
"Accruals & Provisions": {
"Accruals": {
"Accrued Personnel Cost": {
- "Accrued - Commissions": {},
- "Accrued - Leave Salary": {},
- "Accrued - Leave Tickets": {},
- "Accrued - Salaries": {},
- "Accrued Other Personnel Cost": {},
- "Accrued Salaries Increment": {},
+ "Accrued - Commissions": {},
+ "Accrued - Leave Salary": {},
+ "Accrued - Leave Tickets": {},
+ "Accrued - Salaries": {},
+ "Accrued Other Personnel Cost": {},
+ "Accrued Salaries Increment": {},
"Accrued-Staff Bonus": {}
}
- },
+ },
"Accrued Expenses": {
"Accrued Other Expenses": {
- "Accrued - Audit Fees": {},
- "Accrued - Office Rent": {},
- "Accrued - Sponsorship": {},
- "Accrued - Telephone": {},
- "Accrued - Utilities": {},
+ "Accrued - Audit Fees": {},
+ "Accrued - Office Rent": {},
+ "Accrued - Sponsorship": {},
+ "Accrued - Telephone": {},
+ "Accrued - Utilities": {},
"Accrued Others": {}
}
- },
+ },
"Other Current Liabilities": {
- "Accrued Dubai Customs": {},
- "Deferred income": {},
+ "Accrued Dubai Customs": {},
+ "Deferred income": {},
"Shipping & Handling": {}
- },
+ },
"Provisions": {
"Tax Payables": {
- "Income Tax Payable": {},
- "Sales Tax Payable": {},
+ "Income Tax Payable": {},
+ "Sales Tax Payable": {},
"Withholding Tax Payable": {}
}
- },
+ },
"Short Term Loan": {}
- },
+ },
"Duties and Taxes": {
- "account_type": "Tax",
+ "account_type": "Tax",
"is_group": 1
- },
+ },
"Reservations & Credit Notes": {
"Credit Notes": {
- "Credit Notes to Customers": {},
+ "Credit Notes to Customers": {},
"Reservations": {}
}
- },
+ },
"Stock Liabilities": {
"Stock Received But Not Billed": {
"account_type": "Stock Received But Not Billed"
}
- },
+ },
"Unearned Income": {}
- },
+ },
"Long Term Liabilities": {
"Long Term Loans & Provisions": {}
- },
+ },
"root_type": "Liability"
- },
+ },
"Revenue": {
"Direct Revenue": {
"Other Direct Revenue": {
"Other Revenue - Operating": {
- "Advertising Income": {},
- "Branding Income": {},
- "Early Setmt Margin from Suppliers": {},
- "Marketing Rebate from Suppliers": {},
- "Rebate from Suppliers": {},
- "Service Income": {},
+ "Advertising Income": {},
+ "Branding Income": {},
+ "Early Setmt Margin from Suppliers": {},
+ "Marketing Rebate from Suppliers": {},
+ "Rebate from Suppliers": {},
+ "Service Income": {},
"Space Rental Income": {}
}
}
- },
+ },
"Indirect Revenue": {
"Other Indirect Revenue": {
- "Capital Gain": {},
- "Excess In Till": {},
- "Gain On Difference Of Exchange": {},
- "Management Consultancy Fees": {},
+ "Capital Gain": {},
+ "Excess In Till": {},
+ "Gain On Difference Of Exchange": {},
+ "Management Consultancy Fees": {},
"Other Income": {}
- },
+ },
"Other Revenue - Non Operating": {
- "Interest Revenue": {},
- "Interest from FD": {},
- "Products Listing Fees from Suppliers": {},
+ "Interest Revenue": {},
+ "Interest from FD": {},
+ "Products Listing Fees from Suppliers": {},
"Trade Opening Fees from suppliers": {}
}
- },
+ },
"Sales": {
"Sales from Other Regions": {
"Sales from Other Region": {}
- },
+ },
"Sales of same region": {
- "Management Consultancy Fees 1": {},
- "Sales Account": {},
+ "Management Consultancy Fees 1": {},
+ "Sales Account": {},
"Sales of I/C": {}
}
- },
+ },
"root_type": "Income"
- },
+ },
"Share Holder Equity": {
"Capital": {
- "Contributed Capital": {},
- "Share Capital": {},
- "Shareholders Current A/c": {},
- "Sub Ordinated Loan": {},
+ "Contributed Capital": {},
+ "Share Capital": {},
+ "Shareholders Current A/c": {},
+ "Sub Ordinated Loan": {},
"Treasury Stocks": {}
- },
+ },
"Retained Earnings": {
- "Current Year Results": {},
- "Dividends Paid": {},
+ "Current Year Results": {},
+ "Dividends Paid": {},
"Previous Years Results": {}
- },
- "account_type": "Equity",
+ },
+ "account_type": "Equity",
"root_type": "Equity"
}
}
diff --git a/erpnext/accounts/doctype/account/test_account.py b/erpnext/accounts/doctype/account/test_account.py
index 4ee5573..dc23b2b 100644
--- a/erpnext/accounts/doctype/account/test_account.py
+++ b/erpnext/accounts/doctype/account/test_account.py
@@ -160,7 +160,7 @@
["_Test Payable USD", "Current Liabilities", 0, "Payable", "USD"]
]
- for company, abbr in [["_Test Company", "_TC"], ["_Test Company 1", "_TC1"]]:
+ for company, abbr in [["_Test Company", "_TC"], ["_Test Company 1", "_TC1"], ["_Test Company with perpetual inventory", "TCP1"]]:
test_objects = make_test_objects("Account", [{
"doctype": "Account",
"account_name": account_name,
diff --git a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py
index af51fc5..522ed4f 100644
--- a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py
+++ b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py
@@ -24,6 +24,11 @@
msg = _("Not allowed to create accounting dimension for {0}").format(self.document_type)
frappe.throw(msg)
+ exists = frappe.db.get_value("Accounting Dimension", {'document_type': self.document_type}, ['name'])
+
+ if exists and self.is_new():
+ frappe.throw("Document Type already used as a dimension")
+
def after_insert(self):
if frappe.flags.in_test:
make_dimension_in_accounting_doctypes(doc=self)
@@ -60,7 +65,8 @@
"label": doc.label,
"fieldtype": "Link",
"options": doc.document_type,
- "insert_after": insert_after_field
+ "insert_after": insert_after_field,
+ "owner": "Administrator"
}
if doctype == "Budget":
diff --git a/erpnext/accounts/doctype/accounting_period/accounting_period.py b/erpnext/accounts/doctype/accounting_period/accounting_period.py
index 180460c..f48d6df 100644
--- a/erpnext/accounts/doctype/accounting_period/accounting_period.py
+++ b/erpnext/accounts/doctype/accounting_period/accounting_period.py
@@ -41,8 +41,8 @@
def get_doctypes_for_closing(self):
docs_for_closing = []
- doctypes = ["Sales Invoice", "Purchase Invoice", "Journal Entry", "Payroll Entry", "Bank Reconciliation",
- "Asset", "Purchase Order", "Sales Order", "Leave Application", "Leave Allocation", "Stock Entry"]
+ doctypes = ["Sales Invoice", "Purchase Invoice", "Journal Entry", "Payroll Entry", \
+ "Bank Reconciliation", "Asset", "Stock Entry"]
closed_doctypes = [{"document_type": doctype, "closed": 1} for doctype in doctypes]
for closed_doctype in closed_doctypes:
docs_for_closing.append(closed_doctype)
diff --git a/erpnext/accounts/doctype/accounts_settings/accounts_settings.py b/erpnext/accounts/doctype/accounts_settings/accounts_settings.py
index 3222aeb..2473d71 100644
--- a/erpnext/accounts/doctype/accounts_settings/accounts_settings.py
+++ b/erpnext/accounts/doctype/accounts_settings/accounts_settings.py
@@ -15,8 +15,8 @@
frappe.clear_cache()
def validate(self):
- for f in ["add_taxes_from_item_tax_template"]:
- frappe.db.set_default(f, self.get(f, ""))
+ frappe.db.set_default("add_taxes_from_item_tax_template",
+ self.get("add_taxes_from_item_tax_template", 0))
self.validate_stale_days()
self.enable_payment_schedule_in_print()
diff --git a/erpnext/accounts/doctype/bank_transaction/bank_transaction_upload.py b/erpnext/accounts/doctype/bank_transaction/bank_transaction_upload.py
index deedafd..33ae454 100644
--- a/erpnext/accounts/doctype/bank_transaction/bank_transaction_upload.py
+++ b/erpnext/accounts/doctype/bank_transaction/bank_transaction_upload.py
@@ -15,8 +15,8 @@
with open(frappe.uploaded_file, "rb") as upfile:
fcontent = upfile.read()
else:
- from frappe.utils.file_manager import get_uploaded_content
- fname, fcontent = get_uploaded_content()
+ fcontent = frappe.local.uploaded_file
+ fname = frappe.local.uploaded_filename
if frappe.safe_encode(fname).lower().endswith("csv".encode('utf-8')):
from frappe.utils.csvutils import read_csv_content
diff --git a/erpnext/accounts/doctype/chart_of_accounts_importer/chart_of_accounts_importer.py b/erpnext/accounts/doctype/chart_of_accounts_importer/chart_of_accounts_importer.py
index 9bf5887..34070b0 100644
--- a/erpnext/accounts/doctype/chart_of_accounts_importer/chart_of_accounts_importer.py
+++ b/erpnext/accounts/doctype/chart_of_accounts_importer/chart_of_accounts_importer.py
@@ -185,7 +185,8 @@
return _("Please identify/create Account (Ledger) for type - {0}").format(' , '.join(missing))
account_types_for_group = ["Bank", "Cash", "Stock"]
- account_groups = [accounts[d]["account_type"] for d in accounts if accounts[d]['is_group'] not in ('', 1)]
+ # fix logic bug
+ account_groups = [accounts[d]["account_type"] for d in accounts if accounts[d]['is_group'] == 1]
missing = list(set(account_types_for_group) - set(account_groups))
if missing:
diff --git a/erpnext/accounts/doctype/cost_center/cost_center.py b/erpnext/accounts/doctype/cost_center/cost_center.py
index 584e11c..0294e78 100644
--- a/erpnext/accounts/doctype/cost_center/cost_center.py
+++ b/erpnext/accounts/doctype/cost_center/cost_center.py
@@ -18,6 +18,7 @@
def validate(self):
self.validate_mandatory()
+ self.validate_parent_cost_center()
def validate_mandatory(self):
if self.cost_center_name != self.company and not self.parent_cost_center:
@@ -25,6 +26,12 @@
elif self.cost_center_name == self.company and self.parent_cost_center:
frappe.throw(_("Root cannot have a parent cost center"))
+ def validate_parent_cost_center(self):
+ if self.parent_cost_center:
+ if not frappe.db.get_value('Cost Center', self.parent_cost_center, 'is_group'):
+ frappe.throw(_("{0} is not a group node. Please select a group node as parent cost center").format(
+ frappe.bold(self.parent_cost_center)))
+
def convert_group_to_ledger(self):
if self.check_if_child_exists():
frappe.throw(_("Cannot convert Cost Center to ledger as it has child nodes"))
diff --git a/erpnext/accounts/doctype/cost_center/test_cost_center.py b/erpnext/accounts/doctype/cost_center/test_cost_center.py
index c4fad75..8f23d90 100644
--- a/erpnext/accounts/doctype/cost_center/test_cost_center.py
+++ b/erpnext/accounts/doctype/cost_center/test_cost_center.py
@@ -1,12 +1,26 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-
-
+import unittest
import frappe
+
test_records = frappe.get_test_records('Cost Center')
+class TestCostCenter(unittest.TestCase):
+ def test_cost_center_creation_against_child_node(self):
+ if not frappe.db.get_value('Cost Center', {'name': '_Test Cost Center 2 - _TC'}):
+ frappe.get_doc(test_records[1]).insert()
+
+ cost_center = frappe.get_doc({
+ 'doctype': 'Cost Center',
+ 'cost_center_name': '_Test Cost Center 3',
+ 'parent_cost_center': '_Test Cost Center 2 - _TC',
+ 'is_group': 0,
+ 'company': '_Test Company'
+ })
+
+ self.assertRaises(frappe.ValidationError, cost_center.save)
def create_cost_center(**args):
args = frappe._dict(args)
diff --git a/erpnext/accounts/doctype/coupon_code/coupon_code.js b/erpnext/accounts/doctype/coupon_code/coupon_code.js
index 0bf097f..da3a9f8 100644
--- a/erpnext/accounts/doctype/coupon_code/coupon_code.js
+++ b/erpnext/accounts/doctype/coupon_code/coupon_code.js
@@ -2,6 +2,15 @@
// For license information, please see license.txt
frappe.ui.form.on('Coupon Code', {
+ setup: function(frm) {
+ frm.set_query("pricing_rule", function() {
+ return {
+ filters: [
+ ["Pricing Rule","coupon_code_based", "=", "1"]
+ ]
+ };
+ });
+ },
coupon_name:function(frm){
if (frm.doc.__islocal===1) {
frm.trigger("make_coupon_code");
diff --git a/erpnext/accounts/doctype/coupon_code/coupon_code.json b/erpnext/accounts/doctype/coupon_code/coupon_code.json
index fafc635..7dc5e9d 100644
--- a/erpnext/accounts/doctype/coupon_code/coupon_code.json
+++ b/erpnext/accounts/doctype/coupon_code/coupon_code.json
@@ -24,6 +24,7 @@
],
"fields": [
{
+ "description": "e.g. \"Summer Holiday 2019 Offer 20\"",
"fieldname": "coupon_name",
"fieldtype": "Data",
"label": "Coupon Name",
@@ -50,7 +51,7 @@
"fieldtype": "Column Break"
},
{
- "description": "To be used to get discount",
+ "description": "unique e.g. SAVE20 To be used to get discount",
"fieldname": "coupon_code",
"fieldtype": "Data",
"label": "Coupon Code",
@@ -62,12 +63,13 @@
"fieldname": "pricing_rule",
"fieldtype": "Link",
"label": "Pricing Rule",
- "options": "Pricing Rule"
+ "options": "Pricing Rule",
+ "reqd": 1
},
{
"fieldname": "uses",
"fieldtype": "Section Break",
- "label": "Uses"
+ "label": "Validity and Usage"
},
{
"fieldname": "valid_from",
@@ -113,7 +115,7 @@
"read_only": 1
}
],
- "modified": "2019-10-15 14:12:22.686986",
+ "modified": "2019-10-19 14:48:14.602481",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Coupon Code",
diff --git a/erpnext/accounts/doctype/gl_entry/gl_entry.py b/erpnext/accounts/doctype/gl_entry/gl_entry.py
index 078e058..041e419 100644
--- a/erpnext/accounts/doctype/gl_entry/gl_entry.py
+++ b/erpnext/accounts/doctype/gl_entry/gl_entry.py
@@ -29,7 +29,6 @@
self.validate_and_set_fiscal_year()
self.pl_must_have_cost_center()
self.validate_cost_center()
- self.validate_dimensions_for_pl_and_bs()
if not self.flags.from_repost:
self.check_pl_account()
@@ -39,6 +38,7 @@
def on_update_with_args(self, adv_adj, update_outstanding = 'Yes', from_repost=False):
if not from_repost:
self.validate_account_details(adv_adj)
+ self.validate_dimensions_for_pl_and_bs()
check_freezing_date(self.posting_date, adv_adj)
validate_frozen_account(self.account, adv_adj)
diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.js b/erpnext/accounts/doctype/journal_entry/journal_entry.js
index 11d847d..3604b60 100644
--- a/erpnext/accounts/doctype/journal_entry/journal_entry.js
+++ b/erpnext/accounts/doctype/journal_entry/journal_entry.js
@@ -190,7 +190,6 @@
if(jvd.reference_type==="Employee Advance") {
return {
filters: {
- 'status': ['=', 'Unpaid'],
'docstatus': 1
}
};
@@ -398,7 +397,7 @@
method: "erpnext.accounts.doctype.journal_entry.journal_entry.get_default_bank_cash_account",
args: {
"account_type": (doc.voucher_type=="Bank Entry" ?
- "Bank" : (doc.voucher_type=="Cash" ? "Cash" : null)),
+ "Bank" : (doc.voucher_type=="Cash Entry" ? "Cash" : null)),
"company": doc.company
},
callback: function(r) {
@@ -570,7 +569,7 @@
},
{fieldtype: "Date", fieldname: "posting_date", label: __("Date"), reqd: 1,
default: frm.doc.posting_date},
- {fieldtype: "Small Text", fieldname: "user_remark", label: __("User Remark"), reqd: 1},
+ {fieldtype: "Small Text", fieldname: "user_remark", label: __("User Remark")},
{fieldtype: "Select", fieldname: "naming_series", label: __("Series"), reqd: 1,
options: naming_series_options, default: naming_series_default},
]
diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py
index e25942c..8897337 100644
--- a/erpnext/accounts/doctype/journal_entry/journal_entry.py
+++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py
@@ -968,7 +968,7 @@
# The date used to retreive the exchange rate here is the date passed
# in as an argument to this function.
- elif (not exchange_rate or exchange_rate==1) and account_currency and posting_date:
+ elif (not exchange_rate or flt(exchange_rate)==1) and account_currency and posting_date:
exchange_rate = get_exchange_rate(account_currency, company_currency, posting_date)
else:
exchange_rate = 1
diff --git a/erpnext/accounts/doctype/journal_entry_account/journal_entry_account.json b/erpnext/accounts/doctype/journal_entry_account/journal_entry_account.json
index ab811d8..c3f95fa 100644
--- a/erpnext/accounts/doctype/journal_entry_account/journal_entry_account.json
+++ b/erpnext/accounts/doctype/journal_entry_account/journal_entry_account.json
@@ -201,7 +201,7 @@
"fieldname": "reference_type",
"fieldtype": "Select",
"label": "Reference Type",
- "options": "\nSales Invoice\nPurchase Invoice\nJournal Entry\nSales Order\nPurchase Order\nExpense Claim\nAsset\nLoan\nPayroll Entry\nEmployee Advance\nExchange Rate Revaluation\nInvoice Discounting"
+ "options": "\nSales Invoice\nPurchase Invoice\nJournal Entry\nSales Order\nPurchase Order\nExpense Claim\nAsset\nLoan\nPayroll Entry\nEmployee Advance\nExchange Rate Revaluation\nInvoice Discounting\nFees"
},
{
"fieldname": "reference_name",
@@ -281,4 +281,4 @@
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
-}
\ No newline at end of file
+}
diff --git a/erpnext/accounts/doctype/loyalty_program/test_loyalty_program.py b/erpnext/accounts/doctype/loyalty_program/test_loyalty_program.py
index 4a7406e..341884c 100644
--- a/erpnext/accounts/doctype/loyalty_program/test_loyalty_program.py
+++ b/erpnext/accounts/doctype/loyalty_program/test_loyalty_program.py
@@ -8,10 +8,12 @@
from frappe.utils import today, cint, flt, getdate
from erpnext.accounts.doctype.loyalty_program.loyalty_program import get_loyalty_program_details_with_points
from erpnext.accounts.party import get_dashboard_info
+from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory
class TestLoyaltyProgram(unittest.TestCase):
@classmethod
def setUpClass(self):
+ set_perpetual_inventory(0)
# create relevant item, customer, loyalty program, etc
create_records()
diff --git a/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py b/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py
index ce8aba7..54464e7 100644
--- a/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py
+++ b/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py
@@ -32,8 +32,10 @@
})
invoices_summary.update({company: _summary})
- paid_amount.append(invoice.paid_amount)
- outstanding_amount.append(invoice.outstanding_amount)
+ if invoice.paid_amount:
+ paid_amount.append(invoice.paid_amount)
+ if invoice.outstanding_amount:
+ outstanding_amount.append(invoice.outstanding_amount)
if paid_amount or outstanding_amount:
max_count.update({
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.js b/erpnext/accounts/doctype/payment_entry/payment_entry.js
index 1e0b1bc..2192b7b 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.js
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.js
@@ -554,7 +554,7 @@
frappe.flags.allocate_payment_amount = true;
frm.events.validate_filters_data(frm, filters);
frm.events.get_outstanding_documents(frm, filters);
- }, __("Filters"), __("Get Outstanding Invoices"));
+ }, __("Filters"), __("Get Outstanding Documents"));
},
validate_filters_data: function(frm, filters) {
@@ -652,14 +652,16 @@
(frm.doc.payment_type=="Receive" && frm.doc.party_type=="Student")
) {
if(total_positive_outstanding > total_negative_outstanding)
- frm.set_value("paid_amount",
- total_positive_outstanding - total_negative_outstanding);
+ if (!frm.doc.paid_amount)
+ frm.set_value("paid_amount",
+ total_positive_outstanding - total_negative_outstanding);
} else if (
total_negative_outstanding &&
total_positive_outstanding < total_negative_outstanding
) {
- frm.set_value("received_amount",
- total_negative_outstanding - total_positive_outstanding);
+ if (!frm.doc.received_amount)
+ frm.set_value("received_amount",
+ total_negative_outstanding - total_positive_outstanding);
}
}
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.json b/erpnext/accounts/doctype/payment_entry/payment_entry.json
index a85eccd..9979377 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.json
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.json
@@ -62,6 +62,7 @@
"dimension_col_break",
"cost_center",
"section_break_12",
+ "status",
"remarks",
"column_break_16",
"letter_head",
@@ -331,6 +332,7 @@
"label": "Reference"
},
{
+ "depends_on": "eval:doc.docstatus==0",
"fieldname": "get_outstanding_invoice",
"fieldtype": "Button",
"label": "Get Outstanding Invoice"
@@ -563,10 +565,18 @@
{
"fieldname": "dimension_col_break",
"fieldtype": "Column Break"
+ },
+ {
+ "default": "Draft",
+ "fieldname": "status",
+ "fieldtype": "Select",
+ "label": "Status",
+ "options": "\nDraft\nSubmitted\nCancelled",
+ "read_only": 1
}
],
"is_submittable": 1,
- "modified": "2019-05-27 15:53:21.108857",
+ "modified": "2019-12-08 13:02:30.016610",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Payment Entry",
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py
index 89aaffb..214d608 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.py
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py
@@ -61,6 +61,7 @@
self.validate_duplicate_entry()
self.validate_allocated_amount()
self.ensure_supplier_is_not_blocked()
+ self.set_status()
def on_submit(self):
self.setup_party_account_field()
@@ -70,6 +71,7 @@
self.update_outstanding_amounts()
self.update_advance_paid()
self.update_expense_claim()
+ self.set_status()
def on_cancel(self):
@@ -79,6 +81,7 @@
self.update_advance_paid()
self.update_expense_claim()
self.delink_advance_entry_references()
+ self.set_status()
def update_outstanding_amounts(self):
self.set_missing_ref_details(force=True)
@@ -275,6 +278,14 @@
frappe.throw(_("Against Journal Entry {0} does not have any unmatched {1} entry")
.format(d.reference_name, dr_or_cr))
+ def set_status(self):
+ if self.docstatus == 2:
+ self.status = 'Cancelled'
+ elif self.docstatus == 1:
+ self.status = 'Submitted'
+ else:
+ self.status = 'Draft'
+
def set_amounts(self):
self.set_amounts_in_company_currency()
self.set_total_allocated_amount()
@@ -900,7 +911,10 @@
else:
party_account = get_party_account(party_type, doc.get(party_type.lower()), doc.company)
- party_account_currency = doc.get("party_account_currency") or get_account_currency(party_account)
+ if dt not in ("Sales Invoice", "Purchase Invoice"):
+ party_account_currency = get_account_currency(party_account)
+ else:
+ party_account_currency = doc.get("party_account_currency") or get_account_currency(party_account)
# payment type
if (dt == "Sales Order" or (dt in ("Sales Invoice", "Fees") and doc.outstanding_amount > 0)) \
@@ -920,9 +934,9 @@
grand_total = doc.rounded_total or doc.grand_total
outstanding_amount = doc.outstanding_amount
elif dt in ("Expense Claim"):
- grand_total = doc.total_sanctioned_amount
- outstanding_amount = doc.total_sanctioned_amount \
- - doc.total_amount_reimbursed - flt(doc.total_advance_amount)
+ grand_total = doc.total_sanctioned_amount + doc.total_taxes_and_charges
+ outstanding_amount = doc.grand_total \
+ - doc.total_amount_reimbursed
elif dt == "Employee Advance":
grand_total = doc.advance_amount
outstanding_amount = flt(doc.advance_amount) - flt(doc.paid_amount)
diff --git a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
index 4665d75..2c04a27 100644
--- a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
+++ b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
@@ -23,6 +23,8 @@
if self.party_type in ["Customer", "Supplier"]:
dr_or_cr_notes = self.get_dr_or_cr_notes()
+ else:
+ dr_or_cr_notes = []
self.add_payment_entries(payment_entries + journal_entries + dr_or_cr_notes)
@@ -90,7 +92,8 @@
FROM `tab{doc}`, `tabGL Entry`
WHERE
(`tab{doc}`.name = `tabGL Entry`.against_voucher or `tab{doc}`.name = `tabGL Entry`.voucher_no)
- and `tab{doc}`.is_return = 1 and `tabGL Entry`.against_voucher_type = %(voucher_type)s
+ and `tab{doc}`.is_return = 1 and `tab{doc}`.return_against IS NULL
+ and `tabGL Entry`.against_voucher_type = %(voucher_type)s
and `tab{doc}`.docstatus = 1 and `tabGL Entry`.party = %(party)s
and `tabGL Entry`.party_type = %(party_type)s and `tabGL Entry`.account = %(account)s
GROUP BY `tab{doc}`.name
diff --git a/erpnext/accounts/doctype/payment_request/payment_request.js b/erpnext/accounts/doctype/payment_request/payment_request.js
index e2510f6..e1e4314 100644
--- a/erpnext/accounts/doctype/payment_request/payment_request.js
+++ b/erpnext/accounts/doctype/payment_request/payment_request.js
@@ -2,6 +2,16 @@
cur_frm.add_fetch("payment_gateway_account", "payment_gateway", "payment_gateway")
cur_frm.add_fetch("payment_gateway_account", "message", "message")
+frappe.ui.form.on("Payment Request", {
+ setup: function(frm) {
+ frm.set_query("party_type", function() {
+ return {
+ query: "erpnext.setup.doctype.party_type.party_type.get_party_type",
+ };
+ });
+ }
+})
+
frappe.ui.form.on("Payment Request", "onload", function(frm, dt, dn){
if (frm.doc.reference_doctype) {
frappe.call({
diff --git a/erpnext/accounts/doctype/payment_request/payment_request.py b/erpnext/accounts/doctype/payment_request/payment_request.py
index eda59ab..6133b1c 100644
--- a/erpnext/accounts/doctype/payment_request/payment_request.py
+++ b/erpnext/accounts/doctype/payment_request/payment_request.py
@@ -350,13 +350,13 @@
if dt in ["Sales Order", "Purchase Order"]:
grand_total = flt(ref_doc.grand_total) - flt(ref_doc.advance_paid)
- if dt in ["Sales Invoice", "Purchase Invoice"]:
+ elif dt in ["Sales Invoice", "Purchase Invoice"]:
if ref_doc.party_account_currency == ref_doc.currency:
grand_total = flt(ref_doc.outstanding_amount)
else:
grand_total = flt(ref_doc.outstanding_amount) / ref_doc.conversion_rate
- if dt == "Fees":
+ elif dt == "Fees":
grand_total = ref_doc.outstanding_amount
if grand_total > 0 :
diff --git a/erpnext/assets/doctype/asset_settings/__init__.py b/erpnext/accounts/doctype/pos_field/__init__.py
similarity index 100%
copy from erpnext/assets/doctype/asset_settings/__init__.py
copy to erpnext/accounts/doctype/pos_field/__init__.py
diff --git a/erpnext/accounts/doctype/pos_field/pos_field.json b/erpnext/accounts/doctype/pos_field/pos_field.json
new file mode 100644
index 0000000..13edabd
--- /dev/null
+++ b/erpnext/accounts/doctype/pos_field/pos_field.json
@@ -0,0 +1,77 @@
+{
+ "creation": "2019-08-22 14:35:39.043242",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "fieldname",
+ "label",
+ "fieldtype",
+ "column_break_7",
+ "options",
+ "default_value",
+ "reqd",
+ "read_only"
+ ],
+ "fields": [
+ {
+ "fieldname": "fieldname",
+ "fieldtype": "Select",
+ "in_list_view": 1,
+ "label": "Fieldname"
+ },
+ {
+ "fieldname": "fieldtype",
+ "fieldtype": "Data",
+ "in_list_view": 1,
+ "label": "Fieldtype",
+ "read_only": 1
+ },
+ {
+ "fieldname": "label",
+ "fieldtype": "Data",
+ "in_list_view": 1,
+ "label": "Label",
+ "read_only": 1
+ },
+ {
+ "fieldname": "options",
+ "fieldtype": "Text",
+ "in_list_view": 1,
+ "label": "Options",
+ "read_only": 1
+ },
+ {
+ "default": "0",
+ "fieldname": "reqd",
+ "fieldtype": "Check",
+ "label": "Mandatory"
+ },
+ {
+ "default": "0",
+ "fieldname": "read_only",
+ "fieldtype": "Check",
+ "label": "Read Only"
+ },
+ {
+ "fieldname": "column_break_7",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "default_value",
+ "fieldtype": "Data",
+ "label": "Default Value"
+ }
+ ],
+ "istable": 1,
+ "modified": "2019-08-23 13:59:34.025523",
+ "modified_by": "Administrator",
+ "module": "Accounts",
+ "name": "POS Field",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/assets/doctype/asset_settings/asset_settings.py b/erpnext/accounts/doctype/pos_field/pos_field.py
similarity index 61%
rename from erpnext/assets/doctype/asset_settings/asset_settings.py
rename to erpnext/accounts/doctype/pos_field/pos_field.py
index e303ebd..b4720b3 100644
--- a/erpnext/assets/doctype/asset_settings/asset_settings.py
+++ b/erpnext/accounts/doctype/pos_field/pos_field.py
@@ -1,9 +1,10 @@
# -*- coding: utf-8 -*-
-# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
+# 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 AssetSettings(Document):
+class POSField(Document):
pass
diff --git a/erpnext/accounts/doctype/pos_settings/pos_settings.js b/erpnext/accounts/doctype/pos_settings/pos_settings.js
index 1a14618..f5b681b 100644
--- a/erpnext/accounts/doctype/pos_settings/pos_settings.js
+++ b/erpnext/accounts/doctype/pos_settings/pos_settings.js
@@ -2,7 +2,46 @@
// For license information, please see license.txt
frappe.ui.form.on('POS Settings', {
- refresh: function() {
+ onload: function(frm) {
+ frm.trigger("get_invoice_fields");
+ },
+ use_pos_in_offline_mode: function(frm) {
+ frm.trigger("get_invoice_fields");
+ },
+
+ get_invoice_fields: function(frm) {
+ if (!frm.doc.use_pos_in_offline_mode) {
+ frappe.model.with_doctype("Sales Invoice", () => {
+ var fields = $.map(frappe.get_doc("DocType", "Sales Invoice").fields, function(d) {
+ if (frappe.model.no_value_type.indexOf(d.fieldtype) === -1 ||
+ d.fieldtype === 'Table') {
+ return { label: d.label + ' (' + d.fieldtype + ')', value: d.fieldname };
+ } else {
+ return null;
+ }
+ });
+
+ frappe.meta.get_docfield("POS Field", "fieldname", frm.doc.name).options = [""].concat(fields);
+ });
+ } else {
+ frappe.meta.get_docfield("POS Field", "fieldname", frm.doc.name).options = [""];
+ }
+ }
+});
+
+frappe.ui.form.on("POS Field", {
+ fieldname: function(frm, doctype, name) {
+ var doc = frappe.get_doc(doctype, name);
+ var df = $.map(frappe.get_doc("DocType", "Sales Invoice").fields, function(d) {
+ return doc.fieldname == d.fieldname ? d : null;
+ })[0];
+
+ doc.label = df.label;
+ doc.reqd = df.reqd;
+ doc.options = df.options;
+ doc.fieldtype = df.fieldtype;
+ doc.default_value = df.default;
+ frm.refresh_field("fields");
}
});
diff --git a/erpnext/accounts/doctype/pos_settings/pos_settings.json b/erpnext/accounts/doctype/pos_settings/pos_settings.json
index 8f5b631..1d55880 100644
--- a/erpnext/accounts/doctype/pos_settings/pos_settings.json
+++ b/erpnext/accounts/doctype/pos_settings/pos_settings.json
@@ -1,133 +1,68 @@
{
- "allow_copy": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "beta": 0,
- "creation": "2017-08-28 16:46:41.732676",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "",
- "editable_grid": 1,
- "engine": "InnoDB",
+ "actions": [],
+ "creation": "2017-08-28 16:46:41.732676",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "use_pos_in_offline_mode",
+ "section_break_2",
+ "fields"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "0",
- "fieldname": "use_pos_in_offline_mode",
- "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": "Use POS in Offline Mode",
- "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
+ "default": "0",
+ "fieldname": "use_pos_in_offline_mode",
+ "fieldtype": "Check",
+ "label": "Use POS in Offline Mode"
+ },
+ {
+ "fieldname": "section_break_2",
+ "fieldtype": "Section Break"
+ },
+ {
+ "depends_on": "eval:!doc.use_pos_in_offline_mode",
+ "fieldname": "fields",
+ "fieldtype": "Table",
+ "label": "POS Field",
+ "options": "POS Field"
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 1,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2017-09-11 13:57:28.787023",
- "modified_by": "Administrator",
- "module": "Accounts",
- "name": "POS Settings",
- "name_case": "",
- "owner": "Administrator",
+ ],
+ "issingle": 1,
+ "links": [],
+ "modified": "2019-12-26 11:50:47.122997",
+ "modified_by": "Administrator",
+ "module": "Accounts",
+ "name": "POS Settings",
+ "owner": "Administrator",
"permissions": [
{
- "amend": 0,
- "apply_user_permissions": 0,
- "cancel": 0,
- "create": 0,
- "delete": 0,
- "email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 0,
- "role": "System Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "role": "System Manager",
+ "share": 1,
"write": 1
- },
+ },
{
- "amend": 0,
- "apply_user_permissions": 0,
- "cancel": 0,
- "create": 0,
- "delete": 0,
- "email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 0,
- "role": "Accounts User",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "role": "Accounts User",
+ "share": 1,
"write": 1
- },
+ },
{
- "amend": 0,
- "apply_user_permissions": 0,
- "cancel": 0,
- "create": 0,
- "delete": 0,
- "email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 0,
- "role": "Sales User",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "role": "Sales User",
+ "share": 1,
"write": 1
}
- ],
- "quick_entry": 1,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1,
- "track_seen": 0
+ ],
+ "quick_entry": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.json b/erpnext/accounts/doctype/pricing_rule/pricing_rule.json
index 971d308..29d8378 100644
--- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.json
+++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.json
@@ -389,8 +389,7 @@
"fieldname": "rate_or_discount",
"fieldtype": "Select",
"label": "Rate or Discount",
- "options": "\nRate\nDiscount Percentage\nDiscount Amount",
- "reqd": 1
+ "options": "\nRate\nDiscount Percentage\nDiscount Amount"
},
{
"default": "Grand Total",
@@ -439,19 +438,20 @@
},
{
"default": "0",
- "depends_on": "eval:!doc.mixed_conditions",
+ "depends_on": "eval:!doc.mixed_conditions && doc.apply_on != 'Transaction'",
"fieldname": "same_item",
"fieldtype": "Check",
"label": "Same Item"
},
{
- "depends_on": "eval:!doc.same_item || doc.mixed_conditions",
+ "depends_on": "eval:(!doc.same_item || doc.apply_on == 'Transaction') || doc.mixed_conditions",
"fieldname": "free_item",
"fieldtype": "Link",
"label": "Free Item",
"options": "Item"
},
{
+ "default": "0",
"fieldname": "free_qty",
"fieldtype": "Float",
"label": "Qty"
@@ -554,7 +554,7 @@
],
"icon": "fa fa-gift",
"idx": 1,
- "modified": "2019-10-15 12:39:40.399792",
+ "modified": "2019-12-18 17:29:22.957077",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Pricing Rule",
diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py
index 1776275..3c14819 100644
--- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py
+++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py
@@ -34,8 +34,7 @@
def validate_duplicate_apply_on(self):
field = apply_on_dict.get(self.apply_on)
- values = [d.get(frappe.scrub(self.apply_on)) for d in self.get(field)]
-
+ values = [d.get(frappe.scrub(self.apply_on)) for d in self.get(field) if field]
if len(values) != len(set(values)):
frappe.throw(_("Duplicate {0} found in the table").format(self.apply_on))
@@ -48,6 +47,9 @@
if tocheck and not self.get(tocheck):
throw(_("{0} is required").format(self.meta.get_label(tocheck)), frappe.MandatoryError)
+ if self.price_or_product_discount == 'Price' and not self.rate_or_discount:
+ throw(_("Rate or Discount is required for the price discount."), frappe.MandatoryError)
+
def validate_applicable_for_selling_or_buying(self):
if not self.selling and not self.buying:
throw(_("Atleast one of the Selling or Buying must be selected"))
@@ -181,8 +183,9 @@
item_details.serial_no = get_serial_no(args)
return item_details
-def get_pricing_rule_for_item(args, price_list_rate=0, doc=None):
- from erpnext.accounts.doctype.pricing_rule.utils import get_pricing_rules
+def get_pricing_rule_for_item(args, price_list_rate=0, doc=None, for_validate=False):
+ from erpnext.accounts.doctype.pricing_rule.utils import (get_pricing_rules,
+ get_applied_pricing_rules, get_pricing_rule_items, get_product_discount_rule)
if isinstance(doc, string_types):
doc = json.loads(doc)
@@ -209,6 +212,57 @@
item_details, args.get('item_code'))
return item_details
+ update_args_for_pricing_rule(args)
+
+ pricing_rules = (get_applied_pricing_rules(args)
+ if for_validate and args.get("pricing_rules") else get_pricing_rules(args, doc))
+
+ if pricing_rules:
+ rules = []
+
+ for pricing_rule in pricing_rules:
+ if not pricing_rule: continue
+
+ if isinstance(pricing_rule, string_types):
+ pricing_rule = frappe.get_cached_doc("Pricing Rule", pricing_rule)
+ pricing_rule.apply_rule_on_other_items = get_pricing_rule_items(pricing_rule)
+
+ if pricing_rule.get('suggestion'): continue
+
+ item_details.validate_applied_rule = pricing_rule.get("validate_applied_rule", 0)
+ item_details.price_or_product_discount = pricing_rule.get("price_or_product_discount")
+
+ rules.append(get_pricing_rule_details(args, pricing_rule))
+
+ if pricing_rule.mixed_conditions or pricing_rule.apply_rule_on_other:
+ item_details.update({
+ 'apply_rule_on_other_items': json.dumps(pricing_rule.apply_rule_on_other_items),
+ 'apply_rule_on': (frappe.scrub(pricing_rule.apply_rule_on_other)
+ if pricing_rule.apply_rule_on_other else frappe.scrub(pricing_rule.get('apply_on')))
+ })
+
+ if pricing_rule.coupon_code_based==1 and args.coupon_code==None:
+ return item_details
+
+ if not pricing_rule.validate_applied_rule:
+ if pricing_rule.price_or_product_discount == "Price":
+ apply_price_discount_rule(pricing_rule, item_details, args)
+ else:
+ get_product_discount_rule(pricing_rule, item_details, doc)
+
+ item_details.has_pricing_rule = 1
+
+ item_details.pricing_rules = ','.join([d.pricing_rule for d in rules])
+
+ if not doc: return item_details
+
+ elif args.get("pricing_rules"):
+ item_details = remove_pricing_rule_for_item(args.get("pricing_rules"),
+ item_details, args.get('item_code'))
+
+ return item_details
+
+def update_args_for_pricing_rule(args):
if not (args.item_group and args.brand):
try:
args.item_group, args.brand = frappe.get_cached_value("Item", args.item_code, ["item_group", "brand"])
@@ -235,56 +289,16 @@
args.supplier_group = frappe.get_cached_value("Supplier", args.supplier, "supplier_group")
args.customer = args.customer_group = args.territory = None
- pricing_rules = get_pricing_rules(args, doc)
-
- if pricing_rules:
- rules = []
-
- for pricing_rule in pricing_rules:
- if not pricing_rule or pricing_rule.get('suggestion'): continue
-
- item_details.validate_applied_rule = pricing_rule.get("validate_applied_rule", 0)
-
- rules.append(get_pricing_rule_details(args, pricing_rule))
- if pricing_rule.mixed_conditions or pricing_rule.apply_rule_on_other:
- continue
-
- if pricing_rule.coupon_code_based==1 and args.coupon_code==None:
- return item_details
-
- if (not pricing_rule.validate_applied_rule and
- pricing_rule.price_or_product_discount == "Price"):
- apply_price_discount_pricing_rule(pricing_rule, item_details, args)
-
- item_details.has_pricing_rule = 1
-
- # if discount is applied on the rate and not on price list rate
- # if price_list_rate:
- # set_discount_amount(price_list_rate, item_details)
-
- item_details.pricing_rules = ','.join([d.pricing_rule for d in rules])
-
- if not doc: return item_details
-
- for rule in rules:
- doc.append('pricing_rules', rule)
-
- elif args.get("pricing_rules"):
- item_details = remove_pricing_rule_for_item(args.get("pricing_rules"),
- item_details, args.get('item_code'))
-
- return item_details
-
def get_pricing_rule_details(args, pricing_rule):
return frappe._dict({
'pricing_rule': pricing_rule.name,
'rate_or_discount': pricing_rule.rate_or_discount,
'margin_type': pricing_rule.margin_type,
- 'item_code': pricing_rule.item_code or args.get("item_code"),
+ 'item_code': args.get("item_code"),
'child_docname': args.get('child_docname')
})
-def apply_price_discount_pricing_rule(pricing_rule, item_details, args):
+def apply_price_discount_rule(pricing_rule, item_details, args):
item_details.pricing_rule_for = pricing_rule.rate_or_discount
if ((pricing_rule.margin_type == 'Amount' and pricing_rule.currency == args.currency)
@@ -327,10 +341,10 @@
item_details.rate = rate
def remove_pricing_rule_for_item(pricing_rules, item_details, item_code=None):
- from erpnext.accounts.doctype.pricing_rule.utils import get_apply_on_and_items
+ from erpnext.accounts.doctype.pricing_rule.utils import get_pricing_rule_items
for d in pricing_rules.split(','):
if not d or not frappe.db.exists("Pricing Rule", d): continue
- pricing_rule = frappe.get_doc('Pricing Rule', d)
+ pricing_rule = frappe.get_cached_doc('Pricing Rule', d)
if pricing_rule.price_or_product_discount == 'Price':
if pricing_rule.rate_or_discount == 'Discount Percentage':
@@ -348,8 +362,9 @@
else pricing_rule.get('free_item'))
if pricing_rule.get("mixed_conditions") or pricing_rule.get("apply_rule_on_other"):
- apply_on, items = get_apply_on_and_items(pricing_rule, item_details)
- item_details.apply_on = apply_on
+ items = get_pricing_rule_items(pricing_rule)
+ item_details.apply_on = (frappe.scrub(pricing_rule.apply_rule_on_other)
+ if pricing_rule.apply_rule_on_other else frappe.scrub(pricing_rule.get('apply_on')))
item_details.applied_on_items = ','.join(items)
item_details.pricing_rules = ''
diff --git a/erpnext/accounts/doctype/pricing_rule/utils.py b/erpnext/accounts/doctype/pricing_rule/utils.py
index ef26c2e..fe68fdb 100644
--- a/erpnext/accounts/doctype/pricing_rule/utils.py
+++ b/erpnext/accounts/doctype/pricing_rule/utils.py
@@ -7,7 +7,8 @@
import frappe, copy, json
from frappe import throw, _
from six import string_types
-from frappe.utils import flt, cint, get_datetime
+from frappe.utils import flt, cint, get_datetime, get_link_to_form, today
+from erpnext.setup.doctype.item_group.item_group import get_child_item_groups
from erpnext.stock.doctype.warehouse.warehouse import get_child_warehouses
from erpnext.stock.get_item_details import get_conversion_factor
@@ -173,10 +174,11 @@
if (field and pricing_rules[0].get('other_' + field) != args.get(field)): return
- pr_doc = frappe.get_doc('Pricing Rule', pricing_rules[0].name)
+ pr_doc = frappe.get_cached_doc('Pricing Rule', pricing_rules[0].name)
if pricing_rules[0].mixed_conditions and doc:
- stock_qty, amount = get_qty_and_rate_for_mixed_conditions(doc, pr_doc, args)
+ stock_qty, amount, items = get_qty_and_rate_for_mixed_conditions(doc, pr_doc, args)
+ pricing_rules[0].apply_rule_on_other_items = items
elif pricing_rules[0].is_cumulative:
items = [args.get(frappe.scrub(pr_doc.get('apply_on')))]
@@ -282,7 +284,7 @@
status = True
# if user has created item price against the transaction UOM
- if rule.get("uom") == args.get("uom"):
+ if args and rule.get("uom") == args.get("uom"):
conversion_factor = 1.0
if status and (flt(rate) >= (flt(rule.min_amt) * conversion_factor)
@@ -339,17 +341,19 @@
sum_qty += data[0]
sum_amt += data[1]
- return sum_qty, sum_amt
+ return sum_qty, sum_amt, items
def get_qty_and_rate_for_other_item(doc, pr_doc, pricing_rules):
- for d in get_pricing_rule_items(pr_doc):
- for row in doc.items:
- if d == row.get(frappe.scrub(pr_doc.apply_on)):
- pricing_rules = filter_pricing_rules_for_qty_amount(row.get("stock_qty"),
- row.get("amount"), pricing_rules, row)
+ items = get_pricing_rule_items(pr_doc)
- if pricing_rules and pricing_rules[0]:
- return pricing_rules
+ for row in doc.items:
+ if row.get(frappe.scrub(pr_doc.apply_rule_on_other)) in items:
+ pricing_rules = filter_pricing_rules_for_qty_amount(row.get("stock_qty"),
+ row.get("amount"), pricing_rules, row)
+
+ if pricing_rules and pricing_rules[0]:
+ pricing_rules[0].apply_rule_on_other_items = items
+ return pricing_rules
def get_qty_amount_data_for_cumulative(pr_doc, doc, items=[]):
sum_qty, sum_amt = [0, 0]
@@ -397,38 +401,15 @@
return [sum_qty, sum_amt]
-def validate_pricing_rules(doc):
- validate_pricing_rule_on_transactions(doc)
-
- for d in doc.items:
- validate_pricing_rule_on_items(doc, d)
-
- doc.calculate_taxes_and_totals()
-
-def validate_pricing_rule_on_items(doc, item_row, do_not_validate = False):
- value = 0
- for pricing_rule in get_applied_pricing_rules(doc, item_row):
- pr_doc = frappe.get_doc('Pricing Rule', pricing_rule)
-
- if pr_doc.get('apply_on') == 'Transaction': continue
-
- if pr_doc.get('price_or_product_discount') == 'Product':
- apply_pricing_rule_for_free_items(doc, pr_doc)
- else:
- for field in ['discount_percentage', 'discount_amount', 'rate']:
- if not pr_doc.get(field): continue
-
- value += pr_doc.get(field)
- apply_pricing_rule(doc, pr_doc, item_row, value, do_not_validate)
-
-def validate_pricing_rule_on_transactions(doc):
+def apply_pricing_rule_on_transaction(doc):
conditions = "apply_on = 'Transaction'"
values = {}
conditions = get_other_conditions(conditions, values, doc)
pricing_rules = frappe.db.sql(""" Select `tabPricing Rule`.* from `tabPricing Rule`
- where {conditions} """.format(conditions = conditions), values, as_dict=1)
+ where {conditions} and `tabPricing Rule`.disable = 0
+ """.format(conditions = conditions), values, as_dict=1)
if pricing_rules:
pricing_rules = filter_pricing_rules_for_qty_amount(doc.total_qty,
@@ -440,98 +421,83 @@
doc.set('apply_discount_on', d.apply_discount_on)
for field in ['additional_discount_percentage', 'discount_amount']:
- if not d.get(field): continue
-
pr_field = ('discount_percentage'
if field == 'additional_discount_percentage' else field)
+ if not d.get(pr_field): continue
+
if d.validate_applied_rule and doc.get(field) < d.get(pr_field):
frappe.msgprint(_("User has not applied rule on the invoice {0}")
.format(doc.name))
else:
doc.set(field, d.get(pr_field))
- elif d.price_or_product_discount == 'Product':
- apply_pricing_rule_for_free_items(doc, d)
-def get_applied_pricing_rules(doc, item_row):
+ doc.calculate_taxes_and_totals()
+ elif d.price_or_product_discount == 'Product':
+ item_details = frappe._dict({'parenttype': doc.doctype})
+ get_product_discount_rule(d, item_details, doc)
+ apply_pricing_rule_for_free_items(doc, item_details.free_item_data)
+ doc.set_missing_values()
+
+def get_applied_pricing_rules(item_row):
return (item_row.get("pricing_rules").split(',')
if item_row.get("pricing_rules") else [])
-def apply_pricing_rule_for_free_items(doc, pricing_rule):
- if pricing_rule.get('free_item'):
+def get_product_discount_rule(pricing_rule, item_details, doc=None):
+ free_item = (pricing_rule.free_item
+ if not pricing_rule.same_item or pricing_rule.apply_on == 'Transaction' else item_details.item_code)
+
+ if not free_item:
+ frappe.throw(_("Free item not set in the pricing rule {0}")
+ .format(get_link_to_form("Pricing Rule", pricing_rule.name)))
+
+ item_details.free_item_data = {
+ 'item_code': free_item,
+ 'qty': pricing_rule.free_qty or 1,
+ 'rate': pricing_rule.free_item_rate or 0,
+ 'price_list_rate': pricing_rule.free_item_rate or 0,
+ 'is_free_item': 1
+ }
+
+ item_data = frappe.get_cached_value('Item', free_item, ['item_name',
+ 'description', 'stock_uom'], as_dict=1)
+
+ item_details.free_item_data.update(item_data)
+ item_details.free_item_data['uom'] = pricing_rule.free_item_uom or item_data.stock_uom
+ item_details.free_item_data['conversion_factor'] = get_conversion_factor(free_item,
+ item_details.free_item_data['uom']).get("conversion_factor", 1)
+
+ if item_details.get("parenttype") == 'Purchase Order':
+ item_details.free_item_data['schedule_date'] = doc.schedule_date if doc else today()
+
+ if item_details.get("parenttype") == 'Sales Order':
+ item_details.free_item_data['delivery_date'] = doc.delivery_date if doc else today()
+
+def apply_pricing_rule_for_free_items(doc, pricing_rule_args, set_missing_values=False):
+ if pricing_rule_args.get('item_code'):
items = [d.item_code for d in doc.items
- if d.item_code == (d.item_code
- if pricing_rule.get('same_item') else pricing_rule.get('free_item')) and d.is_free_item]
+ if d.item_code == (pricing_rule_args.get("item_code")) and d.is_free_item]
if not items:
- doc.append('items', {
- 'item_code': pricing_rule.get('free_item'),
- 'qty': pricing_rule.get('free_qty'),
- 'uom': pricing_rule.get('free_item_uom'),
- 'rate': pricing_rule.get('free_item_rate'),
- 'is_free_item': 1
- })
-
- doc.set_missing_values()
-
-def apply_pricing_rule(doc, pr_doc, item_row, value, do_not_validate=False):
- apply_on, items = get_apply_on_and_items(pr_doc, item_row)
-
- rule_applied = {}
-
- for item in doc.get("items"):
- if item.get(apply_on) in items:
- if not item.pricing_rules:
- item.pricing_rules = item_row.pricing_rules
-
- for field in ['discount_percentage', 'discount_amount', 'rate']:
- if not pr_doc.get(field): continue
-
- key = (item.name, item.pricing_rules)
- if not pr_doc.validate_applied_rule:
- rule_applied[key] = 1
- item.set(field, value)
- elif item.get(field) < value:
- if not do_not_validate and item.idx == item_row.idx:
- rule_applied[key] = 0
- frappe.msgprint(_("Row {0}: user has not applied rule <b>{1}</b> on the item <b>{2}</b>")
- .format(item.idx, pr_doc.title, item.item_code))
-
- if rule_applied and doc.get("pricing_rules"):
- for d in doc.get("pricing_rules"):
- key = (d.child_docname, d.pricing_rule)
- if key in rule_applied:
- d.rule_applied = 1
-
-def get_apply_on_and_items(pr_doc, item_row):
- # for mixed or other items conditions
- apply_on = frappe.scrub(pr_doc.get('apply_on'))
- items = (get_pricing_rule_items(pr_doc)
- if pr_doc.mixed_conditions else [item_row.get(apply_on)])
-
- if pr_doc.apply_rule_on_other:
- apply_on = frappe.scrub(pr_doc.apply_rule_on_other)
- items = [pr_doc.get(apply_on)]
-
- return apply_on, items
+ doc.append('items', pricing_rule_args)
def get_pricing_rule_items(pr_doc):
+ apply_on_data = []
apply_on = frappe.scrub(pr_doc.get('apply_on'))
pricing_rule_apply_on = apply_on_table.get(pr_doc.get('apply_on'))
- return [item.get(apply_on) for item in pr_doc.get(pricing_rule_apply_on)] or []
+ for d in pr_doc.get(pricing_rule_apply_on):
+ if apply_on == 'item_group':
+ get_child_item_groups(d.get(apply_on))
+ else:
+ apply_on_data.append(d.get(apply_on))
-@frappe.whitelist()
-def validate_pricing_rule_for_different_cond(doc):
- if isinstance(doc, string_types):
- doc = json.loads(doc)
+ if pr_doc.apply_rule_on_other:
+ apply_on = frappe.scrub(pr_doc.apply_rule_on_other)
+ apply_on_data.append(pr_doc.get("other_" + apply_on))
- doc = frappe.get_doc(doc)
- for d in doc.get("items"):
- validate_pricing_rule_on_items(doc, d, True)
-
- return doc
+ return list(set(apply_on_data))
def validate_coupon_code(coupon_name):
from frappe.utils import today,getdate
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
index f4b656d..643de7d 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
@@ -330,23 +330,6 @@
frm: cur_frm
})
},
-
- asset: function(frm, cdt, cdn) {
- var row = locals[cdt][cdn];
- if(row.asset) {
- frappe.call({
- method: "erpnext.assets.doctype.asset_category.asset_category.get_asset_category_account",
- args: {
- "asset": row.asset,
- "fieldname": "fixed_asset_account",
- "account": row.expense_account
- },
- callback: function(r, rt) {
- frappe.model.set_value(cdt, cdn, "expense_account", r.message);
- }
- })
- }
- }
});
cur_frm.script_manager.make(erpnext.accounts.PurchaseInvoice);
@@ -399,21 +382,11 @@
cur_frm.fields_dict['credit_to'].get_query = function(doc) {
// filter on Account
- if (doc.supplier) {
- return {
- filters: {
- 'account_type': 'Payable',
- 'is_group': 0,
- 'company': doc.company
- }
- }
- } else {
- return {
- filters: {
- 'report_type': 'Balance Sheet',
- 'is_group': 0,
- 'company': doc.company
- }
+ return {
+ filters: {
+ 'account_type': 'Payable',
+ 'is_group': 0,
+ 'company': doc.company
}
}
}
@@ -430,19 +403,7 @@
cur_frm.set_query("expense_account", "items", function(doc) {
return {
query: "erpnext.controllers.queries.get_expense_account",
- filters: {'company': doc.company}
- }
-});
-
-cur_frm.set_query("asset", "items", function(doc, cdt, cdn) {
- var d = locals[cdt][cdn];
- return {
- filters: {
- 'item_code': d.item_code,
- 'docstatus': 1,
- 'company': doc.company,
- 'status': 'Submitted'
- }
+ filters: {'company': doc.company }
}
});
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
index 6fe1811..7725994 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
@@ -1,4 +1,5 @@
{
+ "actions": [],
"allow_import": 1,
"autoname": "naming_series:",
"creation": "2013-05-21 16:16:39",
@@ -417,6 +418,7 @@
"fieldname": "contact_email",
"fieldtype": "Small Text",
"label": "Contact Email",
+ "options": "Email",
"print_hide": 1,
"read_only": 1
},
@@ -705,7 +707,7 @@
},
{
"fieldname": "other_charges_calculation",
- "fieldtype": "Text",
+ "fieldtype": "Long Text",
"label": "Taxes and Charges Calculation",
"no_copy": 1,
"oldfieldtype": "HTML",
@@ -1287,7 +1289,8 @@
"icon": "fa fa-file-text",
"idx": 204,
"is_submittable": 1,
- "modified": "2019-09-17 22:31:42.666601",
+ "links": [],
+ "modified": "2019-12-30 19:13:49.610538",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Invoice",
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
index 4ea9b1c..917acba 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
@@ -18,13 +18,14 @@
from erpnext.accounts.doctype.gl_entry.gl_entry import update_outstanding_amt
from erpnext.buying.utils import check_on_hold_or_closed_status
from erpnext.accounts.general_ledger import get_round_off_account_and_cost_center
-from erpnext.assets.doctype.asset.asset import get_asset_account, is_cwip_accounting_disabled
+from erpnext.assets.doctype.asset.asset import get_asset_account, is_cwip_accounting_enabled
from frappe.model.mapper import get_mapped_doc
from six import iteritems
from erpnext.accounts.doctype.sales_invoice.sales_invoice import validate_inter_company_party, update_linked_doc,\
unlink_inter_company_doc
from erpnext.accounts.doctype.tax_withholding_category.tax_withholding_category import get_party_tax_withholding_details
from erpnext.accounts.deferred_revenue import validate_service_stop_date
+from erpnext.stock.doctype.purchase_receipt.purchase_receipt import get_item_account_wise_additional_cost
form_grid_templates = {
"items": "templates/form_grid/item_grid.html"
@@ -97,7 +98,6 @@
self.set_against_expense_account()
self.validate_write_off_account()
self.validate_multiple_billing("Purchase Receipt", "pr_detail", "amount", "items")
- self.validate_fixed_asset()
self.create_remarks()
self.set_status()
self.validate_purchase_receipt_if_update_stock()
@@ -225,6 +225,8 @@
# in case of auto inventory accounting,
# expense account is always "Stock Received But Not Billed" for a stock item
# except epening entry, drop-ship entry and fixed asset items
+ if item.item_code:
+ asset_category = frappe.get_cached_value("Item", item.item_code, "asset_category")
if auto_accounting_for_stock and item.item_code in stock_items \
and self.is_opening == 'No' and not item.is_fixed_asset \
@@ -235,12 +237,8 @@
item.expense_account = warehouse_account[item.warehouse]["account"]
else:
item.expense_account = stock_not_billed_account
- elif item.is_fixed_asset and is_cwip_accounting_disabled():
- if not item.asset:
- frappe.throw(_("Row {0}: asset is required for item {1}")
- .format(item.idx, item.item_code))
-
- item.expense_account = get_asset_category_account(item.asset, 'fixed_asset_account',
+ elif item.is_fixed_asset and not is_cwip_accounting_enabled(asset_category):
+ item.expense_account = get_asset_category_account('fixed_asset_account', item=item.item_code,
company = self.company)
elif item.is_fixed_asset and item.pr_detail:
item.expense_account = asset_received_but_not_billed
@@ -250,7 +248,7 @@
def set_against_expense_account(self):
against_accounts = []
for item in self.get("items"):
- if item.expense_account not in against_accounts:
+ if item.expense_account and (item.expense_account not in against_accounts):
against_accounts.append(item.expense_account)
self.against_expense_account = ",".join(against_accounts)
@@ -391,7 +389,8 @@
self.make_supplier_gl_entry(gl_entries)
self.make_item_gl_entries(gl_entries)
- if not is_cwip_accounting_disabled():
+
+ if self.check_asset_cwip_enabled():
self.get_asset_gl_entry(gl_entries)
self.make_tax_gl_entries(gl_entries)
@@ -404,6 +403,15 @@
return gl_entries
+ def check_asset_cwip_enabled(self):
+ # Check if there exists any item with cwip accounting enabled in it's asset category
+ for item in self.get("items"):
+ if item.item_code and item.is_fixed_asset:
+ asset_category = frappe.get_cached_value("Item", item.item_code, "asset_category")
+ if is_cwip_accounting_enabled(asset_category):
+ return 1
+ return 0
+
def make_supplier_gl_entry(self, gl_entries):
# Checked both rounding_adjustment and rounded_total
# because rounded_total had value even before introcution of posting GLE based on rounded total
@@ -436,15 +444,23 @@
if self.update_stock and self.auto_accounting_for_stock:
warehouse_account = get_warehouse_account_map(self.company)
+ landed_cost_entries = get_item_account_wise_additional_cost(self.name)
+
voucher_wise_stock_value = {}
if self.update_stock:
for d in frappe.get_all('Stock Ledger Entry',
fields = ["voucher_detail_no", "stock_value_difference"], filters={'voucher_no': self.name}):
voucher_wise_stock_value.setdefault(d.voucher_detail_no, d.stock_value_difference)
+ valuation_tax_accounts = [d.account_head for d in self.get("taxes")
+ if d.category in ('Valuation', 'Total and Valuation')
+ and flt(d.base_tax_amount_after_discount_amount)]
+
for item in self.get("items"):
if flt(item.base_net_amount):
account_currency = get_account_currency(item.expense_account)
+ if item.item_code:
+ asset_category = frappe.get_cached_value("Item", item.item_code, "asset_category")
if self.update_stock and self.auto_accounting_for_stock and item.item_code in stock_items:
# warehouse account
@@ -463,15 +479,16 @@
)
# Amount added through landed-cost-voucher
- if flt(item.landed_cost_voucher_amount):
- gl_entries.append(self.get_gl_dict({
- "account": expenses_included_in_valuation,
- "against": item.expense_account,
- "cost_center": item.cost_center,
- "remarks": self.get("remarks") or _("Accounting Entry for Stock"),
- "credit": flt(item.landed_cost_voucher_amount),
- "project": item.project
- }, item=item))
+ if landed_cost_entries:
+ for account, amount in iteritems(landed_cost_entries[(item.item_code, item.name)]):
+ gl_entries.append(self.get_gl_dict({
+ "account": account,
+ "against": item.expense_account,
+ "cost_center": item.cost_center,
+ "remarks": self.get("remarks") or _("Accounting Entry for Stock"),
+ "credit": flt(amount),
+ "project": item.project
+ }, item=item))
# sub-contracting warehouse
if flt(item.rm_supp_cost):
@@ -486,31 +503,61 @@
"remarks": self.get("remarks") or _("Accounting Entry for Stock"),
"credit": flt(item.rm_supp_cost)
}, warehouse_account[self.supplier_warehouse]["account_currency"], item=item))
- elif not item.is_fixed_asset or (item.is_fixed_asset and is_cwip_accounting_disabled()):
+ elif not item.is_fixed_asset or (item.is_fixed_asset and not is_cwip_accounting_enabled(asset_category)):
expense_account = (item.expense_account
if (not item.enable_deferred_expense or self.is_return) else item.deferred_expense_account)
- gl_entries.append(
- self.get_gl_dict({
+ if not item.is_fixed_asset:
+ amount = flt(item.base_net_amount, item.precision("base_net_amount"))
+ else:
+ amount = flt(item.base_net_amount + item.item_tax_amount, item.precision("base_net_amount"))
+
+ gl_entries.append(self.get_gl_dict({
"account": expense_account,
"against": self.supplier,
- "debit": flt(item.base_net_amount, item.precision("base_net_amount")),
- "debit_in_account_currency": (flt(item.base_net_amount,
- item.precision("base_net_amount")) if account_currency==self.company_currency
- else flt(item.net_amount, item.precision("net_amount"))),
+ "debit": amount,
"cost_center": item.cost_center,
"project": item.project
- }, account_currency, item=item)
- )
+ }, account_currency, item=item))
+
+ # If asset is bought through this document and not linked to PR
+ if self.update_stock and item.landed_cost_voucher_amount:
+ expenses_included_in_asset_valuation = self.get_company_default("expenses_included_in_asset_valuation")
+ # Amount added through landed-cost-voucher
+ gl_entries.append(self.get_gl_dict({
+ "account": expenses_included_in_asset_valuation,
+ "against": expense_account,
+ "cost_center": item.cost_center,
+ "remarks": self.get("remarks") or _("Accounting Entry for Stock"),
+ "credit": flt(item.landed_cost_voucher_amount),
+ "project": item.project
+ }, item=item))
+
+ gl_entries.append(self.get_gl_dict({
+ "account": expense_account,
+ "against": expenses_included_in_asset_valuation,
+ "cost_center": item.cost_center,
+ "remarks": self.get("remarks") or _("Accounting Entry for Stock"),
+ "debit": flt(item.landed_cost_voucher_amount),
+ "project": item.project
+ }, item=item))
+
+ # update gross amount of asset bought through this document
+ assets = frappe.db.get_all('Asset',
+ filters={ 'purchase_invoice': self.name, 'item_code': item.item_code }
+ )
+ for asset in assets:
+ frappe.db.set_value("Asset", asset.name, "gross_purchase_amount", flt(item.valuation_rate))
+ frappe.db.set_value("Asset", asset.name, "purchase_receipt_amount", flt(item.valuation_rate))
if self.auto_accounting_for_stock and self.is_opening == "No" and \
item.item_code in stock_items and item.item_tax_amount:
# Post reverse entry for Stock-Received-But-Not-Billed if it is booked in Purchase Receipt
- if item.purchase_receipt:
+ if item.purchase_receipt and valuation_tax_accounts:
negative_expense_booked_in_pr = frappe.db.sql("""select name from `tabGL Entry`
- where voucher_type='Purchase Receipt' and voucher_no=%s and account=%s""",
- (item.purchase_receipt, self.expenses_included_in_valuation))
+ where voucher_type='Purchase Receipt' and voucher_no=%s and account in %s""",
+ (item.purchase_receipt, valuation_tax_accounts))
if not negative_expense_booked_in_pr:
gl_entries.append(
@@ -527,27 +574,27 @@
item.precision("item_tax_amount"))
def get_asset_gl_entry(self, gl_entries):
+ arbnb_account = self.get_company_default("asset_received_but_not_billed")
+ eiiav_account = self.get_company_default("expenses_included_in_asset_valuation")
+
for item in self.get("items"):
if item.is_fixed_asset:
- eiiav_account = self.get_company_default("expenses_included_in_asset_valuation")
-
asset_amount = flt(item.net_amount) + flt(item.item_tax_amount/self.conversion_rate)
base_asset_amount = flt(item.base_net_amount + item.item_tax_amount)
- if (not item.expense_account or frappe.db.get_value('Account',
- item.expense_account, 'account_type') not in ['Asset Received But Not Billed', 'Fixed Asset']):
- arbnb_account = self.get_company_default("asset_received_but_not_billed")
+ item_exp_acc_type = frappe.db.get_value('Account', item.expense_account, 'account_type')
+ if (not item.expense_account or item_exp_acc_type not in ['Asset Received But Not Billed', 'Fixed Asset']):
item.expense_account = arbnb_account
if not self.update_stock:
- asset_rbnb_currency = get_account_currency(item.expense_account)
+ arbnb_currency = get_account_currency(item.expense_account)
gl_entries.append(self.get_gl_dict({
"account": item.expense_account,
"against": self.supplier,
"remarks": self.get("remarks") or _("Accounting Entry for Asset"),
"debit": base_asset_amount,
"debit_in_account_currency": (base_asset_amount
- if asset_rbnb_currency == self.company_currency else asset_amount),
+ if arbnb_currency == self.company_currency else asset_amount),
"cost_center": item.cost_center
}, item=item))
@@ -564,8 +611,7 @@
item.item_tax_amount / self.conversion_rate)
}, item=item))
else:
- cwip_account = get_asset_account("capital_work_in_progress_account",
- item.asset, company = self.company)
+ cwip_account = get_asset_account("capital_work_in_progress_account", company = self.company)
cwip_account_currency = get_account_currency(cwip_account)
gl_entries.append(self.get_gl_dict({
@@ -591,6 +637,36 @@
item.item_tax_amount / self.conversion_rate)
}, item=item))
+ # When update stock is checked
+ # Assets are bought through this document then it will be linked to this document
+ if self.update_stock:
+ if flt(item.landed_cost_voucher_amount):
+ gl_entries.append(self.get_gl_dict({
+ "account": eiiav_account,
+ "against": cwip_account,
+ "cost_center": item.cost_center,
+ "remarks": self.get("remarks") or _("Accounting Entry for Stock"),
+ "credit": flt(item.landed_cost_voucher_amount),
+ "project": item.project
+ }, item=item))
+
+ gl_entries.append(self.get_gl_dict({
+ "account": cwip_account,
+ "against": eiiav_account,
+ "cost_center": item.cost_center,
+ "remarks": self.get("remarks") or _("Accounting Entry for Stock"),
+ "debit": flt(item.landed_cost_voucher_amount),
+ "project": item.project
+ }, item=item))
+
+ # update gross amount of assets bought through this document
+ assets = frappe.db.get_all('Asset',
+ filters={ 'purchase_invoice': self.name, 'item_code': item.item_code }
+ )
+ for asset in assets:
+ frappe.db.set_value("Asset", asset.name, "gross_purchase_amount", flt(item.valuation_rate))
+ frappe.db.set_value("Asset", asset.name, "purchase_receipt_amount", flt(item.valuation_rate))
+
return gl_entries
def make_stock_adjustment_entry(self, gl_entries, item, voucher_wise_stock_value, account_currency):
@@ -641,14 +717,14 @@
if account_currency==self.company_currency \
else tax.tax_amount_after_discount_amount,
"cost_center": tax.cost_center
- }, account_currency)
+ }, account_currency, item=tax)
)
# accumulate valuation tax
if self.is_opening == "No" and tax.category in ("Valuation", "Valuation and Total") and flt(tax.base_tax_amount_after_discount_amount):
if self.auto_accounting_for_stock and not tax.cost_center:
frappe.throw(_("Cost Center is required in row {0} in Taxes table for type {1}").format(tax.idx, _(tax.category)))
- valuation_tax.setdefault(tax.cost_center, 0)
- valuation_tax[tax.cost_center] += \
+ valuation_tax.setdefault(tax.name, 0)
+ valuation_tax[tax.name] += \
(tax.add_deduct_tax == "Add" and 1 or -1) * flt(tax.base_tax_amount_after_discount_amount)
if self.is_opening == "No" and self.negative_expense_to_be_booked and valuation_tax:
@@ -658,36 +734,38 @@
total_valuation_amount = sum(valuation_tax.values())
amount_including_divisional_loss = self.negative_expense_to_be_booked
i = 1
- for cost_center, amount in iteritems(valuation_tax):
- if i == len(valuation_tax):
- applicable_amount = amount_including_divisional_loss
- else:
- applicable_amount = self.negative_expense_to_be_booked * (amount / total_valuation_amount)
- amount_including_divisional_loss -= applicable_amount
+ for tax in self.get("taxes"):
+ if valuation_tax.get(tax.name):
+ if i == len(valuation_tax):
+ applicable_amount = amount_including_divisional_loss
+ else:
+ applicable_amount = self.negative_expense_to_be_booked * (valuation_tax[tax.name] / total_valuation_amount)
+ amount_including_divisional_loss -= applicable_amount
- gl_entries.append(
- self.get_gl_dict({
- "account": self.expenses_included_in_valuation,
- "cost_center": cost_center,
- "against": self.supplier,
- "credit": applicable_amount,
- "remarks": self.remarks or "Accounting Entry for Stock"
- })
- )
+ gl_entries.append(
+ self.get_gl_dict({
+ "account": tax.account_head,
+ "cost_center": tax.cost_center,
+ "against": self.supplier,
+ "credit": applicable_amount,
+ "remarks": self.remarks or _("Accounting Entry for Stock"),
+ }, item=tax)
+ )
- i += 1
+ i += 1
if self.auto_accounting_for_stock and self.update_stock and valuation_tax:
- for cost_center, amount in iteritems(valuation_tax):
- gl_entries.append(
- self.get_gl_dict({
- "account": self.expenses_included_in_valuation,
- "cost_center": cost_center,
- "against": self.supplier,
- "credit": amount,
- "remarks": self.remarks or "Accounting Entry for Stock"
- })
- )
+ for tax in self.get("taxes"):
+ if valuation_tax.get(tax.name):
+ gl_entries.append(
+ self.get_gl_dict({
+ "account": tax.account_head,
+ "cost_center": tax.cost_center,
+ "against": self.supplier,
+ "credit": valuation_tax[tax.name],
+ "remarks": self.remarks or "Accounting Entry for Stock"
+ }, item=tax)
+ )
def make_payment_gl_entries(self, gl_entries):
# Make Cash GL Entries
@@ -752,7 +830,11 @@
)
def make_gle_for_rounding_adjustment(self, gl_entries):
- if self.rounding_adjustment:
+ # if rounding adjustment in small and conversion rate is also small then
+ # base_rounding_adjustment may become zero due to small precision
+ # eg: rounding_adjustment = 0.01 and exchange rate = 0.05 and precision of base_rounding_adjustment is 2
+ # then base_rounding_adjustment becomes zero and error is thrown in GL Entry
+ if self.rounding_adjustment and self.base_rounding_adjustment:
round_off_account, round_off_cost_center = \
get_round_off_account_and_cost_center(self.company)
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice_list.js b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice_list.js
index 4e76a8d..800ed92 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice_list.js
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice_list.js
@@ -6,8 +6,8 @@
add_fields: ["supplier", "supplier_name", "base_grand_total", "outstanding_amount", "due_date", "company",
"currency", "is_return", "release_date", "on_hold"],
get_indicator: function(doc) {
- if(flt(doc.outstanding_amount) < 0 && doc.docstatus == 1) {
- return [__("Debit Note Issued"), "darkgrey", "outstanding_amount,<,0"]
+ if( (flt(doc.outstanding_amount) <= 0) && doc.docstatus == 1 && doc.status == 'Debit Note Issued') {
+ return [__("Debit Note Issued"), "darkgrey", "outstanding_amount,<=,0"];
} else if(flt(doc.outstanding_amount) > 0 && doc.docstatus==1) {
if(cint(doc.on_hold) && !doc.release_date) {
return [__("On Hold"), "darkgrey"];
diff --git a/erpnext/accounts/doctype/purchase_invoice/regional/india.js b/erpnext/accounts/doctype/purchase_invoice/regional/india.js
new file mode 100644
index 0000000..81488a2
--- /dev/null
+++ b/erpnext/accounts/doctype/purchase_invoice/regional/india.js
@@ -0,0 +1,3 @@
+{% include "erpnext/regional/india/taxes.js" %}
+
+erpnext.setup_auto_gst_taxation('Purchase Invoice');
diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
index 6deee38..e41ad42 100644
--- a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
@@ -10,7 +10,7 @@
from frappe.utils import cint, flt, today, nowdate, add_days
import frappe.defaults
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory, \
- test_records as pr_test_records
+ test_records as pr_test_records, make_purchase_receipt, get_taxes
from erpnext.controllers.accounts_controller import get_payment_terms
from erpnext.exceptions import InvalidCurrency
from erpnext.stock.doctype.stock_entry.test_stock_entry import get_qty_after_transaction
@@ -57,16 +57,11 @@
self.assertEqual([d.debit, d.credit], expected_gl_entries.get(d.account))
def test_gl_entries_with_perpetual_inventory(self):
- pi = frappe.copy_doc(test_records[1])
- set_perpetual_inventory(1, pi.company)
+ pi = make_purchase_invoice(company="_Test Company with perpetual inventory", supplier_warehouse="Work In Progress - TCP1", warehouse= "Stores - TCP1", cost_center = "Main - TCP1", expense_account ="_Test Account Cost for Goods Sold - TCP1", get_taxes_and_charges=True, qty=10)
self.assertTrue(cint(erpnext.is_perpetual_inventory_enabled(pi.company)), 1)
- pi.insert()
- pi.submit()
self.check_gle_for_pi(pi.name)
- set_perpetual_inventory(0, pi.company)
-
def test_terms_added_after_save(self):
pi = frappe.copy_doc(test_records[1])
pi.insert()
@@ -196,32 +191,33 @@
self.assertEqual(pi.on_hold, 0)
def test_gl_entries_with_perpetual_inventory_against_pr(self):
- pr = frappe.copy_doc(pr_test_records[0])
- set_perpetual_inventory(1, pr.company)
- self.assertTrue(cint(erpnext.is_perpetual_inventory_enabled(pr.company)), 1)
- pr.submit()
- pi = frappe.copy_doc(test_records[1])
- for d in pi.get("items"):
+ pr = make_purchase_receipt(company="_Test Company with perpetual inventory", supplier_warehouse="Work In Progress - TCP1", warehouse= "Stores - TCP1", cost_center = "Main - TCP1", get_taxes_and_charges=True,)
+
+ self.assertTrue(cint(erpnext.is_perpetual_inventory_enabled(pr.company)), 1)
+
+ pi = make_purchase_invoice(company="_Test Company with perpetual inventory", supplier_warehouse="Work In Progress - TCP1", warehouse= "Stores - TCP1", cost_center = "Main - TCP1", expense_account ="_Test Account Cost for Goods Sold - TCP1", get_taxes_and_charges=True, qty=10,do_not_save= "True")
+
+ for d in pi.items:
d.purchase_receipt = pr.name
+
pi.insert()
pi.submit()
self.check_gle_for_pi(pi.name)
- set_perpetual_inventory(0, pr.company)
-
def check_gle_for_pi(self, pi):
- gl_entries = frappe.db.sql("""select account, debit, credit
+ gl_entries = frappe.db.sql("""select account, sum(debit) as debit, sum(credit) as credit
from `tabGL Entry` where voucher_type='Purchase Invoice' and voucher_no=%s
- order by account asc""", pi, as_dict=1)
+ group by account""", pi, as_dict=1)
+
self.assertTrue(gl_entries)
expected_values = dict((d[0], d) for d in [
- ["_Test Payable - _TC", 0, 720],
- ["Stock Received But Not Billed - _TC", 500.0, 0],
- ["_Test Account Shipping Charges - _TC", 100.0, 0],
- ["_Test Account VAT - _TC", 120.0, 0],
+ ["Creditors - TCP1", 0, 720],
+ ["Stock Received But Not Billed - TCP1", 500.0, 0],
+ ["_Test Account Shipping Charges - TCP1", 100.0, 0.0],
+ ["_Test Account VAT - TCP1", 120.0, 0]
])
for i, gle in enumerate(gl_entries):
@@ -524,10 +520,9 @@
self.assertFalse(gle)
def test_purchase_invoice_update_stock_gl_entry_with_perpetual_inventory(self):
- set_perpetual_inventory()
pi = make_purchase_invoice(update_stock=1, posting_date=frappe.utils.nowdate(),
- posting_time=frappe.utils.nowtime())
+ posting_time=frappe.utils.nowtime(), cash_bank_account="Cash - TCP1", company="_Test Company with perpetual inventory", supplier_warehouse="Work In Progress - TCP1", warehouse= "Stores - TCP1", cost_center = "Main - TCP1", expense_account ="_Test Account Cost for Goods Sold - TCP1")
gl_entries = frappe.db.sql("""select account, account_currency, debit, credit,
debit_in_account_currency, credit_in_account_currency
@@ -548,9 +543,9 @@
self.assertEqual(expected_gl_entries[gle.account][2], gle.credit)
def test_purchase_invoice_for_is_paid_and_update_stock_gl_entry_with_perpetual_inventory(self):
- set_perpetual_inventory()
+
pi = make_purchase_invoice(update_stock=1, posting_date=frappe.utils.nowdate(),
- posting_time=frappe.utils.nowtime(), cash_bank_account="Cash - _TC", is_paid=1)
+ posting_time=frappe.utils.nowtime(), cash_bank_account="Cash - TCP1", is_paid=1, company="_Test Company with perpetual inventory", supplier_warehouse="Work In Progress - TCP1", warehouse= "Stores - TCP1", cost_center = "Main - TCP1", expense_account ="_Test Account Cost for Goods Sold - TCP1")
gl_entries = frappe.db.sql("""select account, account_currency, sum(debit) as debit,
sum(credit) as credit, debit_in_account_currency, credit_in_account_currency
@@ -563,7 +558,7 @@
expected_gl_entries = dict((d[0], d) for d in [
[pi.credit_to, 250.0, 250.0],
[stock_in_hand_account, 250.0, 0.0],
- ["Cash - _TC", 0.0, 250.0]
+ ["Cash - TCP1", 0.0, 250.0]
])
for i, gle in enumerate(gl_entries):
@@ -630,6 +625,7 @@
self.assertEqual(pi.get("items")[0].rm_supp_cost, flt(rm_supp_cost, 2))
def test_rejected_serial_no(self):
+ set_perpetual_inventory(0)
pi = make_purchase_invoice(item_code="_Test Serialized Item With Series", received_qty=2, qty=1,
rejected_qty=1, rate=500, update_stock=1,
rejected_warehouse = "_Test Rejected Warehouse - _TC")
@@ -881,7 +877,7 @@
pi.is_return = args.is_return
pi.return_against = args.return_against
pi.is_subcontracted = args.is_subcontracted or "No"
- pi.supplier_warehouse = "_Test Warehouse 1 - _TC"
+ pi.supplier_warehouse = args.supplier_warehouse or "_Test Warehouse 1 - _TC"
pi.append("items", {
"item_code": args.item or args.item_code or "_Test Item",
@@ -890,14 +886,21 @@
"received_qty": args.received_qty or 0,
"rejected_qty": args.rejected_qty or 0,
"rate": args.rate or 50,
+ 'expense_account': args.expense_account or '_Test Account Cost for Goods Sold - _TC',
"conversion_factor": 1.0,
"serial_no": args.serial_no,
"stock_uom": "_Test UOM",
- "cost_center": "_Test Cost Center - _TC",
+ "cost_center": args.cost_center or "_Test Cost Center - _TC",
"project": args.project,
"rejected_warehouse": args.rejected_warehouse or "",
"rejected_serial_no": args.rejected_serial_no or ""
})
+
+ if args.get_taxes_and_charges:
+ taxes = get_taxes()
+ for tax in taxes:
+ pi.append("taxes", tax)
+
if not args.do_not_save:
pi.insert()
if not args.do_not_submit:
diff --git a/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json b/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json
index 3a19bb1..acb0398 100644
--- a/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json
+++ b/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json
@@ -1,4 +1,5 @@
{
+ "actions": [],
"autoname": "hash",
"creation": "2013-05-22 12:43:10",
"doctype": "DocType",
@@ -71,8 +72,8 @@
"expense_account",
"col_break5",
"is_fixed_asset",
- "asset",
"asset_location",
+ "asset_category",
"deferred_expense_section",
"deferred_expense_account",
"service_stop_date",
@@ -116,6 +117,8 @@
"fieldtype": "Column Break"
},
{
+ "fetch_from": "item_code.item_name",
+ "fetch_if_empty": 1,
"fieldname": "item_name",
"fieldtype": "Data",
"in_global_search": 1,
@@ -414,6 +417,7 @@
"print_hide": 1
},
{
+ "depends_on": "eval:!doc.is_fixed_asset",
"fieldname": "batch_no",
"fieldtype": "Link",
"label": "Batch No",
@@ -425,12 +429,14 @@
"fieldtype": "Column Break"
},
{
+ "depends_on": "eval:!doc.is_fixed_asset",
"fieldname": "serial_no",
"fieldtype": "Text",
"label": "Serial No",
"no_copy": 1
},
{
+ "depends_on": "eval:!doc.is_fixed_asset",
"fieldname": "rejected_serial_no",
"fieldtype": "Text",
"label": "Rejected Serial No",
@@ -502,7 +508,8 @@
"depends_on": "enable_deferred_expense",
"fieldname": "service_stop_date",
"fieldtype": "Date",
- "label": "Service Stop Date"
+ "label": "Service Stop Date",
+ "no_copy": 1
},
{
"default": "0",
@@ -518,13 +525,15 @@
"depends_on": "enable_deferred_expense",
"fieldname": "service_start_date",
"fieldtype": "Date",
- "label": "Service Start Date"
+ "label": "Service Start Date",
+ "no_copy": 1
},
{
"depends_on": "enable_deferred_expense",
"fieldname": "service_end_date",
"fieldtype": "Date",
- "label": "Service End Date"
+ "label": "Service End Date",
+ "no_copy": 1
},
{
"fieldname": "reference",
@@ -615,6 +624,7 @@
},
{
"default": "0",
+ "fetch_from": "item_code.is_fixed_asset",
"fieldname": "is_fixed_asset",
"fieldtype": "Check",
"hidden": 1,
@@ -625,14 +635,6 @@
},
{
"depends_on": "is_fixed_asset",
- "fieldname": "asset",
- "fieldtype": "Link",
- "label": "Asset",
- "no_copy": 1,
- "options": "Asset"
- },
- {
- "depends_on": "is_fixed_asset",
"fieldname": "asset_location",
"fieldtype": "Link",
"label": "Asset Location",
@@ -676,7 +678,7 @@
"fieldname": "pr_detail",
"fieldtype": "Data",
"hidden": 1,
- "label": "PR Detail",
+ "label": "Purchase Receipt Detail",
"no_copy": 1,
"oldfieldname": "pr_detail",
"oldfieldtype": "Data",
@@ -754,11 +756,22 @@
"fieldtype": "Data",
"label": "Manufacturer Part Number",
"read_only": 1
+ },
+ {
+ "depends_on": "is_fixed_asset",
+ "fetch_from": "item_code.asset_category",
+ "fieldname": "asset_category",
+ "fieldtype": "Data",
+ "in_preview": 1,
+ "label": "Asset Category",
+ "options": "Asset Category",
+ "read_only": 1
}
],
"idx": 1,
"istable": 1,
- "modified": "2019-09-17 22:32:05.984240",
+ "links": [],
+ "modified": "2019-12-04 12:23:17.046413",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Invoice Item",
diff --git a/erpnext/accounts/doctype/purchase_taxes_and_charges_template/purchase_taxes_and_charges_template.json b/erpnext/accounts/doctype/purchase_taxes_and_charges_template/purchase_taxes_and_charges_template.json
index bc42630..a18fec6 100644
--- a/erpnext/accounts/doctype/purchase_taxes_and_charges_template/purchase_taxes_and_charges_template.json
+++ b/erpnext/accounts/doctype/purchase_taxes_and_charges_template/purchase_taxes_and_charges_template.json
@@ -1,300 +1,108 @@
{
- "allow_copy": 0,
- "allow_import": 1,
- "allow_rename": 1,
- "autoname": "field:title",
- "beta": 0,
- "creation": "2013-01-10 16:34:08",
- "custom": 0,
- "description": "Standard tax template that can be applied to all Purchase Transactions. This template can contain list of tax heads and also other expense heads like \"Shipping\", \"Insurance\", \"Handling\" etc.\n\n#### Note\n\nThe tax rate you define here will be the standard tax rate for all **Items**. If there are **Items** that have different rates, they must be added in the **Item Tax** table in the **Item** master.\n\n#### Description of Columns\n\n1. Calculation Type: \n - This can be on **Net Total** (that is the sum of basic amount).\n - **On Previous Row Total / Amount** (for cumulative taxes or charges). If you select this option, the tax will be applied as a percentage of the previous row (in the tax table) amount or total.\n - **Actual** (as mentioned).\n2. Account Head: The Account ledger under which this tax will be booked\n3. Cost Center: If the tax / charge is an income (like shipping) or expense it needs to be booked against a Cost Center.\n4. Description: Description of the tax (that will be printed in invoices / quotes).\n5. Rate: Tax rate.\n6. Amount: Tax amount.\n7. Total: Cumulative total to this point.\n8. Enter Row: If based on \"Previous Row Total\" you can select the row number which will be taken as a base for this calculation (default is the previous row).\n9. Consider Tax or Charge for: In this section you can specify if the tax / charge is only for valuation (not a part of total) or only for total (does not add value to the item) or for both.\n10. Add or Deduct: Whether you want to add or deduct the tax.",
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "Setup",
- "editable_grid": 0,
+ "allow_import": 1,
+ "allow_rename": 1,
+ "creation": "2013-01-10 16:34:08",
+ "description": "Standard tax template that can be applied to all Purchase Transactions. This template can contain list of tax heads and also other expense heads like \"Shipping\", \"Insurance\", \"Handling\" etc.\n\n#### Note\n\nThe tax rate you define here will be the standard tax rate for all **Items**. If there are **Items** that have different rates, they must be added in the **Item Tax** table in the **Item** master.\n\n#### Description of Columns\n\n1. Calculation Type: \n - This can be on **Net Total** (that is the sum of basic amount).\n - **On Previous Row Total / Amount** (for cumulative taxes or charges). If you select this option, the tax will be applied as a percentage of the previous row (in the tax table) amount or total.\n - **Actual** (as mentioned).\n2. Account Head: The Account ledger under which this tax will be booked\n3. Cost Center: If the tax / charge is an income (like shipping) or expense it needs to be booked against a Cost Center.\n4. Description: Description of the tax (that will be printed in invoices / quotes).\n5. Rate: Tax rate.\n6. Amount: Tax amount.\n7. Total: Cumulative total to this point.\n8. Enter Row: If based on \"Previous Row Total\" you can select the row number which will be taken as a base for this calculation (default is the previous row).\n9. Consider Tax or Charge for: In this section you can specify if the tax / charge is only for valuation (not a part of total) or only for total (does not add value to the item) or for both.\n10. Add or Deduct: Whether you want to add or deduct the tax.",
+ "doctype": "DocType",
+ "document_type": "Setup",
+ "field_order": [
+ "title",
+ "is_default",
+ "disabled",
+ "column_break4",
+ "company",
+ "tax_category",
+ "section_break6",
+ "taxes"
+ ],
"fields": [
{
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "title",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 1,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Title",
- "length": 0,
- "no_copy": 1,
- "oldfieldname": "title",
- "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": "title",
+ "fieldtype": "Data",
+ "label": "Title",
+ "no_copy": 1,
+ "oldfieldname": "title",
+ "oldfieldtype": "Data",
+ "reqd": 1
+ },
{
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "is_default",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Default",
- "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
- },
+ "default": "0",
+ "fieldname": "is_default",
+ "fieldtype": "Check",
+ "in_list_view": 1,
+ "label": "Default"
+ },
{
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "disabled",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Disabled",
- "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
- },
+ "default": "0",
+ "fieldname": "disabled",
+ "fieldtype": "Check",
+ "in_list_view": 1,
+ "label": "Disabled"
+ },
{
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break4",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "fieldname": "column_break4",
+ "fieldtype": "Column Break"
+ },
{
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "company",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 1,
- "in_list_view": 1,
- "in_standard_filter": 1,
- "label": "Company",
- "length": 0,
- "no_copy": 0,
- "options": "Company",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 1,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "in_standard_filter": 1,
+ "label": "Company",
+ "options": "Company",
+ "remember_last_selected_value": 1,
+ "reqd": 1
+ },
{
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "section_break6",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "fieldname": "section_break6",
+ "fieldtype": "Section Break"
+ },
{
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "taxes",
- "fieldtype": "Table",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Purchase Taxes and Charges",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "purchase_tax_details",
- "oldfieldtype": "Table",
- "options": "Purchase Taxes and Charges",
- "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": "taxes",
+ "fieldtype": "Table",
+ "label": "Purchase Taxes and Charges",
+ "oldfieldname": "purchase_tax_details",
+ "oldfieldtype": "Table",
+ "options": "Purchase Taxes and Charges"
+ },
+ {
+ "fieldname": "tax_category",
+ "fieldtype": "Link",
+ "label": "Tax Category",
+ "options": "Tax Category"
}
- ],
- "hide_heading": 0,
- "hide_toolbar": 0,
- "icon": "fa fa-money",
- "idx": 1,
- "image_view": 0,
- "in_create": 0,
-
- "is_submittable": 0,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2016-11-07 05:18:44.095798",
- "modified_by": "Administrator",
- "module": "Accounts",
- "name": "Purchase Taxes and Charges Template",
- "owner": "wasim@webnotestech.com",
+ ],
+ "icon": "fa fa-money",
+ "idx": 1,
+ "modified": "2019-11-25 13:05:26.220275",
+ "modified_by": "Administrator",
+ "module": "Accounts",
+ "name": "Purchase Taxes and Charges Template",
+ "owner": "wasim@webnotestech.com",
"permissions": [
{
- "amend": 0,
- "apply_user_permissions": 0,
- "cancel": 0,
- "create": 0,
- "delete": 0,
- "email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "is_custom": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Purchase Manager",
- "set_user_permissions": 0,
- "share": 0,
- "submit": 0,
- "write": 0
- },
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Purchase Manager"
+ },
{
- "amend": 0,
- "apply_user_permissions": 0,
- "cancel": 0,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "is_custom": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Purchase Master Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Purchase Master 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,
- "is_custom": 0,
- "permlevel": 0,
- "print": 0,
- "read": 1,
- "report": 0,
- "role": "Purchase User",
- "set_user_permissions": 0,
- "share": 0,
- "submit": 0,
- "write": 0
+ "read": 1,
+ "role": "Purchase User"
}
- ],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "sort_order": "DESC",
- "track_seen": 0
+ ],
+ "sort_order": "DESC",
+ "track_changes": 1
}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/sales_invoice/pos.py b/erpnext/accounts/doctype/sales_invoice/pos.py
index 7d4fc63..a48d224 100755
--- a/erpnext/accounts/doctype/sales_invoice/pos.py
+++ b/erpnext/accounts/doctype/sales_invoice/pos.py
@@ -357,14 +357,11 @@
def get_bin_data(pos_profile):
itemwise_bin_data = {}
- cond = "1=1"
+ filters = { 'actual_qty': ['>', 0] }
if pos_profile.get('warehouse'):
- cond = "warehouse = %(warehouse)s"
+ filters.update({ 'warehouse': pos_profile.get('warehouse') })
- bin_data = frappe.db.sql(""" select item_code, warehouse, actual_qty from `tabBin`
- where actual_qty > 0 and {cond}""".format(cond=cond), {
- 'warehouse': frappe.db.escape(pos_profile.get('warehouse'))
- }, as_dict=1)
+ bin_data = frappe.db.get_all('Bin', fields = ['item_code', 'warehouse', 'actual_qty'], filters=filters)
for bins in bin_data:
if bins.item_code not in itemwise_bin_data:
@@ -402,14 +399,21 @@
for docs in doc_list:
for name, doc in iteritems(docs):
if not frappe.db.exists('Sales Invoice', {'offline_pos_name': name}):
- validate_records(doc)
- si_doc = frappe.new_doc('Sales Invoice')
- si_doc.offline_pos_name = name
- si_doc.update(doc)
- si_doc.set_posting_time = 1
- si_doc.customer = get_customer_id(doc)
- si_doc.due_date = doc.get('posting_date')
- name_list = submit_invoice(si_doc, name, doc, name_list)
+ if isinstance(doc, dict):
+ validate_records(doc)
+ si_doc = frappe.new_doc('Sales Invoice')
+ si_doc.offline_pos_name = name
+ si_doc.update(doc)
+ si_doc.set_posting_time = 1
+ si_doc.customer = get_customer_id(doc)
+ si_doc.due_date = doc.get('posting_date')
+ name_list = submit_invoice(si_doc, name, doc, name_list)
+ else:
+ doc.due_date = doc.get('posting_date')
+ doc.customer = get_customer_id(doc)
+ doc.set_posting_time = 1
+ doc.offline_pos_name = name
+ name_list = submit_invoice(doc, name, doc, name_list)
else:
name_list.append(name)
@@ -543,11 +547,15 @@
def make_email_queue(email_queue):
name_list = []
+
for key, data in iteritems(email_queue):
name = frappe.db.get_value('Sales Invoice', {'offline_pos_name': key}, 'name')
+ if not name: continue
+
data = json.loads(data)
sender = frappe.session.user
print_format = "POS Invoice" if not cint(frappe.db.get_value('Print Format', 'POS Invoice', 'disabled')) else None
+
attachments = [frappe.attach_print('Sales Invoice', name, print_format=print_format)]
make(subject=data.get('subject'), content=data.get('content'), recipients=data.get('recipients'),
diff --git a/erpnext/accounts/doctype/sales_invoice/regional/india.js b/erpnext/accounts/doctype/sales_invoice/regional/india.js
index c8305e3..48fa364 100644
--- a/erpnext/accounts/doctype/sales_invoice/regional/india.js
+++ b/erpnext/accounts/doctype/sales_invoice/regional/india.js
@@ -1,3 +1,7 @@
+{% include "erpnext/regional/india/taxes.js" %}
+
+erpnext.setup_auto_gst_taxation('Sales Invoice');
+
frappe.ui.form.on("Sales Invoice", {
setup: function(frm) {
frm.set_query('transporter', function() {
@@ -35,4 +39,5 @@
}, __("Make"));
}
}
+
});
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
index 3c85210..db6ac55 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
@@ -556,22 +556,11 @@
}
cur_frm.set_query("debit_to", function(doc) {
- // filter on Account
- if (doc.customer) {
- return {
- filters: {
- 'account_type': 'Receivable',
- 'is_group': 0,
- 'company': doc.company
- }
- }
- } else {
- return {
- filters: {
- 'report_type': 'Balance Sheet',
- 'is_group': 0,
- 'company': doc.company
- }
+ return {
+ filters: {
+ 'account_type': 'Receivable',
+ 'is_group': 0,
+ 'company': doc.company
}
}
});
@@ -697,8 +686,8 @@
if (frm.doc.company)
{
frappe.call({
- method:"frappe.contacts.doctype.address.address.get_default_address",
- args:{ doctype:'Company',name:frm.doc.company},
+ method:"erpnext.setup.doctype.company.company.get_default_company_address",
+ args:{name:frm.doc.company, existing_address: frm.doc.company_address},
callback: function(r){
if (r.message){
frm.set_value("company_address",r.message)
@@ -789,22 +778,21 @@
method: "frappe.client.get_value",
args:{
doctype: "Patient",
- filters: {"name": frm.doc.patient},
+ filters: {
+ "name": frm.doc.patient
+ },
fieldname: "customer"
},
- callback:function(patient_customer) {
- if(patient_customer){
- frm.set_value("customer", patient_customer.message.customer);
- frm.refresh_fields();
+ callback:function(r) {
+ if(r && r.message.customer){
+ frm.set_value("customer", r.message.customer);
}
}
});
}
- else{
- frm.set_value("customer", '');
- }
}
},
+
refresh: function(frm) {
if (frappe.boot.active_domains.includes("Healthcare")){
frm.set_df_property("patient", "hidden", 0);
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
index 96aceac..33ee7a2 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
@@ -1,4 +1,5 @@
{
+ "actions": [],
"allow_import": 1,
"autoname": "naming_series:",
"creation": "2013-05-24 19:29:05",
@@ -774,7 +775,7 @@
},
{
"fieldname": "other_charges_calculation",
- "fieldtype": "Text",
+ "fieldtype": "Long Text",
"label": "Taxes and Charges Calculation",
"no_copy": 1,
"oldfieldtype": "HTML",
@@ -1567,7 +1568,8 @@
"icon": "fa fa-file-text",
"idx": 181,
"is_submittable": 1,
- "modified": "2019-10-05 21:39:49.235990",
+ "links": [],
+ "modified": "2019-12-30 19:15:59.580414",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice",
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index e1256a7..703df79 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -90,6 +90,7 @@
self.validate_account_for_change_amount()
self.validate_fixed_asset()
self.set_income_account_for_fixed_assets()
+ self.validate_item_cost_centers()
validate_inter_company_party(self.doctype, self.customer, self.company, self.inter_company_invoice_reference)
if cint(self.is_pos):
@@ -136,6 +137,22 @@
if self.redeem_loyalty_points and self.loyalty_program and self.loyalty_points:
validate_loyalty_points(self, self.loyalty_points)
+ def validate_fixed_asset(self):
+ for d in self.get("items"):
+ if d.is_fixed_asset and d.meta.get_field("asset") and d.asset:
+ asset = frappe.get_doc("Asset", d.asset)
+ if self.doctype == "Sales Invoice" and self.docstatus == 1:
+ if self.update_stock:
+ frappe.throw(_("'Update Stock' cannot be checked for fixed asset sale"))
+
+ elif asset.status in ("Scrapped", "Cancelled", "Sold"):
+ frappe.throw(_("Row #{0}: Asset {1} cannot be submitted, it is already {2}").format(d.idx, d.asset, asset.status))
+
+ def validate_item_cost_centers(self):
+ for item in self.items:
+ cost_center_company = frappe.get_cached_value("Cost Center", item.cost_center, "company")
+ if cost_center_company != self.company:
+ frappe.throw(_("Row #{0}: Cost Center {1} does not belong to company {2}").format(frappe.bold(item.idx), frappe.bold(item.cost_center), frappe.bold(self.company)))
def before_save(self):
set_account_for_mode_of_payment(self)
@@ -338,7 +355,8 @@
"print_format": print_format,
"allow_edit_rate": pos.get("allow_user_to_edit_rate"),
"allow_edit_discount": pos.get("allow_user_to_edit_discount"),
- "campaign": pos.get("campaign")
+ "campaign": pos.get("campaign"),
+ "allow_print_before_pay": pos.get("allow_print_before_pay")
}
def update_time_sheet(self, sales_invoice):
@@ -525,9 +543,7 @@
for i in dic:
if frappe.db.get_single_value('Selling Settings', dic[i][0]) == 'Yes':
for d in self.get('items'):
- is_stock_item = frappe.get_cached_value('Item', d.item_code, 'is_stock_item')
- if (d.item_code and is_stock_item == 1\
- and not d.get(i.lower().replace(' ','_')) and not self.get(dic[i][1])):
+ if (d.item_code and not d.get(i.lower().replace(' ','_')) and not self.get(dic[i][1])):
msgprint(_("{0} is mandatory for Item {1}").format(i,d.item_code), raise_exception=1)
@@ -686,7 +702,6 @@
def make_gl_entries(self, gl_entries=None, repost_future_gle=True, from_repost=False):
auto_accounting_for_stock = erpnext.is_perpetual_inventory_enabled(self.company)
-
if not gl_entries:
gl_entries = self.get_gl_entries()
@@ -944,7 +959,7 @@
)
def make_gle_for_rounding_adjustment(self, gl_entries):
- if flt(self.rounding_adjustment, self.precision("rounding_adjustment")):
+ if flt(self.rounding_adjustment, self.precision("rounding_adjustment")) and self.base_rounding_adjustment:
round_off_account, round_off_cost_center = \
get_round_off_account_and_cost_center(self.company)
@@ -992,10 +1007,8 @@
continue
for serial_no in item.serial_no.split("\n"):
- if serial_no and frappe.db.exists('Serial No', serial_no):
- sno = frappe.get_doc('Serial No', serial_no)
- sno.sales_invoice = invoice
- sno.db_update()
+ if serial_no and frappe.db.get_value('Serial No', serial_no, 'item_code') == item.item_code:
+ frappe.db.set_value('Serial No', serial_no, 'sales_invoice', invoice)
def validate_serial_numbers(self):
"""
@@ -1041,12 +1054,18 @@
continue
for serial_no in item.serial_no.split("\n"):
- sales_invoice = frappe.db.get_value("Serial No", serial_no, "sales_invoice")
- if sales_invoice and self.name != sales_invoice:
- sales_invoice_company = frappe.db.get_value("Sales Invoice", sales_invoice, "company")
+ serial_no_details = frappe.db.get_value("Serial No", serial_no,
+ ["sales_invoice", "item_code"], as_dict=1)
+
+ if not serial_no_details:
+ continue
+
+ if serial_no_details.sales_invoice and serial_no_details.item_code == item.item_code \
+ and self.name != serial_no_details.sales_invoice:
+ sales_invoice_company = frappe.db.get_value("Sales Invoice", serial_no_details.sales_invoice, "company")
if sales_invoice_company == self.company:
frappe.throw(_("Serial Number: {0} is already referenced in Sales Invoice: {1}"
- .format(serial_no, sales_invoice)))
+ .format(serial_no, serial_no_details.sales_invoice)))
def update_project(self):
if self.project:
@@ -1231,7 +1250,8 @@
self.status = "Unpaid and Discounted"
elif flt(self.outstanding_amount) > 0 and getdate(self.due_date) >= getdate(nowdate()):
self.status = "Unpaid"
- elif flt(self.outstanding_amount) < 0 and self.is_return==0 and frappe.db.get_value('Sales Invoice', {'is_return': 1, 'return_against': self.name, 'docstatus': 1}):
+ #Check if outstanding amount is 0 due to credit note issued against invoice
+ elif flt(self.outstanding_amount) <= 0 and self.is_return == 0 and frappe.db.get_value('Sales Invoice', {'is_return': 1, 'return_against': self.name, 'docstatus': 1}):
self.status = "Credit Note Issued"
elif self.is_return == 1:
self.status = "Return"
diff --git a/erpnext/accounts/doctype/sales_invoice/test_records.json b/erpnext/accounts/doctype/sales_invoice/test_records.json
index 9c8de7d..ebe6e3d 100644
--- a/erpnext/accounts/doctype/sales_invoice/test_records.json
+++ b/erpnext/accounts/doctype/sales_invoice/test_records.json
@@ -68,8 +68,6 @@
"selling_price_list": "_Test Price List",
"territory": "_Test Territory"
},
-
-
{
"company": "_Test Company",
"conversion_rate": 1.0,
@@ -276,7 +274,6 @@
"uom": "_Test UOM 1",
"conversion_factor": 1,
"stock_uom": "_Test UOM 1"
-
},
{
"cost_center": "_Test Cost Center - _TC",
diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
index 4f253b6..a2a47b3 100644
--- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
@@ -5,7 +5,7 @@
import frappe
import unittest, copy, time
-from frappe.utils import nowdate, flt, getdate, cint
+from frappe.utils import nowdate, flt, getdate, cint, add_days
from frappe.model.dynamic_links import get_dynamic_link_map
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry, get_qty_after_transaction
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import unlink_payment_on_cancel_of_invoice
@@ -20,6 +20,9 @@
from six import iteritems
from erpnext.accounts.doctype.sales_invoice.sales_invoice import make_inter_company_transaction
from erpnext.regional.india.utils import get_ewb_data
+from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
+from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt
+from erpnext.stock.doctype.delivery_note.delivery_note import make_sales_invoice
class TestSalesInvoice(unittest.TestCase):
def make(self):
@@ -550,7 +553,6 @@
si.get("taxes")[6].tax_amount = 2
si.insert()
- print(si.name)
expected_values = [
{
@@ -679,56 +681,67 @@
self.assertFalse(gle)
def test_pos_gl_entry_with_perpetual_inventory(self):
- set_perpetual_inventory()
make_pos_profile()
- self._insert_purchase_receipt()
- pos = copy.deepcopy(test_records[1])
- pos["is_pos"] = 1
- pos["update_stock"] = 1
- pos["payments"] = [{'mode_of_payment': 'Bank Draft', 'account': '_Test Bank - _TC', 'amount': 300},
- {'mode_of_payment': 'Cash', 'account': 'Cash - _TC', 'amount': 300}]
+ pr = make_purchase_receipt(company= "_Test Company with perpetual inventory",supplier_warehouse= "Work In Progress - TCP1", item_code= "_Test FG Item",warehouse= "Stores - TCP1",cost_center= "Main - TCP1")
+
+ pos = create_sales_invoice(company= "_Test Company with perpetual inventory", debit_to="Debtors - TCP1", item_code= "_Test FG Item", warehouse="Stores - TCP1", income_account = "Sales - TCP1", expense_account = "Cost of Goods Sold - TCP1", cost_center = "Main - TCP1", do_not_save=True)
+
+ pos.is_pos = 1
+ pos.update_stock = 1
+
+ pos.append("payments", {'mode_of_payment': 'Bank Draft', 'account': '_Test Bank - TCP1', 'amount': 50})
+ pos.append("payments", {'mode_of_payment': 'Cash', 'account': 'Cash - TCP1', 'amount': 50})
+
+ taxes = get_taxes_and_charges()
+ pos.taxes = []
+ for tax in taxes:
+ pos.append("taxes", tax)
si = frappe.copy_doc(pos)
si.insert()
si.submit()
+ self.assertEqual(si.paid_amount, 100.0)
- self.assertEqual(si.paid_amount, 600.0)
-
- self.pos_gl_entry(si, pos, 300)
+ self.pos_gl_entry(si, pos, 50)
def test_pos_change_amount(self):
- set_perpetual_inventory()
make_pos_profile()
- self._insert_purchase_receipt()
- pos = copy.deepcopy(test_records[1])
- pos["is_pos"] = 1
- pos["update_stock"] = 1
- pos["payments"] = [{'mode_of_payment': 'Bank Draft', 'account': '_Test Bank - _TC', 'amount': 300},
- {'mode_of_payment': 'Cash', 'account': 'Cash - _TC', 'amount': 340}]
+ pr = make_purchase_receipt(company= "_Test Company with perpetual inventory",supplier_warehouse= "Work In Progress - TCP1", item_code= "_Test FG Item",warehouse= "Stores - TCP1",cost_center= "Main - TCP1")
- si = frappe.copy_doc(pos)
- si.change_amount = 5.0
- si.insert()
- si.submit()
+ pos = create_sales_invoice(company= "_Test Company with perpetual inventory", debit_to="Debtors - TCP1", item_code= "_Test FG Item", warehouse="Stores - TCP1", income_account = "Sales - TCP1", expense_account = "Cost of Goods Sold - TCP1", cost_center = "Main - TCP1", do_not_save=True)
- self.assertEqual(si.grand_total, 630.0)
- self.assertEqual(si.write_off_amount, -5)
+ pos.is_pos = 1
+ pos.update_stock = 1
+
+ pos.append("payments", {'mode_of_payment': 'Bank Draft', 'account': '_Test Bank - TCP1', 'amount': 50})
+ pos.append("payments", {'mode_of_payment': 'Cash', 'account': 'Cash - TCP1', 'amount': 60})
+
+ pos.change_amount = 5.0
+ pos.insert()
+ pos.submit()
+
+ self.assertEqual(pos.grand_total, 100.0)
+ self.assertEqual(pos.write_off_amount, -5)
def test_make_pos_invoice(self):
from erpnext.accounts.doctype.sales_invoice.pos import make_invoice
- set_perpetual_inventory()
-
make_pos_profile()
- self._insert_purchase_receipt()
+ pr = make_purchase_receipt(company= "_Test Company with perpetual inventory",supplier_warehouse= "Work In Progress - TCP1", item_code= "_Test FG Item",warehouse= "Stores - TCP1",cost_center= "Main - TCP1")
+ pos = create_sales_invoice(company= "_Test Company with perpetual inventory", debit_to="Debtors - TCP1", item_code= "_Test FG Item", warehouse="Stores - TCP1", income_account = "Sales - TCP1", expense_account = "Cost of Goods Sold - TCP1", cost_center = "Main - TCP1", do_not_save=True)
- pos = copy.deepcopy(test_records[1])
- pos["is_pos"] = 1
- pos["update_stock"] = 1
- pos["payments"] = [{'mode_of_payment': 'Bank Draft', 'account': '_Test Bank - _TC', 'amount': 300},
- {'mode_of_payment': 'Cash', 'account': 'Cash - _TC', 'amount': 330}]
+ pos.is_pos = 1
+ pos.update_stock = 1
+
+ pos.append("payments", {'mode_of_payment': 'Bank Draft', 'account': '_Test Bank - TCP1', 'amount': 50})
+ pos.append("payments", {'mode_of_payment': 'Cash', 'account': 'Cash - TCP1', 'amount': 50})
+
+ taxes = get_taxes_and_charges()
+ pos.taxes = []
+ for tax in taxes:
+ pos.append("taxes", tax)
invoice_data = [{'09052016142': pos}]
si = make_invoice(invoice_data).get('invoice')
@@ -736,16 +749,15 @@
sales_invoice = frappe.get_all('Sales Invoice', fields =["*"], filters = {'offline_pos_name': '09052016142', 'docstatus': 1})
si = frappe.get_doc('Sales Invoice', sales_invoice[0].name)
- self.assertEqual(si.grand_total, 630.0)
- self.pos_gl_entry(si, pos, 330)
+ self.assertEqual(si.grand_total, 100)
+
+ self.pos_gl_entry(si, pos, 50)
def test_make_pos_invoice_in_draft(self):
from erpnext.accounts.doctype.sales_invoice.pos import make_invoice
from erpnext.stock.doctype.item.test_item import make_item
- set_perpetual_inventory()
-
allow_negative_stock = frappe.db.get_single_value('Stock Settings', 'allow_negative_stock')
if allow_negative_stock:
frappe.db.set_value('Stock Settings', None, 'allow_negative_stock', 0)
@@ -789,7 +801,7 @@
si.name, as_dict=1)[0]
self.assertTrue(sle)
self.assertEqual([sle.item_code, sle.warehouse, sle.actual_qty],
- ["_Test Item", "_Test Warehouse - _TC", -1.0])
+ ['_Test FG Item', 'Stores - TCP1', -1.0])
# check gl entries
gl_entries = frappe.db.sql("""select account, debit, credit
@@ -797,19 +809,19 @@
order by account asc, debit asc, credit asc""", si.name, as_dict=1)
self.assertTrue(gl_entries)
- stock_in_hand = get_inventory_account('_Test Company')
-
+ stock_in_hand = get_inventory_account('_Test Company with perpetual inventory')
expected_gl_entries = sorted([
- [si.debit_to, 630.0, 0.0],
- [pos["items"][0]["income_account"], 0.0, 500.0],
- [pos["taxes"][0]["account_head"], 0.0, 80.0],
- [pos["taxes"][1]["account_head"], 0.0, 50.0],
+ [si.debit_to, 100.0, 0.0],
+ [pos.items[0].income_account, 0.0, 89.09],
+ ['Round Off - TCP1', 0.0, 0.01],
+ [pos.taxes[0].account_head, 0.0, 10.69],
+ [pos.taxes[1].account_head, 0.0, 0.21],
[stock_in_hand, 0.0, abs(sle.stock_value_difference)],
- [pos["items"][0]["expense_account"], abs(sle.stock_value_difference), 0.0],
- [si.debit_to, 0.0, 300.0],
+ [pos.items[0].expense_account, abs(sle.stock_value_difference), 0.0],
+ [si.debit_to, 0.0, 50.0],
[si.debit_to, 0.0, cash_amount],
- ["_Test Bank - _TC", 300.0, 0.0],
- ["Cash - _TC", cash_amount, 0.0]
+ ["_Test Bank - TCP1", 50, 0.0],
+ ["Cash - TCP1", cash_amount, 0.0]
])
for i, gle in enumerate(sorted(gl_entries, key=lambda gle: gle.account)):
@@ -823,9 +835,9 @@
self.assertFalse(gle)
- set_perpetual_inventory(0)
frappe.db.sql("delete from `tabPOS Profile`")
+ si.delete()
def test_pos_si_without_payment(self):
set_perpetual_inventory()
@@ -1008,7 +1020,6 @@
"""
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_serialized_item
from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note
- from erpnext.stock.doctype.delivery_note.delivery_note import make_sales_invoice
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
se = make_serialized_item()
@@ -1023,14 +1034,17 @@
self.assertEqual(si.get("items")[0].serial_no, dn.get("items")[0].serial_no)
def test_return_sales_invoice(self):
- set_perpetual_inventory()
- make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC", qty=50, basic_rate=100)
+ make_stock_entry(item_code="_Test Item", target="Stores - TCP1", qty=50, basic_rate=100)
- actual_qty_0 = get_qty_after_transaction()
+ actual_qty_0 = get_qty_after_transaction(item_code = "_Test Item", warehouse = "Stores - TCP1")
- si = create_sales_invoice(qty=5, rate=500, update_stock=1)
+ si = create_sales_invoice(qty = 5, rate=500, update_stock=1, company= "_Test Company with perpetual inventory", debit_to="Debtors - TCP1", item_code= "_Test Item", warehouse="Stores - TCP1", income_account = "Sales - TCP1", expense_account = "Cost of Goods Sold - TCP1", cost_center = "Main - TCP1")
- actual_qty_1 = get_qty_after_transaction()
+
+ actual_qty_1 = get_qty_after_transaction(item_code = "_Test Item", warehouse = "Stores - TCP1")
+
+ frappe.db.commit()
+
self.assertEqual(actual_qty_0 - 5, actual_qty_1)
# outgoing_rate
@@ -1038,10 +1052,9 @@
"voucher_no": si.name}, "stock_value_difference") / 5
# return entry
- si1 = create_sales_invoice(is_return=1, return_against=si.name, qty=-2, rate=500, update_stock=1)
+ si1 = create_sales_invoice(is_return=1, return_against=si.name, qty=-2, rate=500, update_stock=1, company= "_Test Company with perpetual inventory", debit_to="Debtors - TCP1", item_code= "_Test Item", warehouse="Stores - TCP1", income_account = "Sales - TCP1", expense_account = "Cost of Goods Sold - TCP1", cost_center = "Main - TCP1")
- actual_qty_2 = get_qty_after_transaction()
-
+ actual_qty_2 = get_qty_after_transaction(item_code = "_Test Item", warehouse = "Stores - TCP1")
self.assertEqual(actual_qty_1 + 2, actual_qty_2)
incoming_rate, stock_value_difference = frappe.db.get_value("Stock Ledger Entry",
@@ -1049,7 +1062,7 @@
["incoming_rate", "stock_value_difference"])
self.assertEqual(flt(incoming_rate, 3), abs(flt(outgoing_rate, 3)))
- stock_in_hand_account = get_inventory_account('_Test Company', si1.items[0].warehouse)
+ stock_in_hand_account = get_inventory_account('_Test Company with perpetual inventory', si1.items[0].warehouse)
# Check gl entry
gle_warehouse_amount = frappe.db.get_value("GL Entry", {"voucher_type": "Sales Invoice",
@@ -1058,7 +1071,7 @@
self.assertEqual(gle_warehouse_amount, stock_value_difference)
party_credited = frappe.db.get_value("GL Entry", {"voucher_type": "Sales Invoice",
- "voucher_no": si1.name, "account": "Debtors - _TC", "party": "_Test Customer"}, "credit")
+ "voucher_no": si1.name, "account": "Debtors - TCP1", "party": "_Test Customer"}, "credit")
self.assertEqual(party_credited, 1000)
@@ -1066,7 +1079,6 @@
self.assertFalse(si1.outstanding_amount)
self.assertEqual(frappe.db.get_value("Sales Invoice", si.name, "outstanding_amount"), 1500)
- set_perpetual_inventory(0)
def test_discount_on_net_total(self):
si = frappe.copy_doc(test_records[2])
@@ -1524,6 +1536,8 @@
self.assertEqual(si.total_taxes_and_charges, 577.05)
self.assertEqual(si.grand_total, 1827.05)
+
+
def test_create_invoice_without_terms(self):
si = create_sales_invoice(do_not_save=1)
self.assertFalse(si.get('payment_schedule'))
@@ -1833,6 +1847,26 @@
self.assertEqual(data['billLists'][0]['vehicleNo'], 'KA12KA1234')
self.assertEqual(data['billLists'][0]['itemList'][0]['taxableAmount'], 60000)
+ def test_item_tax_validity(self):
+ item = frappe.get_doc("Item", "_Test Item 2")
+
+ if item.taxes:
+ item.taxes = []
+ item.save()
+
+ item.append("taxes", {
+ "item_tax_template": "_Test Item Tax Template 1",
+ "valid_from": add_days(nowdate(), 1)
+ })
+
+ item.save()
+
+ sales_invoice = create_sales_invoice(item = "_Test Item 2", do_not_save=1)
+ sales_invoice.items[0].item_tax_template = "_Test Item Tax Template 1"
+ self.assertRaises(frappe.ValidationError, sales_invoice.save)
+
+ item.taxes = []
+ item.save()
def create_sales_invoice(**args):
si = frappe.new_doc("Sales Invoice")
@@ -1930,4 +1964,29 @@
if against_voucher_type == 'Purchase Invoice':
bal = bal * -1
- return bal
\ No newline at end of file
+ return bal
+
+def get_taxes_and_charges():
+ return [{
+ "account_head": "_Test Account Excise Duty - TCP1",
+ "charge_type": "On Net Total",
+ "cost_center": "Main - TCP1",
+ "description": "Excise Duty",
+ "doctype": "Sales Taxes and Charges",
+ "idx": 1,
+ "included_in_print_rate": 1,
+ "parentfield": "taxes",
+ "rate": 12
+ },
+ {
+ "account_head": "_Test Account Education Cess - TCP1",
+ "charge_type": "On Previous Row Amount",
+ "cost_center": "Main - TCP1",
+ "description": "Education Cess",
+ "doctype": "Sales Taxes and Charges",
+ "idx": 2,
+ "included_in_print_rate": 1,
+ "parentfield": "taxes",
+ "rate": 2,
+ "row_id": 1
+ }]
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json
index 779ac4f..b2294e4 100644
--- a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json
+++ b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json
@@ -1,4 +1,5 @@
{
+ "actions": [],
"autoname": "hash",
"creation": "2013-06-04 11:02:19",
"doctype": "DocType",
@@ -484,7 +485,8 @@
"depends_on": "enable_deferred_revenue",
"fieldname": "service_stop_date",
"fieldtype": "Date",
- "label": "Service Stop Date"
+ "label": "Service Stop Date",
+ "no_copy": 1
},
{
"default": "0",
@@ -500,13 +502,15 @@
"depends_on": "enable_deferred_revenue",
"fieldname": "service_start_date",
"fieldtype": "Date",
- "label": "Service Start Date"
+ "label": "Service Start Date",
+ "no_copy": 1
},
{
"depends_on": "enable_deferred_revenue",
"fieldname": "service_end_date",
"fieldtype": "Date",
- "label": "Service End Date"
+ "label": "Service End Date",
+ "no_copy": 1
},
{
"collapsible": 1,
@@ -783,7 +787,8 @@
],
"idx": 1,
"istable": 1,
- "modified": "2019-07-16 16:36:46.527606",
+ "links": [],
+ "modified": "2019-12-04 12:22:38.517710",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice Item",
diff --git a/erpnext/accounts/doctype/sales_taxes_and_charges_template/sales_taxes_and_charges_template.json b/erpnext/accounts/doctype/sales_taxes_and_charges_template/sales_taxes_and_charges_template.json
index 29e15d1..19781bd 100644
--- a/erpnext/accounts/doctype/sales_taxes_and_charges_template/sales_taxes_and_charges_template.json
+++ b/erpnext/accounts/doctype/sales_taxes_and_charges_template/sales_taxes_and_charges_template.json
@@ -1,299 +1,119 @@
{
- "allow_copy": 0,
- "allow_import": 1,
- "allow_rename": 1,
- "autoname": "field:title",
- "beta": 0,
- "creation": "2013-01-10 16:34:09",
- "custom": 0,
- "description": "Standard tax template that can be applied to all Sales Transactions. This template can contain list of tax heads and also other expense / income heads like \"Shipping\", \"Insurance\", \"Handling\" etc.\n\n#### Note\n\nThe tax rate you define here will be the standard tax rate for all **Items**. If there are **Items** that have different rates, they must be added in the **Item Tax** table in the **Item** master.\n\n#### Description of Columns\n\n1. Calculation Type: \n - This can be on **Net Total** (that is the sum of basic amount).\n - **On Previous Row Total / Amount** (for cumulative taxes or charges). If you select this option, the tax will be applied as a percentage of the previous row (in the tax table) amount or total.\n - **Actual** (as mentioned).\n2. Account Head: The Account ledger under which this tax will be booked\n3. Cost Center: If the tax / charge is an income (like shipping) or expense it needs to be booked against a Cost Center.\n4. Description: Description of the tax (that will be printed in invoices / quotes).\n5. Rate: Tax rate.\n6. Amount: Tax amount.\n7. Total: Cumulative total to this point.\n8. Enter Row: If based on \"Previous Row Total\" you can select the row number which will be taken as a base for this calculation (default is the previous row).\n9. Is this Tax included in Basic Rate?: If you check this, it means that this tax will not be shown below the item table, but will be included in the Basic Rate in your main item table. This is useful where you want give a flat price (inclusive of all taxes) price to customers.",
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "Setup",
- "editable_grid": 0,
+ "allow_import": 1,
+ "allow_rename": 1,
+ "creation": "2013-01-10 16:34:09",
+ "description": "Standard tax template that can be applied to all Sales Transactions. This template can contain list of tax heads and also other expense / income heads like \"Shipping\", \"Insurance\", \"Handling\" etc.\n\n#### Note\n\nThe tax rate you define here will be the standard tax rate for all **Items**. If there are **Items** that have different rates, they must be added in the **Item Tax** table in the **Item** master.\n\n#### Description of Columns\n\n1. Calculation Type: \n - This can be on **Net Total** (that is the sum of basic amount).\n - **On Previous Row Total / Amount** (for cumulative taxes or charges). If you select this option, the tax will be applied as a percentage of the previous row (in the tax table) amount or total.\n - **Actual** (as mentioned).\n2. Account Head: The Account ledger under which this tax will be booked\n3. Cost Center: If the tax / charge is an income (like shipping) or expense it needs to be booked against a Cost Center.\n4. Description: Description of the tax (that will be printed in invoices / quotes).\n5. Rate: Tax rate.\n6. Amount: Tax amount.\n7. Total: Cumulative total to this point.\n8. Enter Row: If based on \"Previous Row Total\" you can select the row number which will be taken as a base for this calculation (default is the previous row).\n9. Is this Tax included in Basic Rate?: If you check this, it means that this tax will not be shown below the item table, but will be included in the Basic Rate in your main item table. This is useful where you want give a flat price (inclusive of all taxes) price to customers.",
+ "doctype": "DocType",
+ "document_type": "Setup",
+ "engine": "InnoDB",
+ "field_order": [
+ "title",
+ "is_default",
+ "disabled",
+ "column_break_3",
+ "company",
+ "tax_category",
+ "section_break_5",
+ "taxes"
+ ],
"fields": [
{
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "title",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 1,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Title",
- "length": 0,
- "no_copy": 1,
- "oldfieldname": "title",
- "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": "title",
+ "fieldtype": "Data",
+ "label": "Title",
+ "no_copy": 1,
+ "oldfieldname": "title",
+ "oldfieldtype": "Data",
+ "reqd": 1
+ },
{
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "is_default",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Default",
- "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
- },
+ "default": "0",
+ "fieldname": "is_default",
+ "fieldtype": "Check",
+ "in_list_view": 1,
+ "label": "Default"
+ },
{
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "disabled",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Disabled",
- "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
- },
+ "default": "0",
+ "fieldname": "disabled",
+ "fieldtype": "Check",
+ "label": "Disabled"
+ },
{
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_3",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_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,
- "unique": 0
- },
+ "fieldname": "column_break_3",
+ "fieldtype": "Column Break"
+ },
{
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "company",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 1,
- "in_list_view": 1,
- "in_standard_filter": 1,
- "label": "Company",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "company",
- "oldfieldtype": "Link",
- "options": "Company",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 1,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "in_standard_filter": 1,
+ "label": "Company",
+ "oldfieldname": "company",
+ "oldfieldtype": "Link",
+ "options": "Company",
+ "remember_last_selected_value": 1,
+ "reqd": 1
+ },
{
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "section_break_5",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 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,
- "unique": 0
- },
+ "fieldname": "section_break_5",
+ "fieldtype": "Section Break"
+ },
{
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "* Will be calculated in the transaction.",
- "fieldname": "taxes",
- "fieldtype": "Table",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Sales Taxes and Charges",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "other_charges",
- "oldfieldtype": "Table",
- "options": "Sales Taxes and Charges",
- "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
+ "description": "* Will be calculated in the transaction.",
+ "fieldname": "taxes",
+ "fieldtype": "Table",
+ "label": "Sales Taxes and Charges",
+ "oldfieldname": "other_charges",
+ "oldfieldtype": "Table",
+ "options": "Sales Taxes and Charges"
+ },
+ {
+ "fieldname": "tax_category",
+ "fieldtype": "Link",
+ "label": "Tax Category",
+ "options": "Tax Category"
}
- ],
- "hide_heading": 0,
- "hide_toolbar": 0,
- "icon": "fa fa-money",
- "idx": 1,
- "image_view": 0,
- "in_create": 0,
-
- "is_submittable": 0,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2016-11-07 05:18:41.743257",
- "modified_by": "Administrator",
- "module": "Accounts",
- "name": "Sales Taxes and Charges Template",
- "owner": "Administrator",
+ ],
+ "icon": "fa fa-money",
+ "idx": 1,
+ "modified": "2019-11-25 13:06:03.279099",
+ "modified_by": "Administrator",
+ "module": "Accounts",
+ "name": "Sales Taxes and Charges Template",
+ "owner": "Administrator",
"permissions": [
{
- "amend": 0,
- "apply_user_permissions": 1,
- "cancel": 0,
- "create": 0,
- "delete": 0,
- "email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "is_custom": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Sales User",
- "set_user_permissions": 0,
- "share": 0,
- "submit": 0,
- "write": 0
- },
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Sales User"
+ },
{
- "amend": 0,
- "apply_user_permissions": 0,
- "cancel": 0,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "is_custom": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Accounts Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
+ "create": 1,
+ "delete": 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": 1,
- "delete": 1,
- "email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "is_custom": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Sales Master Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Sales Master Manager",
+ "share": 1,
"write": 1
}
- ],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "sort_order": "ASC",
- "track_seen": 0
+ ],
+ "sort_field": "modified",
+ "sort_order": "ASC",
+ "track_changes": 1
}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/share_transfer/share_transfer.js b/erpnext/accounts/doctype/share_transfer/share_transfer.js
index 364ca6f..1cad4df 100644
--- a/erpnext/accounts/doctype/share_transfer/share_transfer.js
+++ b/erpnext/accounts/doctype/share_transfer/share_transfer.js
@@ -21,6 +21,8 @@
erpnext.share_transfer.make_jv(frm);
});
}
+
+ frm.toggle_reqd("asset_account", frm.doc.transfer_type != "Transfer");
},
no_of_shares: (frm) => {
if (frm.doc.rate != undefined || frm.doc.rate != null){
@@ -56,6 +58,10 @@
};
});
}
+ },
+
+ transfer_type: function(frm) {
+ frm.toggle_reqd("asset_account", frm.doc.transfer_type != "Transfer");
}
});
diff --git a/erpnext/accounts/doctype/share_transfer/share_transfer.json b/erpnext/accounts/doctype/share_transfer/share_transfer.json
index 24c4569..59a3053 100644
--- a/erpnext/accounts/doctype/share_transfer/share_transfer.json
+++ b/erpnext/accounts/doctype/share_transfer/share_transfer.json
@@ -1,881 +1,242 @@
{
- "allow_copy": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "autoname": "ACC-SHT-.YYYY.-.#####",
- "beta": 0,
- "creation": "2017-12-25 17:18:03.143726",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "",
- "editable_grid": 1,
- "engine": "InnoDB",
+ "autoname": "ACC-SHT-.YYYY.-.#####",
+ "creation": "2017-12-25 17:18:03.143726",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "transfer_type",
+ "column_break_1",
+ "date",
+ "section_break_1",
+ "from_shareholder",
+ "from_folio_no",
+ "column_break_3",
+ "to_shareholder",
+ "to_folio_no",
+ "section_break_10",
+ "equity_or_liability_account",
+ "column_break_12",
+ "asset_account",
+ "section_break_4",
+ "share_type",
+ "from_no",
+ "rate",
+ "column_break_8",
+ "no_of_shares",
+ "to_no",
+ "amount",
+ "section_break_11",
+ "company",
+ "section_break_6",
+ "remarks",
+ "amended_from"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "transfer_type",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Transfer Type",
- "length": 0,
- "no_copy": 0,
- "options": "\nIssue\nPurchase\nTransfer",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "transfer_type",
+ "fieldtype": "Select",
+ "in_list_view": 1,
+ "label": "Transfer Type",
+ "options": "\nIssue\nPurchase\nTransfer",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_1",
- "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
- },
+ "fieldname": "column_break_1",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "date",
- "fieldtype": "Date",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Date",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "date",
+ "fieldtype": "Date",
+ "label": "Date",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "section_break_1",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "section_break_1",
+ "fieldtype": "Section Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:doc.transfer_type != 'Issue'",
- "fieldname": "from_shareholder",
- "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 Shareholder",
- "length": 0,
- "no_copy": 0,
- "options": "Shareholder",
- "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
- },
+ "depends_on": "eval:doc.transfer_type != 'Issue'",
+ "fieldname": "from_shareholder",
+ "fieldtype": "Link",
+ "label": "From Shareholder",
+ "options": "Shareholder"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:doc.transfer_type != 'Issue'",
- "fetch_from": "from_shareholder.folio_no",
- "fieldname": "from_folio_no",
- "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": "From Folio No",
- "length": 0,
- "no_copy": 0,
- "options": "",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "depends_on": "eval:doc.transfer_type != 'Issue'",
+ "fetch_from": "from_shareholder.folio_no",
+ "fieldname": "from_folio_no",
+ "fieldtype": "Data",
+ "label": "From Folio No"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:doc.company",
- "fieldname": "equity_or_liability_account",
- "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": "Equity/Liability Account",
- "length": 0,
- "no_copy": 0,
- "options": "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,
- "translatable": 0,
- "unique": 0
- },
+ "depends_on": "eval:doc.company",
+ "fieldname": "equity_or_liability_account",
+ "fieldtype": "Link",
+ "label": "Equity/Liability Account",
+ "options": "Account",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:(doc.transfer_type != 'Transfer') && (doc.company)",
- "fieldname": "asset_account",
- "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": "Asset Account",
- "length": 0,
- "no_copy": 0,
- "options": "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,
- "translatable": 0,
- "unique": 0
- },
+ "depends_on": "eval:(doc.transfer_type != 'Transfer') && (doc.company)",
+ "fieldname": "asset_account",
+ "fieldtype": "Link",
+ "label": "Asset Account",
+ "options": "Account"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_3",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "column_break_3",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:doc.transfer_type != 'Purchase'",
- "fieldname": "to_shareholder",
- "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 Shareholder",
- "length": 0,
- "no_copy": 0,
- "options": "Shareholder",
- "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
- },
+ "depends_on": "eval:doc.transfer_type != 'Purchase'",
+ "fieldname": "to_shareholder",
+ "fieldtype": "Link",
+ "label": "To Shareholder",
+ "options": "Shareholder"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:doc.transfer_type != 'Purchase'",
- "fetch_from": "to_shareholder.folio_no",
- "fieldname": "to_folio_no",
- "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": "To Folio No",
- "length": 0,
- "no_copy": 0,
- "options": "",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "depends_on": "eval:doc.transfer_type != 'Purchase'",
+ "fetch_from": "to_shareholder.folio_no",
+ "fieldname": "to_folio_no",
+ "fieldtype": "Data",
+ "label": "To Folio No"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "section_break_4",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "section_break_4",
+ "fieldtype": "Section Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "share_type",
- "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": "Share Type",
- "length": 0,
- "no_copy": 0,
- "options": "Share Type",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "share_type",
+ "fieldtype": "Link",
+ "label": "Share Type",
+ "options": "Share Type",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "(including)",
- "fieldname": "from_no",
- "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": "From No",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "description": "(including)",
+ "fieldname": "from_no",
+ "fieldtype": "Int",
+ "label": "From No",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "rate",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Rate",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "rate",
+ "fieldtype": "Currency",
+ "label": "Rate",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_8",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "column_break_8",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "no_of_shares",
- "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": "No of Shares",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "no_of_shares",
+ "fieldtype": "Int",
+ "label": "No of Shares",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "(including)",
- "fieldname": "to_no",
- "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": "To No",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "description": "(including)",
+ "fieldname": "to_no",
+ "fieldtype": "Int",
+ "label": "To No",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "amount",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Amount",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "amount",
+ "fieldtype": "Currency",
+ "label": "Amount",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "section_break_11",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "section_break_11",
+ "fieldtype": "Section Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "company",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Company",
- "length": 0,
- "no_copy": 0,
- "options": "Company",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "label": "Company",
+ "options": "Company",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "section_break_6",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "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
- },
+ "fieldname": "section_break_6",
+ "fieldtype": "Section Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "remarks",
- "fieldtype": "Long 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": "Remarks",
- "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
- },
+ "fieldname": "remarks",
+ "fieldtype": "Long Text",
+ "label": "Remarks"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "amended_from",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Amended From",
- "length": 0,
- "no_copy": 1,
- "options": "Share Transfer",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "fieldname": "amended_from",
+ "fieldtype": "Link",
+ "label": "Amended From",
+ "no_copy": 1,
+ "options": "Share Transfer",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "fieldname": "section_break_10",
+ "fieldtype": "Section Break"
+ },
+ {
+ "fieldname": "column_break_12",
+ "fieldtype": "Column Break"
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 1,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2018-09-18 14:14:46.233568",
- "modified_by": "Administrator",
- "module": "Accounts",
- "name": "Share Transfer",
- "name_case": "",
- "owner": "Administrator",
+ ],
+ "is_submittable": 1,
+ "modified": "2019-12-20 14:48:01.990600",
+ "modified_by": "Administrator",
+ "module": "Accounts",
+ "name": "Share Transfer",
+ "owner": "Administrator",
"permissions": [
{
- "amend": 1,
- "cancel": 0,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "System Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 1,
+ "amend": 1,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "System Manager",
+ "share": 1,
+ "submit": 1,
"write": 1
- },
+ },
{
- "amend": 0,
- "cancel": 0,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Accounts User",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Accounts User",
+ "share": 1,
"write": 1
- },
+ },
{
- "amend": 0,
- "cancel": 0,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Accounts Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Accounts Manager",
+ "share": 1,
+ "submit": 1,
"write": 1
}
- ],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1,
- "track_seen": 0,
- "track_views": 0
+ ],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/share_transfer/share_transfer.py b/erpnext/accounts/doctype/share_transfer/share_transfer.py
index e95c694..65f248e 100644
--- a/erpnext/accounts/doctype/share_transfer/share_transfer.py
+++ b/erpnext/accounts/doctype/share_transfer/share_transfer.py
@@ -13,9 +13,9 @@
class ShareDontExists(ValidationError): pass
class ShareTransfer(Document):
- def before_submit(self):
+ def on_submit(self):
if self.transfer_type == 'Issue':
- shareholder = self.get_shareholder_doc(self.company)
+ shareholder = self.get_company_shareholder()
shareholder.append('share_balance', {
'share_type': self.share_type,
'from_no': self.from_no,
@@ -28,7 +28,7 @@
})
shareholder.save()
- doc = frappe.get_doc('Shareholder', self.to_shareholder)
+ doc = self.get_shareholder_doc(self.to_shareholder)
doc.append('share_balance', {
'share_type': self.share_type,
'from_no': self.from_no,
@@ -41,11 +41,11 @@
elif self.transfer_type == 'Purchase':
self.remove_shares(self.from_shareholder)
- self.remove_shares(self.get_shareholder_doc(self.company).name)
+ self.remove_shares(self.get_company_shareholder().name)
elif self.transfer_type == 'Transfer':
self.remove_shares(self.from_shareholder)
- doc = frappe.get_doc('Shareholder', self.to_shareholder)
+ doc = self.get_shareholder_doc(self.to_shareholder)
doc.append('share_balance', {
'share_type': self.share_type,
'from_no': self.from_no,
@@ -56,143 +56,127 @@
})
doc.save()
+ def on_cancel(self):
+ if self.transfer_type == 'Issue':
+ compnay_shareholder = self.get_company_shareholder()
+ self.remove_shares(compnay_shareholder.name)
+ self.remove_shares(self.to_shareholder)
+
+ elif self.transfer_type == 'Purchase':
+ compnay_shareholder = self.get_company_shareholder()
+ from_shareholder = self.get_shareholder_doc(self.from_shareholder)
+
+ from_shareholder.append('share_balance', {
+ 'share_type': self.share_type,
+ 'from_no': self.from_no,
+ 'to_no': self.to_no,
+ 'rate': self.rate,
+ 'amount': self.amount,
+ 'no_of_shares': self.no_of_shares
+ })
+
+ from_shareholder.save()
+
+ compnay_shareholder.append('share_balance', {
+ 'share_type': self.share_type,
+ 'from_no': self.from_no,
+ 'to_no': self.to_no,
+ 'rate': self.rate,
+ 'amount': self.amount,
+ 'no_of_shares': self.no_of_shares
+ })
+
+ compnay_shareholder.save()
+
+ elif self.transfer_type == 'Transfer':
+ self.remove_shares(self.to_shareholder)
+ from_shareholder = self.get_shareholder_doc(self.from_shareholder)
+ from_shareholder.append('share_balance', {
+ 'share_type': self.share_type,
+ 'from_no': self.from_no,
+ 'to_no': self.to_no,
+ 'rate': self.rate,
+ 'amount': self.amount,
+ 'no_of_shares': self.no_of_shares
+ })
+ from_shareholder.save()
+
def validate(self):
+ self.get_company_shareholder()
self.basic_validations()
self.folio_no_validation()
+
if self.transfer_type == 'Issue':
- if not self.get_shareholder_doc(self.company):
- shareholder = frappe.get_doc({
- 'doctype': 'Shareholder',
- 'title': self.company,
- 'company': self.company,
- 'is_company': 1
- })
- shareholder.insert()
- # validate share doesnt exist in company
- ret_val = self.share_exists(self.get_shareholder_doc(self.company).name)
- if ret_val != False:
+ # validate share doesn't exist in company
+ ret_val = self.share_exists(self.get_company_shareholder().name)
+ if ret_val in ('Complete', 'Partial'):
frappe.throw(_('The shares already exist'), frappe.DuplicateEntryError)
else:
# validate share exists with from_shareholder
ret_val = self.share_exists(self.from_shareholder)
- if ret_val != True:
+ if ret_val in ('Outside', 'Partial'):
frappe.throw(_("The shares don't exist with the {0}")
.format(self.from_shareholder), ShareDontExists)
def basic_validations(self):
if self.transfer_type == 'Purchase':
self.to_shareholder = ''
- if self.from_shareholder is None or self.from_shareholder is '':
+ if not self.from_shareholder:
frappe.throw(_('The field From Shareholder cannot be blank'))
- if self.from_folio_no is None or self.from_folio_no is '':
+ if not self.from_folio_no:
self.to_folio_no = self.autoname_folio(self.to_shareholder)
- if self.asset_account is None:
+ if not self.asset_account:
frappe.throw(_('The field Asset Account cannot be blank'))
elif (self.transfer_type == 'Issue'):
self.from_shareholder = ''
- if self.to_shareholder is None or self.to_shareholder == '':
+ if not self.to_shareholder:
frappe.throw(_('The field To Shareholder cannot be blank'))
- if self.to_folio_no is None or self.to_folio_no is '':
+ if not self.to_folio_no:
self.to_folio_no = self.autoname_folio(self.to_shareholder)
- if self.asset_account is None:
+ if not self.asset_account:
frappe.throw(_('The field Asset Account cannot be blank'))
else:
- if self.from_shareholder is None or self.to_shareholder is None:
+ if not self.from_shareholder or not self.to_shareholder:
frappe.throw(_('The fields From Shareholder and To Shareholder cannot be blank'))
- if self.to_folio_no is None or self.to_folio_no is '':
+ if not self.to_folio_no:
self.to_folio_no = self.autoname_folio(self.to_shareholder)
- if self.equity_or_liability_account is None:
+ if not self.equity_or_liability_account:
frappe.throw(_('The field Equity/Liability Account cannot be blank'))
if self.from_shareholder == self.to_shareholder:
frappe.throw(_('The seller and the buyer cannot be the same'))
if self.no_of_shares != self.to_no - self.from_no + 1:
frappe.throw(_('The number of shares and the share numbers are inconsistent'))
- if self.amount is None:
+ if not self.amount:
self.amount = self.rate * self.no_of_shares
if self.amount != self.rate * self.no_of_shares:
frappe.throw(_('There are inconsistencies between the rate, no of shares and the amount calculated'))
def share_exists(self, shareholder):
- # return True if exits,
- # False if completely doesn't exist,
- # 'partially exists' if partailly doesn't exist
- ret_val = self.recursive_share_check(shareholder, self.share_type,
- query = {
- 'from_no': self.from_no,
- 'to_no': self.to_no
- }
- )
- if all(boolean == True for boolean in ret_val):
- return True
- elif True in ret_val:
- return 'partially exists'
- else:
- return False
-
- def recursive_share_check(self, shareholder, share_type, query):
- # query = {'from_no': share_starting_no, 'to_no': share_ending_no}
- # Recursive check if a given part of shares is held by the shareholder
- # return a list containing True and False
- # Eg. [True, False, True]
- # All True implies its completely inside
- # All False implies its completely outside
- # A mix implies its partially inside/outside
- does_share_exist = []
- doc = frappe.get_doc('Shareholder', shareholder)
+ doc = self.get_shareholder_doc(shareholder)
for entry in doc.share_balance:
- if entry.share_type != share_type or \
- entry.from_no > query['to_no'] or \
- entry.to_no < query['from_no']:
+ if entry.share_type != self.share_type or \
+ entry.from_no > self.to_no or \
+ entry.to_no < self.from_no:
continue # since query lies outside bounds
- elif entry.from_no <= query['from_no'] and entry.to_no >= query['to_no']:
- return [True] # absolute truth!
- elif entry.from_no >= query['from_no'] and entry.to_no <= query['to_no']:
- # split and check
- does_share_exist.extend(self.recursive_share_check(shareholder,
- share_type,
- {
- 'from_no': query['from_no'],
- 'to_no': entry.from_no - 1
- }
- ))
- does_share_exist.append(True)
- does_share_exist.extend(self.recursive_share_check(shareholder,
- share_type,
- {
- 'from_no': entry.to_no + 1,
- 'to_no': query['to_no']
- }
- ))
- elif query['from_no'] <= entry.from_no <= query['to_no'] and entry.to_no >= query['to_no']:
- does_share_exist.extend(self.recursive_share_check(shareholder,
- share_type,
- {
- 'from_no': query['from_no'],
- 'to_no': entry.from_no - 1
- }
- ))
- elif query['from_no'] <= entry.to_no <= query['to_no'] and entry.from_no <= query['from_no']:
- does_share_exist.extend(self.recursive_share_check(shareholder,
- share_type,
- {
- 'from_no': entry.to_no + 1,
- 'to_no': query['to_no']
- }
- ))
+ elif entry.from_no <= self.from_no and entry.to_no >= self.to_no: #both inside
+ return 'Complete' # absolute truth!
+ elif entry.from_no <= self.from_no <= self.to_no:
+ return 'Partial'
+ elif entry.from_no <= self.to_no <= entry.to_no:
+ return 'Partial'
- does_share_exist.append(False)
- return does_share_exist
+ return 'Outside'
def folio_no_validation(self):
shareholders = ['from_shareholder', 'to_shareholder']
shareholders = [shareholder for shareholder in shareholders if self.get(shareholder) is not '']
for shareholder in shareholders:
- doc = frappe.get_doc('Shareholder', self.get(shareholder))
+ doc = self.get_shareholder_doc(self.get(shareholder))
if doc.company != self.company:
frappe.throw(_('The shareholder does not belong to this company'))
- if doc.folio_no is '' or doc.folio_no is None:
+ if not doc.folio_no:
doc.folio_no = self.from_folio_no \
- if (shareholder == 'from_shareholder') else self.to_folio_no;
+ if (shareholder == 'from_shareholder') else self.to_folio_no
doc.save()
else:
if doc.folio_no and doc.folio_no != (self.from_folio_no if (shareholder == 'from_shareholder') else self.to_folio_no):
@@ -200,24 +184,14 @@
def autoname_folio(self, shareholder, is_company=False):
if is_company:
- doc = self.get_shareholder_doc(shareholder)
+ doc = self.get_company_shareholder()
else:
- doc = frappe.get_doc('Shareholder' , shareholder)
+ doc = self.get_shareholder_doc(shareholder)
doc.folio_no = make_autoname('FN.#####')
doc.save()
return doc.folio_no
def remove_shares(self, shareholder):
- self.iterative_share_removal(shareholder, self.share_type,
- {
- 'from_no': self.from_no,
- 'to_no' : self.to_no
- },
- rate = self.rate,
- amount = self.amount
- )
-
- def iterative_share_removal(self, shareholder, share_type, query, rate, amount):
# query = {'from_no': share_starting_no, 'to_no': share_ending_no}
# Shares exist for sure
# Iterate over all entries and modify entry if in entry
@@ -227,31 +201,31 @@
for entry in current_entries:
# use spaceage logic here
- if entry.share_type != share_type or \
- entry.from_no > query['to_no'] or \
- entry.to_no < query['from_no']:
+ if entry.share_type != self.share_type or \
+ entry.from_no > self.to_no or \
+ entry.to_no < self.from_no:
new_entries.append(entry)
continue # since query lies outside bounds
- elif entry.from_no <= query['from_no'] and entry.to_no >= query['to_no']:
+ elif entry.from_no <= self.from_no and entry.to_no >= self.to_no:
#split
- if entry.from_no == query['from_no']:
- if entry.to_no == query['to_no']:
+ if entry.from_no == self.from_no:
+ if entry.to_no == self.to_no:
pass #nothing to append
else:
- new_entries.append(self.return_share_balance_entry(query['to_no']+1, entry.to_no, entry.rate))
+ new_entries.append(self.return_share_balance_entry(self.to_no+1, entry.to_no, entry.rate))
else:
- if entry.to_no == query['to_no']:
- new_entries.append(self.return_share_balance_entry(entry.from_no, query['from_no']-1, entry.rate))
+ if entry.to_no == self.to_no:
+ new_entries.append(self.return_share_balance_entry(entry.from_no, self.from_no-1, entry.rate))
else:
- new_entries.append(self.return_share_balance_entry(entry.from_no, query['from_no']-1, entry.rate))
- new_entries.append(self.return_share_balance_entry(query['to_no']+1, entry.to_no, entry.rate))
- elif entry.from_no >= query['from_no'] and entry.to_no <= query['to_no']:
+ new_entries.append(self.return_share_balance_entry(entry.from_no, self.from_no-1, entry.rate))
+ new_entries.append(self.return_share_balance_entry(self.to_no+1, entry.to_no, entry.rate))
+ elif entry.from_no >= self.from_no and entry.to_no <= self.to_no:
# split and check
pass #nothing to append
- elif query['from_no'] <= entry.from_no <= query['to_no'] and entry.to_no >= query['to_no']:
- new_entries.append(self.return_share_balance_entry(query['to_no']+1, entry.to_no, entry.rate))
- elif query['from_no'] <= entry.to_no <= query['to_no'] and entry.from_no <= query['from_no']:
- new_entries.append(self.return_share_balance_entry(entry.from_no, query['from_no']-1, entry.rate))
+ elif self.from_no <= entry.from_no <= self.to_no and entry.to_no >= self.to_no:
+ new_entries.append(self.return_share_balance_entry(self.to_no+1, entry.to_no, entry.rate))
+ elif self.from_no <= entry.to_no <= self.to_no and entry.from_no <= self.from_no:
+ new_entries.append(self.return_share_balance_entry(entry.from_no, self.from_no-1, entry.rate))
else:
new_entries.append(entry)
@@ -272,16 +246,34 @@
}
def get_shareholder_doc(self, shareholder):
- # Get Shareholder doc based on the Shareholder title
- doc = frappe.get_list('Shareholder',
- filters = [
- ('Shareholder', 'title', '=', shareholder)
- ]
- )
- if len(doc) == 1:
- return frappe.get_doc('Shareholder', doc[0]['name'])
- else: #It will necessarily by 0 indicating it doesn't exist
- return False
+ # Get Shareholder doc based on the Shareholder name
+ if shareholder:
+ query_filters = {'name': shareholder}
+
+ name = frappe.db.get_value('Shareholder', {'name': shareholder}, 'name')
+
+ return frappe.get_doc('Shareholder', name)
+
+ def get_company_shareholder(self):
+ # Get company doc or create one if not present
+ company_shareholder = frappe.db.get_value('Shareholder',
+ {
+ 'company': self.company,
+ 'is_company': 1
+ }, 'name')
+
+ if company_shareholder:
+ return frappe.get_doc('Shareholder', company_shareholder)
+ else:
+ shareholder = frappe.get_doc({
+ 'doctype': 'Shareholder',
+ 'title': self.company,
+ 'company': self.company,
+ 'is_company': 1
+ })
+ shareholder.insert()
+
+ return shareholder
@frappe.whitelist()
def make_jv_entry( company, account, amount, payment_account,\
diff --git a/erpnext/accounts/doctype/share_transfer/test_share_transfer.py b/erpnext/accounts/doctype/share_transfer/test_share_transfer.py
index 910dfd0..2ff9b02 100644
--- a/erpnext/accounts/doctype/share_transfer/test_share_transfer.py
+++ b/erpnext/accounts/doctype/share_transfer/test_share_transfer.py
@@ -15,73 +15,73 @@
frappe.db.sql("delete from `tabShare Balance`")
share_transfers = [
{
- "doctype" : "Share Transfer",
- "transfer_type" : "Issue",
- "date" : "2018-01-01",
- "to_shareholder" : "SH-00001",
- "share_type" : "Equity",
- "from_no" : 1,
- "to_no" : 500,
- "no_of_shares" : 500,
- "rate" : 10,
- "company" : "_Test Company",
- "asset_account" : "Cash - _TC",
+ "doctype": "Share Transfer",
+ "transfer_type": "Issue",
+ "date": "2018-01-01",
+ "to_shareholder": "SH-00001",
+ "share_type": "Equity",
+ "from_no": 1,
+ "to_no": 500,
+ "no_of_shares": 500,
+ "rate": 10,
+ "company": "_Test Company",
+ "asset_account": "Cash - _TC",
"equity_or_liability_account": "Creditors - _TC"
},
{
- "doctype" : "Share Transfer",
- "transfer_type" : "Transfer",
- "date" : "2018-01-02",
- "from_shareholder" : "SH-00001",
- "to_shareholder" : "SH-00002",
- "share_type" : "Equity",
- "from_no" : 101,
- "to_no" : 200,
- "no_of_shares" : 100,
- "rate" : 15,
- "company" : "_Test Company",
+ "doctype": "Share Transfer",
+ "transfer_type": "Transfer",
+ "date": "2018-01-02",
+ "from_shareholder": "SH-00001",
+ "to_shareholder": "SH-00002",
+ "share_type": "Equity",
+ "from_no": 101,
+ "to_no": 200,
+ "no_of_shares": 100,
+ "rate": 15,
+ "company": "_Test Company",
"equity_or_liability_account": "Creditors - _TC"
},
{
- "doctype" : "Share Transfer",
- "transfer_type" : "Transfer",
- "date" : "2018-01-03",
- "from_shareholder" : "SH-00001",
- "to_shareholder" : "SH-00003",
- "share_type" : "Equity",
- "from_no" : 201,
- "to_no" : 500,
- "no_of_shares" : 300,
- "rate" : 20,
- "company" : "_Test Company",
+ "doctype": "Share Transfer",
+ "transfer_type": "Transfer",
+ "date": "2018-01-03",
+ "from_shareholder": "SH-00001",
+ "to_shareholder": "SH-00003",
+ "share_type": "Equity",
+ "from_no": 201,
+ "to_no": 500,
+ "no_of_shares": 300,
+ "rate": 20,
+ "company": "_Test Company",
"equity_or_liability_account": "Creditors - _TC"
},
{
- "doctype" : "Share Transfer",
- "transfer_type" : "Transfer",
- "date" : "2018-01-04",
- "from_shareholder" : "SH-00003",
- "to_shareholder" : "SH-00002",
- "share_type" : "Equity",
- "from_no" : 201,
- "to_no" : 400,
- "no_of_shares" : 200,
- "rate" : 15,
- "company" : "_Test Company",
+ "doctype": "Share Transfer",
+ "transfer_type": "Transfer",
+ "date": "2018-01-04",
+ "from_shareholder": "SH-00003",
+ "to_shareholder": "SH-00002",
+ "share_type": "Equity",
+ "from_no": 201,
+ "to_no": 400,
+ "no_of_shares": 200,
+ "rate": 15,
+ "company": "_Test Company",
"equity_or_liability_account": "Creditors - _TC"
},
{
- "doctype" : "Share Transfer",
- "transfer_type" : "Purchase",
- "date" : "2018-01-05",
- "from_shareholder" : "SH-00003",
- "share_type" : "Equity",
- "from_no" : 401,
- "to_no" : 500,
- "no_of_shares" : 100,
- "rate" : 25,
- "company" : "_Test Company",
- "asset_account" : "Cash - _TC",
+ "doctype": "Share Transfer",
+ "transfer_type": "Purchase",
+ "date": "2018-01-05",
+ "from_shareholder": "SH-00003",
+ "share_type": "Equity",
+ "from_no": 401,
+ "to_no": 500,
+ "no_of_shares": 100,
+ "rate": 25,
+ "company": "_Test Company",
+ "asset_account": "Cash - _TC",
"equity_or_liability_account": "Creditors - _TC"
}
]
@@ -91,33 +91,33 @@
def test_invalid_share_transfer(self):
doc = frappe.get_doc({
- "doctype" : "Share Transfer",
- "transfer_type" : "Transfer",
- "date" : "2018-01-05",
- "from_shareholder" : "SH-00003",
- "to_shareholder" : "SH-00002",
- "share_type" : "Equity",
- "from_no" : 1,
- "to_no" : 100,
- "no_of_shares" : 100,
- "rate" : 15,
- "company" : "_Test Company",
+ "doctype": "Share Transfer",
+ "transfer_type": "Transfer",
+ "date": "2018-01-05",
+ "from_shareholder": "SH-00003",
+ "to_shareholder": "SH-00002",
+ "share_type": "Equity",
+ "from_no": 1,
+ "to_no": 100,
+ "no_of_shares": 100,
+ "rate": 15,
+ "company": "_Test Company",
"equity_or_liability_account": "Creditors - _TC"
})
self.assertRaises(ShareDontExists, doc.insert)
doc = frappe.get_doc({
- "doctype" : "Share Transfer",
- "transfer_type" : "Purchase",
- "date" : "2018-01-02",
- "from_shareholder" : "SH-00001",
- "share_type" : "Equity",
- "from_no" : 1,
- "to_no" : 200,
- "no_of_shares" : 200,
- "rate" : 15,
- "company" : "_Test Company",
- "asset_account" : "Cash - _TC",
+ "doctype": "Share Transfer",
+ "transfer_type": "Purchase",
+ "date": "2018-01-02",
+ "from_shareholder": "SH-00001",
+ "share_type": "Equity",
+ "from_no": 1,
+ "to_no": 200,
+ "no_of_shares": 200,
+ "rate": 15,
+ "company": "_Test Company",
+ "asset_account": "Cash - _TC",
"equity_or_liability_account": "Creditors - _TC"
})
self.assertRaises(ShareDontExists, doc.insert)
diff --git a/erpnext/accounts/doctype/shareholder/shareholder.json b/erpnext/accounts/doctype/shareholder/shareholder.json
index 873a3e7..e94aea9 100644
--- a/erpnext/accounts/doctype/shareholder/shareholder.json
+++ b/erpnext/accounts/doctype/shareholder/shareholder.json
@@ -1,587 +1,163 @@
{
- "allow_copy": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "autoname": "naming_series:",
- "beta": 0,
- "creation": "2017-12-25 16:50:53.878430",
- "custom": 0,
- "description": "",
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "",
- "editable_grid": 1,
- "engine": "InnoDB",
+ "autoname": "naming_series:",
+ "creation": "2017-12-25 16:50:53.878430",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "title",
+ "column_break_2",
+ "naming_series",
+ "section_break_2",
+ "folio_no",
+ "column_break_4",
+ "company",
+ "is_company",
+ "address_contacts",
+ "address_html",
+ "column_break_9",
+ "contact_html",
+ "section_break_3",
+ "share_balance",
+ "contact_list"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "title",
- "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": "Title",
- "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
- },
+ "fieldname": "title",
+ "fieldtype": "Data",
+ "label": "Title",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_2",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "column_break_2",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "",
- "fieldname": "naming_series",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "",
- "length": 0,
- "no_copy": 0,
- "options": "ACC-SH-.YYYY.-",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "naming_series",
+ "fieldtype": "Select",
+ "options": "ACC-SH-.YYYY.-"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "section_break_2",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "section_break_2",
+ "fieldtype": "Section Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "folio_no",
- "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": "Folio no.",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
+ "fieldname": "folio_no",
+ "fieldtype": "Data",
+ "label": "Folio no.",
+ "read_only": 1,
"unique": 1
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_4",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "column_break_4",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "company",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Company",
- "length": 0,
- "no_copy": 0,
- "options": "Company",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Company",
+ "options": "Company",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "is_company",
- "fieldtype": "Check",
- "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": "Is Company",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "default": "0",
+ "fieldname": "is_company",
+ "fieldtype": "Check",
+ "hidden": 1,
+ "label": "Is Company",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "address_contacts",
- "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": "Address and Contacts",
- "length": 0,
- "no_copy": 0,
- "options": "fa fa-map-marker",
- "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
- },
+ "fieldname": "address_contacts",
+ "fieldtype": "Section Break",
+ "label": "Address and Contacts",
+ "options": "fa fa-map-marker"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "address_html",
- "fieldtype": "HTML",
- "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": "Address HTML",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "address_html",
+ "fieldtype": "HTML",
+ "label": "Address HTML",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_9",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "column_break_9",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "contact_html",
- "fieldtype": "HTML",
- "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": "Contact HTML",
- "length": 0,
- "no_copy": 0,
- "options": "",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "contact_html",
+ "fieldtype": "HTML",
+ "label": "Contact HTML",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "section_break_3",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Share Balance",
- "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
- },
+ "fieldname": "section_break_3",
+ "fieldtype": "Section Break",
+ "label": "Share Balance"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "share_balance",
- "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": "Share Balance",
- "length": 0,
- "no_copy": 0,
- "options": "Share Balance",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "share_balance",
+ "fieldtype": "Table",
+ "label": "Share Balance",
+ "options": "Share Balance",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "Hidden list maintaining the list of contacts linked to Shareholder",
- "fieldname": "contact_list",
- "fieldtype": "Code",
- "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": "Contact List",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "description": "Hidden list maintaining the list of contacts linked to Shareholder",
+ "fieldname": "contact_list",
+ "fieldtype": "Code",
+ "hidden": 1,
+ "label": "Contact List",
+ "read_only": 1
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2018-09-18 14:14:24.953014",
- "modified_by": "Administrator",
- "module": "Accounts",
- "name": "Shareholder",
- "name_case": "Title Case",
- "owner": "Administrator",
+ ],
+ "modified": "2019-11-17 23:24:11.395882",
+ "modified_by": "Administrator",
+ "module": "Accounts",
+ "name": "Shareholder",
+ "name_case": "Title Case",
+ "owner": "Administrator",
"permissions": [
{
- "amend": 0,
- "cancel": 0,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "System Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "System Manager",
+ "share": 1,
"write": 1
- },
+ },
{
- "amend": 0,
- "cancel": 0,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Accounts Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Accounts Manager",
+ "share": 1,
"write": 1
- },
+ },
{
- "amend": 0,
- "cancel": 0,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Accounts User",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Accounts User",
+ "share": 1,
"write": 1
}
- ],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "search_fields": "folio_no",
- "show_name_in_global_search": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "title_field": "title",
- "track_changes": 1,
- "track_seen": 0,
- "track_views": 0
+ ],
+ "search_fields": "folio_no",
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "title_field": "title",
+ "track_changes": 1
}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/shipping_rule/shipping_rule.py b/erpnext/accounts/doctype/shipping_rule/shipping_rule.py
index a20f5c0..8c4efbe 100644
--- a/erpnext/accounts/doctype/shipping_rule/shipping_rule.py
+++ b/erpnext/accounts/doctype/shipping_rule/shipping_rule.py
@@ -70,7 +70,7 @@
def get_shipping_amount_from_rules(self, value):
for condition in self.get("conditions"):
- if not condition.to_value or (flt(condition.from_value) <= value <= flt(condition.to_value)):
+ if not condition.to_value or (flt(condition.from_value) <= flt(value) <= flt(condition.to_value)):
return condition.shipping_amount
return 0.0
diff --git a/erpnext/accounts/doctype/shipping_rule/test_shipping_rule.py b/erpnext/accounts/doctype/shipping_rule/test_shipping_rule.py
index 582ecb2..abc6ab8 100644
--- a/erpnext/accounts/doctype/shipping_rule/test_shipping_rule.py
+++ b/erpnext/accounts/doctype/shipping_rule/test_shipping_rule.py
@@ -14,13 +14,13 @@
shipping_rule.name = test_records[0].get('name')
shipping_rule.get("conditions")[0].from_value = 101
self.assertRaises(FromGreaterThanToError, shipping_rule.insert)
-
+
def test_many_zero_to_values(self):
shipping_rule = frappe.copy_doc(test_records[0])
shipping_rule.name = test_records[0].get('name')
shipping_rule.get("conditions")[0].to_value = 0
self.assertRaises(ManyBlankToValuesError, shipping_rule.insert)
-
+
def test_overlapping_conditions(self):
for range_a, range_b in [
((50, 150), (0, 100)),
@@ -38,6 +38,10 @@
self.assertRaises(OverlappingConditionError, shipping_rule.insert)
def create_shipping_rule(shipping_rule_type, shipping_rule_name):
+
+ if frappe.db.exists("Shipping Rule", shipping_rule_name):
+ return frappe.get_doc("Shipping Rule", shipping_rule_name)
+
sr = frappe.new_doc("Shipping Rule")
sr.account = "_Test Account Shipping Charges - _TC"
sr.calculate_based_on = "Net Total"
@@ -70,4 +74,4 @@
})
sr.insert(ignore_permissions=True)
sr.submit()
- return sr
+ return sr
diff --git a/erpnext/accounts/doctype/subscription/subscription.py b/erpnext/accounts/doctype/subscription/subscription.py
index f13ca4c..5482750 100644
--- a/erpnext/accounts/doctype/subscription/subscription.py
+++ b/erpnext/accounts/doctype/subscription/subscription.py
@@ -338,6 +338,16 @@
# Check invoice dates and make sure it doesn't have outstanding invoices
return getdate(nowdate()) >= getdate(self.current_invoice_start) and not self.has_outstanding_invoice()
+
+ def is_current_invoice_paid(self):
+ if self.is_new_subscription():
+ return False
+
+ last_invoice = frappe.get_doc('Sales Invoice', self.invoices[-1].invoice)
+ if getdate(last_invoice.posting_date) == getdate(self.current_invoice_start) and last_invoice.status == 'Paid':
+ return True
+
+ return False
def process_for_active(self):
"""
@@ -348,7 +358,7 @@
2. Change the `Subscription` status to 'Past Due Date'
3. Change the `Subscription` status to 'Cancelled'
"""
- if self.is_postpaid_to_invoice() or self.is_prepaid_to_invoice():
+ if not self.is_current_invoice_paid() and (self.is_postpaid_to_invoice() or self.is_prepaid_to_invoice()):
self.generate_invoice()
if self.current_invoice_is_past_due():
self.status = 'Past Due Date'
diff --git a/erpnext/accounts/general_ledger.py b/erpnext/accounts/general_ledger.py
index 5c9e93d..bb1b7e3 100644
--- a/erpnext/accounts/general_ledger.py
+++ b/erpnext/accounts/general_ledger.py
@@ -3,8 +3,9 @@
from __future__ import unicode_literals
import frappe, erpnext
-from frappe.utils import flt, cstr, cint
+from frappe.utils import flt, cstr, cint, comma_and
from frappe import _
+from erpnext.accounts.utils import get_stock_and_account_balance
from frappe.model.meta import get_field_precision
from erpnext.accounts.doctype.budget.budget import validate_expense_against_budget
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions
@@ -12,6 +13,7 @@
class ClosedAccountingPeriod(frappe.ValidationError): pass
class StockAccountInvalidTransaction(frappe.ValidationError): pass
+class StockValueAndAccountBalanceOutOfSync(frappe.ValidationError): pass
def make_gl_entries(gl_map, cancel=False, adv_adj=False, merge_entries=True, update_outstanding='Yes', from_repost=False):
if gl_map:
@@ -88,8 +90,12 @@
else:
merged_gl_map.append(entry)
+ company = gl_map[0].company if gl_map else erpnext.get_default_company()
+ company_currency = erpnext.get_company_currency(company)
+ precision = get_field_precision(frappe.get_meta("GL Entry").get_field("debit"), company_currency)
+
# filter zero debit and credit entries
- merged_gl_map = filter(lambda x: flt(x.debit, 9)!=0 or flt(x.credit, 9)!=0, merged_gl_map)
+ merged_gl_map = filter(lambda x: flt(x.debit, precision)!=0 or flt(x.credit, precision)!=0, merged_gl_map)
merged_gl_map = list(merged_gl_map)
return merged_gl_map
@@ -115,11 +121,9 @@
def save_entries(gl_map, adv_adj, update_outstanding, from_repost=False):
if not from_repost:
- validate_account_for_perpetual_inventory(gl_map)
validate_cwip_accounts(gl_map)
round_off_debit_credit(gl_map)
-
for entry in gl_map:
make_entry(entry, adv_adj, update_outstanding, from_repost)
@@ -127,6 +131,10 @@
if not from_repost:
validate_expense_against_budget(entry)
+ if not from_repost:
+ validate_account_for_perpetual_inventory(gl_map)
+
+
def make_entry(args, adv_adj, update_outstanding, from_repost=False):
args.update({"doctype": "GL Entry"})
gle = frappe.get_doc(args)
@@ -137,25 +145,67 @@
gle.submit()
def validate_account_for_perpetual_inventory(gl_map):
- if cint(erpnext.is_perpetual_inventory_enabled(gl_map[0].company)) \
- and gl_map[0].voucher_type=="Journal Entry":
- aii_accounts = [d[0] for d in frappe.db.sql("""select name from tabAccount
- where account_type = 'Stock' and is_group=0""")]
+ if cint(erpnext.is_perpetual_inventory_enabled(gl_map[0].company)):
+ account_list = [gl_entries.account for gl_entries in gl_map]
- for entry in gl_map:
- if entry.account in aii_accounts:
+ aii_accounts = [d.name for d in frappe.get_all("Account",
+ filters={'account_type': 'Stock', 'is_group': 0, 'company': gl_map[0].company})]
+
+ for account in account_list:
+ if account not in aii_accounts:
+ continue
+
+ account_bal, stock_bal, warehouse_list = get_stock_and_account_balance(account,
+ gl_map[0].posting_date, gl_map[0].company)
+
+ if gl_map[0].voucher_type=="Journal Entry":
+ # In case of Journal Entry, there are no corresponding SL entries,
+ # hence deducting currency amount
+ account_bal -= flt(gl_map[0].debit) - flt(gl_map[0].credit)
+ if account_bal == stock_bal:
frappe.throw(_("Account: {0} can only be updated via Stock Transactions")
- .format(entry.account), StockAccountInvalidTransaction)
+ .format(account), StockAccountInvalidTransaction)
+
+ # This has been comment for a temporary, will add this code again on release of immutable ledger
+ # elif account_bal != stock_bal:
+ # precision = get_field_precision(frappe.get_meta("GL Entry").get_field("debit"),
+ # currency=frappe.get_cached_value('Company', gl_map[0].company, "default_currency"))
+
+ # diff = flt(stock_bal - account_bal, precision)
+ # error_reason = _("Stock Value ({0}) and Account Balance ({1}) are out of sync for account {2} and it's linked warehouses.").format(
+ # stock_bal, account_bal, frappe.bold(account))
+ # error_resolution = _("Please create adjustment Journal Entry for amount {0} ").format(frappe.bold(diff))
+ # stock_adjustment_account = frappe.db.get_value("Company",gl_map[0].company,"stock_adjustment_account")
+
+ # db_or_cr_warehouse_account =('credit_in_account_currency' if diff < 0 else 'debit_in_account_currency')
+ # db_or_cr_stock_adjustment_account = ('debit_in_account_currency' if diff < 0 else 'credit_in_account_currency')
+
+ # journal_entry_args = {
+ # 'accounts':[
+ # {'account': account, db_or_cr_warehouse_account : abs(diff)},
+ # {'account': stock_adjustment_account, db_or_cr_stock_adjustment_account : abs(diff) }]
+ # }
+
+ # frappe.msgprint(msg="""{0}<br></br>{1}<br></br>""".format(error_reason, error_resolution),
+ # raise_exception=StockValueAndAccountBalanceOutOfSync,
+ # title=_('Values Out Of Sync'),
+ # primary_action={
+ # 'label': _('Make Journal Entry'),
+ # 'client_action': 'erpnext.route_to_adjustment_jv',
+ # 'args': journal_entry_args
+ # })
def validate_cwip_accounts(gl_map):
- if not cint(frappe.db.get_value("Asset Settings", None, "disable_cwip_accounting")) \
- and gl_map[0].voucher_type == "Journal Entry":
+ cwip_enabled = any([cint(ac.enable_cwip_accounting) for ac in frappe.db.get_all("Asset Category","enable_cwip_accounting")])
+
+ if cwip_enabled and gl_map[0].voucher_type == "Journal Entry":
cwip_accounts = [d[0] for d in frappe.db.sql("""select name from tabAccount
where account_type = 'Capital Work in Progress' and is_group=0""")]
for entry in gl_map:
if entry.account in cwip_accounts:
- frappe.throw(_("Account: <b>{0}</b> is capital Work in progress and can not be updated by Journal Entry").format(entry.account))
+ frappe.throw(
+ _("Account: <b>{0}</b> is capital Work in progress and can not be updated by Journal Entry").format(entry.account))
def round_off_debit_credit(gl_map):
precision = get_field_precision(frappe.get_meta("GL Entry").get_field("debit"),
diff --git a/erpnext/accounts/page/bank_reconciliation/bank_reconciliation.js b/erpnext/accounts/page/bank_reconciliation/bank_reconciliation.js
index 6eafa0d..efc76f9 100644
--- a/erpnext/accounts/page/bank_reconciliation/bank_reconciliation.js
+++ b/erpnext/accounts/page/bank_reconciliation/bank_reconciliation.js
@@ -139,15 +139,11 @@
}
make() {
- const me = this;
- frappe.upload.make({
- args: {
- method: 'erpnext.accounts.doctype.bank_transaction.bank_transaction_upload.upload_bank_statement',
- allow_multiple: 0
- },
- no_socketio: true,
- sample_url: "e.g. http://example.com/somefile.csv",
- callback: function(attachment, r) {
+ const me = this;
+ new frappe.ui.FileUploader({
+ method: 'erpnext.accounts.doctype.bank_transaction.bank_transaction_upload.upload_bank_statement',
+ allow_multiple: 0,
+ on_success: function(attachment, r) {
if (!r.exc && r.message) {
me.data = r.message;
me.setup_transactions_dom();
@@ -533,9 +529,16 @@
frappe.db.get_doc(dt, event.value)
.then(doc => {
let displayed_docs = []
+ let payment = []
if (dt === "Payment Entry") {
payment.currency = doc.payment_type == "Receive" ? doc.paid_to_account_currency : doc.paid_from_account_currency;
payment.doctype = dt
+ payment.posting_date = doc.posting_date;
+ payment.party = doc.party;
+ payment.reference_no = doc.reference_no;
+ payment.reference_date = doc.reference_date;
+ payment.paid_amount = doc.paid_amount;
+ payment.name = doc.name;
displayed_docs.push(payment);
} else if (dt === "Journal Entry") {
doc.accounts.forEach(payment => {
@@ -568,11 +571,11 @@
const details_wrapper = me.dialog.fields_dict.payment_details.$wrapper;
details_wrapper.append(frappe.render_template("linked_payment_header"));
- displayed_docs.forEach(values => {
- details_wrapper.append(frappe.render_template("linked_payment_row", values));
+ displayed_docs.forEach(payment => {
+ details_wrapper.append(frappe.render_template("linked_payment_row", payment));
})
})
}
}
-}
\ No newline at end of file
+}
diff --git a/erpnext/accounts/page/bank_reconciliation/bank_reconciliation.py b/erpnext/accounts/page/bank_reconciliation/bank_reconciliation.py
index bd4b4d7..69f9907 100644
--- a/erpnext/accounts/page/bank_reconciliation/bank_reconciliation.py
+++ b/erpnext/accounts/page/bank_reconciliation/bank_reconciliation.py
@@ -18,6 +18,10 @@
account = frappe.db.get_value("Bank Account", transaction.bank_account, "account")
gl_entry = frappe.get_doc("GL Entry", dict(account=account, voucher_type=payment_doctype, voucher_no=payment_name))
+ if payment_doctype == "Payment Entry" and payment_entry.unallocated_amount > transaction.unallocated_amount:
+ frappe.throw(_("The unallocated amount of Payment Entry {0} \
+ is greater than the Bank Transaction's unallocated amount").format(payment_name))
+
if transaction.unallocated_amount == 0:
frappe.throw(_("This bank transaction is already fully reconciled"))
@@ -373,4 +377,4 @@
'start': start,
'page_len': page_len
}
- )
\ No newline at end of file
+ )
diff --git a/erpnext/accounts/party.py b/erpnext/accounts/party.py
index 59936d5..156f218 100644
--- a/erpnext/accounts/party.py
+++ b/erpnext/accounts/party.py
@@ -23,7 +23,7 @@
@frappe.whitelist()
def get_party_details(party=None, account=None, party_type="Customer", company=None, posting_date=None,
bill_date=None, price_list=None, currency=None, doctype=None, ignore_permissions=False, fetch_payment_terms_template=True,
- party_address=None, shipping_address=None, pos_profile=None):
+ party_address=None, company_address=None, shipping_address=None, pos_profile=None):
if not party:
return {}
@@ -31,14 +31,14 @@
frappe.throw(_("{0}: {1} does not exists").format(party_type, party))
return _get_party_details(party, account, party_type,
company, posting_date, bill_date, price_list, currency, doctype, ignore_permissions,
- fetch_payment_terms_template, party_address, shipping_address, pos_profile)
+ fetch_payment_terms_template, party_address, company_address, shipping_address, pos_profile)
def _get_party_details(party=None, account=None, party_type="Customer", company=None, posting_date=None,
bill_date=None, price_list=None, currency=None, doctype=None, ignore_permissions=False,
- fetch_payment_terms_template=True, party_address=None, shipping_address=None, pos_profile=None):
+ fetch_payment_terms_template=True, party_address=None, company_address=None,shipping_address=None, pos_profile=None):
- out = frappe._dict(set_account_and_due_date(party, account, party_type, company, posting_date, bill_date, doctype))
- party = out[party_type.lower()]
+ party_details = frappe._dict(set_account_and_due_date(party, account, party_type, company, posting_date, bill_date, doctype))
+ party = party_details[party_type.lower()]
if not ignore_permissions and not frappe.has_permission(party_type, "read", party):
frappe.throw(_("Not permitted for {0}").format(party), frappe.PermissionError)
@@ -46,76 +46,81 @@
party = frappe.get_doc(party_type, party)
currency = party.default_currency if party.get("default_currency") else get_company_currency(company)
- party_address, shipping_address = set_address_details(out, party, party_type, doctype, company, party_address, shipping_address)
- set_contact_details(out, party, party_type)
- set_other_values(out, party, party_type)
- set_price_list(out, party, party_type, price_list, pos_profile)
+ party_address, shipping_address = set_address_details(party_details, party, party_type, doctype, company, party_address, company_address, shipping_address)
+ set_contact_details(party_details, party, party_type)
+ set_other_values(party_details, party, party_type)
+ set_price_list(party_details, party, party_type, price_list, pos_profile)
- out["tax_category"] = get_address_tax_category(party.get("tax_category"),
+ party_details["tax_category"] = get_address_tax_category(party.get("tax_category"),
party_address, shipping_address if party_type != "Supplier" else party_address)
- out["taxes_and_charges"] = set_taxes(party.name, party_type, posting_date, company,
- customer_group=out.customer_group, supplier_group=out.supplier_group, tax_category=out.tax_category,
- billing_address=party_address, shipping_address=shipping_address)
+
+ if not party_details.get("taxes_and_charges"):
+ party_details["taxes_and_charges"] = set_taxes(party.name, party_type, posting_date, company,
+ customer_group=party_details.customer_group, supplier_group=party_details.supplier_group, tax_category=party_details.tax_category,
+ billing_address=party_address, shipping_address=shipping_address)
if fetch_payment_terms_template:
- out["payment_terms_template"] = get_pyt_term_template(party.name, party_type, company)
+ party_details["payment_terms_template"] = get_pyt_term_template(party.name, party_type, company)
- if not out.get("currency"):
- out["currency"] = currency
+ if not party_details.get("currency"):
+ party_details["currency"] = currency
# sales team
if party_type=="Customer":
- out["sales_team"] = [{
+ party_details["sales_team"] = [{
"sales_person": d.sales_person,
"allocated_percentage": d.allocated_percentage or None
} for d in party.get("sales_team")]
# supplier tax withholding category
if party_type == "Supplier" and party:
- out["supplier_tds"] = frappe.get_value(party_type, party.name, "tax_withholding_category")
+ party_details["supplier_tds"] = frappe.get_value(party_type, party.name, "tax_withholding_category")
- return out
+ return party_details
-def set_address_details(out, party, party_type, doctype=None, company=None, party_address=None, shipping_address=None):
+def set_address_details(party_details, party, party_type, doctype=None, company=None, party_address=None, company_address=None, shipping_address=None):
billing_address_field = "customer_address" if party_type == "Lead" \
else party_type.lower() + "_address"
- out[billing_address_field] = party_address or get_default_address(party_type, party.name)
+ party_details[billing_address_field] = party_address or get_default_address(party_type, party.name)
if doctype:
- out.update(get_fetch_values(doctype, billing_address_field, out[billing_address_field]))
+ party_details.update(get_fetch_values(doctype, billing_address_field, party_details[billing_address_field]))
# address display
- out.address_display = get_address_display(out[billing_address_field])
+ party_details.address_display = get_address_display(party_details[billing_address_field])
# shipping address
if party_type in ["Customer", "Lead"]:
- out.shipping_address_name = shipping_address or get_party_shipping_address(party_type, party.name)
- out.shipping_address = get_address_display(out["shipping_address_name"])
+ party_details.shipping_address_name = shipping_address or get_party_shipping_address(party_type, party.name)
+ party_details.shipping_address = get_address_display(party_details["shipping_address_name"])
if doctype:
- out.update(get_fetch_values(doctype, 'shipping_address_name', out.shipping_address_name))
+ party_details.update(get_fetch_values(doctype, 'shipping_address_name', party_details.shipping_address_name))
- if doctype and doctype in ['Delivery Note', 'Sales Invoice']:
- out.update(get_company_address(company))
- if out.company_address:
- out.update(get_fetch_values(doctype, 'company_address', out.company_address))
- get_regional_address_details(out, doctype, company)
+ if company_address:
+ party_details.update({'company_address': company_address})
+ else:
+ party_details.update(get_company_address(company))
- elif doctype and doctype == "Purchase Invoice":
- out.update(get_company_address(company))
- if out.company_address:
- out["shipping_address"] = shipping_address or out["company_address"]
- out.shipping_address_display = get_address_display(out["shipping_address"])
- out.update(get_fetch_values(doctype, 'shipping_address', out.shipping_address))
- get_regional_address_details(out, doctype, company)
+ if doctype and doctype in ['Delivery Note', 'Sales Invoice', 'Sales Order']:
+ if party_details.company_address:
+ party_details.update(get_fetch_values(doctype, 'company_address', party_details.company_address))
+ get_regional_address_details(party_details, doctype, company)
- return out.get(billing_address_field), out.shipping_address_name
+ elif doctype and doctype in ["Purchase Invoice", "Purchase Order", "Purchase Receipt"]:
+ if party_details.company_address:
+ party_details["shipping_address"] = shipping_address or party_details["company_address"]
+ party_details.shipping_address_display = get_address_display(party_details["shipping_address"])
+ party_details.update(get_fetch_values(doctype, 'shipping_address', party_details.shipping_address))
+ get_regional_address_details(party_details, doctype, company)
+
+ return party_details.get(billing_address_field), party_details.shipping_address_name
@erpnext.allow_regional
-def get_regional_address_details(out, doctype, company):
+def get_regional_address_details(party_details, doctype, company):
pass
-def set_contact_details(out, party, party_type):
- out.contact_person = get_default_contact(party_type, party.name)
+def set_contact_details(party_details, party, party_type):
+ party_details.contact_person = get_default_contact(party_type, party.name)
- if not out.contact_person:
- out.update({
+ if not party_details.contact_person:
+ party_details.update({
"contact_person": None,
"contact_display": None,
"contact_email": None,
@@ -125,22 +130,22 @@
"contact_department": None
})
else:
- out.update(get_contact_details(out.contact_person))
+ party_details.update(get_contact_details(party_details.contact_person))
-def set_other_values(out, party, party_type):
+def set_other_values(party_details, party, party_type):
# copy
if party_type=="Customer":
to_copy = ["customer_name", "customer_group", "territory", "language"]
else:
to_copy = ["supplier_name", "supplier_group", "language"]
for f in to_copy:
- out[f] = party.get(f)
+ party_details[f] = party.get(f)
# fields prepended with default in Customer doctype
for f in ['currency'] \
+ (['sales_partner', 'commission_rate'] if party_type=="Customer" else []):
if party.get("default_" + f):
- out[f] = party.get("default_" + f)
+ party_details[f] = party.get("default_" + f)
def get_default_price_list(party):
"""Return default price list for party (Document object)"""
@@ -155,7 +160,7 @@
return None
-def set_price_list(out, party, party_type, given_price_list, pos=None):
+def set_price_list(party_details, party, party_type, given_price_list, pos=None):
# price list
price_list = get_permitted_documents('Price List')
@@ -173,9 +178,9 @@
price_list = get_default_price_list(party) or given_price_list
if price_list:
- out.price_list_currency = frappe.db.get_value("Price List", price_list, "currency", cache=True)
+ party_details.price_list_currency = frappe.db.get_value("Price List", price_list, "currency", cache=True)
- out["selling_price_list" if party.doctype=="Customer" else "buying_price_list"] = price_list
+ party_details["selling_price_list" if party.doctype=="Customer" else "buying_price_list"] = price_list
def set_account_and_due_date(party, account, party_type, company, posting_date, bill_date, doctype):
diff --git a/erpnext/accounts/print_format/bank_and_cash_payment_voucher/bank_and_cash_payment_voucher.html b/erpnext/accounts/print_format/bank_and_cash_payment_voucher/bank_and_cash_payment_voucher.html
index 69e42c3..6fe6999 100644
--- a/erpnext/accounts/print_format/bank_and_cash_payment_voucher/bank_and_cash_payment_voucher.html
+++ b/erpnext/accounts/print_format/bank_and_cash_payment_voucher/bank_and_cash_payment_voucher.html
@@ -49,7 +49,7 @@
{% endfor %}
<tr>
<td class="right" colspan="3" ><strong>Total (debit) </strong></td>
- <td class="left" >{{ gl | sum(attribute='debit') }}</td>
+ <td class="left" >{{ frappe.format((gl | sum(attribute="debit")), {fieldtype: "Currency"}) }}</td>
</tr>
<tr>
<td class="top-bottom" colspan="5"><strong>Credit</strong></td>
@@ -69,7 +69,7 @@
{% endfor %}
<tr>
<td class="right" colspan="3"><strong>Total (credit) </strong></td>
- <td class="left" >{{ gl | sum(attribute='credit') }}</td>
+ <td class="left" >{{ frappe.format((gl | sum(attribute="credit")), {fieldtype: "Currency"}) }}</td>
</tr>
</table>
<div>
diff --git a/erpnext/accounts/print_format/gst_pos_invoice/gst_pos_invoice.json b/erpnext/accounts/print_format/gst_pos_invoice/gst_pos_invoice.json
index 8a31368..1c5a195 100644
--- a/erpnext/accounts/print_format/gst_pos_invoice/gst_pos_invoice.json
+++ b/erpnext/accounts/print_format/gst_pos_invoice/gst_pos_invoice.json
@@ -1,22 +1,23 @@
{
- "align_labels_right": 0,
- "creation": "2017-08-08 12:33:04.773099",
- "custom_format": 1,
- "disabled": 0,
- "doc_type": "Sales Invoice",
- "docstatus": 0,
- "doctype": "Print Format",
- "font": "Default",
- "html": "<style>\n\t.print-format table, .print-format tr, \n\t.print-format td, .print-format div, .print-format p {\n\t\tfont-family: Monospace;\n\t\tline-height: 200%;\n\t\tvertical-align: middle;\n\t}\n\t@media screen {\n\t\t.print-format {\n\t\t\twidth: 4in;\n\t\t\tpadding: 0.25in;\n\t\t\tmin-height: 8in;\n\t\t}\n\t}\n</style>\n\n<p class=\"text-center\">\n\t{{ doc.company }}<br>\n\t{% if doc.company_address_display %}\n\t\t{% set company_address = doc.company_address_display.replace(\"\\n\", \" \").replace(\"<br>\", \" \") %}\n\t\t{% if \"GSTIN\" not in company_address %}\n\t\t\t{{ company_address }}\n\t\t\t<b>{{ _(\"GSTIN\") }}:</b>{{ doc.company_gstin }}\n\t\t{% else %}\n\t\t\t{{ company_address.replace(\"GSTIN\", \"<br>GSTIN\") }}\n\t\t{% endif %}\n\t{% endif %}\n\t<br>\n\t{% if doc.docstatus == 0 %}\n\t\t<b>{{ doc.status + \" \"+ (doc.select_print_heading or _(\"Invoice\")) }}</b><br>\n\t{% else %}\n\t\t<b>{{ doc.select_print_heading or _(\"Invoice\") }}</b><br>\n\t{% endif %}\n</p>\n<p>\n\t<b>{{ _(\"Receipt No\") }}:</b> {{ doc.name }}<br>\n\t<b>{{ _(\"Date\") }}:</b> {{ doc.get_formatted(\"posting_date\") }}<br>\n\t{% if doc.grand_total > 50000 %}\n\t\t{% set customer_address = doc.address_display.replace(\"\\n\", \" \").replace(\"<br>\", \" \") %}\n\t\t<b>{{ _(\"Customer\") }}:</b><br>\n\t\t{{ doc.customer_name }}<br>\n\t\t{{ customer_address }}\n\t{% endif %}\n</p>\n\n<hr>\n<table class=\"table table-condensed cart no-border\">\n\t<thead>\n\t\t<tr>\n\t\t\t<th width=\"40%\">{{ _(\"Item\") }}</b></th>\n\t\t\t<th width=\"30%\" class=\"text-right\">{{ _(\"Qty\") }}</th>\n\t\t\t<th width=\"30%\" class=\"text-right\">{{ _(\"Amount\") }}</th>\n\t\t</tr>\n\t</thead>\n\t<tbody>\n\t\t{%- for item in doc.items -%}\n\t\t<tr>\n\t\t\t<td>\n\t\t\t\t{{ item.item_code }}\n\t\t\t\t{%- if item.item_name != item.item_code -%}\n\t\t\t\t\t<br>{{ item.item_name }}\n\t\t\t\t{%- endif -%}\n\t\t\t\t{%- if item.gst_hsn_code -%}\n\t\t\t\t\t<br><b>{{ _(\"HSN/SAC\") }}:</b> {{ item.gst_hsn_code }}\n\t\t\t\t{%- endif -%}\n\t\t\t\t{%- if item.serial_no -%}\n\t\t\t\t\t<br><b>{{ _(\"Serial No\") }}:</b> {{ item.serial_no }}\n\t\t\t\t{%- endif -%}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">{{ item.qty }}<br>@ {{ item.rate }}</td>\n\t\t\t<td class=\"text-right\">{{ item.get_formatted(\"amount\") }}</td>\n\t\t</tr>\n\t\t{%- endfor -%}\n\t</tbody>\n</table>\n<table class=\"table table-condensed no-border\">\n\t<tbody>\n\t\t<tr>\n\t\t\t{% if doc.flags.show_inclusive_tax_in_print %}\n\t\t\t\t<td class=\"text-right\" style=\"width: 70%\">\n\t\t\t\t\t{{ _(\"Total Excl. Tax\") }}\n\t\t\t\t</td>\n\t\t\t\t<td class=\"text-right\">\n\t\t\t\t\t{{ doc.get_formatted(\"net_total\", doc) }}\n\t\t\t\t</td>\n\t\t\t{% else %}\n\t\t\t\t<td class=\"text-right\" style=\"width: 70%\">\n\t\t\t\t\t{{ _(\"Total\") }}\n\t\t\t\t</td>\n\t\t\t\t<td class=\"text-right\">\n\t\t\t\t\t{{ doc.get_formatted(\"total\", doc) }}\n\t\t\t\t</td>\n\t\t\t{% endif %}\n\t\t</tr>\n\t\t{%- for row in doc.taxes -%}\n\t\t {%- if (not row.included_in_print_rate or doc.flags.show_inclusive_tax_in_print) and row.tax_amount != 0 -%}\n\t\t\t<tr>\n\t\t\t\t<td class=\"text-right\" style=\"width: 70%\">\n\t\t\t\t\t{{ row.description }}\n\t\t\t\t</td>\n\t\t\t\t<td class=\"text-right\">\n\t\t\t\t\t{{ row.get_formatted(\"tax_amount\", doc) }}\n\t\t\t\t</td>\n\t\t\t<tr>\n\t\t {%- endif -%}\n\t\t{%- endfor -%}\n\t\t{%- if doc.discount_amount -%}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 75%\">\n\t\t\t\t{{ _(\"Discount\") }}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ doc.get_formatted(\"discount_amount\") }}\n\t\t\t</td>\n\t\t</tr>\n\t\t{%- endif -%}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 75%\">\n\t\t\t\t<b>{{ _(\"Grand Total\") }}</b>\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ doc.get_formatted(\"grand_total\") }}\n\t\t\t</td>\n\t\t</tr>\n\t\t{%- if doc.rounded_total -%}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 75%\">\n\t\t\t\t<b>{{ _(\"Rounded Total\") }}</b>\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ doc.get_formatted(\"rounded_total\") }}\n\t\t\t</td>\n\t\t</tr>\n\t\t{%- endif -%}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 75%\">\n\t\t\t\t<b>{{ _(\"Paid Amount\") }}</b>\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ doc.get_formatted(\"paid_amount\") }}\n\t\t\t</td>\n\t\t</tr>\n\t{%- if doc.change_amount -%}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 75%\">\n\t\t\t\t<b>{{ _(\"Change Amount\") }}</b>\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ doc.get_formatted(\"change_amount\") }}\n\t\t\t</td>\n\t\t</tr>\n\t{%- endif -%}\n\t</tbody>\n</table>\n<p>{{ doc.terms or \"\" }}</p>\n<p class=\"text-center\">{{ _(\"Thank you, please visit again.\") }}</p>",
- "idx": 0,
- "line_breaks": 0,
- "modified": "2019-01-24 17:09:27.190929",
- "modified_by": "Administrator",
- "module": "Accounts",
- "name": "GST POS Invoice",
- "owner": "Administrator",
- "print_format_builder": 0,
- "print_format_type": "Server",
- "show_section_headings": 0,
+ "align_labels_right": 0,
+ "creation": "2017-08-08 12:33:04.773099",
+ "custom_format": 1,
+ "disabled": 0,
+ "doc_type": "Sales Invoice",
+ "docstatus": 0,
+ "doctype": "Print Format",
+ "font": "Default",
+ "html": "<style>\n\t.print-format table, .print-format tr, \n\t.print-format td, .print-format div, .print-format p {\n\t\tfont-family: Monospace;\n\t\tline-height: 200%;\n\t\tvertical-align: middle;\n\t}\n\t@media screen {\n\t\t.print-format {\n\t\t\twidth: 4in;\n\t\t\tpadding: 0.25in;\n\t\t\tmin-height: 8in;\n\t\t}\n\t}\n</style>\n\n{% if letter_head %}\n {{ letter_head }}\n{% endif %}\n<p class=\"text-center\">\n\t{{ doc.company }}<br>\n\t{% if doc.company_address_display %}\n\t\t{% set company_address = doc.company_address_display.replace(\"\\n\", \" \").replace(\"<br>\", \" \") %}\n\t\t{% if \"GSTIN\" not in company_address %}\n\t\t\t{{ company_address }}\n\t\t\t<b>{{ _(\"GSTIN\") }}:</b>{{ doc.company_gstin }}\n\t\t{% else %}\n\t\t\t{{ company_address.replace(\"GSTIN\", \"<br>GSTIN\") }}\n\t\t{% endif %}\n\t{% endif %}\n\t<br>\n\t{% if doc.docstatus == 0 %}\n\t\t<b>{{ doc.status + \" \"+ (doc.select_print_heading or _(\"Invoice\")) }}</b><br>\n\t{% else %}\n\t\t<b>{{ doc.select_print_heading or _(\"Invoice\") }}</b><br>\n\t{% endif %}\n</p>\n<p>\n\t<b>{{ _(\"Receipt No\") }}:</b> {{ doc.name }}<br>\n\t<b>{{ _(\"Date\") }}:</b> {{ doc.get_formatted(\"posting_date\") }}<br>\n\t{% if doc.grand_total > 50000 %}\n\t\t{% set customer_address = doc.address_display.replace(\"\\n\", \" \").replace(\"<br>\", \" \") %}\n\t\t<b>{{ _(\"Customer\") }}:</b><br>\n\t\t{{ doc.customer_name }}<br>\n\t\t{{ customer_address }}\n\t{% endif %}\n</p>\n\n<hr>\n<table class=\"table table-condensed cart no-border\">\n\t<thead>\n\t\t<tr>\n\t\t\t<th width=\"40%\">{{ _(\"Item\") }}</b></th>\n\t\t\t<th width=\"30%\" class=\"text-right\">{{ _(\"Qty\") }}</th>\n\t\t\t<th width=\"30%\" class=\"text-right\">{{ _(\"Amount\") }}</th>\n\t\t</tr>\n\t</thead>\n\t<tbody>\n\t\t{%- for item in doc.items -%}\n\t\t<tr>\n\t\t\t<td>\n\t\t\t\t{{ item.item_code }}\n\t\t\t\t{%- if item.item_name != item.item_code -%}\n\t\t\t\t\t<br>{{ item.item_name }}\n\t\t\t\t{%- endif -%}\n\t\t\t\t{%- if item.gst_hsn_code -%}\n\t\t\t\t\t<br><b>{{ _(\"HSN/SAC\") }}:</b> {{ item.gst_hsn_code }}\n\t\t\t\t{%- endif -%}\n\t\t\t\t{%- if item.serial_no -%}\n\t\t\t\t\t<br><b>{{ _(\"Serial No\") }}:</b> {{ item.serial_no }}\n\t\t\t\t{%- endif -%}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">{{ item.qty }}<br>@ {{ item.rate }}</td>\n\t\t\t<td class=\"text-right\">{{ item.get_formatted(\"amount\") }}</td>\n\t\t</tr>\n\t\t{%- endfor -%}\n\t</tbody>\n</table>\n<table class=\"table table-condensed no-border\">\n\t<tbody>\n\t\t<tr>\n\t\t\t{% if doc.flags.show_inclusive_tax_in_print %}\n\t\t\t\t<td class=\"text-right\" style=\"width: 70%\">\n\t\t\t\t\t{{ _(\"Total Excl. Tax\") }}\n\t\t\t\t</td>\n\t\t\t\t<td class=\"text-right\">\n\t\t\t\t\t{{ doc.get_formatted(\"net_total\", doc) }}\n\t\t\t\t</td>\n\t\t\t{% else %}\n\t\t\t\t<td class=\"text-right\" style=\"width: 70%\">\n\t\t\t\t\t{{ _(\"Total\") }}\n\t\t\t\t</td>\n\t\t\t\t<td class=\"text-right\">\n\t\t\t\t\t{{ doc.get_formatted(\"total\", doc) }}\n\t\t\t\t</td>\n\t\t\t{% endif %}\n\t\t</tr>\n\t\t{%- for row in doc.taxes -%}\n\t\t {%- if (not row.included_in_print_rate or doc.flags.show_inclusive_tax_in_print) and row.tax_amount != 0 -%}\n\t\t\t<tr>\n\t\t\t\t<td class=\"text-right\" style=\"width: 70%\">\n\t\t\t\t\t{{ row.description }}\n\t\t\t\t</td>\n\t\t\t\t<td class=\"text-right\">\n\t\t\t\t\t{{ row.get_formatted(\"tax_amount\", doc) }}\n\t\t\t\t</td>\n\t\t\t<tr>\n\t\t {%- endif -%}\n\t\t{%- endfor -%}\n\t\t{%- if doc.discount_amount -%}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 75%\">\n\t\t\t\t{{ _(\"Discount\") }}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ doc.get_formatted(\"discount_amount\") }}\n\t\t\t</td>\n\t\t</tr>\n\t\t{%- endif -%}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 75%\">\n\t\t\t\t<b>{{ _(\"Grand Total\") }}</b>\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ doc.get_formatted(\"grand_total\") }}\n\t\t\t</td>\n\t\t</tr>\n\t\t{%- if doc.rounded_total -%}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 75%\">\n\t\t\t\t<b>{{ _(\"Rounded Total\") }}</b>\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ doc.get_formatted(\"rounded_total\") }}\n\t\t\t</td>\n\t\t</tr>\n\t\t{%- endif -%}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 75%\">\n\t\t\t\t<b>{{ _(\"Paid Amount\") }}</b>\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ doc.get_formatted(\"paid_amount\") }}\n\t\t\t</td>\n\t\t</tr>\n\t{%- if doc.change_amount -%}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 75%\">\n\t\t\t\t<b>{{ _(\"Change Amount\") }}</b>\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ doc.get_formatted(\"change_amount\") }}\n\t\t\t</td>\n\t\t</tr>\n\t{%- endif -%}\n\t</tbody>\n</table>\n<p>{{ doc.terms or \"\" }}</p>\n<p class=\"text-center\">{{ _(\"Thank you, please visit again.\") }}</p>",
+ "idx": 0,
+ "line_breaks": 0,
+ "modified": "2019-12-09 17:39:23.356573",
+ "modified_by": "Administrator",
+ "module": "Accounts",
+ "name": "GST POS Invoice",
+ "owner": "Administrator",
+ "print_format_builder": 0,
+ "print_format_type": "Jinja",
+ "raw_printing": 0,
+ "show_section_headings": 0,
"standard": "Yes"
}
\ No newline at end of file
diff --git a/erpnext/accounts/print_format/pos_invoice/pos_invoice.json b/erpnext/accounts/print_format/pos_invoice/pos_invoice.json
index c3450d6..be69922 100644
--- a/erpnext/accounts/print_format/pos_invoice/pos_invoice.json
+++ b/erpnext/accounts/print_format/pos_invoice/pos_invoice.json
@@ -1,21 +1,22 @@
{
- "align_labels_right": 0,
- "creation": "2011-12-21 11:08:55",
- "custom_format": 1,
- "disabled": 0,
- "doc_type": "Sales Invoice",
- "docstatus": 0,
- "doctype": "Print Format",
- "html": "<style>\n\t.print-format table, .print-format tr, \n\t.print-format td, .print-format div, .print-format p {\n\t\tfont-family: Monospace;\n\t\tline-height: 200%;\n\t\tvertical-align: middle;\n\t}\n\t@media screen {\n\t\t.print-format {\n\t\t\twidth: 4in;\n\t\t\tpadding: 0.25in;\n\t\t\tmin-height: 8in;\n\t\t}\n\t}\n</style>\n\n<p class=\"text-center\">\n\t{{ doc.company }}<br>\n\t{% if doc.docstatus == 0 %}\n\t\t{{ doc.status + \" \" + (doc.select_print_heading or _(\"Invoice\")) }}<br>\n\t{% else %}\n\t\t{{ doc.select_print_heading or _(\"Invoice\") }}<br>\n\t{% endif %}\n</p>\n<p>\n\t<b>{{ _(\"Receipt No\") }}:</b> {{ doc.name }}<br>\n\t<b>{{ _(\"Date\") }}:</b> {{ doc.get_formatted(\"posting_date\") }}<br>\n\t<b>{{ _(\"Customer\") }}:</b> {{ doc.customer_name }}\n</p>\n\n<hr>\n<table class=\"table table-condensed cart no-border\">\n\t<thead>\n\t\t<tr>\n\t\t\t<th width=\"50%\">{{ _(\"Item\") }}</b></th>\n\t\t\t<th width=\"25%\" class=\"text-right\">{{ _(\"Qty\") }}</th>\n\t\t\t<th width=\"25%\" class=\"text-right\">{{ _(\"Amount\") }}</th>\n\t\t</tr>\n\t</thead>\n\t<tbody>\n\t\t{%- for item in doc.items -%}\n\t\t<tr>\n\t\t\t<td>\n\t\t\t\t{{ item.item_code }}\n\t\t\t\t{%- if item.item_name != item.item_code -%}\n\t\t\t\t\t<br>{{ item.item_name }}{%- endif -%}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">{{ item.qty }}<br>@ {{ item.get_formatted(\"rate\") }}</td>\n\t\t\t<td class=\"text-right\">{{ item.get_formatted(\"amount\") }}</td>\n\t\t</tr>\n\t\t{%- endfor -%}\n\t</tbody>\n</table>\n<table class=\"table table-condensed no-border\">\n\t<tbody>\n\t\t<tr>\n\t\t\t{% if doc.flags.show_inclusive_tax_in_print %}\n\t\t\t\t<td class=\"text-right\" style=\"width: 70%\">\n\t\t\t\t\t{{ _(\"Total Excl. Tax\") }}\n\t\t\t\t</td>\n\t\t\t\t<td class=\"text-right\">\n\t\t\t\t\t{{ doc.get_formatted(\"net_total\", doc) }}\n\t\t\t\t</td>\n\t\t\t{% else %}\n\t\t\t\t<td class=\"text-right\" style=\"width: 70%\">\n\t\t\t\t\t{{ _(\"Total\") }}\n\t\t\t\t</td>\n\t\t\t\t<td class=\"text-right\">\n\t\t\t\t\t{{ doc.get_formatted(\"total\", doc) }}\n\t\t\t\t</td>\n\t\t\t{% endif %}\n\t\t</tr>\n\t\t{%- for row in doc.taxes -%}\n\t\t {%- if not row.included_in_print_rate or doc.flags.show_inclusive_tax_in_print -%}\n\t\t\t<tr>\n\t\t\t\t<td class=\"text-right\" style=\"width: 70%\">\n\t\t\t\t\t{{ row.description }}\n\t\t\t\t</td>\n\t\t\t\t<td class=\"text-right\">\n\t\t\t\t\t{{ row.get_formatted(\"tax_amount\", doc) }}\n\t\t\t\t</td>\n\t\t\t<tr>\n\t\t {%- endif -%}\n\t\t{%- endfor -%}\n\n\t\t{%- if doc.discount_amount -%}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 75%\">\n\t\t\t\t{{ _(\"Discount\") }}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ doc.get_formatted(\"discount_amount\") }}\n\t\t\t</td>\n\t\t</tr>\n\t\t{%- endif -%}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 75%\">\n\t\t\t\t<b>{{ _(\"Grand Total\") }}</b>\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ doc.get_formatted(\"grand_total\") }}\n\t\t\t</td>\n\t\t</tr>\n\t\t{%- if doc.rounded_total -%}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 75%\">\n\t\t\t\t<b>{{ _(\"Rounded Total\") }}</b>\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ doc.get_formatted(\"rounded_total\") }}\n\t\t\t</td>\n\t\t</tr>\n\t\t{%- endif -%}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 75%\">\n\t\t\t\t<b>{{ _(\"Paid Amount\") }}</b>\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ doc.get_formatted(\"paid_amount\") }}\n\t\t\t</td>\n\t\t</tr>\n\t\t{%- if doc.change_amount -%}\n\t\t\t<tr>\n\t\t\t\t<td class=\"text-right\" style=\"width: 75%\">\n\t\t\t\t\t<b>{{ _(\"Change Amount\") }}</b>\n\t\t\t\t</td>\n\t\t\t\t<td class=\"text-right\">\n\t\t\t\t\t{{ doc.get_formatted(\"change_amount\") }}\n\t\t\t\t</td>\n\t\t\t</tr>\n\t\t{%- endif -%}\n\t\t{%- if doc.pos_total_qty -%}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 75%\">\n\t\t\t\t<b>{{ _(\"Total Qty\") }}</b>\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ doc.get_formatted(\"pos_total_qty\") }}\n\t\t\t</td>\n\t\t</tr>\n\t\t{%- endif -%}\n\t</tbody>\n</table>\n<hr>\n<p>{{ doc.terms or \"\" }}</p>\n<p class=\"text-center\">{{ _(\"Thank you, please visit again.\") }}</p>",
- "idx": 1,
- "line_breaks": 0,
- "modified": "2018-03-20 14:24:12.394354",
- "modified_by": "Administrator",
- "module": "Accounts",
- "name": "POS Invoice",
- "owner": "Administrator",
- "print_format_builder": 0,
- "print_format_type": "Server",
- "show_section_headings": 0,
+ "align_labels_right": 0,
+ "creation": "2011-12-21 11:08:55",
+ "custom_format": 1,
+ "disabled": 0,
+ "doc_type": "Sales Invoice",
+ "docstatus": 0,
+ "doctype": "Print Format",
+ "html": "<style>\n\t.print-format table, .print-format tr, \n\t.print-format td, .print-format div, .print-format p {\n\t\tfont-family: Monospace;\n\t\tline-height: 200%;\n\t\tvertical-align: middle;\n\t}\n\t@media screen {\n\t\t.print-format {\n\t\t\twidth: 4in;\n\t\t\tpadding: 0.25in;\n\t\t\tmin-height: 8in;\n\t\t}\n\t}\n</style>\n\n{% if letter_head %}\n {{ letter_head }}\n{% endif %}\n\n<p class=\"text-center\">\n\t{{ doc.company }}<br>\n\t{{ doc.select_print_heading or _(\"Invoice\") }}<br>\n</p>\n<p>\n\t<b>{{ _(\"Receipt No\") }}:</b> {{ doc.name }}<br>\n\t<b>{{ _(\"Date\") }}:</b> {{ doc.get_formatted(\"posting_date\") }}<br>\n\t<b>{{ _(\"Customer\") }}:</b> {{ doc.customer_name }}\n</p>\n\n<hr>\n<table class=\"table table-condensed cart no-border\">\n\t<thead>\n\t\t<tr>\n\t\t\t<th width=\"50%\">{{ _(\"Item\") }}</b></th>\n\t\t\t<th width=\"25%\" class=\"text-right\">{{ _(\"Qty\") }}</th>\n\t\t\t<th width=\"25%\" class=\"text-right\">{{ _(\"Amount\") }}</th>\n\t\t</tr>\n\t</thead>\n\t<tbody>\n\t\t{%- for item in doc.items -%}\n\t\t<tr>\n\t\t\t<td>\n\t\t\t\t{{ item.item_code }}\n\t\t\t\t{%- if item.item_name != item.item_code -%}\n\t\t\t\t\t<br>{{ item.item_name }}{%- endif -%}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">{{ item.qty }}<br>@ {{ item.get_formatted(\"rate\") }}</td>\n\t\t\t<td class=\"text-right\">{{ item.get_formatted(\"amount\") }}</td>\n\t\t</tr>\n\t\t{%- endfor -%}\n\t</tbody>\n</table>\n<table class=\"table table-condensed no-border\">\n\t<tbody>\n\t\t<tr>\n\t\t\t{% if doc.flags.show_inclusive_tax_in_print %}\n\t\t\t\t<td class=\"text-right\" style=\"width: 70%\">\n\t\t\t\t\t{{ _(\"Total Excl. Tax\") }}\n\t\t\t\t</td>\n\t\t\t\t<td class=\"text-right\">\n\t\t\t\t\t{{ doc.get_formatted(\"net_total\", doc) }}\n\t\t\t\t</td>\n\t\t\t{% else %}\n\t\t\t\t<td class=\"text-right\" style=\"width: 70%\">\n\t\t\t\t\t{{ _(\"Total\") }}\n\t\t\t\t</td>\n\t\t\t\t<td class=\"text-right\">\n\t\t\t\t\t{{ doc.get_formatted(\"total\", doc) }}\n\t\t\t\t</td>\n\t\t\t{% endif %}\n\t\t</tr>\n\t\t{%- for row in doc.taxes -%}\n\t\t {%- if not row.included_in_print_rate or doc.flags.show_inclusive_tax_in_print -%}\n\t\t\t<tr>\n\t\t\t\t<td class=\"text-right\" style=\"width: 70%\">\n\t\t\t\t\t{{ row.description }}\n\t\t\t\t</td>\n\t\t\t\t<td class=\"text-right\">\n\t\t\t\t\t{{ row.get_formatted(\"tax_amount\", doc) }}\n\t\t\t\t</td>\n\t\t\t<tr>\n\t\t {%- endif -%}\n\t\t{%- endfor -%}\n\n\t\t{%- if doc.discount_amount -%}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 75%\">\n\t\t\t\t{{ _(\"Discount\") }}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ doc.get_formatted(\"discount_amount\") }}\n\t\t\t</td>\n\t\t</tr>\n\t\t{%- endif -%}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 75%\">\n\t\t\t\t<b>{{ _(\"Grand Total\") }}</b>\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ doc.get_formatted(\"grand_total\") }}\n\t\t\t</td>\n\t\t</tr>\n\t\t{%- if doc.rounded_total -%}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 75%\">\n\t\t\t\t<b>{{ _(\"Rounded Total\") }}</b>\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ doc.get_formatted(\"rounded_total\") }}\n\t\t\t</td>\n\t\t</tr>\n\t\t{%- endif -%}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 75%\">\n\t\t\t\t<b>{{ _(\"Paid Amount\") }}</b>\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ doc.get_formatted(\"paid_amount\") }}\n\t\t\t</td>\n\t\t</tr>\n\t\t{%- if doc.change_amount -%}\n\t\t\t<tr>\n\t\t\t\t<td class=\"text-right\" style=\"width: 75%\">\n\t\t\t\t\t<b>{{ _(\"Change Amount\") }}</b>\n\t\t\t\t</td>\n\t\t\t\t<td class=\"text-right\">\n\t\t\t\t\t{{ doc.get_formatted(\"change_amount\") }}\n\t\t\t\t</td>\n\t\t\t</tr>\n\t\t{%- endif -%}\n\t</tbody>\n</table>\n<hr>\n<p>{{ doc.terms or \"\" }}</p>\n<p class=\"text-center\">{{ _(\"Thank you, please visit again.\") }}</p>",
+ "idx": 1,
+ "line_breaks": 0,
+ "modified": "2019-12-09 17:40:53.183574",
+ "modified_by": "Administrator",
+ "module": "Accounts",
+ "name": "POS Invoice",
+ "owner": "Administrator",
+ "print_format_builder": 0,
+ "print_format_type": "Jinja",
+ "raw_printing": 0,
+ "show_section_headings": 0,
"standard": "Yes"
}
\ No newline at end of file
diff --git a/erpnext/accounts/report/accounts_payable/accounts_payable.js b/erpnext/accounts/report/accounts_payable/accounts_payable.js
index 8eb670de..b1f427c 100644
--- a/erpnext/accounts/report/accounts_payable/accounts_payable.js
+++ b/erpnext/accounts/report/accounts_payable/accounts_payable.js
@@ -101,6 +101,11 @@
"options": "Supplier Group"
},
{
+ "fieldname":"based_on_payment_terms",
+ "label": __("Based On Payment Terms"),
+ "fieldtype": "Check",
+ },
+ {
"fieldname":"tax_id",
"label": __("Tax Id"),
"fieldtype": "Data",
diff --git a/erpnext/accounts/report/accounts_payable_summary/accounts_payable_summary.js b/erpnext/accounts/report/accounts_payable_summary/accounts_payable_summary.js
index 5f0fdc9..4a9f1b0 100644
--- a/erpnext/accounts/report/accounts_payable_summary/accounts_payable_summary.js
+++ b/erpnext/accounts/report/accounts_payable_summary/accounts_payable_summary.js
@@ -88,6 +88,11 @@
"label": __("Supplier Group"),
"fieldtype": "Link",
"options": "Supplier Group"
+ },
+ {
+ "fieldname":"based_on_payment_terms",
+ "label": __("Based On Payment Terms"),
+ "fieldtype": "Check",
}
],
diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.js b/erpnext/accounts/report/accounts_receivable/accounts_receivable.js
index 228be18..9b4dda2 100644
--- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.js
+++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.js
@@ -79,13 +79,20 @@
"options": "Customer",
on_change: () => {
var customer = frappe.query_report.get_filter_value('customer');
+ var company = frappe.query_report.get_filter_value('company');
if (customer) {
- frappe.db.get_value('Customer', customer, ["tax_id", "customer_name", "credit_limit", "payment_terms"], function(value) {
+ frappe.db.get_value('Customer', customer, ["tax_id", "customer_name", "payment_terms"], function(value) {
frappe.query_report.set_filter_value('tax_id', value["tax_id"]);
frappe.query_report.set_filter_value('customer_name', value["customer_name"]);
- frappe.query_report.set_filter_value('credit_limit', value["credit_limit"]);
frappe.query_report.set_filter_value('payment_terms', value["payment_terms"]);
});
+
+ frappe.db.get_value('Customer Credit Limit', {'parent': customer, 'company': company},
+ ["credit_limit"], function(value) {
+ if (value) {
+ frappe.query_report.set_filter_value('credit_limit', value["credit_limit"]);
+ }
+ }, "Customer");
} else {
frappe.query_report.set_filter_value('tax_id', "");
frappe.query_report.set_filter_value('customer_name', "");
diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
index bcbd427..f82146a 100755
--- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
+++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
@@ -60,6 +60,7 @@
def get_data(self):
self.get_gl_entries()
+ self.get_sales_invoices_or_customers_based_on_sales_person()
self.voucher_balance = OrderedDict()
self.init_voucher_balance() # invoiced, paid, credit_note, outstanding
@@ -103,12 +104,18 @@
def get_invoices(self, gle):
if gle.voucher_type in ('Sales Invoice', 'Purchase Invoice'):
- self.invoices.add(gle.voucher_no)
+ if self.filters.get("sales_person"):
+ if gle.voucher_no in self.sales_person_records.get("Sales Invoice", []) \
+ or gle.party in self.sales_person_records.get("Customer", []):
+ self.invoices.add(gle.voucher_no)
+ else:
+ self.invoices.add(gle.voucher_no)
def update_voucher_balance(self, gle):
# get the row where this balance needs to be updated
# if its a payment, it will return the linked invoice or will be considered as advance
row = self.get_voucher_balance(gle)
+ if not row: return
# gle_balance will be the total "debit - credit" for receivable type reports and
# and vice-versa for payable type reports
gle_balance = self.get_gle_balance(gle)
@@ -129,8 +136,13 @@
row.paid -= gle_balance
def get_voucher_balance(self, gle):
- voucher_balance = None
+ if self.filters.get("sales_person"):
+ against_voucher = gle.against_voucher or gle.voucher_no
+ if not (gle.party in self.sales_person_records.get("Customer", []) or \
+ against_voucher in self.sales_person_records.get("Sales Invoice", [])):
+ return
+ voucher_balance = None
if gle.against_voucher:
# find invoice
against_voucher = gle.against_voucher
@@ -159,7 +171,7 @@
row.outstanding = flt(row.invoiced - row.paid - row.credit_note, self.currency_precision)
row.invoice_grand_total = row.invoiced
- if abs(row.outstanding) > 0.1/10 ** self.currency_precision:
+ if abs(row.outstanding) > 1.0/10 ** self.currency_precision:
# non-zero oustanding, we must consider this row
if self.is_invoice(row) and self.filters.based_on_payment_terms:
@@ -188,7 +200,11 @@
self.data.append(row)
def set_invoice_details(self, row):
- row.update(self.invoice_details.get(row.voucher_no, {}))
+ invoice_details = self.invoice_details.get(row.voucher_no, {})
+ if row.due_date:
+ invoice_details.pop("due_date", None)
+ row.update(invoice_details)
+
if row.voucher_type == 'Sales Invoice':
if self.filters.show_delivery_notes:
self.set_delivery_notes(row)
@@ -269,7 +285,7 @@
def set_party_details(self, row):
# customer / supplier name
- party_details = self.get_party_details(row.party)
+ party_details = self.get_party_details(row.party) or {}
row.update(party_details)
if self.filters.get(scrub(self.filters.party_type)):
row.currency = row.account_currency
@@ -314,7 +330,7 @@
self.append_payment_term(row, d, term)
def append_payment_term(self, row, d, term):
- if self.filters.get("customer") and d.currency == d.party_account_currency:
+ if (self.filters.get("customer") or self.filters.get("supplier")) and d.currency == d.party_account_currency:
invoiced = d.payment_amount
else:
invoiced = flt(flt(d.payment_amount) * flt(d.conversion_rate), self.currency_precision)
@@ -508,6 +524,22 @@
order by posting_date, party"""
.format(select_fields, conditions), values, as_dict=True)
+ def get_sales_invoices_or_customers_based_on_sales_person(self):
+ if self.filters.get("sales_person"):
+ lft, rgt = frappe.db.get_value("Sales Person",
+ self.filters.get("sales_person"), ["lft", "rgt"])
+
+ records = frappe.db.sql("""
+ select distinct parent, parenttype
+ from `tabSales Team` steam
+ where parenttype in ('Customer', 'Sales Invoice')
+ and exists(select name from `tabSales Person` where lft >= %s and rgt <= %s and name = steam.sales_person)
+ """, (lft, rgt), as_dict=1)
+
+ self.sales_person_records = frappe._dict()
+ for d in records:
+ self.sales_person_records.setdefault(d.parenttype, set()).add(d.parent)
+
def prepare_conditions(self):
conditions = [""]
values = [self.party_type, self.filters.report_date]
@@ -560,16 +592,6 @@
conditions.append("party in (select name from tabCustomer where default_sales_partner=%s)")
values.append(self.filters.get("sales_partner"))
- if self.filters.get("sales_person"):
- lft, rgt = frappe.db.get_value("Sales Person",
- self.filters.get("sales_person"), ["lft", "rgt"])
-
- conditions.append("""exists(select name from `tabSales Team` steam where
- steam.sales_person in (select name from `tabSales Person` where lft >= {0} and rgt <= {1})
- and ((steam.parent = voucher_no and steam.parenttype = voucher_type)
- or (steam.parent = against_voucher and steam.parenttype = against_voucher_type)
- or (steam.parent = party and steam.parenttype = 'Customer')))""".format(lft, rgt))
-
def add_supplier_filters(self, conditions, values):
if self.filters.get("supplier_group"):
conditions.append("""party in (select name from tabSupplier
diff --git a/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.js b/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.js
index 0120608..d54824b 100644
--- a/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.js
+++ b/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.js
@@ -106,6 +106,11 @@
"label": __("Sales Person"),
"fieldtype": "Link",
"options": "Sales Person"
+ },
+ {
+ "fieldname":"based_on_payment_terms",
+ "label": __("Based On Payment Terms"),
+ "fieldtype": "Check",
}
],
diff --git a/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py b/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py
index b90a7a9..b607c0f 100644
--- a/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py
+++ b/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py
@@ -36,6 +36,9 @@
self.filters.report_date) or {}
for party, party_dict in iteritems(self.party_total):
+ if party_dict.outstanding == 0:
+ continue
+
row = frappe._dict()
row.party = party
diff --git a/erpnext/accounts/report/asset_depreciations_and_balances/asset_depreciations_and_balances.py b/erpnext/accounts/report/asset_depreciations_and_balances/asset_depreciations_and_balances.py
index 0c99f14..7854660 100644
--- a/erpnext/accounts/report/asset_depreciations_and_balances/asset_depreciations_and_balances.py
+++ b/erpnext/accounts/report/asset_depreciations_and_balances/asset_depreciations_and_balances.py
@@ -4,126 +4,141 @@
from __future__ import unicode_literals
import frappe
from frappe import _
-from frappe.utils import formatdate, getdate, flt, add_days
+from frappe.utils import formatdate, flt, add_days
+
def execute(filters=None):
filters.day_before_from_date = add_days(filters.from_date, -1)
columns, data = get_columns(filters), get_data(filters)
return columns, data
-
+
+
def get_data(filters):
data = []
-
+
asset_categories = get_asset_categories(filters)
assets = get_assets(filters)
- asset_costs = get_asset_costs(assets, filters)
- asset_depreciations = get_accumulated_depreciations(assets, filters)
-
+
for asset_category in asset_categories:
row = frappe._dict()
- row.asset_category = asset_category
- row.update(asset_costs.get(asset_category))
+ # row.asset_category = asset_category
+ row.update(asset_category)
- row.cost_as_on_to_date = (flt(row.cost_as_on_from_date) + flt(row.cost_of_new_purchase)
- - flt(row.cost_of_sold_asset) - flt(row.cost_of_scrapped_asset))
-
- row.update(asset_depreciations.get(asset_category))
- row.accumulated_depreciation_as_on_to_date = (flt(row.accumulated_depreciation_as_on_from_date) +
- flt(row.depreciation_amount_during_the_period) - flt(row.depreciation_eliminated))
-
- row.net_asset_value_as_on_from_date = (flt(row.cost_as_on_from_date) -
- flt(row.accumulated_depreciation_as_on_from_date))
-
- row.net_asset_value_as_on_to_date = (flt(row.cost_as_on_to_date) -
- flt(row.accumulated_depreciation_as_on_to_date))
-
+ row.cost_as_on_to_date = (flt(row.cost_as_on_from_date) + flt(row.cost_of_new_purchase) -
+ flt(row.cost_of_sold_asset) - flt(row.cost_of_scrapped_asset))
+
+ row.update(next(asset for asset in assets if asset["asset_category"] == asset_category.get("asset_category", "")))
+ row.accumulated_depreciation_as_on_to_date = (flt(row.accumulated_depreciation_as_on_from_date) +
+ flt(row.depreciation_amount_during_the_period) - flt(row.depreciation_eliminated))
+
+ row.net_asset_value_as_on_from_date = (flt(row.cost_as_on_from_date) -
+ flt(row.accumulated_depreciation_as_on_from_date))
+
+ row.net_asset_value_as_on_to_date = (flt(row.cost_as_on_to_date) -
+ flt(row.accumulated_depreciation_as_on_to_date))
+
data.append(row)
-
+
return data
-
+
+
def get_asset_categories(filters):
- return frappe.db.sql_list("""
- select distinct asset_category from `tabAsset`
- where docstatus=1 and company=%s and purchase_date <= %s
- """, (filters.company, filters.to_date))
-
+ return frappe.db.sql("""
+ SELECT asset_category,
+ ifnull(sum(case when purchase_date < %(from_date)s then
+ case when ifnull(disposal_date, 0) = 0 or disposal_date >= %(from_date)s then
+ gross_purchase_amount
+ else
+ 0
+ end
+ else
+ 0
+ end), 0) as cost_as_on_from_date,
+ ifnull(sum(case when purchase_date >= %(from_date)s then
+ gross_purchase_amount
+ else
+ 0
+ end), 0) as cost_of_new_purchase,
+ ifnull(sum(case when ifnull(disposal_date, 0) != 0
+ and disposal_date >= %(from_date)s
+ and disposal_date <= %(to_date)s then
+ case when status = "Sold" then
+ gross_purchase_amount
+ else
+ 0
+ end
+ else
+ 0
+ end), 0) as cost_of_sold_asset,
+ ifnull(sum(case when ifnull(disposal_date, 0) != 0
+ and disposal_date >= %(from_date)s
+ and disposal_date <= %(to_date)s then
+ case when status = "Scrapped" then
+ gross_purchase_amount
+ else
+ 0
+ end
+ else
+ 0
+ end), 0) as cost_of_scrapped_asset
+ from `tabAsset`
+ where docstatus=1 and company=%(company)s and purchase_date <= %(to_date)s
+ group by asset_category
+ """, {"to_date": filters.to_date, "from_date": filters.from_date, "company": filters.company}, as_dict=1)
+
+
def get_assets(filters):
return frappe.db.sql("""
- select name, asset_category, purchase_date, gross_purchase_amount, disposal_date, status
- from `tabAsset`
- where docstatus=1 and company=%s and purchase_date <= %s""",
- (filters.company, filters.to_date), as_dict=1)
-
-def get_asset_costs(assets, filters):
- asset_costs = frappe._dict()
- for d in assets:
- asset_costs.setdefault(d.asset_category, frappe._dict({
- "cost_as_on_from_date": 0,
- "cost_of_new_purchase": 0,
- "cost_of_sold_asset": 0,
- "cost_of_scrapped_asset": 0
- }))
-
- costs = asset_costs[d.asset_category]
-
- if getdate(d.purchase_date) < getdate(filters.from_date):
- if not d.disposal_date or getdate(d.disposal_date) >= getdate(filters.from_date):
- costs.cost_as_on_from_date += flt(d.gross_purchase_amount)
- else:
- costs.cost_of_new_purchase += flt(d.gross_purchase_amount)
-
- if d.disposal_date and getdate(d.disposal_date) >= getdate(filters.from_date) \
- and getdate(d.disposal_date) <= getdate(filters.to_date):
- if d.status == "Sold":
- costs.cost_of_sold_asset += flt(d.gross_purchase_amount)
- elif d.status == "Scrapped":
- costs.cost_of_scrapped_asset += flt(d.gross_purchase_amount)
-
- return asset_costs
-
-def get_accumulated_depreciations(assets, filters):
- asset_depreciations = frappe._dict()
- for d in assets:
- asset = frappe.get_doc("Asset", d.name)
-
- if d.asset_category in asset_depreciations:
- asset_depreciations[d.asset_category]['accumulated_depreciation_as_on_from_date'] += asset.opening_accumulated_depreciation
- else:
- asset_depreciations.setdefault(d.asset_category, frappe._dict({
- "accumulated_depreciation_as_on_from_date": asset.opening_accumulated_depreciation,
- "depreciation_amount_during_the_period": 0,
- "depreciation_eliminated_during_the_period": 0
- }))
+ SELECT results.asset_category,
+ sum(results.accumulated_depreciation_as_on_from_date) as accumulated_depreciation_as_on_from_date,
+ sum(results.depreciation_eliminated_during_the_period) as depreciation_eliminated_during_the_period,
+ sum(results.depreciation_amount_during_the_period) as depreciation_amount_during_the_period
+ from (SELECT a.asset_category,
+ ifnull(sum(a.opening_accumulated_depreciation +
+ case when ds.schedule_date < %(from_date)s and
+ (ifnull(a.disposal_date, 0) = 0 or a.disposal_date >= %(from_date)s) then
+ ds.depreciation_amount
+ else
+ 0
+ end), 0) as accumulated_depreciation_as_on_from_date,
+ ifnull(sum(case when ifnull(a.disposal_date, 0) != 0 and a.disposal_date >= %(from_date)s
+ and a.disposal_date <= %(to_date)s and ds.schedule_date <= a.disposal_date then
+ ds.depreciation_amount
+ else
+ 0
+ end), 0) as depreciation_eliminated_during_the_period,
- depr = asset_depreciations[d.asset_category]
+ ifnull(sum(case when ds.schedule_date >= %(from_date)s and ds.schedule_date <= %(to_date)s
+ and (ifnull(a.disposal_date, 0) = 0 or ds.schedule_date <= a.disposal_date) then
+ ds.depreciation_amount
+ else
+ 0
+ end), 0) as depreciation_amount_during_the_period
+ from `tabAsset` a, `tabDepreciation Schedule` ds
+ where a.docstatus=1 and a.company=%(company)s and a.purchase_date <= %(to_date)s and a.name = ds.parent
+ group by a.asset_category
+ union
+ SELECT a.asset_category,
+ ifnull(sum(case when ifnull(a.disposal_date, 0) != 0
+ and (a.disposal_date < %(from_date)s or a.disposal_date > %(to_date)s) then
+ 0
+ else
+ a.opening_accumulated_depreciation
+ end), 0) as accumulated_depreciation_as_on_from_date,
+ ifnull(sum(case when a.disposal_date >= %(from_date)s and a.disposal_date <= %(to_date)s then
+ a.opening_accumulated_depreciation
+ else
+ 0
+ end), 0) as depreciation_eliminated_during_the_period,
+ 0 as depreciation_amount_during_the_period
+ from `tabAsset` a
+ where a.docstatus=1 and a.company=%(company)s and a.purchase_date <= %(to_date)s
+ and not exists(select * from `tabDepreciation Schedule` ds where a.name = ds.parent)
+ group by a.asset_category) as results
+ group by results.asset_category
+ """, {"to_date": filters.to_date, "from_date": filters.from_date, "company": filters.company}, as_dict=1)
- if not asset.schedules: # if no schedule,
- if asset.disposal_date:
- # and disposal is NOT within the period, then opening accumulated depreciation not included
- if getdate(asset.disposal_date) < getdate(filters.from_date) or getdate(asset.disposal_date) > getdate(filters.to_date):
- asset_depreciations[d.asset_category]['accumulated_depreciation_as_on_from_date'] = 0
- # if no schedule, and disposal is within period, accumulated dep is the amount eliminated
- if getdate(asset.disposal_date) >= getdate(filters.from_date) and getdate(asset.disposal_date) <= getdate(filters.to_date):
- depr.depreciation_eliminated_during_the_period += asset.opening_accumulated_depreciation
-
- for schedule in asset.get("schedules"):
- if getdate(schedule.schedule_date) < getdate(filters.from_date):
- if not asset.disposal_date or getdate(asset.disposal_date) >= getdate(filters.from_date):
- depr.accumulated_depreciation_as_on_from_date += flt(schedule.depreciation_amount)
- elif getdate(schedule.schedule_date) <= getdate(filters.to_date):
- if not asset.disposal_date:
- depr.depreciation_amount_during_the_period += flt(schedule.depreciation_amount)
- else:
- if getdate(schedule.schedule_date) <= getdate(asset.disposal_date):
- depr.depreciation_amount_during_the_period += flt(schedule.depreciation_amount)
-
- if asset.disposal_date and getdate(asset.disposal_date) >= getdate(filters.from_date) and getdate(asset.disposal_date) <= getdate(filters.to_date):
- if getdate(schedule.schedule_date) <= getdate(asset.disposal_date):
- depr.depreciation_eliminated_during_the_period += flt(schedule.depreciation_amount)
-
- return asset_depreciations
-
def get_columns(filters):
return [
{
diff --git a/erpnext/accounts/report/balance_sheet/balance_sheet.js b/erpnext/accounts/report/balance_sheet/balance_sheet.js
index 4bc29da..8c11514 100644
--- a/erpnext/accounts/report/balance_sheet/balance_sheet.js
+++ b/erpnext/accounts/report/balance_sheet/balance_sheet.js
@@ -2,7 +2,7 @@
// License: GNU General Public License v3. See license.txt
frappe.require("assets/erpnext/js/financial_statements.js", function() {
- frappe.query_reports["Balance Sheet"] = erpnext.financial_statements;
+ frappe.query_reports["Balance Sheet"] = $.extend({}, erpnext.financial_statements);
frappe.query_reports["Balance Sheet"]["filters"].push({
"fieldname": "accumulated_values",
diff --git a/erpnext/accounts/report/budget_variance_report/budget_variance_report.js b/erpnext/accounts/report/budget_variance_report/budget_variance_report.js
index 2451187..3ec4d30 100644
--- a/erpnext/accounts/report/budget_variance_report/budget_variance_report.js
+++ b/erpnext/accounts/report/budget_variance_report/budget_variance_report.js
@@ -46,13 +46,24 @@
fieldtype: "Select",
options: ["Cost Center", "Project"],
default: "Cost Center",
- reqd: 1
+ reqd: 1,
+ on_change: function() {
+ frappe.query_report.set_filter_value("budget_against_filter", []);
+ frappe.query_report.refresh();
+ }
},
{
- fieldname: "cost_center",
- label: __("Cost Center"),
- fieldtype: "Link",
- options: "Cost Center"
+ fieldname:"budget_against_filter",
+ label: __('Dimension Filter'),
+ fieldtype: "MultiSelectList",
+ get_data: function(txt) {
+ if (!frappe.query_report.filters) return;
+
+ let budget_against = frappe.query_report.get_filter_value('budget_against');
+ if (!budget_against) return;
+
+ return frappe.db.get_link_options(budget_against, txt);
+ }
},
{
fieldname:"show_cumulative",
diff --git a/erpnext/accounts/report/budget_variance_report/budget_variance_report.py b/erpnext/accounts/report/budget_variance_report/budget_variance_report.py
index 8d65ac8..39e218b 100644
--- a/erpnext/accounts/report/budget_variance_report/budget_variance_report.py
+++ b/erpnext/accounts/report/budget_variance_report/budget_variance_report.py
@@ -12,22 +12,22 @@
from pprint import pprint
def execute(filters=None):
if not filters: filters = {}
- validate_filters(filters)
+
columns = get_columns(filters)
- if filters.get("cost_center"):
- cost_centers = [filters.get("cost_center")]
+ if filters.get("budget_against_filter"):
+ dimensions = filters.get("budget_against_filter")
else:
- cost_centers = get_cost_centers(filters)
+ dimensions = get_cost_centers(filters)
period_month_ranges = get_period_month_ranges(filters["period"], filters["from_fiscal_year"])
- cam_map = get_cost_center_account_month_map(filters)
+ cam_map = get_dimension_account_month_map(filters)
data = []
- for cost_center in cost_centers:
- cost_center_items = cam_map.get(cost_center)
- if cost_center_items:
- for account, monthwise_data in iteritems(cost_center_items):
- row = [cost_center, account]
+ for dimension in dimensions:
+ dimension_items = cam_map.get(dimension)
+ if dimension_items:
+ for account, monthwise_data in iteritems(dimension_items):
+ row = [dimension, account]
totals = [0, 0, 0]
for year in get_fiscal_years(filters):
last_total = 0
@@ -55,10 +55,6 @@
return columns, data
-def validate_filters(filters):
- if filters.get("budget_against") != "Cost Center" and filters.get("cost_center"):
- frappe.throw(_("Filter based on Cost Center is only applicable if Budget Against is selected as Cost Center"))
-
def get_columns(filters):
columns = [_(filters.get("budget_against")) + ":Link/%s:150"%(filters.get("budget_against")), _("Account") + ":Link/Account:150"]
@@ -98,11 +94,12 @@
else:
return frappe.db.sql_list("""select name from `tab{tab}`""".format(tab=filters.get("budget_against"))) #nosec
-#Get cost center & target details
-def get_cost_center_target_details(filters):
+#Get dimension & target details
+def get_dimension_target_details(filters):
cond = ""
- if filters.get("cost_center"):
- cond += " and b.cost_center=%s" % frappe.db.escape(filters.get("cost_center"))
+ if filters.get("budget_against_filter"):
+ cond += " and b.{budget_against} in (%s)".format(budget_against = \
+ frappe.scrub(filters.get('budget_against'))) % ', '.join(['%s']* len(filters.get('budget_against_filter')))
return frappe.db.sql("""
select b.{budget_against} as budget_against, b.monthly_distribution, ba.account, ba.budget_amount,b.fiscal_year
@@ -110,8 +107,8 @@
where b.name=ba.parent and b.docstatus = 1 and b.fiscal_year between %s and %s
and b.budget_against = %s and b.company=%s {cond} order by b.fiscal_year
""".format(budget_against=filters.get("budget_against").replace(" ", "_").lower(), cond=cond),
- (filters.from_fiscal_year,filters.to_fiscal_year,filters.budget_against, filters.company), as_dict=True)
-
+ tuple([filters.from_fiscal_year,filters.to_fiscal_year,filters.budget_against, filters.company] + filters.get('budget_against_filter')),
+ as_dict=True)
#Get target distribution details of accounts of cost center
@@ -153,14 +150,14 @@
return cc_actual_details
-def get_cost_center_account_month_map(filters):
+def get_dimension_account_month_map(filters):
import datetime
- cost_center_target_details = get_cost_center_target_details(filters)
+ dimension_target_details = get_dimension_target_details(filters)
tdd = get_target_distribution_details(filters)
cam_map = {}
- for ccd in cost_center_target_details:
+ for ccd in dimension_target_details:
actual_details = get_actual_details(ccd.budget_against, filters)
for month_id in range(1, 13):
diff --git a/erpnext/accounts/report/financial_statements.html b/erpnext/accounts/report/financial_statements.html
index 4081723..50947ec 100644
--- a/erpnext/accounts/report/financial_statements.html
+++ b/erpnext/accounts/report/financial_statements.html
@@ -1,5 +1,6 @@
{%
var report_columns = report.get_columns_for_print();
+ report_columns = report_columns.filter(col => !col.hidden);
if (report_columns.length > 8) {
frappe.throw(__("Too many columns. Export the report and print it using a spreadsheet application."));
@@ -15,34 +16,35 @@
height: 37px;
}
</style>
-{% var letterhead= filters.letter_head || (frappe.get_doc(":Company", filters.company) && frappe.get_doc(":Company", filters.company).default_letter_head) %}
-{% if(letterhead) { %}
-<div style="margin-bottom: 7px;" class="text-center">
- {%= frappe.boot.letter_heads[letterhead].header %}
-</div>
-{% } %}
+
<h2 class="text-center">{%= __(report.report_name) %}</h2>
<h3 class="text-center">{%= filters.company %}</h3>
+
{% if 'cost_center' in filters %}
<h3 class="text-center">{%= filters.cost_center %}</h3>
{% endif %}
+
<h3 class="text-center">{%= filters.fiscal_year %}</h3>
-<h5 class="text-center">{%= __("Currency") %} : {%= filters.presentation_currency || erpnext.get_currency(filters.company) %} </h4>
+<h5 class="text-center">
+ {%= __("Currency") %} : {%= filters.presentation_currency || erpnext.get_currency(filters.company) %}
+</h5>
{% if (filters.from_date) { %}
- <h4 class="text-center">{%= frappe.datetime.str_to_user(filters.from_date) %} - {%= frappe.datetime.str_to_user(filters.to_date) %}</h3>
+ <h5 class="text-center">
+ {%= frappe.datetime.str_to_user(filters.from_date) %} - {%= frappe.datetime.str_to_user(filters.to_date) %}
+ </h5>
{% } %}
<hr>
<table class="table table-bordered">
<thead>
<tr>
- <th style="width: {%= 100 - (report_columns.length - 2) * 13 %}%"></th>
- {% for(var i=2, l=report_columns.length; i<l; i++) { %}
+ <th style="width: {%= 100 - (report_columns.length - 1) * 13 %}%"></th>
+ {% for (let i=1, l=report_columns.length; i<l; i++) { %}
<th class="text-right">{%= report_columns[i].label %}</th>
{% } %}
</tr>
</thead>
<tbody>
- {% for(var j=0, k=data.length-1; j<k; j++) { %}
+ {% for(let j=0, k=data.length-1; j<k; j++) { %}
{%
var row = data[j];
var row_class = data[j].parent_account ? "" : "financial-statements-important";
@@ -52,11 +54,11 @@
<td>
<span style="padding-left: {%= cint(data[j].indent) * 2 %}em">{%= row.account_name %}</span>
</td>
- {% for(var i=2, l=report_columns.length; i<l; i++) { %}
+ {% for(let i=1, l=report_columns.length; i<l; i++) { %}
<td class="text-right">
- {% var fieldname = report_columns[i].fieldname; %}
+ {% const fieldname = report_columns[i].fieldname; %}
{% if (!is_null(row[fieldname])) { %}
- {%= format_currency(row[fieldname], filters.presentation_currency) %}
+ {%= frappe.format(row[fieldname], report_columns[i], {}, row) %}
{% } %}
</td>
{% } %}
@@ -64,4 +66,6 @@
{% } %}
</tbody>
</table>
-<p class="text-right text-muted">Printed On {%= frappe.datetime.str_to_user(frappe.datetime.get_datetime_as_string()) %}</p>
+<p class="text-right text-muted">
+ Printed On {%= frappe.datetime.str_to_user(frappe.datetime.get_datetime_as_string()) %}
+</p>
diff --git a/erpnext/accounts/report/financial_statements.py b/erpnext/accounts/report/financial_statements.py
index 3c8de60..40d5682 100644
--- a/erpnext/accounts/report/financial_statements.py
+++ b/erpnext/accounts/report/financial_statements.py
@@ -264,8 +264,8 @@
def add_total_row(out, root_type, balance_must_be, period_list, company_currency):
total_row = {
- "account_name": "'" + _("Total {0} ({1})").format(_(root_type), _(balance_must_be)) + "'",
- "account": "'" + _("Total {0} ({1})").format(_(root_type), _(balance_must_be)) + "'",
+ "account_name": _("Total {0} ({1})").format(_(root_type), _(balance_must_be)),
+ "account": _("Total {0} ({1})").format(_(root_type), _(balance_must_be)),
"currency": company_currency
}
diff --git a/erpnext/accounts/report/general_ledger/general_ledger.html b/erpnext/accounts/report/general_ledger/general_ledger.html
index 17da3b9..40469ae 100644
--- a/erpnext/accounts/report/general_ledger/general_ledger.html
+++ b/erpnext/accounts/report/general_ledger/general_ledger.html
@@ -33,7 +33,7 @@
</tr>
</thead>
<tbody>
- {% for(var i=0, l=data.length-1; i<l; i++) { %}
+ {% for(var i=0, l=data.length; i<l; i++) { %}
<tr>
{% if(data[i].posting_date) { %}
<td>{%= frappe.datetime.str_to_user(data[i].posting_date) %}</td>
diff --git a/erpnext/accounts/report/sales_register/sales_register.py b/erpnext/accounts/report/sales_register/sales_register.py
index 0e2821a..afdd31d 100644
--- a/erpnext/accounts/report/sales_register/sales_register.py
+++ b/erpnext/accounts/report/sales_register/sales_register.py
@@ -38,32 +38,46 @@
cost_center = list(set(invoice_cc_wh_map.get(inv.name, {}).get("cost_center", [])))
warehouse = list(set(invoice_cc_wh_map.get(inv.name, {}).get("warehouse", [])))
- row = [
- inv.name, inv.posting_date, inv.customer, inv.customer_name
- ]
+ row = {
+ 'invoice': inv.name,
+ 'posting_date': inv.posting_date,
+ 'customer': inv.customer,
+ 'customer_name': inv.customer_name
+ }
if additional_query_columns:
for col in additional_query_columns:
- row.append(inv.get(col))
+ row.update({
+ col: inv.get(col)
+ })
- row +=[
- inv.get("customer_group"),
- inv.get("territory"),
- inv.get("tax_id"),
- inv.debit_to, ", ".join(mode_of_payments.get(inv.name, [])),
- inv.project, inv.owner, inv.remarks,
- ", ".join(sales_order), ", ".join(delivery_note),", ".join(cost_center),
- ", ".join(warehouse), company_currency
- ]
+ row.update({
+ 'customer_group': inv.get("customer_group"),
+ 'territory': inv.get("territory"),
+ 'tax_id': inv.get("tax_id"),
+ 'receivable_account': inv.debit_to,
+ 'mode_of_payment': ", ".join(mode_of_payments.get(inv.name, [])),
+ 'project': inv.project,
+ 'owner': inv.owner,
+ 'remarks': inv.remarks,
+ 'sales_order': ", ".join(sales_order),
+ 'delivery_note': ", ".join(delivery_note),
+ 'cost_center': ", ".join(cost_center),
+ 'warehouse': ", ".join(warehouse),
+ 'currency': company_currency
+ })
+
# map income values
base_net_total = 0
for income_acc in income_accounts:
income_amount = flt(invoice_income_map.get(inv.name, {}).get(income_acc))
base_net_total += income_amount
- row.append(income_amount)
+ row.update({
+ frappe.scrub(income_acc): income_amount
+ })
# net total
- row.append(base_net_total or inv.base_net_total)
+ row.update({'net_total': base_net_total or inv.base_net_total})
# tax account
total_tax = 0
@@ -72,10 +86,18 @@
tax_amount_precision = get_field_precision(frappe.get_meta("Sales Taxes and Charges").get_field("tax_amount"), currency=company_currency) or 2
tax_amount = flt(invoice_tax_map.get(inv.name, {}).get(tax_acc), tax_amount_precision)
total_tax += tax_amount
- row.append(tax_amount)
+ row.update({
+ frappe.scrub(tax_acc): tax_amount
+ })
# total tax, grand total, outstanding amount & rounded total
- row += [total_tax, inv.base_grand_total, inv.base_rounded_total, inv.outstanding_amount]
+
+ row.update({
+ 'tax_total': total_tax,
+ 'grand_total': inv.base_grand_total,
+ 'rounded_total': inv.base_rounded_total,
+ 'outstanding_amount': inv.outstanding_amount
+ })
data.append(row)
@@ -84,19 +106,118 @@
def get_columns(invoice_list, additional_table_columns):
"""return columns based on filters"""
columns = [
- _("Invoice") + ":Link/Sales Invoice:120", _("Posting Date") + ":Date:80",
- _("Customer") + ":Link/Customer:120", _("Customer Name") + "::120"
+ {
+ 'label': _("Invoice"),
+ 'fieldname': 'invoice',
+ 'fieldtype': 'Link',
+ 'options': 'Sales Invoice',
+ 'width': 120
+ },
+ {
+ 'label': _("Posting Date"),
+ 'fieldname': 'posting_date',
+ 'fieldtype': 'Date',
+ 'width': 80
+ },
+ {
+ 'label': _("Customer"),
+ 'fieldname': 'customer',
+ 'fieldtype': 'Link',
+ 'options': 'Customer',
+ 'width': 120
+ },
+ {
+ 'label': _("Customer Name"),
+ 'fieldname': 'customer_name',
+ 'fieldtype': 'Data',
+ 'width': 120
+ },
]
if additional_table_columns:
columns += additional_table_columns
columns +=[
- _("Customer Group") + ":Link/Customer Group:120", _("Territory") + ":Link/Territory:80",
- _("Tax Id") + "::80", _("Receivable Account") + ":Link/Account:120", _("Mode of Payment") + "::120",
- _("Project") +":Link/Project:80", _("Owner") + "::150", _("Remarks") + "::150",
- _("Sales Order") + ":Link/Sales Order:100", _("Delivery Note") + ":Link/Delivery Note:100",
- _("Cost Center") + ":Link/Cost Center:100", _("Warehouse") + ":Link/Warehouse:100",
+ {
+ 'label': _("Custmer Group"),
+ 'fieldname': 'customer_group',
+ 'fieldtype': 'Link',
+ 'options': 'Customer Group',
+ 'width': 120
+ },
+ {
+ 'label': _("Territory"),
+ 'fieldname': 'territory',
+ 'fieldtype': 'Link',
+ 'options': 'Territory',
+ 'width': 80
+ },
+ {
+ 'label': _("Tax Id"),
+ 'fieldname': 'tax_id',
+ 'fieldtype': 'Data',
+ 'width': 120
+ },
+ {
+ 'label': _("Receivable Account"),
+ 'fieldname': 'receivable_account',
+ 'fieldtype': 'Link',
+ 'options': 'Account',
+ 'width': 80
+ },
+ {
+ 'label': _("Mode Of Payment"),
+ 'fieldname': 'mode_of_payment',
+ 'fieldtype': 'Data',
+ 'width': 120
+ },
+ {
+ 'label': _("Project"),
+ 'fieldname': 'project',
+ 'fieldtype': 'Link',
+ 'options': 'project',
+ 'width': 80
+ },
+ {
+ 'label': _("Owner"),
+ 'fieldname': 'owner',
+ 'fieldtype': 'Data',
+ 'width': 150
+ },
+ {
+ 'label': _("Remarks"),
+ 'fieldname': 'remarks',
+ 'fieldtype': 'Data',
+ 'width': 150
+ },
+ {
+ 'label': _("Sales Order"),
+ 'fieldname': 'sales_order',
+ 'fieldtype': 'Link',
+ 'options': 'Sales Order',
+ 'width': 100
+ },
+ {
+ 'label': _("Delivery Note"),
+ 'fieldname': 'delivery_note',
+ 'fieldtype': 'Link',
+ 'options': 'Delivery Note',
+ 'width': 100
+ },
+ {
+ 'label': _("Cost Center"),
+ 'fieldname': 'cost_center',
+ 'fieldtype': 'Link',
+ 'options': 'Cost Center',
+ 'width': 100
+ },
+ {
+ 'label': _("Warehouse"),
+ 'fieldname': 'warehouse',
+ 'fieldtype': 'Link',
+ 'options': 'Warehouse',
+ 'width': 100
+ },
{
"fieldname": "currency",
"label": _("Currency"),
@@ -105,7 +226,10 @@
}
]
- income_accounts = tax_accounts = income_columns = tax_columns = []
+ income_accounts = []
+ tax_accounts = []
+ income_columns = []
+ tax_columns = []
if invoice_list:
income_accounts = frappe.db.sql_list("""select distinct income_account
@@ -119,14 +243,65 @@
and parent in (%s) order by account_head""" %
', '.join(['%s']*len(invoice_list)), tuple([inv.name for inv in invoice_list]))
- income_columns = [(account + ":Currency/currency:120") for account in income_accounts]
+ for account in income_accounts:
+ income_columns.append({
+ "label": account,
+ "fieldname": frappe.scrub(account),
+ "fieldtype": "Currency",
+ "options": 'currency',
+ "width": 120
+ })
+
for account in tax_accounts:
if account not in income_accounts:
- tax_columns.append(account + ":Currency/currency:120")
+ tax_columns.append({
+ "label": account,
+ "fieldname": frappe.scrub(account),
+ "fieldtype": "Currency",
+ "options": 'currency',
+ "width": 120
+ })
- columns = columns + income_columns + [_("Net Total") + ":Currency/currency:120"] + tax_columns + \
- [_("Total Tax") + ":Currency/currency:120", _("Grand Total") + ":Currency/currency:120",
- _("Rounded Total") + ":Currency/currency:120", _("Outstanding Amount") + ":Currency/currency:120"]
+ net_total_column = [{
+ "label": _("Net Total"),
+ "fieldname": "net_total",
+ "fieldtype": "Currency",
+ "options": 'currency',
+ "width": 120
+ }]
+
+ total_columns = [
+ {
+ "label": _("Tax Total"),
+ "fieldname": "tax_total",
+ "fieldtype": "Currency",
+ "options": 'currency',
+ "width": 120
+ },
+ {
+ "label": _("Grand Total"),
+ "fieldname": "grand_total",
+ "fieldtype": "Currency",
+ "options": 'currency',
+ "width": 120
+ },
+ {
+ "label": _("Rounded Total"),
+ "fieldname": "rounded_total",
+ "fieldtype": "Currency",
+ "options": 'currency',
+ "width": 120
+ },
+ {
+ "label": _("Outstanding Amount"),
+ "fieldname": "outstanding_amount",
+ "fieldtype": "Currency",
+ "options": 'currency',
+ "width": 120
+ }
+ ]
+
+ columns = columns + income_columns + net_total_column + tax_columns + total_columns
return columns, income_accounts, tax_accounts
diff --git a/erpnext/accounts/report/trial_balance/trial_balance.py b/erpnext/accounts/report/trial_balance/trial_balance.py
index 10e977a..faeee0f 100644
--- a/erpnext/accounts/report/trial_balance/trial_balance.py
+++ b/erpnext/accounts/report/trial_balance/trial_balance.py
@@ -76,8 +76,7 @@
accumulate_values_into_parents(accounts, accounts_by_name)
data = prepare_data(accounts, filters, total_row, parent_children_map, company_currency)
- data = filter_out_zero_value_rows(data, parent_children_map,
- show_zero_values=filters.get("show_zero_values"))
+ data = filter_out_zero_value_rows(data, parent_children_map, show_zero_values=filters.get("show_zero_values"))
return data
@@ -187,33 +186,11 @@
d["closing_debit"] = d["opening_debit"] + d["debit"]
d["closing_credit"] = d["opening_credit"] + d["credit"]
- total_row["debit"] += d["debit"]
- total_row["credit"] += d["credit"]
- if d["root_type"] == "Asset" or d["root_type"] == "Equity" or d["root_type"] == "Expense":
- d["opening_debit"] -= d["opening_credit"]
- d["closing_debit"] -= d["closing_credit"]
+ prepare_opening_closing(d)
- # For opening
- check_opening_closing_has_negative_value(d, "opening_debit", "opening_credit")
-
- # For closing
- check_opening_closing_has_negative_value(d, "closing_debit", "closing_credit")
-
- if d["root_type"] == "Liability" or d["root_type"] == "Income":
- d["opening_credit"] -= d["opening_debit"]
- d["closing_credit"] -= d["closing_debit"]
-
- # For opening
- check_opening_closing_has_negative_value(d, "opening_credit", "opening_debit")
-
- # For closing
- check_opening_closing_has_negative_value(d, "closing_credit", "closing_debit")
-
- total_row["opening_debit"] += d["opening_debit"]
- total_row["closing_debit"] += d["closing_debit"]
- total_row["opening_credit"] += d["opening_credit"]
- total_row["closing_credit"] += d["closing_credit"]
+ for field in value_fields:
+ total_row[field] += d[field]
return total_row
@@ -227,6 +204,10 @@
data = []
for d in accounts:
+ # Prepare opening closing for group account
+ if parent_children_map.get(d.account):
+ prepare_opening_closing(d)
+
has_value = False
row = {
"account": d.name,
@@ -313,11 +294,16 @@
}
]
-def check_opening_closing_has_negative_value(d, dr_or_cr, switch_to_column):
- # If opening debit has negetive value then move it to opening credit and vice versa.
+def prepare_opening_closing(row):
+ dr_or_cr = "debit" if row["root_type"] in ["Asset", "Equity", "Expense"] else "credit"
+ reverse_dr_or_cr = "credit" if dr_or_cr == "debit" else "debit"
- if d[dr_or_cr] < 0:
- d[switch_to_column] = abs(d[dr_or_cr])
- d[dr_or_cr] = 0.0
- else:
- d[switch_to_column] = 0.0
+ for col_type in ["opening", "closing"]:
+ valid_col = col_type + "_" + dr_or_cr
+ reverse_col = col_type + "_" + reverse_dr_or_cr
+ row[valid_col] -= row[reverse_col]
+ if row[valid_col] < 0:
+ row[reverse_col] = abs(row[valid_col])
+ row[valid_col] = 0.0
+ else:
+ row[reverse_col] = 0.0
\ No newline at end of file
diff --git a/erpnext/accounts/report/trial_balance_for_party/trial_balance_for_party.js b/erpnext/accounts/report/trial_balance_for_party/trial_balance_for_party.js
index 873c65e..0e93035 100644
--- a/erpnext/accounts/report/trial_balance_for_party/trial_balance_for_party.js
+++ b/erpnext/accounts/report/trial_balance_for_party/trial_balance_for_party.js
@@ -66,6 +66,21 @@
}
},
{
+ "fieldname": "account",
+ "label": __("Account"),
+ "fieldtype": "Link",
+ "options": "Account",
+ "get_query": function() {
+ var company = frappe.query_report.get_filter_value('company');
+ return {
+ "doctype": "Account",
+ "filters": {
+ "company": company,
+ }
+ }
+ }
+ },
+ {
"fieldname": "show_zero_values",
"label": __("Show zero values"),
"fieldtype": "Check"
diff --git a/erpnext/accounts/report/trial_balance_for_party/trial_balance_for_party.py b/erpnext/accounts/report/trial_balance_for_party/trial_balance_for_party.py
index bd2c34b..78c7e43 100644
--- a/erpnext/accounts/report/trial_balance_for_party/trial_balance_for_party.py
+++ b/erpnext/accounts/report/trial_balance_for_party/trial_balance_for_party.py
@@ -18,14 +18,17 @@
return columns, data
def get_data(filters, show_party_name):
- party_name_field = "{0}_name".format(frappe.scrub(filters.get('party_type')))
- if filters.get('party_type') == 'Student':
+ if filters.get('party_type') in ('Customer', 'Supplier', 'Employee', 'Member'):
+ party_name_field = "{0}_name".format(frappe.scrub(filters.get('party_type')))
+ elif filters.get('party_type') == 'Student':
party_name_field = 'first_name'
elif filters.get('party_type') == 'Shareholder':
party_name_field = 'title'
+ else:
+ party_name_field = 'name'
party_filters = {"name": filters.get("party")} if filters.get("party") else {}
- parties = frappe.get_all(filters.get("party_type"), fields = ["name", party_name_field],
+ parties = frappe.get_all(filters.get("party_type"), fields = ["name", party_name_field],
filters = party_filters, order_by="name")
company_currency = frappe.get_cached_value('Company', filters.company, "default_currency")
opening_balances = get_opening_balances(filters)
@@ -70,7 +73,7 @@
# totals
for col in total_row:
total_row[col] += row.get(col)
-
+
row.update({
"currency": company_currency
})
@@ -78,7 +81,7 @@
has_value = False
if (opening_debit or opening_credit or debit or credit or closing_debit or closing_credit):
has_value =True
-
+
if cint(filters.show_zero_values) or has_value:
data.append(row)
@@ -93,13 +96,19 @@
return data
def get_opening_balances(filters):
+
+ account_filter = ''
+ if filters.get('account'):
+ account_filter = "and account = %s" % (frappe.db.escape(filters.get('account')))
+
gle = frappe.db.sql("""
- select party, sum(debit) as opening_debit, sum(credit) as opening_credit
+ select party, sum(debit) as opening_debit, sum(credit) as opening_credit
from `tabGL Entry`
- where company=%(company)s
+ where company=%(company)s
and ifnull(party_type, '') = %(party_type)s and ifnull(party, '') != ''
and (posting_date < %(from_date)s or ifnull(is_opening, 'No') = 'Yes')
- group by party""", {
+ {account_filter}
+ group by party""".format(account_filter=account_filter), {
"company": filters.company,
"from_date": filters.from_date,
"party_type": filters.party_type
@@ -113,14 +122,20 @@
return opening
def get_balances_within_period(filters):
+
+ account_filter = ''
+ if filters.get('account'):
+ account_filter = "and account = %s" % (frappe.db.escape(filters.get('account')))
+
gle = frappe.db.sql("""
- select party, sum(debit) as debit, sum(credit) as credit
+ select party, sum(debit) as debit, sum(credit) as credit
from `tabGL Entry`
- where company=%(company)s
+ where company=%(company)s
and ifnull(party_type, '') = %(party_type)s and ifnull(party, '') != ''
- and posting_date >= %(from_date)s and posting_date <= %(to_date)s
+ and posting_date >= %(from_date)s and posting_date <= %(to_date)s
and ifnull(is_opening, 'No') = 'No'
- group by party""", {
+ {account_filter}
+ group by party""".format(account_filter=account_filter), {
"company": filters.company,
"from_date": filters.from_date,
"to_date": filters.to_date,
diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py
index ac69fd3..89c8467 100644
--- a/erpnext/accounts/utils.py
+++ b/erpnext/accounts/utils.py
@@ -13,6 +13,10 @@
# imported to enable erpnext.accounts.utils.get_account_currency
from erpnext.accounts.doctype.account.account import get_account_currency
+from erpnext.stock.utils import get_stock_value_on
+from erpnext.stock import get_warehouse_account_map
+
+
class FiscalYearError(frappe.ValidationError): pass
@frappe.whitelist()
@@ -560,23 +564,23 @@
(dr_or_cr, dr_or_cr, '%s', '%s', '%s', dr_or_cr),
(d.diff, d.voucher_type, d.voucher_no))
-def get_stock_and_account_difference(account_list=None, posting_date=None, company=None):
- from erpnext.stock.utils import get_stock_value_on
- from erpnext.stock import get_warehouse_account_map
-
+def get_stock_and_account_balance(account=None, posting_date=None, company=None):
if not posting_date: posting_date = nowdate()
- difference = {}
warehouse_account = get_warehouse_account_map(company)
- for warehouse, account_data in iteritems(warehouse_account):
- if account_data.get('account') in account_list:
- account_balance = get_balance_on(account_data.get('account'), posting_date, in_account_currency=False)
- stock_value = get_stock_value_on(warehouse, posting_date)
- if abs(flt(stock_value) - flt(account_balance)) > 0.005:
- difference.setdefault(account_data.get('account'), flt(stock_value) - flt(account_balance))
+ account_balance = get_balance_on(account, posting_date, in_account_currency=False, ignore_account_permission=True)
- return difference
+ related_warehouses = [wh for wh, wh_details in warehouse_account.items()
+ if wh_details.account == account and not wh_details.is_group]
+
+ total_stock_value = 0.0
+ for warehouse in related_warehouses:
+ value = get_stock_value_on(warehouse, posting_date)
+ total_stock_value += value
+
+ precision = frappe.get_precision("Journal Entry Account", "debit_in_account_currency")
+ return flt(account_balance, precision), flt(total_stock_value, precision), related_warehouses
def get_currency_precision():
precision = cint(frappe.db.get_default("currency_precision"))
@@ -626,7 +630,7 @@
'select name from `tabPurchase Invoice` where release_date IS NOT NULL and release_date > CURDATE()',
as_dict=1
)
- held_invoices = [d['name'] for d in held_invoices]
+ held_invoices = set([d['name'] for d in held_invoices])
return held_invoices
@@ -635,14 +639,19 @@
outstanding_invoices = []
precision = frappe.get_precision("Sales Invoice", "outstanding_amount") or 2
- if erpnext.get_party_account_type(party_type) == 'Receivable':
+ if account:
+ root_type = frappe.get_cached_value("Account", account, "root_type")
+ party_account_type = "Receivable" if root_type == "Asset" else "Payable"
+ else:
+ party_account_type = erpnext.get_party_account_type(party_type)
+
+ if party_account_type == 'Receivable':
dr_or_cr = "debit_in_account_currency - credit_in_account_currency"
payment_dr_or_cr = "credit_in_account_currency - debit_in_account_currency"
else:
dr_or_cr = "credit_in_account_currency - debit_in_account_currency"
payment_dr_or_cr = "debit_in_account_currency - credit_in_account_currency"
- invoice = 'Sales Invoice' if erpnext.get_party_account_type(party_type) == 'Receivable' else 'Purchase Invoice'
held_invoices = get_held_invoices(party_type, party)
invoice_list = frappe.db.sql("""
@@ -661,7 +670,6 @@
group by voucher_type, voucher_no
order by posting_date, name""".format(
dr_or_cr=dr_or_cr,
- invoice = invoice,
condition=condition or ""
), {
"party_type": party_type,
diff --git a/erpnext/agriculture/doctype/crop_cycle/crop_cycle.py b/erpnext/agriculture/doctype/crop_cycle/crop_cycle.py
index bb9045c..3e51933 100644
--- a/erpnext/agriculture/doctype/crop_cycle/crop_cycle.py
+++ b/erpnext/agriculture/doctype/crop_cycle/crop_cycle.py
@@ -51,27 +51,25 @@
self.create_task(disease_doc.treatment_task, self.name, start_date)
def create_project(self, period, crop_tasks):
- project = frappe.new_doc("Project")
- project.update({
+ project = frappe.get_doc({
+ "doctype": "Project",
"project_name": self.title,
"expected_start_date": self.start_date,
"expected_end_date": add_days(self.start_date, period - 1)
- })
- project.insert()
+ }).insert()
return project.name
def create_task(self, crop_tasks, project_name, start_date):
for crop_task in crop_tasks:
- task = frappe.new_doc("Task")
- task.update({
+ frappe.get_doc({
+ "doctype": "Task",
"subject": crop_task.get("task_name"),
"priority": crop_task.get("priority"),
"project": project_name,
"exp_start_date": add_days(start_date, crop_task.get("start_day") - 1),
"exp_end_date": add_days(start_date, crop_task.get("end_day") - 1)
- })
- task.insert()
+ }).insert()
def reload_linked_analysis(self):
linked_doctypes = ['Soil Texture', 'Soil Analysis', 'Plant Analysis']
diff --git a/erpnext/assets/doctype/asset/asset.js b/erpnext/assets/doctype/asset/asset.js
index c5cad73..f6a7fa2 100644
--- a/erpnext/assets/doctype/asset/asset.js
+++ b/erpnext/assets/doctype/asset/asset.js
@@ -41,6 +41,39 @@
});
},
+ setup: function(frm) {
+ frm.make_methods = {
+ 'Asset Movement': () => {
+ frappe.call({
+ method: "erpnext.assets.doctype.asset.asset.make_asset_movement",
+ freeze: true,
+ args:{
+ "assets": [{ name: cur_frm.doc.name }]
+ },
+ callback: function (r) {
+ if (r.message) {
+ var doc = frappe.model.sync(r.message)[0];
+ frappe.set_route("Form", doc.doctype, doc.name);
+ }
+ }
+ });
+ },
+ }
+
+ frm.set_query("purchase_receipt", (doc) => {
+ return {
+ query: "erpnext.controllers.queries.get_purchase_receipts",
+ filters: { item_code: doc.item_code }
+ }
+ });
+ frm.set_query("purchase_invoice", (doc) => {
+ return {
+ query: "erpnext.controllers.queries.get_purchase_invoices",
+ filters: { item_code: doc.item_code }
+ }
+ });
+ },
+
refresh: function(frm) {
frappe.ui.form.trigger("Asset", "is_existing_asset");
frm.toggle_display("next_depreciation_date", frm.doc.docstatus < 1);
@@ -78,11 +111,6 @@
});
}
- if (frm.doc.status=='Submitted' && !frm.doc.is_existing_asset && !frm.doc.purchase_invoice) {
- frm.add_custom_button(__("Purchase Invoice"), function() {
- frm.trigger("make_purchase_invoice");
- }, __('Create'));
- }
if (frm.doc.maintenance_required && !frm.doc.maintenance_schedule) {
frm.add_custom_button(__("Asset Maintenance"), function() {
frm.trigger("create_asset_maintenance");
@@ -104,11 +132,40 @@
frm.trigger("setup_chart");
}
+ frm.trigger("toggle_reference_doc");
+
if (frm.doc.docstatus == 0) {
frm.toggle_reqd("finance_books", frm.doc.calculate_depreciation);
}
},
+ toggle_reference_doc: function(frm) {
+ if (frm.doc.purchase_receipt && frm.doc.purchase_invoice && frm.doc.docstatus === 1) {
+ frm.set_df_property('purchase_invoice', 'read_only', 1);
+ frm.set_df_property('purchase_receipt', 'read_only', 1);
+ }
+ else if (frm.doc.is_existing_asset) {
+ frm.toggle_reqd('purchase_receipt', 0);
+ frm.toggle_reqd('purchase_invoice', 0);
+ }
+ else if (frm.doc.purchase_receipt) {
+ // if purchase receipt link is set then set PI disabled
+ frm.toggle_reqd('purchase_invoice', 0);
+ frm.set_df_property('purchase_invoice', 'read_only', 1);
+ }
+ else if (frm.doc.purchase_invoice) {
+ // if purchase invoice link is set then set PR disabled
+ frm.toggle_reqd('purchase_receipt', 0);
+ frm.set_df_property('purchase_receipt', 'read_only', 1);
+ }
+ else {
+ frm.toggle_reqd('purchase_receipt', 1);
+ frm.set_df_property('purchase_receipt', 'read_only', 0);
+ frm.toggle_reqd('purchase_invoice', 1);
+ frm.set_df_property('purchase_invoice', 'read_only', 0);
+ }
+ },
+
make_journal_entry: function(frm) {
frappe.call({
method: "erpnext.assets.doctype.asset.asset.make_journal_entry",
@@ -176,21 +233,25 @@
item_code: function(frm) {
if(frm.doc.item_code) {
- frappe.call({
- method: "erpnext.assets.doctype.asset.asset.get_item_details",
- args: {
- item_code: frm.doc.item_code,
- asset_category: frm.doc.asset_category
- },
- callback: function(r, rt) {
- if(r.message) {
- frm.set_value('finance_books', r.message);
- }
- }
- })
+ frm.trigger('set_finance_book');
}
},
+ set_finance_book: function(frm) {
+ frappe.call({
+ method: "erpnext.assets.doctype.asset.asset.get_item_details",
+ args: {
+ item_code: frm.doc.item_code,
+ asset_category: frm.doc.asset_category
+ },
+ callback: function(r, rt) {
+ if(r.message) {
+ frm.set_value('finance_books', r.message);
+ }
+ }
+ })
+ },
+
available_for_use_date: function(frm) {
$.each(frm.doc.finance_books || [], function(i, d) {
if(!d.depreciation_start_date) d.depreciation_start_date = frm.doc.available_for_use_date;
@@ -199,37 +260,23 @@
},
is_existing_asset: function(frm) {
+ frm.trigger("toggle_reference_doc");
// frm.toggle_reqd("next_depreciation_date", (!frm.doc.is_existing_asset && frm.doc.calculate_depreciation));
},
opening_accumulated_depreciation: function(frm) {
- erpnext.asset.set_accululated_depreciation(frm);
+ erpnext.asset.set_accumulated_depreciation(frm);
},
make_schedules_editable: function(frm) {
- var is_editable = frm.doc.finance_books.filter(d => d.depreciation_method == "Manual").length > 0
- ? true : false;
+ if (frm.doc.finance_books) {
+ var is_editable = frm.doc.finance_books.filter(d => d.depreciation_method == "Manual").length > 0
+ ? true : false;
- frm.toggle_enable("schedules", is_editable);
- frm.fields_dict["schedules"].grid.toggle_enable("schedule_date", is_editable);
- frm.fields_dict["schedules"].grid.toggle_enable("depreciation_amount", is_editable);
- },
-
- make_purchase_invoice: function(frm) {
- frappe.call({
- args: {
- "asset": frm.doc.name,
- "item_code": frm.doc.item_code,
- "gross_purchase_amount": frm.doc.gross_purchase_amount,
- "company": frm.doc.company,
- "posting_date": frm.doc.purchase_date
- },
- method: "erpnext.assets.doctype.asset.asset.make_purchase_invoice",
- callback: function(r) {
- var doclist = frappe.model.sync(r.message);
- frappe.set_route("Form", doclist[0].doctype, doclist[0].name);
- }
- })
+ frm.toggle_enable("schedules", is_editable);
+ frm.fields_dict["schedules"].grid.toggle_enable("schedule_date", is_editable);
+ frm.fields_dict["schedules"].grid.toggle_enable("depreciation_amount", is_editable);
+ }
},
make_sales_invoice: function(frm) {
@@ -282,17 +329,6 @@
},
calculate_depreciation: function(frm) {
- frappe.db.get_value("Asset Settings", {'name':"Asset Settings"}, 'schedule_based_on_fiscal_year', (data) => {
- if (data.schedule_based_on_fiscal_year == 1) {
- frm.set_df_property("depreciation_method", "options", "\nStraight Line\nManual");
- frm.toggle_reqd("available_for_use_date", true);
- frm.toggle_display("frequency_of_depreciation", false);
- frappe.db.get_value("Fiscal Year", {'name': frappe.sys_defaults.fiscal_year}, "year_end_date", (data) => {
- frm.set_value("next_depreciation_date", data.year_end_date);
- })
- }
- })
-
frm.toggle_reqd("finance_books", frm.doc.calculate_depreciation);
},
@@ -302,6 +338,65 @@
})
},
+ purchase_receipt: function(frm) {
+ frm.trigger('toggle_reference_doc');
+
+ if (frm.doc.purchase_receipt) {
+ if (frm.doc.item_code) {
+ frappe.db.get_doc('Purchase Receipt', frm.doc.purchase_receipt).then(pr_doc => {
+ frm.set_value('company', pr_doc.company);
+ frm.set_value('purchase_date', pr_doc.posting_date);
+ const item = pr_doc.items.find(item => item.item_code === frm.doc.item_code);
+ if (!item) {
+ frm.set_value('purchase_receipt', '');
+ frappe.msgprint({
+ title: __('Invalid Purchase Receipt'),
+ message: __("The selected Purchase Receipt doesn't contains selected Asset Item."),
+ indicator: 'red'
+ });
+ }
+ frm.set_value('gross_purchase_amount', item.base_net_rate);
+ frm.set_value('location', item.asset_location);
+ });
+ } else {
+ frm.set_value('purchase_receipt', '');
+ frappe.msgprint({
+ title: __('Not Allowed'),
+ message: __("Please select Item Code first")
+ });
+ }
+ }
+ },
+
+ purchase_invoice: function(frm) {
+ frm.trigger('toggle_reference_doc');
+ if (frm.doc.purchase_invoice) {
+ if (frm.doc.item_code) {
+ frappe.db.get_doc('Purchase Invoice', frm.doc.purchase_invoice).then(pi_doc => {
+ frm.set_value('company', pi_doc.company);
+ frm.set_value('purchase_date', pi_doc.posting_date);
+ const item = pi_doc.items.find(item => item.item_code === frm.doc.item_code);
+ if (!item) {
+ frm.set_value('purchase_invoice', '');
+ frappe.msgprint({
+ title: __('Invalid Purchase Invoice'),
+ message: __("The selected Purchase Invoice doesn't contains selected Asset Item."),
+ indicator: 'red'
+ });
+ }
+ frm.set_value('gross_purchase_amount', item.base_net_rate);
+ frm.set_value('location', item.asset_location);
+ });
+ } else {
+ frm.set_value('purchase_invoice', '');
+ frappe.msgprint({
+ title: __('Not Allowed'),
+ message: __("Please select Item Code first")
+ });
+ }
+ }
+ },
+
set_depreciation_rate: function(frm, row) {
if (row.total_number_of_depreciations && row.frequency_of_depreciation
&& row.expected_value_after_useful_life) {
@@ -371,12 +466,12 @@
},
depreciation_amount: function(frm, cdt, cdn) {
- erpnext.asset.set_accululated_depreciation(frm);
+ erpnext.asset.set_accumulated_depreciation(frm);
}
})
-erpnext.asset.set_accululated_depreciation = function(frm) {
+erpnext.asset.set_accumulated_depreciation = function(frm) {
if(frm.doc.depreciation_method != "Manual") return;
var accumulated_depreciation = flt(frm.doc.opening_accumulated_depreciation);
@@ -415,92 +510,19 @@
})
};
-erpnext.asset.transfer_asset = function(frm) {
- var dialog = new frappe.ui.Dialog({
- title: __("Transfer Asset"),
- fields: [
- {
- "label": __("Target Location"),
- "fieldname": "target_location",
- "fieldtype": "Link",
- "options": "Location",
- "get_query": function () {
- return {
- filters: [
- ["Location", "is_group", "=", 0]
- ]
- }
- },
- "reqd": 1
- },
- {
- "label": __("Select Serial No"),
- "fieldname": "serial_nos",
- "fieldtype": "Link",
- "options": "Serial No",
- "get_query": function () {
- return {
- filters: {
- 'asset': frm.doc.name
- }
- }
- },
- "onchange": function() {
- let val = this.get_value();
- if (val) {
- let serial_nos = dialog.get_value("serial_no") || val;
- if (serial_nos) {
- serial_nos = serial_nos.split('\n');
- serial_nos.push(val);
-
- const unique_sn = serial_nos.filter(function(elem, index, self) {
- return index === self.indexOf(elem);
- });
-
- dialog.set_value("serial_no", unique_sn.join('\n'));
- dialog.set_value("serial_nos", "");
- }
- }
- }
- },
- {
- "label": __("Serial No"),
- "fieldname": "serial_no",
- "read_only": 1,
- "fieldtype": "Small Text"
- },
- {
- "label": __("Date"),
- "fieldname": "transfer_date",
- "fieldtype": "Datetime",
- "reqd": 1,
- "default": frappe.datetime.now_datetime()
+erpnext.asset.transfer_asset = function() {
+ frappe.call({
+ method: "erpnext.assets.doctype.asset.asset.make_asset_movement",
+ freeze: true,
+ args:{
+ "assets": [{ name: cur_frm.doc.name }],
+ "purpose": "Transfer"
+ },
+ callback: function (r) {
+ if (r.message) {
+ var doc = frappe.model.sync(r.message)[0];
+ frappe.set_route("Form", doc.doctype, doc.name);
}
- ]
+ }
});
-
- dialog.set_primary_action(__("Transfer"), function() {
- var args = dialog.get_values();
- if(!args) return;
- dialog.hide();
- return frappe.call({
- type: "GET",
- method: "erpnext.assets.doctype.asset.asset.transfer_asset",
- args: {
- args: {
- "asset": frm.doc.name,
- "transaction_date": args.transfer_date,
- "source_location": frm.doc.location,
- "target_location": args.target_location,
- "serial_no": args.serial_no,
- "company": frm.doc.company
- }
- },
- freeze: true,
- callback: function(r) {
- cur_frm.reload_doc();
- }
- })
- });
- dialog.show();
};
diff --git a/erpnext/assets/doctype/asset/asset.json b/erpnext/assets/doctype/asset/asset.json
index c60ec5e..97165a3 100644
--- a/erpnext/assets/doctype/asset/asset.json
+++ b/erpnext/assets/doctype/asset/asset.json
@@ -1,497 +1,505 @@
{
- "allow_import": 1,
- "allow_rename": 1,
- "autoname": "naming_series:",
- "creation": "2016-03-01 17:01:27.920130",
- "doctype": "DocType",
- "document_type": "Document",
- "field_order": [
- "naming_series",
- "asset_name",
- "item_code",
- "item_name",
- "asset_category",
- "asset_owner",
- "asset_owner_company",
- "supplier",
- "customer",
- "image",
- "column_break_3",
- "company",
- "location",
- "custodian",
- "department",
- "purchase_date",
- "disposal_date",
- "journal_entry_for_scrap",
- "accounting_dimensions_section",
- "cost_center",
- "dimension_col_break",
- "section_break_5",
- "gross_purchase_amount",
- "available_for_use_date",
- "column_break_18",
- "calculate_depreciation",
- "is_existing_asset",
- "opening_accumulated_depreciation",
- "number_of_depreciations_booked",
- "section_break_23",
- "finance_books",
- "section_break_33",
- "depreciation_method",
- "value_after_depreciation",
- "total_number_of_depreciations",
- "column_break_24",
- "frequency_of_depreciation",
- "next_depreciation_date",
- "section_break_14",
- "schedules",
- "insurance_details",
- "policy_number",
- "insurer",
- "insured_value",
- "column_break_48",
- "insurance_start_date",
- "insurance_end_date",
- "comprehensive_insurance",
- "section_break_31",
- "maintenance_required",
- "other_details",
- "status",
- "booked_fixed_asset",
- "column_break_51",
- "purchase_receipt",
- "purchase_receipt_amount",
- "purchase_invoice",
- "default_finance_book",
- "amended_from"
- ],
- "fields": [
- {
- "fieldname": "naming_series",
- "fieldtype": "Select",
- "label": "Naming Series",
- "options": "ACC-ASS-.YYYY.-"
- },
- {
- "fieldname": "asset_name",
- "fieldtype": "Data",
- "in_list_view": 1,
- "label": "Asset Name",
- "reqd": 1
- },
- {
- "fieldname": "item_code",
- "fieldtype": "Link",
- "in_standard_filter": 1,
- "label": "Item Code",
- "options": "Item",
- "reqd": 1
- },
- {
- "fetch_from": "item_code.item_name",
- "fieldname": "item_name",
- "fieldtype": "Read Only",
- "label": "Item Name"
- },
- {
- "fetch_from": "item_code.asset_category",
- "fieldname": "asset_category",
- "fieldtype": "Link",
- "in_global_search": 1,
- "in_list_view": 1,
- "in_standard_filter": 1,
- "label": "Asset Category",
- "options": "Asset Category",
- "read_only": 1
- },
- {
- "fieldname": "asset_owner",
- "fieldtype": "Select",
- "label": "Asset Owner",
- "options": "\nCompany\nSupplier\nCustomer"
- },
- {
- "depends_on": "eval:doc.asset_owner == \"Company\"",
- "fieldname": "asset_owner_company",
- "fieldtype": "Link",
- "label": "Asset Owner Company",
- "options": "Company"
- },
- {
- "depends_on": "eval:doc.asset_owner == \"Supplier\"",
- "fieldname": "supplier",
- "fieldtype": "Link",
- "label": "Supplier",
- "options": "Supplier"
- },
- {
- "depends_on": "eval:doc.asset_owner == \"Customer\"",
- "fieldname": "customer",
- "fieldtype": "Link",
- "label": "Customer",
- "options": "Customer"
- },
- {
- "allow_on_submit": 1,
- "fieldname": "image",
- "fieldtype": "Attach Image",
- "hidden": 1,
- "label": "Image",
- "no_copy": 1,
- "print_hide": 1
- },
- {
- "fieldname": "column_break_3",
- "fieldtype": "Column Break"
- },
- {
- "fieldname": "company",
- "fieldtype": "Link",
- "label": "Company",
- "options": "Company",
- "remember_last_selected_value": 1,
- "reqd": 1
- },
- {
- "fieldname": "location",
- "fieldtype": "Link",
- "in_list_view": 1,
- "label": "Location",
- "options": "Location",
- "reqd": 1
- },
- {
- "fieldname": "custodian",
- "fieldtype": "Link",
- "ignore_user_permissions": 1,
- "label": "Custodian",
- "options": "Employee"
- },
- {
- "fieldname": "cost_center",
- "fieldtype": "Link",
- "label": "Cost Center",
- "options": "Cost Center"
- },
- {
- "fieldname": "department",
- "fieldtype": "Link",
- "label": "Department",
- "options": "Department"
- },
- {
- "fieldname": "purchase_date",
- "fieldtype": "Date",
- "label": "Purchase Date",
- "reqd": 1
- },
- {
- "fieldname": "disposal_date",
- "fieldtype": "Date",
- "label": "Disposal Date",
- "read_only": 1
- },
- {
- "fieldname": "journal_entry_for_scrap",
- "fieldtype": "Link",
- "label": "Journal Entry for Scrap",
- "no_copy": 1,
- "options": "Journal Entry",
- "print_hide": 1,
- "read_only": 1
- },
- {
- "fieldname": "section_break_5",
- "fieldtype": "Section Break"
- },
- {
- "fieldname": "gross_purchase_amount",
- "fieldtype": "Currency",
- "label": "Gross Purchase Amount",
- "options": "Company:company:default_currency",
- "reqd": 1
- },
- {
- "fieldname": "available_for_use_date",
- "fieldtype": "Date",
- "label": "Available-for-use Date"
- },
- {
- "fieldname": "column_break_18",
- "fieldtype": "Column Break"
- },
- {
- "default": "0",
- "fieldname": "calculate_depreciation",
- "fieldtype": "Check",
- "label": "Calculate Depreciation"
- },
- {
- "default": "0",
- "fieldname": "is_existing_asset",
- "fieldtype": "Check",
- "label": "Is Existing Asset"
- },
- {
- "depends_on": "is_existing_asset",
- "fieldname": "opening_accumulated_depreciation",
- "fieldtype": "Currency",
- "label": "Opening Accumulated Depreciation",
- "no_copy": 1,
- "options": "Company:company:default_currency"
- },
- {
- "depends_on": "eval:(doc.is_existing_asset && doc.opening_accumulated_depreciation)",
- "fieldname": "number_of_depreciations_booked",
- "fieldtype": "Int",
- "label": "Number of Depreciations Booked",
- "no_copy": 1
- },
- {
- "depends_on": "calculate_depreciation",
- "fieldname": "section_break_23",
- "fieldtype": "Section Break",
- "label": "Depreciation"
- },
- {
- "fieldname": "finance_books",
- "fieldtype": "Table",
- "label": "Finance Books",
- "options": "Asset Finance Book"
- },
- {
- "fieldname": "section_break_33",
- "fieldtype": "Section Break",
- "hidden": 1
- },
- {
- "fieldname": "depreciation_method",
- "fieldtype": "Select",
- "label": "Depreciation Method",
- "options": "\nStraight Line\nDouble Declining Balance\nManual"
- },
- {
- "fieldname": "value_after_depreciation",
- "fieldtype": "Currency",
- "hidden": 1,
- "label": "Value After Depreciation",
- "options": "Company:company:default_currency",
- "read_only": 1
- },
- {
- "fieldname": "total_number_of_depreciations",
- "fieldtype": "Int",
- "label": "Total Number of Depreciations"
- },
- {
- "fieldname": "column_break_24",
- "fieldtype": "Column Break"
- },
- {
- "fieldname": "frequency_of_depreciation",
- "fieldtype": "Int",
- "label": "Frequency of Depreciation (Months)"
- },
- {
- "fieldname": "next_depreciation_date",
- "fieldtype": "Date",
- "label": "Next Depreciation Date",
- "no_copy": 1
- },
- {
- "depends_on": "calculate_depreciation",
- "fieldname": "section_break_14",
- "fieldtype": "Section Break",
- "label": "Depreciation Schedule"
- },
- {
- "fieldname": "schedules",
- "fieldtype": "Table",
- "label": "Depreciation Schedules",
- "no_copy": 1,
- "options": "Depreciation Schedule"
- },
- {
- "collapsible": 1,
- "fieldname": "insurance_details",
- "fieldtype": "Section Break",
- "label": "Insurance details"
- },
- {
- "fieldname": "policy_number",
- "fieldtype": "Data",
- "label": "Policy number"
- },
- {
- "fieldname": "insurer",
- "fieldtype": "Data",
- "label": "Insurer"
- },
- {
- "fieldname": "insured_value",
- "fieldtype": "Data",
- "label": "Insured value"
- },
- {
- "fieldname": "column_break_48",
- "fieldtype": "Column Break"
- },
- {
- "fieldname": "insurance_start_date",
- "fieldtype": "Date",
- "label": "Insurance Start Date"
- },
- {
- "fieldname": "insurance_end_date",
- "fieldtype": "Date",
- "label": "Insurance End Date"
- },
- {
- "fieldname": "comprehensive_insurance",
- "fieldtype": "Data",
- "label": "Comprehensive Insurance"
- },
- {
- "fieldname": "section_break_31",
- "fieldtype": "Section Break",
- "label": "Maintenance"
- },
- {
- "allow_on_submit": 1,
- "default": "0",
- "description": "Check if Asset requires Preventive Maintenance or Calibration",
- "fieldname": "maintenance_required",
- "fieldtype": "Check",
- "label": "Maintenance Required"
- },
- {
- "collapsible": 1,
- "fieldname": "other_details",
- "fieldtype": "Section Break",
- "label": "Other Details"
- },
- {
- "allow_on_submit": 1,
- "default": "Draft",
- "fieldname": "status",
- "fieldtype": "Select",
- "in_list_view": 1,
- "in_standard_filter": 1,
- "label": "Status",
- "no_copy": 1,
- "options": "Draft\nSubmitted\nPartially Depreciated\nFully Depreciated\nSold\nScrapped\nIn Maintenance\nOut of Order\nIssue\nReceipt",
- "read_only": 1
- },
- {
- "default": "0",
- "fieldname": "booked_fixed_asset",
- "fieldtype": "Check",
- "label": "Booked Fixed Asset",
- "no_copy": 1,
- "read_only": 1
- },
- {
- "fieldname": "column_break_51",
- "fieldtype": "Column Break"
- },
- {
- "fieldname": "purchase_receipt",
- "fieldtype": "Link",
- "label": "Purchase Receipt",
- "no_copy": 1,
- "options": "Purchase Receipt",
- "print_hide": 1,
- "read_only": 1
- },
- {
- "fieldname": "purchase_receipt_amount",
- "fieldtype": "Currency",
- "hidden": 1,
- "label": "Purchase Receipt Amount",
- "no_copy": 1,
- "print_hide": 1,
- "read_only": 1
- },
- {
- "fieldname": "purchase_invoice",
- "fieldtype": "Link",
- "label": "Purchase Invoice",
- "no_copy": 1,
- "options": "Purchase Invoice",
- "read_only": 1
- },
- {
- "fetch_from": "company.default_finance_book",
- "fieldname": "default_finance_book",
- "fieldtype": "Link",
- "hidden": 1,
- "label": "Default Finance Book",
- "options": "Finance Book",
- "read_only": 1
- },
- {
- "fieldname": "amended_from",
- "fieldtype": "Link",
- "label": "Amended From",
- "no_copy": 1,
- "options": "Asset",
- "print_hide": 1,
- "read_only": 1
- },
- {
- "collapsible": 1,
- "fieldname": "accounting_dimensions_section",
- "fieldtype": "Section Break",
- "label": "Accounting Dimensions"
- },
- {
- "fieldname": "dimension_col_break",
- "fieldtype": "Column Break"
- }
- ],
- "idx": 72,
- "image_field": "image",
- "is_submittable": 1,
- "modified": "2019-05-25 22:26:19.786201",
- "modified_by": "Administrator",
- "module": "Assets",
- "name": "Asset",
- "owner": "Administrator",
- "permissions": [
- {
- "amend": 1,
- "cancel": 1,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "import": 1,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Accounts User",
- "share": 1,
- "submit": 1,
- "write": 1
- },
- {
- "cancel": 1,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Quality Manager",
- "share": 1,
- "submit": 1,
- "write": 1
- }
- ],
- "show_name_in_global_search": 1,
- "sort_field": "modified",
- "sort_order": "DESC",
- "title_field": "asset_name"
- }
\ No newline at end of file
+ "allow_import": 1,
+ "allow_rename": 1,
+ "autoname": "naming_series:",
+ "creation": "2016-03-01 17:01:27.920130",
+ "doctype": "DocType",
+ "document_type": "Document",
+ "engine": "InnoDB",
+ "field_order": [
+ "naming_series",
+ "asset_name",
+ "item_code",
+ "item_name",
+ "asset_category",
+ "asset_owner",
+ "asset_owner_company",
+ "supplier",
+ "customer",
+ "image",
+ "purchase_invoice",
+ "column_break_3",
+ "company",
+ "location",
+ "custodian",
+ "department",
+ "purchase_date",
+ "disposal_date",
+ "journal_entry_for_scrap",
+ "purchase_receipt",
+ "accounting_dimensions_section",
+ "cost_center",
+ "dimension_col_break",
+ "section_break_5",
+ "gross_purchase_amount",
+ "available_for_use_date",
+ "column_break_18",
+ "calculate_depreciation",
+ "allow_monthly_depreciation",
+ "is_existing_asset",
+ "opening_accumulated_depreciation",
+ "number_of_depreciations_booked",
+ "section_break_23",
+ "finance_books",
+ "section_break_33",
+ "depreciation_method",
+ "value_after_depreciation",
+ "total_number_of_depreciations",
+ "column_break_24",
+ "frequency_of_depreciation",
+ "next_depreciation_date",
+ "section_break_14",
+ "schedules",
+ "insurance_details",
+ "policy_number",
+ "insurer",
+ "insured_value",
+ "column_break_48",
+ "insurance_start_date",
+ "insurance_end_date",
+ "comprehensive_insurance",
+ "section_break_31",
+ "maintenance_required",
+ "other_details",
+ "status",
+ "booked_fixed_asset",
+ "column_break_51",
+
+ "purchase_receipt_amount",
+ "default_finance_book",
+ "amended_from"
+ ],
+ "fields": [
+ {
+ "fieldname": "naming_series",
+ "fieldtype": "Select",
+ "label": "Naming Series",
+ "options": "ACC-ASS-.YYYY.-"
+ },
+ {
+ "fieldname": "asset_name",
+ "fieldtype": "Data",
+ "in_list_view": 1,
+ "label": "Asset Name",
+ "reqd": 1
+ },
+ {
+ "fieldname": "item_code",
+ "fieldtype": "Link",
+ "in_standard_filter": 1,
+ "label": "Item Code",
+ "options": "Item",
+ "reqd": 1
+ },
+ {
+ "fetch_from": "item_code.item_name",
+ "fieldname": "item_name",
+ "fieldtype": "Read Only",
+ "label": "Item Name"
+ },
+ {
+ "fetch_from": "item_code.asset_category",
+ "fieldname": "asset_category",
+ "fieldtype": "Link",
+ "in_global_search": 1,
+ "in_list_view": 1,
+ "in_standard_filter": 1,
+ "label": "Asset Category",
+ "options": "Asset Category",
+ "read_only": 1
+ },
+ {
+ "fieldname": "asset_owner",
+ "fieldtype": "Select",
+ "label": "Asset Owner",
+ "options": "\nCompany\nSupplier\nCustomer"
+ },
+ {
+ "depends_on": "eval:doc.asset_owner == \"Company\"",
+ "fieldname": "asset_owner_company",
+ "fieldtype": "Link",
+ "label": "Asset Owner Company",
+ "options": "Company"
+ },
+ {
+ "depends_on": "eval:doc.asset_owner == \"Supplier\"",
+ "fieldname": "supplier",
+ "fieldtype": "Link",
+ "label": "Supplier",
+ "options": "Supplier"
+ },
+ {
+ "depends_on": "eval:doc.asset_owner == \"Customer\"",
+ "fieldname": "customer",
+ "fieldtype": "Link",
+ "label": "Customer",
+ "options": "Customer"
+ },
+ {
+ "allow_on_submit": 1,
+ "fieldname": "image",
+ "fieldtype": "Attach Image",
+ "hidden": 1,
+ "label": "Image",
+ "no_copy": 1,
+ "print_hide": 1
+ },
+ {
+ "fieldname": "column_break_3",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "label": "Company",
+ "options": "Company",
+ "remember_last_selected_value": 1,
+ "reqd": 1
+ },
+ {
+ "fieldname": "location",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Location",
+ "options": "Location",
+ "reqd": 1
+ },
+ {
+ "fieldname": "custodian",
+ "fieldtype": "Link",
+ "ignore_user_permissions": 1,
+ "label": "Custodian",
+ "options": "Employee"
+ },
+ {
+ "fieldname": "cost_center",
+ "fieldtype": "Link",
+ "label": "Cost Center",
+ "options": "Cost Center"
+ },
+ {
+ "fieldname": "department",
+ "fieldtype": "Link",
+ "label": "Department",
+ "options": "Department"
+ },
+ {
+ "fieldname": "purchase_date",
+ "fieldtype": "Date",
+ "label": "Purchase Date",
+ "reqd": 1
+ },
+ {
+ "fieldname": "disposal_date",
+ "fieldtype": "Date",
+ "label": "Disposal Date",
+ "read_only": 1
+ },
+ {
+ "fieldname": "journal_entry_for_scrap",
+ "fieldtype": "Link",
+ "label": "Journal Entry for Scrap",
+ "no_copy": 1,
+ "options": "Journal Entry",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "fieldname": "section_break_5",
+ "fieldtype": "Section Break"
+ },
+ {
+ "fieldname": "gross_purchase_amount",
+ "fieldtype": "Currency",
+ "label": "Gross Purchase Amount",
+ "options": "Company:company:default_currency",
+ "reqd": 1
+ },
+ {
+ "fieldname": "available_for_use_date",
+ "fieldtype": "Date",
+ "label": "Available-for-use Date"
+ },
+ {
+ "fieldname": "column_break_18",
+ "fieldtype": "Column Break"
+ },
+ {
+ "default": "0",
+ "fieldname": "calculate_depreciation",
+ "fieldtype": "Check",
+ "label": "Calculate Depreciation"
+ },
+ {
+ "default": "0",
+ "fieldname": "is_existing_asset",
+ "fieldtype": "Check",
+ "label": "Is Existing Asset"
+ },
+ {
+ "depends_on": "is_existing_asset",
+ "fieldname": "opening_accumulated_depreciation",
+ "fieldtype": "Currency",
+ "label": "Opening Accumulated Depreciation",
+ "no_copy": 1,
+ "options": "Company:company:default_currency"
+ },
+ {
+ "depends_on": "eval:(doc.is_existing_asset && doc.opening_accumulated_depreciation)",
+ "fieldname": "number_of_depreciations_booked",
+ "fieldtype": "Int",
+ "label": "Number of Depreciations Booked",
+ "no_copy": 1
+ },
+ {
+ "depends_on": "calculate_depreciation",
+ "fieldname": "section_break_23",
+ "fieldtype": "Section Break",
+ "label": "Depreciation"
+ },
+ {
+ "fieldname": "finance_books",
+ "fieldtype": "Table",
+ "label": "Finance Books",
+ "options": "Asset Finance Book"
+ },
+ {
+ "fieldname": "section_break_33",
+ "fieldtype": "Section Break",
+ "hidden": 1
+ },
+ {
+ "fieldname": "depreciation_method",
+ "fieldtype": "Select",
+ "label": "Depreciation Method",
+ "options": "\nStraight Line\nDouble Declining Balance\nManual"
+ },
+ {
+ "fieldname": "value_after_depreciation",
+ "fieldtype": "Currency",
+ "hidden": 1,
+ "label": "Value After Depreciation",
+ "options": "Company:company:default_currency",
+ "read_only": 1
+ },
+ {
+ "fieldname": "total_number_of_depreciations",
+ "fieldtype": "Int",
+ "label": "Total Number of Depreciations"
+ },
+ {
+ "fieldname": "column_break_24",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "frequency_of_depreciation",
+ "fieldtype": "Int",
+ "label": "Frequency of Depreciation (Months)"
+ },
+ {
+ "fieldname": "next_depreciation_date",
+ "fieldtype": "Date",
+ "label": "Next Depreciation Date",
+ "no_copy": 1
+ },
+ {
+ "depends_on": "calculate_depreciation",
+ "fieldname": "section_break_14",
+ "fieldtype": "Section Break",
+ "label": "Depreciation Schedule"
+ },
+ {
+ "fieldname": "schedules",
+ "fieldtype": "Table",
+ "label": "Depreciation Schedules",
+ "no_copy": 1,
+ "options": "Depreciation Schedule"
+ },
+ {
+ "collapsible": 1,
+ "fieldname": "insurance_details",
+ "fieldtype": "Section Break",
+ "label": "Insurance details"
+ },
+ {
+ "fieldname": "policy_number",
+ "fieldtype": "Data",
+ "label": "Policy number"
+ },
+ {
+ "fieldname": "insurer",
+ "fieldtype": "Data",
+ "label": "Insurer"
+ },
+ {
+ "fieldname": "insured_value",
+ "fieldtype": "Data",
+ "label": "Insured value"
+ },
+ {
+ "fieldname": "column_break_48",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "insurance_start_date",
+ "fieldtype": "Date",
+ "label": "Insurance Start Date"
+ },
+ {
+ "fieldname": "insurance_end_date",
+ "fieldtype": "Date",
+ "label": "Insurance End Date"
+ },
+ {
+ "fieldname": "comprehensive_insurance",
+ "fieldtype": "Data",
+ "label": "Comprehensive Insurance"
+ },
+ {
+ "fieldname": "section_break_31",
+ "fieldtype": "Section Break",
+ "label": "Maintenance"
+ },
+ {
+ "allow_on_submit": 1,
+ "default": "0",
+ "description": "Check if Asset requires Preventive Maintenance or Calibration",
+ "fieldname": "maintenance_required",
+ "fieldtype": "Check",
+ "label": "Maintenance Required"
+ },
+ {
+ "collapsible": 1,
+ "fieldname": "other_details",
+ "fieldtype": "Section Break",
+ "label": "Other Details"
+ },
+ {
+ "allow_on_submit": 1,
+ "default": "Draft",
+ "fieldname": "status",
+ "fieldtype": "Select",
+ "in_list_view": 1,
+ "in_standard_filter": 1,
+ "label": "Status",
+ "no_copy": 1,
+ "options": "Draft\nSubmitted\nPartially Depreciated\nFully Depreciated\nSold\nScrapped\nIn Maintenance\nOut of Order\nIssue\nReceipt",
+ "read_only": 1
+ },
+ {
+ "default": "0",
+ "fieldname": "booked_fixed_asset",
+ "fieldtype": "Check",
+ "label": "Booked Fixed Asset",
+ "no_copy": 1,
+ "read_only": 1
+ },
+ {
+ "fieldname": "column_break_51",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "purchase_receipt",
+ "fieldtype": "Link",
+ "label": "Purchase Receipt",
+ "no_copy": 1,
+ "options": "Purchase Receipt",
+ "print_hide": 1
+ },
+ {
+ "fieldname": "purchase_receipt_amount",
+ "fieldtype": "Currency",
+ "hidden": 1,
+ "label": "Purchase Receipt Amount",
+ "no_copy": 1,
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "fieldname": "purchase_invoice",
+ "fieldtype": "Link",
+ "label": "Purchase Invoice",
+ "no_copy": 1,
+ "options": "Purchase Invoice"
+ },
+ {
+ "fetch_from": "company.default_finance_book",
+ "fieldname": "default_finance_book",
+ "fieldtype": "Link",
+ "hidden": 1,
+ "label": "Default Finance Book",
+ "options": "Finance Book",
+ "read_only": 1
+ },
+ {
+ "fieldname": "amended_from",
+ "fieldtype": "Link",
+ "label": "Amended From",
+ "no_copy": 1,
+ "options": "Asset",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "collapsible": 1,
+ "fieldname": "accounting_dimensions_section",
+ "fieldtype": "Section Break",
+ "label": "Accounting Dimensions"
+ },
+ {
+ "fieldname": "dimension_col_break",
+ "fieldtype": "Column Break"
+ },
+ {
+ "default": "0",
+ "depends_on": "calculate_depreciation",
+ "fieldname": "allow_monthly_depreciation",
+ "fieldtype": "Check",
+ "label": "Allow Monthly Depreciation"
+ }
+ ],
+ "idx": 72,
+ "image_field": "image",
+ "is_submittable": 1,
+ "modified": "2019-10-22 15:47:36.050828",
+ "modified_by": "Administrator",
+ "module": "Assets",
+ "name": "Asset",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "amend": 1,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "import": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Accounts User",
+ "share": 1,
+ "submit": 1,
+ "write": 1
+ },
+ {
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Quality Manager",
+ "share": 1,
+ "submit": 1,
+ "write": 1
+ }
+ ],
+ "show_name_in_global_search": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "title_field": "asset_name"
+}
\ No newline at end of file
diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py
index 6e2bbc1..3e7f683 100644
--- a/erpnext/assets/doctype/asset/asset.py
+++ b/erpnext/assets/doctype/asset/asset.py
@@ -6,7 +6,7 @@
import frappe, erpnext, math, json
from frappe import _
from six import string_types
-from frappe.utils import flt, add_months, cint, nowdate, getdate, today, date_diff, add_days
+from frappe.utils import flt, add_months, cint, nowdate, getdate, today, date_diff, month_diff, add_days
from frappe.model.document import Document
from erpnext.assets.doctype.asset_category.asset_category import get_asset_category_account
from erpnext.assets.doctype.asset.depreciation \
@@ -18,6 +18,7 @@
class Asset(AccountsController):
def validate(self):
self.validate_asset_values()
+ self.validate_asset_and_reference()
self.validate_item()
self.set_missing_values()
self.prepare_depreciation_data()
@@ -29,10 +30,13 @@
def on_submit(self):
self.validate_in_use_date()
self.set_status()
- self.update_stock_movement()
- if not self.booked_fixed_asset and not is_cwip_accounting_disabled():
+ self.make_asset_movement()
+ if not self.booked_fixed_asset and is_cwip_accounting_enabled(self.asset_category):
self.make_gl_entries()
+ def before_cancel(self):
+ self.cancel_auto_gen_movement()
+
def on_cancel(self):
self.validate_cancellation()
self.delete_depreciation_entries()
@@ -40,6 +44,18 @@
delete_gl_entries(voucher_type='Asset', voucher_no=self.name)
self.db_set('booked_fixed_asset', 0)
+ def validate_asset_and_reference(self):
+ if self.purchase_invoice or self.purchase_receipt:
+ reference_doc = 'Purchase Invoice' if self.purchase_invoice else 'Purchase Receipt'
+ reference_name = self.purchase_invoice or self.purchase_receipt
+ reference_doc = frappe.get_doc(reference_doc, reference_name)
+ if reference_doc.get('company') != self.company:
+ frappe.throw(_("Company of asset {0} and purchase document {1} doesn't matches.").format(self.name, reference_doc.get('name')))
+
+
+ if self.is_existing_asset and self.purchase_invoice:
+ frappe.throw(_("Purchase Invoice cannot be made against an existing asset {0}").format(self.name))
+
def prepare_depreciation_data(self):
if self.calculate_depreciation:
self.value_after_depreciation = 0
@@ -76,10 +92,13 @@
self.set('finance_books', finance_books)
def validate_asset_values(self):
+ if not self.asset_category:
+ self.asset_category = frappe.get_cached_value("Item", self.item_code, "asset_category")
+
if not flt(self.gross_purchase_amount):
frappe.throw(_("Gross Purchase Amount is mandatory"), frappe.MandatoryError)
- if not is_cwip_accounting_disabled():
+ if is_cwip_accounting_enabled(self.asset_category):
if not self.is_existing_asset and not (self.purchase_receipt or self.purchase_invoice):
frappe.throw(_("Please create purchase receipt or purchase invoice for the item {0}").
format(self.item_code))
@@ -105,6 +124,38 @@
if self.available_for_use_date and getdate(self.available_for_use_date) < getdate(self.purchase_date):
frappe.throw(_("Available-for-use Date should be after purchase date"))
+ def cancel_auto_gen_movement(self):
+ movements = frappe.db.sql(
+ """SELECT asm.name, asm.docstatus
+ FROM `tabAsset Movement` asm, `tabAsset Movement Item` asm_item
+ WHERE asm_item.parent=asm.name and asm_item.asset=%s and asm.docstatus=1""", self.name, as_dict=1)
+ if len(movements) > 1:
+ frappe.throw(_('Asset has multiple Asset Movement Entries which has to be \
+ cancelled manually to cancel this asset.'))
+ movement = frappe.get_doc('Asset Movement', movements[0].get('name'))
+ movement.flags.ignore_validate = True
+ movement.cancel()
+
+ def make_asset_movement(self):
+ reference_doctype = 'Purchase Receipt' if self.purchase_receipt else 'Purchase Invoice'
+ reference_docname = self.purchase_receipt or self.purchase_invoice
+ assets = [{
+ 'asset': self.name,
+ 'asset_name': self.asset_name,
+ 'target_location': self.location,
+ 'to_employee': self.custodian
+ }]
+ asset_movement = frappe.get_doc({
+ 'doctype': 'Asset Movement',
+ 'assets': assets,
+ 'purpose': 'Receipt',
+ 'company': self.company,
+ 'transaction_date': getdate(nowdate()),
+ 'reference_doctype': reference_doctype,
+ 'reference_name': reference_docname
+ }).insert()
+ asset_movement.submit()
+
def set_depreciation_rate(self):
for d in self.get("finance_books"):
d.rate_of_depreciation = flt(self.get_depreciation_rate(d, on_validate=True),
@@ -145,19 +196,31 @@
schedule_date = add_months(d.depreciation_start_date,
n * cint(d.frequency_of_depreciation))
+ # schedule date will be a year later from start date
+ # so monthly schedule date is calculated by removing 11 months from it
+ monthly_schedule_date = add_months(schedule_date, - d.frequency_of_depreciation + 1)
+
# For first row
if has_pro_rata and n==0:
- depreciation_amount, days = get_pro_rata_amt(d, depreciation_amount,
+ depreciation_amount, days, months = get_pro_rata_amt(d, depreciation_amount,
self.available_for_use_date, d.depreciation_start_date)
+
+ # For first depr schedule date will be the start date
+ # so monthly schedule date is calculated by removing month difference between use date and start date
+ monthly_schedule_date = add_months(d.depreciation_start_date, - months + 1)
+
# For last row
elif has_pro_rata and n == cint(number_of_pending_depreciations) - 1:
to_date = add_months(self.available_for_use_date,
n * cint(d.frequency_of_depreciation))
- depreciation_amount, days = get_pro_rata_amt(d,
+ depreciation_amount, days, months = get_pro_rata_amt(d,
depreciation_amount, schedule_date, to_date)
+ monthly_schedule_date = add_months(schedule_date, 1)
+
schedule_date = add_days(schedule_date, days)
+ last_schedule_date = schedule_date
if not depreciation_amount: continue
value_after_depreciation -= flt(depreciation_amount,
@@ -171,13 +234,50 @@
skip_row = True
if depreciation_amount > 0:
- self.append("schedules", {
- "schedule_date": schedule_date,
- "depreciation_amount": depreciation_amount,
- "depreciation_method": d.depreciation_method,
- "finance_book": d.finance_book,
- "finance_book_id": d.idx
- })
+ # With monthly depreciation, each depreciation is divided by months remaining until next date
+ if self.allow_monthly_depreciation:
+ # month range is 1 to 12
+ # In pro rata case, for first and last depreciation, month range would be different
+ month_range = months \
+ if (has_pro_rata and n==0) or (has_pro_rata and n == cint(number_of_pending_depreciations) - 1) \
+ else d.frequency_of_depreciation
+
+ for r in range(month_range):
+ if (has_pro_rata and n == 0):
+ # For first entry of monthly depr
+ if r == 0:
+ days_until_first_depr = date_diff(monthly_schedule_date, self.available_for_use_date)
+ per_day_amt = depreciation_amount / days
+ depreciation_amount_for_current_month = per_day_amt * days_until_first_depr
+ depreciation_amount -= depreciation_amount_for_current_month
+ date = monthly_schedule_date
+ amount = depreciation_amount_for_current_month
+ else:
+ date = add_months(monthly_schedule_date, r)
+ amount = depreciation_amount / (month_range - 1)
+ elif (has_pro_rata and n == cint(number_of_pending_depreciations) - 1) and r == cint(month_range) - 1:
+ # For last entry of monthly depr
+ date = last_schedule_date
+ amount = depreciation_amount / month_range
+ else:
+ date = add_months(monthly_schedule_date, r)
+ amount = depreciation_amount / month_range
+
+ self.append("schedules", {
+ "schedule_date": date,
+ "depreciation_amount": amount,
+ "depreciation_method": d.depreciation_method,
+ "finance_book": d.finance_book,
+ "finance_book_id": d.idx
+ })
+ else:
+ self.append("schedules", {
+ "schedule_date": schedule_date,
+ "depreciation_amount": depreciation_amount,
+ "depreciation_method": d.depreciation_method,
+ "finance_book": d.finance_book,
+ "finance_book_id": d.idx
+ })
def check_is_pro_rata(self, row):
has_pro_rata = False
@@ -196,7 +296,9 @@
.format(row.idx))
if not row.depreciation_start_date:
- frappe.throw(_("Row {0}: Depreciation Start Date is required").format(row.idx))
+ if not self.available_for_use_date:
+ frappe.throw(_("Row {0}: Depreciation Start Date is required").format(row.idx))
+ row.depreciation_start_date = self.available_for_use_date
if not self.is_existing_asset:
self.opening_accumulated_depreciation = 0
@@ -345,22 +447,13 @@
if d.finance_book == self.default_finance_book:
return cint(d.idx) - 1
- def update_stock_movement(self):
- asset_movement = frappe.db.get_value('Asset Movement',
- {'asset': self.name, 'reference_name': self.purchase_receipt, 'docstatus': 0}, 'name')
-
- if asset_movement:
- doc = frappe.get_doc('Asset Movement', asset_movement)
- doc.naming_series = 'ACC-ASM-.YYYY.-'
- doc.submit()
-
def make_gl_entries(self):
gl_entries = []
- if ((self.purchase_receipt or (self.purchase_invoice and
- frappe.db.get_value('Purchase Invoice', self.purchase_invoice, 'update_stock')))
+ if ((self.purchase_receipt \
+ or (self.purchase_invoice and frappe.db.get_value('Purchase Invoice', self.purchase_invoice, 'update_stock')))
and self.purchase_receipt_amount and self.available_for_use_date <= nowdate()):
- fixed_aseet_account = get_asset_category_account(self.name, 'fixed_asset_account',
+ fixed_asset_account = get_asset_category_account('fixed_asset_account', asset=self.name,
asset_category = self.asset_category, company = self.company)
cwip_account = get_asset_account("capital_work_in_progress_account",
@@ -368,7 +461,7 @@
gl_entries.append(self.get_gl_dict({
"account": cwip_account,
- "against": fixed_aseet_account,
+ "against": fixed_asset_account,
"remarks": self.get("remarks") or _("Accounting Entry for Asset"),
"posting_date": self.available_for_use_date,
"credit": self.purchase_receipt_amount,
@@ -377,7 +470,7 @@
}))
gl_entries.append(self.get_gl_dict({
- "account": fixed_aseet_account,
+ "account": fixed_asset_account,
"against": cwip_account,
"remarks": self.get("remarks") or _("Accounting Entry for Asset"),
"posting_date": self.available_for_use_date,
@@ -424,40 +517,24 @@
asset.set_status('Out of Order')
def make_post_gl_entry():
- if is_cwip_accounting_disabled():
- return
- assets = frappe.db.sql_list(""" select name from `tabAsset`
- where ifnull(booked_fixed_asset, 0) = 0 and available_for_use_date = %s""", nowdate())
+ asset_categories = frappe.db.get_all('Asset Category', fields = ['name', 'enable_cwip_accounting'])
- for asset in assets:
- doc = frappe.get_doc('Asset', asset)
- doc.make_gl_entries()
+ for asset_category in asset_categories:
+ if cint(asset_category.enable_cwip_accounting):
+ assets = frappe.db.sql_list(""" select name from `tabAsset`
+ where asset_category = %s and ifnull(booked_fixed_asset, 0) = 0
+ and available_for_use_date = %s""", (asset_category.name, nowdate()))
+
+ for asset in assets:
+ doc = frappe.get_doc('Asset', asset)
+ doc.make_gl_entries()
def get_asset_naming_series():
meta = frappe.get_meta('Asset')
return meta.get_field("naming_series").options
@frappe.whitelist()
-def make_purchase_invoice(asset, item_code, gross_purchase_amount, company, posting_date):
- pi = frappe.new_doc("Purchase Invoice")
- pi.company = company
- pi.currency = frappe.get_cached_value('Company', company, "default_currency")
- pi.set_posting_time = 1
- pi.posting_date = posting_date
- pi.append("items", {
- "item_code": item_code,
- "is_fixed_asset": 1,
- "asset": asset,
- "expense_account": get_asset_category_account(asset, 'fixed_asset_account'),
- "qty": 1,
- "price_list_rate": gross_purchase_amount,
- "rate": gross_purchase_amount
- })
- pi.set_missing_values()
- return pi
-
-@frappe.whitelist()
def make_sales_invoice(asset, item_code, company, serial_no=None):
si = frappe.new_doc("Sales Invoice")
si.company = company
@@ -531,15 +608,21 @@
def get_asset_account(account_name, asset=None, asset_category=None, company=None):
account = None
if asset:
- account = get_asset_category_account(asset, account_name,
+ account = get_asset_category_account(account_name, asset=asset,
asset_category = asset_category, company = company)
+
+ if not asset and not account:
+ account = get_asset_category_account(account_name, asset_category = asset_category, company = company)
if not account:
account = frappe.get_cached_value('Company', company, account_name)
if not account:
- frappe.throw(_("Set {0} in asset category {1} or company {2}")
- .format(account_name.replace('_', ' ').title(), asset_category, company))
+ if not asset_category:
+ frappe.throw(_("Set {0} in company {2}").format(account_name.replace('_', ' ').title(), company))
+ else:
+ frappe.throw(_("Set {0} in asset category {1} or company {2}")
+ .format(account_name.replace('_', ' ').title(), asset_category, company))
return account
@@ -574,17 +657,43 @@
return je
-def is_cwip_accounting_disabled():
- return cint(frappe.db.get_single_value("Asset Settings", "disable_cwip_accounting"))
+@frappe.whitelist()
+def make_asset_movement(assets, purpose=None):
+ import json
+ from six import string_types
+
+ if isinstance(assets, string_types):
+ assets = json.loads(assets)
+
+ if len(assets) == 0:
+ frappe.throw(_('Atleast one asset has to be selected.'))
+
+ asset_movement = frappe.new_doc("Asset Movement")
+ asset_movement.quantity = len(assets)
+ for asset in assets:
+ asset = frappe.get_doc('Asset', asset.get('name'))
+ asset_movement.company = asset.get('company')
+ asset_movement.append("assets", {
+ 'asset': asset.get('name'),
+ 'source_location': asset.get('location'),
+ 'from_employee': asset.get('custodian')
+ })
+
+ if asset_movement.get('assets'):
+ return asset_movement.as_dict()
+
+def is_cwip_accounting_enabled(asset_category):
+ return cint(frappe.db.get_value("Asset Category", asset_category, "enable_cwip_accounting"))
def get_pro_rata_amt(row, depreciation_amount, from_date, to_date):
days = date_diff(to_date, from_date)
+ months = month_diff(to_date, from_date)
total_days = get_total_days(to_date, row.frequency_of_depreciation)
- return (depreciation_amount * flt(days)) / flt(total_days), days
+ return (depreciation_amount * flt(days)) / flt(total_days), days, months
def get_total_days(date, frequency):
period_start_date = add_months(date,
cint(frequency) * -1)
- return date_diff(date, period_start_date)
\ No newline at end of file
+ return date_diff(date, period_start_date)
diff --git a/erpnext/assets/doctype/asset/asset_list.js b/erpnext/assets/doctype/asset/asset_list.js
index 3b95a17..02f39e0 100644
--- a/erpnext/assets/doctype/asset/asset_list.js
+++ b/erpnext/assets/doctype/asset/asset_list.js
@@ -30,8 +30,24 @@
} else if (doc.status === "Draft") {
return [__("Draft"), "red", "status,=,Draft"];
-
}
-
+ },
+ onload: function(me) {
+ me.page.add_action_item('Make Asset Movement', function() {
+ const assets = me.get_checked_items();
+ frappe.call({
+ method: "erpnext.assets.doctype.asset.asset.make_asset_movement",
+ freeze: true,
+ args:{
+ "assets": assets
+ },
+ callback: function (r) {
+ if (r.message) {
+ var doc = frappe.model.sync(r.message)[0];
+ frappe.set_route("Form", doc.doctype, doc.name);
+ }
+ }
+ });
+ });
},
}
\ No newline at end of file
diff --git a/erpnext/assets/doctype/asset/test_asset.py b/erpnext/assets/doctype/asset/test_asset.py
index c09b94f..a56440d 100644
--- a/erpnext/assets/doctype/asset/test_asset.py
+++ b/erpnext/assets/doctype/asset/test_asset.py
@@ -7,14 +7,13 @@
import unittest
from frappe.utils import cstr, nowdate, getdate, flt, get_last_day, add_days, add_months
from erpnext.assets.doctype.asset.depreciation import post_depreciation_entries, scrap_asset, restore_asset
-from erpnext.assets.doctype.asset.asset import make_sales_invoice, make_purchase_invoice
+from erpnext.assets.doctype.asset.asset import make_sales_invoice
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt
from erpnext.stock.doctype.purchase_receipt.purchase_receipt import make_purchase_invoice as make_invoice
class TestAsset(unittest.TestCase):
def setUp(self):
set_depreciation_settings_in_company()
- remove_prorated_depreciation_schedule()
create_asset_data()
frappe.db.sql("delete from `tabTax Rule`")
@@ -40,15 +39,15 @@
})
asset.submit()
- pi = make_purchase_invoice(asset.name, asset.item_code, asset.gross_purchase_amount,
- asset.company, asset.purchase_date)
+ pi = make_invoice(pr.name)
pi.supplier = "_Test Supplier"
pi.insert()
pi.submit()
asset.load_from_db()
self.assertEqual(asset.supplier, "_Test Supplier")
self.assertEqual(asset.purchase_date, getdate(purchase_date))
- self.assertEqual(asset.purchase_invoice, pi.name)
+ # Asset won't have reference to PI when purchased through PR
+ self.assertEqual(asset.purchase_receipt, pr.name)
expected_gle = (
("Asset Received But Not Billed - _TC", 100000.0, 0.0),
@@ -61,20 +60,23 @@
self.assertEqual(gle, expected_gle)
pi.cancel()
-
+ asset.cancel()
asset.load_from_db()
- self.assertEqual(asset.supplier, None)
- self.assertEqual(asset.purchase_invoice, None)
+ pr.load_from_db()
+ pr.cancel()
+ self.assertEqual(asset.docstatus, 2)
self.assertFalse(frappe.db.get_value("GL Entry",
{"voucher_type": "Purchase Invoice", "voucher_no": pi.name}))
def test_is_fixed_asset_set(self):
+ asset = create_asset(is_existing_asset = 1)
doc = frappe.new_doc('Purchase Invoice')
doc.supplier = '_Test Supplier'
doc.append('items', {
'item_code': 'Macbook Pro',
- 'qty': 1
+ 'qty': 1,
+ 'asset': asset.name
})
doc.set_missing_values()
@@ -200,7 +202,6 @@
self.assertEqual(schedules, expected_schedules)
def test_schedule_for_prorated_straight_line_method(self):
- set_prorated_depreciation_schedule()
pr = make_purchase_receipt(item_code="Macbook Pro",
qty=1, rate=100000.0, location="Test Location")
@@ -233,8 +234,6 @@
self.assertEqual(schedules, expected_schedules)
- remove_prorated_depreciation_schedule()
-
def test_depreciation(self):
pr = make_purchase_receipt(item_code="Macbook Pro",
qty=1, rate=100000.0, location="Test Location")
@@ -484,9 +483,6 @@
self.assertTrue(asset.finance_books[0].expected_value_after_useful_life >= asset_value_after_full_schedule)
def test_cwip_accounting(self):
- from erpnext.stock.doctype.purchase_receipt.purchase_receipt import (
- make_purchase_invoice as make_purchase_invoice_from_pr)
-
pr = make_purchase_receipt(item_code="Macbook Pro",
qty=1, rate=5000, do_not_submit=True, location="Test Location")
@@ -515,13 +511,13 @@
("CWIP Account - _TC", 5250.0, 0.0)
)
- gle = frappe.db.sql("""select account, debit, credit from `tabGL Entry`
+ pr_gle = frappe.db.sql("""select account, debit, credit from `tabGL Entry`
where voucher_type='Purchase Receipt' and voucher_no = %s
order by account""", pr.name)
- self.assertEqual(gle, expected_gle)
+ self.assertEqual(pr_gle, expected_gle)
- pi = make_purchase_invoice_from_pr(pr.name)
+ pi = make_invoice(pr.name)
pi.submit()
expected_gle = (
@@ -532,11 +528,11 @@
("Expenses Included In Asset Valuation - _TC", 0.0, 250.0),
)
- gle = frappe.db.sql("""select account, debit, credit from `tabGL Entry`
+ pi_gle = frappe.db.sql("""select account, debit, credit from `tabGL Entry`
where voucher_type='Purchase Invoice' and voucher_no = %s
order by account""", pi.name)
- self.assertEqual(gle, expected_gle)
+ self.assertEqual(pi_gle, expected_gle)
asset = frappe.db.get_value('Asset',
{'purchase_receipt': pr.name, 'docstatus': 0}, 'name')
@@ -565,6 +561,7 @@
where voucher_type='Asset' and voucher_no = %s
order by account""", asset_doc.name)
+
self.assertEqual(gle, expected_gle)
def test_expense_head(self):
@@ -575,7 +572,6 @@
self.assertEquals('Asset Received But Not Billed - _TC', doc.items[0].expense_account)
-
def create_asset_data():
if not frappe.db.exists("Asset Category", "Computers"):
create_asset_category()
@@ -596,15 +592,15 @@
asset = frappe.get_doc({
"doctype": "Asset",
- "asset_name": "Macbook Pro 1",
+ "asset_name": args.asset_name or "Macbook Pro 1",
"asset_category": "Computers",
- "item_code": "Macbook Pro",
- "company": "_Test Company",
+ "item_code": args.item_code or "Macbook Pro",
+ "company": args.company or"_Test Company",
"purchase_date": "2015-01-01",
"calculate_depreciation": 0,
"gross_purchase_amount": 100000,
"expected_value_after_useful_life": 10000,
- "warehouse": "_Test Warehouse - _TC",
+ "warehouse": args.warehouse or "_Test Warehouse - _TC",
"available_for_use_date": "2020-06-06",
"location": "Test Location",
"asset_owner": "Company",
@@ -616,6 +612,9 @@
except frappe.DuplicateEntryError:
pass
+ if args.submit:
+ asset.submit()
+
return asset
def create_asset_category():
@@ -623,6 +622,7 @@
asset_category.asset_category_name = "Computers"
asset_category.total_number_of_depreciations = 3
asset_category.frequency_of_depreciation = 3
+ asset_category.enable_cwip_accounting = 1
asset_category.append("accounts", {
"company_name": "_Test Company",
"fixed_asset_account": "_Test Fixed Asset - _TC",
@@ -632,6 +632,8 @@
asset_category.insert()
def create_fixed_asset_item():
+ meta = frappe.get_meta('Asset')
+ naming_series = meta.get_field("naming_series").options.splitlines()[0] or 'ACC-ASS-.YYYY.-'
try:
frappe.get_doc({
"doctype": "Item",
@@ -642,7 +644,9 @@
"item_group": "All Item Groups",
"stock_uom": "Nos",
"is_stock_item": 0,
- "is_fixed_asset": 1
+ "is_fixed_asset": 1,
+ "auto_create_assets": 1,
+ "asset_naming_series": naming_series
}).insert()
except frappe.DuplicateEntryError:
pass
@@ -656,19 +660,4 @@
company.save()
# Enable booking asset depreciation entry automatically
- frappe.db.set_value("Accounts Settings", None, "book_asset_depreciation_entry_automatically", 1)
-
-def remove_prorated_depreciation_schedule():
- asset_settings = frappe.get_doc("Asset Settings", "Asset Settings")
- asset_settings.schedule_based_on_fiscal_year = 0
- asset_settings.save()
-
- frappe.db.commit()
-
-def set_prorated_depreciation_schedule():
- asset_settings = frappe.get_doc("Asset Settings", "Asset Settings")
- asset_settings.schedule_based_on_fiscal_year = 1
- asset_settings.number_of_days_in_fiscal_year = 360
- asset_settings.save()
-
- frappe.db.commit()
+ frappe.db.set_value("Accounts Settings", None, "book_asset_depreciation_entry_automatically", 1)
\ No newline at end of file
diff --git a/erpnext/assets/doctype/asset_category/asset_category.json b/erpnext/assets/doctype/asset_category/asset_category.json
index 882cbe2..7483b41 100644
--- a/erpnext/assets/doctype/asset_category/asset_category.json
+++ b/erpnext/assets/doctype/asset_category/asset_category.json
@@ -1,284 +1,115 @@
{
- "allow_copy": 0,
- "allow_guest_to_view": 0,
- "allow_import": 1,
- "allow_rename": 1,
- "autoname": "field:asset_category_name",
- "beta": 0,
- "creation": "2016-03-01 17:41:39.778765",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "Document",
- "editable_grid": 0,
- "engine": "InnoDB",
+ "allow_import": 1,
+ "allow_rename": 1,
+ "autoname": "field:asset_category_name",
+ "creation": "2016-03-01 17:41:39.778765",
+ "doctype": "DocType",
+ "document_type": "Document",
+ "engine": "InnoDB",
+ "field_order": [
+ "asset_category_name",
+ "column_break_3",
+ "depreciation_options",
+ "enable_cwip_accounting",
+ "finance_book_detail",
+ "finance_books",
+ "section_break_2",
+ "accounts"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "asset_category_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": "Asset Category Name",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "fieldname": "asset_category_name",
+ "fieldtype": "Data",
+ "in_list_view": 1,
+ "label": "Asset Category Name",
+ "reqd": 1,
+ "unique": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_3",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "fieldname": "column_break_3",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "finance_book_detail",
- "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": "Finance Book Detail",
- "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": "finance_book_detail",
+ "fieldtype": "Section Break",
+ "label": "Finance Book Detail"
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "finance_books",
- "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": "Finance Books",
- "length": 0,
- "no_copy": 0,
- "options": "Asset Finance Book",
- "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": "finance_books",
+ "fieldtype": "Table",
+ "label": "Finance Books",
+ "options": "Asset Finance Book"
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "section_break_2",
- "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": "Accounts",
- "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_2",
+ "fieldtype": "Section Break",
+ "label": "Accounts"
+ },
{
- "allow_bulk_edit": 0,
- "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": "Asset Category 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": 1,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
+ "fieldname": "accounts",
+ "fieldtype": "Table",
+ "label": "Accounts",
+ "options": "Asset Category Account",
+ "reqd": 1
+ },
+ {
+ "fieldname": "depreciation_options",
+ "fieldtype": "Section Break",
+ "label": "Depreciation Options"
+ },
+ {
+ "default": "0",
+ "fieldname": "enable_cwip_accounting",
+ "fieldtype": "Check",
+ "label": "Enable Capital Work in Progress Accounting"
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2018-05-12 14:56:04.116425",
- "modified_by": "Administrator",
- "module": "Assets",
- "name": "Asset Category",
- "name_case": "",
- "owner": "Administrator",
+ ],
+ "modified": "2019-10-11 12:19:59.759136",
+ "modified_by": "Administrator",
+ "module": "Assets",
+ "name": "Asset Category",
+ "owner": "Administrator",
"permissions": [
{
- "amend": 0,
- "apply_user_permissions": 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": "Accounts User",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "import": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Accounts User",
+ "share": 1,
"write": 1
- },
+ },
{
- "amend": 0,
- "apply_user_permissions": 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": "Accounts Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "import": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Accounts Manager",
+ "share": 1,
"write": 1
- },
+ },
{
- "amend": 0,
- "apply_user_permissions": 0,
- "cancel": 0,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Quality Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Quality Manager",
+ "share": 1,
"write": 1
}
- ],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 1,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 0,
- "track_seen": 0
+ ],
+ "show_name_in_global_search": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC"
}
\ No newline at end of file
diff --git a/erpnext/assets/doctype/asset_category/asset_category.py b/erpnext/assets/doctype/asset_category/asset_category.py
index bbdc6ec..fc08841 100644
--- a/erpnext/assets/doctype/asset_category/asset_category.py
+++ b/erpnext/assets/doctype/asset_category/asset_category.py
@@ -10,20 +10,27 @@
class AssetCategory(Document):
def validate(self):
+ self.validate_finance_books()
+
+ def validate_finance_books(self):
for d in self.finance_books:
for field in ("Total Number of Depreciations", "Frequency of Depreciation"):
if cint(d.get(frappe.scrub(field)))<1:
frappe.throw(_("Row {0}: {1} must be greater than 0").format(d.idx, field), frappe.MandatoryError)
@frappe.whitelist()
-def get_asset_category_account(asset, fieldname, account=None, asset_category = None, company = None):
- if not asset_category and company:
+def get_asset_category_account(fieldname, item=None, asset=None, account=None, asset_category = None, company = None):
+ if item and frappe.db.get_value("Item", item, "is_fixed_asset"):
+ asset_category = frappe.db.get_value("Item", item, ["asset_category"])
+
+ elif not asset_category or not company:
if account:
if frappe.db.get_value("Account", account, "account_type") != "Fixed Asset":
account=None
if not account:
- asset_category, company = frappe.db.get_value("Asset", asset, ["asset_category", "company"])
+ asset_details = frappe.db.get_value("Asset", asset, ["asset_category", "company"])
+ asset_category, company = asset_details or [None, None]
account = frappe.db.get_value("Asset Category Account",
filters={"parent": asset_category, "company_name": company}, fieldname=fieldname)
diff --git a/erpnext/assets/doctype/asset_maintenance/test_asset_maintenance.py b/erpnext/assets/doctype/asset_maintenance/test_asset_maintenance.py
index 735302a..6c2fd67 100644
--- a/erpnext/assets/doctype/asset_maintenance/test_asset_maintenance.py
+++ b/erpnext/assets/doctype/asset_maintenance/test_asset_maintenance.py
@@ -73,8 +73,10 @@
'doctype': 'Location',
'location_name': 'Test Location'
}).insert()
-
+
if not frappe.db.exists("Item", "Photocopier"):
+ meta = frappe.get_meta('Asset')
+ naming_series = meta.get_field("naming_series").options
frappe.get_doc({
"doctype": "Item",
"item_code": "Photocopier",
@@ -83,7 +85,9 @@
"company": "_Test Company",
"is_fixed_asset": 1,
"is_stock_item": 0,
- "asset_category": "Equipment"
+ "asset_category": "Equipment",
+ "auto_create_assets": 1,
+ "asset_naming_series": naming_series
}).insert()
def create_maintenance_team():
diff --git a/erpnext/assets/doctype/asset_movement/asset_movement.js b/erpnext/assets/doctype/asset_movement/asset_movement.js
index 7ef6461..06d8879 100644
--- a/erpnext/assets/doctype/asset_movement/asset_movement.js
+++ b/erpnext/assets/doctype/asset_movement/asset_movement.js
@@ -2,27 +2,101 @@
// For license information, please see license.txt
frappe.ui.form.on('Asset Movement', {
- select_serial_no: function(frm) {
- if (frm.doc.select_serial_no) {
- let serial_no = frm.doc.serial_no
- ? frm.doc.serial_no + '\n' + frm.doc.select_serial_no : frm.doc.select_serial_no;
- frm.set_value("serial_no", serial_no);
- frm.set_value("quantity", serial_no.split('\n').length);
- }
- },
-
- serial_no: function(frm) {
- const qty = frm.doc.serial_no ? frm.doc.serial_no.split('\n').length : 0;
- frm.set_value("quantity", qty);
- },
-
- setup: function(frm) {
- frm.set_query("select_serial_no", function() {
+ setup: (frm) => {
+ frm.set_query("to_employee", "assets", (doc) => {
return {
filters: {
- "asset": frm.doc.asset
+ company: doc.company
}
};
+ })
+ frm.set_query("from_employee", "assets", (doc) => {
+ return {
+ filters: {
+ company: doc.company
+ }
+ };
+ })
+ frm.set_query("reference_name", (doc) => {
+ return {
+ filters: {
+ company: doc.company,
+ docstatus: 1
+ }
+ };
+ })
+ frm.set_query("reference_doctype", () => {
+ return {
+ filters: {
+ name: ["in", ["Purchase Receipt", "Purchase Invoice"]]
+ }
+ };
+ }),
+ frm.set_query("asset", "assets", () => {
+ return {
+ filters: {
+ status: ["not in", ["Draft"]]
+ }
+ }
+ })
+ },
+
+ onload: (frm) => {
+ frm.trigger('set_required_fields');
+ },
+
+ purpose: (frm) => {
+ frm.trigger('set_required_fields');
+ },
+
+ set_required_fields: (frm, cdt, cdn) => {
+ let fieldnames_to_be_altered;
+ if (frm.doc.purpose === 'Transfer') {
+ fieldnames_to_be_altered = {
+ target_location: { read_only: 0, reqd: 1 },
+ source_location: { read_only: 1, reqd: 1 },
+ from_employee: { read_only: 1, reqd: 0 },
+ to_employee: { read_only: 1, reqd: 0 }
+ };
+ }
+ else if (frm.doc.purpose === 'Receipt') {
+ fieldnames_to_be_altered = {
+ target_location: { read_only: 0, reqd: 1 },
+ source_location: { read_only: 1, reqd: 0 },
+ from_employee: { read_only: 0, reqd: 1 },
+ to_employee: { read_only: 1, reqd: 0 }
+ };
+ }
+ else if (frm.doc.purpose === 'Issue') {
+ fieldnames_to_be_altered = {
+ target_location: { read_only: 1, reqd: 0 },
+ source_location: { read_only: 1, reqd: 1 },
+ from_employee: { read_only: 1, reqd: 0 },
+ to_employee: { read_only: 0, reqd: 1 }
+ };
+ }
+ Object.keys(fieldnames_to_be_altered).forEach(fieldname => {
+ let property_to_be_altered = fieldnames_to_be_altered[fieldname];
+ Object.keys(property_to_be_altered).forEach(property => {
+ let value = property_to_be_altered[property];
+ frm.set_df_property(fieldname, property, value, cdn, 'assets');
+ });
});
+ frm.refresh_field('assets');
}
});
+
+frappe.ui.form.on('Asset Movement Item', {
+ asset: function(frm, cdt, cdn) {
+ // on manual entry of an asset auto sets their source location / employee
+ const asset_name = locals[cdt][cdn].asset;
+ if (asset_name){
+ frappe.db.get_doc('Asset', asset_name).then((asset_doc) => {
+ if(asset_doc.location) frappe.model.set_value(cdt, cdn, 'source_location', asset_doc.location);
+ if(asset_doc.custodian) frappe.model.set_value(cdt, cdn, 'from_employee', asset_doc.custodian);
+ }).catch((err) => {
+ console.log(err); // eslint-disable-line
+ });
+ }
+ }
+});
\ No newline at end of file
diff --git a/erpnext/assets/doctype/asset_movement/asset_movement.json b/erpnext/assets/doctype/asset_movement/asset_movement.json
index 68076e1..3472ab5 100644
--- a/erpnext/assets/doctype/asset_movement/asset_movement.json
+++ b/erpnext/assets/doctype/asset_movement/asset_movement.json
@@ -1,26 +1,19 @@
{
"allow_import": 1,
- "autoname": "naming_series:",
+ "autoname": "format:ACC-ASM-{YYYY}-{#####}",
"creation": "2016-04-25 18:00:23.559973",
"doctype": "DocType",
+ "engine": "InnoDB",
"field_order": [
- "naming_series",
"company",
"purpose",
- "asset",
- "transaction_date",
"column_break_4",
- "quantity",
- "select_serial_no",
- "serial_no",
- "section_break_7",
- "source_location",
- "target_location",
- "column_break_10",
- "from_employee",
- "to_employee",
+ "transaction_date",
+ "section_break_10",
+ "assets",
"reference",
"reference_doctype",
+ "column_break_9",
"reference_name",
"amended_from"
],
@@ -36,7 +29,6 @@
"reqd": 1
},
{
- "default": "Transfer",
"fieldname": "purpose",
"fieldtype": "Select",
"label": "Purpose",
@@ -44,16 +36,6 @@
"reqd": 1
},
{
- "fieldname": "asset",
- "fieldtype": "Link",
- "in_global_search": 1,
- "in_list_view": 1,
- "in_standard_filter": 1,
- "label": "Asset",
- "options": "Asset",
- "reqd": 1
- },
- {
"fieldname": "transaction_date",
"fieldtype": "Datetime",
"in_list_view": 1,
@@ -65,56 +47,7 @@
"fieldtype": "Column Break"
},
{
- "fieldname": "quantity",
- "fieldtype": "Float",
- "label": "Quantity"
- },
- {
- "fieldname": "select_serial_no",
- "fieldtype": "Link",
- "label": "Select Serial No",
- "options": "Serial No"
- },
- {
- "fieldname": "serial_no",
- "fieldtype": "Small Text",
- "label": "Serial No"
- },
- {
- "fieldname": "section_break_7",
- "fieldtype": "Section Break"
- },
- {
- "fieldname": "source_location",
- "fieldtype": "Link",
- "label": "Source Location",
- "options": "Location"
- },
- {
- "fieldname": "target_location",
- "fieldtype": "Link",
- "label": "Target Location",
- "options": "Location"
- },
- {
- "fieldname": "column_break_10",
- "fieldtype": "Column Break"
- },
- {
- "fieldname": "from_employee",
- "fieldtype": "Link",
- "ignore_user_permissions": 1,
- "label": "From Employee",
- "options": "Employee"
- },
- {
- "fieldname": "to_employee",
- "fieldtype": "Link",
- "ignore_user_permissions": 1,
- "label": "To Employee",
- "options": "Employee"
- },
- {
+ "collapsible": 1,
"fieldname": "reference",
"fieldtype": "Section Break",
"label": "Reference"
@@ -122,18 +55,16 @@
{
"fieldname": "reference_doctype",
"fieldtype": "Link",
- "label": "Reference DocType",
+ "label": "Reference Document Type",
"no_copy": 1,
- "options": "DocType",
- "read_only": 1
+ "options": "DocType"
},
{
"fieldname": "reference_name",
"fieldtype": "Dynamic Link",
- "label": "Reference Name",
+ "label": "Reference Document Name",
"no_copy": 1,
- "options": "reference_doctype",
- "read_only": 1
+ "options": "reference_doctype"
},
{
"fieldname": "amended_from",
@@ -145,16 +76,23 @@
"read_only": 1
},
{
- "default": "ACC-ASM-.YYYY.-",
- "fieldname": "naming_series",
- "fieldtype": "Select",
- "label": "Series",
- "options": "ACC-ASM-.YYYY.-",
+ "fieldname": "section_break_10",
+ "fieldtype": "Section Break"
+ },
+ {
+ "fieldname": "assets",
+ "fieldtype": "Table",
+ "label": "Assets",
+ "options": "Asset Movement Item",
"reqd": 1
+ },
+ {
+ "fieldname": "column_break_9",
+ "fieldtype": "Column Break"
}
],
"is_submittable": 1,
- "modified": "2019-09-16 16:27:53.887634",
+ "modified": "2019-11-23 13:28:47.256935",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Movement",
diff --git a/erpnext/assets/doctype/asset_movement/asset_movement.py b/erpnext/assets/doctype/asset_movement/asset_movement.py
index a1d3308..3a08baa 100644
--- a/erpnext/assets/doctype/asset_movement/asset_movement.py
+++ b/erpnext/assets/doctype/asset_movement/asset_movement.py
@@ -5,101 +5,142 @@
from __future__ import unicode_literals
import frappe
from frappe import _
-from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
from frappe.model.document import Document
class AssetMovement(Document):
def validate(self):
self.validate_asset()
self.validate_location()
+ self.validate_employee()
def validate_asset(self):
- status, company = frappe.db.get_value("Asset", self.asset, ["status", "company"])
- if self.purpose == 'Transfer' and status in ("Draft", "Scrapped", "Sold"):
- frappe.throw(_("{0} asset cannot be transferred").format(status))
+ for d in self.assets:
+ status, company = frappe.db.get_value("Asset", d.asset, ["status", "company"])
+ if self.purpose == 'Transfer' and status in ("Draft", "Scrapped", "Sold"):
+ frappe.throw(_("{0} asset cannot be transferred").format(status))
- if company != self.company:
- frappe.throw(_("Asset {0} does not belong to company {1}").format(self.asset, self.company))
+ if company != self.company:
+ frappe.throw(_("Asset {0} does not belong to company {1}").format(d.asset, self.company))
- if self.serial_no and len(get_serial_nos(self.serial_no)) != self.quantity:
- frappe.throw(_("Number of serial nos and quantity must be the same"))
-
- if not(self.source_location or self.target_location or self.from_employee or self.to_employee):
- frappe.throw(_("Either location or employee must be required"))
-
- if (not self.serial_no and
- frappe.db.get_value('Serial No', {'asset': self.asset}, 'name')):
- frappe.throw(_("Serial no is required for the asset {0}").format(self.asset))
+ if not (d.source_location or d.target_location or d.from_employee or d.to_employee):
+ frappe.throw(_("Either location or employee must be required"))
def validate_location(self):
- if self.purpose in ['Transfer', 'Issue']:
- if not self.serial_no and not (self.from_employee or self.to_employee):
- self.source_location = frappe.db.get_value("Asset", self.asset, "location")
+ for d in self.assets:
+ if self.purpose in ['Transfer', 'Issue']:
+ if not d.source_location:
+ d.source_location = frappe.db.get_value("Asset", d.asset, "location")
- if self.purpose == 'Issue' and not (self.source_location or self.from_employee):
- frappe.throw(_("Source Location is required for the asset {0}").format(self.asset))
+ if not d.source_location:
+ frappe.throw(_("Source Location is required for the Asset {0}").format(d.asset))
- if self.serial_no and self.source_location:
- s_nos = get_serial_nos(self.serial_no)
- serial_nos = frappe.db.sql_list(""" select name from `tabSerial No` where location != '%s'
- and name in (%s)""" %(self.source_location, ','.join(['%s'] * len(s_nos))), tuple(s_nos))
+ if d.source_location:
+ current_location = frappe.db.get_value("Asset", d.asset, "location")
- if serial_nos:
- frappe.throw(_("Serial nos {0} does not belongs to the location {1}").
- format(','.join(serial_nos), self.source_location))
+ if current_location != d.source_location:
+ frappe.throw(_("Asset {0} does not belongs to the location {1}").
+ format(d.asset, d.source_location))
+
+ if self.purpose == 'Issue':
+ if d.target_location:
+ frappe.throw(_("Issuing cannot be done to a location. \
+ Please enter employee who has issued Asset {0}").format(d.asset), title="Incorrect Movement Purpose")
+ if not d.to_employee:
+ frappe.throw(_("Employee is required while issuing Asset {0}").format(d.asset))
+
+ if self.purpose == 'Transfer':
+ if d.to_employee:
+ frappe.throw(_("Transferring cannot be done to an Employee. \
+ Please enter location where Asset {0} has to be transferred").format(
+ d.asset), title="Incorrect Movement Purpose")
+ if not d.target_location:
+ frappe.throw(_("Target Location is required while transferring Asset {0}").format(d.asset))
+ if d.source_location == d.target_location:
+ frappe.throw(_("Source and Target Location cannot be same"))
+
+ if self.purpose == 'Receipt':
+ # only when asset is bought and first entry is made
+ if not d.source_location and not (d.target_location or d.to_employee):
+ frappe.throw(_("Target Location or To Employee is required while receiving Asset {0}").format(d.asset))
+ elif d.source_location:
+ # when asset is received from an employee
+ if d.target_location and not d.from_employee:
+ frappe.throw(_("From employee is required while receiving Asset {0} to a target location").format(d.asset))
+ if d.from_employee and not d.target_location:
+ frappe.throw(_("Target Location is required while receiving Asset {0} from an employee").format(d.asset))
+ if d.to_employee and d.target_location:
+ frappe.throw(_("Asset {0} cannot be received at a location and \
+ given to employee in a single movement").format(d.asset))
- if self.source_location and self.source_location == self.target_location and self.purpose == 'Transfer':
- frappe.throw(_("Source and Target Location cannot be same"))
+ def validate_employee(self):
+ for d in self.assets:
+ if d.from_employee:
+ current_custodian = frappe.db.get_value("Asset", d.asset, "custodian")
- if self.purpose == 'Receipt' and not (self.target_location or self.to_employee):
- frappe.throw(_("Target Location is required for the asset {0}").format(self.asset))
+ if current_custodian != d.from_employee:
+ frappe.throw(_("Asset {0} does not belongs to the custodian {1}").
+ format(d.asset, d.from_employee))
+
+ if d.to_employee and frappe.db.get_value("Employee", d.to_employee, "company") != self.company:
+ frappe.throw(_("Employee {0} does not belongs to the company {1}").
+ format(d.to_employee, self.company))
def on_submit(self):
self.set_latest_location_in_asset()
+
+ def before_cancel(self):
+ self.validate_last_movement()
def on_cancel(self):
self.set_latest_location_in_asset()
+
+ def validate_last_movement(self):
+ for d in self.assets:
+ auto_gen_movement_entry = frappe.db.sql(
+ """
+ SELECT asm.name
+ FROM `tabAsset Movement Item` asm_item, `tabAsset Movement` asm
+ WHERE
+ asm.docstatus=1 and
+ asm_item.parent=asm.name and
+ asm_item.asset=%s and
+ asm.company=%s and
+ asm_item.source_location is NULL and
+ asm.purpose=%s
+ ORDER BY
+ asm.transaction_date asc
+ """, (d.asset, self.company, 'Receipt'), as_dict=1)
+ if auto_gen_movement_entry and auto_gen_movement_entry[0].get('name') == self.name:
+ frappe.throw(_('{0} will be cancelled automatically on asset cancellation as it was \
+ auto generated for Asset {1}').format(self.name, d.asset))
def set_latest_location_in_asset(self):
- location, employee = '', ''
+ current_location, current_employee = '', ''
cond = "1=1"
- args = {
- 'asset': self.asset,
- 'company': self.company
- }
+ for d in self.assets:
+ args = {
+ 'asset': d.asset,
+ 'company': self.company
+ }
- if self.serial_no:
- cond = "serial_no like %(txt)s"
- args.update({
- 'txt': "%%%s%%" % self.serial_no
- })
+ # latest entry corresponds to current document's location, employee when transaction date > previous dates
+ # In case of cancellation it corresponds to previous latest document's location, employee
+ latest_movement_entry = frappe.db.sql(
+ """
+ SELECT asm_item.target_location, asm_item.to_employee
+ FROM `tabAsset Movement Item` asm_item, `tabAsset Movement` asm
+ WHERE
+ asm_item.parent=asm.name and
+ asm_item.asset=%(asset)s and
+ asm.company=%(company)s and
+ asm.docstatus=1 and {0}
+ ORDER BY
+ asm.transaction_date desc limit 1
+ """.format(cond), args)
+ if latest_movement_entry:
+ current_location = latest_movement_entry[0][0]
+ current_employee = latest_movement_entry[0][1]
- latest_movement_entry = frappe.db.sql("""select target_location, to_employee from `tabAsset Movement`
- where asset=%(asset)s and docstatus=1 and company=%(company)s and {0}
- order by transaction_date desc limit 1""".format(cond), args)
-
- if latest_movement_entry:
- location = latest_movement_entry[0][0]
- employee = latest_movement_entry[0][1]
- elif self.purpose in ['Transfer', 'Receipt']:
- movement_entry = frappe.db.sql("""select source_location, from_employee from `tabAsset Movement`
- where asset=%(asset)s and docstatus=2 and company=%(company)s and {0}
- order by transaction_date asc limit 1""".format(cond), args)
- if movement_entry:
- location = movement_entry[0][0]
- employee = movement_entry[0][1]
-
- if not self.serial_no:
- frappe.db.set_value("Asset", self.asset, "location", location)
-
- if not employee and self.purpose in ['Receipt', 'Transfer']:
- employee = self.to_employee
-
- if self.serial_no:
- for d in get_serial_nos(self.serial_no):
- if (location or (self.purpose == 'Issue' and self.source_location)):
- frappe.db.set_value('Serial No', d, 'location', location)
-
- if employee or self.docstatus==2 or self.purpose == 'Issue':
- frappe.db.set_value('Serial No', d, 'employee', employee)
+ frappe.db.set_value('Asset', d.asset, 'location', current_location)
+ frappe.db.set_value('Asset', d.asset, 'custodian', current_employee)
diff --git a/erpnext/assets/doctype/asset_movement/test_asset_movement.py b/erpnext/assets/doctype/asset_movement/test_asset_movement.py
index 4d85337..c3755a3 100644
--- a/erpnext/assets/doctype/asset_movement/test_asset_movement.py
+++ b/erpnext/assets/doctype/asset_movement/test_asset_movement.py
@@ -5,6 +5,7 @@
import frappe
import unittest
+import erpnext
from erpnext.stock.doctype.item.test_item import make_item
from frappe.utils import now, nowdate, get_last_day, add_days
from erpnext.assets.doctype.asset.test_asset import create_asset_data
@@ -16,7 +17,6 @@
def setUp(self):
create_asset_data()
make_location()
- make_serialized_item()
def test_movement(self):
pr = make_purchase_receipt(item_code="Macbook Pro",
@@ -38,68 +38,72 @@
if asset.docstatus == 0:
asset.submit()
+
+ # check asset movement is created
if not frappe.db.exists("Location", "Test Location 2"):
frappe.get_doc({
'doctype': 'Location',
'location_name': 'Test Location 2'
}).insert()
- movement1 = create_asset_movement(asset= asset.name, purpose = 'Transfer',
- company=asset.company, source_location="Test Location", target_location="Test Location 2")
+ movement1 = create_asset_movement(purpose = 'Transfer', company = asset.company,
+ assets = [{ 'asset': asset.name , 'source_location': 'Test Location', 'target_location': 'Test Location 2'}],
+ reference_doctype = 'Purchase Receipt', reference_name = pr.name)
self.assertEqual(frappe.db.get_value("Asset", asset.name, "location"), "Test Location 2")
- movement2 = create_asset_movement(asset= asset.name, purpose = 'Transfer',
- company=asset.company, source_location = "Test Location 2", target_location="Test Location")
+ movement2 = create_asset_movement(purpose = 'Transfer', company = asset.company,
+ assets = [{ 'asset': asset.name , 'source_location': 'Test Location 2', 'target_location': 'Test Location'}],
+ reference_doctype = 'Purchase Receipt', reference_name = pr.name)
self.assertEqual(frappe.db.get_value("Asset", asset.name, "location"), "Test Location")
movement1.cancel()
self.assertEqual(frappe.db.get_value("Asset", asset.name, "location"), "Test Location")
- movement2.cancel()
- self.assertEqual(frappe.db.get_value("Asset", asset.name, "location"), "Test Location")
-
- def test_movement_for_serialized_asset(self):
- asset_item = "Test Serialized Asset Item"
- pr = make_purchase_receipt(item_code=asset_item, rate = 1000, qty=3, location = "Mumbai")
- asset_name = frappe.db.get_value('Asset', {'purchase_receipt': pr.name}, 'name')
-
+ employee = make_employee("testassetmovemp@example.com", company="_Test Company")
+ movement3 = create_asset_movement(purpose = 'Issue', company = asset.company,
+ assets = [{ 'asset': asset.name , 'source_location': 'Test Location', 'to_employee': employee}],
+ reference_doctype = 'Purchase Receipt', reference_name = pr.name)
+
+ # after issuing asset should belong to an employee not at a location
+ self.assertEqual(frappe.db.get_value("Asset", asset.name, "location"), None)
+ self.assertEqual(frappe.db.get_value("Asset", asset.name, "custodian"), employee)
+
+ def test_last_movement_cancellation(self):
+ pr = make_purchase_receipt(item_code="Macbook Pro",
+ qty=1, rate=100000.0, location="Test Location")
+
+ asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, 'name')
asset = frappe.get_doc('Asset', asset_name)
- month_end_date = get_last_day(nowdate())
- asset.available_for_use_date = nowdate() if nowdate() != month_end_date else add_days(nowdate(), -15)
-
asset.calculate_depreciation = 1
+ asset.available_for_use_date = '2020-06-06'
+ asset.purchase_date = '2020-06-06'
asset.append("finance_books", {
- "expected_value_after_useful_life": 200,
+ "expected_value_after_useful_life": 10000,
+ "next_depreciation_date": "2020-12-31",
"depreciation_method": "Straight Line",
"total_number_of_depreciations": 3,
"frequency_of_depreciation": 10,
- "depreciation_start_date": month_end_date
+ "depreciation_start_date": "2020-06-06"
})
- asset.submit()
- serial_nos = frappe.db.get_value('Asset Movement', {'reference_name': pr.name}, 'serial_no')
+ if asset.docstatus == 0:
+ asset.submit()
+
+ if not frappe.db.exists("Location", "Test Location 2"):
+ frappe.get_doc({
+ 'doctype': 'Location',
+ 'location_name': 'Test Location 2'
+ }).insert()
+
+ movement = frappe.get_doc({'doctype': 'Asset Movement', 'reference_name': pr.name })
+ self.assertRaises(frappe.ValidationError, movement.cancel)
- mov1 = create_asset_movement(asset=asset_name, purpose = 'Transfer',
- company=asset.company, source_location = "Mumbai", target_location="Pune", serial_no=serial_nos)
- self.assertEqual(mov1.target_location, "Pune")
+ movement1 = create_asset_movement(purpose = 'Transfer', company = asset.company,
+ assets = [{ 'asset': asset.name , 'source_location': 'Test Location', 'target_location': 'Test Location 2'}],
+ reference_doctype = 'Purchase Receipt', reference_name = pr.name)
+ self.assertEqual(frappe.db.get_value("Asset", asset.name, "location"), "Test Location 2")
- serial_no = frappe.db.get_value('Serial No', {'asset': asset_name}, 'name')
-
- employee = make_employee("testassetemp@example.com")
- create_asset_movement(asset=asset_name, purpose = 'Transfer',
- company=asset.company, serial_no=serial_no, to_employee=employee)
-
- self.assertEqual(frappe.db.get_value('Serial No', serial_no, 'employee'), employee)
-
- create_asset_movement(asset=asset_name, purpose = 'Transfer', company=asset.company,
- serial_no=serial_no, from_employee=employee, to_employee="_T-Employee-00001")
-
- self.assertEqual(frappe.db.get_value('Serial No', serial_no, 'location'), "Pune")
-
- mov4 = create_asset_movement(asset=asset_name, purpose = 'Transfer',
- company=asset.company, source_location = "Pune", target_location="Nagpur", serial_no=serial_nos)
- self.assertEqual(mov4.target_location, "Nagpur")
- self.assertEqual(frappe.db.get_value('Serial No', serial_no, 'location'), "Nagpur")
- self.assertEqual(frappe.db.get_value('Serial No', serial_no, 'employee'), "_T-Employee-00001")
+ movement1.cancel()
+ self.assertEqual(frappe.db.get_value("Asset", asset.name, "location"), "Test Location")
def create_asset_movement(**args):
args = frappe._dict(args)
@@ -109,22 +113,14 @@
movement = frappe.new_doc("Asset Movement")
movement.update({
- "asset": args.asset,
+ "assets": args.assets,
"transaction_date": args.transaction_date,
- "target_location": args.target_location,
"company": args.company,
'purpose': args.purpose or 'Receipt',
- 'serial_no': args.serial_no,
- 'quantity': len(get_serial_nos(args.serial_no)) if args.serial_no else 1,
- 'from_employee': "_T-Employee-00001" or args.from_employee,
- 'to_employee': args.to_employee
+ 'reference_doctype': args.reference_doctype,
+ 'reference_name': args.reference_name
})
- if args.source_location:
- movement.update({
- 'source_location': args.source_location
- })
-
movement.insert()
movement.submit()
@@ -137,33 +133,3 @@
'doctype': 'Location',
'location_name': location
}).insert(ignore_permissions = True)
-
-def make_serialized_item():
- asset_item = "Test Serialized Asset Item"
-
- if not frappe.db.exists('Item', asset_item):
- asset_category = frappe.get_all('Asset Category')
-
- if asset_category:
- asset_category = asset_category[0].name
-
- if not asset_category:
- doc = frappe.get_doc({
- 'doctype': 'Asset Category',
- 'asset_category_name': 'Test Asset Category',
- 'depreciation_method': 'Straight Line',
- 'total_number_of_depreciations': 12,
- 'frequency_of_depreciation': 1,
- 'accounts': [{
- 'company_name': '_Test Company',
- 'fixed_asset_account': '_Test Fixed Asset - _TC',
- 'accumulated_depreciation_account': 'Depreciation - _TC',
- 'depreciation_expense_account': 'Depreciation - _TC'
- }]
- }).insert()
-
- asset_category = doc.name
-
- make_item(asset_item, {'is_stock_item':0,
- 'stock_uom': 'Box', 'is_fixed_asset': 1, 'has_serial_no': 1,
- 'asset_category': asset_category, 'serial_no_series': 'ABC.###'})
diff --git a/erpnext/assets/doctype/asset_settings/__init__.py b/erpnext/assets/doctype/asset_movement_item/__init__.py
similarity index 100%
rename from erpnext/assets/doctype/asset_settings/__init__.py
rename to erpnext/assets/doctype/asset_movement_item/__init__.py
diff --git a/erpnext/assets/doctype/asset_movement_item/asset_movement_item.json b/erpnext/assets/doctype/asset_movement_item/asset_movement_item.json
new file mode 100644
index 0000000..994c3c0
--- /dev/null
+++ b/erpnext/assets/doctype/asset_movement_item/asset_movement_item.json
@@ -0,0 +1,86 @@
+{
+ "creation": "2019-10-07 18:49:00.737806",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "company",
+ "asset",
+ "source_location",
+ "from_employee",
+ "column_break_2",
+ "asset_name",
+ "target_location",
+ "to_employee"
+ ],
+ "fields": [
+ {
+ "fieldname": "asset",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Asset",
+ "options": "Asset",
+ "reqd": 1
+ },
+ {
+ "fetch_from": "asset.asset_name",
+ "fieldname": "asset_name",
+ "fieldtype": "Data",
+ "label": "Asset Name",
+ "read_only": 1
+ },
+ {
+ "fieldname": "source_location",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Source Location",
+ "options": "Location"
+ },
+ {
+ "fieldname": "target_location",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Target Location",
+ "options": "Location"
+ },
+ {
+ "fieldname": "from_employee",
+ "fieldtype": "Link",
+ "ignore_user_permissions": 1,
+ "in_list_view": 1,
+ "label": "From Employee",
+ "options": "Employee"
+ },
+ {
+ "fieldname": "to_employee",
+ "fieldtype": "Link",
+ "ignore_user_permissions": 1,
+ "in_list_view": 1,
+ "label": "To Employee",
+ "options": "Employee"
+ },
+ {
+ "fieldname": "column_break_2",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "hidden": 1,
+ "label": "Company",
+ "options": "Company",
+ "read_only": 1
+ }
+ ],
+ "istable": 1,
+ "modified": "2019-10-09 15:59:08.265141",
+ "modified_by": "Administrator",
+ "module": "Assets",
+ "name": "Asset Movement Item",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/assets/doctype/asset_movement_item/asset_movement_item.py b/erpnext/assets/doctype/asset_movement_item/asset_movement_item.py
new file mode 100644
index 0000000..4c6aaab
--- /dev/null
+++ b/erpnext/assets/doctype/asset_movement_item/asset_movement_item.py
@@ -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 AssetMovementItem(Document):
+ pass
diff --git a/erpnext/assets/doctype/asset_settings/asset_settings.js b/erpnext/assets/doctype/asset_settings/asset_settings.js
deleted file mode 100644
index 3b42148..0000000
--- a/erpnext/assets/doctype/asset_settings/asset_settings.js
+++ /dev/null
@@ -1,5 +0,0 @@
-// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
-// For license information, please see license.txt
-
-frappe.ui.form.on('Asset Settings', {
-});
diff --git a/erpnext/assets/doctype/asset_settings/asset_settings.json b/erpnext/assets/doctype/asset_settings/asset_settings.json
deleted file mode 100644
index edc5ce1..0000000
--- a/erpnext/assets/doctype/asset_settings/asset_settings.json
+++ /dev/null
@@ -1,148 +0,0 @@
-{
- "allow_copy": 0,
- "allow_events_in_timeline": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "beta": 0,
- "creation": "2018-01-03 10:30:32.983381",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "",
- "editable_grid": 1,
- "engine": "InnoDB",
- "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": "depreciation_options",
- "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": "Depreciation Options",
- "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
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "disable_cwip_accounting",
- "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": "Disable CWIP Accounting",
- "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
- }
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 1,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2019-05-26 18:31:19.930563",
- "modified_by": "Administrator",
- "module": "Assets",
- "name": "Asset Settings",
- "name_case": "",
- "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": 0,
- "role": "System Manager",
- "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": 0,
- "role": "Accounts Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
- "write": 1
- }
- ],
- "quick_entry": 1,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1,
- "track_seen": 0,
- "track_views": 0
-}
\ No newline at end of file
diff --git a/erpnext/assets/doctype/asset_settings/test_asset_settings.js b/erpnext/assets/doctype/asset_settings/test_asset_settings.js
deleted file mode 100644
index eac2c92..0000000
--- a/erpnext/assets/doctype/asset_settings/test_asset_settings.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Asset Settings", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Asset Settings
- () => frappe.tests.make('Asset Settings', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/assets/doctype/asset_settings/test_asset_settings.py b/erpnext/assets/doctype/asset_settings/test_asset_settings.py
deleted file mode 100644
index 75f146a..0000000
--- a/erpnext/assets/doctype/asset_settings/test_asset_settings.py
+++ /dev/null
@@ -1,9 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
-# See license.txt
-from __future__ import unicode_literals
-
-import unittest
-
-class TestAssetSettings(unittest.TestCase):
- pass
diff --git a/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.json b/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.json
index a25b4ce..3236e72 100644
--- a/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.json
+++ b/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.json
@@ -60,7 +60,8 @@
{
"fieldname": "date",
"fieldtype": "Date",
- "label": "Date"
+ "label": "Date",
+ "reqd": 1
},
{
"fieldname": "current_asset_value",
@@ -110,7 +111,7 @@
}
],
"is_submittable": 1,
- "modified": "2019-05-26 09:46:23.613412",
+ "modified": "2019-11-22 14:09:25.800375",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Value Adjustment",
diff --git a/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py b/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py
index 56425a0..155597e 100644
--- a/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py
+++ b/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py
@@ -5,12 +5,13 @@
from __future__ import unicode_literals
import frappe
from frappe import _
-from frappe.utils import flt, getdate, cint, date_diff
+from frappe.utils import flt, getdate, cint, date_diff, formatdate
from erpnext.assets.doctype.asset.depreciation import get_depreciation_accounts
from frappe.model.document import Document
class AssetValueAdjustment(Document):
def validate(self):
+ self.validate_date()
self.set_difference_amount()
self.set_current_asset_value()
@@ -23,6 +24,12 @@
frappe.throw(_("Cancel the journal entry {0} first").format(self.journal_entry))
self.reschedule_depreciations(self.current_asset_value)
+
+ def validate_date(self):
+ asset_purchase_date = frappe.db.get_value('Asset', self.asset, 'purchase_date')
+ if getdate(self.date) < getdate(asset_purchase_date):
+ frappe.throw(_("Asset Value Adjustment cannot be posted before Asset's purchase date <b>{0}</b>.")
+ .format(formatdate(asset_purchase_date)), title="Incorrect Date")
def set_difference_amount(self):
self.difference_amount = flt(self.current_asset_value - self.new_asset_value)
diff --git a/erpnext/assets/report/fixed_asset_register/fixed_asset_register.js b/erpnext/assets/report/fixed_asset_register/fixed_asset_register.js
index 426caaa..8c737d0 100644
--- a/erpnext/assets/report/fixed_asset_register/fixed_asset_register.js
+++ b/erpnext/assets/report/fixed_asset_register/fixed_asset_register.js
@@ -26,5 +26,11 @@
fieldtype: "Link",
options: "Finance Book"
},
+ {
+ fieldname:"date",
+ label: __("Date"),
+ fieldtype: "Date",
+ default: frappe.datetime.get_today()
+ },
]
};
diff --git a/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py b/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py
index f395499..1498444 100644
--- a/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py
+++ b/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py
@@ -4,7 +4,7 @@
from __future__ import unicode_literals
import frappe
from frappe import _
-from frappe.utils import cstr
+from frappe.utils import cstr, today, flt
def execute(filters=None):
filters = frappe._dict(filters or {})
@@ -86,8 +86,8 @@
"width": 90
},
{
- "label": _("Current Value"),
- "fieldname": "current_value",
+ "label": _("Asset Value"),
+ "fieldname": "asset_value",
"options": "Currency",
"width": 90
},
@@ -114,7 +114,7 @@
data = []
conditions = get_conditions(filters)
- current_value_map = get_finance_book_value_map(filters.finance_book)
+ depreciation_amount_map = get_finance_book_value_map(filters.date, filters.finance_book)
pr_supplier_map = get_purchase_receipt_supplier_map()
pi_supplier_map = get_purchase_invoice_supplier_map()
@@ -122,10 +122,12 @@
filters=conditions,
fields=["name", "asset_name", "department", "cost_center", "purchase_receipt",
"asset_category", "purchase_date", "gross_purchase_amount", "location",
- "available_for_use_date", "status", "purchase_invoice"])
+ "available_for_use_date", "status", "purchase_invoice", "opening_accumulated_depreciation"])
for asset in assets_record:
- if current_value_map.get(asset.name) is not None:
+ asset_value = asset.gross_purchase_amount - flt(asset.opening_accumulated_depreciation) \
+ - flt(depreciation_amount_map.get(asset.name))
+ if asset_value:
row = {
"asset_id": asset.name,
"asset_name": asset.asset_name,
@@ -138,19 +140,24 @@
"location": asset.location,
"asset_category": asset.asset_category,
"purchase_date": asset.purchase_date,
- "current_value": current_value_map.get(asset.name)
+ "asset_value": asset_value
}
data.append(row)
return data
-def get_finance_book_value_map(finance_book=''):
+def get_finance_book_value_map(date, finance_book=''):
+ if not date:
+ date = today()
return frappe._dict(frappe.db.sql(''' Select
- parent, value_after_depreciation
- FROM `tabAsset Finance Book`
+ parent, SUM(depreciation_amount)
+ FROM `tabDepreciation Schedule`
WHERE
- parentfield='finance_books'
- AND ifnull(finance_book, '')=%s''', cstr(finance_book)))
+ parentfield='schedules'
+ AND schedule_date<=%s
+ AND journal_entry IS NOT NULL
+ AND ifnull(finance_book, '')=%s
+ GROUP BY parent''', (date, cstr(finance_book))))
def get_purchase_receipt_supplier_map():
return frappe._dict(frappe.db.sql(''' Select
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.js b/erpnext/buying/doctype/purchase_order/purchase_order.js
index c5fa98d..7b1f135 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.js
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.js
@@ -18,6 +18,7 @@
return {
filters: {
"company": frm.doc.company,
+ "name": ['!=', frm.doc.supplier_warehouse],
"is_group": 0
}
}
@@ -133,7 +134,7 @@
if (doc.status != "On Hold") {
if(flt(doc.per_received, 2) < 100 && allow_receipt) {
cur_frm.add_custom_button(__('Receipt'), this.make_purchase_receipt, __('Create'));
- if(doc.is_subcontracted==="Yes") {
+ if(doc.is_subcontracted==="Yes" && me.has_unsupplied_items()) {
cur_frm.add_custom_button(__('Material to Supplier'),
function() { me.make_stock_entry(); }, __("Transfer"));
}
@@ -190,6 +191,10 @@
set_schedule_date(this.frm);
},
+ has_unsupplied_items: function() {
+ return this.frm.doc['supplied_items'].some(item => item.required_qty != item.supplied_qty)
+ },
+
make_stock_entry: function() {
var items = $.map(cur_frm.doc.items, function(d) { return d.bom ? d.item_code : false; });
var me = this;
@@ -266,7 +271,7 @@
if (me.frm.doc['supplied_items']) {
me.frm.doc['supplied_items'].forEach((item, index) => {
- if (item.rm_item_code && item.main_item_code) {
+ if (item.rm_item_code && item.main_item_code && item.required_qty - item.supplied_qty != 0) {
me.raw_material_data.push ({
'name':item.name,
'item_code': item.main_item_code,
@@ -283,6 +288,8 @@
})
}
+ me.dialog.get_field('sub_con_rm_items').check_all_rows()
+
me.dialog.show()
this.dialog.set_primary_action(__('Transfer'), function() {
me.values = me.dialog.get_values();
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.json b/erpnext/buying/doctype/purchase_order/purchase_order.json
index 5dce349..9201eef 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.json
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.json
@@ -1,4 +1,5 @@
{
+ "actions": [],
"allow_import": 1,
"autoname": "naming_series:",
"creation": "2013-05-21 16:16:39",
@@ -47,6 +48,7 @@
"ignore_pricing_rule",
"sec_warehouse",
"set_warehouse",
+ "set_reserve_warehouse",
"col_break_warehouse",
"is_subcontracted",
"supplier_warehouse",
@@ -340,6 +342,7 @@
"fieldname": "contact_email",
"fieldtype": "Small Text",
"label": "Contact Email",
+ "options": "Email",
"print_hide": 1,
"read_only": 1
},
@@ -607,7 +610,7 @@
},
{
"fieldname": "other_charges_calculation",
- "fieldtype": "Text",
+ "fieldtype": "Long Text",
"label": "Taxes and Charges Calculation",
"no_copy": 1,
"oldfieldtype": "HTML",
@@ -1039,12 +1042,20 @@
"fieldtype": "Link",
"label": "Tax Category",
"options": "Tax Category"
+ },
+ {
+ "depends_on": "supplied_items",
+ "fieldname": "set_reserve_warehouse",
+ "fieldtype": "Link",
+ "label": "Set Reserve Warehouse",
+ "options": "Warehouse"
}
],
"icon": "fa fa-file-text",
"idx": 105,
"is_submittable": 1,
- "modified": "2019-07-11 18:25:49.509343",
+ "links": [],
+ "modified": "2019-12-30 19:11:54.122264",
"modified_by": "Administrator",
"module": "Buying",
"name": "Purchase Order",
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py
index 845ff74..f62df20 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.py
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.py
@@ -313,7 +313,7 @@
last_purchase_details = get_last_purchase_details(item_code, name)
if last_purchase_details:
- last_purchase_rate = (last_purchase_details['base_rate'] * (flt(conversion_factor) or 1.0)) / conversion_rate
+ last_purchase_rate = (last_purchase_details['base_net_rate'] * (flt(conversion_factor) or 1.0)) / conversion_rate
return last_purchase_rate
else:
item_last_purchase_rate = frappe.get_cached_value("Item", item_code, "last_purchase_rate")
diff --git a/erpnext/buying/doctype/purchase_order/regional/india.js b/erpnext/buying/doctype/purchase_order/regional/india.js
new file mode 100644
index 0000000..42d3995
--- /dev/null
+++ b/erpnext/buying/doctype/purchase_order/regional/india.js
@@ -0,0 +1,3 @@
+{% include "erpnext/regional/india/taxes.js" %}
+
+erpnext.setup_auto_gst_taxation('Purchase Order');
\ No newline at end of file
diff --git a/erpnext/buying/doctype/purchase_order/test_purchase_order.py b/erpnext/buying/doctype/purchase_order/test_purchase_order.py
index 4506db6..1712369 100644
--- a/erpnext/buying/doctype/purchase_order/test_purchase_order.py
+++ b/erpnext/buying/doctype/purchase_order/test_purchase_order.py
@@ -17,6 +17,8 @@
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
from erpnext.controllers.accounts_controller import update_child_qty_rate
from erpnext.controllers.status_updater import OverAllowanceError
+from erpnext.manufacturing.doctype.blanket_order.test_blanket_order import make_blanket_order
+
class TestPurchaseOrder(unittest.TestCase):
def test_make_purchase_receipt(self):
@@ -116,6 +118,73 @@
self.assertEqual(po.get("items")[0].amount, 1400)
self.assertEqual(get_ordered_qty(), existing_ordered_qty + 3)
+
+ def test_add_new_item_in_update_child_qty_rate(self):
+ po = create_purchase_order(do_not_save=1)
+ po.items[0].qty = 4
+ po.save()
+ po.submit()
+ pr = make_pr_against_po(po.name, 2)
+
+ po.load_from_db()
+ first_item_of_po = po.get("items")[0]
+
+ trans_item = json.dumps([
+ {
+ 'item_code': first_item_of_po.item_code,
+ 'rate': first_item_of_po.rate,
+ 'qty': first_item_of_po.qty,
+ 'docname': first_item_of_po.name
+ },
+ {'item_code' : '_Test Item', 'rate' : 200, 'qty' : 7}
+ ])
+ update_child_qty_rate('Purchase Order', trans_item, po.name)
+
+ po.reload()
+ self.assertEquals(len(po.get('items')), 2)
+ self.assertEqual(po.status, 'To Receive and Bill')
+
+
+ def test_remove_item_in_update_child_qty_rate(self):
+ po = create_purchase_order(do_not_save=1)
+ po.items[0].qty = 4
+ po.save()
+ po.submit()
+ pr = make_pr_against_po(po.name, 2)
+
+ po.reload()
+ first_item_of_po = po.get("items")[0]
+ # add an item
+ trans_item = json.dumps([
+ {
+ 'item_code': first_item_of_po.item_code,
+ 'rate': first_item_of_po.rate,
+ 'qty': first_item_of_po.qty,
+ 'docname': first_item_of_po.name
+ },
+ {'item_code' : '_Test Item', 'rate' : 200, 'qty' : 7}])
+ update_child_qty_rate('Purchase Order', trans_item, po.name)
+
+ po.reload()
+ # check if can remove received item
+ trans_item = json.dumps([{'item_code' : '_Test Item', 'rate' : 200, 'qty' : 7, 'docname': po.get("items")[1].name}])
+ self.assertRaises(frappe.ValidationError, update_child_qty_rate, 'Purchase Order', trans_item, po.name)
+
+ first_item_of_po = po.get("items")[0]
+ trans_item = json.dumps([
+ {
+ 'item_code': first_item_of_po.item_code,
+ 'rate': first_item_of_po.rate,
+ 'qty': first_item_of_po.qty,
+ 'docname': first_item_of_po.name
+ }
+ ])
+ update_child_qty_rate('Purchase Order', trans_item, po.name)
+
+ po.reload()
+ self.assertEquals(len(po.get('items')), 1)
+ self.assertEqual(po.status, 'To Receive and Bill')
+
def test_update_qty(self):
po = create_purchase_order()
@@ -519,47 +588,62 @@
def test_backflush_based_on_stock_entry(self):
item_code = "_Test Subcontracted FG Item 1"
make_subcontracted_item(item_code)
+ make_item('Sub Contracted Raw Material 1', {
+ 'is_stock_item': 1,
+ 'is_sub_contracted_item': 1
+ })
update_backflush_based_on("Material Transferred for Subcontract")
- po = create_purchase_order(item_code=item_code, qty=1,
+
+ order_qty = 5
+ po = create_purchase_order(item_code=item_code, qty=order_qty,
is_subcontracted="Yes", supplier_warehouse="_Test Warehouse 1 - _TC")
- make_stock_entry(target="_Test Warehouse - _TC", qty=10, basic_rate=100)
make_stock_entry(target="_Test Warehouse - _TC",
item_code="_Test Item Home Desktop 100", qty=10, basic_rate=100)
make_stock_entry(target="_Test Warehouse - _TC",
item_code = "Test Extra Item 1", qty=100, basic_rate=100)
make_stock_entry(target="_Test Warehouse - _TC",
item_code = "Test Extra Item 2", qty=10, basic_rate=100)
+ make_stock_entry(target="_Test Warehouse - _TC",
+ item_code = "Sub Contracted Raw Material 1", qty=10, basic_rate=100)
- rm_item = [
- {"item_code":item_code,"rm_item_code":"_Test Item","item_name":"_Test Item",
- "qty":1,"warehouse":"_Test Warehouse - _TC","rate":100,"amount":100,"stock_uom":"Nos"},
+ rm_items = [
+ {"item_code":item_code,"rm_item_code":"Sub Contracted Raw Material 1","item_name":"_Test Item",
+ "qty":10,"warehouse":"_Test Warehouse - _TC", "stock_uom":"Nos"},
{"item_code":item_code,"rm_item_code":"_Test Item Home Desktop 100","item_name":"_Test Item Home Desktop 100",
- "qty":2,"warehouse":"_Test Warehouse - _TC","rate":100,"amount":200,"stock_uom":"Nos"},
+ "qty":20,"warehouse":"_Test Warehouse - _TC", "stock_uom":"Nos"},
{"item_code":item_code,"rm_item_code":"Test Extra Item 1","item_name":"Test Extra Item 1",
- "qty":1,"warehouse":"_Test Warehouse - _TC","rate":100,"amount":200,"stock_uom":"Nos"}]
+ "qty":10,"warehouse":"_Test Warehouse - _TC", "stock_uom":"Nos"},
+ {'item_code': item_code, 'rm_item_code': 'Test Extra Item 2', 'stock_uom':'Nos',
+ 'qty': 10, 'warehouse': '_Test Warehouse - _TC', 'item_name':'Test Extra Item 2'}]
- rm_item_string = json.dumps(rm_item)
+ rm_item_string = json.dumps(rm_items)
se = frappe.get_doc(make_subcontract_transfer_entry(po.name, rm_item_string))
- se.append('items', {
- 'item_code': "Test Extra Item 2",
- "qty": 1,
- "rate": 100,
- "s_warehouse": "_Test Warehouse - _TC",
- "t_warehouse": "_Test Warehouse 1 - _TC"
- })
- se.set_missing_values()
se.submit()
pr = make_purchase_receipt(po.name)
+
+ received_qty = 2
+ # partial receipt
+ pr.get('items')[0].qty = received_qty
pr.save()
pr.submit()
- se_items = sorted([d.item_code for d in se.get('items')])
- supplied_items = sorted([d.rm_item_code for d in pr.get('supplied_items')])
+ transferred_items = sorted([d.item_code for d in se.get('items') if se.purchase_order == po.name])
+ issued_items = sorted([d.rm_item_code for d in pr.get('supplied_items')])
- self.assertEquals(se_items, supplied_items)
+ self.assertEquals(transferred_items, issued_items)
+ self.assertEquals(pr.get('items')[0].rm_supp_cost, 2000)
+
+
+ transferred_rm_map = frappe._dict()
+ for item in rm_items:
+ transferred_rm_map[item.get('rm_item_code')] = item
+
+ for item in pr.get('supplied_items'):
+ self.assertEqual(item.get('required_qty'), (transferred_rm_map[item.get('rm_item_code')].get('qty') / order_qty) * received_qty)
+
update_backflush_based_on("BOM")
def test_advance_payment_entry_unlink_against_purchase_order(self):
@@ -605,6 +689,27 @@
po.save()
self.assertEqual(po.schedule_date, add_days(nowdate(), 2))
+
+ def test_po_optional_blanket_order(self):
+ """
+ Expected result: Blanket order Ordered Quantity should only be affected on Purchase Order with against_blanket_order = 1.
+ Second Purchase Order should not add on to Blanket Orders Ordered Quantity.
+ """
+
+ bo = make_blanket_order(blanket_order_type = "Purchasing", quantity = 10, rate = 10)
+
+ po = create_purchase_order(item_code= "_Test Item", qty = 5, against_blanket_order = 1)
+ po_doc = frappe.get_doc('Purchase Order', po.get('name'))
+ # To test if the PO has a Blanket Order
+ self.assertTrue(po_doc.items[0].blanket_order)
+
+ po = create_purchase_order(item_code= "_Test Item", qty = 5, against_blanket_order = 0)
+ po_doc = frappe.get_doc('Purchase Order', po.get('name'))
+ # To test if the PO does NOT have a Blanket Order
+ self.assertEqual(po_doc.items[0].blanket_order, None)
+
+
+
def make_pr_against_po(po, received_qty=0):
pr = make_purchase_receipt(po)
@@ -678,7 +783,8 @@
"qty": args.qty or 10,
"rate": args.rate or 500,
"schedule_date": add_days(nowdate(), 1),
- "include_exploded_items": args.get('include_exploded_items', 1)
+ "include_exploded_items": args.get('include_exploded_items', 1),
+ "against_blanket_order": args.against_blanket_order
})
if not args.do_not_save:
po.insert()
diff --git a/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json b/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json
index 66ad97a..6768dfa 100644
--- a/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json
+++ b/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json
@@ -1,4 +1,5 @@
{
+ "actions": [],
"autoname": "hash",
"creation": "2013-05-24 19:29:06",
"doctype": "DocType",
@@ -43,6 +44,7 @@
"base_amount",
"pricing_rules",
"is_free_item",
+ "is_fixed_asset",
"section_break_29",
"net_rate",
"net_amount",
@@ -66,6 +68,7 @@
"supplier_quotation",
"supplier_quotation_item",
"col_break5",
+ "against_blanket_order",
"blanket_order",
"blanket_order_rate",
"item_group",
@@ -510,6 +513,7 @@
"read_only": 1
},
{
+ "depends_on": "eval:doc.against_blanket_order",
"fieldname": "blanket_order",
"fieldtype": "Link",
"label": "Blanket Order",
@@ -517,6 +521,7 @@
"options": "Blanket Order"
},
{
+ "depends_on": "eval:doc.against_blanket_order",
"fieldname": "blanket_order_rate",
"fieldtype": "Currency",
"label": "Blanket Order Rate",
@@ -699,11 +704,26 @@
"fieldtype": "Data",
"label": "Manufacturer Part Number",
"read_only": 1
+ },
+ {
+ "default": "0",
+ "fieldname": "against_blanket_order",
+ "fieldtype": "Check",
+ "label": "Against Blanket Order"
+ },
+ {
+ "default": "0",
+ "fetch_from": "item_code.is_fixed_asset",
+ "fieldname": "is_fixed_asset",
+ "fieldtype": "Check",
+ "label": "Is Fixed Asset",
+ "read_only": 1
}
],
"idx": 1,
"istable": 1,
- "modified": "2019-09-17 22:32:34.703923",
+ "links": [],
+ "modified": "2019-12-06 13:17:12.142799",
"modified_by": "Administrator",
"module": "Buying",
"name": "Purchase Order Item",
diff --git a/erpnext/buying/doctype/purchase_receipt_item_supplied/purchase_receipt_item_supplied.json b/erpnext/buying/doctype/purchase_receipt_item_supplied/purchase_receipt_item_supplied.json
index 2e0fc94..6f2fbe5 100644
--- a/erpnext/buying/doctype/purchase_receipt_item_supplied/purchase_receipt_item_supplied.json
+++ b/erpnext/buying/doctype/purchase_receipt_item_supplied/purchase_receipt_item_supplied.json
@@ -1,537 +1,168 @@
{
- "allow_copy": 0,
- "allow_events_in_timeline": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "beta": 0,
- "creation": "2013-02-22 01:27:42",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "editable_grid": 1,
- "engine": "InnoDB",
+ "creation": "2013-02-22 01:27:42",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "main_item_code",
+ "rm_item_code",
+ "description",
+ "batch_no",
+ "serial_no",
+ "col_break1",
+ "required_qty",
+ "consumed_qty",
+ "stock_uom",
+ "rate",
+ "amount",
+ "conversion_factor",
+ "current_stock",
+ "reference_name",
+ "bom_detail_no"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "main_item_code",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Item Code",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "main_item_code",
- "oldfieldtype": "Data",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "main_item_code",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Item Code",
+ "oldfieldname": "main_item_code",
+ "oldfieldtype": "Data",
+ "options": "Item",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "rm_item_code",
- "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": "Raw Material Item Code",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "rm_item_code",
- "oldfieldtype": "Data",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "rm_item_code",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Raw Material Item Code",
+ "oldfieldname": "rm_item_code",
+ "oldfieldtype": "Data",
+ "options": "Item",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "description",
- "fieldtype": "Text Editor",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 1,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Description",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "description",
- "oldfieldtype": "Data",
- "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,
- "translatable": 0,
- "unique": 0,
+ "fieldname": "description",
+ "fieldtype": "Text Editor",
+ "in_global_search": 1,
+ "in_list_view": 1,
+ "label": "Description",
+ "oldfieldname": "description",
+ "oldfieldtype": "Data",
+ "print_width": "300px",
+ "read_only": 1,
"width": "300px"
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "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": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "batch_no",
+ "fieldtype": "Link",
+ "label": "Batch No",
+ "no_copy": 1,
+ "options": "Batch"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "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": 1,
- "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
- },
+ "fieldname": "serial_no",
+ "fieldtype": "Text",
+ "label": "Serial No",
+ "no_copy": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "col_break1",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "col_break1",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "required_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": "Required Qty",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "required_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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "required_qty",
+ "fieldtype": "Float",
+ "in_list_view": 1,
+ "label": "Required Qty",
+ "oldfieldname": "required_qty",
+ "oldfieldtype": "Currency",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "consumed_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": "Consumed Qty",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "consumed_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": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "consumed_qty",
+ "fieldtype": "Float",
+ "label": "Consumed Qty",
+ "oldfieldname": "consumed_qty",
+ "oldfieldtype": "Currency",
+ "read_only": 1,
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "stock_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": "Stock Uom",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "stock_uom",
- "oldfieldtype": "Data",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "stock_uom",
+ "fieldtype": "Link",
+ "label": "Stock Uom",
+ "oldfieldname": "stock_uom",
+ "oldfieldtype": "Data",
+ "options": "UOM",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "rate",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Rate",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "rate",
- "oldfieldtype": "Currency",
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "rate",
+ "fieldtype": "Currency",
+ "label": "Rate",
+ "oldfieldname": "rate",
+ "oldfieldtype": "Currency",
+ "options": "Company:company:default_currency",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "amount",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Amount",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "amount",
- "oldfieldtype": "Currency",
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "amount",
+ "fieldtype": "Currency",
+ "label": "Amount",
+ "oldfieldname": "amount",
+ "oldfieldtype": "Currency",
+ "options": "Company:company:default_currency",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "conversion_factor",
- "fieldtype": "Float",
- "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": "Conversion Factor",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "conversion_factor",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "conversion_factor",
+ "fieldtype": "Float",
+ "hidden": 1,
+ "label": "Conversion Factor",
+ "oldfieldname": "conversion_factor",
+ "oldfieldtype": "Currency",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "current_stock",
- "fieldtype": "Float",
- "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": "Current Stock",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "current_stock",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "current_stock",
+ "fieldtype": "Float",
+ "in_list_view": 1,
+ "label": "Current Stock",
+ "oldfieldname": "current_stock",
+ "oldfieldtype": "Currency",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "reference_name",
- "fieldtype": "Data",
- "hidden": 1,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Reference Name",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "reference_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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "reference_name",
+ "fieldtype": "Data",
+ "hidden": 1,
+ "in_list_view": 1,
+ "label": "Reference Name",
+ "oldfieldname": "reference_name",
+ "oldfieldtype": "Data",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "bom_detail_no",
- "fieldtype": "Data",
- "hidden": 1,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "BOM Detail No",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "bom_detail_no",
- "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,
- "translatable": 0,
- "unique": 0
+ "fieldname": "bom_detail_no",
+ "fieldtype": "Data",
+ "hidden": 1,
+ "in_list_view": 1,
+ "label": "BOM Detail No",
+ "oldfieldname": "bom_detail_no",
+ "oldfieldtype": "Data",
+ "read_only": 1
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 1,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 1,
- "max_attachments": 0,
- "modified": "2019-01-07 16:51:59.536291",
- "modified_by": "Administrator",
- "module": "Buying",
- "name": "Purchase Receipt Item Supplied",
- "owner": "wasim@webnotestech.com",
- "permissions": [],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1,
- "track_seen": 0,
- "track_views": 0
+ ],
+ "idx": 1,
+ "istable": 1,
+ "modified": "2019-11-21 16:25:29.909112",
+ "modified_by": "Administrator",
+ "module": "Buying",
+ "name": "Purchase Receipt Item Supplied",
+ "owner": "wasim@webnotestech.com",
+ "permissions": [],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
}
\ No newline at end of file
diff --git a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.js b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.js
index 9ad06f9..2f0cfa6 100644
--- a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.js
+++ b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.js
@@ -134,7 +134,7 @@
if (args.search_type === "Tag" && args.tag) {
return frappe.call({
type: "GET",
- method: "frappe.desk.tags.get_tagged_docs",
+ method: "frappe.desk.doctype.tag.tag.get_tagged_docs",
args: {
"doctype": "Supplier",
"tag": args.tag
diff --git a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py
index a10ce46..95db33b 100644
--- a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py
+++ b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py
@@ -344,13 +344,9 @@
@frappe.whitelist()
def get_supplier_tag():
- data = frappe.db.sql("select _user_tags from `tabSupplier`")
+ if not frappe.cache().hget("Supplier", "Tags"):
+ filters = {"document_type": "Supplier"}
+ tags = list(set([tag.tag for tag in frappe.get_all("Tag Link", filters=filters, fields=["tag"]) if tag]))
+ frappe.cache().hset("Supplier", "Tags", tags)
- tags = []
- for tag in data:
- tags += filter(bool, tag[0].split(","))
-
- tags = list(set(tags))
-
- return tags
-
+ return frappe.cache().hget("Supplier", "Tags")
diff --git a/erpnext/buying/doctype/supplier/supplier.py b/erpnext/buying/doctype/supplier/supplier.py
index b6d588e..62a04f3 100644
--- a/erpnext/buying/doctype/supplier/supplier.py
+++ b/erpnext/buying/doctype/supplier/supplier.py
@@ -56,3 +56,23 @@
def after_rename(self, olddn, newdn, merge=False):
if frappe.defaults.get_global_default('supp_master_name') == 'Supplier Name':
frappe.db.set(self, "supplier_name", newdn)
+
+ def create_onboarding_docs(self, args):
+ defaults = frappe.defaults.get_defaults()
+ for i in range(1, args.get('max_count')):
+ supplier = args.get('supplier_name_' + str(i))
+ if supplier:
+ try:
+ doc = frappe.get_doc({
+ 'doctype': self.doctype,
+ 'supplier_name': supplier,
+ 'supplier_group': _('Local'),
+ 'company': defaults.get('company')
+ }).insert()
+
+ if args.get('supplier_email_' + str(i)):
+ from erpnext.selling.doctype.customer.customer import create_contact
+ create_contact(supplier, 'Supplier',
+ doc.name, args.get('supplier_email_' + str(i)))
+ except frappe.NameError:
+ pass
\ No newline at end of file
diff --git a/erpnext/buying/doctype/supplier_quotation/supplier_quotation.json b/erpnext/buying/doctype/supplier_quotation/supplier_quotation.json
index b17bed4..82fc628 100644
--- a/erpnext/buying/doctype/supplier_quotation/supplier_quotation.json
+++ b/erpnext/buying/doctype/supplier_quotation/supplier_quotation.json
@@ -1,3060 +1,866 @@
{
- "allow_copy": 0,
- "allow_events_in_timeline": 0,
- "allow_guest_to_view": 0,
- "allow_import": 1,
- "allow_rename": 0,
- "autoname": "naming_series:",
- "beta": 0,
- "creation": "2013-05-21 16:16:45",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "Document",
- "editable_grid": 0,
+ "actions": [],
+ "allow_import": 1,
+ "autoname": "naming_series:",
+ "creation": "2013-05-21 16:16:45",
+ "doctype": "DocType",
+ "document_type": "Document",
+ "engine": "InnoDB",
+ "field_order": [
+ "supplier_section",
+ "title",
+ "naming_series",
+ "supplier",
+ "supplier_name",
+ "column_break1",
+ "transaction_date",
+ "amended_from",
+ "company",
+ "address_section",
+ "supplier_address",
+ "contact_person",
+ "address_display",
+ "contact_display",
+ "contact_mobile",
+ "contact_email",
+ "currency_and_price_list",
+ "currency",
+ "conversion_rate",
+ "cb_price_list",
+ "buying_price_list",
+ "price_list_currency",
+ "plc_conversion_rate",
+ "ignore_pricing_rule",
+ "items_section",
+ "items",
+ "link_to_mrs",
+ "pricing_rule_details",
+ "pricing_rules",
+ "section_break_22",
+ "total_qty",
+ "base_total",
+ "base_net_total",
+ "column_break_24",
+ "total",
+ "net_total",
+ "total_net_weight",
+ "taxes_section",
+ "tax_category",
+ "column_break_36",
+ "shipping_rule",
+ "section_break_38",
+ "taxes_and_charges",
+ "taxes",
+ "tax_breakup",
+ "other_charges_calculation",
+ "totals",
+ "base_taxes_and_charges_added",
+ "base_taxes_and_charges_deducted",
+ "base_total_taxes_and_charges",
+ "column_break_37",
+ "taxes_and_charges_added",
+ "taxes_and_charges_deducted",
+ "total_taxes_and_charges",
+ "section_break_41",
+ "apply_discount_on",
+ "base_discount_amount",
+ "column_break_43",
+ "additional_discount_percentage",
+ "discount_amount",
+ "section_break_46",
+ "base_grand_total",
+ "base_rounding_adjustment",
+ "base_in_words",
+ "base_rounded_total",
+ "column_break4",
+ "grand_total",
+ "rounding_adjustment",
+ "rounded_total",
+ "in_words",
+ "disable_rounded_total",
+ "terms_section_break",
+ "tc_name",
+ "terms",
+ "printing_settings",
+ "select_print_heading",
+ "group_same_items",
+ "column_break_72",
+ "letter_head",
+ "language",
+ "subscription_section",
+ "auto_repeat",
+ "update_auto_repeat_reference",
+ "more_info",
+ "status",
+ "column_break_57",
+ "is_subcontracted",
+ "reference",
+ "opportunity"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "supplier_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": "",
- "length": 0,
- "no_copy": 0,
- "options": "fa fa-user",
- "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
- },
+ "fieldname": "supplier_section",
+ "fieldtype": "Section Break",
+ "options": "fa fa-user"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "{supplier_name}",
- "fieldname": "title",
- "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": "Title",
- "length": 0,
- "no_copy": 1,
- "permlevel": 0,
- "precision": "",
- "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
- },
+ "default": "{supplier_name}",
+ "fieldname": "title",
+ "fieldtype": "Data",
+ "hidden": 1,
+ "label": "Title",
+ "no_copy": 1,
+ "print_hide": 1,
+ "report_hide": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "",
- "fieldname": "naming_series",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Series",
- "length": 0,
- "no_copy": 1,
- "oldfieldname": "naming_series",
- "oldfieldtype": "Select",
- "options": "PUR-SQTN-.YYYY.-",
- "permlevel": 0,
- "print_hide": 1,
- "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": 1,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "naming_series",
+ "fieldtype": "Select",
+ "label": "Series",
+ "no_copy": 1,
+ "oldfieldname": "naming_series",
+ "oldfieldtype": "Select",
+ "options": "PUR-SQTN-.YYYY.-",
+ "print_hide": 1,
+ "reqd": 1,
+ "set_only_once": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 1,
- "collapsible": 0,
- "columns": 0,
- "description": "",
- "fieldname": "supplier",
- "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": 1,
- "label": "Supplier",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "supplier",
- "oldfieldtype": "Link",
- "options": "Supplier",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 1,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "bold": 1,
+ "fieldname": "supplier",
+ "fieldtype": "Link",
+ "in_standard_filter": 1,
+ "label": "Supplier",
+ "oldfieldname": "supplier",
+ "oldfieldtype": "Link",
+ "options": "Supplier",
+ "print_hide": 1,
+ "reqd": 1,
+ "search_index": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 1,
- "collapsible": 0,
- "columns": 0,
- "fetch_from": "supplier.supplier_name",
- "fieldname": "supplier_name",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 1,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Name",
- "length": 0,
- "no_copy": 0,
- "options": "",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "bold": 1,
+ "fetch_from": "supplier.supplier_name",
+ "fieldname": "supplier_name",
+ "fieldtype": "Data",
+ "in_global_search": 1,
+ "label": "Name",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break1",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "oldfieldtype": "Column Break",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "print_width": "50%",
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
+ "fieldname": "column_break1",
+ "fieldtype": "Column Break",
+ "oldfieldtype": "Column Break",
+ "print_width": "50%",
"width": "50%"
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "Today",
- "fieldname": "transaction_date",
- "fieldtype": "Date",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Date",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "transaction_date",
- "oldfieldtype": "Date",
- "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": 1,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "default": "Today",
+ "fieldname": "transaction_date",
+ "fieldtype": "Date",
+ "label": "Date",
+ "oldfieldname": "transaction_date",
+ "oldfieldtype": "Date",
+ "reqd": 1,
+ "search_index": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "amended_from",
- "fieldtype": "Link",
- "hidden": 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": "Amended From",
- "length": 0,
- "no_copy": 1,
- "oldfieldname": "amended_from",
- "oldfieldtype": "Data",
- "options": "Supplier Quotation",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "amended_from",
+ "fieldtype": "Link",
+ "hidden": 1,
+ "ignore_user_permissions": 1,
+ "label": "Amended From",
+ "no_copy": 1,
+ "oldfieldname": "amended_from",
+ "oldfieldtype": "Data",
+ "options": "Supplier Quotation",
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "",
- "fieldname": "company",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 1,
- "label": "Company",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "company",
- "oldfieldtype": "Link",
- "options": "Company",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 1,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 1,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "in_standard_filter": 1,
+ "label": "Company",
+ "oldfieldname": "company",
+ "oldfieldtype": "Link",
+ "options": "Company",
+ "print_hide": 1,
+ "remember_last_selected_value": 1,
+ "reqd": 1,
+ "search_index": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "columns": 0,
- "fieldname": "address_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": "Address and Contact",
- "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
- },
+ "collapsible": 1,
+ "fieldname": "address_section",
+ "fieldtype": "Section Break",
+ "label": "Address and Contact"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "supplier_address",
- "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": "Supplier Address",
- "length": 0,
- "no_copy": 0,
- "options": "Address",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "supplier_address",
+ "fieldtype": "Link",
+ "label": "Supplier Address",
+ "options": "Address",
+ "print_hide": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "contact_person",
- "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": "Contact Person",
- "length": 0,
- "no_copy": 0,
- "options": "Contact",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "contact_person",
+ "fieldtype": "Link",
+ "label": "Contact Person",
+ "options": "Contact",
+ "print_hide": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "address_display",
- "fieldtype": "Small Text",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Address",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "address_display",
+ "fieldtype": "Small Text",
+ "label": "Address",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "contact_display",
- "fieldtype": "Small Text",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 1,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Contact",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "contact_display",
+ "fieldtype": "Small Text",
+ "in_global_search": 1,
+ "label": "Contact",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "contact_mobile",
- "fieldtype": "Small Text",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Mobile No",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "contact_mobile",
+ "fieldtype": "Small Text",
+ "label": "Mobile No",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "contact_email",
- "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": "Contact Email",
- "length": 0,
- "no_copy": 0,
- "options": "Email",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "contact_email",
+ "fieldtype": "Data",
+ "label": "Contact Email",
+ "options": "Email",
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "columns": 0,
- "fieldname": "currency_and_price_list",
- "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": "Currency and Price List",
- "length": 0,
- "no_copy": 0,
- "options": "fa fa-tag",
- "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
- },
+ "collapsible": 1,
+ "fieldname": "currency_and_price_list",
+ "fieldtype": "Section Break",
+ "label": "Currency and Price List",
+ "options": "fa fa-tag"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "currency",
- "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": "Currency",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "currency",
- "oldfieldtype": "Select",
- "options": "Currency",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "currency",
+ "fieldtype": "Link",
+ "label": "Currency",
+ "oldfieldname": "currency",
+ "oldfieldtype": "Select",
+ "options": "Currency",
+ "print_hide": 1,
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "",
- "fieldname": "conversion_rate",
- "fieldtype": "Float",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Exchange Rate",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "conversion_rate",
- "oldfieldtype": "Currency",
- "permlevel": 0,
- "precision": "9",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "conversion_rate",
+ "fieldtype": "Float",
+ "label": "Exchange Rate",
+ "oldfieldname": "conversion_rate",
+ "oldfieldtype": "Currency",
+ "precision": "9",
+ "print_hide": 1,
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "cb_price_list",
- "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,
- "print_width": "50%",
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
+ "fieldname": "cb_price_list",
+ "fieldtype": "Column Break",
+ "print_width": "50%",
"width": "50%"
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "buying_price_list",
- "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": "Price List",
- "length": 0,
- "no_copy": 0,
- "options": "Price List",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "buying_price_list",
+ "fieldtype": "Link",
+ "label": "Price List",
+ "options": "Price List",
+ "print_hide": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "buying_price_list",
- "fieldname": "price_list_currency",
- "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": "Price List Currency",
- "length": 0,
- "no_copy": 0,
- "options": "Currency",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "depends_on": "buying_price_list",
+ "fieldname": "price_list_currency",
+ "fieldtype": "Link",
+ "label": "Price List Currency",
+ "options": "Currency",
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "buying_price_list",
- "fieldname": "plc_conversion_rate",
- "fieldtype": "Float",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Price List Exchange Rate",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "9",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "depends_on": "buying_price_list",
+ "fieldname": "plc_conversion_rate",
+ "fieldtype": "Float",
+ "label": "Price List Exchange Rate",
+ "precision": "9",
+ "print_hide": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "ignore_pricing_rule",
- "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": "Ignore Pricing Rule",
- "length": 0,
- "no_copy": 1,
- "permlevel": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "default": "0",
+ "fieldname": "ignore_pricing_rule",
+ "fieldtype": "Check",
+ "label": "Ignore Pricing Rule",
+ "no_copy": 1,
+ "permlevel": 1,
+ "print_hide": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "items_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": "",
- "length": 0,
- "no_copy": 0,
- "oldfieldtype": "Section Break",
- "options": "fa fa-shopping-cart",
- "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
- },
+ "fieldname": "items_section",
+ "fieldtype": "Section Break",
+ "oldfieldtype": "Section Break",
+ "options": "fa fa-shopping-cart"
+ },
{
- "allow_bulk_edit": 1,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "items",
- "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": "Items",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "po_details",
- "oldfieldtype": "Table",
- "options": "Supplier Quotation Item",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "allow_bulk_edit": 1,
+ "fieldname": "items",
+ "fieldtype": "Table",
+ "label": "Items",
+ "oldfieldname": "po_details",
+ "oldfieldtype": "Table",
+ "options": "Supplier Quotation Item",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:doc.docstatus===0 && (doc.items && doc.items.length)",
- "fieldname": "link_to_mrs",
- "fieldtype": "Button",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Link to material requests",
- "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
- },
+ "depends_on": "eval:doc.docstatus===0 && (doc.items && doc.items.length)",
+ "fieldname": "link_to_mrs",
+ "fieldtype": "Button",
+ "label": "Link to material requests"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "pricing_rule_details",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Pricing Rules",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "pricing_rule_details",
+ "fieldtype": "Section Break",
+ "label": "Pricing Rules"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "pricing_rules",
- "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": "Pricing Rule Detail",
- "length": 0,
- "no_copy": 0,
- "options": "Pricing Rule Detail",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "pricing_rules",
+ "fieldtype": "Table",
+ "label": "Pricing Rule Detail",
+ "options": "Pricing Rule Detail",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "section_break_22",
- "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,
- "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
- },
+ "fieldname": "section_break_22",
+ "fieldtype": "Section Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "total_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": "Total Quantity",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "total_qty",
+ "fieldtype": "Float",
+ "label": "Total Quantity",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "base_total",
- "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": "Total (Company Currency)",
- "length": 0,
- "no_copy": 0,
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "base_total",
+ "fieldtype": "Currency",
+ "label": "Total (Company Currency)",
+ "options": "Company:company:default_currency",
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "base_net_total",
- "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": "Net Total (Company Currency)",
- "length": 0,
- "no_copy": 1,
- "oldfieldname": "net_total",
- "oldfieldtype": "Currency",
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "base_net_total",
+ "fieldtype": "Currency",
+ "label": "Net Total (Company Currency)",
+ "no_copy": 1,
+ "oldfieldname": "net_total",
+ "oldfieldtype": "Currency",
+ "options": "Company:company:default_currency",
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_24",
- "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
- },
+ "fieldname": "column_break_24",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "total",
- "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": "Total",
- "length": 0,
- "no_copy": 0,
- "options": "currency",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "total",
+ "fieldtype": "Currency",
+ "label": "Total",
+ "options": "currency",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "net_total",
- "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": "Net Total",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "net_total_import",
- "oldfieldtype": "Currency",
- "options": "currency",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "net_total",
+ "fieldtype": "Currency",
+ "label": "Net Total",
+ "oldfieldname": "net_total_import",
+ "oldfieldtype": "Currency",
+ "options": "currency",
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "total_net_weight",
- "fieldtype": "Float",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Total Net Weight",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "total_net_weight",
+ "fieldtype": "Float",
+ "label": "Total Net Weight",
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "taxes_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": "Taxes and Charges",
- "length": 0,
- "no_copy": 0,
- "oldfieldtype": "Section Break",
- "options": "fa fa-money",
- "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
- },
+ "fieldname": "taxes_section",
+ "fieldtype": "Section Break",
+ "label": "Taxes and Charges",
+ "oldfieldtype": "Section Break",
+ "options": "fa fa-money"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "tax_category",
- "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": "Tax Category",
- "length": 0,
- "no_copy": 0,
- "options": "Tax Category",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "tax_category",
+ "fieldtype": "Link",
+ "label": "Tax Category",
+ "options": "Tax Category",
+ "print_hide": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_36",
- "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
- },
+ "fieldname": "column_break_36",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "shipping_rule",
- "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": "Shipping Rule",
- "length": 0,
- "no_copy": 0,
- "options": "Shipping Rule",
- "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
- },
+ "fieldname": "shipping_rule",
+ "fieldtype": "Link",
+ "label": "Shipping Rule",
+ "options": "Shipping Rule"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "section_break_38",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "section_break_38",
+ "fieldtype": "Section Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "",
- "fieldname": "taxes_and_charges",
- "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": "Purchase Taxes and Charges Template",
- "length": 0,
- "no_copy": 1,
- "oldfieldname": "purchase_other_charges",
- "oldfieldtype": "Link",
- "options": "Purchase Taxes and Charges Template",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "taxes_and_charges",
+ "fieldtype": "Link",
+ "label": "Purchase Taxes and Charges Template",
+ "no_copy": 1,
+ "oldfieldname": "purchase_other_charges",
+ "oldfieldtype": "Link",
+ "options": "Purchase Taxes and Charges Template",
+ "print_hide": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "taxes",
- "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": "Purchase Taxes and Charges",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "purchase_tax_details",
- "oldfieldtype": "Table",
- "options": "Purchase Taxes and Charges",
- "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
- },
+ "fieldname": "taxes",
+ "fieldtype": "Table",
+ "label": "Purchase Taxes and Charges",
+ "oldfieldname": "purchase_tax_details",
+ "oldfieldtype": "Table",
+ "options": "Purchase Taxes and Charges"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "columns": 0,
- "fieldname": "tax_breakup",
- "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": "Tax Breakup",
- "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
- },
+ "collapsible": 1,
+ "fieldname": "tax_breakup",
+ "fieldtype": "Section Break",
+ "label": "Tax Breakup"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "other_charges_calculation",
- "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": "Taxes and Charges Calculation",
- "length": 0,
- "no_copy": 1,
- "oldfieldtype": "HTML",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "other_charges_calculation",
+ "fieldtype": "Long Text",
+ "label": "Taxes and Charges Calculation",
+ "no_copy": 1,
+ "oldfieldtype": "HTML",
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "totals",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "",
- "length": 0,
- "no_copy": 0,
- "oldfieldtype": "Section Break",
- "options": "fa fa-money",
- "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
- },
+ "fieldname": "totals",
+ "fieldtype": "Section Break",
+ "oldfieldtype": "Section Break",
+ "options": "fa fa-money"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "base_taxes_and_charges_added",
- "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": "Taxes and Charges Added (Company Currency)",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "other_charges_added",
- "oldfieldtype": "Currency",
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "base_taxes_and_charges_added",
+ "fieldtype": "Currency",
+ "label": "Taxes and Charges Added (Company Currency)",
+ "oldfieldname": "other_charges_added",
+ "oldfieldtype": "Currency",
+ "options": "Company:company:default_currency",
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "base_taxes_and_charges_deducted",
- "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": "Taxes and Charges Deducted (Company Currency)",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "other_charges_deducted",
- "oldfieldtype": "Currency",
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "base_taxes_and_charges_deducted",
+ "fieldtype": "Currency",
+ "label": "Taxes and Charges Deducted (Company Currency)",
+ "oldfieldname": "other_charges_deducted",
+ "oldfieldtype": "Currency",
+ "options": "Company:company:default_currency",
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "base_total_taxes_and_charges",
- "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": "Total Taxes and Charges (Company Currency)",
- "length": 0,
- "no_copy": 1,
- "oldfieldname": "total_tax",
- "oldfieldtype": "Currency",
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "base_total_taxes_and_charges",
+ "fieldtype": "Currency",
+ "label": "Total Taxes and Charges (Company Currency)",
+ "no_copy": 1,
+ "oldfieldname": "total_tax",
+ "oldfieldtype": "Currency",
+ "options": "Company:company:default_currency",
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_37",
- "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
- },
+ "fieldname": "column_break_37",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "taxes_and_charges_added",
- "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": "Taxes and Charges Added",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "other_charges_added_import",
- "oldfieldtype": "Currency",
- "options": "currency",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "taxes_and_charges_added",
+ "fieldtype": "Currency",
+ "label": "Taxes and Charges Added",
+ "oldfieldname": "other_charges_added_import",
+ "oldfieldtype": "Currency",
+ "options": "currency",
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "taxes_and_charges_deducted",
- "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": "Taxes and Charges Deducted",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "other_charges_deducted_import",
- "oldfieldtype": "Currency",
- "options": "currency",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "taxes_and_charges_deducted",
+ "fieldtype": "Currency",
+ "label": "Taxes and Charges Deducted",
+ "oldfieldname": "other_charges_deducted_import",
+ "oldfieldtype": "Currency",
+ "options": "currency",
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "total_taxes_and_charges",
- "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": "Total Taxes and Charges",
- "length": 0,
- "no_copy": 0,
- "options": "currency",
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "total_taxes_and_charges",
+ "fieldtype": "Currency",
+ "label": "Total Taxes and Charges",
+ "options": "currency",
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "collapsible_depends_on": "discount_amount",
- "columns": 0,
- "fieldname": "section_break_41",
- "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": "Additional Discount",
- "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
- },
+ "collapsible": 1,
+ "collapsible_depends_on": "discount_amount",
+ "fieldname": "section_break_41",
+ "fieldtype": "Section Break",
+ "label": "Additional Discount"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "Grand Total",
- "fieldname": "apply_discount_on",
- "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": "Apply Additional Discount On",
- "length": 0,
- "no_copy": 0,
- "options": "\nGrand Total\nNet Total",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "default": "Grand Total",
+ "fieldname": "apply_discount_on",
+ "fieldtype": "Select",
+ "label": "Apply Additional Discount On",
+ "options": "\nGrand Total\nNet Total",
+ "print_hide": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "base_discount_amount",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Additional Discount Amount (Company Currency)",
- "length": 0,
- "no_copy": 0,
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "base_discount_amount",
+ "fieldtype": "Currency",
+ "label": "Additional Discount Amount (Company Currency)",
+ "options": "Company:company:default_currency",
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_43",
- "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
- },
+ "fieldname": "column_break_43",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "additional_discount_percentage",
- "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": "Additional Discount Percentage",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "additional_discount_percentage",
+ "fieldtype": "Float",
+ "label": "Additional Discount Percentage",
+ "print_hide": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "discount_amount",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Additional Discount Amount",
- "length": 0,
- "no_copy": 0,
- "options": "currency",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "discount_amount",
+ "fieldtype": "Currency",
+ "label": "Additional Discount Amount",
+ "options": "currency",
+ "print_hide": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "section_break_46",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "section_break_46",
+ "fieldtype": "Section Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "base_grand_total",
- "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": "Grand Total (Company Currency)",
- "length": 0,
- "no_copy": 1,
- "oldfieldname": "grand_total",
- "oldfieldtype": "Currency",
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "base_grand_total",
+ "fieldtype": "Currency",
+ "label": "Grand Total (Company Currency)",
+ "no_copy": 1,
+ "oldfieldname": "grand_total",
+ "oldfieldtype": "Currency",
+ "options": "Company:company:default_currency",
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "base_rounding_adjustment",
- "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": "Rounding Adjustment (Company Currency",
- "length": 0,
- "no_copy": 1,
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "base_rounding_adjustment",
+ "fieldtype": "Currency",
+ "label": "Rounding Adjustment (Company Currency",
+ "no_copy": 1,
+ "options": "Company:company:default_currency",
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "",
- "fieldname": "base_in_words",
- "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": "In Words (Company Currency)",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "in_words",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "base_in_words",
+ "fieldtype": "Data",
+ "label": "In Words (Company Currency)",
+ "oldfieldname": "in_words",
+ "oldfieldtype": "Data",
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "base_rounded_total",
- "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": "Rounded Total (Company Currency)",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "rounded_total",
- "oldfieldtype": "Currency",
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "base_rounded_total",
+ "fieldtype": "Currency",
+ "label": "Rounded Total (Company Currency)",
+ "oldfieldname": "rounded_total",
+ "oldfieldtype": "Currency",
+ "options": "Company:company:default_currency",
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break4",
- "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,
- "oldfieldtype": "Column Break",
- "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
- },
+ "fieldname": "column_break4",
+ "fieldtype": "Column Break",
+ "oldfieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "grand_total",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Grand Total",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "grand_total_import",
- "oldfieldtype": "Currency",
- "options": "currency",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "grand_total",
+ "fieldtype": "Currency",
+ "in_list_view": 1,
+ "label": "Grand Total",
+ "oldfieldname": "grand_total_import",
+ "oldfieldtype": "Currency",
+ "options": "currency",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "rounding_adjustment",
- "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": "Rounding Adjustment",
- "length": 0,
- "no_copy": 1,
- "options": "currency",
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "rounding_adjustment",
+ "fieldtype": "Currency",
+ "label": "Rounding Adjustment",
+ "no_copy": 1,
+ "options": "currency",
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "rounded_total",
- "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": "Rounded Total",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "rounded_total",
+ "fieldtype": "Currency",
+ "label": "Rounded Total",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "in_words",
- "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": "In Words",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "in_words_import",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "in_words",
+ "fieldtype": "Data",
+ "label": "In Words",
+ "oldfieldname": "in_words_import",
+ "oldfieldtype": "Data",
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "disable_rounded_total",
- "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": "Disable Rounded Total",
- "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
- },
+ "default": "0",
+ "fieldname": "disable_rounded_total",
+ "fieldtype": "Check",
+ "label": "Disable Rounded Total"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "collapsible_depends_on": "terms",
- "columns": 0,
- "fieldname": "terms_section_break",
- "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": "Terms and Conditions",
- "length": 0,
- "no_copy": 0,
- "oldfieldtype": "Section Break",
- "options": "fa fa-legal",
- "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
- },
+ "collapsible": 1,
+ "collapsible_depends_on": "terms",
+ "fieldname": "terms_section_break",
+ "fieldtype": "Section Break",
+ "label": "Terms and Conditions",
+ "oldfieldtype": "Section Break",
+ "options": "fa fa-legal"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "tc_name",
- "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": "Terms",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "tc_name",
- "oldfieldtype": "Link",
- "options": "Terms and Conditions",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "tc_name",
+ "fieldtype": "Link",
+ "label": "Terms",
+ "oldfieldname": "tc_name",
+ "oldfieldtype": "Link",
+ "options": "Terms and Conditions",
+ "print_hide": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "terms",
- "fieldtype": "Text Editor",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Terms and Conditions",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "terms",
- "oldfieldtype": "Text Editor",
- "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
- },
+ "fieldname": "terms",
+ "fieldtype": "Text Editor",
+ "label": "Terms and Conditions",
+ "oldfieldname": "terms",
+ "oldfieldtype": "Text Editor"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "columns": 0,
- "fieldname": "printing_settings",
- "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": "Printing Settings",
- "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
- },
+ "collapsible": 1,
+ "fieldname": "printing_settings",
+ "fieldtype": "Section Break",
+ "label": "Printing Settings"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "select_print_heading",
- "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": "Print Heading",
- "length": 0,
- "no_copy": 1,
- "oldfieldname": "select_print_heading",
- "oldfieldtype": "Link",
- "options": "Print Heading",
- "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
- },
+ "allow_on_submit": 1,
+ "fieldname": "select_print_heading",
+ "fieldtype": "Link",
+ "label": "Print Heading",
+ "no_copy": 1,
+ "oldfieldname": "select_print_heading",
+ "oldfieldtype": "Link",
+ "options": "Print Heading",
+ "print_hide": 1,
+ "report_hide": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "group_same_items",
- "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": "Group same items",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "allow_on_submit": 1,
+ "default": "0",
+ "fieldname": "group_same_items",
+ "fieldtype": "Check",
+ "label": "Group same items",
+ "print_hide": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_72",
- "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
- },
+ "fieldname": "column_break_72",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "letter_head",
- "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": "Letter Head",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "letter_head",
- "oldfieldtype": "Select",
- "options": "Letter Head",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "allow_on_submit": 1,
+ "fieldname": "letter_head",
+ "fieldtype": "Link",
+ "label": "Letter Head",
+ "oldfieldname": "letter_head",
+ "oldfieldtype": "Select",
+ "options": "Letter Head",
+ "print_hide": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "language",
- "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": "Print Language",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "language",
+ "fieldtype": "Data",
+ "label": "Print Language",
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "subscription_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": "Auto Repeat Section",
- "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
- },
+ "fieldname": "subscription_section",
+ "fieldtype": "Section Break",
+ "label": "Auto Repeat Section"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "auto_repeat",
- "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": "Auto Repeat",
- "length": 0,
- "no_copy": 1,
- "options": "Auto Repeat",
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "auto_repeat",
+ "fieldtype": "Link",
+ "label": "Auto Repeat",
+ "no_copy": 1,
+ "options": "Auto Repeat",
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval: doc.auto_repeat",
- "fieldname": "update_auto_repeat_reference",
- "fieldtype": "Button",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Update Auto Repeat Reference",
- "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
- },
+ "allow_on_submit": 1,
+ "depends_on": "eval: doc.auto_repeat",
+ "fieldname": "update_auto_repeat_reference",
+ "fieldtype": "Button",
+ "label": "Update Auto Repeat Reference"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "columns": 0,
- "fieldname": "more_info",
- "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": "More Information",
- "length": 0,
- "no_copy": 0,
- "oldfieldtype": "Section Break",
- "options": "fa fa-file-text",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "collapsible": 1,
+ "fieldname": "more_info",
+ "fieldtype": "Section Break",
+ "label": "More Information",
+ "oldfieldtype": "Section Break",
+ "options": "fa fa-file-text"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "status",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Status",
- "length": 0,
- "no_copy": 1,
- "oldfieldname": "status",
- "oldfieldtype": "Select",
- "options": "\nDraft\nSubmitted\nStopped\nCancelled",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 1,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "status",
+ "fieldtype": "Select",
+ "label": "Status",
+ "no_copy": 1,
+ "oldfieldname": "status",
+ "oldfieldtype": "Select",
+ "options": "\nDraft\nSubmitted\nStopped\nCancelled",
+ "print_hide": 1,
+ "read_only": 1,
+ "reqd": 1,
+ "search_index": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_57",
- "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
- },
+ "fieldname": "column_break_57",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "No",
- "fieldname": "is_subcontracted",
- "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": "Is Subcontracted",
- "length": 0,
- "no_copy": 0,
- "options": "\nYes\nNo",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "default": "No",
+ "fieldname": "is_subcontracted",
+ "fieldtype": "Select",
+ "label": "Is Subcontracted",
+ "options": "\nYes\nNo",
+ "print_hide": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "reference",
- "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": "Reference",
- "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
- },
+ "fieldname": "reference",
+ "fieldtype": "Section Break",
+ "label": "Reference"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "opportunity",
- "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": "Opportunity",
- "length": 0,
- "no_copy": 1,
- "options": "Opportunity",
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "fieldname": "opportunity",
+ "fieldtype": "Link",
+ "label": "Opportunity",
+ "no_copy": 1,
+ "options": "Opportunity",
+ "print_hide": 1,
+ "read_only": 1
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "icon": "fa fa-shopping-cart",
- "idx": 29,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 1,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "menu_index": 0,
- "modified": "2019-02-13 00:52:28.602904",
- "modified_by": "Administrator",
- "module": "Buying",
- "name": "Supplier Quotation",
- "owner": "Administrator",
+ ],
+ "icon": "fa fa-shopping-cart",
+ "idx": 29,
+ "is_submittable": 1,
+ "links": [],
+ "modified": "2019-12-30 19:17:28.208693",
+ "modified_by": "Administrator",
+ "module": "Buying",
+ "name": "Supplier Quotation",
+ "owner": "Administrator",
"permissions": [
{
- "amend": 1,
- "cancel": 1,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Manufacturing Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 1,
+ "amend": 1,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Manufacturing Manager",
+ "share": 1,
+ "submit": 1,
"write": 1
- },
+ },
{
- "amend": 1,
- "cancel": 1,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Purchase Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 1,
+ "amend": 1,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Purchase Manager",
+ "share": 1,
+ "submit": 1,
"write": 1
- },
+ },
{
- "amend": 1,
- "cancel": 0,
- "create": 1,
- "delete": 0,
- "email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Purchase User",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 1,
+ "amend": 1,
+ "create": 1,
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Purchase User",
+ "share": 1,
+ "submit": 1,
"write": 1
- },
+ },
{
- "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": "Stock User",
- "set_user_permissions": 0,
- "share": 0,
- "submit": 0,
- "write": 0
- },
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Stock 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": "Purchase Manager",
- "set_user_permissions": 0,
- "share": 0,
- "submit": 0,
+ "permlevel": 1,
+ "read": 1,
+ "role": "Purchase Manager",
"write": 1
}
- ],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 1,
- "search_fields": "status, transaction_date, supplier,grand_total",
- "show_name_in_global_search": 1,
- "sort_field": "modified",
- "sort_order": "DESC",
- "timeline_field": "supplier",
- "title_field": "title",
- "track_changes": 0,
- "track_seen": 0,
- "track_views": 0
-}
+ ],
+ "search_fields": "status, transaction_date, supplier,grand_total",
+ "show_name_in_global_search": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "timeline_field": "supplier",
+ "title_field": "title"
+}
\ No newline at end of file
diff --git a/erpnext/buying/doctype/supplier_scorecard/supplier_scorecard.py b/erpnext/buying/doctype/supplier_scorecard/supplier_scorecard.py
index 9e201e3..af109ba 100644
--- a/erpnext/buying/doctype/supplier_scorecard/supplier_scorecard.py
+++ b/erpnext/buying/doctype/supplier_scorecard/supplier_scorecard.py
@@ -138,7 +138,7 @@
# Check to see if any new scorecard periods are created
if make_all_scorecards(sc.name) > 0:
# Save the scorecard to update the score and standings
- sc.save()
+ frappe.get_doc('Supplier Scorecard', sc.name).save()
@frappe.whitelist()
diff --git a/erpnext/buying/onboarding_slide/add_a_few_suppliers/add_a_few_suppliers.json b/erpnext/buying/onboarding_slide/add_a_few_suppliers/add_a_few_suppliers.json
new file mode 100644
index 0000000..ce3d8cf
--- /dev/null
+++ b/erpnext/buying/onboarding_slide/add_a_few_suppliers/add_a_few_suppliers.json
@@ -0,0 +1,49 @@
+{
+ "add_more_button": 1,
+ "app": "ERPNext",
+ "creation": "2019-11-15 14:45:32.626641",
+ "docstatus": 0,
+ "doctype": "Onboarding Slide",
+ "domains": [],
+ "help_links": [
+ {
+ "label": "Learn More",
+ "video_id": "zsrrVDk6VBs"
+ }
+ ],
+ "idx": 0,
+ "image_src": "",
+ "is_completed": 0,
+ "max_count": 3,
+ "modified": "2019-12-09 17:54:18.452038",
+ "modified_by": "Administrator",
+ "name": "Add A Few Suppliers",
+ "owner": "Administrator",
+ "ref_doctype": "Supplier",
+ "slide_desc": "",
+ "slide_fields": [
+ {
+ "align": "",
+ "fieldname": "supplier_name",
+ "fieldtype": "Data",
+ "label": "Supplier Name",
+ "placeholder": "",
+ "reqd": 1
+ },
+ {
+ "align": "",
+ "fieldtype": "Column Break",
+ "reqd": 0
+ },
+ {
+ "align": "",
+ "fieldname": "supplier_email",
+ "fieldtype": "Data",
+ "label": "Supplier Email",
+ "reqd": 1
+ }
+ ],
+ "slide_order": 50,
+ "slide_title": "Add A Few Suppliers",
+ "slide_type": "Create"
+}
\ No newline at end of file
diff --git a/erpnext/buying/utils.py b/erpnext/buying/utils.py
index 8c0a1e5..b5598f8 100644
--- a/erpnext/buying/utils.py
+++ b/erpnext/buying/utils.py
@@ -24,12 +24,12 @@
last_purchase_rate = None
if last_purchase_details and \
(last_purchase_details.purchase_date > this_purchase_date):
- last_purchase_rate = last_purchase_details['base_rate']
+ last_purchase_rate = last_purchase_details['base_net_rate']
elif is_submit == 1:
# even if this transaction is the latest one, it should be submitted
# for it to be considered for latest purchase rate
if flt(d.conversion_factor):
- last_purchase_rate = flt(d.base_rate) / flt(d.conversion_factor)
+ last_purchase_rate = flt(d.base_net_rate) / flt(d.conversion_factor)
# Check if item code is present
# Conversion factor should not be mandatory for non itemized items
elif d.item_code:
diff --git a/erpnext/change_log/v12/v12_2_0.md b/erpnext/change_log/v12/v12_2_0.md
new file mode 100644
index 0000000..0ec0eec
--- /dev/null
+++ b/erpnext/change_log/v12/v12_2_0.md
@@ -0,0 +1,14 @@
+# Version 12.2.0 Release Notes
+
+### Accounting
+
+1. Fixed Asset
+ - "Enable CWIP" options moved to Asset Category from Asset Settings
+ - Removed Asset link from Purchase Receipt Item table
+ - Enhanced Asset master
+ - Asset Movement now handles movement of multiple assets
+ - Introduced monthly depreciation
+2. GL Entries for Landed Cost Voucher now posted directly against individual Charges account
+3. Optimization of BOM Update Tool
+4. Syncing of Stock and Account balance is enforced, in case of perpetual inventory
+5. Rendered email template in Email Campaign
diff --git a/erpnext/config/accounts.py b/erpnext/config/accounts.py
index ab75f21..08711fc 100644
--- a/erpnext/config/accounts.py
+++ b/erpnext/config/accounts.py
@@ -197,6 +197,11 @@
"name": "Bank Reconciliation Statement",
"is_query_report": True,
"doctype": "Journal Entry"
+ },{
+ "type": "page",
+ "name": "bank-reconciliation",
+ "label": _("Bank Reconciliation"),
+ "icon": "fa fa-bar-chart"
},
{
"type": "report",
diff --git a/erpnext/config/assets.py b/erpnext/config/assets.py
index 3c9452f..4cf7cf0 100644
--- a/erpnext/config/assets.py
+++ b/erpnext/config/assets.py
@@ -23,10 +23,6 @@
},
{
"type": "doctype",
- "name": "Asset Settings",
- },
- {
- "type": "doctype",
"name": "Asset Movement",
"description": _("Transfer an asset from one warehouse to another")
},
diff --git a/erpnext/config/crm.py b/erpnext/config/crm.py
index eba6c7a..cf10219 100644
--- a/erpnext/config/crm.py
+++ b/erpnext/config/crm.py
@@ -46,6 +46,16 @@
"name": "Contract",
"description": _("Helps you keep tracks of Contracts based on Supplier, Customer and Employee"),
},
+ {
+ "type": "doctype",
+ "name": "Appointment",
+ "description" : _("Helps you manage appointments with your leads"),
+ },
+ {
+ "type": "doctype",
+ "name": "Newsletter",
+ "label": _("Newsletter"),
+ }
]
},
{
@@ -165,6 +175,11 @@
"type": "doctype",
"name": "SMS Settings",
"description": _("Setup SMS gateway settings")
+ },
+ {
+ "type": "doctype",
+ "label": _("Email Group"),
+ "name": "Email Group",
}
]
},
diff --git a/erpnext/config/stock.py b/erpnext/config/stock.py
index 441a3ab..03e26b2 100644
--- a/erpnext/config/stock.py
+++ b/erpnext/config/stock.py
@@ -241,6 +241,10 @@
"type": "doctype",
"name": "Quality Inspection Template",
},
+ {
+ "type": "doctype",
+ "name": "Quick Stock Balance",
+ },
]
},
{
@@ -332,6 +336,18 @@
"is_query_report": True,
"name": "Item Variant Details",
"doctype": "Item"
+ },
+ {
+ "type": "report",
+ "is_query_report": True,
+ "name": "Subcontracted Raw Materials To Be Transferred",
+ "doctype": "Purchase Order"
+ },
+ {
+ "type": "report",
+ "is_query_report": True,
+ "name": "Subcontracted Item To Be Received",
+ "doctype": "Purchase Order"
}
]
},
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index 320a618..7faf792 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -5,15 +5,17 @@
import frappe, erpnext
import json
from frappe import _, throw
-from frappe.utils import today, flt, cint, fmt_money, formatdate, getdate, add_days, add_months, get_last_day, nowdate
-from erpnext.stock.get_item_details import get_conversion_factor
+from frappe.utils import (today, flt, cint, fmt_money, formatdate,
+ getdate, add_days, add_months, get_last_day, nowdate, get_link_to_form)
+from erpnext.stock.get_item_details import get_conversion_factor, get_item_details
from erpnext.setup.utils import get_exchange_rate
from erpnext.accounts.utils import get_fiscal_years, validate_fiscal_year, get_account_currency
from erpnext.utilities.transaction_base import TransactionBase
from erpnext.buying.utils import update_last_purchase_rate
from erpnext.controllers.sales_and_purchase_return import validate_return
from erpnext.accounts.party import get_party_account_currency, validate_party_frozen_disabled
-from erpnext.accounts.doctype.pricing_rule.utils import validate_pricing_rules
+from erpnext.accounts.doctype.pricing_rule.utils import (apply_pricing_rule_on_transaction,
+ apply_pricing_rule_for_free_items, get_applied_pricing_rules)
from erpnext.exceptions import InvalidCurrency
from six import text_type
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions
@@ -59,7 +61,6 @@
_('{0} is blocked so this transaction cannot proceed'.format(supplier_name)), raise_exception=1)
def validate(self):
-
if not self.get('is_return'):
self.validate_qty_is_not_zero()
@@ -98,10 +99,22 @@
if self.is_return:
self.validate_qty()
+ else:
+ self.validate_deferred_start_and_end_date()
validate_regional(self)
if self.doctype != 'Material Request':
- validate_pricing_rules(self)
+ apply_pricing_rule_on_transaction(self)
+
+ def validate_deferred_start_and_end_date(self):
+ for d in self.items:
+ if d.get("enable_deferred_revenue") or d.get("enable_deferred_expense"):
+ if not (d.service_start_date and d.service_end_date):
+ frappe.throw(_("Row #{0}: Service Start and End Date is required for deferred accounting").format(d.idx))
+ elif getdate(d.service_start_date) > getdate(d.service_end_date):
+ frappe.throw(_("Row #{0}: Service Start Date cannot be greater than Service End Date").format(d.idx))
+ elif getdate(self.posting_date) > getdate(d.service_end_date):
+ frappe.throw(_("Row #{0}: Service End Date cannot be before Invoice Posting Date").format(d.idx))
def validate_invoice_documents_schedule(self):
self.validate_payment_schedule_dates()
@@ -232,7 +245,6 @@
def set_missing_item_details(self, for_validate=False):
"""set missing item values"""
- from erpnext.stock.get_item_details import get_item_details
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
if hasattr(self, "items"):
@@ -244,7 +256,6 @@
document_type = "{} Item".format(self.doctype)
parent_dict.update({"document_type": document_type})
- self.set('pricing_rules', [])
# party_name field used for customer in quotation
if self.doctype == "Quotation" and self.quotation_to == "Customer" and parent_dict.get("party_name"):
parent_dict.update({"customer": parent_dict.get("party_name")})
@@ -264,7 +275,7 @@
if self.get("is_subcontracted"):
args["is_subcontracted"] = self.is_subcontracted
- ret = get_item_details(args, self, overwrite_warehouse=False)
+ ret = get_item_details(args, self, for_validate=True, overwrite_warehouse=False)
for fieldname, value in ret.items():
if item.meta.get_field(fieldname) and value is not None:
@@ -285,24 +296,42 @@
if self.doctype in ["Purchase Invoice", "Sales Invoice"] and item.meta.get_field('is_fixed_asset'):
item.set('is_fixed_asset', ret.get('is_fixed_asset', 0))
- if ret.get("pricing_rules") and not ret.get("validate_applied_rule", 0):
- # if user changed the discount percentage then set user's discount percentage ?
- item.set("pricing_rules", ret.get("pricing_rules"))
- item.set("discount_percentage", ret.get("discount_percentage"))
- item.set("discount_amount", ret.get("discount_amount"))
- if ret.get("pricing_rule_for") == "Rate":
- item.set("price_list_rate", ret.get("price_list_rate"))
-
- if item.get("price_list_rate"):
- item.rate = flt(item.price_list_rate *
- (1.0 - (flt(item.discount_percentage) / 100.0)), item.precision("rate"))
-
- if item.get('discount_amount'):
- item.rate = item.price_list_rate - item.discount_amount
+ if ret.get("pricing_rules"):
+ self.apply_pricing_rule_on_items(item, ret)
if self.doctype == "Purchase Invoice":
self.set_expense_account(for_validate)
+ def apply_pricing_rule_on_items(self, item, pricing_rule_args):
+ if not pricing_rule_args.get("validate_applied_rule", 0):
+ # if user changed the discount percentage then set user's discount percentage ?
+ if pricing_rule_args.get("price_or_product_discount") == 'Price':
+ item.set("pricing_rules", pricing_rule_args.get("pricing_rules"))
+ item.set("discount_percentage", pricing_rule_args.get("discount_percentage"))
+ item.set("discount_amount", pricing_rule_args.get("discount_amount"))
+ if pricing_rule_args.get("pricing_rule_for") == "Rate":
+ item.set("price_list_rate", pricing_rule_args.get("price_list_rate"))
+
+ if item.get("price_list_rate"):
+ item.rate = flt(item.price_list_rate *
+ (1.0 - (flt(item.discount_percentage) / 100.0)), item.precision("rate"))
+
+ if item.get('discount_amount'):
+ item.rate = item.price_list_rate - item.discount_amount
+
+ elif pricing_rule_args.get('free_item_data'):
+ apply_pricing_rule_for_free_items(self, pricing_rule_args.get('free_item_data'))
+
+ elif pricing_rule_args.get("validate_applied_rule"):
+ for pricing_rule in get_applied_pricing_rules(item):
+ pricing_rule_doc = frappe.get_cached_doc("Pricing Rule", pricing_rule)
+ for field in ['discount_percentage', 'discount_amount', 'rate']:
+ if item.get(field) < pricing_rule_doc.get(field):
+ title = get_link_to_form("Pricing Rule", pricing_rule)
+
+ frappe.msgprint(_("Row {0}: user has not applied the rule {1} on the item {2}")
+ .format(item.idx, frappe.bold(title), frappe.bold(item.item_code)))
+
def set_taxes(self):
if not self.meta.get_field("taxes"):
return
@@ -397,9 +426,10 @@
return gl_dict
def validate_qty_is_not_zero(self):
- for item in self.items:
- if not item.qty:
- frappe.throw(_("Item quantity can not be zero"))
+ if self.doctype != "Purchase Receipt":
+ for item in self.items:
+ if not item.qty:
+ frappe.throw(_("Item quantity can not be zero"))
def validate_account_currency(self, account, account_currency=None):
valid_currency = [self.company_currency]
@@ -718,48 +748,6 @@
# at quotation / sales order level and we shouldn't stop someone
# from creating a sales invoice if sales order is already created
- def validate_fixed_asset(self):
- for d in self.get("items"):
- if d.is_fixed_asset:
- # if d.qty > 1:
- # frappe.throw(_("Row #{0}: Qty must be 1, as item is a fixed asset. Please use separate row for multiple qty.").format(d.idx))
-
- if d.meta.get_field("asset") and d.asset:
- asset = frappe.get_doc("Asset", d.asset)
-
- if asset.company != self.company:
- frappe.throw(_("Row #{0}: Asset {1} does not belong to company {2}")
- .format(d.idx, d.asset, self.company))
-
- elif asset.item_code != d.item_code:
- frappe.throw(_("Row #{0}: Asset {1} does not linked to Item {2}")
- .format(d.idx, d.asset, d.item_code))
-
- # elif asset.docstatus != 1:
- # frappe.throw(_("Row #{0}: Asset {1} must be submitted").format(d.idx, d.asset))
-
- elif self.doctype == "Purchase Invoice":
- # if asset.status != "Submitted":
- # frappe.throw(_("Row #{0}: Asset {1} is already {2}")
- # .format(d.idx, d.asset, asset.status))
- if getdate(asset.purchase_date) != getdate(self.posting_date):
- frappe.throw(
- _("Row #{0}: Posting Date must be same as purchase date {1} of asset {2}").format(d.idx,
- asset.purchase_date,
- d.asset))
- elif asset.is_existing_asset:
- frappe.throw(
- _("Row #{0}: Purchase Invoice cannot be made against an existing asset {1}").format(
- d.idx, d.asset))
-
- elif self.docstatus == "Sales Invoice" and self.docstatus == 1:
- if self.update_stock:
- frappe.throw(_("'Update Stock' cannot be checked for fixed asset sale"))
-
- elif asset.status in ("Scrapped", "Cancelled", "Sold"):
- frappe.throw(_("Row #{0}: Asset {1} cannot be submitted, it is already {2}")
- .format(d.idx, d.asset, asset.status))
-
def delink_advance_entries(self, linked_doc_name):
total_allocated_amount = 0
for adv in self.advances:
@@ -1167,13 +1155,40 @@
child_item.base_amount = 1 # Initiallize value will update in parent validation
return child_item
+def check_and_delete_children(parent, data):
+ deleted_children = []
+ updated_item_names = [d.get("docname") for d in data]
+ for item in parent.items:
+ if item.name not in updated_item_names:
+ deleted_children.append(item)
+
+ for d in deleted_children:
+ if parent.doctype == "Sales Order":
+ if flt(d.delivered_qty):
+ frappe.throw(_("Row #{0}: Cannot delete item {1} which has already been delivered").format(d.idx, d.item_code))
+ if flt(d.work_order_qty):
+ frappe.throw(_("Row #{0}: Cannot delete item {1} which has work order assigned to it.").format(d.idx, d.item_code))
+ if flt(d.ordered_qty):
+ frappe.throw(_("Row #{0}: Cannot delete item {1} which is assigned to customer's purchase order.").format(d.idx, d.item_code))
+
+ if parent.doctype == "Purchase Order" and flt(d.received_qty):
+ frappe.throw(_("Row #{0}: Cannot delete item {1} which has already been received").format(d.idx, d.item_code))
+
+ if flt(d.billed_amt):
+ frappe.throw(_("Row #{0}: Cannot delete item {1} which has already been billed.").format(d.idx, d.item_code))
+
+ d.cancel()
+ d.delete()
@frappe.whitelist()
def update_child_qty_rate(parent_doctype, trans_items, parent_doctype_name, child_docname="items"):
data = json.loads(trans_items)
+ sales_doctypes = ['Sales Order', 'Sales Invoice', 'Delivery Note', 'Quotation']
parent = frappe.get_doc(parent_doctype, parent_doctype_name)
+ check_and_delete_children(parent, data)
+
for d in data:
new_child_flag = False
if not d.get("docname"):
@@ -1192,8 +1207,9 @@
frappe.throw(_("Cannot set quantity less than received quantity"))
child_item.qty = flt(d.get("qty"))
+ precision = child_item.precision("rate") or 2
- if flt(child_item.billed_amt) > (flt(d.get("rate")) * flt(d.get("qty"))):
+ if flt(child_item.billed_amt, precision) > flt(flt(d.get("rate")) * flt(d.get("qty")), precision):
frappe.throw(_("Row #{0}: Cannot set Rate if amount is greater than billed amount for Item {1}.")
.format(child_item.idx, child_item.item_code))
else:
@@ -1204,18 +1220,22 @@
# if rate is greater than price_list_rate, set margin
# or set discount
child_item.discount_percentage = 0
- child_item.margin_type = "Amount"
- child_item.margin_rate_or_amount = flt(child_item.rate - child_item.price_list_rate,
- child_item.precision("margin_rate_or_amount"))
- child_item.rate_with_margin = child_item.rate
+
+ if parent_doctype in sales_doctypes:
+ child_item.margin_type = "Amount"
+ child_item.margin_rate_or_amount = flt(child_item.rate - child_item.price_list_rate,
+ child_item.precision("margin_rate_or_amount"))
+ child_item.rate_with_margin = child_item.rate
else:
child_item.discount_percentage = flt((1 - flt(child_item.rate) / flt(child_item.price_list_rate)) * 100.0,
child_item.precision("discount_percentage"))
child_item.discount_amount = flt(
child_item.price_list_rate) - flt(child_item.rate)
- child_item.margin_type = ""
- child_item.margin_rate_or_amount = 0
- child_item.rate_with_margin = 0
+
+ if parent_doctype in sales_doctypes:
+ child_item.margin_type = ""
+ child_item.margin_rate_or_amount = 0
+ child_item.rate_with_margin = 0
child_item.flags.ignore_validate_update_after_submit = True
if new_child_flag:
diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py
index 0dde898..75b896b 100644
--- a/erpnext/controllers/buying_controller.py
+++ b/erpnext/controllers/buying_controller.py
@@ -101,7 +101,7 @@
msgprint(_('Tax Category has been changed to "Total" because all the Items are non-stock items'))
def get_asset_items(self):
- if self.doctype not in ['Purchase Invoice', 'Purchase Receipt']:
+ if self.doctype not in ['Purchase Order', 'Purchase Invoice', 'Purchase Receipt']:
return []
return [d.item_code for d in self.items if d.is_fixed_asset]
@@ -150,25 +150,26 @@
TODO: rename item_tax_amount to valuation_tax_amount
"""
- stock_items = self.get_stock_items() + self.get_asset_items()
+ stock_and_asset_items = self.get_stock_items() + self.get_asset_items()
- stock_items_qty, stock_items_amount = 0, 0
- last_stock_item_idx = 1
+ stock_and_asset_items_qty, stock_and_asset_items_amount = 0, 0
+ last_item_idx = 1
for d in self.get(parentfield):
- if d.item_code and d.item_code in stock_items:
- stock_items_qty += flt(d.qty)
- stock_items_amount += flt(d.base_net_amount)
- last_stock_item_idx = d.idx
+ if d.item_code and d.item_code in stock_and_asset_items:
+ stock_and_asset_items_qty += flt(d.qty)
+ stock_and_asset_items_amount += flt(d.base_net_amount)
+ last_item_idx = d.idx
total_valuation_amount = sum([flt(d.base_tax_amount_after_discount_amount) for d in self.get("taxes")
if d.category in ["Valuation", "Valuation and Total"]])
valuation_amount_adjustment = total_valuation_amount
for i, item in enumerate(self.get(parentfield)):
- if item.item_code and item.qty and item.item_code in stock_items:
- item_proportion = flt(item.base_net_amount) / stock_items_amount if stock_items_amount \
- else flt(item.qty) / stock_items_qty
- if i == (last_stock_item_idx - 1):
+ if item.item_code and item.qty and item.item_code in stock_and_asset_items:
+ item_proportion = flt(item.base_net_amount) / stock_and_asset_items_amount if stock_and_asset_items_amount \
+ else flt(item.qty) / stock_and_asset_items_qty
+
+ if i == (last_item_idx - 1):
item.item_tax_amount = flt(valuation_amount_adjustment,
self.precision("item_tax_amount", item))
else:
@@ -220,7 +221,7 @@
"backflush_raw_materials_of_subcontract_based_on")
if (self.doctype == 'Purchase Receipt' and
backflush_raw_materials_based_on != 'BOM'):
- self.update_raw_materials_supplied_based_on_stock_entries(raw_material_table)
+ self.update_raw_materials_supplied_based_on_stock_entries()
else:
for item in self.get("items"):
if self.doctype in ["Purchase Receipt", "Purchase Invoice"]:
@@ -240,41 +241,96 @@
if self.is_subcontracted == "No" and self.get("supplied_items"):
self.set('supplied_items', [])
- def update_raw_materials_supplied_based_on_stock_entries(self, raw_material_table):
- self.set(raw_material_table, [])
- purchase_orders = [d.purchase_order for d in self.items]
- if purchase_orders:
- items = get_subcontracted_raw_materials_from_se(purchase_orders)
- backflushed_raw_materials = get_backflushed_subcontracted_raw_materials_from_se(purchase_orders, self.name)
+ def update_raw_materials_supplied_based_on_stock_entries(self):
+ self.set('supplied_items', [])
- for d in items:
- qty = d.qty - backflushed_raw_materials.get(d.item_code, 0)
- rm = self.append(raw_material_table, {})
- rm.rm_item_code = d.item_code
- rm.item_name = d.item_name
- rm.main_item_code = d.main_item_code
- rm.description = d.description
- rm.stock_uom = d.stock_uom
- rm.required_qty = qty
- rm.consumed_qty = qty
- rm.serial_no = d.serial_no
- rm.batch_no = d.batch_no
+ purchase_orders = set([d.purchase_order for d in self.items])
- # get raw materials rate
- from erpnext.stock.utils import get_incoming_rate
- rm.rate = get_incoming_rate({
- "item_code": d.item_code,
- "warehouse": self.supplier_warehouse,
- "posting_date": self.posting_date,
- "posting_time": self.posting_time,
- "qty": -1 * qty,
- "serial_no": rm.serial_no
- })
- if not rm.rate:
- rm.rate = get_valuation_rate(d.item_code, self.supplier_warehouse,
- self.doctype, self.name, currency=self.company_currency, company = self.company)
+ # qty of raw materials backflushed (for each item per purchase order)
+ backflushed_raw_materials_map = get_backflushed_subcontracted_raw_materials(purchase_orders)
- rm.amount = qty * flt(rm.rate)
+ # qty of "finished good" item yet to be received
+ qty_to_be_received_map = get_qty_to_be_received(purchase_orders)
+
+ for item in self.get('items'):
+ # reset raw_material cost
+ item.rm_supp_cost = 0
+
+ # qty of raw materials transferred to the supplier
+ transferred_raw_materials = get_subcontracted_raw_materials_from_se(item.purchase_order, item.item_code)
+
+ non_stock_items = get_non_stock_items(item.purchase_order, item.item_code)
+
+ item_key = '{}{}'.format(item.item_code, item.purchase_order)
+
+ fg_yet_to_be_received = qty_to_be_received_map.get(item_key)
+
+ transferred_batch_qty_map = get_transferred_batch_qty_map(item.purchase_order, item.item_code)
+ backflushed_batch_qty_map = get_backflushed_batch_qty_map(item.purchase_order, item.item_code)
+
+ for raw_material in transferred_raw_materials + non_stock_items:
+ rm_item_key = '{}{}'.format(raw_material.rm_item_code, item.purchase_order)
+ raw_material_data = backflushed_raw_materials_map.get(rm_item_key, {})
+
+ consumed_qty = raw_material_data.get('qty', 0)
+ consumed_serial_nos = raw_material_data.get('serial_nos', '')
+ consumed_batch_nos = raw_material_data.get('batch_nos', '')
+
+ transferred_qty = raw_material.qty
+
+ rm_qty_to_be_consumed = transferred_qty - consumed_qty
+
+ # backflush all remaining transferred qty in the last Purchase Receipt
+ if fg_yet_to_be_received == item.qty:
+ qty = rm_qty_to_be_consumed
+ else:
+ qty = (rm_qty_to_be_consumed / fg_yet_to_be_received) * item.qty
+
+ if frappe.get_cached_value('UOM', raw_material.stock_uom, 'must_be_whole_number'):
+ qty = frappe.utils.ceil(qty)
+
+ if qty > rm_qty_to_be_consumed:
+ qty = rm_qty_to_be_consumed
+
+ if not qty: continue
+
+ if raw_material.serial_nos:
+ set_serial_nos(raw_material, consumed_serial_nos, qty)
+
+ if raw_material.batch_nos:
+ batches_qty = get_batches_with_qty(raw_material.rm_item_code, raw_material.main_item_code,
+ qty, transferred_batch_qty_map, backflushed_batch_qty_map)
+ for batch_data in batches_qty:
+ qty = batch_data['qty']
+ raw_material.batch_no = batch_data['batch']
+ self.append_raw_material_to_be_backflushed(item, raw_material, qty)
+ else:
+ self.append_raw_material_to_be_backflushed(item, raw_material, qty)
+
+ def append_raw_material_to_be_backflushed(self, fg_item_doc, raw_material_data, qty):
+ rm = self.append('supplied_items', {})
+ rm.update(raw_material_data)
+
+ rm.required_qty = qty
+ rm.consumed_qty = qty
+
+ if not raw_material_data.get('non_stock_item'):
+ from erpnext.stock.utils import get_incoming_rate
+ rm.rate = get_incoming_rate({
+ "item_code": raw_material_data.rm_item_code,
+ "warehouse": self.supplier_warehouse,
+ "posting_date": self.posting_date,
+ "posting_time": self.posting_time,
+ "qty": -1 * qty,
+ "serial_no": rm.serial_no
+ })
+
+ if not rm.rate:
+ rm.rate = get_valuation_rate(raw_material_data.item_code, self.supplier_warehouse,
+ self.doctype, self.name, currency=self.company_currency, company=self.company)
+
+ rm.amount = qty * flt(rm.rate)
+ fg_item_doc.rm_supp_cost += rm.amount
def update_raw_materials_supplied_based_on_bom(self, item, raw_material_table):
exploded_item = 1
@@ -386,9 +442,11 @@
item_codes = list(set(item.item_code for item in
self.get("items")))
if item_codes:
- self._sub_contracted_items = [r[0] for r in frappe.db.sql("""select name
- from `tabItem` where name in (%s) and is_sub_contracted_item=1""" % \
- (", ".join((["%s"]*len(item_codes))),), item_codes)]
+ items = frappe.get_all('Item', filters={
+ 'name': ['in', item_codes],
+ 'is_sub_contracted_item': 1
+ })
+ self._sub_contracted_items = [item.name for item in items]
return self._sub_contracted_items
@@ -572,43 +630,33 @@
asset_items = self.get_asset_items()
if asset_items:
- self.make_serial_nos_for_asset(asset_items)
+ self.auto_make_assets(asset_items)
- def make_serial_nos_for_asset(self, asset_items):
+ def auto_make_assets(self, asset_items):
items_data = get_asset_item_details(asset_items)
+ messages = []
for d in self.items:
if d.is_fixed_asset:
item_data = items_data.get(d.item_code)
- if not d.asset:
- asset = self.make_asset(d)
- d.db_set('asset', asset)
- if item_data.get('has_serial_no'):
- # If item has serial no
- if item_data.get('serial_no_series') and not d.serial_no:
- serial_nos = get_auto_serial_nos(item_data.get('serial_no_series'), d.qty)
- elif d.serial_no:
- serial_nos = d.serial_no
- elif not d.serial_no:
- frappe.throw(_("Serial no is mandatory for the item {0}").format(d.item_code))
+ if item_data.get('auto_create_assets'):
+ # If asset has to be auto created
+ # Check for asset naming series
+ if item_data.get('asset_naming_series'):
+ for qty in range(cint(d.qty)):
+ self.make_asset(d)
+ is_plural = 's' if cint(d.qty) != 1 else ''
+ messages.append(_('{0} Asset{2} Created for <b>{1}</b>').format(cint(d.qty), d.item_code, is_plural))
+ else:
+ frappe.throw(_("Row {1}: Asset Naming Series is mandatory for the auto creation for item {0}")
+ .format(d.item_code, d.idx))
+ else:
+ messages.append(_("Assets not created for <b>{0}</b>. You will have to create asset manually.")
+ .format(d.item_code))
- auto_make_serial_nos({
- 'serial_no': serial_nos,
- 'item_code': d.item_code,
- 'via_stock_ledger': False,
- 'company': self.company,
- 'supplier': self.supplier,
- 'actual_qty': d.qty,
- 'purchase_document_type': self.doctype,
- 'purchase_document_no': self.name,
- 'asset': d.asset,
- 'location': d.asset_location
- })
- d.db_set('serial_no', serial_nos)
-
- if d.asset:
- self.make_asset_movement(d)
+ for message in messages:
+ frappe.msgprint(message, title="Success")
def make_asset(self, row):
if not row.asset_location:
@@ -617,7 +665,7 @@
item_data = frappe.db.get_value('Item',
row.item_code, ['asset_naming_series', 'asset_category'], as_dict=1)
- purchase_amount = flt(row.base_net_amount + row.item_tax_amount)
+ purchase_amount = flt(row.base_rate + row.item_tax_amount)
asset = frappe.get_doc({
'doctype': 'Asset',
'item_code': row.item_code,
@@ -640,57 +688,49 @@
asset.set_missing_values()
asset.insert()
- asset_link = frappe.utils.get_link_to_form('Asset', asset.name)
- frappe.msgprint(_("Asset {0} created").format(asset_link))
- return asset.name
-
- def make_asset_movement(self, row):
- asset_movement = frappe.get_doc({
- 'doctype': 'Asset Movement',
- 'asset': row.asset,
- 'target_location': row.asset_location,
- 'purpose': 'Receipt',
- 'serial_no': row.serial_no,
- 'quantity': len(get_serial_nos(row.serial_no)),
- 'company': self.company,
- 'transaction_date': self.posting_date,
- 'reference_doctype': self.doctype,
- 'reference_name': self.name
- }).insert()
-
- return asset_movement.name
-
def update_fixed_asset(self, field, delete_asset = False):
for d in self.get("items"):
- if d.is_fixed_asset and d.asset:
- asset = frappe.get_doc("Asset", d.asset)
+ if d.is_fixed_asset:
+ is_auto_create_enabled = frappe.db.get_value('Item', d.item_code, 'auto_create_assets')
+ assets = frappe.db.get_all('Asset', filters={ field : self.name, 'item_code' : d.item_code })
- if delete_asset and asset.docstatus == 0:
- frappe.delete_doc("Asset", asset.name)
- d.db_set('asset', None)
- continue
+ for asset in assets:
+ asset = frappe.get_doc('Asset', asset.name)
+ if delete_asset and is_auto_create_enabled:
+ # need to delete movements to delete assets otherwise throws link exists error
+ movements = frappe.db.sql(
+ """SELECT asm.name
+ FROM `tabAsset Movement` asm, `tabAsset Movement Item` asm_item
+ WHERE asm_item.parent=asm.name and asm_item.asset=%s""", asset.name, as_dict=1)
+ for movement in movements:
+ frappe.delete_doc('Asset Movement', movement.name, force=1)
+ frappe.delete_doc("Asset", asset.name, force=1)
+ continue
- if self.docstatus in [0, 1] and not asset.get(field):
- asset.set(field, self.name)
- asset.purchase_date = self.posting_date
- asset.supplier = self.supplier
- elif self.docstatus == 2:
- asset.set(field, None)
- asset.supplier = None
+ if self.docstatus in [0, 1] and not asset.get(field):
+ asset.set(field, self.name)
+ asset.purchase_date = self.posting_date
+ asset.supplier = self.supplier
+ elif self.docstatus == 2:
+ if asset.docstatus == 0:
+ asset.set(field, None)
+ asset.supplier = None
+ if asset.docstatus == 1 and delete_asset:
+ frappe.throw(_('Cannot cancel this document as it is linked with submitted asset {0}.\
+ Please cancel the it to continue.').format(asset.name))
- asset.flags.ignore_validate_update_after_submit = True
- asset.flags.ignore_mandatory = True
- if asset.docstatus == 0:
- asset.flags.ignore_validate = True
+ asset.flags.ignore_validate_update_after_submit = True
+ asset.flags.ignore_mandatory = True
+ if asset.docstatus == 0:
+ asset.flags.ignore_validate = True
- asset.save()
+ asset.save()
def delete_linked_asset(self):
if self.doctype == 'Purchase Invoice' and not self.get('update_stock'):
return
frappe.db.sql("delete from `tabAsset Movement` where reference_name=%s", self.name)
- frappe.db.sql("delete from `tabSerial No` where purchase_document_no=%s", self.name)
def validate_schedule_date(self):
if not self.get("items"):
@@ -739,32 +779,76 @@
return bom_items
-def get_subcontracted_raw_materials_from_se(purchase_orders):
- return frappe.db.sql("""
- select
- sed.item_name, sed.item_code, sum(sed.qty) as qty, sed.description,
- sed.stock_uom, sed.subcontracted_item as main_item_code, sed.serial_no, sed.batch_no
- from `tabStock Entry` se,`tabStock Entry Detail` sed
- where
- se.name = sed.parent and se.docstatus=1 and se.purpose='Send to Subcontractor'
- and se.purchase_order in (%s) and ifnull(sed.t_warehouse, '') != ''
- group by sed.item_code, sed.t_warehouse
- """ % (','.join(['%s'] * len(purchase_orders))), tuple(purchase_orders), as_dict=1)
+def get_subcontracted_raw_materials_from_se(purchase_order, fg_item):
+ common_query = """
+ SELECT
+ sed.item_code AS rm_item_code,
+ SUM(sed.qty) AS qty,
+ sed.description,
+ sed.stock_uom,
+ sed.subcontracted_item AS main_item_code,
+ {serial_no_concat_syntax} AS serial_nos,
+ {batch_no_concat_syntax} AS batch_nos
+ FROM `tabStock Entry` se,`tabStock Entry Detail` sed
+ WHERE
+ se.name = sed.parent
+ AND se.docstatus=1
+ AND se.purpose='Send to Subcontractor'
+ AND se.purchase_order = %s
+ AND IFNULL(sed.t_warehouse, '') != ''
+ AND sed.subcontracted_item = %s
+ GROUP BY sed.item_code, sed.subcontracted_item
+ """
+ raw_materials = frappe.db.multisql({
+ 'mariadb': common_query.format(
+ serial_no_concat_syntax="GROUP_CONCAT(sed.serial_no)",
+ batch_no_concat_syntax="GROUP_CONCAT(sed.batch_no)"
+ ),
+ 'postgres': common_query.format(
+ serial_no_concat_syntax="STRING_AGG(sed.serial_no, ',')",
+ batch_no_concat_syntax="STRING_AGG(sed.batch_no, ',')"
+ )
+ }, (purchase_order, fg_item), as_dict=1)
-def get_backflushed_subcontracted_raw_materials_from_se(purchase_orders, purchase_receipt):
- return frappe._dict(frappe.db.sql("""
- select
- prsi.rm_item_code as item_code, sum(prsi.consumed_qty) as qty
- from `tabPurchase Receipt` pr, `tabPurchase Receipt Item` pri, `tabPurchase Receipt Item Supplied` prsi
- where
- pr.name = pri.parent and pr.name = prsi.parent and pri.purchase_order in (%s)
- and pri.item_code = prsi.main_item_code and pr.name != '%s' and pr.docstatus = 1
- group by prsi.rm_item_code
- """ % (','.join(['%s'] * len(purchase_orders)), purchase_receipt), tuple(purchase_orders)))
+ return raw_materials
+
+def get_backflushed_subcontracted_raw_materials(purchase_orders):
+ common_query = """
+ SELECT
+ CONCAT(prsi.rm_item_code, pri.purchase_order) AS item_key,
+ SUM(prsi.consumed_qty) AS qty,
+ {serial_no_concat_syntax} AS serial_nos,
+ {batch_no_concat_syntax} AS batch_nos
+ FROM `tabPurchase Receipt` pr, `tabPurchase Receipt Item` pri, `tabPurchase Receipt Item Supplied` prsi
+ WHERE
+ pr.name = pri.parent
+ AND pr.name = prsi.parent
+ AND pri.purchase_order IN %s
+ AND pri.item_code = prsi.main_item_code
+ AND pr.docstatus = 1
+ GROUP BY prsi.rm_item_code, pri.purchase_order
+ """
+
+ backflushed_raw_materials = frappe.db.multisql({
+ 'mariadb': common_query.format(
+ serial_no_concat_syntax="GROUP_CONCAT(prsi.serial_no)",
+ batch_no_concat_syntax="GROUP_CONCAT(prsi.batch_no)"
+ ),
+ 'postgres': common_query.format(
+ serial_no_concat_syntax="STRING_AGG(prsi.serial_no, ',')",
+ batch_no_concat_syntax="STRING_AGG(prsi.batch_no, ',')"
+ )
+ }, (purchase_orders, ), as_dict=1)
+
+ backflushed_raw_materials_map = frappe._dict()
+ for item in backflushed_raw_materials:
+ backflushed_raw_materials_map.setdefault(item.item_key, item)
+
+ return backflushed_raw_materials_map
def get_asset_item_details(asset_items):
asset_items_data = {}
- for d in frappe.get_all('Item', fields = ["name", "has_serial_no", "serial_no_series"],
+ for d in frappe.get_all('Item', fields = ["name", "auto_create_assets", "asset_naming_series"],
filters = {'name': ('in', asset_items)}):
asset_items_data.setdefault(d.name, d)
@@ -793,3 +877,125 @@
error_message = _("Following item {0} is not marked as {1} item. You can enable them as {1} item from its Item master".format(items, message))
frappe.throw(error_message)
+
+def get_qty_to_be_received(purchase_orders):
+ return frappe._dict(frappe.db.sql("""
+ SELECT CONCAT(poi.`item_code`, poi.`parent`) AS item_key,
+ SUM(poi.`qty`) - SUM(poi.`received_qty`) AS qty_to_be_received
+ FROM `tabPurchase Order Item` poi
+ WHERE
+ poi.`parent` in %s
+ GROUP BY poi.`item_code`, poi.`parent`
+ HAVING SUM(poi.`qty`) > SUM(poi.`received_qty`)
+ """, (purchase_orders)))
+
+def get_non_stock_items(purchase_order, fg_item_code):
+ return frappe.db.sql("""
+ SELECT
+ pois.main_item_code,
+ pois.rm_item_code,
+ item.description,
+ pois.required_qty AS qty,
+ pois.rate,
+ 1 as non_stock_item,
+ pois.stock_uom
+ FROM `tabPurchase Order Item Supplied` pois, `tabItem` item
+ WHERE
+ pois.`rm_item_code` = item.`name`
+ AND item.is_stock_item = 0
+ AND pois.`parent` = %s
+ AND pois.`main_item_code` = %s
+ """, (purchase_order, fg_item_code), as_dict=1)
+
+
+def set_serial_nos(raw_material, consumed_serial_nos, qty):
+ serial_nos = set(get_serial_nos(raw_material.serial_nos)) - \
+ set(get_serial_nos(consumed_serial_nos))
+ if serial_nos and qty <= len(serial_nos):
+ raw_material.serial_no = '\n'.join(list(serial_nos)[0:frappe.utils.cint(qty)])
+
+def get_transferred_batch_qty_map(purchase_order, fg_item):
+ # returns
+ # {
+ # (item_code, fg_code): {
+ # batch1: 10, # qty
+ # batch2: 16
+ # },
+ # }
+ transferred_batch_qty_map = {}
+ transferred_batches = frappe.db.sql("""
+ SELECT
+ sed.batch_no,
+ SUM(sed.qty) AS qty,
+ sed.item_code
+ FROM `tabStock Entry` se,`tabStock Entry Detail` sed
+ WHERE
+ se.name = sed.parent
+ AND se.docstatus=1
+ AND se.purpose='Send to Subcontractor'
+ AND se.purchase_order = %s
+ AND sed.subcontracted_item = %s
+ AND sed.batch_no IS NOT NULL
+ GROUP BY
+ sed.batch_no,
+ sed.item_code
+ """, (purchase_order, fg_item), as_dict=1)
+
+ for batch_data in transferred_batches:
+ transferred_batch_qty_map.setdefault((batch_data.item_code, fg_item), {})
+ transferred_batch_qty_map[(batch_data.item_code, fg_item)][batch_data.batch_no] = batch_data.qty
+
+ return transferred_batch_qty_map
+
+def get_backflushed_batch_qty_map(purchase_order, fg_item):
+ # returns
+ # {
+ # (item_code, fg_code): {
+ # batch1: 10, # qty
+ # batch2: 16
+ # },
+ # }
+ backflushed_batch_qty_map = {}
+ backflushed_batches = frappe.db.sql("""
+ SELECT
+ pris.batch_no,
+ SUM(pris.consumed_qty) AS qty,
+ pris.rm_item_code AS item_code
+ FROM `tabPurchase Receipt` pr, `tabPurchase Receipt Item` pri, `tabPurchase Receipt Item Supplied` pris
+ WHERE
+ pr.name = pri.parent
+ AND pri.parent = pris.parent
+ AND pri.purchase_order = %s
+ AND pri.item_code = pris.main_item_code
+ AND pr.docstatus = 1
+ AND pris.main_item_code = %s
+ AND pris.batch_no IS NOT NULL
+ GROUP BY
+ pris.rm_item_code, pris.batch_no
+ """, (purchase_order, fg_item), as_dict=1)
+
+ for batch_data in backflushed_batches:
+ backflushed_batch_qty_map.setdefault((batch_data.item_code, fg_item), {})
+ backflushed_batch_qty_map[(batch_data.item_code, fg_item)][batch_data.batch_no] = batch_data.qty
+
+ return backflushed_batch_qty_map
+
+def get_batches_with_qty(item_code, fg_item, required_qty, transferred_batch_qty_map, backflushed_batch_qty_map):
+ # Returns available batches to be backflushed based on requirements
+ transferred_batches = transferred_batch_qty_map.get((item_code, fg_item), {})
+ backflushed_batches = backflushed_batch_qty_map.get((item_code, fg_item), {})
+
+ available_batches = []
+
+ for (batch, transferred_qty) in transferred_batches.items():
+ backflushed_qty = backflushed_batches.get(batch, 0)
+ available_qty = transferred_qty - backflushed_qty
+
+ if available_qty >= required_qty:
+ available_batches.append({'batch': batch, 'qty': required_qty})
+ break
+ else:
+ available_batches.append({'batch': batch, 'qty': available_qty})
+ required_qty -= available_qty
+
+ return available_batches
\ No newline at end of file
diff --git a/erpnext/controllers/queries.py b/erpnext/controllers/queries.py
index 2f6b59f..d18f8e5 100644
--- a/erpnext/controllers/queries.py
+++ b/erpnext/controllers/queries.py
@@ -4,9 +4,9 @@
from __future__ import unicode_literals
import frappe
from frappe.desk.reportview import get_match_cond, get_filters_cond
-from frappe.utils import nowdate
+from frappe.utils import nowdate, getdate
from collections import defaultdict
-
+from erpnext.stock.get_item_details import _get_item_tax_template
# searches for active employees
def employee_query(doctype, txt, searchfield, start, page_len, filters):
@@ -152,6 +152,24 @@
def item_query(doctype, txt, searchfield, start, page_len, filters, as_dict=False):
conditions = []
+ #Get searchfields from meta and use in Item Link field query
+ meta = frappe.get_meta("Item", cached=True)
+ searchfields = meta.get_search_fields()
+
+ if "description" in searchfields:
+ searchfields.remove("description")
+
+ columns = ''
+ extra_searchfields = [field for field in searchfields
+ if not field in ["name", "item_group", "description"]]
+
+ if extra_searchfields:
+ columns = ", " + ", ".join(extra_searchfields)
+
+ searchfields = searchfields + [field for field in[searchfield or "name", "item_code", "item_group", "item_name"]
+ if not field in searchfields]
+ searchfields = " or ".join([field + " like %(txt)s" for field in searchfields])
+
description_cond = ''
if frappe.db.count('Item', cache=True) < 50000:
# scan description only if items are less than 50000
@@ -162,17 +180,14 @@
concat(substr(tabItem.item_name, 1, 40), "..."), item_name) as item_name,
tabItem.item_group,
if(length(tabItem.description) > 40, \
- concat(substr(tabItem.description, 1, 40), "..."), description) as decription
+ concat(substr(tabItem.description, 1, 40), "..."), description) as description
+ {columns}
from tabItem
where tabItem.docstatus < 2
and tabItem.has_variants=0
and tabItem.disabled=0
and (tabItem.end_of_life > %(today)s or ifnull(tabItem.end_of_life, '0000-00-00')='0000-00-00')
- and (tabItem.`{key}` LIKE %(txt)s
- or tabItem.item_code LIKE %(txt)s
- or tabItem.item_group LIKE %(txt)s
- or tabItem.item_name LIKE %(txt)s
- or tabItem.item_code IN (select parent from `tabItem Barcode` where barcode LIKE %(txt)s)
+ and ({scond} or tabItem.item_code IN (select parent from `tabItem Barcode` where barcode LIKE %(txt)s)
{description_cond})
{fcond} {mcond}
order by
@@ -182,6 +197,8 @@
name, item_name
limit %(start)s, %(page_len)s """.format(
key=searchfield,
+ columns=columns,
+ scond=searchfields,
fcond=get_filters_cond(doctype, filters, conditions).replace('%', '%%'),
mcond=get_match_cond(doctype).replace('%', '%%'),
description_cond = description_cond),
@@ -294,6 +311,7 @@
and sle.item_code = %(item_code)s
and sle.warehouse = %(warehouse)s
and (sle.batch_no like %(txt)s
+ or batch.expiry_date like %(txt)s
or batch.manufacturing_date like %(txt)s)
and batch.docstatus < 2
{cond}
@@ -312,6 +330,7 @@
where batch.disabled = 0
and item = %(item_code)s
and (name like %(txt)s
+ or expiry_date like %(txt)s
or manufacturing_date like %(txt)s)
and docstatus < 2
{0}
@@ -463,3 +482,53 @@
as_list=1
)
return item_manufacturers
+
+@frappe.whitelist()
+def get_purchase_receipts(doctype, txt, searchfield, start, page_len, filters):
+ query = """
+ select pr.name
+ from `tabPurchase Receipt` pr, `tabPurchase Receipt Item` pritem
+ where pr.docstatus = 1 and pritem.parent = pr.name
+ and pr.name like {txt}""".format(txt = frappe.db.escape('%{0}%'.format(txt)))
+
+ if filters and filters.get('item_code'):
+ query += " and pritem.item_code = {item_code}".format(item_code = frappe.db.escape(filters.get('item_code')))
+
+ return frappe.db.sql(query, filters)
+
+@frappe.whitelist()
+def get_purchase_invoices(doctype, txt, searchfield, start, page_len, filters):
+ query = """
+ select pi.name
+ from `tabPurchase Invoice` pi, `tabPurchase Invoice Item` piitem
+ where pi.docstatus = 1 and piitem.parent = pi.name
+ and pi.name like {txt}""".format(txt = frappe.db.escape('%{0}%'.format(txt)))
+
+ if filters and filters.get('item_code'):
+ query += " and piitem.item_code = {item_code}".format(item_code = frappe.db.escape(filters.get('item_code')))
+
+ return frappe.db.sql(query, filters)
+
+@frappe.whitelist()
+def get_tax_template(doctype, txt, searchfield, start, page_len, filters):
+
+ item_doc = frappe.get_cached_doc('Item', filters.get('item_code'))
+ item_group = filters.get('item_group')
+ taxes = item_doc.taxes or []
+
+ while item_group:
+ item_group_doc = frappe.get_cached_doc('Item Group', item_group)
+ taxes += item_group_doc.taxes or []
+ item_group = item_group_doc.parent_item_group
+
+ if not taxes:
+ return frappe.db.sql(""" SELECT name FROM `tabItem Tax Template` """)
+ else:
+ args = {
+ 'item_code': filters.get('item_code'),
+ 'posting_date': filters.get('valid_from'),
+ 'tax_category': filters.get('tax_category')
+ }
+
+ taxes = _get_item_tax_template(args, taxes, for_validate=True)
+ return [(d,) for d in set(taxes)]
diff --git a/erpnext/controllers/sales_and_purchase_return.py b/erpnext/controllers/sales_and_purchase_return.py
index 8595292..81fdbbe 100644
--- a/erpnext/controllers/sales_and_purchase_return.py
+++ b/erpnext/controllers/sales_and_purchase_return.py
@@ -72,7 +72,7 @@
items_returned = False
for d in doc.get("items"):
- if d.item_code and (flt(d.qty) < 0 or d.get('received_qty') < 0):
+ if d.item_code and (flt(d.qty) < 0 or flt(d.get('received_qty')) < 0):
if d.item_code not in valid_items:
frappe.throw(_("Row # {0}: Returned Item {1} does not exists in {2} {3}")
.format(d.idx, d.item_code, doc.doctype, doc.return_against))
diff --git a/erpnext/controllers/selling_controller.py b/erpnext/controllers/selling_controller.py
index 9dbd5be..9a9f3d1 100644
--- a/erpnext/controllers/selling_controller.py
+++ b/erpnext/controllers/selling_controller.py
@@ -148,13 +148,6 @@
if sales_team and total != 100.0:
throw(_("Total allocated percentage for sales team should be 100"))
- def validate_order_type(self):
- valid_types = ["Sales", "Maintenance", "Shopping Cart"]
- if not self.order_type:
- self.order_type = "Sales"
- elif self.order_type not in valid_types:
- throw(_("Order Type must be one of {0}").format(comma_or(valid_types)))
-
def validate_max_discount(self):
for d in self.get("items"):
if d.item_code:
diff --git a/erpnext/controllers/status_updater.py b/erpnext/controllers/status_updater.py
index 9d1389c..2b2c27b 100644
--- a/erpnext/controllers/status_updater.py
+++ b/erpnext/controllers/status_updater.py
@@ -49,7 +49,8 @@
["Submitted", "eval:self.docstatus==1"],
["Paid", "eval:self.outstanding_amount==0 and self.docstatus==1"],
["Return", "eval:self.is_return==1 and self.docstatus==1"],
- ["Debit Note Issued", "eval:self.outstanding_amount < 0 and self.docstatus==1"],
+ ["Debit Note Issued",
+ "eval:self.outstanding_amount <= 0 and self.docstatus==1 and self.is_return==0 and get_value('Purchase Invoice', {'is_return': 1, 'return_against': self.name, 'docstatus': 1})"],
["Unpaid", "eval:self.outstanding_amount > 0 and getdate(self.due_date) >= getdate(nowdate()) and self.docstatus==1"],
["Overdue", "eval:self.outstanding_amount > 0 and getdate(self.due_date) < getdate(nowdate()) and self.docstatus==1"],
["Cancelled", "eval:self.docstatus==2"],
@@ -118,7 +119,6 @@
if self.doctype in status_map:
_status = self.status
-
if status and update:
self.db_set("status", status)
diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py
index 2d87a98..f4a13d5 100644
--- a/erpnext/controllers/stock_controller.py
+++ b/erpnext/controllers/stock_controller.py
@@ -20,6 +20,7 @@
def validate(self):
super(StockController, self).validate()
self.validate_inspection()
+ self.validate_serialized_batch()
def make_gl_entries(self, gl_entries=None, repost_future_gle=True, from_repost=False):
if self.docstatus == 2:
@@ -42,6 +43,17 @@
gl_entries = self.get_asset_gl_entry(gl_entries)
make_gl_entries(gl_entries, from_repost=from_repost)
+ def validate_serialized_batch(self):
+ from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
+ for d in self.get("items"):
+ if hasattr(d, 'serial_no') and hasattr(d, 'batch_no') and d.serial_no and d.batch_no:
+ serial_nos = get_serial_nos(d.serial_no)
+ for serial_no_data in frappe.get_all("Serial No",
+ filters={"name": ("in", serial_nos)}, fields=["batch_no", "name"]):
+ if serial_no_data.batch_no != d.batch_no:
+ frappe.throw(_("Row #{0}: Serial No {1} does not belong to Batch {2}")
+ .format(d.idx, serial_no_data.name, d.batch_no))
+
def get_gl_entries(self, warehouse_account=None, default_expense_account=None,
default_cost_center=None):
@@ -207,41 +219,6 @@
reference_doctype=self.doctype,
reference_name=self.name)).insert().name
- def make_adjustment_entry(self, expected_gle, voucher_obj):
- from erpnext.accounts.utils import get_stock_and_account_difference
- account_list = [d.account for d in expected_gle]
- acc_diff = get_stock_and_account_difference(account_list,
- expected_gle[0].posting_date, self.company)
-
- cost_center = self.get_company_default("cost_center")
- stock_adjustment_account = self.get_company_default("stock_adjustment_account")
-
- gl_entries = []
- for account, diff in acc_diff.items():
- if diff:
- gl_entries.append([
- # stock in hand account
- voucher_obj.get_gl_dict({
- "account": account,
- "against": stock_adjustment_account,
- "debit": diff,
- "remarks": "Adjustment Accounting Entry for Stock",
- }),
-
- # account against stock in hand
- voucher_obj.get_gl_dict({
- "account": stock_adjustment_account,
- "against": account,
- "credit": diff,
- "cost_center": cost_center or None,
- "remarks": "Adjustment Accounting Entry for Stock",
- }),
- ])
-
- if gl_entries:
- from erpnext.accounts.general_ledger import make_gl_entries
- make_gl_entries(gl_entries)
-
def check_expense_account(self, item):
if not item.get("expense_account"):
frappe.throw(_("Expense or Difference account is mandatory for Item {0} as it impacts overall stock value").format(item.item_code))
diff --git a/erpnext/controllers/taxes_and_totals.py b/erpnext/controllers/taxes_and_totals.py
index d2db9d0..b52a07d 100644
--- a/erpnext/controllers/taxes_and_totals.py
+++ b/erpnext/controllers/taxes_and_totals.py
@@ -8,6 +8,7 @@
from frappe.utils import cint, flt, round_based_on_smallest_currency_fraction
from erpnext.controllers.accounts_controller import validate_conversion_rate, \
validate_taxes_and_charges, validate_inclusive_tax
+from erpnext.stock.get_item_details import _get_item_tax_template
class calculate_taxes_and_totals(object):
def __init__(self, doc):
@@ -34,6 +35,7 @@
def _calculate(self):
self.validate_conversion_rate()
self.calculate_item_values()
+ self.validate_item_tax_template()
self.initialize_taxes()
self.determine_exclusive_rate()
self.calculate_net_total()
@@ -43,6 +45,38 @@
self._cleanup()
self.calculate_total_net_weight()
+ def validate_item_tax_template(self):
+ for item in self.doc.get('items'):
+ if item.item_code and item.get('item_tax_template'):
+ item_doc = frappe.get_cached_doc("Item", item.item_code)
+ args = {
+ 'tax_category': self.doc.get('tax_category'),
+ 'posting_date': self.doc.get('posting_date'),
+ 'bill_date': self.doc.get('bill_date'),
+ 'transaction_date': self.doc.get('transaction_date')
+ }
+
+ item_group = item_doc.item_group
+ item_group_taxes = []
+
+ while item_group:
+ item_group_doc = frappe.get_cached_doc('Item Group', item_group)
+ item_group_taxes += item_group_doc.taxes or []
+ item_group = item_group_doc.parent_item_group
+
+ item_taxes = item_doc.taxes or []
+
+ if not item_group_taxes and (not item_taxes):
+ # No validation if no taxes in item or item group
+ continue
+
+ taxes = _get_item_tax_template(args, item_taxes + item_group_taxes, for_validate=True)
+
+ if item.item_tax_template not in taxes:
+ frappe.throw(_("Row {0}: Invalid Item Tax Template for item {1}").format(
+ item.idx, frappe.bold(item.item_code)
+ ))
+
def validate_conversion_rate(self):
# validate conversion rate
company_currency = erpnext.get_company_currency(self.doc.company)
@@ -312,11 +346,19 @@
last_tax = self.doc.get("taxes")[-1]
non_inclusive_tax_amount = sum([flt(d.tax_amount_after_discount_amount)
for d in self.doc.get("taxes") if not d.included_in_print_rate])
+
diff = self.doc.total + non_inclusive_tax_amount \
- flt(last_tax.total, last_tax.precision("total"))
+
+ # If discount amount applied, deduct the discount amount
+ # because self.doc.total is always without discount, but last_tax.total is after discount
+ if self.discount_amount_applied and self.doc.discount_amount:
+ diff -= flt(self.doc.discount_amount)
+
+ diff = flt(diff, self.doc.precision("rounding_adjustment"))
+
if diff and abs(diff) <= (5.0 / 10**last_tax.precision("tax_amount")):
- self.doc.rounding_adjustment = flt(flt(self.doc.rounding_adjustment) +
- flt(diff), self.doc.precision("rounding_adjustment"))
+ self.doc.rounding_adjustment = diff
def calculate_totals(self):
self.doc.grand_total = flt(self.doc.get("taxes")[-1].total) + flt(self.doc.rounding_adjustment) \
@@ -552,7 +594,7 @@
if item.price_list_rate:
if item.pricing_rules and not self.doc.ignore_pricing_rule:
for d in item.pricing_rules.split(','):
- pricing_rule = frappe.get_doc('Pricing Rule', d)
+ pricing_rule = frappe.get_cached_doc('Pricing Rule', d)
if (pricing_rule.margin_type == 'Amount' and pricing_rule.currency == self.doc.currency)\
or (pricing_rule.margin_type == 'Percentage'):
diff --git a/erpnext/assets/doctype/asset_settings/__init__.py b/erpnext/crm/doctype/appointment/__init__.py
similarity index 100%
copy from erpnext/assets/doctype/asset_settings/__init__.py
copy to erpnext/crm/doctype/appointment/__init__.py
diff --git a/erpnext/crm/doctype/appointment/appointment.js b/erpnext/crm/doctype/appointment/appointment.js
new file mode 100644
index 0000000..8888b56
--- /dev/null
+++ b/erpnext/crm/doctype/appointment/appointment.js
@@ -0,0 +1,17 @@
+// Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Appointment', {
+ refresh: function(frm) {
+ if(frm.doc.lead){
+ frm.add_custom_button(frm.doc.lead,()=>{
+ frappe.set_route("Form", "Lead", frm.doc.lead);
+ });
+ }
+ if(frm.doc.calendar_event){
+ frm.add_custom_button(__(frm.doc.calendar_event),()=>{
+ frappe.set_route("Form", "Event", frm.doc.calendar_event);
+ });
+ }
+ }
+});
diff --git a/erpnext/crm/doctype/appointment/appointment.json b/erpnext/crm/doctype/appointment/appointment.json
new file mode 100644
index 0000000..32df8ec
--- /dev/null
+++ b/erpnext/crm/doctype/appointment/appointment.json
@@ -0,0 +1,153 @@
+{
+ "autoname": "format:APMT-{customer_name}-{####}",
+ "creation": "2019-08-27 10:48:27.926283",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "scheduled_time",
+ "status",
+ "customer_details_section",
+ "customer_name",
+ "customer_phone_number",
+ "customer_skype",
+ "customer_email",
+ "col_br_2",
+ "customer_details",
+ "linked_docs_section",
+ "lead",
+ "col_br_3",
+ "calendar_event"
+ ],
+ "fields": [
+ {
+ "fieldname": "customer_details_section",
+ "fieldtype": "Section Break",
+ "label": "Customer Details"
+ },
+ {
+ "fieldname": "customer_name",
+ "fieldtype": "Data",
+ "in_list_view": 1,
+ "label": "Name",
+ "reqd": 1
+ },
+ {
+ "fieldname": "customer_phone_number",
+ "fieldtype": "Data",
+ "label": "Phone Number"
+ },
+ {
+ "fieldname": "customer_skype",
+ "fieldtype": "Data",
+ "label": "Skype ID"
+ },
+ {
+ "fieldname": "customer_details",
+ "fieldtype": "Long Text",
+ "label": "Details"
+ },
+ {
+ "fieldname": "scheduled_time",
+ "fieldtype": "Datetime",
+ "in_list_view": 1,
+ "label": "Scheduled Time",
+ "reqd": 1
+ },
+ {
+ "fieldname": "status",
+ "fieldtype": "Select",
+ "label": "Status",
+ "options": "Open\nUnverified\nClosed",
+ "reqd": 1
+ },
+ {
+ "fieldname": "lead",
+ "fieldtype": "Link",
+ "label": "Lead",
+ "options": "Lead"
+ },
+ {
+ "fieldname": "calendar_event",
+ "fieldtype": "Link",
+ "label": "Calendar Event",
+ "options": "Event"
+ },
+ {
+ "fieldname": "col_br_2",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "customer_email",
+ "fieldtype": "Data",
+ "label": "Email",
+ "reqd": 1
+ },
+ {
+ "fieldname": "linked_docs_section",
+ "fieldtype": "Section Break",
+ "label": "Linked Documents"
+ },
+ {
+ "fieldname": "col_br_3",
+ "fieldtype": "Column Break"
+ }
+ ],
+ "modified": "2019-10-14 15:23:54.630731",
+ "modified_by": "Administrator",
+ "module": "CRM",
+ "name": "Appointment",
+ "name_case": "UPPER CASE",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "System Manager",
+ "share": 1,
+ "write": 1
+ },
+ {
+ "create": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Guest",
+ "share": 1
+ },
+ {
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Sales Manager",
+ "share": 1,
+ "write": 1
+ },
+ {
+ "create": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Sales User",
+ "share": 1,
+ "write": 1
+ }
+ ],
+ "quick_entry": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/crm/doctype/appointment/appointment.py b/erpnext/crm/doctype/appointment/appointment.py
new file mode 100644
index 0000000..f502930
--- /dev/null
+++ b/erpnext/crm/doctype/appointment/appointment.py
@@ -0,0 +1,223 @@
+# -*- 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 urllib
+from collections import Counter
+from datetime import timedelta
+
+import frappe
+from frappe import _
+from frappe.model.document import Document
+from frappe.utils import get_url, getdate
+from frappe.utils.verified_command import verify_request, get_signed_params
+
+
+class Appointment(Document):
+
+ def find_lead_by_email(self):
+ lead_list = frappe.get_list(
+ 'Lead', filters={'email_id': self.customer_email}, ignore_permissions=True)
+ if lead_list:
+ return lead_list[0].name
+ return None
+
+ def before_insert(self):
+ number_of_appointments_in_same_slot = frappe.db.count(
+ 'Appointment', filters={'scheduled_time': self.scheduled_time})
+ number_of_agents = frappe.db.get_single_value('Appointment Booking Settings', 'number_of_agents')
+ if not number_of_agents == 0:
+ if (number_of_appointments_in_same_slot >= number_of_agents):
+ frappe.throw('Time slot is not available')
+ # Link lead
+ if not self.lead:
+ self.lead = self.find_lead_by_email()
+
+ def after_insert(self):
+ if self.lead:
+ # Create Calendar event
+ self.auto_assign()
+ self.create_calendar_event()
+ else:
+ # Set status to unverified
+ self.status = 'Unverified'
+ # Send email to confirm
+ self.send_confirmation_email()
+
+ def send_confirmation_email(self):
+ verify_url = self._get_verify_url()
+ template = 'confirm_appointment'
+ args = {
+ "link":verify_url,
+ "site_url":frappe.utils.get_url(),
+ "full_name":self.customer_name,
+ }
+ frappe.sendmail(recipients=[self.customer_email],
+ template=template,
+ args=args,
+ subject=_('Appointment Confirmation'))
+ if frappe.session.user == "Guest":
+ frappe.msgprint(
+ 'Please check your email to confirm the appointment')
+ else :
+ frappe.msgprint(
+ 'Appointment was created. But no lead was found. Please check the email to confirm')
+
+ def on_change(self):
+ # Sync Calendar
+ if not self.calendar_event:
+ return
+ cal_event = frappe.get_doc('Event', self.calendar_event)
+ cal_event.starts_on = self.scheduled_time
+ cal_event.save(ignore_permissions=True)
+
+
+ def set_verified(self, email):
+ if not email == self.customer_email:
+ frappe.throw('Email verification failed.')
+ # Create new lead
+ self.create_lead_and_link()
+ # Remove unverified status
+ self.status = 'Open'
+ # Create calender event
+ self.auto_assign()
+ self.create_calendar_event()
+ self.save(ignore_permissions=True)
+ frappe.db.commit()
+
+ def create_lead_and_link(self):
+ # Return if already linked
+ if self.lead:
+ return
+ lead = frappe.get_doc({
+ 'doctype': 'Lead',
+ 'lead_name': self.customer_name,
+ 'email_id': self.customer_email,
+ 'notes': self.customer_details,
+ 'phone': self.customer_phone_number,
+ })
+ lead.insert(ignore_permissions=True)
+ # Link lead
+ self.lead = lead.name
+
+ def auto_assign(self):
+ from frappe.desk.form.assign_to import add as add_assignemnt
+ existing_assignee = self.get_assignee_from_latest_opportunity()
+ if existing_assignee:
+ # If the latest opportunity is assigned to someone
+ # Assign the appointment to the same
+ add_assignemnt({
+ 'doctype': self.doctype,
+ 'name': self.name,
+ 'assign_to': existing_assignee
+ })
+ return
+ if self._assign:
+ return
+ available_agents = _get_agents_sorted_by_asc_workload(
+ getdate(self.scheduled_time))
+ for agent in available_agents:
+ if(_check_agent_availability(agent, self.scheduled_time)):
+ agent = agent[0]
+ add_assignemnt({
+ 'doctype': self.doctype,
+ 'name': self.name,
+ 'assign_to': agent
+ })
+ break
+
+ def get_assignee_from_latest_opportunity(self):
+ if not self.lead:
+ return None
+ if not frappe.db.exists('Lead', self.lead):
+ return None
+ opporutnities = frappe.get_list(
+ 'Opportunity',
+ filters={
+ 'party_name': self.lead,
+ },
+ ignore_permissions=True,
+ order_by='creation desc')
+ if not opporutnities:
+ return None
+ latest_opportunity = frappe.get_doc('Opportunity', opporutnities[0].name )
+ assignee = latest_opportunity._assign
+ if not assignee:
+ return None
+ assignee = frappe.parse_json(assignee)[0]
+ return assignee
+
+ def create_calendar_event(self):
+ if self.calendar_event:
+ return
+ appointment_event = frappe.get_doc({
+ 'doctype': 'Event',
+ 'subject': ' '.join(['Appointment with', self.customer_name]),
+ 'starts_on': self.scheduled_time,
+ 'status': 'Open',
+ 'type': 'Public',
+ 'send_reminder': frappe.db.get_single_value('Appointment Booking Settings', 'email_reminders'),
+ 'event_participants': [dict(reference_doctype='Lead', reference_docname=self.lead)]
+ })
+ employee = _get_employee_from_user(self._assign)
+ if employee:
+ appointment_event.append('event_participants', dict(
+ reference_doctype='Employee',
+ reference_docname=employee.name))
+ appointment_event.insert(ignore_permissions=True)
+ self.calendar_event = appointment_event.name
+ self.save(ignore_permissions=True)
+
+ def _get_verify_url(self):
+ verify_route = '/book_appointment/verify'
+ params = {
+ 'email': self.customer_email,
+ 'appointment': self.name
+ }
+ return get_url(verify_route + '?' + get_signed_params(params))
+
+
+def _get_agents_sorted_by_asc_workload(date):
+ appointments = frappe.db.get_list('Appointment', fields='*')
+ agent_list = _get_agent_list_as_strings()
+ if not appointments:
+ return agent_list
+ appointment_counter = Counter(agent_list)
+ for appointment in appointments:
+ assigned_to = frappe.parse_json(appointment._assign)
+ if not assigned_to:
+ continue
+ if (assigned_to[0] in agent_list) and getdate(appointment.scheduled_time) == date:
+ appointment_counter[assigned_to[0]] += 1
+ sorted_agent_list = appointment_counter.most_common()
+ sorted_agent_list.reverse()
+ return sorted_agent_list
+
+
+def _get_agent_list_as_strings():
+ agent_list_as_strings = []
+ agent_list = frappe.get_doc('Appointment Booking Settings').agent_list
+ for agent in agent_list:
+ agent_list_as_strings.append(agent.user)
+ return agent_list_as_strings
+
+
+def _check_agent_availability(agent_email, scheduled_time):
+ appointemnts_at_scheduled_time = frappe.get_list(
+ 'Appointment', filters={'scheduled_time': scheduled_time})
+ for appointment in appointemnts_at_scheduled_time:
+ if appointment._assign == agent_email:
+ return False
+ return True
+
+
+def _get_employee_from_user(user):
+ employee_docname = frappe.db.exists(
+ {'doctype': 'Employee', 'user_id': user})
+ if employee_docname:
+ # frappe.db.exists returns a tuple of a tuple
+ return frappe.get_doc('Employee', employee_docname[0][0])
+ return None
+
diff --git a/erpnext/crm/doctype/appointment/test_appointment.py b/erpnext/crm/doctype/appointment/test_appointment.py
new file mode 100644
index 0000000..50c98c5
--- /dev/null
+++ b/erpnext/crm/doctype/appointment/test_appointment.py
@@ -0,0 +1,58 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+import frappe
+import unittest
+import datetime
+
+
+def create_test_lead():
+ test_lead = frappe.db.exists({'doctype': 'Lead', 'lead_name': 'Test Lead'})
+ if test_lead:
+ return frappe.get_doc('Lead', test_lead[0][0])
+ test_lead = frappe.get_doc({
+ 'doctype': 'Lead',
+ 'lead_name': 'Test Lead',
+ 'email_id': 'test@example.com'
+ })
+ test_lead.insert(ignore_permissions=True)
+ return test_lead
+
+
+def create_test_appointments():
+ test_appointment = frappe.db.exists(
+ {'doctype': 'Appointment', 'scheduled_time':datetime.datetime.now(),'email':'test@example.com'})
+ if test_appointment:
+ return frappe.get_doc('Appointment', test_appointment[0][0])
+ test_appointment = frappe.get_doc({
+ 'doctype': 'Appointment',
+ 'email': 'test@example.com',
+ 'status': 'Open',
+ 'customer_name': 'Test Lead',
+ 'customer_phone_number': '666',
+ 'customer_skype': 'test',
+ 'customer_email': 'test@example.com',
+ 'scheduled_time': datetime.datetime.now()
+ })
+ test_appointment.insert()
+ return test_appointment
+
+
+class TestAppointment(unittest.TestCase):
+ test_appointment = test_lead = None
+
+ def setUp(self):
+ self.test_lead = create_test_lead()
+ self.test_appointment = create_test_appointments()
+
+ def test_calendar_event_created(self):
+ cal_event = frappe.get_doc(
+ 'Event', self.test_appointment.calendar_event)
+ self.assertEqual(cal_event.starts_on,
+ self.test_appointment.scheduled_time)
+
+ def test_lead_linked(self):
+ lead = frappe.get_doc('Lead', self.test_lead.name)
+ self.assertIsNotNone(lead)
diff --git a/erpnext/assets/doctype/asset_settings/__init__.py b/erpnext/crm/doctype/appointment_booking_settings/__init__.py
similarity index 100%
copy from erpnext/assets/doctype/asset_settings/__init__.py
copy to erpnext/crm/doctype/appointment_booking_settings/__init__.py
diff --git a/erpnext/crm/doctype/appointment_booking_settings/appointment_booking_settings.js b/erpnext/crm/doctype/appointment_booking_settings/appointment_booking_settings.js
new file mode 100644
index 0000000..99b8214
--- /dev/null
+++ b/erpnext/crm/doctype/appointment_booking_settings/appointment_booking_settings.js
@@ -0,0 +1,10 @@
+frappe.ui.form.on('Appointment Booking Settings', 'validate',check_times);
+function check_times(frm) {
+ $.each(frm.doc.availability_of_slots || [], function (i, d) {
+ let from_time = Date.parse('01/01/2019 ' + d.from_time);
+ let to_time = Date.parse('01/01/2019 ' + d.to_time);
+ if (from_time > to_time) {
+ frappe.throw(__(`In row ${i + 1} of Appointment Booking Slots : "To Time" must be later than "From Time"`));
+ }
+ });
+}
\ No newline at end of file
diff --git a/erpnext/crm/doctype/appointment_booking_settings/appointment_booking_settings.json b/erpnext/crm/doctype/appointment_booking_settings/appointment_booking_settings.json
new file mode 100644
index 0000000..4b26e49
--- /dev/null
+++ b/erpnext/crm/doctype/appointment_booking_settings/appointment_booking_settings.json
@@ -0,0 +1,151 @@
+{
+ "creation": "2019-08-27 10:56:48.309824",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "enable_scheduling",
+ "agent_detail_section",
+ "availability_of_slots",
+ "number_of_agents",
+ "agent_list",
+ "holiday_list",
+ "appointment_details_section",
+ "appointment_duration",
+ "email_reminders",
+ "advance_booking_days",
+ "success_details",
+ "success_redirect_url"
+ ],
+ "fields": [
+ {
+ "fieldname": "availability_of_slots",
+ "fieldtype": "Table",
+ "label": "Availability Of Slots",
+ "options": "Appointment Booking Slots",
+ "reqd": 1
+ },
+ {
+ "default": "1",
+ "fieldname": "number_of_agents",
+ "fieldtype": "Int",
+ "hidden": 1,
+ "in_list_view": 1,
+ "label": "Number of Concurrent Appointments",
+ "read_only": 1,
+ "reqd": 1
+ },
+ {
+ "fieldname": "holiday_list",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Holiday List",
+ "options": "Holiday List",
+ "reqd": 1
+ },
+ {
+ "default": "60",
+ "fieldname": "appointment_duration",
+ "fieldtype": "Int",
+ "label": "Appointment Duration (In Minutes)",
+ "reqd": 1
+ },
+ {
+ "default": "0",
+ "description": "Notify customer and agent via email on the day of the appointment.",
+ "fieldname": "email_reminders",
+ "fieldtype": "Check",
+ "label": "Notify Via Email"
+ },
+ {
+ "default": "7",
+ "fieldname": "advance_booking_days",
+ "fieldtype": "Int",
+ "label": "Number of days appointments can be booked in advance",
+ "reqd": 1
+ },
+ {
+ "fieldname": "agent_list",
+ "fieldtype": "Table MultiSelect",
+ "label": "Agents",
+ "options": "Assignment Rule User",
+ "reqd": 1
+ },
+ {
+ "default": "0",
+ "fieldname": "enable_scheduling",
+ "fieldtype": "Check",
+ "label": "Enable Appointment Scheduling",
+ "reqd": 1
+ },
+ {
+ "fieldname": "agent_detail_section",
+ "fieldtype": "Section Break",
+ "label": "Agent Details"
+ },
+ {
+ "fieldname": "appointment_details_section",
+ "fieldtype": "Section Break",
+ "label": "Appointment Details"
+ },
+ {
+ "fieldname": "success_details",
+ "fieldtype": "Section Break",
+ "label": "Success Settings"
+ },
+ {
+ "description": "Leave blank for home.\nThis is relative to site URL, for example \"about\" will redirect to \"https://yoursitename.com/about\"",
+ "fieldname": "success_redirect_url",
+ "fieldtype": "Data",
+ "label": "Success Redirect URL"
+ }
+ ],
+ "issingle": 1,
+ "modified": "2019-11-26 12:14:17.669366",
+ "modified_by": "Administrator",
+ "module": "CRM",
+ "name": "Appointment Booking Settings",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "role": "System Manager",
+ "share": 1,
+ "write": 1
+ },
+ {
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "role": "Guest",
+ "share": 1
+ },
+ {
+ "create": 1,
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "role": "HR Manager",
+ "share": 1,
+ "write": 1
+ },
+ {
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "role": "Sales Manager",
+ "share": 1,
+ "write": 1
+ }
+ ],
+ "quick_entry": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/crm/doctype/appointment_booking_settings/appointment_booking_settings.py b/erpnext/crm/doctype/appointment_booking_settings/appointment_booking_settings.py
new file mode 100644
index 0000000..27f14b1
--- /dev/null
+++ b/erpnext/crm/doctype/appointment_booking_settings/appointment_booking_settings.py
@@ -0,0 +1,43 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe import _
+import datetime
+from frappe.model.document import Document
+
+
+class AppointmentBookingSettings(Document):
+ agent_list = [] #Hack
+ min_date = '01/01/1970 '
+ format_string = "%d/%m/%Y %H:%M:%S"
+
+ def validate(self):
+ self.validate_availability_of_slots()
+
+ def save(self):
+ self.number_of_agents = len(self.agent_list)
+ super(AppointmentBookingSettings, self).save()
+
+ def validate_availability_of_slots(self):
+ for record in self.availability_of_slots:
+ from_time = datetime.datetime.strptime(
+ self.min_date+record.from_time, self.format_string)
+ to_time = datetime.datetime.strptime(
+ self.min_date+record.to_time, self.format_string)
+ timedelta = to_time-from_time
+ self.validate_from_and_to_time(from_time, to_time)
+ self.duration_is_divisible(from_time, to_time)
+
+ def validate_from_and_to_time(self, from_time, to_time):
+ if from_time > to_time:
+ err_msg = _('<b>From Time</b> cannot be later than <b>To Time</b> for {0}').format(record.day_of_week)
+ frappe.throw(_(err_msg))
+
+ def duration_is_divisible(self, from_time, to_time):
+ timedelta = to_time - from_time
+ if timedelta.total_seconds() % (self.appointment_duration * 60):
+ frappe.throw(
+ _('The difference between from time and To Time must be a multiple of Appointment'))
diff --git a/erpnext/crm/doctype/appointment_booking_settings/test_appointment_booking_settings.py b/erpnext/crm/doctype/appointment_booking_settings/test_appointment_booking_settings.py
new file mode 100644
index 0000000..3dc3c39
--- /dev/null
+++ b/erpnext/crm/doctype/appointment_booking_settings/test_appointment_booking_settings.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+# import frappe
+import unittest
+
+class TestAppointmentBookingSettings(unittest.TestCase):
+ pass
diff --git a/erpnext/assets/doctype/asset_settings/__init__.py b/erpnext/crm/doctype/appointment_booking_slots/__init__.py
similarity index 100%
copy from erpnext/assets/doctype/asset_settings/__init__.py
copy to erpnext/crm/doctype/appointment_booking_slots/__init__.py
diff --git a/erpnext/crm/doctype/appointment_booking_slots/appointment_booking_slots.json b/erpnext/crm/doctype/appointment_booking_slots/appointment_booking_slots.json
new file mode 100644
index 0000000..ddf8738
--- /dev/null
+++ b/erpnext/crm/doctype/appointment_booking_slots/appointment_booking_slots.json
@@ -0,0 +1,46 @@
+{
+ "creation": "2019-11-19 10:49:49.494927",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "day_of_week",
+ "from_time",
+ "to_time"
+ ],
+ "fields": [
+ {
+ "fieldname": "day_of_week",
+ "fieldtype": "Select",
+ "in_list_view": 1,
+ "label": "Day Of Week",
+ "options": "Sunday\nMonday\nTuesday\nWednesday\nThursday\nFriday\nSaturday",
+ "reqd": 1
+ },
+ {
+ "fieldname": "from_time",
+ "fieldtype": "Time",
+ "in_list_view": 1,
+ "label": "From Time ",
+ "reqd": 1
+ },
+ {
+ "fieldname": "to_time",
+ "fieldtype": "Time",
+ "in_list_view": 1,
+ "label": "To Time",
+ "reqd": 1
+ }
+ ],
+ "istable": 1,
+ "modified": "2019-11-19 10:49:49.494927",
+ "modified_by": "Administrator",
+ "module": "CRM",
+ "name": "Appointment Booking Slots",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/crm/doctype/appointment_booking_slots/appointment_booking_slots.py b/erpnext/crm/doctype/appointment_booking_slots/appointment_booking_slots.py
new file mode 100644
index 0000000..3cadbc9
--- /dev/null
+++ b/erpnext/crm/doctype/appointment_booking_slots/appointment_booking_slots.py
@@ -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 AppointmentBookingSlots(Document):
+ pass
diff --git a/erpnext/assets/doctype/asset_settings/__init__.py b/erpnext/crm/doctype/availability_of_slots/__init__.py
similarity index 100%
copy from erpnext/assets/doctype/asset_settings/__init__.py
copy to erpnext/crm/doctype/availability_of_slots/__init__.py
diff --git a/erpnext/crm/doctype/availability_of_slots/availability_of_slots.json b/erpnext/crm/doctype/availability_of_slots/availability_of_slots.json
new file mode 100644
index 0000000..b54af8d
--- /dev/null
+++ b/erpnext/crm/doctype/availability_of_slots/availability_of_slots.json
@@ -0,0 +1,46 @@
+{
+ "creation": "2019-09-10 15:02:05.779434",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "day_of_week",
+ "from_time",
+ "to_time"
+ ],
+ "fields": [
+ {
+ "fieldname": "day_of_week",
+ "fieldtype": "Select",
+ "in_list_view": 1,
+ "label": "Day Of Week",
+ "options": "Sunday\nMonday\nTuesday\nWednesday\nThursday\nFriday\nSaturday",
+ "reqd": 1
+ },
+ {
+ "fieldname": "from_time",
+ "fieldtype": "Time",
+ "in_list_view": 1,
+ "label": "From Time",
+ "reqd": 1
+ },
+ {
+ "fieldname": "to_time",
+ "fieldtype": "Time",
+ "in_list_view": 1,
+ "label": "To Time",
+ "reqd": 1
+ }
+ ],
+ "istable": 1,
+ "modified": "2019-09-10 15:05:20.406855",
+ "modified_by": "Administrator",
+ "module": "CRM",
+ "name": "Availability Of Slots",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/crm/doctype/availability_of_slots/availability_of_slots.py b/erpnext/crm/doctype/availability_of_slots/availability_of_slots.py
new file mode 100644
index 0000000..8258471
--- /dev/null
+++ b/erpnext/crm/doctype/availability_of_slots/availability_of_slots.py
@@ -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 AvailabilityOfSlots(Document):
+ pass
diff --git a/erpnext/crm/doctype/email_campaign/email_campaign.json b/erpnext/crm/doctype/email_campaign/email_campaign.json
index 3259136..736a9d6 100644
--- a/erpnext/crm/doctype/email_campaign/email_campaign.json
+++ b/erpnext/crm/doctype/email_campaign/email_campaign.json
@@ -52,7 +52,8 @@
"fieldtype": "Select",
"in_list_view": 1,
"label": "Email Campaign For ",
- "options": "\nLead\nContact"
+ "options": "\nLead\nContact",
+ "reqd": 1
},
{
"fieldname": "recipient",
@@ -69,7 +70,7 @@
"options": "User"
}
],
- "modified": "2019-07-12 13:47:37.261213",
+ "modified": "2019-11-11 17:18:47.342839",
"modified_by": "Administrator",
"module": "CRM",
"name": "Email Campaign",
diff --git a/erpnext/crm/doctype/email_campaign/email_campaign.py b/erpnext/crm/doctype/email_campaign/email_campaign.py
index 98e4927..00a4bd1 100644
--- a/erpnext/crm/doctype/email_campaign/email_campaign.py
+++ b/erpnext/crm/doctype/email_campaign/email_campaign.py
@@ -41,7 +41,8 @@
email_campaign_exists = frappe.db.exists("Email Campaign", {
"campaign_name": self.campaign_name,
"recipient": self.recipient,
- "status": ("in", ["In Progress", "Scheduled"])
+ "status": ("in", ["In Progress", "Scheduled"]),
+ "name": ("!=", self.name)
})
if email_campaign_exists:
frappe.throw(_("The Campaign '{0}' already exists for the {1} '{2}'").format(self.campaign_name, self.email_campaign_for, self.recipient))
@@ -73,13 +74,13 @@
email_template = frappe.get_doc("Email Template", entry.get("email_template"))
sender = frappe.db.get_value("User", email_campaign.get("sender"), 'email')
-
+ context = {"doc": frappe.get_doc(email_campaign.email_campaign_for, email_campaign.recipient)}
# send mail and link communication to document
comm = make(
doctype = "Email Campaign",
name = email_campaign.name,
- subject = email_template.get("subject"),
- content = email_template.get("response"),
+ subject = frappe.render_template(email_template.get("subject"), context),
+ content = frappe.render_template(email_template.get("response"), context),
sender = sender,
recipients = recipient,
communication_medium = "Email",
diff --git a/erpnext/crm/doctype/lead/lead.js b/erpnext/crm/doctype/lead/lead.js
index 122e2b4..0c88d28 100644
--- a/erpnext/crm/doctype/lead/lead.js
+++ b/erpnext/crm/doctype/lead/lead.js
@@ -1,4 +1,4 @@
-// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
+// Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
frappe.provide("erpnext");
@@ -7,57 +7,54 @@
erpnext.LeadController = frappe.ui.form.Controller.extend({
setup: function () {
this.frm.make_methods = {
+ 'Customer': this.make_customer,
'Quotation': this.make_quotation,
- 'Opportunity': this.create_opportunity
- }
-
- this.frm.fields_dict.customer.get_query = function (doc, cdt, cdn) {
- return { query: "erpnext.controllers.queries.customer_query" }
- }
+ 'Opportunity': this.make_opportunity
+ };
this.frm.toggle_reqd("lead_name", !this.frm.doc.organization_lead);
},
onload: function () {
- if (cur_frm.fields_dict.lead_owner.df.options.match(/^User/)) {
- cur_frm.fields_dict.lead_owner.get_query = function (doc, cdt, cdn) {
- return { query: "frappe.core.doctype.user.user.user_query" }
- }
- }
+ this.frm.set_query("customer", function (doc, cdt, cdn) {
+ return { query: "erpnext.controllers.queries.customer_query" }
+ });
- if (cur_frm.fields_dict.contact_by.df.options.match(/^User/)) {
- cur_frm.fields_dict.contact_by.get_query = function (doc, cdt, cdn) {
- return { query: "frappe.core.doctype.user.user.user_query" }
- }
- }
+ this.frm.set_query("lead_owner", function (doc, cdt, cdn) {
+ return { query: "frappe.core.doctype.user.user.user_query" }
+ });
+
+ this.frm.set_query("contact_by", function (doc, cdt, cdn) {
+ return { query: "frappe.core.doctype.user.user.user_query" }
+ });
},
refresh: function () {
- var doc = this.frm.doc;
+ let doc = this.frm.doc;
erpnext.toggle_naming_series();
frappe.dynamic_link = { doc: doc, fieldname: 'name', doctype: 'Lead' }
- if(!doc.__islocal && doc.__onload && !doc.__onload.is_customer) {
- this.frm.add_custom_button(__("Customer"), this.create_customer, __('Create'));
- this.frm.add_custom_button(__("Opportunity"), this.create_opportunity, __('Create'));
- this.frm.add_custom_button(__("Quotation"), this.make_quotation, __('Create'));
+ if (!this.frm.is_new() && doc.__onload && !doc.__onload.is_customer) {
+ this.frm.add_custom_button(__("Customer"), this.make_customer, __("Create"));
+ this.frm.add_custom_button(__("Opportunity"), this.make_opportunity, __("Create"));
+ this.frm.add_custom_button(__("Quotation"), this.make_quotation, __("Create"));
}
- if (!this.frm.doc.__islocal) {
- frappe.contacts.render_address_and_contact(cur_frm);
+ if (!this.frm.is_new()) {
+ frappe.contacts.render_address_and_contact(this.frm);
} else {
- frappe.contacts.clear_address_and_contact(cur_frm);
+ frappe.contacts.clear_address_and_contact(this.frm);
}
},
- create_customer: function () {
+ make_customer: function () {
frappe.model.open_mapped_doc({
method: "erpnext.crm.doctype.lead.lead.make_customer",
frm: cur_frm
})
},
- create_opportunity: function () {
+ make_opportunity: function () {
frappe.model.open_mapped_doc({
method: "erpnext.crm.doctype.lead.lead.make_opportunity",
frm: cur_frm
@@ -77,7 +74,7 @@
},
company_name: function () {
- if (this.frm.doc.organization_lead == 1) {
+ if (this.frm.doc.organization_lead && !this.frm.doc.lead_name) {
this.frm.set_value("lead_name", this.frm.doc.company_name);
}
},
@@ -85,7 +82,7 @@
contact_date: function () {
if (this.frm.doc.contact_date) {
let d = moment(this.frm.doc.contact_date);
- d.add(1, "hours");
+ d.add(1, "day");
this.frm.set_value("ends_on", d.format(frappe.defaultDatetimeFormat));
}
}
diff --git a/erpnext/crm/doctype/lead/lead.json b/erpnext/crm/doctype/lead/lead.json
index 3c22dc7..bc007b1 100644
--- a/erpnext/crm/doctype/lead/lead.json
+++ b/erpnext/crm/doctype/lead/lead.json
@@ -1,1436 +1,445 @@
{
- "allow_copy": 0,
+ "actions": [],
"allow_events_in_timeline": 1,
- "allow_guest_to_view": 0,
"allow_import": 1,
- "allow_rename": 0,
"autoname": "naming_series:",
- "beta": 0,
"creation": "2013-04-10 11:45:37",
- "custom": 0,
- "docstatus": 0,
"doctype": "DocType",
"document_type": "Document",
- "editable_grid": 0,
+ "engine": "InnoDB",
+ "field_order": [
+ "organization_lead",
+ "lead_details",
+ "naming_series",
+ "lead_name",
+ "company_name",
+ "email_id",
+ "col_break123",
+ "lead_owner",
+ "status",
+ "salutation",
+ "designation",
+ "gender",
+ "source",
+ "customer",
+ "campaign_name",
+ "image",
+ "section_break_12",
+ "contact_by",
+ "column_break_14",
+ "contact_date",
+ "ends_on",
+ "notes_section",
+ "notes",
+ "address_info",
+ "address_html",
+ "address_title",
+ "address_line1",
+ "address_line2",
+ "city",
+ "county",
+ "column_break2",
+ "contact_html",
+ "state",
+ "country",
+ "pincode",
+ "contact_section",
+ "phone",
+ "mobile_no",
+ "fax",
+ "more_info",
+ "type",
+ "market_segment",
+ "industry",
+ "request_type",
+ "column_break3",
+ "company",
+ "website",
+ "territory",
+ "unsubscribed",
+ "blog_subscriber",
+ "title"
+ ],
"fields": [
{
- "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": "organization_lead",
"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": "Lead is an Organization",
- "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": 1,
- "translatable": 0,
- "unique": 0
+ "set_only_once": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "lead_details",
"fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "",
- "length": 0,
- "no_copy": 0,
- "options": "fa fa-user",
- "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": "fa fa-user"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "",
- "fetch_if_empty": 0,
"fieldname": "naming_series",
"fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Series",
- "length": 0,
"no_copy": 1,
"oldfieldname": "naming_series",
"oldfieldtype": "Select",
"options": "CRM-LEAD-.YYYY.-",
- "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": 1,
- "translatable": 0,
- "unique": 0
+ "set_only_once": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:!doc.organization_lead",
- "fetch_if_empty": 0,
"fieldname": "lead_name",
"fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
"in_global_search": 1,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Person Name",
- "length": 0,
- "no_copy": 0,
"oldfieldname": "lead_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": 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,
- "fetch_if_empty": 0,
"fieldname": "company_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": "Organization Name",
- "length": 0,
- "no_copy": 0,
"oldfieldname": "company_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": 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": "email_id",
"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": "Email Address",
- "length": 0,
- "no_copy": 0,
"oldfieldname": "email_id",
"oldfieldtype": "Data",
"options": "Email",
- "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": 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,
- "fetch_if_empty": 0,
"fieldname": "col_break123",
"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,
"width": "50%"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"default": "__user",
- "fetch_if_empty": 0,
"fieldname": "lead_owner",
"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": "Lead Owner",
- "length": 0,
- "no_copy": 0,
"oldfieldname": "lead_owner",
"oldfieldtype": "Link",
"options": "User",
- "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": 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,
"default": "Lead",
- "fetch_if_empty": 0,
"fieldname": "status",
"fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 1,
"label": "Status",
- "length": 0,
"no_copy": 1,
"oldfieldname": "status",
"oldfieldtype": "Select",
"options": "Lead\nOpen\nReplied\nOpportunity\nQuotation\nLost Quotation\nInterested\nConverted\nDo Not Contact",
- "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": 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,
- "depends_on": "eval:!doc.organization_lead",
- "fetch_if_empty": 0,
+ "depends_on": "eval: doc.__islocal",
+ "fieldname": "salutation",
+ "fieldtype": "Link",
+ "label": "Salutation",
+ "options": "Salutation"
+ },
+ {
"fieldname": "gender",
"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": "Gender",
- "length": 0,
- "no_copy": 0,
- "options": "Gender",
- "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": "Gender"
},
{
- "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": "source",
"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": "Source",
- "length": 0,
- "no_copy": 0,
"oldfieldname": "source",
"oldfieldtype": "Select",
- "options": "Lead Source",
- "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": "Lead Source"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"depends_on": "eval:doc.source == 'Existing Customer'",
- "fetch_if_empty": 0,
"fieldname": "customer",
"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 Customer",
- "length": 0,
"no_copy": 1,
"oldfieldname": "customer",
"oldfieldtype": "Link",
- "options": "Customer",
- "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"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"depends_on": "eval: doc.source==\"Campaign\"",
- "description": "",
- "fetch_if_empty": 0,
"fieldname": "campaign_name",
"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": "Campaign Name",
- "length": 0,
- "no_copy": 0,
"oldfieldname": "campaign_name",
"oldfieldtype": "Link",
- "options": "Campaign",
- "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": "Campaign"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "image",
"fieldtype": "Attach Image",
"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": "Image",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "print_hide": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "section_break_12",
"fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Follow Up",
- "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": "Follow Up"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "contact_by",
"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": "Next Contact By",
- "length": 0,
- "no_copy": 0,
"oldfieldname": "contact_by",
"oldfieldtype": "Link",
"options": "User",
- "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,
"width": "100px"
},
{
- "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_14",
- "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": 1,
- "collapsible": 0,
- "columns": 0,
- "description": "",
- "fetch_if_empty": 0,
"fieldname": "contact_date",
"fieldtype": "Datetime",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Next Contact Date",
- "length": 0,
"no_copy": 1,
"oldfieldname": "contact_date",
"oldfieldtype": "Date",
- "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,
"width": "100px"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
"bold": 1,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "ends_on",
"fieldtype": "Datetime",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Ends On",
- "length": 0,
- "no_copy": 1,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "no_copy": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
"collapsible": 1,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "notes_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": "Notes",
- "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": "Notes"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "notes",
"fieldtype": "Text Editor",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Notes",
- "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": "Notes"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "contact_info",
- "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": "Address & Contact",
- "length": 0,
- "no_copy": 0,
- "oldfieldtype": "Column Break",
- "options": "fa fa-map-marker",
- "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
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:doc.__islocal",
- "fetch_if_empty": 0,
- "fieldname": "address_desc",
- "fieldtype": "HTML",
- "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": "Address Desc",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "address_html",
"fieldtype": "HTML",
- "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": "Address HTML",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "read_only": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
+ "depends_on": "eval: doc.__islocal",
+ "fieldname": "address_title",
+ "fieldtype": "Data",
+ "label": "Address Title"
+ },
+ {
+ "depends_on": "eval: doc.__islocal",
+ "fieldname": "address_line1",
+ "fieldtype": "Data",
+ "label": "Address Line 1"
+ },
+ {
+ "depends_on": "eval: doc.__islocal",
+ "fieldname": "address_line2",
+ "fieldtype": "Data",
+ "label": "Address Line 2"
+ },
+ {
+ "depends_on": "eval: doc.__islocal",
+ "fieldname": "city",
+ "fieldtype": "Data",
+ "label": "City/Town"
+ },
+ {
+ "depends_on": "eval: doc.__islocal",
+ "fieldname": "county",
+ "fieldtype": "Data",
+ "label": "County"
+ },
+ {
+ "depends_on": "eval: doc.__islocal",
+ "fieldname": "state",
+ "fieldtype": "Data",
+ "label": "State"
+ },
+ {
+ "depends_on": "eval: doc.__islocal",
+ "fieldname": "country",
+ "fieldtype": "Link",
+ "label": "Country",
+ "options": "Country"
+ },
+ {
+ "depends_on": "eval: doc.__islocal",
+ "fieldname": "pincode",
+ "fieldtype": "Data",
+ "label": "Postal Code",
+ "options": "Country"
+ },
+ {
"fieldname": "column_break2",
- "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,
- "depends_on": "eval:doc.organization_lead",
- "fetch_if_empty": 0,
"fieldname": "contact_html",
"fieldtype": "HTML",
- "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": "Contact HTML",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "read_only": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:!doc.organization_lead",
- "fetch_if_empty": 0,
+ "depends_on": "eval: doc.__islocal",
"fieldname": "phone",
"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": "Phone",
- "length": 0,
- "no_copy": 0,
"oldfieldname": "contact_no",
- "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,
- "depends_on": "eval:!doc.organization_lead",
- "fetch_if_empty": 0,
- "fieldname": "salutation",
- "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": "Salutation",
- "length": 0,
- "no_copy": 0,
- "options": "Salutation",
- "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
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:!doc.organization_lead",
- "fetch_if_empty": 0,
+ "depends_on": "eval: doc.__islocal",
"fieldname": "mobile_no",
"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": "Mobile No.",
- "length": 0,
- "no_copy": 0,
"oldfieldname": "mobile_no",
- "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,
- "depends_on": "eval:!doc.organization_lead",
- "fetch_if_empty": 0,
+ "depends_on": "eval: doc.__islocal",
"fieldname": "fax",
"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": "Fax",
- "length": 0,
- "no_copy": 0,
"oldfieldname": "fax",
- "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": "website",
- "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": "Website",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "website",
- "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
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "",
- "fetch_if_empty": 0,
- "fieldname": "territory",
- "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": "Territory",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "territory",
- "oldfieldtype": "Link",
- "options": "Territory",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
"collapsible": 1,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "more_info",
"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": "More Information",
- "length": 0,
- "no_copy": 0,
"oldfieldtype": "Section Break",
- "options": "fa fa-file-text",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "options": "fa fa-file-text"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 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": 0,
"label": "Lead Type",
- "length": 0,
- "no_copy": 0,
"oldfieldname": "type",
"oldfieldtype": "Select",
- "options": "\nClient\nChannel Partner\nConsultant",
- "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": "\nClient\nChannel Partner\nConsultant"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "market_segment",
"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": "Market Segment",
- "length": 0,
- "no_copy": 0,
"oldfieldname": "market_segment",
"oldfieldtype": "Select",
- "options": "Market Segment",
- "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": "Market Segment"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "industry",
"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": "Industry",
- "length": 0,
- "no_copy": 0,
"oldfieldname": "industry",
"oldfieldtype": "Link",
- "options": "Industry Type",
- "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": "Industry Type"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "request_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": 0,
"label": "Request Type",
- "length": 0,
- "no_copy": 0,
"oldfieldname": "request_type",
"oldfieldtype": "Select",
- "options": "\nProduct Enquiry\nRequest for Information\nSuggestions\nOther",
- "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": "\nProduct Enquiry\nRequest for Information\nSuggestions\nOther"
},
{
- "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_break3",
"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,
"oldfieldtype": "Column Break",
- "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,
"width": "50%"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "company",
"fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Company",
- "length": 0,
- "no_copy": 0,
"oldfieldname": "company",
"oldfieldtype": "Link",
"options": "Company",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 1,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "remember_last_selected_value": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
+ "fieldname": "website",
+ "fieldtype": "Data",
+ "label": "Website",
+ "oldfieldname": "website",
+ "oldfieldtype": "Data"
+ },
+ {
+ "fieldname": "territory",
+ "fieldtype": "Link",
+ "label": "Territory",
+ "oldfieldname": "territory",
+ "oldfieldtype": "Link",
+ "options": "Territory",
+ "print_hide": 1
+ },
+ {
+ "default": "0",
"fieldname": "unsubscribed",
"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": "Unsubscribed",
- "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": "Unsubscribed"
},
{
- "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": "blog_subscriber",
"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": "Blog Subscriber",
- "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": "Blog Subscriber"
+ },
+ {
+ "fieldname": "title",
+ "fieldtype": "Data",
+ "hidden": 1,
+ "label": "Title",
+ "print_hide": 1
+ },
+ {
+ "fieldname": "designation",
+ "fieldtype": "Link",
+ "label": "Designation",
+ "options": "Designation"
+ },
+ {
+ "collapsible": 1,
+ "collapsible_depends_on": "eval: doc.__islocal",
+ "fieldname": "address_info",
+ "fieldtype": "Section Break",
+ "label": "Address & Contact",
+ "oldfieldtype": "Column Break",
+ "options": "fa fa-map-marker"
+ },
+ {
+ "collapsible": 1,
+ "collapsible_depends_on": "eval: doc.__islocal",
+ "fieldname": "contact_section",
+ "fieldtype": "Section Break",
+ "label": "Contact"
}
],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
"icon": "fa fa-user",
"idx": 5,
"image_field": "image",
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2019-06-18 03:22:57.283628",
+ "links": [],
+ "modified": "2019-12-24 16:00:44.239168",
"modified_by": "Administrator",
"module": "CRM",
"name": "Lead",
@@ -1438,128 +447,69 @@
"owner": "Administrator",
"permissions": [
{
- "amend": 0,
- "cancel": 0,
- "create": 0,
- "delete": 0,
- "email": 0,
- "export": 0,
- "if_owner": 0,
- "import": 0,
"permlevel": 1,
- "print": 0,
"read": 1,
"report": 1,
- "role": "All",
- "set_user_permissions": 0,
- "share": 0,
- "submit": 0,
- "write": 0
+ "role": "All"
},
{
- "amend": 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": "Sales User",
- "set_user_permissions": 0,
"share": 1,
- "submit": 0,
"write": 1
},
{
- "amend": 0,
- "cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
- "if_owner": 0,
"import": 1,
- "permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Sales Manager",
- "set_user_permissions": 0,
"share": 1,
- "submit": 0,
"write": 1
},
{
- "amend": 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": "System 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": 1,
- "print": 0,
"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": 0,
- "export": 0,
- "if_owner": 0,
- "import": 0,
"permlevel": 1,
- "print": 0,
"read": 1,
"report": 1,
- "role": "Sales User",
- "set_user_permissions": 0,
- "share": 0,
- "submit": 0,
- "write": 0
+ "role": "Sales User"
+ },
+ {
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Guest",
+ "share": 1
}
],
- "quick_entry": 0,
- "read_only": 0,
"search_fields": "lead_name,lead_owner,status",
"show_name_in_global_search": 1,
"sort_field": "modified",
"sort_order": "DESC",
- "title_field": "lead_name",
- "track_changes": 0,
- "track_seen": 0,
- "track_views": 0
+ "title_field": "title"
}
\ No newline at end of file
diff --git a/erpnext/crm/doctype/lead/lead.py b/erpnext/crm/doctype/lead/lead.py
index 1dae4b9..6cab18dc 100644
--- a/erpnext/crm/doctype/lead/lead.py
+++ b/erpnext/crm/doctype/lead/lead.py
@@ -2,18 +2,19 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
-from frappe import _
-from frappe.utils import (cstr, validate_email_address, cint, comma_and, has_gravatar, now, getdate, nowdate)
-from frappe.model.mapper import get_mapped_doc
-from erpnext.controllers.selling_controller import SellingController
-from frappe.contacts.address_and_contact import load_address_and_contact
+import frappe
from erpnext.accounts.party import set_taxes
+from erpnext.controllers.selling_controller import SellingController
+from frappe import _
+from frappe.contacts.address_and_contact import load_address_and_contact
from frappe.email.inbox import link_communication_to_document
+from frappe.model.mapper import get_mapped_doc
+from frappe.utils import cint, comma_and, cstr, getdate, has_gravatar, nowdate, validate_email_address
sender_field = "email_id"
+
class Lead(SellingController):
def get_feed(self):
return '{0}: {1}'.format(_(self.status), self.lead_name)
@@ -23,15 +24,23 @@
self.get("__onload").is_customer = customer
load_address_and_contact(self)
+ def before_insert(self):
+ self.address_doc = self.create_address()
+ self.contact_doc = self.create_contact()
+
+ def after_insert(self):
+ self.update_links()
+ # after the address and contact are created, flush the field values
+ # to avoid inconsistent reporting in case the documents are changed
+ self.flush_address_and_contact_fields()
+
def validate(self):
self.set_lead_name()
+ self.set_title()
self._prev = frappe._dict({
- "contact_date": frappe.db.get_value("Lead", self.name, "contact_date") if \
- (not cint(self.get("__islocal"))) else None,
- "ends_on": frappe.db.get_value("Lead", self.name, "ends_on") if \
- (not cint(self.get("__islocal"))) else None,
- "contact_by": frappe.db.get_value("Lead", self.name, "contact_by") if \
- (not cint(self.get("__islocal"))) else None,
+ "contact_date": frappe.db.get_value("Lead", self.name, "contact_date") if (not cint(self.is_new())) else None,
+ "ends_on": frappe.db.get_value("Lead", self.name, "ends_on") if (not cint(self.is_new())) else None,
+ "contact_by": frappe.db.get_value("Lead", self.name, "contact_by") if (not cint(self.is_new())) else None,
})
self.set_status()
@@ -39,7 +48,7 @@
if self.email_id:
if not self.flags.ignore_email_validation:
- validate_email_address(self.email_id, True)
+ validate_email_address(self.email_id, throw=True)
if self.email_id == self.lead_owner:
frappe.throw(_("Lead Owner cannot be same as the Lead"))
@@ -53,8 +62,7 @@
if self.contact_date and getdate(self.contact_date) < getdate(nowdate()):
frappe.throw(_("Next Contact Date cannot be in the past"))
- if self.ends_on and self.contact_date and\
- (self.ends_on < self.contact_date):
+ if self.ends_on and self.contact_date and (self.ends_on < self.contact_date):
frappe.throw(_("Ends On date cannot be before Next Contact Date."))
def on_update(self):
@@ -66,23 +74,21 @@
"starts_on": self.contact_date,
"ends_on": self.ends_on or "",
"subject": ('Contact ' + cstr(self.lead_name)),
- "description": ('Contact ' + cstr(self.lead_name)) + \
- (self.contact_by and ('. By : ' + cstr(self.contact_by)) or '')
+ "description": ('Contact ' + cstr(self.lead_name)) + (self.contact_by and ('. By : ' + cstr(self.contact_by)) or '')
}, force)
def check_email_id_is_unique(self):
if self.email_id:
# validate email is unique
- duplicate_leads = frappe.db.sql_list("""select name from tabLead
- where email_id=%s and name!=%s""", (self.email_id, self.name))
+ duplicate_leads = frappe.get_all("Lead", filters={"email_id": self.email_id, "name": ["!=", self.name]})
+ duplicate_leads = [lead.name for lead in duplicate_leads]
if duplicate_leads:
frappe.throw(_("Email Address must be unique, already exists for {0}")
.format(comma_and(duplicate_leads)), frappe.DuplicateEntryError)
def on_trash(self):
- frappe.db.sql("""update `tabIssue` set lead='' where lead=%s""",
- self.name)
+ frappe.db.sql("""update `tabIssue` set lead='' where lead=%s""", self.name)
self.delete_events()
@@ -115,10 +121,101 @@
self.lead_name = self.company_name
+ def set_title(self):
+ if self.organization_lead:
+ self.title = self.company_name
+ else:
+ self.title = self.lead_name
+
+ def create_address(self):
+ address_fields = ["address_title", "address_line1", "address_line2",
+ "city", "county", "state", "country", "pincode"]
+ info_fields = ["email_id", "phone", "fax"]
+
+ # do not create an address if no fields are available,
+ # skipping country since the system auto-sets it from system defaults
+ if not any([self.get(field) for field in address_fields if field != "country"]):
+ return
+
+ address = frappe.new_doc("Address")
+ address.update({addr_field: self.get(addr_field) for addr_field in address_fields})
+ address.update({info_field: self.get(info_field) for info_field in info_fields})
+ address.insert()
+
+ return address
+
+ def create_contact(self):
+ if not self.lead_name:
+ self.set_lead_name()
+
+ names = self.lead_name.split(" ")
+ if len(names) > 1:
+ first_name, last_name = names[0], " ".join(names[1:])
+ else:
+ first_name, last_name = self.lead_name, None
+
+ contact = frappe.new_doc("Contact")
+ contact.update({
+ "first_name": first_name,
+ "last_name": last_name,
+ "salutation": self.salutation,
+ "gender": self.gender,
+ "designation": self.designation,
+ })
+
+ if self.email_id:
+ contact.append("email_ids", {
+ "email_id": self.email_id,
+ "is_primary": 1
+ })
+
+ if self.phone:
+ contact.append("phone_nos", {
+ "phone": self.phone,
+ "is_primary": 1
+ })
+
+ if self.mobile_no:
+ contact.append("phone_nos", {
+ "phone": self.mobile_no
+ })
+
+ contact.insert()
+
+ return contact
+
+ def update_links(self):
+ # update address links
+ if self.address_doc:
+ self.address_doc.append("links", {
+ "link_doctype": "Lead",
+ "link_name": self.name,
+ "link_title": self.lead_name
+ })
+ self.address_doc.save()
+
+ # update contact links
+ if self.contact_doc:
+ self.contact_doc.append("links", {
+ "link_doctype": "Lead",
+ "link_name": self.name,
+ "link_title": self.lead_name
+ })
+ self.contact_doc.save()
+
+ def flush_address_and_contact_fields(self):
+ fields = ['address_line1', 'address_line2', 'address_title',
+ 'city', 'county', 'country', 'fax', 'pincode', 'state']
+
+ for field in fields:
+ self.set(field, None)
+
+
@frappe.whitelist()
def make_customer(source_name, target_doc=None):
return _make_customer(source_name, target_doc)
+
def _make_customer(source_name, target_doc=None, ignore_permissions=False):
def set_missing_values(source, target):
if source.company_name:
@@ -143,6 +240,7 @@
return doclist
+
@frappe.whitelist()
def make_opportunity(source_name, target_doc=None):
def set_missing_values(source, target):
@@ -164,6 +262,7 @@
return target_doc
+
@frappe.whitelist()
def make_quotation(source_name, target_doc=None):
def set_missing_values(source, target):
@@ -205,7 +304,8 @@
@frappe.whitelist()
def get_lead_details(lead, posting_date=None, company=None):
- if not lead: return {}
+ if not lead:
+ return {}
from erpnext.accounts.party import set_address_details
out = frappe._dict()
@@ -231,6 +331,7 @@
return out
+
@frappe.whitelist()
def make_lead_from_communication(communication, ignore_communication_links=False):
""" raise a issue from email """
@@ -267,4 +368,4 @@
lead = leads[0].name if leads else None
- return lead
\ No newline at end of file
+ return lead
diff --git a/erpnext/crm/doctype/opportunity/opportunity.py b/erpnext/crm/doctype/opportunity/opportunity.py
index 99486fa..2880c80 100644
--- a/erpnext/crm/doctype/opportunity/opportunity.py
+++ b/erpnext/crm/doctype/opportunity/opportunity.py
@@ -130,10 +130,10 @@
def has_lost_quotation(self):
lost_quotation = frappe.db.sql("""
- select q.name
- from `tabQuotation` q, `tabQuotation Item` qi
- where q.name = qi.parent and q.docstatus=1
- and qi.prevdoc_docname =%s and q.status = 'Lost'
+ select name
+ from `tabQuotation`
+ where docstatus=1
+ and opportunity =%s and status = 'Lost'
""", self.name)
if lost_quotation:
if self.has_active_quotation():
diff --git a/erpnext/education/doctype/education_settings/education_settings.json b/erpnext/education/doctype/education_settings/education_settings.json
index 32b5fb8..967a030 100644
--- a/erpnext/education/doctype/education_settings/education_settings.json
+++ b/erpnext/education/doctype/education_settings/education_settings.json
@@ -11,6 +11,7 @@
"validate_batch",
"validate_course",
"academic_term_reqd",
+ "user_creation_skip",
"section_break_7",
"instructor_created_by",
"web_academy_settings_section",
@@ -91,6 +92,13 @@
"fieldname": "enable_lms",
"fieldtype": "Check",
"label": "Enable LMS"
+ },
+ {
+ "default": "0",
+ "description": "By default, a new User is created for every new Student. If enabled, no new User will be created when a new Student is created.",
+ "fieldname": "user_creation_skip",
+ "fieldtype": "Check",
+ "label": "Skip User creation for new Student"
}
],
"issingle": 1,
@@ -133,4 +141,4 @@
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
-}
\ No newline at end of file
+}
diff --git a/erpnext/education/doctype/instructor/instructor.js b/erpnext/education/doctype/instructor/instructor.js
index f9c7a2a..71e044b 100644
--- a/erpnext/education/doctype/instructor/instructor.js
+++ b/erpnext/education/doctype/instructor/instructor.js
@@ -4,11 +4,11 @@
frappe.ui.form.on("Instructor", {
employee: function(frm) {
if(!frm.doc.employee) return;
- frappe.db.get_value('Employee', {name: frm.doc.employee}, 'company', (company) => {
+ frappe.db.get_value('Employee', {name: frm.doc.employee}, 'company', (d) => {
frm.set_query("department", function() {
return {
"filters": {
- "company": company,
+ "company": d.company,
}
};
});
@@ -16,7 +16,7 @@
frm.set_query("department", "instructor_log", function() {
return {
"filters": {
- "company": company,
+ "company": d.company,
}
};
});
diff --git a/erpnext/education/doctype/instructor/instructor.py b/erpnext/education/doctype/instructor/instructor.py
index 0756b5f..28df2fc 100644
--- a/erpnext/education/doctype/instructor/instructor.py
+++ b/erpnext/education/doctype/instructor/instructor.py
@@ -22,3 +22,12 @@
self.name = self.employee
elif naming_method == 'Full Name':
self.name = self.instructor_name
+
+ def validate(self):
+ self.validate_duplicate_employee()
+
+ def validate_duplicate_employee(self):
+ if self.employee and frappe.db.get_value("Instructor", {'employee': self.employee, 'name': ['!=', self.name]}, 'name'):
+ frappe.throw(_("Employee ID is linked with another instructor"))
+
+
diff --git a/erpnext/education/doctype/program_enrollment/program_enrollment.py b/erpnext/education/doctype/program_enrollment/program_enrollment.py
index d5348ff..7536172 100644
--- a/erpnext/education/doctype/program_enrollment/program_enrollment.py
+++ b/erpnext/education/doctype/program_enrollment/program_enrollment.py
@@ -71,7 +71,7 @@
def create_course_enrollments(self):
student = frappe.get_doc("Student", self.student)
program = frappe.get_doc("Program", self.program)
- course_list = [course.course for course in program.get_all_children()]
+ course_list = [course.course for course in program.courses]
for course_name in course_list:
student.enroll_in_course(course_name=course_name, program_enrollment=self.name)
diff --git a/erpnext/education/doctype/student/student.js b/erpnext/education/doctype/student/student.js
index 2c933e2..1936dcb 100644
--- a/erpnext/education/doctype/student/student.js
+++ b/erpnext/education/doctype/student/student.js
@@ -27,3 +27,31 @@
}
}
});
+
+frappe.ui.form.on('Student Guardian', {
+ guardians_add: function(frm){
+ frm.fields_dict['guardians'].grid.get_field('guardian').get_query = function(doc){
+ let guardian_list = [];
+ if(!doc.__islocal) guardian_list.push(doc.guardian);
+ $.each(doc.guardians, function(idx, val){
+ if (val.guardian) guardian_list.push(val.guardian);
+ });
+ return { filters: [['Guardian', 'name', 'not in', guardian_list]] };
+ };
+ }
+});
+
+
+frappe.ui.form.on('Student Sibling', {
+ siblings_add: function(frm){
+ frm.fields_dict['siblings'].grid.get_field('student').get_query = function(doc){
+ let sibling_list = [frm.doc.name];
+ $.each(doc.siblings, function(idx, val){
+ if (val.student && val.studying_in_same_institute == 'YES') {
+ sibling_list.push(val.student);
+ }
+ });
+ return { filters: [['Student', 'name', 'not in', sibling_list]] };
+ };
+ }
+});
\ No newline at end of file
diff --git a/erpnext/education/doctype/student/student.py b/erpnext/education/doctype/student/student.py
index 705c6e4..99c4c0e 100644
--- a/erpnext/education/doctype/student/student.py
+++ b/erpnext/education/doctype/student/student.py
@@ -5,12 +5,14 @@
from __future__ import unicode_literals
import frappe
from frappe.model.document import Document
+from frappe.utils import getdate,today
from frappe import _
from frappe.desk.form.linked_with import get_linked_doctypes
from erpnext.education.utils import check_content_completion, check_quiz_completion
class Student(Document):
def validate(self):
self.title = " ".join(filter(None, [self.first_name, self.middle_name, self.last_name]))
+ self.validate_dates()
if self.student_applicant:
self.check_unique()
@@ -19,6 +21,13 @@
if frappe.get_value("Student", self.name, "title") != self.title:
self.update_student_name_in_linked_doctype()
+ def validate_dates(self):
+ if self.date_of_birth and getdate(self.date_of_birth) >= getdate(today()):
+ frappe.throw(_("Date of Birth cannot be greater than today."))
+
+ if self.joining_date and self.date_of_leaving and getdate(self.joining_date) > getdate(self.date_of_leaving):
+ frappe.throw(_("Joining Date can not be greater than Leaving Date"))
+
def update_student_name_in_linked_doctype(self):
linked_doctypes = get_linked_doctypes("Student")
for d in linked_doctypes:
@@ -40,7 +49,8 @@
frappe.throw(_("Student {0} exist against student applicant {1}").format(student[0][0], self.student_applicant))
def after_insert(self):
- self.create_student_user()
+ if not frappe.get_single('Education Settings').get('user_creation_skip'):
+ self.create_student_user()
def create_student_user(self):
"""Create a website user for student creation if not already exists"""
diff --git a/erpnext/education/doctype/student_group/student_group.js b/erpnext/education/doctype/student_group/student_group.js
index c29c134..4165ce0 100644
--- a/erpnext/education/doctype/student_group/student_group.js
+++ b/erpnext/education/doctype/student_group/student_group.js
@@ -122,3 +122,15 @@
}
}
});
+
+frappe.ui.form.on('Student Group Instructor', {
+ instructors_add: function(frm){
+ frm.fields_dict['instructors'].grid.get_field('instructor').get_query = function(doc){
+ let instructor_list = [];
+ $.each(doc.instructors, function(idx, val){
+ instructor_list.push(val.instructor);
+ });
+ return { filters: [['Instructor', 'name', 'not in', instructor_list]] };
+ };
+ }
+});
\ No newline at end of file
diff --git a/erpnext/erpnext_integrations/connectors/woocommerce_connection.py b/erpnext/erpnext_integrations/connectors/woocommerce_connection.py
index 0b6ea8c..28c2ab9 100644
--- a/erpnext/erpnext_integrations/connectors/woocommerce_connection.py
+++ b/erpnext/erpnext_integrations/connectors/woocommerce_connection.py
@@ -1,10 +1,8 @@
from __future__ import unicode_literals
import frappe, base64, hashlib, hmac, json
-import datetime
from frappe import _
-
def verify_request():
woocommerce_settings = frappe.get_doc("Woocommerce Settings")
sig = base64.b64encode(
@@ -30,191 +28,149 @@
frappe.log_error(error_message, "WooCommerce Error")
raise
-
def _order(*args, **kwargs):
woocommerce_settings = frappe.get_doc("Woocommerce Settings")
if frappe.flags.woocomm_test_order_data:
- fd = frappe.flags.woocomm_test_order_data
+ order = frappe.flags.woocomm_test_order_data
event = "created"
elif frappe.request and frappe.request.data:
verify_request()
- fd = json.loads(frappe.request.data)
+ try:
+ order = json.loads(frappe.request.data)
+ except ValueError:
+ #woocommerce returns 'webhook_id=value' for the first request which is not JSON
+ order = frappe.request.data
event = frappe.get_request_header("X-Wc-Webhook-Event")
else:
return "success"
if event == "created":
- raw_billing_data = fd.get("billing")
- customer_woo_com_email = raw_billing_data.get("email")
-
- if frappe.get_value("Customer",{"woocommerce_email": customer_woo_com_email}):
- # Edit
- link_customer_and_address(raw_billing_data,1)
- else:
- # Create
- link_customer_and_address(raw_billing_data,0)
-
-
- items_list = fd.get("line_items")
- for item in items_list:
-
- item_woo_com_id = item.get("product_id")
-
- if frappe.get_value("Item",{"woocommerce_id": item_woo_com_id}):
- #Edit
- link_item(item,1)
- else:
- link_item(item,0)
-
-
+ raw_billing_data = order.get("billing")
customer_name = raw_billing_data.get("first_name") + " " + raw_billing_data.get("last_name")
+ link_customer_and_address(raw_billing_data, customer_name)
+ link_items(order.get("line_items"), woocommerce_settings)
+ create_sales_order(order, woocommerce_settings, customer_name)
- new_sales_order = frappe.new_doc("Sales Order")
- new_sales_order.customer = customer_name
-
- created_date = fd.get("date_created").split("T")
- new_sales_order.transaction_date = created_date[0]
-
- new_sales_order.po_no = fd.get("id")
- new_sales_order.woocommerce_id = fd.get("id")
- new_sales_order.naming_series = woocommerce_settings.sales_order_series or "SO-WOO-"
-
- placed_order_date = created_date[0]
- raw_date = datetime.datetime.strptime(placed_order_date, "%Y-%m-%d")
- raw_delivery_date = frappe.utils.add_to_date(raw_date,days = 7)
- order_delivery_date_str = raw_delivery_date.strftime('%Y-%m-%d')
- order_delivery_date = str(order_delivery_date_str)
-
- new_sales_order.delivery_date = order_delivery_date
- default_set_company = frappe.get_doc("Global Defaults")
- company = raw_billing_data.get("company") or default_set_company.default_company
- found_company = frappe.get_doc("Company",{"name":company})
- company_abbr = found_company.abbr
-
- new_sales_order.company = company
-
- for item in items_list:
- woocomm_item_id = item.get("product_id")
- found_item = frappe.get_doc("Item",{"woocommerce_id": woocomm_item_id})
-
- ordered_items_tax = item.get("total_tax")
-
- new_sales_order.append("items",{
- "item_code": found_item.item_code,
- "item_name": found_item.item_name,
- "description": found_item.item_name,
- "delivery_date":order_delivery_date,
- "uom": woocommerce_settings.uom or _("Nos"),
- "qty": item.get("quantity"),
- "rate": item.get("price"),
- "warehouse": woocommerce_settings.warehouse or "Stores" + " - " + company_abbr
- })
-
- add_tax_details(new_sales_order,ordered_items_tax,"Ordered Item tax",0)
-
- # shipping_details = fd.get("shipping_lines") # used for detailed order
- shipping_total = fd.get("shipping_total")
- shipping_tax = fd.get("shipping_tax")
-
- add_tax_details(new_sales_order,shipping_tax,"Shipping Tax",1)
- add_tax_details(new_sales_order,shipping_total,"Shipping Total",1)
-
- new_sales_order.submit()
-
- frappe.db.commit()
-
-def link_customer_and_address(raw_billing_data,customer_status):
-
- if customer_status == 0:
- # create
+def link_customer_and_address(raw_billing_data, customer_name):
+ customer_woo_com_email = raw_billing_data.get("email")
+ customer_exists = frappe.get_value("Customer", {"woocommerce_email": customer_woo_com_email})
+ if not customer_exists:
+ # Create Customer
customer = frappe.new_doc("Customer")
- address = frappe.new_doc("Address")
-
- if customer_status == 1:
- # Edit
- customer_woo_com_email = raw_billing_data.get("email")
- customer = frappe.get_doc("Customer",{"woocommerce_email": customer_woo_com_email})
+ else:
+ # Edit Customer
+ customer = frappe.get_doc("Customer", {"woocommerce_email": customer_woo_com_email})
old_name = customer.customer_name
- full_name = str(raw_billing_data.get("first_name"))+ " "+str(raw_billing_data.get("last_name"))
- customer.customer_name = full_name
- customer.woocommerce_email = str(raw_billing_data.get("email"))
- customer.save()
- frappe.db.commit()
+ customer.customer_name = customer_name
+ customer.woocommerce_email = customer_woo_com_email
+ customer.flags.ignore_mandatory = True
+ customer.save()
- if customer_status == 1:
- frappe.rename_doc("Customer", old_name, full_name)
- address = frappe.get_doc("Address",{"woocommerce_email":customer_woo_com_email})
- customer = frappe.get_doc("Customer",{"woocommerce_email": customer_woo_com_email})
+ if customer_exists:
+ frappe.rename_doc("Customer", old_name, customer_name)
+ address = frappe.get_doc("Address", {"woocommerce_email": customer_woo_com_email})
+ else:
+ address = frappe.new_doc("Address")
address.address_line1 = raw_billing_data.get("address_1", "Not Provided")
address.address_line2 = raw_billing_data.get("address_2", "Not Provided")
address.city = raw_billing_data.get("city", "Not Provided")
- address.woocommerce_email = str(raw_billing_data.get("email"))
- address.address_type = "Shipping"
- address.country = frappe.get_value("Country", filters={"code":raw_billing_data.get("country", "IN").lower()})
- address.state = raw_billing_data.get("state")
- address.pincode = str(raw_billing_data.get("postcode"))
- address.phone = str(raw_billing_data.get("phone"))
- address.email_id = str(raw_billing_data.get("email"))
-
+ address.woocommerce_email = customer_woo_com_email
+ address.address_type = "Billing"
+ address.country = frappe.get_value("Country", {"code": raw_billing_data.get("country", "IN").lower()})
+ address.state = raw_billing_data.get("state")
+ address.pincode = raw_billing_data.get("postcode")
+ address.phone = raw_billing_data.get("phone")
+ address.email_id = customer_woo_com_email
address.append("links", {
"link_doctype": "Customer",
"link_name": customer.customer_name
})
+ address.flags.ignore_mandatory = True
+ address = address.save()
- address.save()
- frappe.db.commit()
-
- if customer_status == 1:
-
- address = frappe.get_doc("Address",{"woocommerce_email":customer_woo_com_email})
+ if customer_exists:
old_address_title = address.name
- new_address_title = customer.customer_name+"-billing"
+ new_address_title = customer.customer_name + "-billing"
address.address_title = customer.customer_name
address.save()
- frappe.rename_doc("Address",old_address_title,new_address_title)
+ frappe.rename_doc("Address", old_address_title, new_address_title)
- frappe.db.commit()
-
-def link_item(item_data,item_status):
- woocommerce_settings = frappe.get_doc("Woocommerce Settings")
-
- if item_status == 0:
- #Create Item
- item = frappe.new_doc("Item")
-
- if item_status == 1:
- #Edit Item
+def link_items(items_list, woocommerce_settings):
+ for item_data in items_list:
item_woo_com_id = item_data.get("product_id")
- item = frappe.get_doc("Item",{"woocommerce_id": item_woo_com_id})
- item.item_name = str(item_data.get("name"))
- item.item_code = "woocommerce - " + str(item_data.get("product_id"))
- item.woocommerce_id = str(item_data.get("product_id"))
- item.item_group = _("WooCommerce Products")
- item.stock_uom = woocommerce_settings.uom or _("Nos")
- item.save()
+ if frappe.get_value("Item", {"woocommerce_id": item_woo_com_id}):
+ #Edit Item
+ item = frappe.get_doc("Item", {"woocommerce_id": item_woo_com_id})
+ else:
+ #Create Item
+ item = frappe.new_doc("Item")
+
+ item.item_name = item_data.get("name")
+ item.item_code = _("woocommerce - {0}").format(item_data.get("product_id"))
+ item.woocommerce_id = item_data.get("product_id")
+ item.item_group = _("WooCommerce Products")
+ item.stock_uom = woocommerce_settings.uom or _("Nos")
+ item.flags.ignore_mandatory = True
+ item.save()
+
+def create_sales_order(order, woocommerce_settings, customer_name):
+ new_sales_order = frappe.new_doc("Sales Order")
+ new_sales_order.customer = customer_name
+
+ new_sales_order.po_no = new_sales_order.woocommerce_id = order.get("id")
+ new_sales_order.naming_series = woocommerce_settings.sales_order_series or "SO-WOO-"
+
+ created_date = order.get("date_created").split("T")
+ new_sales_order.transaction_date = created_date[0]
+ delivery_after = woocommerce_settings.delivery_after_days or 7
+ new_sales_order.delivery_date = frappe.utils.add_days(created_date[0], delivery_after)
+
+ new_sales_order.company = woocommerce_settings.company
+
+ set_items_in_sales_order(new_sales_order, woocommerce_settings, order)
+ new_sales_order.flags.ignore_mandatory = True
+ new_sales_order.insert()
+ new_sales_order.submit()
+
frappe.db.commit()
-def add_tax_details(sales_order,price,desc,status):
+def set_items_in_sales_order(new_sales_order, woocommerce_settings, order):
+ company_abbr = frappe.db.get_value('Company', woocommerce_settings.company, 'abbr')
- woocommerce_settings = frappe.get_doc("Woocommerce Settings")
+ for item in order.get("line_items"):
+ woocomm_item_id = item.get("product_id")
+ found_item = frappe.get_doc("Item", {"woocommerce_id": woocomm_item_id})
- if status == 0:
- # Product taxes
- account_head_type = woocommerce_settings.tax_account
+ ordered_items_tax = item.get("total_tax")
- if status == 1:
- # Shipping taxes
- account_head_type = woocommerce_settings.f_n_f_account
+ new_sales_order.append("items",{
+ "item_code": found_item.item_code,
+ "item_name": found_item.item_name,
+ "description": found_item.item_name,
+ "delivery_date": new_sales_order.delivery_date,
+ "uom": woocommerce_settings.uom or _("Nos"),
+ "qty": item.get("quantity"),
+ "rate": item.get("price"),
+ "warehouse": woocommerce_settings.warehouse or _("Stores - {0}").format(company_abbr)
+ })
- sales_order.append("taxes",{
- "charge_type":"Actual",
- "account_head": account_head_type,
- "tax_amount": price,
- "description": desc
- })
+ add_tax_details(new_sales_order, ordered_items_tax, "Ordered Item tax", woocommerce_settings.tax_account)
+
+ # shipping_details = order.get("shipping_lines") # used for detailed order
+
+ add_tax_details(new_sales_order, order.get("shipping_tax"), "Shipping Tax", woocommerce_settings.f_n_f_account)
+ add_tax_details(new_sales_order, order.get("shipping_total"), "Shipping Total", woocommerce_settings.f_n_f_account)
+
+def add_tax_details(sales_order, price, desc, tax_account_head):
+ sales_order.append("taxes", {
+ "charge_type":"Actual",
+ "account_head": tax_account_head,
+ "tax_amount": price,
+ "description": desc
+ })
diff --git a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.json b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.json
index 9903048..df77ad8 100644
--- a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.json
+++ b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.json
@@ -1,4 +1,5 @@
{
+ "actions": [],
"creation": "2018-10-25 10:02:48.656165",
"doctype": "DocType",
"editable_grid": 1,
@@ -23,48 +24,41 @@
},
{
"default": "0",
- "depends_on": "eval:doc.enabled==1",
+ "depends_on": "enabled",
"fieldname": "automatic_sync",
"fieldtype": "Check",
"label": "Synchronize all accounts every hour"
},
{
- "depends_on": "eval:doc.enabled==1",
"fieldname": "plaid_client_id",
"fieldtype": "Data",
"in_list_view": 1,
- "label": "Plaid Client ID",
- "reqd": 1
+ "label": "Plaid Client ID"
},
{
- "depends_on": "eval:doc.enabled==1",
"fieldname": "plaid_secret",
"fieldtype": "Password",
"in_list_view": 1,
- "label": "Plaid Secret",
- "reqd": 1
+ "label": "Plaid Secret"
},
{
- "depends_on": "eval:doc.enabled==1",
"fieldname": "plaid_public_key",
"fieldtype": "Data",
"in_list_view": 1,
- "label": "Plaid Public Key",
- "reqd": 1
+ "label": "Plaid Public Key"
},
{
- "depends_on": "eval:doc.enabled==1",
"fieldname": "plaid_env",
"fieldtype": "Data",
"in_list_view": 1,
- "label": "Plaid Environment",
- "reqd": 1
+ "label": "Plaid Environment"
},
{
"fieldname": "column_break_2",
"fieldtype": "Column Break"
},
{
+ "depends_on": "enabled",
"fieldname": "section_break_4",
"fieldtype": "Section Break"
},
@@ -74,7 +68,8 @@
}
],
"issingle": 1,
- "modified": "2019-08-13 17:00:06.939422",
+ "links": [],
+ "modified": "2020-01-05 10:00:22.137832",
"modified_by": "Administrator",
"module": "ERPNext Integrations",
"name": "Plaid Settings",
diff --git a/erpnext/erpnext_integrations/doctype/shopify_settings/shopify_settings.py b/erpnext/erpnext_integrations/doctype/shopify_settings/shopify_settings.py
index 0cad0cc..64c3b2d 100644
--- a/erpnext/erpnext_integrations/doctype/shopify_settings/shopify_settings.py
+++ b/erpnext/erpnext_integrations/doctype/shopify_settings/shopify_settings.py
@@ -50,7 +50,7 @@
deleted_webhooks = []
for d in self.webhooks:
- url = get_shopify_url('admin/api/2019-04/webhooks.json'.format(d.webhook_id), self)
+ url = get_shopify_url('admin/api/2019-04/webhooks/{0}.json'.format(d.webhook_id), self)
try:
res = session.delete(url, headers=get_header(self))
res.raise_for_status()
diff --git a/erpnext/erpnext_integrations/doctype/woocommerce_settings/woocommerce_settings.json b/erpnext/erpnext_integrations/doctype/woocommerce_settings/woocommerce_settings.json
index dd3c24d..956ae09 100644
--- a/erpnext/erpnext_integrations/doctype/woocommerce_settings/woocommerce_settings.json
+++ b/erpnext/erpnext_integrations/doctype/woocommerce_settings/woocommerce_settings.json
@@ -1,694 +1,175 @@
{
- "allow_copy": 0,
- "allow_events_in_timeline": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "beta": 0,
"creation": "2018-02-12 15:10:05.495713",
- "custom": 0,
- "docstatus": 0,
"doctype": "DocType",
- "document_type": "",
"editable_grid": 1,
"engine": "InnoDB",
+ "field_order": [
+ "enable_sync",
+ "sb_00",
+ "woocommerce_server_url",
+ "secret",
+ "cb_00",
+ "api_consumer_key",
+ "api_consumer_secret",
+ "sb_accounting_details",
+ "tax_account",
+ "column_break_10",
+ "f_n_f_account",
+ "defaults_section",
+ "creation_user",
+ "warehouse",
+ "sales_order_series",
+ "column_break_14",
+ "company",
+ "delivery_after_days",
+ "uom",
+ "endpoints",
+ "endpoint"
+ ],
"fields": [
{
- "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": "enable_sync",
"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": "Enable Sync",
- "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": "Enable Sync"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "sb_00",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "fieldtype": "Section Break"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "woocommerce_server_url",
"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": "Woocommerce Server URL",
- "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": "Woocommerce Server URL"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "secret",
"fieldtype": "Code",
- "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": "Secret",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "read_only": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "cb_00",
- "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,
"fieldname": "api_consumer_key",
"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": "API consumer key",
- "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": "API consumer key"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "api_consumer_secret",
"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": "API consumer secret",
- "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": "API consumer secret"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "sb_accounting_details",
"fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Accounting Details",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "label": "Accounting Details"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "tax_account",
"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": "Tax Account",
- "length": 0,
- "no_copy": 0,
"options": "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": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "reqd": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "column_break_10",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "fieldtype": "Column Break"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "f_n_f_account",
"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": "Freight and Forwarding Account",
- "length": 0,
- "no_copy": 0,
"options": "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": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "reqd": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "defaults_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": "Defaults",
- "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": "Defaults"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"description": "The user that will be used to create Customers, Items and Sales Orders. This user should have the relevant permissions.",
- "fetch_if_empty": 0,
"fieldname": "creation_user",
"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": "Creation User",
- "length": 0,
- "no_copy": 0,
"options": "User",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "reqd": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "This warehouse will be used to create Sale Orders. The fallback warehouse is \"Stores\".",
- "fetch_if_empty": 0,
+ "description": "This warehouse will be used to create Sales Orders. The fallback warehouse is \"Stores\".",
"fieldname": "warehouse",
"fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Warehouse",
- "length": 0,
- "no_copy": 0,
- "options": "Warehouse",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "options": "Warehouse"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "column_break_14",
- "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,
"description": "The fallback series is \"SO-WOO-\".",
- "fetch_if_empty": 0,
"fieldname": "sales_order_series",
"fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Sales Order Series",
- "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": "Sales Order Series"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"description": "This is the default UOM used for items and Sales orders. The fallback UOM is \"Nos\".",
- "fetch_if_empty": 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,
- "options": "UOM",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "options": "UOM"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "endpoints",
"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": "Endpoints",
- "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": "Endpoints"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "endpoint",
"fieldtype": "Code",
- "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": "Endpoint",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "read_only": 1
+ },
+ {
+ "description": "This company will be used to create Sales Orders.",
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "label": "Company",
+ "options": "Company",
+ "reqd": 1
+ },
+ {
+ "description": "This is the default offset (days) for the Delivery Date in Sales Orders. The fallback offset is 7 days from the order placement date.",
+ "fieldname": "delivery_after_days",
+ "fieldtype": "Int",
+ "label": "Delivery After (Days)"
}
],
- "has_web_view": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "in_create": 0,
- "is_submittable": 0,
"issingle": 1,
- "istable": 0,
- "max_attachments": 0,
- "menu_index": 0,
- "modified": "2019-04-08 17:04:16.720696",
+ "modified": "2019-11-04 00:45:21.232096",
"modified_by": "Administrator",
"module": "ERPNext Integrations",
"name": "Woocommerce Settings",
- "name_case": "",
"owner": "Administrator",
"permissions": [
{
- "amend": 0,
- "cancel": 0,
"create": 1,
- "delete": 0,
"email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
"print": 1,
"read": 1,
- "report": 0,
"role": "System Manager",
- "set_user_permissions": 0,
"share": 1,
- "submit": 0,
"write": 1
}
],
"quick_entry": 1,
- "read_only": 0,
- "show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
- "track_changes": 1,
- "track_seen": 0,
- "track_views": 0
+ "track_changes": 1
}
\ No newline at end of file
diff --git a/erpnext/erpnext_integrations/doctype/woocommerce_settings/woocommerce_settings.py b/erpnext/erpnext_integrations/doctype/woocommerce_settings/woocommerce_settings.py
index 055684d..bd072f4 100644
--- a/erpnext/erpnext_integrations/doctype/woocommerce_settings/woocommerce_settings.py
+++ b/erpnext/erpnext_integrations/doctype/woocommerce_settings/woocommerce_settings.py
@@ -8,6 +8,7 @@
from frappe.utils.nestedset import get_root_of
from frappe.model.document import Document
from six.moves.urllib.parse import urlparse
+from frappe.custom.doctype.custom_field.custom_field import create_custom_field
class WoocommerceSettings(Document):
def validate(self):
@@ -17,75 +18,21 @@
def create_delete_custom_fields(self):
if self.enable_sync:
+ custom_fields = {}
# create
- create_custom_field_id_and_check_status = False
- create_custom_field_email_check = False
- names = ["Customer-woocommerce_id","Sales Order-woocommerce_id","Item-woocommerce_id","Address-woocommerce_id"]
- names_check_box = ["Customer-woocommerce_check","Sales Order-woocommerce_check","Item-woocommerce_check","Address-woocommerce_check"]
- email_names = ["Customer-woocommerce_email","Address-woocommerce_email"]
+ for doctype in ["Customer", "Sales Order", "Item", "Address"]:
+ df = dict(fieldname='woocommerce_id', label='Woocommerce ID', fieldtype='Data', read_only=1, print_hide=1)
+ create_custom_field(doctype, df)
- for i in zip(names,names_check_box):
-
- if not frappe.get_value("Custom Field",{"name":i[0]}) or not frappe.get_value("Custom Field",{"name":i[1]}):
- create_custom_field_id_and_check_status = True
- break
-
-
- if create_custom_field_id_and_check_status:
- names = ["Customer","Sales Order","Item","Address"]
- for name in names:
- custom = frappe.new_doc("Custom Field")
- custom.dt = name
- custom.label = "woocommerce_id"
- custom.read_only = 1
- custom.save()
-
- custom = frappe.new_doc("Custom Field")
- custom.dt = name
- custom.label = "woocommerce_check"
- custom.fieldtype = "Check"
- custom.read_only = 1
- custom.save()
-
- for i in email_names:
-
- if not frappe.get_value("Custom Field",{"name":i}):
- create_custom_field_email_check = True
- break;
-
- if create_custom_field_email_check:
- names = ["Customer","Address"]
- for name in names:
- custom = frappe.new_doc("Custom Field")
- custom.dt = name
- custom.label = "woocommerce_email"
- custom.read_only = 1
- custom.save()
-
- if not frappe.get_value("Item Group",{"name": _("WooCommerce Products")}):
+ for doctype in ["Customer", "Address"]:
+ df = dict(fieldname='woocommerce_email', label='Woocommerce Email', fieldtype='Data', read_only=1, print_hide=1)
+ create_custom_field(doctype, df)
+
+ if not frappe.get_value("Item Group", {"name": _("WooCommerce Products")}):
item_group = frappe.new_doc("Item Group")
item_group.item_group_name = _("WooCommerce Products")
item_group.parent_item_group = get_root_of("Item Group")
- item_group.save()
-
-
- elif not self.enable_sync:
- # delete
- names = ["Customer-woocommerce_id","Sales Order-woocommerce_id","Item-woocommerce_id","Address-woocommerce_id"]
- names_check_box = ["Customer-woocommerce_check","Sales Order-woocommerce_check","Item-woocommerce_check","Address-woocommerce_check"]
- email_names = ["Customer-woocommerce_email","Address-woocommerce_email"]
- for name in names:
- frappe.delete_doc("Custom Field",name)
-
- for name in names_check_box:
- frappe.delete_doc("Custom Field",name)
-
- for name in email_names:
- frappe.delete_doc("Custom Field",name)
-
- frappe.delete_doc("Item Group", _("WooCommerce Products"))
-
- frappe.db.commit()
+ item_group.insert()
def validate_settings(self):
if self.enable_sync:
diff --git a/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template.py b/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template.py
index a8a9037..5a71ca5 100644
--- a/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template.py
+++ b/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template.py
@@ -64,10 +64,11 @@
item_code=%s""",(self.template, self.rate, self.item))
def create_item_from_template(doc):
+ disabled = 1
+
if(doc.is_billable == 1):
disabled = 0
- else:
- disabled = 1
+
#insert item
item = frappe.get_doc({
"doctype": "Item",
diff --git a/erpnext/healthcare/doctype/inpatient_record/inpatient_record.py b/erpnext/healthcare/doctype/inpatient_record/inpatient_record.py
index c107cd7..835b38b 100644
--- a/erpnext/healthcare/doctype/inpatient_record/inpatient_record.py
+++ b/erpnext/healthcare/doctype/inpatient_record/inpatient_record.py
@@ -5,7 +5,7 @@
from __future__ import unicode_literals
import frappe
from frappe import _
-from frappe.utils import today, now_datetime
+from frappe.utils import today, now_datetime, getdate
from frappe.model.document import Document
from frappe.desk.reportview import get_match_cond
@@ -15,11 +15,20 @@
frappe.db.set_value("Patient", self.patient, "inpatient_record", self.name)
def validate(self):
+ self.validate_dates()
self.validate_already_scheduled_or_admitted()
if self.status == "Discharged":
frappe.db.set_value("Patient", self.patient, "inpatient_status", None)
frappe.db.set_value("Patient", self.patient, "inpatient_record", None)
+ def validate_dates(self):
+ if (getdate(self.scheduled_date) < getdate(today())) or \
+ (getdate(self.admitted_datetime) < getdate(today())):
+ frappe.throw(_("Scheduled and Admitted dates can not be less than today"))
+ if (getdate(self.expected_discharge) < getdate(self.scheduled_date)) or \
+ (getdate(self.discharge_date) < getdate(self.scheduled_date)):
+ frappe.throw(_("Expected and Discharge dates cannot be less than Admission Schedule date"))
+
def validate_already_scheduled_or_admitted(self):
query = """
select name, status
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index 5c61874..c99ae7d 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -40,8 +40,6 @@
boot_session = "erpnext.startup.boot.boot_session"
notification_config = "erpnext.startup.notifications.get_notification_config"
get_help_messages = "erpnext.utilities.activation.get_help_messages"
-get_user_progress_slides = "erpnext.utilities.user_progress.get_user_progress_slides"
-update_and_get_user_progress = "erpnext.utilities.user_progress_utils.update_default_domain_actions_and_get_state"
leaderboards = "erpnext.startup.leaderboard.get_leaderboards"
@@ -182,6 +180,7 @@
{"title": _("Admission"), "route": "/admissions", "reference_doctype": "Student Admission", "role": "Student"},
{"title": _("Certification"), "route": "/certification", "reference_doctype": "Certification Application", "role": "Non Profit Portal User"},
{"title": _("Material Request"), "route": "/material-requests", "reference_doctype": "Material Request", "role": "Customer"},
+ {"title": _("Appointment Booking"), "route": "/book_appointment"},
]
default_roles = [
@@ -235,24 +234,23 @@
("Sales Taxes and Charges Template", 'Price List'): {
"on_update": "erpnext.shopping_cart.doctype.shopping_cart_settings.shopping_cart_settings.validate_cart_settings"
},
-
"Website Settings": {
"validate": "erpnext.portal.doctype.products_settings.products_settings.home_page_is_products"
},
"Sales Invoice": {
- "on_submit": ["erpnext.regional.france.utils.create_transaction_log", "erpnext.regional.italy.utils.sales_invoice_on_submit"],
+ "on_submit": ["erpnext.regional.create_transaction_log", "erpnext.regional.italy.utils.sales_invoice_on_submit"],
"on_cancel": "erpnext.regional.italy.utils.sales_invoice_on_cancel",
"on_trash": "erpnext.regional.check_deletion_permission"
},
"Payment Entry": {
- "on_submit": ["erpnext.regional.france.utils.create_transaction_log", "erpnext.accounts.doctype.payment_request.payment_request.make_status_as_paid"],
+ "on_submit": ["erpnext.regional.create_transaction_log", "erpnext.accounts.doctype.payment_request.payment_request.make_status_as_paid"],
"on_trash": "erpnext.regional.check_deletion_permission"
},
'Address': {
- 'validate': ['erpnext.regional.india.utils.validate_gstin_for_india', 'erpnext.regional.italy.utils.set_state_code']
+ 'validate': ['erpnext.regional.india.utils.validate_gstin_for_india', 'erpnext.regional.italy.utils.set_state_code', 'erpnext.regional.india.utils.update_gst_category']
},
- ('Sales Invoice', 'Purchase Invoice', 'Delivery Note'): {
- 'validate': 'erpnext.regional.india.utils.set_place_of_supply'
+ ('Sales Invoice', 'Sales Order', 'Delivery Note', 'Purchase Invoice', 'Purchase Order', 'Purchase Receipt'): {
+ 'validate': ['erpnext.regional.india.utils.set_place_of_supply']
},
"Contact": {
"on_trash": "erpnext.support.doctype.issue.issue.update_issue",
@@ -283,7 +281,6 @@
],
"daily": [
"erpnext.stock.reorder_item.reorder_item",
- "erpnext.setup.doctype.email_digest.email_digest.send",
"erpnext.support.doctype.issue.issue.auto_close_tickets",
"erpnext.crm.doctype.opportunity.opportunity.auto_close_opportunity",
"erpnext.controllers.accounts_controller.update_invoice_status",
@@ -303,9 +300,11 @@
"erpnext.quality_management.doctype.quality_review.quality_review.review",
"erpnext.support.doctype.service_level_agreement.service_level_agreement.check_agreement_status",
"erpnext.crm.doctype.email_campaign.email_campaign.send_email_to_leads_or_contacts",
- "erpnext.crm.doctype.email_campaign.email_campaign.set_email_campaign_status"
+ "erpnext.crm.doctype.email_campaign.email_campaign.set_email_campaign_status",
+ "erpnext.selling.doctype.quotation.quotation.set_expired_status"
],
"daily_long": [
+ "erpnext.setup.doctype.email_digest.email_digest.send",
"erpnext.manufacturing.doctype.bom_update_tool.bom_update_tool.update_latest_price_in_all_boms",
"erpnext.hr.doctype.leave_ledger_entry.leave_ledger_entry.process_expired_allocation",
"erpnext.hr.utils.generate_leave_encashment"
diff --git a/erpnext/hr/doctype/additional_salary/additional_salary.json b/erpnext/hr/doctype/additional_salary/additional_salary.json
index 6768b49..7d69f7e 100644
--- a/erpnext/hr/doctype/additional_salary/additional_salary.json
+++ b/erpnext/hr/doctype/additional_salary/additional_salary.json
@@ -1,560 +1,173 @@
{
- "allow_copy": 0,
- "allow_events_in_timeline": 0,
- "allow_guest_to_view": 0,
- "allow_import": 1,
- "allow_rename": 0,
- "autoname": "naming_series:",
- "beta": 0,
- "creation": "2018-05-10 12:04:08.396461",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "",
- "editable_grid": 1,
- "engine": "InnoDB",
+ "actions": [],
+ "allow_import": 1,
+ "autoname": "naming_series:",
+ "creation": "2018-05-10 12:04:08.396461",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "naming_series",
+ "employee",
+ "employee_name",
+ "salary_component",
+ "overwrite_salary_structure_amount",
+ "deduct_full_tax_on_selected_payroll_date",
+ "column_break_5",
+ "company",
+ "payroll_date",
+ "salary_slip",
+ "type",
+ "department",
+ "amount",
+ "amended_from"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "",
- "fetch_if_empty": 0,
- "fieldname": "naming_series",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Series",
- "length": 0,
- "no_copy": 0,
- "options": "HR-ADS-.YY.-.MM.-",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "naming_series",
+ "fieldtype": "Select",
+ "label": "Series",
+ "options": "HR-ADS-.YY.-.MM.-",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "employee",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 1,
- "label": "Employee",
- "length": 0,
- "no_copy": 0,
- "options": "Employee",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 1,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "employee",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "in_standard_filter": 1,
+ "label": "Employee",
+ "options": "Employee",
+ "reqd": 1,
+ "search_index": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "salary_component",
- "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": 1,
- "label": "Salary 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": 1,
- "search_index": 1,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "salary_component",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "in_standard_filter": 1,
+ "label": "Salary Component",
+ "options": "Salary Component",
+ "reqd": 1,
+ "search_index": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "amount",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Amount",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "amount",
+ "fieldtype": "Currency",
+ "in_list_view": 1,
+ "label": "Amount",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "1",
- "fetch_if_empty": 0,
- "fieldname": "overwrite_salary_structure_amount",
- "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": "Overwrite Salary Structure Amount",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "default": "1",
+ "fieldname": "overwrite_salary_structure_amount",
+ "fieldtype": "Check",
+ "label": "Overwrite Salary Structure Amount"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "deduct_full_tax_on_selected_payroll_date",
- "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": "Deduct Full Tax on Selected Payroll Date",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "default": "0",
+ "fieldname": "deduct_full_tax_on_selected_payroll_date",
+ "fieldtype": "Check",
+ "label": "Deduct Full Tax on Selected Payroll Date"
+ },
{
- "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_5",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "column_break_5",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "",
- "description": "Date on which this component is applied",
- "fetch_if_empty": 0,
- "fieldname": "payroll_date",
- "fieldtype": "Date",
- "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": "Payroll Date",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 1,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "description": "Date on which this component is applied",
+ "fieldname": "payroll_date",
+ "fieldtype": "Date",
+ "in_list_view": 1,
+ "label": "Payroll Date",
+ "reqd": 1,
+ "search_index": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_from": "employee.employee_name",
- "fetch_if_empty": 0,
- "fieldname": "employee_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": "Employee Name",
- "length": 0,
- "no_copy": 0,
- "options": "",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fetch_from": "employee.employee_name",
+ "fieldname": "employee_name",
+ "fieldtype": "Data",
+ "in_list_view": 1,
+ "label": "Employee Name",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_from": "employee.department",
- "fetch_if_empty": 0,
- "fieldname": "department",
- "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": "Department",
- "length": 0,
- "no_copy": 0,
- "options": "Department",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fetch_from": "employee.department",
+ "fieldname": "department",
+ "fieldtype": "Link",
+ "label": "Department",
+ "options": "Department",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "company",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Company",
- "length": 0,
- "no_copy": 0,
- "options": "Company",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "label": "Company",
+ "options": "Company",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "salary_slip",
- "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": "Salary Slip",
- "length": 0,
- "no_copy": 0,
- "options": "Salary Slip",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "salary_slip",
+ "fieldtype": "Link",
+ "label": "Salary Slip",
+ "options": "Salary Slip",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_from": "salary_component.type",
- "fetch_if_empty": 0,
- "fieldname": "type",
- "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": "Salary Component Type",
- "length": 0,
- "no_copy": 0,
- "options": "",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fetch_from": "salary_component.type",
+ "fieldname": "type",
+ "fieldtype": "Data",
+ "label": "Salary Component Type",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "amended_from",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Amended From",
- "length": 0,
- "no_copy": 1,
- "options": "Additional Salary",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "fieldname": "amended_from",
+ "fieldtype": "Link",
+ "label": "Amended From",
+ "no_copy": 1,
+ "options": "Additional Salary",
+ "print_hide": 1,
+ "read_only": 1
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 1,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2019-05-09 19:53:37.475839",
- "modified_by": "Administrator",
- "module": "HR",
- "name": "Additional Salary",
- "name_case": "",
- "owner": "Administrator",
+ ],
+ "is_submittable": 1,
+ "links": [],
+ "modified": "2019-12-12 19:07:23.635901",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Additional Salary",
+ "owner": "Administrator",
"permissions": [
{
- "amend": 1,
- "cancel": 1,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "System Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 1,
+ "amend": 1,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "System Manager",
+ "share": 1,
+ "submit": 1,
"write": 1
- },
+ },
{
- "amend": 0,
- "cancel": 0,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "HR User",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "HR User",
+ "share": 1,
+ "submit": 1,
"write": 1
}
- ],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "title_field": "employee",
- "track_changes": 1,
- "track_seen": 0,
- "track_views": 0
+ ],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "title_field": "employee",
+ "track_changes": 1
}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/attendance/attendance.py b/erpnext/hr/doctype/attendance/attendance.py
index b808112..c32ccb5 100644
--- a/erpnext/hr/doctype/attendance/attendance.py
+++ b/erpnext/hr/doctype/attendance/attendance.py
@@ -7,7 +7,8 @@
from frappe.utils import getdate, nowdate
from frappe import _
from frappe.model.document import Document
-from frappe.utils import cstr
+from frappe.utils import cstr, get_datetime, get_datetime_str
+from frappe.utils import update_progress_bar
class Attendance(Document):
def validate_duplicate_record(self):
@@ -89,17 +90,85 @@
if e not in events:
events.append(e)
-def mark_absent(employee, attendance_date, shift=None):
+def mark_attendance(employee, attendance_date, status, shift=None):
employee_doc = frappe.get_doc('Employee', employee)
if not frappe.db.exists('Attendance', {'employee':employee, 'attendance_date':attendance_date, 'docstatus':('!=', '2')}):
doc_dict = {
'doctype': 'Attendance',
'employee': employee,
'attendance_date': attendance_date,
- 'status': 'Absent',
+ 'status': status,
'company': employee_doc.company,
'shift': shift
}
attendance = frappe.get_doc(doc_dict).insert()
attendance.submit()
return attendance.name
+
+@frappe.whitelist()
+def mark_bulk_attendance(data):
+ import json
+ from pprint import pprint
+ if isinstance(data, frappe.string_types):
+ data = json.loads(data)
+ data = frappe._dict(data)
+ company = frappe.get_value('Employee', data.employee, 'company')
+ for date in data.unmarked_days:
+ doc_dict = {
+ 'doctype': 'Attendance',
+ 'employee': data.employee,
+ 'attendance_date': get_datetime(date),
+ 'status': data.status,
+ 'company': company,
+ }
+ attendance = frappe.get_doc(doc_dict).insert()
+ attendance.submit()
+
+
+def get_month_map():
+ return frappe._dict({
+ "January": 1,
+ "February": 2,
+ "March": 3,
+ "April": 4,
+ "May": 5,
+ "June": 6,
+ "July": 7,
+ "August": 8,
+ "September": 9,
+ "October": 10,
+ "November": 11,
+ "December": 12
+ })
+
+@frappe.whitelist()
+def get_unmarked_days(employee, month):
+ import calendar
+ month_map = get_month_map()
+
+ today = get_datetime()
+
+ dates_of_month = ['{}-{}-{}'.format(today.year, month_map[month], r) for r in range(1, calendar.monthrange(today.year, month_map[month])[1] + 1)]
+
+ length = len(dates_of_month)
+ month_start, month_end = dates_of_month[0], dates_of_month[length-1]
+
+
+ records = frappe.get_all("Attendance", fields = ['attendance_date', 'employee'] , filters = [
+ ["attendance_date", ">", month_start],
+ ["attendance_date", "<", month_end],
+ ["employee", "=", employee],
+ ["docstatus", "!=", 2]
+ ])
+
+ marked_days = [get_datetime(record.attendance_date) for record in records]
+ unmarked_days = []
+
+ for date in dates_of_month:
+ date_time = get_datetime(date)
+ if today.day == date_time.day and today.month == date_time.month:
+ break
+ if date_time not in marked_days:
+ unmarked_days.append(date)
+
+ return unmarked_days
diff --git a/erpnext/hr/doctype/attendance/attendance_list.js b/erpnext/hr/doctype/attendance/attendance_list.js
index f36fb15..1161703 100644
--- a/erpnext/hr/doctype/attendance/attendance_list.js
+++ b/erpnext/hr/doctype/attendance/attendance_list.js
@@ -2,5 +2,105 @@
add_fields: ["status", "attendance_date"],
get_indicator: function(doc) {
return [__(doc.status), doc.status=="Present" ? "green" : "darkgrey", "status,=," + doc.status];
+ },
+ onload: function(list_view) {
+ let me = this;
+ const months = moment.months()
+ list_view.page.add_inner_button( __("Mark Attendance"), function(){
+ let dialog = new frappe.ui.Dialog({
+ title: __("Mark Attendance"),
+ fields: [
+ {
+ fieldname: 'employee',
+ label: __('For Employee'),
+ fieldtype: 'Link',
+ options: 'Employee',
+ reqd: 1,
+ onchange: function(){
+ dialog.set_df_property("unmarked_days", "hidden", 1);
+ dialog.set_df_property("status", "hidden", 1);
+ dialog.set_df_property("month", "value", '');
+ dialog.set_df_property("unmarked_days", "options", []);
+ }
+ },
+ {
+ label: __("For Month"),
+ fieldtype: "Select",
+ fieldname: "month",
+ options: months,
+ reqd: 1,
+ onchange: function(){
+ if(dialog.fields_dict.employee.value && dialog.fields_dict.month.value) {
+ dialog.set_df_property("status", "hidden", 0);
+ dialog.set_df_property("unmarked_days", "options", []);
+ me.get_multi_select_options(dialog.fields_dict.employee.value, dialog.fields_dict.month.value).then(options =>{
+ dialog.set_df_property("unmarked_days", "hidden", 0);
+ dialog.set_df_property("unmarked_days", "options", options);
+ });
+ }
+ }
+ },
+ {
+ label: __("Status"),
+ fieldtype: "Select",
+ fieldname: "status",
+ options: ["Present", "Absent", "Half Day"],
+ hidden:1,
+ reqd: 1,
+
+ },
+ {
+ label: __("Unmarked Attendance for days"),
+ fieldname: "unmarked_days",
+ fieldtype: "MultiCheck",
+ options: [],
+ columns: 2,
+ hidden: 1
+ },
+ ],
+ primary_action(data){
+ frappe.confirm(__('Mark attendance as <b>' + data.status + '</b> for <b>' + data.month +'</b>' + ' on selected dates?'), () => {
+ frappe.call({
+ method: "erpnext.hr.doctype.attendance.attendance.mark_bulk_attendance",
+ args: {
+ data : data
+ },
+ callback: function(r) {
+ if(r.message === 1) {
+ frappe.show_alert({message:__("Attendance Marked"), indicator:'blue'});
+ cur_dialog.hide();
+ }
+ }
+ });
+ });
+ dialog.hide();
+ list_view.refresh();
+ },
+ primary_action_label: __('Mark Attendance')
+
+ });
+ dialog.show();
+ });
+ },
+ get_multi_select_options: function(employee, month){
+ return new Promise(resolve => {
+ frappe.call({
+ method: 'erpnext.hr.doctype.attendance.attendance.get_unmarked_days',
+ async: false,
+ args:{
+ employee: employee,
+ month: month,
+ }
+ }).then(r => {
+ var options = [];
+ for(var d in r.message){
+ var momentObj = moment(r.message[d], 'YYYY-MM-DD');
+ var date = momentObj.format('DD-MM-YYYY');
+ options.push({ "label":date, "value": r.message[d] , "checked": 1});
+ }
+ resolve(options);
+ });
+ });
}
+
};
diff --git a/erpnext/hr/doctype/attendance/test_attendance.py b/erpnext/hr/doctype/attendance/test_attendance.py
index 35d1126..838b704 100644
--- a/erpnext/hr/doctype/attendance/test_attendance.py
+++ b/erpnext/hr/doctype/attendance/test_attendance.py
@@ -14,7 +14,7 @@
employee = make_employee("test_mark_absent@example.com")
date = nowdate()
frappe.db.delete('Attendance', {'employee':employee, 'attendance_date':date})
- from erpnext.hr.doctype.attendance.attendance import mark_absent
- attendance = mark_absent(employee, date)
+ from erpnext.hr.doctype.attendance.attendance import mark_attendance
+ attendance = mark_attendance(employee, date, 'Absent')
fetch_attendance = frappe.get_value('Attendance', {'employee':employee, 'attendance_date':date, 'status':'Absent'})
self.assertEqual(attendance, fetch_attendance)
diff --git a/erpnext/hr/doctype/attendance_request/attendance_request.json b/erpnext/hr/doctype/attendance_request/attendance_request.json
index bcd3331..837a878 100644
--- a/erpnext/hr/doctype/attendance_request/attendance_request.json
+++ b/erpnext/hr/doctype/attendance_request/attendance_request.json
@@ -1,575 +1,190 @@
{
- "allow_copy": 0,
- "allow_guest_to_view": 0,
- "allow_import": 1,
- "allow_rename": 1,
- "autoname": "HR-ARQ-.YY.-.MM.-.#####",
- "beta": 0,
- "creation": "2018-04-13 15:37:40.918990",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "",
- "editable_grid": 1,
- "engine": "InnoDB",
+ "actions": [],
+ "allow_import": 1,
+ "allow_rename": 1,
+ "autoname": "HR-ARQ-.YY.-.MM.-.#####",
+ "creation": "2018-04-13 15:37:40.918990",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "employee",
+ "employee_name",
+ "department",
+ "column_break_5",
+ "company",
+ "from_date",
+ "to_date",
+ "half_day",
+ "half_day_date",
+ "reason_section",
+ "reason",
+ "column_break_4",
+ "explanation",
+ "amended_from"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "employee",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Employee",
- "length": 0,
- "no_copy": 0,
- "options": "Employee",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "employee",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Employee",
+ "options": "Employee",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_from": "employee.employee_name",
- "fieldname": "employee_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": "Employee Name",
- "length": 0,
- "no_copy": 0,
- "options": "",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fetch_from": "employee.employee_name",
+ "fieldname": "employee_name",
+ "fieldtype": "Data",
+ "label": "Employee Name",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_from": "employee.department",
- "fieldname": "department",
- "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": "Department",
- "length": 0,
- "no_copy": 0,
- "options": "Department",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fetch_from": "employee.department",
+ "fieldname": "department",
+ "fieldtype": "Link",
+ "label": "Department",
+ "options": "Department",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "company",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Company",
- "length": 0,
- "no_copy": 0,
- "options": "Company",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 1,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "label": "Company",
+ "options": "Company",
+ "remember_last_selected_value": 1,
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_5",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "column_break_5",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "from_date",
- "fieldtype": "Date",
- "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": "From Date",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "from_date",
+ "fieldtype": "Date",
+ "in_list_view": 1,
+ "label": "From Date",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "to_date",
- "fieldtype": "Date",
- "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": "To Date",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "to_date",
+ "fieldtype": "Date",
+ "in_list_view": 1,
+ "label": "To Date",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "half_day",
- "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": "Half Day",
- "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
- },
+ "default": "0",
+ "fieldname": "half_day",
+ "fieldtype": "Check",
+ "label": "Half Day"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "half_day",
- "fieldname": "half_day_date",
- "fieldtype": "Date",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Half Day Date",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "depends_on": "half_day",
+ "fieldname": "half_day_date",
+ "fieldtype": "Date",
+ "label": "Half Day Date"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "reason_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": "Reason",
- "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
- },
+ "fieldname": "reason_section",
+ "fieldtype": "Section Break",
+ "label": "Reason"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "reason",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Reason",
- "length": 0,
- "no_copy": 0,
- "options": "Work From Home\nOn Duty",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "reason",
+ "fieldtype": "Select",
+ "in_list_view": 1,
+ "label": "Reason",
+ "options": "Work From Home\nOn Duty",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_4",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "column_break_4",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "explanation",
- "fieldtype": "Small Text",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Explanation",
- "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
- },
+ "fieldname": "explanation",
+ "fieldtype": "Small Text",
+ "label": "Explanation"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "amended_from",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Amended From",
- "length": 0,
- "no_copy": 1,
- "options": "Attendance Request",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "fieldname": "amended_from",
+ "fieldtype": "Link",
+ "label": "Amended From",
+ "no_copy": 1,
+ "options": "Attendance Request",
+ "print_hide": 1,
+ "read_only": 1
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 1,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2018-08-21 17:09:48.117407",
- "modified_by": "Administrator",
- "module": "HR",
- "name": "Attendance Request",
- "name_case": "",
- "owner": "Administrator",
+ ],
+ "is_submittable": 1,
+ "links": [],
+ "modified": "2019-12-16 11:49:26.943173",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Attendance Request",
+ "owner": "Administrator",
"permissions": [
{
- "amend": 1,
- "cancel": 1,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "System Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 1,
+ "amend": 1,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "System Manager",
+ "share": 1,
+ "submit": 1,
"write": 1
- },
+ },
{
- "amend": 1,
- "cancel": 1,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "HR Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 1,
+ "amend": 1,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "HR Manager",
+ "share": 1,
+ "submit": 1,
"write": 1
- },
+ },
{
- "amend": 1,
- "cancel": 1,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "HR User",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 1,
+ "amend": 1,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "HR User",
+ "share": 1,
+ "submit": 1,
"write": 1
- },
+ },
{
- "amend": 0,
- "cancel": 0,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Employee",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Employee",
+ "share": 1,
"write": 1
}
- ],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "title_field": "employee_name",
- "track_changes": 1,
- "track_seen": 0,
- "track_views": 0
+ ],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "title_field": "employee_name",
+ "track_changes": 1
}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/compensatory_leave_request/compensatory_leave_request.py b/erpnext/hr/doctype/compensatory_leave_request/compensatory_leave_request.py
index bc4a1b4..7a9727f 100644
--- a/erpnext/hr/doctype/compensatory_leave_request/compensatory_leave_request.py
+++ b/erpnext/hr/doctype/compensatory_leave_request/compensatory_leave_request.py
@@ -5,9 +5,10 @@
from __future__ import unicode_literals
import frappe
from frappe import _
-from frappe.utils import date_diff, add_days, getdate
+from frappe.utils import date_diff, add_days, getdate, cint
from frappe.model.document import Document
-from erpnext.hr.utils import validate_dates, validate_overlap, get_leave_period, get_holidays_for_employee
+from erpnext.hr.utils import validate_dates, validate_overlap, get_leave_period, \
+ get_holidays_for_employee, create_additional_leave_ledger_entry
class CompensatoryLeaveRequest(Document):
@@ -25,16 +26,14 @@
frappe.throw(_("Leave Type is madatory"))
def validate_attendance(self):
- query = """select attendance_date, status
- from `tabAttendance` where
- attendance_date between %(work_from_date)s and %(work_end_date)s
- and docstatus=1 and status = 'Present' and employee=%(employee)s"""
+ attendance = frappe.get_all('Attendance',
+ filters={
+ 'attendance_date': ['between', (self.work_from_date, self.work_end_date)],
+ 'status': 'Present',
+ 'docstatus': 1,
+ 'employee': self.employee
+ }, fields=['attendance_date', 'status'])
- attendance = frappe.db.sql(query, {
- "work_from_date": self.work_from_date,
- "work_end_date": self.work_end_date,
- "employee": self.employee
- }, as_dict=True)
if len(attendance) < date_diff(self.work_end_date, self.work_from_date) + 1:
frappe.throw(_("You are not present all day(s) between compensatory leave request days"))
@@ -50,13 +49,19 @@
date_difference -= 0.5
leave_period = get_leave_period(self.work_from_date, self.work_end_date, company)
if leave_period:
- leave_allocation = self.exists_allocation_for_period(leave_period)
+ leave_allocation = self.get_existing_allocation_for_period(leave_period)
if leave_allocation:
leave_allocation.new_leaves_allocated += date_difference
- leave_allocation.submit()
+ leave_allocation.validate()
+ leave_allocation.db_set("new_leaves_allocated", leave_allocation.total_leaves_allocated)
+ leave_allocation.db_set("total_leaves_allocated", leave_allocation.total_leaves_allocated)
+
+ # generate additional ledger entry for the new compensatory leaves off
+ create_additional_leave_ledger_entry(leave_allocation, date_difference, add_days(self.work_end_date, 1))
+
else:
leave_allocation = self.create_leave_allocation(leave_period, date_difference)
- self.db_set("leave_allocation", leave_allocation.name)
+ self.leave_allocation=leave_allocation.name
else:
frappe.throw(_("There is no leave period in between {0} and {1}").format(self.work_from_date, self.work_end_date))
@@ -68,11 +73,16 @@
leave_allocation = frappe.get_doc("Leave Allocation", self.leave_allocation)
if leave_allocation:
leave_allocation.new_leaves_allocated -= date_difference
- if leave_allocation.total_leaves_allocated - date_difference <= 0:
- leave_allocation.total_leaves_allocated = 0
- leave_allocation.submit()
+ if leave_allocation.new_leaves_allocated - date_difference <= 0:
+ leave_allocation.new_leaves_allocated = 0
+ leave_allocation.validate()
+ leave_allocation.db_set("new_leaves_allocated", leave_allocation.total_leaves_allocated)
+ leave_allocation.db_set("total_leaves_allocated", leave_allocation.total_leaves_allocated)
- def exists_allocation_for_period(self, leave_period):
+ # create reverse entry on cancelation
+ create_additional_leave_ledger_entry(leave_allocation, date_difference * -1, add_days(self.work_end_date, 1))
+
+ def get_existing_allocation_for_period(self, leave_period):
leave_allocation = frappe.db.sql("""
select name
from `tabLeave Allocation`
@@ -95,17 +105,18 @@
def create_leave_allocation(self, leave_period, date_difference):
is_carry_forward = frappe.db.get_value("Leave Type", self.leave_type, "is_carry_forward")
- allocation = frappe.new_doc("Leave Allocation")
- allocation.employee = self.employee
- allocation.employee_name = self.employee_name
- allocation.leave_type = self.leave_type
- allocation.from_date = add_days(self.work_end_date, 1)
- allocation.to_date = leave_period[0].to_date
- allocation.new_leaves_allocated = date_difference
- allocation.total_leaves_allocated = date_difference
- allocation.description = self.reason
- if is_carry_forward == 1:
- allocation.carry_forward = True
- allocation.save(ignore_permissions = True)
+ allocation = frappe.get_doc(dict(
+ doctype="Leave Allocation",
+ employee=self.employee,
+ employee_name=self.employee_name,
+ leave_type=self.leave_type,
+ from_date=add_days(self.work_end_date, 1),
+ to_date=leave_period[0].to_date,
+ carry_forward=cint(is_carry_forward),
+ new_leaves_allocated=date_difference,
+ total_leaves_allocated=date_difference,
+ description=self.reason
+ ))
+ allocation.insert(ignore_permissions=True)
allocation.submit()
- return allocation
+ return allocation
\ No newline at end of file
diff --git a/erpnext/hr/doctype/compensatory_leave_request/test_compensatory_leave_request.py b/erpnext/hr/doctype/compensatory_leave_request/test_compensatory_leave_request.py
index f2ca1f4..1615ab3 100644
--- a/erpnext/hr/doctype/compensatory_leave_request/test_compensatory_leave_request.py
+++ b/erpnext/hr/doctype/compensatory_leave_request/test_compensatory_leave_request.py
@@ -5,37 +5,128 @@
import frappe
import unittest
+from frappe.utils import today, add_months, add_days
+from erpnext.hr.doctype.attendance_request.test_attendance_request import get_employee
+from erpnext.hr.doctype.leave_period.test_leave_period import create_leave_period
+from erpnext.hr.doctype.leave_application.leave_application import get_leave_balance_on
-# class TestCompensatoryLeaveRequest(unittest.TestCase):
-# def get_compensatory_leave_request(self):
-# return frappe.get_doc('Compensatory Leave Request', dict(
-# employee = employee,
-# work_from_date = today,
-# work_to_date = today,
-# reason = 'test'
-# )).insert()
-#
-# def test_creation_of_leave_allocation(self):
-# employee = get_employee()
-# today = get_today()
-#
-# compensatory_leave_request = self.get_compensatory_leave_request(today)
-#
-# before = get_leave_balance(employee, compensatory_leave_request.leave_type)
-#
-# compensatory_leave_request.submit()
-#
-# self.assertEqual(get_leave_balance(employee, compensatory_leave_request.leave_type), before + 1)
-#
-# def test_max_compensatory_leave(self):
-# employee = get_employee()
-# today = get_today()
-#
-# compensatory_leave_request = self.get_compensatory_leave_request()
-#
-# frappe.db.set_value('Leave Type', compensatory_leave_request.leave_type, 'max_leaves_allowed', 0)
-#
-# self.assertRaises(MaxLeavesLimitCrossed, compensatory_leave_request.submit)
-#
-# frappe.db.set_value('Leave Type', compensatory_leave_request.leave_type, 'max_leaves_allowed', 10)
-#
+class TestCompensatoryLeaveRequest(unittest.TestCase):
+ def setUp(self):
+ frappe.db.sql(''' delete from `tabCompensatory Leave Request`''')
+ frappe.db.sql(''' delete from `tabLeave Ledger Entry`''')
+ frappe.db.sql(''' delete from `tabLeave Allocation`''')
+ frappe.db.sql(''' delete from `tabAttendance` where attendance_date in {0} '''.format((today(), add_days(today(), -1)))) #nosec
+ create_leave_period(add_months(today(), -3), add_months(today(), 3), "_Test Company")
+ create_holiday_list()
+
+ employee = get_employee()
+ employee.holiday_list = "_Test Compensatory Leave"
+ employee.save()
+
+ def test_leave_balance_on_submit(self):
+ ''' check creation of leave allocation on submission of compensatory leave request '''
+ employee = get_employee()
+ mark_attendance(employee)
+ compensatory_leave_request = get_compensatory_leave_request(employee.name)
+
+ before = get_leave_balance_on(employee.name, compensatory_leave_request.leave_type, today())
+ compensatory_leave_request.submit()
+
+ self.assertEqual(get_leave_balance_on(employee.name, compensatory_leave_request.leave_type, add_days(today(), 1)), before + 1)
+
+ def test_leave_allocation_update_on_submit(self):
+ employee = get_employee()
+ mark_attendance(employee, date=add_days(today(), -1))
+ compensatory_leave_request = get_compensatory_leave_request(employee.name, leave_date=add_days(today(), -1))
+ compensatory_leave_request.submit()
+
+ # leave allocation creation on submit
+ leaves_allocated = frappe.db.get_value('Leave Allocation', {
+ 'name': compensatory_leave_request.leave_allocation
+ }, ['total_leaves_allocated'])
+ self.assertEqual(leaves_allocated, 1)
+
+ mark_attendance(employee)
+ compensatory_leave_request = get_compensatory_leave_request(employee.name)
+ compensatory_leave_request.submit()
+
+ # leave allocation updates on submission of second compensatory leave request
+ leaves_allocated = frappe.db.get_value('Leave Allocation', {
+ 'name': compensatory_leave_request.leave_allocation
+ }, ['total_leaves_allocated'])
+ self.assertEqual(leaves_allocated, 2)
+
+ def test_creation_of_leave_ledger_entry_on_submit(self):
+ ''' check creation of leave ledger entry on submission of leave request '''
+ employee = get_employee()
+ mark_attendance(employee)
+ compensatory_leave_request = get_compensatory_leave_request(employee.name)
+ compensatory_leave_request.submit()
+
+ filters = dict(transaction_name=compensatory_leave_request.leave_allocation)
+ leave_ledger_entry = frappe.get_all('Leave Ledger Entry', fields='*', filters=filters)
+
+ self.assertEquals(len(leave_ledger_entry), 1)
+ self.assertEquals(leave_ledger_entry[0].employee, compensatory_leave_request.employee)
+ self.assertEquals(leave_ledger_entry[0].leave_type, compensatory_leave_request.leave_type)
+ self.assertEquals(leave_ledger_entry[0].leaves, 1)
+
+ # check reverse leave ledger entry on cancellation
+ compensatory_leave_request.cancel()
+ leave_ledger_entry = frappe.get_all('Leave Ledger Entry', fields='*', filters=filters, order_by = 'creation desc')
+
+ self.assertEquals(len(leave_ledger_entry), 2)
+ self.assertEquals(leave_ledger_entry[0].employee, compensatory_leave_request.employee)
+ self.assertEquals(leave_ledger_entry[0].leave_type, compensatory_leave_request.leave_type)
+ self.assertEquals(leave_ledger_entry[0].leaves, -1)
+
+def get_compensatory_leave_request(employee, leave_date=today()):
+ prev_comp_leave_req = frappe.db.get_value('Compensatory Leave Request',
+ dict(leave_type='Compensatory Off',
+ work_from_date=leave_date,
+ work_end_date=leave_date,
+ employee=employee), 'name')
+ if prev_comp_leave_req:
+ return frappe.get_doc('Compensatory Leave Request', prev_comp_leave_req)
+
+ return frappe.get_doc(dict(
+ doctype='Compensatory Leave Request',
+ employee=employee,
+ leave_type='Compensatory Off',
+ work_from_date=leave_date,
+ work_end_date=leave_date,
+ reason='test'
+ )).insert()
+
+def mark_attendance(employee, date=today(), status='Present'):
+ if not frappe.db.exists(dict(doctype='Attendance', employee=employee.name, attendance_date=date, status='Present')):
+ attendance = frappe.get_doc({
+ "doctype": "Attendance",
+ "employee": employee.name,
+ "attendance_date": date,
+ "status": status
+ })
+ attendance.save()
+ attendance.submit()
+
+def create_holiday_list():
+ if frappe.db.exists("Holiday List", "_Test Compensatory Leave"):
+ return
+
+ holiday_list = frappe.get_doc({
+ "doctype": "Holiday List",
+ "from_date": add_months(today(), -3),
+ "to_date": add_months(today(), 3),
+ "holidays": [
+ {
+ "description": "Test Holiday",
+ "holiday_date": today()
+ },
+ {
+ "description": "Test Holiday 1",
+ "holiday_date": add_days(today(), -1)
+ }
+ ],
+ "holiday_list_name": "_Test Compensatory Leave"
+ })
+ holiday_list.save()
\ No newline at end of file
diff --git a/erpnext/hr/doctype/department/department.json b/erpnext/hr/doctype/department/department.json
index 3b400ce..a191b6b 100644
--- a/erpnext/hr/doctype/department/department.json
+++ b/erpnext/hr/doctype/department/department.json
@@ -1,569 +1,180 @@
{
- "allow_copy": 0,
- "allow_events_in_timeline": 0,
- "allow_guest_to_view": 0,
+ "actions": [],
"allow_import": 1,
"allow_rename": 1,
- "autoname": "",
- "beta": 0,
"creation": "2013-02-05 11:48:26",
- "custom": 0,
- "docstatus": 0,
"doctype": "DocType",
"document_type": "Setup",
- "editable_grid": 0,
+ "engine": "InnoDB",
+ "field_order": [
+ "department_name",
+ "parent_department",
+ "column_break_3",
+ "company",
+ "is_group",
+ "disabled",
+ "section_break_4",
+ "leave_block_list",
+ "leave_section",
+ "leave_approvers",
+ "expense_section",
+ "expense_approvers",
+ "lft",
+ "rgt",
+ "old_parent"
+ ],
"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": "department_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": "Department",
- "length": 0,
- "no_copy": 0,
"oldfieldname": "department_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": 0
+ "reqd": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "parent_department",
"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 Department",
- "length": 0,
- "no_copy": 0,
- "options": "Department",
- "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": "Department"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "company",
"fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
"in_standard_filter": 1,
"label": "Company",
- "length": 0,
- "no_copy": 0,
"options": "Company",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "reqd": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
"bold": 1,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
+ "default": "0",
"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,
- "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 Group"
},
{
- "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": "disabled",
"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": "Disabled",
- "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": "Disabled"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "section_break_4",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "fieldtype": "Section Break"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"description": "Days for which Holidays are blocked for this department.",
- "fetch_if_empty": 0,
"fieldname": "leave_block_list",
"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": "Leave Block List",
- "length": 0,
- "no_copy": 0,
- "options": "Leave Block 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": "Leave Block List"
},
{
- "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_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": "Leave Approvers",
- "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": "Leave Approvers"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"description": "The first Leave Approver in the list will be set as the default Leave Approver.",
- "fetch_if_empty": 0,
"fieldname": "leave_approvers",
"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": "Leave Approver",
- "length": 0,
- "no_copy": 0,
- "options": "Department Approver",
- "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": "Department Approver"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "expense_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": "Expense Approvers",
- "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": "Expense Approvers"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"description": "The first Expense Approver in the list will be set as the default Expense Approver.",
- "fetch_if_empty": 0,
"fieldname": "expense_approvers",
"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": "Expense Approver",
- "length": 0,
- "no_copy": 0,
- "options": "Department Approver",
- "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": "Department Approver"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 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": 0,
- "permlevel": 0,
- "precision": "",
"print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "read_only": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 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": 0,
- "permlevel": 0,
- "precision": "",
"print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "read_only": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "old_parent",
"fieldtype": "Data",
"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": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "print_hide": 1
+ },
+ {
+ "fieldname": "column_break_3",
+ "fieldtype": "Column Break"
}
],
- "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": "2019-06-25 18:43:05.550387",
+ "links": [],
+ "modified": "2019-12-12 14:48:35.254308",
"modified_by": "Administrator",
"module": "HR",
"name": "Department",
"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": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "Academics User",
- "set_user_permissions": 0,
"share": 1,
- "submit": 0,
"write": 1
},
{
- "amend": 0,
- "cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
- "if_owner": 0,
"import": 1,
- "permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "HR Manager",
"set_user_permissions": 1,
"share": 1,
- "submit": 0,
"write": 1
}
],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
"show_name_in_global_search": 1,
- "sort_order": "ASC",
- "track_changes": 0,
- "track_seen": 0,
- "track_views": 0
+ "sort_field": "modified",
+ "sort_order": "ASC"
}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/department_approver/department_approver.py b/erpnext/hr/doctype/department_approver/department_approver.py
index 9f2f201..df0f75a 100644
--- a/erpnext/hr/doctype/department_approver/department_approver.py
+++ b/erpnext/hr/doctype/department_approver/department_approver.py
@@ -19,14 +19,19 @@
approvers = []
department_details = {}
department_list = []
- employee_department = filters.get("department") or frappe.get_value("Employee", filters.get("employee"), "department")
+ employee = frappe.get_value("Employee", filters.get("employee"), ["department", "leave_approver"], as_dict=True)
+
+ employee_department = filters.get("department") or employee.department
if employee_department:
department_details = frappe.db.get_value("Department", {"name": employee_department}, ["lft", "rgt"], as_dict=True)
if department_details:
department_list = frappe.db.sql("""select name from `tabDepartment` where lft <= %s
and rgt >= %s
and disabled=0
- order by lft desc""", (department_details.lft, department_details.rgt), as_list = True)
+ order by lft desc""", (department_details.lft, department_details.rgt), as_list=True)
+
+ if filters.get("doctype") == "Leave Application" and employee.leave_approver:
+ approvers.append(frappe.db.get_value("User", employee.leave_approver, ['name', 'first_name', 'last_name']))
if filters.get("doctype") == "Leave Application":
parentfield = "leave_approvers"
@@ -41,4 +46,4 @@
and approver.parentfield = %s
and approver.approver=user.name""",(d, "%" + txt + "%", parentfield), as_list=True)
- return approvers
\ No newline at end of file
+ return set(tuple(approver) for approver in approvers)
diff --git a/erpnext/hr/doctype/driving_license_category/driving_license_category.json b/erpnext/hr/doctype/driving_license_category/driving_license_category.json
index 45e38d3..8bc61a8 100644
--- a/erpnext/hr/doctype/driving_license_category/driving_license_category.json
+++ b/erpnext/hr/doctype/driving_license_category/driving_license_category.json
@@ -1,161 +1,51 @@
{
- "allow_copy": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "beta": 0,
- "creation": "2017-10-17 08:19:43.142329",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "",
- "editable_grid": 1,
- "engine": "InnoDB",
+ "actions": [],
+ "creation": "2017-10-17 08:19:43.142329",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "class",
+ "description",
+ "issuing_date",
+ "expiry_date"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "class",
- "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": "Class",
- "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": "class",
+ "fieldtype": "Data",
+ "in_list_view": 1,
+ "label": "Driver licence class"
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "description",
- "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": "Description",
- "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": "description",
+ "fieldtype": "Data",
+ "in_list_view": 1,
+ "label": "Description"
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "issuing_date",
- "fieldtype": "Date",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Issuing Date",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "fieldname": "issuing_date",
+ "fieldtype": "Date",
+ "in_list_view": 1,
+ "label": "Issuing Date"
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "expiry_date",
- "fieldtype": "Date",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Expiry Date",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
+ "fieldname": "expiry_date",
+ "fieldtype": "Date",
+ "in_list_view": 1,
+ "label": "Expiry Date"
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 1,
- "max_attachments": 0,
- "modified": "2017-10-17 08:19:43.142329",
- "modified_by": "Administrator",
- "module": "HR",
- "name": "Driving License Category",
- "name_case": "",
- "owner": "Administrator",
- "permissions": [],
- "quick_entry": 1,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1,
- "track_seen": 0
+ ],
+ "istable": 1,
+ "links": [],
+ "modified": "2019-12-12 14:40:55.209022",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Driving License Category",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/employee/employee.json b/erpnext/hr/doctype/employee/employee.json
index 9291820..1b236a4 100644
--- a/erpnext/hr/doctype/employee/employee.json
+++ b/erpnext/hr/doctype/employee/employee.json
@@ -1,4 +1,5 @@
{
+ "actions": [],
"allow_events_in_timeline": 1,
"allow_import": 1,
"allow_rename": 1,
@@ -12,24 +13,25 @@
"basic_information",
"employee",
"naming_series",
- "salutation",
"first_name",
"middle_name",
"last_name",
+ "salutation",
"employee_name",
+ "employment_type",
"image",
"column_break1",
"company",
"status",
- "employee_number",
- "employment_type",
"gender",
"date_of_birth",
"date_of_joining",
+ "employee_number",
"emergency_contact_details",
- "emergency_phone_number",
"person_to_be_contacted",
"relation",
+ "column_break_19",
+ "emergency_phone_number",
"erpnext_user",
"user_id",
"create_user",
@@ -52,10 +54,10 @@
"attendance_and_leave_details",
"leave_policy",
"attendance_device_id",
+ "leave_approver",
"column_break_44",
"holiday_list",
"default_shift",
- "leave_approver",
"salary_information",
"salary_mode",
"bank_name",
@@ -65,14 +67,14 @@
"health_insurance_no",
"contact_details",
"cell_number",
- "prefered_contact_email",
"prefered_email",
- "company_email",
"personal_email",
"unsubscribed",
- "column_break4",
"permanent_accommodation_type",
"permanent_address",
+ "column_break4",
+ "prefered_contact_email",
+ "company_email",
"current_accommodation_type",
"current_address",
"sb53",
@@ -82,9 +84,9 @@
"date_of_issue",
"valid_upto",
"place_of_issue",
- "column_break6",
"marital_status",
"blood_group",
+ "column_break6",
"family_background",
"health_details",
"educational_qualification",
@@ -232,7 +234,6 @@
"reqd": 1
},
{
- "description": "You can enter any date manually",
"fieldname": "date_of_birth",
"fieldtype": "Date",
"label": "Date of Birth",
@@ -250,7 +251,6 @@
},
{
"allow_in_quick_entry": 1,
- "collapsible": 1,
"fieldname": "emergency_contact_details",
"fieldtype": "Section Break",
"label": "Emergency Contact"
@@ -777,12 +777,17 @@
"fieldtype": "Link",
"label": "Leave Approver",
"options": "User"
+ },
+ {
+ "fieldname": "column_break_19",
+ "fieldtype": "Column Break"
}
],
"icon": "fa fa-user",
"idx": 24,
"image_field": "image",
- "modified": "2019-09-12 14:21:12.711280",
+ "links": [],
+ "modified": "2019-12-11 13:22:18.323622",
"modified_by": "Administrator",
"module": "HR",
"name": "Employee",
@@ -831,4 +836,4 @@
"sort_order": "DESC",
"title_field": "employee_name",
"track_changes": 1
-}
\ No newline at end of file
+}
diff --git a/erpnext/hr/doctype/employee/employee.py b/erpnext/hr/doctype/employee/employee.py
index 3fc330e..4d49503 100755
--- a/erpnext/hr/doctype/employee/employee.py
+++ b/erpnext/hr/doctype/employee/employee.py
@@ -4,7 +4,7 @@
from __future__ import unicode_literals
import frappe
-from frappe.utils import getdate, validate_email_address, today, add_years, format_datetime
+from frappe.utils import getdate, validate_email_address, today, add_years, format_datetime, cstr
from frappe.model.naming import set_name_by_naming_series
from frappe import throw, _, scrub
from frappe.permissions import add_user_permission, remove_user_permission, \
@@ -152,8 +152,8 @@
elif self.date_of_retirement and self.date_of_joining and (getdate(self.date_of_retirement) <= getdate(self.date_of_joining)):
throw(_("Date Of Retirement must be greater than Date of Joining"))
- elif self.relieving_date and self.date_of_joining and (getdate(self.relieving_date) <= getdate(self.date_of_joining)):
- throw(_("Relieving Date must be greater than Date of Joining"))
+ elif self.relieving_date and self.date_of_joining and (getdate(self.relieving_date) < getdate(self.date_of_joining)):
+ throw(_("Relieving Date must be greater than or equal to Date of Joining"))
elif self.contract_end_date and self.date_of_joining and (getdate(self.contract_end_date) <= getdate(self.date_of_joining)):
throw(_("Contract End Date must be greater than Date of Joining"))
@@ -164,13 +164,20 @@
if self.personal_email:
validate_email_address(self.personal_email, True)
+ def set_preferred_email(self):
+ preferred_email_field = frappe.scrub(self.prefered_contact_email)
+ if preferred_email_field:
+ preferred_email = self.get(preferred_email_field)
+ self.prefered_email = preferred_email
+
def validate_status(self):
if self.status == 'Left':
reports_to = frappe.db.get_all('Employee',
- filters={'reports_to': self.name}
+ filters={'reports_to': self.name, 'status': "Active"},
+ fields=['name','employee_name']
)
if reports_to:
- link_to_employees = [frappe.utils.get_link_to_form('Employee', employee.name) for employee in reports_to]
+ link_to_employees = [frappe.utils.get_link_to_form('Employee', employee.name, label=employee.employee_name) for employee in reports_to]
throw(_("Employee status cannot be set to 'Left' as following employees are currently reporting to this employee: ")
+ ', '.join(link_to_employees), EmployeeLeftValidationError)
if not self.relieving_date:
@@ -217,8 +224,8 @@
def reset_employee_emails_cache(self):
prev_doc = self.get_doc_before_save() or {}
- cell_number = self.get('cell_number')
- prev_number = prev_doc.get('cell_number')
+ cell_number = cstr(self.get('cell_number'))
+ prev_number = cstr(prev_doc.get('cell_number'))
if (cell_number != prev_number or
self.get('user_id') != prev_doc.get('user_id')):
frappe.cache().hdel('employees_with_number', cell_number)
diff --git a/erpnext/hr/doctype/employee/employee_dashboard.py b/erpnext/hr/doctype/employee/employee_dashboard.py
index 162b697..11ad83b 100644
--- a/erpnext/hr/doctype/employee/employee_dashboard.py
+++ b/erpnext/hr/doctype/employee/employee_dashboard.py
@@ -21,7 +21,7 @@
},
{
'label': _('Expense'),
- 'items': ['Expense Claim', 'Travel Request']
+ 'items': ['Expense Claim', 'Travel Request', 'Employee Advance']
},
{
'label': _('Benefit'),
diff --git a/erpnext/hr/doctype/employee/test_employee.py b/erpnext/hr/doctype/employee/test_employee.py
index 5a63beb..d3410de 100644
--- a/erpnext/hr/doctype/employee/test_employee.py
+++ b/erpnext/hr/doctype/employee/test_employee.py
@@ -45,7 +45,7 @@
employee1_doc.status = 'Left'
self.assertRaises(EmployeeLeftValidationError, employee1_doc.save)
-def make_employee(user):
+def make_employee(user, company=None):
if not frappe.db.get_value("User", user):
frappe.get_doc({
"doctype": "User",
@@ -55,12 +55,12 @@
"roles": [{"doctype": "Has Role", "role": "Employee"}]
}).insert()
- if not frappe.db.get_value("Employee", {"user_id": user}):
+ if not frappe.db.get_value("Employee", { "user_id": user, "company": company or erpnext.get_default_company() }):
employee = frappe.get_doc({
"doctype": "Employee",
"naming_series": "EMP-",
"first_name": user,
- "company": erpnext.get_default_company(),
+ "company": company or erpnext.get_default_company(),
"user_id": user,
"date_of_birth": "1990-05-08",
"date_of_joining": "2013-01-01",
diff --git a/erpnext/hr/doctype/employee_advance/employee_advance.js b/erpnext/hr/doctype/employee_advance/employee_advance.js
index 77a2bbc..ba62853 100644
--- a/erpnext/hr/doctype/employee_advance/employee_advance.js
+++ b/erpnext/hr/doctype/employee_advance/employee_advance.js
@@ -34,7 +34,7 @@
}
else if (
frm.doc.docstatus === 1
- && flt(frm.doc.claimed_amount) < flt(frm.doc.paid_amount)
+ && flt(frm.doc.claimed_amount) < flt(frm.doc.paid_amount) - flt(frm.doc.return_amount)
&& frappe.model.can_create("Expense Claim")
) {
frm.add_custom_button(
@@ -45,6 +45,15 @@
__('Create')
);
}
+
+ if (frm.doc.docstatus === 1
+ && (flt(frm.doc.claimed_amount) < flt(frm.doc.paid_amount))
+ && frappe.model.can_create("Journal Entry")) {
+
+ frm.add_custom_button(__("Return"), function() {
+ frm.trigger('make_return_entry');
+ }, __('Create'));
+ }
},
make_payment_entry: function(frm) {
@@ -83,6 +92,24 @@
});
},
+ make_return_entry: function(frm) {
+ frappe.call({
+ method: 'erpnext.hr.doctype.employee_advance.employee_advance.make_return_entry',
+ args: {
+ 'employee_name': frm.doc.employee,
+ 'company': frm.doc.company,
+ 'employee_advance_name': frm.doc.name,
+ 'return_amount': flt(frm.doc.paid_amount - frm.doc.claimed_amount),
+ 'mode_of_payment': frm.doc.mode_of_payment,
+ 'advance_account': frm.doc.advance_account
+ },
+ callback: function(r) {
+ const doclist = frappe.model.sync(r.message);
+ frappe.set_route('Form', doclist[0].doctype, doclist[0].name);
+ }
+ });
+ },
+
employee: function (frm) {
if (frm.doc.employee) {
return frappe.call({
diff --git a/erpnext/hr/doctype/employee_advance/employee_advance.json b/erpnext/hr/doctype/employee_advance/employee_advance.json
index 3597e76..d233a2b 100644
--- a/erpnext/hr/doctype/employee_advance/employee_advance.json
+++ b/erpnext/hr/doctype/employee_advance/employee_advance.json
@@ -1,737 +1,213 @@
{
- "allow_copy": 0,
- "allow_events_in_timeline": 0,
- "allow_guest_to_view": 0,
- "allow_import": 1,
- "allow_rename": 0,
- "autoname": "naming_series:",
- "beta": 0,
- "creation": "2017-10-09 14:26:29.612365",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "",
- "editable_grid": 1,
- "engine": "InnoDB",
+ "actions": [],
+ "allow_import": 1,
+ "autoname": "naming_series:",
+ "creation": "2017-10-09 14:26:29.612365",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "naming_series",
+ "employee",
+ "employee_name",
+ "column_break_4",
+ "posting_date",
+ "department",
+ "section_break_8",
+ "purpose",
+ "column_break_11",
+ "advance_amount",
+ "paid_amount",
+ "due_advance_amount",
+ "claimed_amount",
+ "return_amount",
+ "section_break_7",
+ "status",
+ "company",
+ "amended_from",
+ "column_break_18",
+ "advance_account",
+ "mode_of_payment"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "",
- "fieldname": "naming_series",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Series",
- "length": 0,
- "no_copy": 0,
- "options": "HR-EAD-.YYYY.-",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "naming_series",
+ "fieldtype": "Select",
+ "label": "Series",
+ "options": "HR-EAD-.YYYY.-"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "employee",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Employee",
- "length": 0,
- "no_copy": 0,
- "options": "Employee",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "employee",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Employee",
+ "options": "Employee",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_from": "employee.employee_name",
- "fieldname": "employee_name",
- "fieldtype": "Read Only",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Employee Name",
- "length": 0,
- "no_copy": 0,
- "options": "",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fetch_from": "employee.employee_name",
+ "fieldname": "employee_name",
+ "fieldtype": "Read Only",
+ "label": "Employee Name"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_4",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "column_break_4",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "Today",
- "fieldname": "posting_date",
- "fieldtype": "Date",
- "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": "Posting Date",
- "length": 0,
- "no_copy": 0,
- "options": "",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "default": "Today",
+ "fieldname": "posting_date",
+ "fieldtype": "Date",
+ "in_list_view": 1,
+ "label": "Posting Date",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_from": "employee.department",
- "fieldname": "department",
- "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": "Department",
- "length": 0,
- "no_copy": 0,
- "options": "Department",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fetch_from": "employee.department",
+ "fieldname": "department",
+ "fieldtype": "Link",
+ "label": "Department",
+ "options": "Department",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "section_break_8",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "section_break_8",
+ "fieldtype": "Section Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "purpose",
- "fieldtype": "Small Text",
- "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": "Purpose",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "purpose",
+ "fieldtype": "Small Text",
+ "in_list_view": 1,
+ "label": "Purpose",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_11",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "column_break_11",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "advance_amount",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Advance Amount",
- "length": 0,
- "no_copy": 0,
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "advance_amount",
+ "fieldtype": "Currency",
+ "in_list_view": 1,
+ "label": "Advance Amount",
+ "options": "Company:company:default_currency",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "paid_amount",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Paid Amount",
- "length": 0,
- "no_copy": 1,
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "paid_amount",
+ "fieldtype": "Currency",
+ "label": "Paid Amount",
+ "no_copy": 1,
+ "options": "Company:company:default_currency",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:cur_frm.doc.employee",
- "fieldname": "due_advance_amount",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Due Advance Amount",
- "length": 0,
- "no_copy": 0,
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "depends_on": "eval:cur_frm.doc.employee",
+ "fieldname": "due_advance_amount",
+ "fieldtype": "Currency",
+ "label": "Due Advance Amount",
+ "options": "Company:company:default_currency",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "claimed_amount",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Claimed Amount",
- "length": 0,
- "no_copy": 1,
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "claimed_amount",
+ "fieldtype": "Currency",
+ "label": "Claimed Amount",
+ "no_copy": 1,
+ "options": "Company:company:default_currency",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "section_break_7",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "section_break_7",
+ "fieldtype": "Section Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "status",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Status",
- "length": 0,
- "no_copy": 1,
- "options": "Draft\nPaid\nUnpaid\nClaimed\nCancelled",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "status",
+ "fieldtype": "Select",
+ "label": "Status",
+ "no_copy": 1,
+ "options": "Draft\nPaid\nUnpaid\nClaimed\nCancelled",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "company",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Company",
- "length": 0,
- "no_copy": 0,
- "options": "Company",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "label": "Company",
+ "options": "Company",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "amended_from",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Amended From",
- "length": 0,
- "no_copy": 1,
- "options": "Employee Advance",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "amended_from",
+ "fieldtype": "Link",
+ "label": "Amended From",
+ "no_copy": 1,
+ "options": "Employee Advance",
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_18",
- "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
- },
+ "fieldname": "column_break_18",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "advance_account",
- "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": "Advance Account",
- "length": 0,
- "no_copy": 0,
- "options": "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": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "advance_account",
+ "fieldtype": "Link",
+ "ignore_user_permissions": 1,
+ "label": "Advance Account",
+ "options": "Account",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "mode_of_payment",
- "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": "Mode of Payment",
- "length": 0,
- "no_copy": 0,
- "options": "Mode of Payment",
- "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
+ "fieldname": "mode_of_payment",
+ "fieldtype": "Link",
+ "label": "Mode of Payment",
+ "options": "Mode of Payment"
+ },
+ {
+ "fieldname": "return_amount",
+ "fieldtype": "Currency",
+ "label": "Returned Amount",
+ "options": "Company:company:default_currency",
+ "read_only": 1
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 1,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2019-01-30 11:28:15.529649",
- "modified_by": "Administrator",
- "module": "HR",
- "name": "Employee Advance",
- "name_case": "",
- "owner": "Administrator",
+ ],
+ "is_submittable": 1,
+ "links": [],
+ "modified": "2019-12-15 19:04:07.044505",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Employee Advance",
+ "owner": "Administrator",
"permissions": [
{
- "amend": 0,
- "cancel": 0,
- "create": 1,
- "delete": 0,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Employee",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
+ "create": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Employee",
+ "share": 1,
"write": 1
- },
+ },
{
- "amend": 1,
- "cancel": 1,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Expense Approver",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 1,
+ "amend": 1,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Expense Approver",
+ "share": 1,
+ "submit": 1,
"write": 1
}
- ],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "search_fields": "employee,employee_name",
- "show_name_in_global_search": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1,
- "track_seen": 0,
- "track_views": 0
-}
\ No newline at end of file
+ ],
+ "search_fields": "employee,employee_name",
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
diff --git a/erpnext/hr/doctype/employee_advance/employee_advance.py b/erpnext/hr/doctype/employee_advance/employee_advance.py
index 7813da7..7fe2ebc 100644
--- a/erpnext/hr/doctype/employee_advance/employee_advance.py
+++ b/erpnext/hr/doctype/employee_advance/employee_advance.py
@@ -7,6 +7,7 @@
from frappe import _
from frappe.model.document import Document
from frappe.utils import flt, nowdate
+from erpnext.accounts.doctype.journal_entry.journal_entry import get_default_bank_cash_account
class EmployeeAdvanceOverPayment(frappe.ValidationError):
pass
@@ -53,11 +54,25 @@
and party = %s
""", (self.name, self.employee), as_dict=1)[0].paid_amount
+ return_amount = frappe.db.sql("""
+ select name, ifnull(sum(credit_in_account_currency), 0) as return_amount
+ from `tabGL Entry`
+ where against_voucher_type = 'Employee Advance'
+ and voucher_type != 'Expense Claim'
+ and against_voucher = %s
+ and party_type = 'Employee'
+ and party = %s
+ """, (self.name, self.employee), as_dict=1)[0].return_amount
+
if flt(paid_amount) > self.advance_amount:
frappe.throw(_("Row {0}# Paid Amount cannot be greater than requested advance amount"),
EmployeeAdvanceOverPayment)
+ if flt(return_amount) > self.paid_amount - self.claimed_amount:
+ frappe.throw(_("Return amount cannot be greater unclaimed amount"))
+
self.db_set("paid_amount", paid_amount)
+ self.db_set("return_amount", return_amount)
self.set_status()
frappe.db.set_value("Employee Advance", self.name , "status", self.status)
@@ -88,8 +103,6 @@
@frappe.whitelist()
def make_bank_entry(dt, dn):
- from erpnext.accounts.doctype.journal_entry.journal_entry import get_default_bank_cash_account
-
doc = frappe.get_doc(dt, dn)
payment_account = get_default_bank_cash_account(doc.company, account_type="Cash",
mode_of_payment=doc.mode_of_payment)
@@ -118,3 +131,33 @@
})
return je.as_dict()
+
+@frappe.whitelist()
+def make_return_entry(employee_name, company, employee_advance_name, return_amount, mode_of_payment, advance_account):
+ return_account = get_default_bank_cash_account(company, account_type='Cash', mode_of_payment = mode_of_payment)
+ je = frappe.new_doc('Journal Entry')
+ je.posting_date = nowdate()
+ je.voucher_type = 'Bank Entry'
+ je.company = company
+ je.remark = 'Return against Employee Advance: ' + employee_advance_name
+
+ je.append('accounts', {
+ 'account': advance_account,
+ 'credit_in_account_currency': return_amount,
+ 'reference_type': 'Employee Advance',
+ 'reference_name': employee_advance_name,
+ 'party_type': 'Employee',
+ 'party': employee_name,
+ 'is_advance': 'Yes'
+ })
+
+ je.append("accounts", {
+ "account": return_account.account,
+ "debit_in_account_currency": return_amount,
+ "account_currency": return_account.account_currency,
+ "account_type": return_account.account_type
+ })
+
+ return je.as_dict()
+
+
diff --git a/erpnext/hr/doctype/employee_advance/employee_advance_dashboard.py b/erpnext/hr/doctype/employee_advance/employee_advance_dashboard.py
new file mode 100644
index 0000000..c3b4a3a
--- /dev/null
+++ b/erpnext/hr/doctype/employee_advance/employee_advance_dashboard.py
@@ -0,0 +1,19 @@
+from __future__ import unicode_literals
+from frappe import _
+
+def get_data():
+ return {
+ 'fieldname': 'employee_advance',
+ 'non_standard_fieldnames': {
+ 'Payment Entry': 'reference_name',
+ 'Journal Entry': 'reference_name'
+ },
+ 'transactions': [
+ {
+ 'items': ['Expense Claim']
+ },
+ {
+ 'items': ['Payment Entry', 'Journal Entry']
+ }
+ ]
+ }
diff --git a/erpnext/hr/doctype/employee_attendance_tool/employee_attendance_tool.py b/erpnext/hr/doctype/employee_attendance_tool/employee_attendance_tool.py
index 32fcee1..16c1a32 100644
--- a/erpnext/hr/doctype/employee_attendance_tool/employee_attendance_tool.py
+++ b/erpnext/hr/doctype/employee_attendance_tool/employee_attendance_tool.py
@@ -6,6 +6,7 @@
import frappe
import json
from frappe.model.document import Document
+from frappe.utils import getdate
class EmployeeAttendanceTool(Document):
@@ -43,17 +44,26 @@
@frappe.whitelist()
def mark_employee_attendance(employee_list, status, date, leave_type=None, company=None):
+
employee_list = json.loads(employee_list)
for employee in employee_list:
- attendance = frappe.new_doc("Attendance")
- attendance.employee = employee['employee']
- attendance.employee_name = employee['employee_name']
- attendance.attendance_date = date
- attendance.status = status
+
if status == "On Leave" and leave_type:
- attendance.leave_type = leave_type
- if company:
- attendance.company = company
+ leave_type = leave_type
else:
- attendance.company = frappe.db.get_value("Employee", employee['employee'], "Company")
+ leave_type = None
+
+ if not company:
+ company = frappe.db.get_value("Employee", employee['employee'], "Company")
+
+ attendance=frappe.get_doc(dict(
+ doctype='Attendance',
+ employee=employee.get('employee'),
+ employee_name=employee.get('employee_name'),
+ attendance_date=getdate(date),
+ status=status,
+ leave_type=leave_type,
+ company=company
+ ))
+ attendance.insert()
attendance.submit()
diff --git a/erpnext/hr/doctype/employee_incentive/employee_incentive.json b/erpnext/hr/doctype/employee_incentive/employee_incentive.json
index 3bc772c..ce8e1ea 100644
--- a/erpnext/hr/doctype/employee_incentive/employee_incentive.json
+++ b/erpnext/hr/doctype/employee_incentive/employee_incentive.json
@@ -1,4 +1,5 @@
{
+ "actions": [],
"autoname": "HR-EINV-.YY.-.MM.-.#####",
"creation": "2018-04-13 16:13:43.404546",
"doctype": "DocType",
@@ -7,13 +8,13 @@
"field_order": [
"employee",
"incentive_amount",
+ "employee_name",
+ "additional_salary",
+ "column_break_5",
"payroll_date",
"salary_component",
- "amended_from",
- "column_break_5",
- "employee_name",
"department",
- "additional_salary"
+ "amended_from"
],
"fields": [
{
@@ -81,7 +82,8 @@
}
],
"is_submittable": 1,
- "modified": "2019-09-03 16:48:16.822252",
+ "links": [],
+ "modified": "2019-12-12 13:24:44.761540",
"modified_by": "Administrator",
"module": "HR",
"name": "Employee Incentive",
diff --git a/erpnext/hr/doctype/employee_onboarding/employee_onboarding.js b/erpnext/hr/doctype/employee_onboarding/employee_onboarding.js
index 996dcdf..c128567 100644
--- a/erpnext/hr/doctype/employee_onboarding/employee_onboarding.js
+++ b/erpnext/hr/doctype/employee_onboarding/employee_onboarding.js
@@ -7,6 +7,14 @@
frm.add_fetch("employee_onboarding_template", "department", "department");
frm.add_fetch("employee_onboarding_template", "designation", "designation");
frm.add_fetch("employee_onboarding_template", "employee_grade", "employee_grade");
+
+ frm.set_query('job_offer', function () {
+ return {
+ filters: {
+ 'job_applicant': frm.doc.job_applicant
+ }
+ };
+ });
},
refresh: function(frm) {
diff --git a/erpnext/hr/doctype/employee_skill_map/employee_skill_map.json b/erpnext/hr/doctype/employee_skill_map/employee_skill_map.json
index 624145f..21e2513 100644
--- a/erpnext/hr/doctype/employee_skill_map/employee_skill_map.json
+++ b/erpnext/hr/doctype/employee_skill_map/employee_skill_map.json
@@ -1,298 +1,88 @@
{
- "allow_copy": 0,
- "allow_events_in_timeline": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
+ "actions": [],
"autoname": "field:employee",
- "beta": 0,
"creation": "2019-04-16 10:07:48.303426",
- "custom": 0,
- "docstatus": 0,
"doctype": "DocType",
- "document_type": "",
- "editable_grid": 0,
"engine": "InnoDB",
+ "field_order": [
+ "employee",
+ "employee_name",
+ "column_break_3",
+ "designation",
+ "skills_section",
+ "employee_skills",
+ "trainings_section",
+ "trainings"
+ ],
"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": "employee",
"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": "Employee",
- "length": 0,
- "no_copy": 0,
"options": "Employee",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
"unique": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fetch_from": "employee.employee_name",
- "fetch_if_empty": 0,
"fieldname": "employee_name",
"fieldtype": "Read Only",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Employee Name",
- "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": "Employee Name"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fetch_from": "employee.designation",
- "fetch_if_empty": 0,
"fieldname": "designation",
"fieldtype": "Read Only",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Designation",
- "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": "Designation"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "skills_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": "Skills",
- "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": "Skills"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "employee_skills",
"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": "Employee Skills",
- "length": 0,
- "no_copy": 0,
- "options": "Employee Skill",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "options": "Employee Skill"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "trainings_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": "Trainings",
- "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": "Trainings"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
"fieldname": "trainings",
"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": "Trainings",
- "length": 0,
- "no_copy": 0,
- "options": "Employee Training",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "options": "Employee Training"
+ },
+ {
+ "fieldname": "column_break_3",
+ "fieldtype": "Column Break"
}
],
- "has_web_view": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2019-04-16 16:16:40.058429",
+ "links": [],
+ "modified": "2019-12-16 11:31:09.916893",
"modified_by": "Administrator",
"module": "HR",
"name": "Employee Skill Map",
- "name_case": "",
"owner": "Administrator",
"permissions": [
{
- "amend": 0,
- "cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
- "set_user_permissions": 0,
"share": 1,
- "submit": 0,
"write": 1
}
],
"quick_entry": 1,
- "read_only": 0,
- "show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "ASC",
- "title_field": "employee_name",
- "track_changes": 0,
- "track_seen": 0,
- "track_views": 0
+ "title_field": "employee_name"
}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/expense_claim/expense_claim.js b/erpnext/hr/doctype/expense_claim/expense_claim.js
index 6d3a28e..e0bfc83 100644
--- a/erpnext/hr/doctype/expense_claim/expense_claim.js
+++ b/erpnext/hr/doctype/expense_claim/expense_claim.js
@@ -42,12 +42,6 @@
cur_frm.set_value("posting_date", frappe.datetime.get_today());
cur_frm.cscript.clear_sanctioned(doc);
}
-
- cur_frm.fields_dict.employee.get_query = function() {
- return {
- query: "erpnext.controllers.queries.employee_query"
- };
- };
};
cur_frm.cscript.clear_sanctioned = function(doc) {
@@ -119,7 +113,7 @@
};
erpnext.expense_claim = {
- set_title :function(frm) {
+ set_title: function(frm) {
if (!frm.doc.task) {
frm.set_value("title", frm.doc.employee_name);
}
@@ -131,20 +125,20 @@
frappe.ui.form.on("Expense Claim", {
setup: function(frm) {
- frm.trigger("set_query_for_cost_center");
- frm.trigger("set_query_for_payable_account");
frm.add_fetch("company", "cost_center", "cost_center");
frm.add_fetch("company", "default_expense_claim_payable_account", "payable_account");
- frm.set_query("employee_advance", "advances", function(doc) {
+
+ frm.set_query("employee_advance", "advances", function() {
return {
filters: [
['docstatus', '=', 1],
- ['employee', '=', doc.employee],
+ ['employee', '=', frm.doc.employee],
['paid_amount', '>', 0],
['paid_amount', '>', 'claimed_amount']
]
};
});
+
frm.set_query("expense_approver", function() {
return {
query: "erpnext.hr.doctype.department_approver.department_approver.get_approvers",
@@ -154,14 +148,49 @@
}
};
});
- frm.set_query("account_head", "taxes", function(doc) {
+
+ frm.set_query("account_head", "taxes", function() {
return {
filters: [
- ['company', '=', doc.company],
+ ['company', '=', frm.doc.company],
['account_type', 'in', ["Tax", "Chargeable", "Income Account", "Expenses Included In Valuation"]]
]
};
});
+
+ frm.set_query("cost_center", "expenses", function() {
+ return {
+ filters: {
+ "company": frm.doc.company,
+ "is_group": 0
+ }
+ };
+ });
+
+ frm.set_query("payable_account", function() {
+ return {
+ filters: {
+ "report_type": "Balance Sheet",
+ "account_type": "Payable",
+ "company": frm.doc.company,
+ "is_group": 0
+ }
+ };
+ });
+
+ frm.set_query("task", function() {
+ return {
+ filters: {
+ 'project': frm.doc.project
+ }
+ };
+ });
+
+ frm.set_query("employee", function() {
+ return {
+ query: "erpnext.controllers.queries.employee_query"
+ };
+ });
},
onload: function(frm) {
@@ -208,6 +237,24 @@
frm.refresh_fields();
},
+ grand_total: function(frm) {
+ frm.trigger("update_employee_advance_claimed_amount");
+ },
+
+ update_employee_advance_claimed_amount: function(frm) {
+ let amount_to_be_allocated = frm.doc.grand_total;
+ $.each(frm.doc.advances || [], function(i, advance) {
+ if (amount_to_be_allocated >= advance.unclaimed_amount) {
+ frm.doc.advances[i].allocated_amount = frm.doc.advances[i].unclaimed_amount;
+ amount_to_be_allocated -= advance.allocated_amount;
+ } else {
+ frm.doc.advances[i].allocated_amount = amount_to_be_allocated;
+ amount_to_be_allocated = 0;
+ }
+ frm.refresh_field("advances");
+ });
+ },
+
make_payment_entry: function(frm) {
var method = "erpnext.accounts.doctype.payment_entry.payment_entry.get_payment_entry";
if(frm.doc.__onload && frm.doc.__onload.make_payment_via_journal_entry) {
@@ -226,30 +273,6 @@
});
},
- set_query_for_cost_center: function(frm) {
- frm.fields_dict["cost_center"].get_query = function() {
- return {
- filters: {
- "company": frm.doc.company,
- "is_group": 0
- }
- };
- };
- },
-
- set_query_for_payable_account: function(frm) {
- frm.fields_dict["payable_account"].get_query = function() {
- return {
- filters: {
- "report_type": "Balance Sheet",
- "account_type": "Payable",
- "company": frm.doc.company,
- "is_group": 0
- }
- };
- };
- },
-
is_paid: function(frm) {
frm.trigger("toggle_fields");
},
@@ -300,7 +323,7 @@
row.advance_account = d.advance_account;
row.advance_paid = d.paid_amount;
row.unclaimed_amount = flt(d.paid_amount) - flt(d.claimed_amount);
- row.allocated_amount = flt(d.paid_amount) - flt(d.claimed_amount);
+ row.allocated_amount = 0;
});
refresh_field("advances");
}
@@ -311,6 +334,10 @@
});
frappe.ui.form.on("Expense Claim Detail", {
+ expenses_add: function(frm, cdt, cdn) {
+ var row = frappe.get_doc(cdt, cdn);
+ frm.script_manager.copy_from_first_row("expenses", row, ["cost_center"]);
+ },
amount: function(frm, cdt, cdn) {
var child = locals[cdt][cdn];
var doc = frm.doc;
@@ -323,6 +350,9 @@
cur_frm.cscript.calculate_total(doc,cdt,cdn);
frm.trigger("get_taxes");
frm.trigger("calculate_grand_total");
+ },
+ cost_center: function(frm, cdt, cdn) {
+ erpnext.utils.copy_value_in_all_rows(frm.doc, cdt, cdn, "expenses", "cost_center");
}
});
@@ -393,12 +423,4 @@
tax_amount: function(frm, cdt, cdn) {
frm.trigger("calculate_total_tax", cdt, cdn);
}
-});
-
-cur_frm.fields_dict['task'].get_query = function(doc) {
- return {
- filters:{
- 'project': doc.project
- }
- };
-};
+});
\ No newline at end of file
diff --git a/erpnext/hr/doctype/expense_claim/expense_claim.json b/erpnext/hr/doctype/expense_claim/expense_claim.json
index 4e2778f..96baaab 100644
--- a/erpnext/hr/doctype/expense_claim/expense_claim.json
+++ b/erpnext/hr/doctype/expense_claim/expense_claim.json
@@ -1,435 +1,438 @@
{
- "allow_import": 1,
- "autoname": "naming_series:",
- "creation": "2013-01-10 16:34:14",
- "doctype": "DocType",
- "document_type": "Setup",
- "engine": "InnoDB",
- "field_order": [
- "naming_series",
- "employee",
- "employee_name",
- "department",
- "column_break_5",
- "expense_approver",
- "approval_status",
- "is_paid",
- "expense_details",
- "expenses",
- "sb1",
- "taxes",
- "transactions_section",
- "total_sanctioned_amount",
- "total_taxes_and_charges",
- "total_advance_amount",
- "column_break_17",
- "grand_total",
- "total_claimed_amount",
- "total_amount_reimbursed",
- "section_break_16",
- "posting_date",
- "vehicle_log",
- "task",
- "cb1",
- "remark",
- "title",
- "email_id",
- "accounting_details",
- "company",
- "mode_of_payment",
- "clearance_date",
- "column_break_24",
- "payable_account",
- "accounting_dimensions_section",
- "project",
- "dimension_col_break",
- "cost_center",
- "more_details",
- "status",
- "amended_from",
- "advance_payments",
- "advances"
- ],
- "fields": [
- {
- "fieldname": "naming_series",
- "fieldtype": "Select",
- "label": "Series",
- "no_copy": 1,
- "options": "HR-EXP-.YYYY.-",
- "print_hide": 1,
- "reqd": 1,
- "set_only_once": 1
- },
- {
- "fieldname": "employee",
- "fieldtype": "Link",
- "in_global_search": 1,
- "label": "From Employee",
- "oldfieldname": "employee",
- "oldfieldtype": "Link",
- "options": "Employee",
- "reqd": 1,
- "search_index": 1
- },
- {
- "fetch_from": "employee.employee_name",
- "fieldname": "employee_name",
- "fieldtype": "Data",
- "in_global_search": 1,
- "label": "Employee Name",
- "oldfieldname": "employee_name",
- "oldfieldtype": "Data",
- "read_only": 1,
- "width": "150px"
- },
- {
- "fetch_from": "employee.department",
- "fieldname": "department",
- "fieldtype": "Link",
- "label": "Department",
- "options": "Department",
- "read_only": 1
- },
- {
- "fieldname": "column_break_5",
- "fieldtype": "Column Break"
- },
- {
- "fieldname": "expense_approver",
- "fieldtype": "Link",
- "label": "Expense Approver",
- "options": "User"
- },
- {
- "default": "Draft",
- "fieldname": "approval_status",
- "fieldtype": "Select",
- "label": "Approval Status",
- "no_copy": 1,
- "options": "Draft\nApproved\nRejected",
- "search_index": 1
- },
- {
- "fieldname": "total_claimed_amount",
- "fieldtype": "Currency",
- "in_list_view": 1,
- "label": "Total Claimed Amount",
- "no_copy": 1,
- "oldfieldname": "total_claimed_amount",
- "oldfieldtype": "Currency",
- "options": "Company:company:default_currency",
- "read_only": 1,
- "width": "160px"
- },
- {
- "fieldname": "total_sanctioned_amount",
- "fieldtype": "Currency",
- "label": "Total Sanctioned Amount",
- "no_copy": 1,
- "oldfieldname": "total_sanctioned_amount",
- "oldfieldtype": "Currency",
- "options": "Company:company:default_currency",
- "read_only": 1,
- "width": "160px"
- },
- {
- "default": "0",
- "depends_on": "eval:(doc.docstatus==0 || doc.is_paid)",
- "fieldname": "is_paid",
- "fieldtype": "Check",
- "label": "Is Paid"
- },
- {
- "fieldname": "expense_details",
- "fieldtype": "Section Break",
- "oldfieldtype": "Section Break"
- },
- {
- "fieldname": "expenses",
- "fieldtype": "Table",
- "label": "Expenses",
- "oldfieldname": "expense_voucher_details",
- "oldfieldtype": "Table",
- "options": "Expense Claim Detail",
- "reqd": 1
- },
- {
- "fieldname": "sb1",
- "fieldtype": "Section Break",
- "options": "Simple"
- },
- {
- "default": "Today",
- "fieldname": "posting_date",
- "fieldtype": "Date",
- "label": "Posting Date",
- "oldfieldname": "posting_date",
- "oldfieldtype": "Date",
- "reqd": 1
- },
- {
- "fieldname": "vehicle_log",
- "fieldtype": "Link",
- "label": "Vehicle Log",
- "options": "Vehicle Log",
- "read_only": 1
- },
- {
- "fieldname": "project",
- "fieldtype": "Link",
- "label": "Project",
- "options": "Project"
- },
- {
- "fieldname": "task",
- "fieldtype": "Link",
- "label": "Task",
- "options": "Task",
- "remember_last_selected_value": 1
- },
- {
- "fieldname": "cb1",
- "fieldtype": "Column Break"
- },
- {
- "fieldname": "total_amount_reimbursed",
- "fieldtype": "Currency",
- "in_list_view": 1,
- "label": "Total Amount Reimbursed",
- "no_copy": 1,
- "options": "Company:company:default_currency",
- "read_only": 1
- },
- {
- "fieldname": "remark",
- "fieldtype": "Small Text",
- "label": "Remark",
- "no_copy": 1,
- "oldfieldname": "remark",
- "oldfieldtype": "Small Text"
- },
- {
- "allow_on_submit": 1,
- "default": "{employee_name}",
- "fieldname": "title",
- "fieldtype": "Data",
- "hidden": 1,
- "label": "Title",
- "no_copy": 1
- },
- {
- "fieldname": "email_id",
- "fieldtype": "Data",
- "hidden": 1,
- "label": "Employees Email Id",
- "oldfieldname": "email_id",
- "oldfieldtype": "Data",
- "print_hide": 1
- },
- {
- "fieldname": "accounting_details",
- "fieldtype": "Section Break",
- "label": "Accounting Details"
- },
- {
- "fieldname": "company",
- "fieldtype": "Link",
- "label": "Company",
- "oldfieldname": "company",
- "oldfieldtype": "Link",
- "options": "Company",
- "remember_last_selected_value": 1,
- "reqd": 1
- },
- {
- "depends_on": "is_paid",
- "fieldname": "mode_of_payment",
- "fieldtype": "Link",
- "label": "Mode of Payment",
- "options": "Mode of Payment"
- },
- {
- "fieldname": "clearance_date",
- "fieldtype": "Date",
- "label": "Clearance Date"
- },
- {
- "fieldname": "column_break_24",
- "fieldtype": "Column Break"
- },
- {
- "fieldname": "payable_account",
- "fieldtype": "Link",
- "label": "Payable Account",
- "options": "Account"
- },
- {
- "fieldname": "cost_center",
- "fieldtype": "Link",
- "label": "Cost Center",
- "options": "Cost Center"
- },
- {
- "collapsible": 1,
- "fieldname": "more_details",
- "fieldtype": "Section Break",
- "label": "More Details"
- },
- {
- "default": "Draft",
- "fieldname": "status",
- "fieldtype": "Select",
- "in_list_view": 1,
- "label": "Status",
- "no_copy": 1,
- "options": "Draft\nPaid\nUnpaid\nRejected\nSubmitted\nCancelled",
- "print_hide": 1,
- "read_only": 1
- },
- {
- "fieldname": "amended_from",
- "fieldtype": "Link",
- "ignore_user_permissions": 1,
- "label": "Amended From",
- "no_copy": 1,
- "oldfieldname": "amended_from",
- "oldfieldtype": "Data",
- "options": "Expense Claim",
- "print_hide": 1,
- "read_only": 1,
- "report_hide": 1,
- "width": "160px"
- },
- {
- "fieldname": "advance_payments",
- "fieldtype": "Section Break",
- "label": "Advance Payments"
- },
- {
- "fieldname": "advances",
- "fieldtype": "Table",
- "label": "Advances",
- "options": "Expense Claim Advance"
- },
- {
- "fieldname": "total_advance_amount",
- "fieldtype": "Currency",
- "label": "Total Advance Amount",
- "options": "Company:company:default_currency",
- "read_only": 1
- },
- {
- "fieldname": "accounting_dimensions_section",
- "fieldtype": "Section Break",
- "label": "Accounting Dimensions"
- },
- {
- "fieldname": "dimension_col_break",
- "fieldtype": "Column Break"
- },
- {
- "fieldname": "taxes",
- "fieldtype": "Table",
- "label": "Expense Taxes and Charges",
- "options": "Expense Taxes and Charges"
- },
- {
- "fieldname": "section_break_16",
- "fieldtype": "Section Break"
- },
- {
- "fieldname": "transactions_section",
- "fieldtype": "Section Break"
- },
- {
- "fieldname": "grand_total",
- "fieldtype": "Currency",
- "in_list_view": 1,
- "label": "Grand Total",
- "options": "Company:company:default_currency",
- "read_only": 1
- },
- {
- "fieldname": "column_break_17",
- "fieldtype": "Column Break"
- },
- {
- "fieldname": "total_taxes_and_charges",
- "fieldtype": "Currency",
- "label": "Total Taxes and Charges",
- "options": "Company:company:default_currency",
- "read_only": 1
- }
- ],
- "icon": "fa fa-money",
- "idx": 1,
- "is_submittable": 1,
- "modified": "2019-06-26 18:05:52.530462",
- "modified_by": "Administrator",
- "module": "HR",
- "name": "Expense Claim",
- "name_case": "Title Case",
- "owner": "harshada@webnotestech.com",
- "permissions": [
- {
- "amend": 1,
- "cancel": 1,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "HR Manager",
- "share": 1,
- "submit": 1,
- "write": 1
- },
- {
- "create": 1,
- "email": 1,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Employee",
- "share": 1,
- "write": 1
- },
- {
- "amend": 1,
- "cancel": 1,
- "create": 1,
- "delete": 1,
- "email": 1,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Expense Approver",
- "share": 1,
- "submit": 1,
- "write": 1
- },
- {
- "amend": 1,
- "cancel": 1,
- "create": 1,
- "delete": 1,
- "email": 1,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "HR User",
- "share": 1,
- "submit": 1,
- "write": 1
- }
- ],
- "search_fields": "employee,employee_name",
- "show_name_in_global_search": 1,
- "sort_field": "modified",
- "sort_order": "DESC",
- "timeline_field": "employee",
- "title_field": "title"
- }
\ No newline at end of file
+ "actions": [],
+ "allow_import": 1,
+ "autoname": "naming_series:",
+ "creation": "2013-01-10 16:34:14",
+ "doctype": "DocType",
+ "document_type": "Setup",
+ "engine": "InnoDB",
+ "field_order": [
+ "naming_series",
+ "employee",
+ "employee_name",
+ "department",
+ "column_break_5",
+ "expense_approver",
+ "approval_status",
+ "is_paid",
+ "expense_details",
+ "expenses",
+ "sb1",
+ "taxes",
+ "transactions_section",
+ "total_sanctioned_amount",
+ "total_taxes_and_charges",
+ "total_advance_amount",
+ "column_break_17",
+ "grand_total",
+ "total_claimed_amount",
+ "total_amount_reimbursed",
+ "section_break_16",
+ "posting_date",
+ "vehicle_log",
+ "task",
+ "cb1",
+ "remark",
+ "title",
+ "email_id",
+ "accounting_details",
+ "company",
+ "mode_of_payment",
+ "clearance_date",
+ "column_break_24",
+ "payable_account",
+ "accounting_dimensions_section",
+ "project",
+ "dimension_col_break",
+ "cost_center",
+ "more_details",
+ "status",
+ "amended_from",
+ "advance_payments",
+ "advances"
+ ],
+ "fields": [
+ {
+ "fieldname": "naming_series",
+ "fieldtype": "Select",
+ "label": "Series",
+ "no_copy": 1,
+ "options": "HR-EXP-.YYYY.-",
+ "print_hide": 1,
+ "reqd": 1,
+ "set_only_once": 1
+ },
+ {
+ "fieldname": "employee",
+ "fieldtype": "Link",
+ "in_global_search": 1,
+ "label": "From Employee",
+ "oldfieldname": "employee",
+ "oldfieldtype": "Link",
+ "options": "Employee",
+ "reqd": 1,
+ "search_index": 1
+ },
+ {
+ "fetch_from": "employee.employee_name",
+ "fieldname": "employee_name",
+ "fieldtype": "Data",
+ "in_global_search": 1,
+ "label": "Employee Name",
+ "oldfieldname": "employee_name",
+ "oldfieldtype": "Data",
+ "read_only": 1,
+ "width": "150px"
+ },
+ {
+ "fetch_from": "employee.department",
+ "fieldname": "department",
+ "fieldtype": "Link",
+ "label": "Department",
+ "options": "Department",
+ "read_only": 1
+ },
+ {
+ "fieldname": "column_break_5",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "expense_approver",
+ "fieldtype": "Link",
+ "label": "Expense Approver",
+ "options": "User"
+ },
+ {
+ "default": "Draft",
+ "fieldname": "approval_status",
+ "fieldtype": "Select",
+ "label": "Approval Status",
+ "no_copy": 1,
+ "options": "Draft\nApproved\nRejected",
+ "search_index": 1
+ },
+ {
+ "fieldname": "total_claimed_amount",
+ "fieldtype": "Currency",
+ "in_list_view": 1,
+ "label": "Total Claimed Amount",
+ "no_copy": 1,
+ "oldfieldname": "total_claimed_amount",
+ "oldfieldtype": "Currency",
+ "options": "Company:company:default_currency",
+ "read_only": 1,
+ "width": "160px"
+ },
+ {
+ "fieldname": "total_sanctioned_amount",
+ "fieldtype": "Currency",
+ "label": "Total Sanctioned Amount",
+ "no_copy": 1,
+ "oldfieldname": "total_sanctioned_amount",
+ "oldfieldtype": "Currency",
+ "options": "Company:company:default_currency",
+ "read_only": 1,
+ "width": "160px"
+ },
+ {
+ "default": "0",
+ "depends_on": "eval:(doc.docstatus==0 || doc.is_paid)",
+ "fieldname": "is_paid",
+ "fieldtype": "Check",
+ "label": "Is Paid"
+ },
+ {
+ "fieldname": "expense_details",
+ "fieldtype": "Section Break",
+ "oldfieldtype": "Section Break"
+ },
+ {
+ "fieldname": "expenses",
+ "fieldtype": "Table",
+ "label": "Expenses",
+ "oldfieldname": "expense_voucher_details",
+ "oldfieldtype": "Table",
+ "options": "Expense Claim Detail",
+ "reqd": 1
+ },
+ {
+ "fieldname": "sb1",
+ "fieldtype": "Section Break",
+ "options": "Simple"
+ },
+ {
+ "default": "Today",
+ "fieldname": "posting_date",
+ "fieldtype": "Date",
+ "label": "Posting Date",
+ "oldfieldname": "posting_date",
+ "oldfieldtype": "Date",
+ "reqd": 1
+ },
+ {
+ "fieldname": "vehicle_log",
+ "fieldtype": "Link",
+ "label": "Vehicle Log",
+ "options": "Vehicle Log",
+ "read_only": 1
+ },
+ {
+ "fieldname": "project",
+ "fieldtype": "Link",
+ "label": "Project",
+ "options": "Project"
+ },
+ {
+ "fieldname": "task",
+ "fieldtype": "Link",
+ "label": "Task",
+ "options": "Task",
+ "remember_last_selected_value": 1
+ },
+ {
+ "fieldname": "cb1",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "total_amount_reimbursed",
+ "fieldtype": "Currency",
+ "in_list_view": 1,
+ "label": "Total Amount Reimbursed",
+ "no_copy": 1,
+ "options": "Company:company:default_currency",
+ "read_only": 1
+ },
+ {
+ "fieldname": "remark",
+ "fieldtype": "Small Text",
+ "label": "Remark",
+ "no_copy": 1,
+ "oldfieldname": "remark",
+ "oldfieldtype": "Small Text"
+ },
+ {
+ "allow_on_submit": 1,
+ "default": "{employee_name}",
+ "fieldname": "title",
+ "fieldtype": "Data",
+ "hidden": 1,
+ "label": "Title",
+ "no_copy": 1
+ },
+ {
+ "fieldname": "email_id",
+ "fieldtype": "Data",
+ "hidden": 1,
+ "label": "Employees Email Id",
+ "oldfieldname": "email_id",
+ "oldfieldtype": "Data",
+ "print_hide": 1
+ },
+ {
+ "fieldname": "accounting_details",
+ "fieldtype": "Section Break",
+ "label": "Accounting Details"
+ },
+ {
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "label": "Company",
+ "oldfieldname": "company",
+ "oldfieldtype": "Link",
+ "options": "Company",
+ "remember_last_selected_value": 1,
+ "reqd": 1
+ },
+ {
+ "depends_on": "is_paid",
+ "fieldname": "mode_of_payment",
+ "fieldtype": "Link",
+ "label": "Mode of Payment",
+ "options": "Mode of Payment"
+ },
+ {
+ "fieldname": "clearance_date",
+ "fieldtype": "Date",
+ "label": "Clearance Date"
+ },
+ {
+ "fieldname": "column_break_24",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "payable_account",
+ "fieldtype": "Link",
+ "label": "Payable Account",
+ "options": "Account",
+ "reqd": 1
+ },
+ {
+ "fieldname": "cost_center",
+ "fieldtype": "Link",
+ "label": "Cost Center",
+ "options": "Cost Center"
+ },
+ {
+ "collapsible": 1,
+ "fieldname": "more_details",
+ "fieldtype": "Section Break",
+ "label": "More Details"
+ },
+ {
+ "default": "Draft",
+ "fieldname": "status",
+ "fieldtype": "Select",
+ "in_list_view": 1,
+ "label": "Status",
+ "no_copy": 1,
+ "options": "Draft\nPaid\nUnpaid\nRejected\nSubmitted\nCancelled",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "fieldname": "amended_from",
+ "fieldtype": "Link",
+ "ignore_user_permissions": 1,
+ "label": "Amended From",
+ "no_copy": 1,
+ "oldfieldname": "amended_from",
+ "oldfieldtype": "Data",
+ "options": "Expense Claim",
+ "print_hide": 1,
+ "read_only": 1,
+ "report_hide": 1,
+ "width": "160px"
+ },
+ {
+ "fieldname": "advance_payments",
+ "fieldtype": "Section Break",
+ "label": "Advance Payments"
+ },
+ {
+ "fieldname": "advances",
+ "fieldtype": "Table",
+ "label": "Advances",
+ "options": "Expense Claim Advance"
+ },
+ {
+ "fieldname": "total_advance_amount",
+ "fieldtype": "Currency",
+ "label": "Total Advance Amount",
+ "options": "Company:company:default_currency",
+ "read_only": 1
+ },
+ {
+ "fieldname": "accounting_dimensions_section",
+ "fieldtype": "Section Break",
+ "label": "Accounting Dimensions"
+ },
+ {
+ "fieldname": "dimension_col_break",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "taxes",
+ "fieldtype": "Table",
+ "label": "Expense Taxes and Charges",
+ "options": "Expense Taxes and Charges"
+ },
+ {
+ "fieldname": "section_break_16",
+ "fieldtype": "Section Break"
+ },
+ {
+ "fieldname": "transactions_section",
+ "fieldtype": "Section Break"
+ },
+ {
+ "fieldname": "grand_total",
+ "fieldtype": "Currency",
+ "in_list_view": 1,
+ "label": "Grand Total",
+ "options": "Company:company:default_currency",
+ "read_only": 1
+ },
+ {
+ "fieldname": "column_break_17",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "total_taxes_and_charges",
+ "fieldtype": "Currency",
+ "label": "Total Taxes and Charges",
+ "options": "Company:company:default_currency",
+ "read_only": 1
+ }
+ ],
+ "icon": "fa fa-money",
+ "idx": 1,
+ "is_submittable": 1,
+ "links": [],
+ "modified": "2019-12-14 23:52:05.388458",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Expense Claim",
+ "name_case": "Title Case",
+ "owner": "harshada@webnotestech.com",
+ "permissions": [
+ {
+ "amend": 1,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "HR Manager",
+ "share": 1,
+ "submit": 1,
+ "write": 1
+ },
+ {
+ "create": 1,
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Employee",
+ "share": 1,
+ "write": 1
+ },
+ {
+ "amend": 1,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Expense Approver",
+ "share": 1,
+ "submit": 1,
+ "write": 1
+ },
+ {
+ "amend": 1,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "HR User",
+ "share": 1,
+ "submit": 1,
+ "write": 1
+ }
+ ],
+ "search_fields": "employee,employee_name",
+ "show_name_in_global_search": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "timeline_field": "employee",
+ "title_field": "title"
+}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/expense_claim/expense_claim.py b/erpnext/hr/doctype/expense_claim/expense_claim.py
index caeb2dd..e01e7a4 100644
--- a/erpnext/hr/doctype/expense_claim/expense_claim.py
+++ b/erpnext/hr/doctype/expense_claim/expense_claim.py
@@ -43,9 +43,9 @@
}[cstr(self.docstatus or 0)]
paid_amount = flt(self.total_amount_reimbursed) + flt(self.total_advance_amount)
- precision = self.precision("total_sanctioned_amount")
+ precision = self.precision("grand_total")
if (self.is_paid or (flt(self.total_sanctioned_amount) > 0
- and flt(self.total_sanctioned_amount, precision) == flt(paid_amount, precision))) \
+ and flt(self.grand_total, precision) == flt(paid_amount, precision))) \
and self.docstatus == 1 and self.approval_status == 'Approved':
self.status = "Paid"
elif flt(self.total_sanctioned_amount) > 0 and self.docstatus == 1 and self.approval_status == 'Approved':
@@ -127,7 +127,7 @@
"debit": data.sanctioned_amount,
"debit_in_account_currency": data.sanctioned_amount,
"against": self.employee,
- "cost_center": self.cost_center
+ "cost_center": data.cost_center
})
)
@@ -140,10 +140,11 @@
"against": ",".join([d.default_account for d in self.expenses]),
"party_type": "Employee",
"party": self.employee,
- "against_voucher_type": self.doctype,
- "against_voucher": self.name
+ "against_voucher_type": "Employee Advance",
+ "against_voucher": data.employee_advance
})
)
+
self.add_tax_gl_entries(gl_entry)
if self.is_paid and self.grand_total:
@@ -189,11 +190,9 @@
)
def validate_account_details(self):
- if not self.cost_center:
- frappe.throw(_("Cost center is required to book an expense claim"))
-
- if not self.payable_account:
- frappe.throw(_("Please set default payable account for the company {0}").format(getlink("Company",self.company)))
+ for data in self.expenses:
+ if not data.cost_center:
+ frappe.throw(_("Cost center is required to book an expense claim"))
if self.is_paid:
if not self.mode_of_payment:
@@ -323,7 +322,7 @@
@frappe.whitelist()
def get_advances(employee, advance_id=None):
if not advance_id:
- condition = 'docstatus=1 and employee={0} and paid_amount > 0 and paid_amount > claimed_amount'.format(frappe.db.escape(employee))
+ condition = 'docstatus=1 and employee={0} and paid_amount > 0 and paid_amount > claimed_amount + return_amount'.format(frappe.db.escape(employee))
else:
condition = 'name={0}'.format(frappe.db.escape(advance_id))
diff --git a/erpnext/hr/doctype/expense_claim/test_expense_claim.py b/erpnext/hr/doctype/expense_claim/test_expense_claim.py
index b559dfd..6e97f05 100644
--- a/erpnext/hr/doctype/expense_claim/test_expense_claim.py
+++ b/erpnext/hr/doctype/expense_claim/test_expense_claim.py
@@ -126,7 +126,7 @@
def make_expense_claim(payable_account, amount, sanctioned_amount, company, account, project=None, task_name=None, do_not_submit=False, taxes=None):
employee = frappe.db.get_value("Employee", {"status": "Active"})
- currency = frappe.db.get_value('Company', company, 'default_currency')
+ currency, cost_center = frappe.db.get_value('Company', company, ['default_currency', 'cost_center'])
expense_claim = {
"doctype": "Expense Claim",
"employee": employee,
@@ -134,12 +134,15 @@
"approval_status": "Approved",
"company": company,
'currency': currency,
- "expenses":
- [{"expense_type": "Travel",
+ "expenses": [{
+ "expense_type": "Travel",
"default_account": account,
- 'currency': currency,
+ "currency": currency,
"amount": amount,
- "sanctioned_amount": sanctioned_amount}]}
+ "sanctioned_amount": sanctioned_amount,
+ "cost_center": cost_center
+ }]
+ }
if taxes:
expense_claim.update(taxes)
diff --git a/erpnext/hr/doctype/expense_claim_advance/expense_claim_advance.json b/erpnext/hr/doctype/expense_claim_advance/expense_claim_advance.json
index b5e4fd1..db47d18 100644
--- a/erpnext/hr/doctype/expense_claim_advance/expense_claim_advance.json
+++ b/erpnext/hr/doctype/expense_claim_advance/expense_claim_advance.json
@@ -1,238 +1,100 @@
{
- "allow_copy": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "beta": 0,
- "creation": "2017-10-09 16:53:26.410762",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "Document",
- "editable_grid": 1,
- "engine": "InnoDB",
+ "actions": [],
+ "creation": "2017-10-09 16:53:26.410762",
+ "doctype": "DocType",
+ "document_type": "Document",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "employee_advance",
+ "posting_date",
+ "advance_paid",
+ "column_break_4",
+ "unclaimed_amount",
+ "allocated_amount",
+ "advance_account"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 2,
- "fieldname": "employee_advance",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Employee Advance",
- "length": 0,
- "no_copy": 1,
- "oldfieldname": "journal_voucher",
- "oldfieldtype": "Link",
- "options": "Employee Advance",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "print_width": "250px",
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0,
+ "columns": 2,
+ "fieldname": "employee_advance",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Employee Advance",
+ "no_copy": 1,
+ "oldfieldname": "journal_voucher",
+ "oldfieldtype": "Link",
+ "options": "Employee Advance",
+ "print_width": "250px",
+ "reqd": 1,
"width": "250px"
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 2,
- "fieldname": "posting_date",
- "fieldtype": "Date",
- "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": "Posting Date",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "columns": 2,
+ "fieldname": "posting_date",
+ "fieldtype": "Date",
+ "in_list_view": 1,
+ "label": "Posting Date",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 2,
- "fieldname": "advance_paid",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Advance Paid",
- "length": 0,
- "no_copy": 0,
- "options": "Company:company.default_currency",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "columns": 2,
+ "fieldname": "advance_paid",
+ "fieldtype": "Currency",
+ "in_list_view": 1,
+ "label": "Advance Paid",
+ "options": "Company:company.default_currency",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 2,
- "fieldname": "unclaimed_amount",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Unclaimed amount",
- "length": 0,
- "no_copy": 1,
- "oldfieldname": "advance_amount",
- "oldfieldtype": "Currency",
- "options": "Company:company.default_currency",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "print_width": "120px",
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0,
+ "columns": 2,
+ "fieldname": "unclaimed_amount",
+ "fieldtype": "Currency",
+ "in_list_view": 1,
+ "label": "Unclaimed amount",
+ "no_copy": 1,
+ "oldfieldname": "advance_amount",
+ "oldfieldtype": "Currency",
+ "options": "Company:company.default_currency",
+ "print_width": "120px",
+ "read_only": 1,
+ "reqd": 1,
"width": "120px"
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 2,
- "fieldname": "allocated_amount",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Allocated amount",
- "length": 0,
- "no_copy": 1,
- "oldfieldname": "allocated_amount",
- "oldfieldtype": "Currency",
- "options": "Company:company.default_currency",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "print_width": "120px",
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0,
+ "columns": 2,
+ "fieldname": "allocated_amount",
+ "fieldtype": "Currency",
+ "in_list_view": 1,
+ "label": "Allocated amount",
+ "no_copy": 1,
+ "oldfieldname": "allocated_amount",
+ "oldfieldtype": "Currency",
+ "options": "Company:company.default_currency",
+ "print_width": "120px",
"width": "120px"
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "advance_account",
- "fieldtype": "Link",
- "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": "Advance Account",
- "length": 0,
- "no_copy": 0,
- "options": "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": "advance_account",
+ "fieldtype": "Link",
+ "hidden": 1,
+ "label": "Advance Account",
+ "options": "Account"
+ },
+ {
+ "fieldname": "column_break_4",
+ "fieldtype": "Column Break"
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 1,
- "max_attachments": 0,
- "modified": "2017-10-09 19:59:48.818139",
- "modified_by": "Administrator",
- "module": "HR",
- "name": "Expense Claim Advance",
- "name_case": "",
- "owner": "Administrator",
- "permissions": [],
- "quick_entry": 1,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 0,
- "track_seen": 0
+ ],
+ "istable": 1,
+ "links": [],
+ "modified": "2019-12-11 13:53:22.111766",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Expense Claim Advance",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC"
}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/expense_claim_detail/expense_claim_detail.json b/erpnext/hr/doctype/expense_claim_detail/expense_claim_detail.json
index b23fb6a..16e9eef 100644
--- a/erpnext/hr/doctype/expense_claim_detail/expense_claim_detail.json
+++ b/erpnext/hr/doctype/expense_claim_detail/expense_claim_detail.json
@@ -1,378 +1,120 @@
{
- "allow_copy": 0,
- "allow_events_in_timeline": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "beta": 0,
+ "actions": [],
"creation": "2013-02-22 01:27:46",
- "custom": 0,
- "docstatus": 0,
"doctype": "DocType",
"editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "expense_date",
+ "column_break_2",
+ "expense_type",
+ "default_account",
+ "section_break_4",
+ "description",
+ "section_break_6",
+ "amount",
+ "cost_center",
+ "column_break_8",
+ "sanctioned_amount"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "expense_date",
"fieldtype": "Date",
- "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": "Expense Date",
- "length": 0,
- "no_copy": 0,
"oldfieldname": "expense_date",
"oldfieldtype": "Date",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
"print_width": "150px",
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
"width": "150px"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "column_break_2",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "fieldtype": "Column Break"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "expense_type",
"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": "Expense Claim Type",
- "length": 0,
- "no_copy": 0,
"oldfieldname": "expense_type",
"oldfieldtype": "Link",
"options": "Expense Claim Type",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
"print_width": "150px",
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
"reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
"width": "150px"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"depends_on": "expense_type",
"fieldname": "default_account",
"fieldtype": "Link",
"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": "Default Account",
- "length": 0,
- "no_copy": 0,
"options": "Account",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "read_only": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "section_break_4",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "fieldtype": "Section Break"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_from": "",
"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": "Small Text",
- "options": "",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
"print_width": "300px",
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
"width": "300px"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "section_break_6",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "fieldtype": "Section Break"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "amount",
"fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
"in_list_view": 1,
- "in_standard_filter": 0,
"label": "Amount",
- "length": 0,
- "no_copy": 0,
"oldfieldname": "claim_amount",
"oldfieldtype": "Currency",
"options": "Company:company:default_currency",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
"print_width": "150px",
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
"reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
"width": "150px"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "column_break_8",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "fieldtype": "Column Break"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "sanctioned_amount",
"fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
"in_list_view": 1,
- "in_standard_filter": 0,
"label": "Sanctioned Amount",
- "length": 0,
"no_copy": 1,
"oldfieldname": "sanctioned_amount",
"oldfieldtype": "Currency",
"options": "Company:company:default_currency",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
"print_width": "150px",
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
"width": "150px"
+ },
+ {
+ "fieldname": "cost_center",
+ "fieldtype": "Link",
+ "label": "Cost Center",
+ "options": "Cost Center"
}
],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
"idx": 1,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
"istable": 1,
- "max_attachments": 0,
- "modified": "2019-06-10 08:41:36.122565",
+ "links": [],
+ "modified": "2019-12-11 13:42:33.233432",
"modified_by": "Administrator",
"module": "HR",
"name": "Expense Claim Detail",
"owner": "harshada@webnotestech.com",
"permissions": [],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
"sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 0,
- "track_seen": 0,
- "track_views": 0
+ "sort_order": "DESC"
}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/expense_claim_type/expense_claim_type.js b/erpnext/hr/doctype/expense_claim_type/expense_claim_type.js
index fda6809..d007e1a 100644
--- a/erpnext/hr/doctype/expense_claim_type/expense_claim_type.js
+++ b/erpnext/hr/doctype/expense_claim_type/expense_claim_type.js
@@ -2,13 +2,13 @@
// License: GNU General Public License v3. See license.txt
frappe.ui.form.on("Expense Claim Type", {
- refresh: function(frm){
- frm.fields_dict["accounts"].grid.get_field("default_account").get_query = function(frm, cdt, cdn){
+ refresh: function(frm) {
+ frm.fields_dict["accounts"].grid.get_field("default_account").get_query = function(doc, cdt, cdn) {
var d = locals[cdt][cdn];
- return{
+ return {
filters: {
"is_group": 0,
- "root_type": "Expense",
+ "root_type": frm.doc.deferred_expense_account ? "Asset" : "Expense",
'company': d.company
}
}
diff --git a/erpnext/hr/doctype/expense_claim_type/expense_claim_type.json b/erpnext/hr/doctype/expense_claim_type/expense_claim_type.json
index d0c4122..cf2cbb4 100644
--- a/erpnext/hr/doctype/expense_claim_type/expense_claim_type.json
+++ b/erpnext/hr/doctype/expense_claim_type/expense_claim_type.json
@@ -1,181 +1,74 @@
{
- "allow_copy": 0,
- "allow_guest_to_view": 0,
- "allow_import": 1,
- "allow_rename": 1,
- "autoname": "field:expense_type",
- "beta": 0,
- "creation": "2012-03-27 14:35:55",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "Setup",
- "editable_grid": 0,
- "engine": "InnoDB",
+ "actions": [],
+ "allow_import": 1,
+ "allow_rename": 1,
+ "autoname": "field:expense_type",
+ "creation": "2012-03-27 14:35:55",
+ "doctype": "DocType",
+ "document_type": "Setup",
+ "engine": "InnoDB",
+ "field_order": [
+ "deferred_expense_account",
+ "expense_type",
+ "accounts",
+ "description"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "expense_type",
- "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": "Expense Claim Type",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "expense_type",
- "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,
+ "fieldname": "expense_type",
+ "fieldtype": "Data",
+ "in_list_view": 1,
+ "label": "Expense Claim Type",
+ "oldfieldname": "expense_type",
+ "oldfieldtype": "Data",
+ "reqd": 1,
"unique": 1
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "description",
- "fieldtype": "Small Text",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Description",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "description",
- "oldfieldtype": "Small Text",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
+ "fieldname": "description",
+ "fieldtype": "Small Text",
+ "label": "Description",
+ "oldfieldname": "description",
+ "oldfieldtype": "Small Text",
"width": "300px"
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "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": "Expense Claim 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,
- "translatable": 0,
- "unique": 0
+ "fieldname": "accounts",
+ "fieldtype": "Table",
+ "label": "Accounts",
+ "options": "Expense Claim Account"
+ },
+ {
+ "default": "0",
+ "fieldname": "deferred_expense_account",
+ "fieldtype": "Check",
+ "label": "Deferred Expense Account"
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "icon": "fa fa-flag",
- "idx": 1,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2018-09-18 14:13:43.770829",
- "modified_by": "Administrator",
- "module": "HR",
- "name": "Expense Claim Type",
- "owner": "harshada@webnotestech.com",
+ ],
+ "icon": "fa fa-flag",
+ "idx": 1,
+ "links": [],
+ "modified": "2019-12-11 13:38:59.534034",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Expense Claim Type",
+ "owner": "harshada@webnotestech.com",
"permissions": [
{
- "amend": 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": "HR Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
+ "create": 1,
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "HR Manager",
+ "share": 1,
"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
+ "read": 1,
+ "role": "Employee"
}
- ],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
- "sort_order": "ASC",
- "track_changes": 0,
- "track_seen": 0,
- "track_views": 0
+ ],
+ "sort_field": "modified",
+ "sort_order": "ASC"
}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/expense_taxes_and_charges/expense_taxes_and_charges.json b/erpnext/hr/doctype/expense_taxes_and_charges/expense_taxes_and_charges.json
index 9bf69da..96ad1b7 100644
--- a/erpnext/hr/doctype/expense_taxes_and_charges/expense_taxes_and_charges.json
+++ b/erpnext/hr/doctype/expense_taxes_and_charges/expense_taxes_and_charges.json
@@ -1,4 +1,5 @@
{
+ "actions": [],
"autoname": "hash",
"creation": "2019-06-03 11:42:33.123976",
"doctype": "DocType",
@@ -8,8 +9,8 @@
"field_order": [
"account_head",
"cost_center",
- "col_break1",
"rate",
+ "col_break1",
"description",
"section_break_6",
"tax_amount",
@@ -93,7 +94,8 @@
}
],
"istable": 1,
- "modified": "2019-06-20 12:01:33.919555",
+ "links": [],
+ "modified": "2019-12-11 13:50:02.883328",
"modified_by": "Administrator",
"module": "HR",
"name": "Expense Taxes and Charges",
diff --git a/erpnext/hr/doctype/hr_settings/hr_settings.js b/erpnext/hr/doctype/hr_settings/hr_settings.js
index 4004c1c..b629b42 100644
--- a/erpnext/hr/doctype/hr_settings/hr_settings.js
+++ b/erpnext/hr/doctype/hr_settings/hr_settings.js
@@ -2,10 +2,6 @@
// For license information, please see license.txt
frappe.ui.form.on('HR Settings', {
- refresh: function(frm) {
-
- },
-
encrypt_salary_slips_in_emails: function(frm) {
let encrypt_state = frm.doc.encrypt_salary_slips_in_emails;
frm.set_df_property('password_policy', 'reqd', encrypt_state);
@@ -19,5 +15,9 @@
}
frm.set_value('password_policy', policy.split(new RegExp(" |-", 'g')).filter((token) => token).join('-'));
}
+ },
+
+ restrict_backdated_leave_application: function(frm) {
+ frm.toggle_reqd("role_allowed_to_create_backdated_leave_application", frm.doc.restrict_backdated_leave_application);
}
-});
+});
\ No newline at end of file
diff --git a/erpnext/hr/doctype/hr_settings/hr_settings.json b/erpnext/hr/doctype/hr_settings/hr_settings.json
index a41c887..90f4988 100644
--- a/erpnext/hr/doctype/hr_settings/hr_settings.json
+++ b/erpnext/hr/doctype/hr_settings/hr_settings.json
@@ -1,4 +1,5 @@
{
+ "actions": [],
"creation": "2013-08-02 13:45:23",
"doctype": "DocType",
"document_type": "Other",
@@ -13,6 +14,7 @@
"expense_approver_mandatory_in_expense_claim",
"payroll_settings",
"include_holidays_in_total_working_days",
+ "disable_rounded_total",
"max_working_hours_against_timesheet",
"column_break_11",
"email_salary_slip_to_employee",
@@ -21,10 +23,12 @@
"leave_settings",
"leave_approval_notification_template",
"leave_status_notification_template",
+ "role_allowed_to_create_backdated_leave_application",
"column_break_18",
"leave_approver_mandatory_in_leave_application",
"show_leaves_of_all_department_members_in_calendar",
"auto_leave_encashment",
+ "restrict_backdated_leave_application",
"hiring_settings",
"check_vacancies"
],
@@ -160,12 +164,33 @@
"fieldname": "auto_leave_encashment",
"fieldtype": "Check",
"label": "Auto Leave Encashment"
+ },
+ {
+ "default": "0",
+ "description": "If checked, hides and disables Rounded Total field in Salary Slips",
+ "fieldname": "disable_rounded_total",
+ "fieldtype": "Check",
+ "label": "Disable Rounded Total"
+ },
+ {
+ "default": "0",
+ "fieldname": "restrict_backdated_leave_application",
+ "fieldtype": "Check",
+ "label": "Restrict Backdated Leave Application"
+ },
+ {
+ "depends_on": "eval:doc.restrict_backdated_leave_application == 1",
+ "fieldname": "role_allowed_to_create_backdated_leave_application",
+ "fieldtype": "Link",
+ "label": "Role Allowed to Create Backdated Leave Application",
+ "options": "Role"
}
],
"icon": "fa fa-cog",
"idx": 1,
"issingle": 1,
- "modified": "2019-08-05 13:07:17.993968",
+ "links": [],
+ "modified": "2020-01-06 18:46:30.189815",
"modified_by": "Administrator",
"module": "HR",
"name": "HR Settings",
diff --git a/erpnext/hr/doctype/hr_settings/hr_settings.py b/erpnext/hr/doctype/hr_settings/hr_settings.py
index 2ee1b7b..bf91906 100644
--- a/erpnext/hr/doctype/hr_settings/hr_settings.py
+++ b/erpnext/hr/doctype/hr_settings/hr_settings.py
@@ -7,6 +7,8 @@
import frappe
from frappe import _
from frappe.model.document import Document
+from frappe.utils import cint
+from frappe.custom.doctype.property_setter.property_setter import make_property_setter
class HRSettings(Document):
def validate(self):
@@ -22,3 +24,12 @@
if self.email_salary_slip_to_employee and self.encrypt_salary_slips_in_emails:
if not self.password_policy:
frappe.throw(_("Password policy for Salary Slips is not set"))
+
+ def on_update(self):
+ self.toggle_rounded_total()
+ frappe.clear_cache()
+
+ def toggle_rounded_total(self):
+ self.disable_rounded_total = cint(self.disable_rounded_total)
+ make_property_setter("Salary Slip", "rounded_total", "hidden", self.disable_rounded_total, "Check")
+ make_property_setter("Salary Slip", "rounded_total", "print_hide", self.disable_rounded_total, "Check")
diff --git a/erpnext/hr/doctype/job_offer/job_offer.js b/erpnext/hr/doctype/job_offer/job_offer.js
index c3d83c4..558f495 100755
--- a/erpnext/hr/doctype/job_offer/job_offer.js
+++ b/erpnext/hr/doctype/job_offer/job_offer.js
@@ -10,6 +10,10 @@
});
},
+ setup: function (frm) {
+ frm.email_field = "applicant_email";
+ },
+
select_terms: function (frm) {
erpnext.utils.get_terms(frm.doc.select_terms, frm.doc, function (r) {
if (!r.exc) {
diff --git a/erpnext/hr/doctype/job_offer/job_offer.json b/erpnext/hr/doctype/job_offer/job_offer.json
index 7495c48..ccbfdc5 100644
--- a/erpnext/hr/doctype/job_offer/job_offer.json
+++ b/erpnext/hr/doctype/job_offer/job_offer.json
@@ -1,618 +1,191 @@
{
- "allow_copy": 0,
- "allow_guest_to_view": 0,
- "allow_import": 1,
- "allow_rename": 0,
- "autoname": "HR-OFF-.YYYY.-.#####",
- "beta": 0,
- "creation": "2015-03-04 14:20:17.662207",
- "custom": 0,
- "default_print_format": "",
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "Document",
- "editable_grid": 0,
+ "actions": [],
+ "allow_import": 1,
+ "autoname": "HR-OFF-.YYYY.-.#####",
+ "creation": "2015-03-04 14:20:17.662207",
+ "doctype": "DocType",
+ "document_type": "Document",
+ "engine": "InnoDB",
+ "field_order": [
+ "job_applicant",
+ "applicant_name",
+ "applicant_email",
+ "column_break_3",
+ "status",
+ "offer_date",
+ "designation",
+ "company",
+ "section_break_4",
+ "offer_terms",
+ "section_break_14",
+ "select_terms",
+ "terms",
+ "printing_details",
+ "letter_head",
+ "column_break_16",
+ "select_print_heading",
+ "amended_from"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "job_applicant",
- "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": "Job Applicant",
- "length": 0,
- "no_copy": 0,
- "options": "Job Applicant",
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "job_applicant",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Job Applicant",
+ "options": "Job Applicant",
+ "print_hide": 1,
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_from": "job_applicant.applicant_name",
- "fieldname": "applicant_name",
- "fieldtype": "Data",
- "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": "Applicant Name",
- "length": 0,
- "no_copy": 0,
- "options": "",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fetch_from": "job_applicant.applicant_name",
+ "fieldname": "applicant_name",
+ "fieldtype": "Data",
+ "in_global_search": 1,
+ "in_list_view": 1,
+ "label": "Applicant Name",
+ "read_only": 1,
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_3",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fetch_from": "job_applicant.email_id",
+ "fieldname": "applicant_email",
+ "fieldtype": "Data",
+ "in_global_search": 1,
+ "label": "Applicant Email Address",
+ "options": "Email",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "status",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 1,
- "label": "Status",
- "length": 0,
- "no_copy": 1,
- "options": "Awaiting Response\nAccepted\nRejected",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "column_break_3",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "",
- "fieldname": "offer_date",
- "fieldtype": "Date",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Offer Date",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "allow_on_submit": 1,
+ "fieldname": "status",
+ "fieldtype": "Select",
+ "in_standard_filter": 1,
+ "label": "Status",
+ "no_copy": 1,
+ "options": "Awaiting Response\nAccepted\nRejected",
+ "print_hide": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "designation",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Designation",
- "length": 0,
- "no_copy": 0,
- "options": "Designation",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "offer_date",
+ "fieldtype": "Date",
+ "label": "Offer Date",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "company",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Company",
- "length": 0,
- "no_copy": 0,
- "options": "Company",
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 1,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "designation",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Designation",
+ "options": "Designation",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "section_break_4",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Company",
+ "options": "Company",
+ "print_hide": 1,
+ "remember_last_selected_value": 1,
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "offer_terms",
- "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": "Job Offer Terms",
- "length": 0,
- "no_copy": 0,
- "options": "Job Offer Term",
- "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
- },
+ "fieldname": "section_break_4",
+ "fieldtype": "Section Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "section_break_14",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "offer_terms",
+ "fieldtype": "Table",
+ "label": "Job Offer Terms",
+ "options": "Job Offer Term"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "select_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": "Select Terms and Conditions",
- "length": 0,
- "no_copy": 0,
- "options": "Terms and Conditions",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "section_break_14",
+ "fieldtype": "Section Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "terms",
- "fieldtype": "Text Editor",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Terms and Conditions",
- "length": 0,
- "no_copy": 0,
- "options": "",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "select_terms",
+ "fieldtype": "Link",
+ "label": "Select Terms and Conditions",
+ "options": "Terms and Conditions",
+ "print_hide": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "columns": 0,
- "fieldname": "printing_details",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Printing Details",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "terms",
+ "fieldtype": "Text Editor",
+ "label": "Terms and Conditions"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_from": "company.default_letter_head",
- "fieldname": "letter_head",
- "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": "Letter Head",
- "length": 0,
- "no_copy": 0,
- "options": "Letter Head",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "collapsible": 1,
+ "fieldname": "printing_details",
+ "fieldtype": "Section Break",
+ "label": "Printing Details"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_16",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 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,
- "translatable": 0,
- "unique": 0,
+ "allow_on_submit": 1,
+ "fetch_from": "company.default_letter_head",
+ "fieldname": "letter_head",
+ "fieldtype": "Link",
+ "label": "Letter Head",
+ "options": "Letter Head",
+ "print_hide": 1
+ },
+ {
+ "fieldname": "column_break_16",
+ "fieldtype": "Column Break",
+ "print_hide": 1,
"width": "50%"
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "select_print_heading",
- "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": "Print Heading",
- "length": 0,
- "no_copy": 0,
- "options": "Print Heading",
- "permlevel": 0,
- "precision": "",
- "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
- },
+ "allow_on_submit": 1,
+ "fieldname": "select_print_heading",
+ "fieldtype": "Link",
+ "label": "Print Heading",
+ "options": "Print Heading",
+ "print_hide": 1,
+ "report_hide": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "amended_from",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Amended From",
- "length": 0,
- "no_copy": 1,
- "options": "Job Offer",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "fieldname": "amended_from",
+ "fieldtype": "Link",
+ "label": "Amended From",
+ "no_copy": 1,
+ "options": "Job Offer",
+ "print_hide": 1,
+ "read_only": 1
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 1,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2018-08-21 16:15:35.616910",
- "modified_by": "Administrator",
- "module": "HR",
- "name": "Job Offer",
- "name_case": "",
- "owner": "Administrator",
+ ],
+ "is_submittable": 1,
+ "links": [],
+ "modified": "2019-12-31 02:40:33.650728",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Job Offer",
+ "owner": "Administrator",
"permissions": [
{
- "amend": 1,
- "cancel": 1,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 1,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "HR User",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 1,
+ "amend": 1,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "import": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "HR User",
+ "share": 1,
+ "submit": 1,
"write": 1
}
- ],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 1,
- "sort_field": "modified",
- "sort_order": "DESC",
- "title_field": "applicant_name",
- "track_changes": 0,
- "track_seen": 0,
- "track_views": 0
+ ],
+ "show_name_in_global_search": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "title_field": "applicant_name"
}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/job_offer/job_offer.py b/erpnext/hr/doctype/job_offer/job_offer.py
index ef8004e..32f1b89 100644
--- a/erpnext/hr/doctype/job_offer/job_offer.py
+++ b/erpnext/hr/doctype/job_offer/job_offer.py
@@ -58,7 +58,8 @@
@frappe.whitelist()
def make_employee(source_name, target_doc=None):
def set_missing_values(source, target):
- target.personal_email = frappe.db.get_value("Job Applicant", source.job_applicant, "email_id")
+ target.personal_email, target.first_name = frappe.db.get_value("Job Applicant", \
+ source.job_applicant, ["email_id", "applicant_name"])
doc = get_mapped_doc("Job Offer", source_name, {
"Job Offer": {
"doctype": "Employee",
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.py b/erpnext/hr/doctype/leave_allocation/leave_allocation.py
index 874ae7a..d13bb45 100755
--- a/erpnext/hr/doctype/leave_allocation/leave_allocation.py
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.py
@@ -69,10 +69,14 @@
def validate_allocation_overlap(self):
leave_allocation = frappe.db.sql("""
- select name from `tabLeave Allocation`
- where employee=%s and leave_type=%s and docstatus=1
- and to_date >= %s and from_date <= %s""",
- (self.employee, self.leave_type, self.from_date, self.to_date))
+ SELECT
+ name
+ FROM `tabLeave Allocation`
+ WHERE
+ employee=%s AND leave_type=%s
+ AND name <> %s AND docstatus=1
+ AND to_date >= %s AND from_date <= %s""",
+ (self.employee, self.leave_type, self.name, self.from_date, self.to_date))
if leave_allocation:
frappe.msgprint(_("{0} already allocated for Employee {1} for period {2} to {3}")
diff --git a/erpnext/hr/doctype/leave_application/leave_application.js b/erpnext/hr/doctype/leave_application/leave_application.js
index 1746410..14ffa0e 100755
--- a/erpnext/hr/doctype/leave_application/leave_application.js
+++ b/erpnext/hr/doctype/leave_application/leave_application.js
@@ -60,7 +60,7 @@
}
}
});
- $("div").remove(".form-dashboard-section");
+ $("div").remove(".form-dashboard-section.custom");
frm.dashboard.add_section(
frappe.render_template('leave_application_dashboard', {
data: leave_details
@@ -171,7 +171,7 @@
frm.set_value('to_date', '');
return;
}
- // server call is done to include holidays in leave days calculations
+ // server call is done to include holidays in leave days calculations
return frappe.call({
method: 'erpnext.hr.doctype.leave_application.leave_application.get_number_of_leave_days',
args: {
@@ -194,7 +194,7 @@
set_leave_approver: function(frm) {
if(frm.doc.employee) {
- // server call is done to include holidays in leave days calculations
+ // server call is done to include holidays in leave days calculations
return frappe.call({
method: 'erpnext.hr.doctype.leave_application.leave_application.get_leave_approver',
args: {
diff --git a/erpnext/hr/doctype/leave_application/leave_application.py b/erpnext/hr/doctype/leave_application/leave_application.py
index b73028e..7594cb7 100755
--- a/erpnext/hr/doctype/leave_application/leave_application.py
+++ b/erpnext/hr/doctype/leave_application/leave_application.py
@@ -54,12 +54,14 @@
self.create_leave_ledger_entry()
self.reload()
- def on_cancel(self):
+ def before_cancel(self):
self.status = "Cancelled"
+
+ def on_cancel(self):
+ self.create_leave_ledger_entry(submit=False)
# notify leave applier about cancellation
self.notify_employee()
self.cancel_attendance()
- self.create_leave_ledger_entry(submit=False)
def validate_applicable_after(self):
if self.leave_type:
@@ -77,6 +79,12 @@
frappe.throw(_("{0} applicable after {1} working days").format(self.leave_type, leave_type.applicable_after))
def validate_dates(self):
+ if frappe.db.get_single_value("HR Settings", "restrict_backdated_leave_application"):
+ if self.from_date and self.from_date < frappe.utils.today():
+ allowed_role = frappe.db.get_single_value("HR Settings", "role_allowed_to_create_backdated_leave_application")
+ if allowed_role not in frappe.get_roles():
+ frappe.throw(_("Only users with the {0} role can create backdated leave applications").format(allowed_role))
+
if self.from_date and self.to_date and (getdate(self.to_date) < getdate(self.from_date)):
frappe.throw(_("To date cannot be before from date"))
@@ -125,7 +133,7 @@
status = "Half Day" if date == self.half_day_date else "On Leave"
attendance_name = frappe.db.exists('Attendance', dict(employee = self.employee,
- attenance_date = date, docstatus = ('!=', 2)))
+ attendance_date = date, docstatus = ('!=', 2)))
if attendance_name:
# update existing attendance, change absent to on leave
@@ -351,6 +359,9 @@
pass
def create_leave_ledger_entry(self, submit=True):
+ if self.status != 'Approved' and submit:
+ return
+
expiry_date = get_allocation_expiry(self.employee, self.leave_type,
self.to_date, self.from_date)
@@ -546,10 +557,10 @@
leave_days += leave_entry.leaves
elif inclusive_period and leave_entry.transaction_type == 'Leave Allocation' \
- and not skip_expiry_leaves(leave_entry, to_date):
+ and leave_entry.is_expired and not skip_expiry_leaves(leave_entry, to_date):
leave_days += leave_entry.leaves
- else:
+ elif leave_entry.transaction_type == 'Leave Application':
if leave_entry.from_date < getdate(from_date):
leave_entry.from_date = from_date
if leave_entry.to_date > getdate(to_date):
@@ -576,14 +587,15 @@
def get_leave_entries(employee, leave_type, from_date, to_date):
''' Returns leave entries between from_date and to_date '''
return frappe.db.sql("""
- select employee, leave_type, from_date, to_date, leaves, transaction_type, is_carry_forward, transaction_name
- from `tabLeave Ledger Entry`
- where employee=%(employee)s and leave_type=%(leave_type)s
- and docstatus=1
- and leaves<0
- and (from_date between %(from_date)s and %(to_date)s
- or to_date between %(from_date)s and %(to_date)s
- or (from_date < %(from_date)s and to_date > %(to_date)s))
+ SELECT
+ employee, leave_type, from_date, to_date, leaves, transaction_name, transaction_type,
+ is_carry_forward, is_expired
+ FROM `tabLeave Ledger Entry`
+ WHERE employee=%(employee)s AND leave_type=%(leave_type)s
+ AND docstatus=1 AND leaves<0
+ AND (from_date between %(from_date)s AND %(to_date)s
+ OR to_date between %(from_date)s AND %(to_date)s
+ OR (from_date < %(from_date)s AND to_date > %(to_date)s))
""", {
"from_date": from_date,
"to_date": to_date,
@@ -770,4 +782,4 @@
leave_approver = frappe.db.get_value('Department Approver', {'parent': department,
'parentfield': 'leave_approvers', 'idx': 1}, 'approver')
- return leave_approver
+ return leave_approver
\ No newline at end of file
diff --git a/erpnext/hr/doctype/leave_application/leave_application_dashboard.py b/erpnext/hr/doctype/leave_application/leave_application_dashboard.py
index 8075b7b..c1d6a66 100644
--- a/erpnext/hr/doctype/leave_application/leave_application_dashboard.py
+++ b/erpnext/hr/doctype/leave_application/leave_application_dashboard.py
@@ -5,6 +5,12 @@
def get_data():
return {
+ 'fieldname': 'leave_application',
+ 'transactions': [
+ {
+ 'items': ['Attendance']
+ }
+ ],
'reports': [
{
'label': _('Reports'),
diff --git a/erpnext/hr/doctype/leave_application/test_leave_application.py b/erpnext/hr/doctype/leave_application/test_leave_application.py
index ad141a5..b621642 100644
--- a/erpnext/hr/doctype/leave_application/test_leave_application.py
+++ b/erpnext/hr/doctype/leave_application/test_leave_application.py
@@ -72,7 +72,7 @@
application.to_date = "2013-01-05"
return application
- def test_attendance_creation(self):
+ def test_overwrite_attendance(self):
'''check attendance is automatically created on leave approval'''
make_allocation_record()
application = self.get_application(_test_records[0])
@@ -82,7 +82,8 @@
application.insert()
application.submit()
- attendance = frappe.get_all('Attendance', ['name', 'status', 'attendance_date'], dict(leave_application = application.name))
+ attendance = frappe.get_all('Attendance', ['name', 'status', 'attendance_date'],
+ dict(attendance_date=('between', ['2018-01-01', '2018-01-03']), docstatus=("!=", 2)))
# attendance created for all 3 days
self.assertEqual(len(attendance), 3)
@@ -95,20 +96,6 @@
for d in ('2018-01-01', '2018-01-02', '2018-01-03'):
self.assertTrue(getdate(d) in dates)
- def test_overwrite_attendance(self):
- # employee marked as absent
- doc = frappe.new_doc("Attendance")
- doc.employee = '_T-Employee-00001'
- doc.attendance_date = '2018-01-01'
- doc.company = '_Test Company'
- doc.status = 'Absent'
- doc.flags.ignore_validate = True
- doc.insert(ignore_permissions=True)
- doc.submit()
-
- # now check if the status has been updated
- self.test_attendance_creation()
-
def test_block_list(self):
self._clear_roles()
@@ -248,8 +235,8 @@
frappe.get_doc(dict(
doctype = 'Holiday List',
holiday_list_name = holiday_list,
- from_date = date(date.today().year, 1, 1),
- to_date = date(date.today().year, 12, 31),
+ from_date = add_months(today, -6),
+ to_date = add_months(today, 6),
holidays = [
dict(holiday_date = today, description = 'Test')
]
@@ -314,7 +301,7 @@
to_date = add_days(date, 2),
company = "_Test Company",
docstatus = 1,
- status = "Approved"
+ status = "Approved"
))
leave_application.submit()
@@ -327,7 +314,7 @@
to_date = add_days(date, 8),
company = "_Test Company",
docstatus = 1,
- status = "Approved"
+ status = "Approved"
))
self.assertRaises(frappe.ValidationError, leave_application.insert)
@@ -610,8 +597,8 @@
return frappe.get_doc(dict(
name = 'Test Leave Period',
doctype = 'Leave Period',
- from_date = "{0}-12-01".format(now_datetime().year - 1),
- to_date = "{0}-12-31".format(now_datetime().year),
+ from_date = add_months(nowdate(), -6),
+ to_date = add_months(nowdate(), 6),
company = "_Test Company",
is_active = 1
)).insert()
diff --git a/erpnext/hr/doctype/leave_control_panel/leave_control_panel.json b/erpnext/hr/doctype/leave_control_panel/leave_control_panel.json
index 39985fa..d9c592a 100644
--- a/erpnext/hr/doctype/leave_control_panel/leave_control_panel.json
+++ b/erpnext/hr/doctype/leave_control_panel/leave_control_panel.json
@@ -1,25 +1,28 @@
{
+ "actions": [],
"allow_copy": 1,
"creation": "2013-01-10 16:34:15",
"doctype": "DocType",
+ "engine": "InnoDB",
"field_order": [
"select_employees_section",
"company",
"employment_type",
"branch",
- "column_break1",
"department",
+ "column_break1",
"designation",
"employee_grade",
"employee",
"allocate_leaves_section",
"from_date",
"to_date",
- "leave_policy",
- "leave_type",
"carry_forward",
"no_of_days",
- "allocate"
+ "allocate",
+ "column_break_16",
+ "leave_policy",
+ "leave_type"
],
"fields": [
{
@@ -125,13 +128,18 @@
"fieldname": "allocate_leaves_section",
"fieldtype": "Section Break",
"label": "Allocate Leaves"
+ },
+ {
+ "fieldname": "column_break_16",
+ "fieldtype": "Column Break"
}
],
"hide_toolbar": 1,
"icon": "fa fa-cog",
"idx": 1,
"issingle": 1,
- "modified": "2019-05-24 09:41:34.105741",
+ "links": [],
+ "modified": "2019-12-12 18:51:41.573349",
"modified_by": "Administrator",
"module": "HR",
"name": "Leave Control Panel",
diff --git a/erpnext/hr/doctype/leave_encashment/leave_encashment.json b/erpnext/hr/doctype/leave_encashment/leave_encashment.json
index 29f634e..2cf6ccf 100644
--- a/erpnext/hr/doctype/leave_encashment/leave_encashment.json
+++ b/erpnext/hr/doctype/leave_encashment/leave_encashment.json
@@ -1,577 +1,198 @@
{
- "allow_copy": 0,
- "allow_guest_to_view": 0,
- "allow_import": 1,
- "allow_rename": 1,
- "autoname": "HR-ENC-.YYYY.-.#####",
- "beta": 0,
- "creation": "2018-04-13 15:31:51.197046",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "",
- "editable_grid": 1,
- "engine": "InnoDB",
+ "actions": [],
+ "allow_import": 1,
+ "allow_rename": 1,
+ "autoname": "HR-ENC-.YYYY.-.#####",
+ "creation": "2018-04-13 15:31:51.197046",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "leave_period",
+ "employee",
+ "employee_name",
+ "department",
+ "column_break_4",
+ "leave_type",
+ "leave_allocation",
+ "leave_balance",
+ "encashable_days",
+ "amended_from",
+ "payroll",
+ "encashment_amount",
+ "encashment_date",
+ "additional_salary"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "leave_period",
- "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": "Leave Period",
- "length": 0,
- "no_copy": 0,
- "options": "Leave Period",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "leave_period",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Leave Period",
+ "options": "Leave Period",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "employee",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Employee",
- "length": 0,
- "no_copy": 0,
- "options": "Employee",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "employee",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Employee",
+ "options": "Employee",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_from": "employee.employee_name",
- "fieldname": "employee_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": "Employee Name",
- "length": 0,
- "no_copy": 0,
- "options": "",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fetch_from": "employee.employee_name",
+ "fieldname": "employee_name",
+ "fieldtype": "Data",
+ "label": "Employee Name",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_from": "employee.department",
- "fieldname": "department",
- "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": "Department",
- "length": 0,
- "no_copy": 0,
- "options": "Department",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fetch_from": "employee.department",
+ "fieldname": "department",
+ "fieldtype": "Link",
+ "label": "Department",
+ "options": "Department",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "leave_type",
- "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": "Leave Type",
- "length": 0,
- "no_copy": 0,
- "options": "Leave Type",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "leave_type",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Leave Type",
+ "options": "Leave Type",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_4",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "column_break_4",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "leave_allocation",
- "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": "Leave Allocation",
- "length": 0,
- "no_copy": 1,
- "options": "Leave Allocation",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "leave_allocation",
+ "fieldtype": "Link",
+ "label": "Leave Allocation",
+ "no_copy": 1,
+ "options": "Leave Allocation",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "leave_balance",
- "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": "Leave Balance",
- "length": 0,
- "no_copy": 1,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "leave_balance",
+ "fieldtype": "Float",
+ "label": "Leave Balance",
+ "no_copy": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "encashable_days",
- "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": "Encashable days",
- "length": 0,
- "no_copy": 1,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "encashable_days",
+ "fieldtype": "Float",
+ "label": "Encashable days",
+ "no_copy": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "amended_from",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Amended From",
- "length": 0,
- "no_copy": 1,
- "options": "Leave Encashment",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "amended_from",
+ "fieldtype": "Link",
+ "label": "Amended From",
+ "no_copy": 1,
+ "options": "Leave Encashment",
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "payroll",
- "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": "Payroll",
- "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
- },
+ "fieldname": "payroll",
+ "fieldtype": "Section Break",
+ "label": "Payroll"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "encashment_amount",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Encashment Amount",
- "length": 0,
- "no_copy": 1,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "encashment_amount",
+ "fieldtype": "Currency",
+ "in_list_view": 1,
+ "label": "Encashment Amount",
+ "no_copy": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "Today",
- "fieldname": "encashment_date",
- "fieldtype": "Date",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Encashment Date",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "default": "Today",
+ "fieldname": "encashment_date",
+ "fieldtype": "Date",
+ "label": "Encashment Date"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "additional_salary",
- "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": "Additional Salary",
- "length": 0,
- "no_copy": 1,
- "options": "Additional Salary",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "fieldname": "additional_salary",
+ "fieldtype": "Link",
+ "label": "Additional Salary",
+ "no_copy": 1,
+ "options": "Additional Salary",
+ "read_only": 1
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 1,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2018-08-21 16:15:43.829272",
- "modified_by": "Administrator",
- "module": "HR",
- "name": "Leave Encashment",
- "name_case": "",
- "owner": "Administrator",
+ ],
+ "is_submittable": 1,
+ "links": [],
+ "modified": "2019-12-16 11:51:57.732223",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Leave Encashment",
+ "owner": "Administrator",
"permissions": [
{
- "amend": 1,
- "cancel": 1,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "System Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 1,
+ "amend": 1,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "System Manager",
+ "share": 1,
+ "submit": 1,
"write": 1
- },
+ },
{
- "amend": 1,
- "cancel": 1,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "HR Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 1,
+ "amend": 1,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "HR Manager",
+ "share": 1,
+ "submit": 1,
"write": 1
- },
+ },
{
- "amend": 1,
- "cancel": 1,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "HR User",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 1,
+ "amend": 1,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "HR User",
+ "share": 1,
+ "submit": 1,
"write": 1
- },
+ },
{
- "amend": 0,
- "cancel": 0,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Employee",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Employee",
+ "share": 1,
"write": 1
}
- ],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1,
- "track_seen": 0,
- "track_views": 0
+ ],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/leave_period/test_leave_period.py b/erpnext/hr/doctype/leave_period/test_leave_period.py
index 850a08d..1762cf9 100644
--- a/erpnext/hr/doctype/leave_period/test_leave_period.py
+++ b/erpnext/hr/doctype/leave_period/test_leave_period.py
@@ -43,10 +43,18 @@
leave_period.grant_leave_allocation(employee=employee_doc_name)
self.assertEqual(get_leave_balance_on(employee_doc_name, leave_type, today()), 20)
-def create_leave_period(from_date, to_date):
+def create_leave_period(from_date, to_date, company=None):
+ leave_period = frappe.db.get_value('Leave Period',
+ dict(company=company or erpnext.get_default_company(),
+ from_date=from_date,
+ to_date=to_date,
+ is_active=1), 'name')
+ if leave_period:
+ return frappe.get_doc("Leave Period", leave_period)
+
leave_period = frappe.get_doc({
"doctype": "Leave Period",
- "company": erpnext.get_default_company(),
+ "company": company or erpnext.get_default_company(),
"from_date": from_date,
"to_date": to_date,
"is_active": 1
diff --git a/erpnext/hr/doctype/leave_type/leave_type.json b/erpnext/hr/doctype/leave_type/leave_type.json
index 550d536..0af832f 100644
--- a/erpnext/hr/doctype/leave_type/leave_type.json
+++ b/erpnext/hr/doctype/leave_type/leave_type.json
@@ -1,4 +1,5 @@
{
+ "actions": [],
"allow_import": 1,
"allow_rename": 1,
"autoname": "field:leave_type_name",
@@ -24,10 +25,12 @@
"encashment",
"allow_encashment",
"encashment_threshold_days",
+ "column_break_17",
"earning_component",
"earned_leave",
"is_earned_leave",
"earned_leave_frequency",
+ "column_break_22",
"rounding"
],
"fields": [
@@ -172,11 +175,20 @@
"fieldname": "maximum_carry_forwarded_leaves",
"fieldtype": "Float",
"label": "Maximum Carry Forwarded Leaves"
+ },
+ {
+ "fieldname": "column_break_17",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "column_break_22",
+ "fieldtype": "Column Break"
}
],
"icon": "fa fa-flag",
"idx": 1,
- "modified": "2019-09-06 18:48:48.946074",
+ "links": [],
+ "modified": "2019-12-12 12:48:37.780254",
"modified_by": "Administrator",
"module": "HR",
"name": "Leave Type",
diff --git a/erpnext/hr/doctype/loan/loan.json b/erpnext/hr/doctype/loan/loan.json
index 505b601..2b2d481 100644
--- a/erpnext/hr/doctype/loan/loan.json
+++ b/erpnext/hr/doctype/loan/loan.json
@@ -1,1200 +1,298 @@
{
- "allow_copy": 0,
- "allow_events_in_timeline": 0,
- "allow_guest_to_view": 0,
- "allow_import": 1,
- "allow_rename": 0,
- "autoname": "ACC-LOAN-.YYYY.-.#####",
- "beta": 0,
- "creation": "2016-12-02 10:11:49.673604",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "Document",
- "editable_grid": 1,
- "engine": "InnoDB",
+ "actions": [],
+ "allow_import": 1,
+ "autoname": "ACC-LOAN-.YYYY.-.#####",
+ "creation": "2016-12-02 10:11:49.673604",
+ "doctype": "DocType",
+ "document_type": "Document",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "applicant_type",
+ "applicant",
+ "applicant_name",
+ "loan_type",
+ "loan_application",
+ "column_break_3",
+ "posting_date",
+ "company",
+ "status",
+ "repay_from_salary",
+ "section_break_8",
+ "loan_amount",
+ "rate_of_interest",
+ "disbursement_date",
+ "repayment_start_date",
+ "column_break_11",
+ "repayment_method",
+ "repayment_periods",
+ "monthly_repayment_amount",
+ "account_info",
+ "mode_of_payment",
+ "payment_account",
+ "column_break_9",
+ "loan_account",
+ "interest_income_account",
+ "section_break_15",
+ "repayment_schedule",
+ "section_break_17",
+ "total_payment",
+ "column_break_19",
+ "total_interest_payable",
+ "total_amount_paid",
+ "amended_from"
+ ],
"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": "applicant_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": 0,
- "label": "Applicant Type",
- "length": 0,
- "no_copy": 0,
- "options": "Employee\nMember",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "applicant_type",
+ "fieldtype": "Select",
+ "label": "Applicant Type",
+ "options": "Employee\nMember",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "applicant",
- "fieldtype": "Dynamic 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": 1,
- "label": "Applicant",
- "length": 0,
- "no_copy": 0,
- "options": "applicant_type",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "applicant",
+ "fieldtype": "Dynamic Link",
+ "in_standard_filter": 1,
+ "label": "Applicant",
+ "options": "applicant_type",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "applicant_name",
- "fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 1,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Applicant Name",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "applicant_name",
+ "fieldtype": "Data",
+ "in_global_search": 1,
+ "label": "Applicant Name",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "loan_application",
- "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": "Loan Application",
- "length": 0,
- "no_copy": 0,
- "options": "Loan Application",
- "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
- },
+ "fieldname": "loan_application",
+ "fieldtype": "Link",
+ "label": "Loan Application",
+ "options": "Loan Application"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "loan_type",
- "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": "Loan Type",
- "length": 0,
- "no_copy": 0,
- "options": "Loan Type",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "loan_type",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Loan Type",
+ "options": "Loan Type",
+ "reqd": 1
+ },
{
- "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
- },
+ "fieldname": "column_break_3",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "Today",
- "fetch_if_empty": 0,
- "fieldname": "posting_date",
- "fieldtype": "Date",
- "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": "Posting Date",
- "length": 0,
- "no_copy": 1,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "default": "Today",
+ "fieldname": "posting_date",
+ "fieldtype": "Date",
+ "in_list_view": 1,
+ "label": "Posting Date",
+ "no_copy": 1,
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "company",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Company",
- "length": 0,
- "no_copy": 0,
- "options": "Company",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 1,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "label": "Company",
+ "options": "Company",
+ "remember_last_selected_value": 1,
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "Sanctioned",
- "fetch_if_empty": 0,
- "fieldname": "status",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Status",
- "length": 0,
- "no_copy": 1,
- "options": "Sanctioned\nDisbursed\nRepaid/Closed",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "default": "Sanctioned",
+ "fieldname": "status",
+ "fieldtype": "Select",
+ "label": "Status",
+ "no_copy": 1,
+ "options": "Sanctioned\nDisbursed\nRepaid/Closed",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:doc.applicant_type==\"Employee\"",
- "fetch_if_empty": 0,
- "fieldname": "repay_from_salary",
- "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": "Repay from Salary",
- "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
- },
+ "default": "0",
+ "depends_on": "eval:doc.applicant_type==\"Employee\"",
+ "fieldname": "repay_from_salary",
+ "fieldtype": "Check",
+ "label": "Repay from Salary"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "section_break_8",
- "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": "Loan Details",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "section_break_8",
+ "fieldtype": "Section Break",
+ "label": "Loan Details"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "loan_amount",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Loan Amount",
- "length": 0,
- "no_copy": 0,
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "loan_amount",
+ "fieldtype": "Currency",
+ "label": "Loan Amount",
+ "options": "Company:company:default_currency",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "",
- "fetch_from": "loan_type.rate_of_interest",
- "fetch_if_empty": 0,
- "fieldname": "rate_of_interest",
- "fieldtype": "Percent",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Rate of Interest (%) / Year",
- "length": 0,
- "no_copy": 0,
- "options": "",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fetch_from": "loan_type.rate_of_interest",
+ "fieldname": "rate_of_interest",
+ "fieldtype": "Percent",
+ "label": "Rate of Interest (%) / Year",
+ "read_only": 1,
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:doc.status==\"Disbursed\"",
- "fetch_if_empty": 0,
- "fieldname": "disbursement_date",
- "fieldtype": "Date",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Disbursement Date",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "depends_on": "eval:doc.status==\"Disbursed\"",
+ "fieldname": "disbursement_date",
+ "fieldtype": "Date",
+ "label": "Disbursement Date"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "repayment_start_date",
- "fieldtype": "Date",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Repayment Start Date",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "repayment_start_date",
+ "fieldtype": "Date",
+ "label": "Repayment Start Date",
+ "reqd": 1
+ },
{
- "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_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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "column_break_11",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "Repay Over Number of Periods",
- "fetch_if_empty": 0,
- "fieldname": "repayment_method",
- "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": "Repayment Method",
- "length": 0,
- "no_copy": 0,
- "options": "\nRepay Fixed Amount per Period\nRepay Over Number of Periods",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "default": "Repay Over Number of Periods",
+ "fieldname": "repayment_method",
+ "fieldtype": "Select",
+ "label": "Repayment Method",
+ "options": "\nRepay Fixed Amount per Period\nRepay Over Number of Periods",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "",
- "depends_on": "",
- "fetch_if_empty": 0,
- "fieldname": "repayment_periods",
- "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": "Repayment Period in Months",
- "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
- },
+ "fieldname": "repayment_periods",
+ "fieldtype": "Int",
+ "label": "Repayment Period in Months"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "",
- "depends_on": "",
- "fetch_if_empty": 0,
- "fieldname": "monthly_repayment_amount",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Monthly Repayment Amount",
- "length": 0,
- "no_copy": 0,
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "monthly_repayment_amount",
+ "fieldtype": "Currency",
+ "label": "Monthly Repayment Amount",
+ "options": "Company:company:default_currency"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "account_info",
- "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": "Account Info",
- "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
- },
+ "collapsible": 1,
+ "fieldname": "account_info",
+ "fieldtype": "Section Break",
+ "label": "Account Info"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "mode_of_payment",
- "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": "Mode of Payment",
- "length": 0,
- "no_copy": 0,
- "options": "Mode of Payment",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "mode_of_payment",
+ "fieldtype": "Link",
+ "label": "Mode of Payment",
+ "options": "Mode of Payment",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "payment_account",
- "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": "Payment Account",
- "length": 0,
- "no_copy": 0,
- "options": "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": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "payment_account",
+ "fieldtype": "Link",
+ "label": "Payment Account",
+ "options": "Account",
+ "reqd": 1
+ },
{
- "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_9",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "column_break_9",
+ "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,
- "fieldname": "loan_account",
- "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": "Loan Account",
- "length": 0,
- "no_copy": 0,
- "options": "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": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "loan_account",
+ "fieldtype": "Link",
+ "label": "Loan Account",
+ "options": "Account",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "interest_income_account",
- "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": "Interest Income Account",
- "length": 0,
- "no_copy": 0,
- "options": "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": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "interest_income_account",
+ "fieldtype": "Link",
+ "label": "Interest Income Account",
+ "options": "Account",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "section_break_15",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Repayment Schedule",
- "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
- },
+ "fieldname": "section_break_15",
+ "fieldtype": "Section Break",
+ "label": "Repayment Schedule"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "repayment_schedule",
- "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": "Repayment Schedule",
- "length": 0,
- "no_copy": 1,
- "options": "Repayment Schedule",
- "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
- },
+ "fieldname": "repayment_schedule",
+ "fieldtype": "Table",
+ "label": "Repayment Schedule",
+ "no_copy": 1,
+ "options": "Repayment Schedule"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "section_break_17",
- "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": "Totals",
- "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
- },
+ "fieldname": "section_break_17",
+ "fieldtype": "Section Break",
+ "label": "Totals"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "0",
- "fetch_if_empty": 0,
- "fieldname": "total_payment",
- "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": "Total Payment",
- "length": 0,
- "no_copy": 0,
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "default": "0",
+ "fieldname": "total_payment",
+ "fieldtype": "Currency",
+ "label": "Total Payment",
+ "options": "Company:company:default_currency",
+ "read_only": 1
+ },
{
- "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_19",
- "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
- },
+ "fieldname": "column_break_19",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "0",
- "fetch_if_empty": 0,
- "fieldname": "total_interest_payable",
- "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": "Total Interest Payable",
- "length": 0,
- "no_copy": 0,
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "default": "0",
+ "fieldname": "total_interest_payable",
+ "fieldtype": "Currency",
+ "label": "Total Interest Payable",
+ "options": "Company:company:default_currency",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "total_amount_paid",
- "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": "Total Amount Paid",
- "length": 0,
- "no_copy": 0,
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "allow_on_submit": 1,
+ "fieldname": "total_amount_paid",
+ "fieldtype": "Currency",
+ "label": "Total Amount Paid",
+ "options": "Company:company:default_currency",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "amended_from",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Amended From",
- "length": 0,
- "no_copy": 1,
- "options": "Loan",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "fieldname": "amended_from",
+ "fieldtype": "Link",
+ "label": "Amended From",
+ "no_copy": 1,
+ "options": "Loan",
+ "print_hide": 1,
+ "read_only": 1
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 1,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2019-07-10 13:04:20.953694",
- "modified_by": "Administrator",
- "module": "HR",
- "name": "Loan",
- "name_case": "",
- "owner": "Administrator",
+ ],
+ "is_submittable": 1,
+ "links": [],
+ "modified": "2019-12-12 14:45:38.823072",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Loan",
+ "owner": "Administrator",
"permissions": [
{
- "amend": 0,
- "cancel": 1,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "HR Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 1,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "HR Manager",
+ "share": 1,
+ "submit": 1,
"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
+ "read": 1,
+ "role": "Employee"
}
- ],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "search_fields": "posting_date",
- "show_name_in_global_search": 0,
- "sort_field": "creation",
- "sort_order": "DESC",
- "track_changes": 1,
- "track_seen": 0,
- "track_views": 0
+ ],
+ "search_fields": "posting_date",
+ "sort_field": "creation",
+ "sort_order": "DESC",
+ "track_changes": 1
}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/payroll_entry/payroll_entry.js b/erpnext/hr/doctype/payroll_entry/payroll_entry.js
index adc0671..d25eb6d 100644
--- a/erpnext/hr/doctype/payroll_entry/payroll_entry.js
+++ b/erpnext/hr/doctype/payroll_entry/payroll_entry.js
@@ -31,7 +31,11 @@
}
if ((frm.doc.employees || []).length) {
frm.page.set_primary_action(__('Create Salary Slips'), () => {
- frm.save('Submit');
+ frm.save('Submit').then(()=>{
+ frm.page.clear_primary_action();
+ frm.refresh();
+ frm.events.refresh(frm);
+ });
});
}
}
diff --git a/erpnext/hr/doctype/payroll_entry/payroll_entry.py b/erpnext/hr/doctype/payroll_entry/payroll_entry.py
index 2de01e6..dfd38eb 100644
--- a/erpnext/hr/doctype/payroll_entry/payroll_entry.py
+++ b/erpnext/hr/doctype/payroll_entry/payroll_entry.py
@@ -163,7 +163,7 @@
"""
cond = self.get_filter_condition()
return frappe.db.sql(""" select eld.loan_account, eld.loan,
- eld.interest_income_account, eld.principal_amount, eld.interest_amount, eld.total_payment
+ eld.interest_income_account, eld.principal_amount, eld.interest_amount, eld.total_payment,t1.employee
from
`tabSalary Slip` t1, `tabSalary Slip Loan` eld
where
@@ -246,6 +246,7 @@
accounts.append({
"account": acc,
"debit_in_account_currency": flt(amount, precision),
+ "party_type": '',
"cost_center": self.cost_center,
"project": self.project
})
@@ -257,6 +258,7 @@
"account": acc,
"credit_in_account_currency": flt(amount, precision),
"cost_center": self.cost_center,
+ "party_type": '',
"project": self.project
})
@@ -264,7 +266,9 @@
for data in loan_details:
accounts.append({
"account": data.loan_account,
- "credit_in_account_currency": data.principal_amount
+ "credit_in_account_currency": data.principal_amount,
+ "party_type": "Employee",
+ "party": data.employee
})
if data.interest_amount and not data.interest_income_account:
@@ -275,14 +279,17 @@
"account": data.interest_income_account,
"credit_in_account_currency": data.interest_amount,
"cost_center": self.cost_center,
- "project": self.project
+ "project": self.project,
+ "party_type": "Employee",
+ "party": data.employee
})
payable_amount -= flt(data.total_payment, precision)
# Payable amount
accounts.append({
"account": default_payroll_payable_account,
- "credit_in_account_currency": flt(payable_amount, precision)
+ "credit_in_account_currency": flt(payable_amount, precision),
+ "party_type": '',
})
journal_entry.set("accounts", accounts)
@@ -546,7 +553,6 @@
count += 1
if publish_progress:
frappe.publish_progress(count*100/len(salary_slips), title = _("Submitting Salary Slips..."))
-
if submitted_ss:
payroll_entry.make_accrual_jv_entry()
frappe.msgprint(_("Salary Slip submitted for period from {0} to {1}")
diff --git a/erpnext/hr/doctype/repayment_schedule/repayment_schedule.json b/erpnext/hr/doctype/repayment_schedule/repayment_schedule.json
index a116185..5bb2d37 100644
--- a/erpnext/hr/doctype/repayment_schedule/repayment_schedule.json
+++ b/erpnext/hr/doctype/repayment_schedule/repayment_schedule.json
@@ -1,231 +1,82 @@
{
- "allow_copy": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "beta": 0,
- "creation": "2016-12-20 15:32:25.078334",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "",
- "editable_grid": 1,
- "engine": "InnoDB",
+ "creation": "2016-12-20 15:32:25.078334",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "payment_date",
+ "principal_amount",
+ "interest_amount",
+ "total_payment",
+ "balance_loan_amount",
+ "paid"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 2,
- "fieldname": "payment_date",
- "fieldtype": "Date",
- "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": "Payment Date",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "allow_on_submit": 1,
+ "columns": 2,
+ "fieldname": "payment_date",
+ "fieldtype": "Date",
+ "in_list_view": 1,
+ "label": "Payment Date"
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 2,
- "fieldname": "principal_amount",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Principal Amount",
- "length": 0,
- "no_copy": 1,
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "columns": 2,
+ "fieldname": "principal_amount",
+ "fieldtype": "Currency",
+ "in_list_view": 1,
+ "label": "Principal Amount",
+ "no_copy": 1,
+ "options": "Company:company:default_currency",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 2,
- "fieldname": "interest_amount",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Interest Amount",
- "length": 0,
- "no_copy": 1,
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "columns": 2,
+ "fieldname": "interest_amount",
+ "fieldtype": "Currency",
+ "in_list_view": 1,
+ "label": "Interest Amount",
+ "no_copy": 1,
+ "options": "Company:company:default_currency",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 2,
- "fieldname": "total_payment",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Total Payment",
- "length": 0,
- "no_copy": 0,
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "columns": 2,
+ "fieldname": "total_payment",
+ "fieldtype": "Currency",
+ "in_list_view": 1,
+ "label": "Total Payment",
+ "options": "Company:company:default_currency",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 2,
- "fieldname": "balance_loan_amount",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Balance Loan Amount",
- "length": 0,
- "no_copy": 1,
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "columns": 2,
+ "fieldname": "balance_loan_amount",
+ "fieldtype": "Currency",
+ "in_list_view": 1,
+ "label": "Balance Loan Amount",
+ "no_copy": 1,
+ "options": "Company:company:default_currency",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "paid",
- "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": "Paid",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "default": "0",
+ "fieldname": "paid",
+ "fieldtype": "Check",
+ "in_list_view": 1,
+ "label": "Paid",
+ "read_only": 1
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 1,
- "max_attachments": 0,
- "modified": "2018-03-30 17:37:31.834792",
- "modified_by": "Administrator",
- "module": "HR",
- "name": "Repayment Schedule",
- "name_case": "",
- "owner": "Administrator",
- "permissions": [],
- "quick_entry": 1,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1,
- "track_seen": 0
+ ],
+ "istable": 1,
+ "modified": "2019-10-29 11:45:10.694557",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Repayment Schedule",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/salary_detail/salary_detail.json b/erpnext/hr/doctype/salary_detail/salary_detail.json
index edf2786..bde735d 100644
--- a/erpnext/hr/doctype/salary_detail/salary_detail.json
+++ b/erpnext/hr/doctype/salary_detail/salary_detail.json
@@ -1,765 +1,203 @@
{
- "allow_copy": 0,
- "allow_events_in_timeline": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "beta": 0,
- "creation": "2016-06-30 15:32:36.385111",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "",
- "editable_grid": 1,
+ "actions": [],
+ "creation": "2016-06-30 15:32:36.385111",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "salary_component",
+ "abbr",
+ "statistical_component",
+ "column_break_3",
+ "deduct_full_tax_on_selected_payroll_date",
+ "depends_on_payment_days",
+ "is_tax_applicable",
+ "is_flexible_benefit",
+ "variable_based_on_taxable_salary",
+ "section_break_2",
+ "condition",
+ "amount_based_on_formula",
+ "formula",
+ "amount",
+ "do_not_include_in_total",
+ "default_amount",
+ "additional_amount",
+ "tax_on_flexible_benefit",
+ "tax_on_additional_salary",
+ "section_break_11",
+ "condition_and_formula_help"
+ ],
"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": "salary_component",
- "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": "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": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "salary_component",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Component",
+ "options": "Salary Component",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 1,
- "default": "",
- "depends_on": "eval:doc.parenttype=='Salary Structure'",
- "fetch_from": "salary_component.salary_component_abbr",
- "fetch_if_empty": 0,
- "fieldname": "abbr",
- "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": "Abbr",
- "length": 0,
- "no_copy": 0,
- "options": "",
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "columns": 1,
+ "depends_on": "eval:doc.parenttype=='Salary Structure'",
+ "fetch_from": "salary_component.salary_component_abbr",
+ "fieldname": "abbr",
+ "fieldtype": "Data",
+ "in_list_view": 1,
+ "label": "Abbr",
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "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
- },
+ "fieldname": "column_break_3",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "If selected, the value specified or calculated in this component will not contribute to the earnings or deductions. However, it's value can be referenced by other components that can be added or deducted. ",
- "fetch_from": "salary_component.statistical_component",
- "fetch_if_empty": 0,
- "fieldname": "statistical_component",
- "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": "Statistical Component",
- "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
- },
+ "default": "0",
+ "description": "If selected, the value specified or calculated in this component will not contribute to the earnings or deductions. However, it's value can be referenced by other components that can be added or deducted. ",
+ "fetch_from": "salary_component.statistical_component",
+ "fieldname": "statistical_component",
+ "fieldtype": "Check",
+ "in_list_view": 1,
+ "label": "Statistical Component"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_from": "salary_component.is_tax_applicable",
- "fetch_if_empty": 0,
- "fieldname": "is_tax_applicable",
- "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 Tax Applicable",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "default": "0",
+ "fetch_from": "salary_component.is_tax_applicable",
+ "fieldname": "is_tax_applicable",
+ "fieldtype": "Check",
+ "label": "Is Tax Applicable",
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_from": "salary_component.is_flexible_benefit",
- "fetch_if_empty": 0,
- "fieldname": "is_flexible_benefit",
- "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 Flexible Benefit",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "default": "0",
+ "fetch_from": "salary_component.is_flexible_benefit",
+ "fieldname": "is_flexible_benefit",
+ "fieldtype": "Check",
+ "label": "Is Flexible Benefit",
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "",
- "fetch_from": "salary_component.variable_based_on_taxable_salary",
- "fetch_if_empty": 0,
- "fieldname": "variable_based_on_taxable_salary",
- "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": "Variable Based On Taxable Salary",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "default": "0",
+ "fetch_from": "salary_component.variable_based_on_taxable_salary",
+ "fieldname": "variable_based_on_taxable_salary",
+ "fieldtype": "Check",
+ "label": "Variable Based On Taxable Salary",
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
- "fetch_from": "salary_component.depends_on_payment_days",
- "fetch_if_empty": 0,
- "fieldname": "depends_on_payment_days",
- "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": "Depends on Payment Days",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "default": "0",
+ "fetch_from": "salary_component.depends_on_payment_days",
+ "fieldname": "depends_on_payment_days",
+ "fieldtype": "Check",
+ "label": "Depends on Payment Days",
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "deduct_full_tax_on_selected_payroll_date",
- "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": "Deduct Full Tax on Selected Payroll Date",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "default": "0",
+ "fieldname": "deduct_full_tax_on_selected_payroll_date",
+ "fieldtype": "Check",
+ "label": "Deduct Full Tax on Selected Payroll Date",
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:doc.is_flexible_benefit != 1",
- "fetch_if_empty": 0,
- "fieldname": "section_break_2",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "depends_on": "eval:doc.is_flexible_benefit != 1",
+ "fieldname": "section_break_2",
+ "fieldtype": "Section Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:doc.parenttype=='Salary Structure'",
- "fetch_if_empty": 0,
- "fieldname": "condition",
- "fieldtype": "Code",
- "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": "Condition",
- "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
- },
+ "allow_on_submit": 1,
+ "depends_on": "eval:doc.parenttype=='Salary Structure'",
+ "fieldname": "condition",
+ "fieldtype": "Code",
+ "label": "Condition"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "0",
- "depends_on": "eval:doc.parenttype=='Salary Structure'",
- "fetch_from": "",
- "fetch_if_empty": 0,
- "fieldname": "amount_based_on_formula",
- "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": "Amount based on formula",
- "length": 0,
- "no_copy": 0,
- "options": "",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "default": "0",
+ "depends_on": "eval:doc.parenttype=='Salary Structure'",
+ "fieldname": "amount_based_on_formula",
+ "fieldtype": "Check",
+ "label": "Amount based on formula"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "",
- "depends_on": "eval:doc.amount_based_on_formula!==0 && doc.parenttype==='Salary Structure'",
- "description": "",
- "fetch_if_empty": 0,
- "fieldname": "formula",
- "fieldtype": "Code",
- "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": "Formula",
- "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
- },
+ "allow_on_submit": 1,
+ "depends_on": "eval:doc.amount_based_on_formula!==0 && doc.parenttype==='Salary Structure'",
+ "fieldname": "formula",
+ "fieldtype": "Code",
+ "in_list_view": 1,
+ "label": "Formula"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:doc.amount_based_on_formula!==1 || doc.parenttype==='Salary Slip'",
- "fetch_if_empty": 0,
- "fieldname": "amount",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Amount",
- "length": 0,
- "no_copy": 0,
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "depends_on": "eval:doc.amount_based_on_formula!==1 || doc.parenttype==='Salary Slip'",
+ "fieldname": "amount",
+ "fieldtype": "Currency",
+ "in_list_view": 1,
+ "label": "Amount",
+ "options": "Company:company:default_currency"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "do_not_include_in_total",
- "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": "Do not include in total",
- "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
- },
+ "default": "0",
+ "fieldname": "do_not_include_in_total",
+ "fieldtype": "Check",
+ "label": "Do not include in total"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:doc.parenttype=='Salary Structure'",
- "fetch_if_empty": 0,
- "fieldname": "default_amount",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Default Amount",
- "length": 0,
- "no_copy": 0,
- "options": "Company:company:default_currency",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "depends_on": "eval:doc.parenttype=='Salary Structure'",
+ "fieldname": "default_amount",
+ "fieldtype": "Currency",
+ "label": "Default Amount",
+ "options": "Company:company:default_currency",
+ "print_hide": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "",
- "fetch_from": "",
- "fetch_if_empty": 0,
- "fieldname": "additional_amount",
- "fieldtype": "Currency",
- "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": "Additional Amount",
- "length": 0,
- "no_copy": 1,
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "additional_amount",
+ "fieldtype": "Currency",
+ "hidden": 1,
+ "label": "Additional Amount",
+ "no_copy": 1,
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:doc.parenttype=='Salary Slip' && doc.parentfield=='deductions' && doc.variable_based_on_taxable_salary == 1",
- "fetch_if_empty": 0,
- "fieldname": "tax_on_flexible_benefit",
- "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": "Tax on flexible benefit",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "depends_on": "eval:doc.parenttype=='Salary Slip' && doc.parentfield=='deductions' && doc.variable_based_on_taxable_salary == 1",
+ "fieldname": "tax_on_flexible_benefit",
+ "fieldtype": "Currency",
+ "label": "Tax on flexible benefit",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:doc.parenttype=='Salary Slip' && doc.parentfield=='deductions' && doc.variable_based_on_taxable_salary == 1",
- "fetch_if_empty": 0,
- "fieldname": "tax_on_additional_salary",
- "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": "Tax on additional salary",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "depends_on": "eval:doc.parenttype=='Salary Slip' && doc.parentfield=='deductions' && doc.variable_based_on_taxable_salary == 1",
+ "fieldname": "tax_on_additional_salary",
+ "fieldtype": "Currency",
+ "label": "Tax on additional salary",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:doc.parenttype=='Salary Structure'",
- "fetch_if_empty": 0,
- "fieldname": "section_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,
- "translatable": 0,
- "unique": 0
- },
+ "depends_on": "eval:doc.parenttype=='Salary Structure'",
+ "fieldname": "section_break_11",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:doc.parenttype=='Salary Structure'",
- "fetch_if_empty": 0,
- "fieldname": "condition_and_formula_help",
- "fieldtype": "HTML",
- "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": "Condition and Formula Help",
- "length": 0,
- "no_copy": 0,
- "options": "<h3>Condition and Formula Help</h3>\n\n<p>Notes:</p>\n\n<ol>\n<li>Use field <code>base</code> for using base salary of the Employee</li>\n<li>Use Salary Component abbreviations in conditions and formulas. <code>BS = Basic Salary</code></li>\n<li>Use field name for employee details in conditions and formulas. <code>Employment Type = employment_type</code><code>Branch = branch</code></li>\n<li>Use field name from Salary Slip in conditions and formulas. <code>Payment Days = payment_days</code><code>Leave without pay = leave_without_pay</code></li>\n<li>Direct Amount can also be entered based on Condtion. See example 3</li></ol>\n\n<h4>Examples</h4>\n<ol>\n<li>Calculating Basic Salary based on <code>base</code>\n<pre><code>Condition: base < 10000</code></pre>\n<pre><code>Formula: base * .2</code></pre></li>\n<li>Calculating HRA based on Basic Salary<code>BS</code> \n<pre><code>Condition: BS > 2000</code></pre>\n<pre><code>Formula: BS * .1</code></pre></li>\n<li>Calculating TDS based on Employment Type<code>employment_type</code> \n<pre><code>Condition: employment_type==\"Intern\"</code></pre>\n<pre><code>Amount: 1000</code></pre></li>\n</ol>",
- "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
+ "depends_on": "eval:doc.parenttype=='Salary Structure'",
+ "fieldname": "condition_and_formula_help",
+ "fieldtype": "HTML",
+ "label": "Condition and Formula Help",
+ "options": "<h3>Condition and Formula Help</h3>\n\n<p>Notes:</p>\n\n<ol>\n<li>Use field <code>base</code> for using base salary of the Employee</li>\n<li>Use Salary Component abbreviations in conditions and formulas. <code>BS = Basic Salary</code></li>\n<li>Use field name for employee details in conditions and formulas. <code>Employment Type = employment_type</code><code>Branch = branch</code></li>\n<li>Use field name from Salary Slip in conditions and formulas. <code>Payment Days = payment_days</code><code>Leave without pay = leave_without_pay</code></li>\n<li>Direct Amount can also be entered based on Condtion. See example 3</li></ol>\n\n<h4>Examples</h4>\n<ol>\n<li>Calculating Basic Salary based on <code>base</code>\n<pre><code>Condition: base < 10000</code></pre>\n<pre><code>Formula: base * .2</code></pre></li>\n<li>Calculating HRA based on Basic Salary<code>BS</code> \n<pre><code>Condition: BS > 2000</code></pre>\n<pre><code>Formula: BS * .1</code></pre></li>\n<li>Calculating TDS based on Employment Type<code>employment_type</code> \n<pre><code>Condition: employment_type==\"Intern\"</code></pre>\n<pre><code>Amount: 1000</code></pre></li>\n</ol>"
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 1,
- "max_attachments": 0,
- "modified": "2019-05-11 17:33:08.508653",
- "modified_by": "Administrator",
- "module": "HR",
- "name": "Salary Detail",
- "name_case": "",
- "owner": "Administrator",
- "permissions": [],
- "quick_entry": 1,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 0,
- "track_seen": 0,
- "track_views": 0
+ ],
+ "istable": 1,
+ "links": [],
+ "modified": "2019-12-31 17:15:25.646689",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Salary Detail",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC"
}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/salary_slip/salary_slip.json b/erpnext/hr/doctype/salary_slip/salary_slip.json
index fa3114c..e73d41a 100644
--- a/erpnext/hr/doctype/salary_slip/salary_slip.json
+++ b/erpnext/hr/doctype/salary_slip/salary_slip.json
@@ -1,1955 +1,508 @@
{
- "allow_copy": 0,
- "allow_events_in_timeline": 0,
- "allow_guest_to_view": 0,
- "allow_import": 1,
- "allow_rename": 0,
- "beta": 0,
- "creation": "2013-01-10 16:34:15",
- "custom": 0,
- "default_print_format": "",
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "Setup",
- "editable_grid": 0,
- "fields": [
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "Today",
- "fieldname": "posting_date",
- "fieldtype": "Date",
- "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": "Posting Date",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "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": "employee",
- "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": 1,
- "label": "Employee",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "employee",
- "oldfieldtype": "Link",
- "options": "Employee",
- "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": 1,
- "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,
- "fetch_from": "employee.employee_name",
- "fieldname": "employee_name",
- "fieldtype": "Read Only",
- "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": "Employee Name",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "employee_name",
- "oldfieldtype": "Data",
- "options": "",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_from": "employee.department",
- "fieldname": "department",
- "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": 1,
- "label": "Department",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "department",
- "oldfieldtype": "Link",
- "options": "Department",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:doc.designation",
- "fetch_from": "employee.designation",
- "fieldname": "designation",
- "fieldtype": "Read Only",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Designation",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "designation",
- "oldfieldtype": "Link",
- "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
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_from": "employee.branch",
- "fieldname": "branch",
- "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": 1,
- "label": "Branch",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "branch",
- "oldfieldtype": "Link",
- "options": "Branch",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break1",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "oldfieldtype": "Column Break",
- "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,
- "width": "50%"
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "status",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Status",
- "length": 0,
- "no_copy": 0,
- "options": "Draft\nSubmitted\nCancelled",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "journal_entry",
- "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": "Journal Entry",
- "length": 0,
- "no_copy": 0,
- "options": "Journal Entry",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "payroll_entry",
- "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": "Payroll Entry",
- "length": 0,
- "no_copy": 0,
- "options": "Payroll Entry",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "company",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 1,
- "label": "Company",
- "length": 0,
- "no_copy": 0,
- "options": "Company",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 1,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "letter_head",
- "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": "Letter Head",
- "length": 0,
- "no_copy": 0,
- "options": "Letter Head",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "section_break_10",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
- "fieldname": "salary_slip_based_on_timesheet",
- "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": "Salary Slip Based on Timesheet",
- "length": 0,
- "no_copy": 0,
- "options": "",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "",
- "fieldname": "start_date",
- "fieldtype": "Date",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Start Date",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "",
- "depends_on": "",
- "fieldname": "end_date",
- "fieldtype": "Date",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "End Date",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_15",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
- "fieldname": "salary_structure",
- "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": "Salary Structure",
- "length": 0,
- "no_copy": 0,
- "options": "Salary Structure",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "",
- "depends_on": "eval:(!doc.salary_slip_based_on_timesheet)",
- "fieldname": "payroll_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": "Payroll Frequency",
- "length": 0,
- "no_copy": 0,
- "options": "\nMonthly\nFortnightly\nBimonthly\nWeekly\nDaily",
- "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
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
- "fieldname": "total_working_days",
- "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": "Working Days",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "total_days_in_month",
- "oldfieldtype": "Int",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
- "fieldname": "leave_without_pay",
- "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": "Leave Without Pay",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "leave_without_pay",
- "oldfieldtype": "Currency",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
- "fieldname": "payment_days",
- "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": "Payment Days",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "payment_days",
- "oldfieldtype": "Float",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
- "fieldname": "hourly_wages",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
- "fieldname": "timesheets",
- "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": "Salary Slip Timesheet",
- "length": 0,
- "no_copy": 0,
- "options": "Salary Slip Timesheet",
- "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
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_20",
- "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
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "total_working_hours",
- "fieldtype": "Float",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Total Working Hours",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 1,
- "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": "hour_rate",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Hour Rate",
- "length": 0,
- "no_copy": 0,
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 1,
- "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,
- "depends_on": "",
- "fieldname": "section_break_26",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "bank_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": "Bank Name",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "bank_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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "bank_account_no",
- "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": "Bank Account No.",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "bank_account_no",
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "section_break_32",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "deduct_tax_for_unclaimed_employee_benefits",
- "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": "Deduct Tax For Unclaimed Employee Benefits",
- "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
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "deduct_tax_for_unsubmitted_tax_exemption_proof",
- "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": "Deduct Tax For Unsubmitted Tax Exemption Proof",
- "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
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "earning_deduction",
- "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": "Earning & Deduction",
- "length": 0,
- "no_copy": 0,
- "oldfieldtype": "Section Break",
- "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
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "earning",
- "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,
- "label": "Earning",
- "length": 0,
- "no_copy": 0,
- "oldfieldtype": "Column Break",
- "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,
- "width": "50%"
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
- "fieldname": "earnings",
- "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": "Earnings",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "earning_details",
- "oldfieldtype": "Table",
- "options": "Salary Detail",
- "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
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "deduction",
- "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,
- "label": "Deduction",
- "length": 0,
- "no_copy": 0,
- "oldfieldtype": "Column Break",
- "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,
- "width": "50%"
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "deductions",
- "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": "Deductions",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "deduction_details",
- "oldfieldtype": "Table",
- "options": "Salary Detail",
- "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
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "totals",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "",
- "length": 0,
- "no_copy": 0,
- "oldfieldtype": "Section Break",
- "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
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "gross_pay",
- "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": "Gross Pay",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "gross_pay",
- "oldfieldtype": "Currency",
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_25",
- "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
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "total_deduction",
- "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": "Total Deduction",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "total_deduction",
- "oldfieldtype": "Currency",
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "total_loan_repayment",
- "fieldname": "loan_repayment",
- "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": "Loan repayment",
- "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
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "loans",
- "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": "Employee Loan",
- "length": 0,
- "no_copy": 0,
- "options": "Salary Slip Loan",
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "section_break_43",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "0",
- "fieldname": "total_principal_amount",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Total Principal Amount",
- "length": 0,
- "no_copy": 0,
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "0",
- "fieldname": "total_interest_amount",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Total Interest Amount",
- "length": 0,
- "no_copy": 0,
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_45",
- "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
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "0",
- "fieldname": "total_loan_repayment",
- "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": "Total Loan Repayment",
- "length": 0,
- "no_copy": 0,
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "net_pay_info",
- "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": "net pay info",
- "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
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "Gross Pay - Total Deduction - Loan Repayment",
- "fieldname": "net_pay",
- "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": "Net Pay",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "net_pay",
- "oldfieldtype": "Currency",
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_53",
- "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
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 1,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "rounded_total",
- "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": "Rounded Total",
- "length": 0,
- "no_copy": 0,
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "section_break_55",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "Net Pay (in words) will be visible once you save the Salary Slip.",
- "fieldname": "total_in_words",
- "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": "Total in words",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "net_pay_in_words",
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "amended_from",
- "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": "Amended From",
- "length": 0,
- "no_copy": 1,
- "oldfieldname": "amended_from",
- "oldfieldtype": "Data",
- "options": "Salary Slip",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- }
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "icon": "fa fa-file-text",
- "idx": 9,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 1,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2019-06-19 13:10:14.524119",
- "modified_by": "Administrator",
- "module": "HR",
- "name": "Salary Slip",
- "owner": "Administrator",
- "permissions": [
- {
- "amend": 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": "HR User",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 1,
- "write": 1
- },
- {
- "amend": 1,
- "cancel": 1,
- "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": 1,
- "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
- }
- ],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 1,
- "sort_field": "modified",
- "sort_order": "DESC",
- "timeline_field": "employee",
- "title_field": "employee_name",
- "track_changes": 0,
- "track_seen": 0,
- "track_views": 0
- }
\ No newline at end of file
+ "actions": [],
+ "allow_import": 1,
+ "creation": "2013-01-10 16:34:15",
+ "doctype": "DocType",
+ "document_type": "Setup",
+ "engine": "InnoDB",
+ "field_order": [
+ "posting_date",
+ "employee",
+ "employee_name",
+ "department",
+ "designation",
+ "column_break1",
+ "company",
+ "journal_entry",
+ "payroll_entry",
+ "letter_head",
+ "branch",
+ "status",
+ "section_break_10",
+ "salary_slip_based_on_timesheet",
+ "payroll_frequency",
+ "start_date",
+ "end_date",
+ "column_break_15",
+ "salary_structure",
+ "total_working_days",
+ "leave_without_pay",
+ "payment_days",
+ "hourly_wages",
+ "timesheets",
+ "column_break_20",
+ "total_working_hours",
+ "hour_rate",
+ "section_break_26",
+ "bank_name",
+ "bank_account_no",
+ "section_break_32",
+ "deduct_tax_for_unclaimed_employee_benefits",
+ "deduct_tax_for_unsubmitted_tax_exemption_proof",
+ "earning_deduction",
+ "earning",
+ "earnings",
+ "deduction",
+ "deductions",
+ "totals",
+ "gross_pay",
+ "column_break_25",
+ "total_deduction",
+ "loan_repayment",
+ "loans",
+ "section_break_43",
+ "total_principal_amount",
+ "total_interest_amount",
+ "column_break_45",
+ "total_loan_repayment",
+ "net_pay_info",
+ "net_pay",
+ "column_break_53",
+ "rounded_total",
+ "section_break_55",
+ "total_in_words",
+ "amended_from"
+ ],
+ "fields": [
+ {
+ "default": "Today",
+ "fieldname": "posting_date",
+ "fieldtype": "Date",
+ "in_list_view": 1,
+ "label": "Posting Date",
+ "reqd": 1
+ },
+ {
+ "fieldname": "employee",
+ "fieldtype": "Link",
+ "in_global_search": 1,
+ "in_list_view": 1,
+ "in_standard_filter": 1,
+ "label": "Employee",
+ "oldfieldname": "employee",
+ "oldfieldtype": "Link",
+ "options": "Employee",
+ "reqd": 1,
+ "search_index": 1
+ },
+ {
+ "fetch_from": "employee.employee_name",
+ "fieldname": "employee_name",
+ "fieldtype": "Read Only",
+ "in_global_search": 1,
+ "in_list_view": 1,
+ "label": "Employee Name",
+ "oldfieldname": "employee_name",
+ "oldfieldtype": "Data",
+ "reqd": 1
+ },
+ {
+ "fetch_from": "employee.department",
+ "fieldname": "department",
+ "fieldtype": "Link",
+ "in_standard_filter": 1,
+ "label": "Department",
+ "oldfieldname": "department",
+ "oldfieldtype": "Link",
+ "options": "Department",
+ "read_only": 1
+ },
+ {
+ "depends_on": "eval:doc.designation",
+ "fetch_from": "employee.designation",
+ "fieldname": "designation",
+ "fieldtype": "Read Only",
+ "label": "Designation",
+ "oldfieldname": "designation",
+ "oldfieldtype": "Link"
+ },
+ {
+ "fetch_from": "employee.branch",
+ "fieldname": "branch",
+ "fieldtype": "Link",
+ "in_standard_filter": 1,
+ "label": "Branch",
+ "oldfieldname": "branch",
+ "oldfieldtype": "Link",
+ "options": "Branch",
+ "read_only": 1
+ },
+ {
+ "fieldname": "column_break1",
+ "fieldtype": "Column Break",
+ "oldfieldtype": "Column Break",
+ "width": "50%"
+ },
+ {
+ "fieldname": "status",
+ "fieldtype": "Select",
+ "label": "Status",
+ "options": "Draft\nSubmitted\nCancelled",
+ "read_only": 1
+ },
+ {
+ "fieldname": "journal_entry",
+ "fieldtype": "Link",
+ "label": "Journal Entry",
+ "options": "Journal Entry",
+ "read_only": 1
+ },
+ {
+ "fieldname": "payroll_entry",
+ "fieldtype": "Link",
+ "label": "Payroll Entry",
+ "options": "Payroll Entry",
+ "read_only": 1
+ },
+ {
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "in_standard_filter": 1,
+ "label": "Company",
+ "options": "Company",
+ "remember_last_selected_value": 1,
+ "reqd": 1
+ },
+ {
+ "allow_on_submit": 1,
+ "fieldname": "letter_head",
+ "fieldtype": "Link",
+ "ignore_user_permissions": 1,
+ "label": "Letter Head",
+ "options": "Letter Head",
+ "print_hide": 1
+ },
+ {
+ "fieldname": "section_break_10",
+ "fieldtype": "Section Break"
+ },
+ {
+ "default": "0",
+ "fieldname": "salary_slip_based_on_timesheet",
+ "fieldtype": "Check",
+ "label": "Salary Slip Based on Timesheet",
+ "read_only": 1
+ },
+ {
+ "fieldname": "start_date",
+ "fieldtype": "Date",
+ "label": "Start Date"
+ },
+ {
+ "fieldname": "end_date",
+ "fieldtype": "Date",
+ "label": "End Date"
+ },
+ {
+ "fieldname": "column_break_15",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "salary_structure",
+ "fieldtype": "Link",
+ "label": "Salary Structure",
+ "options": "Salary Structure",
+ "read_only": 1
+ },
+ {
+ "depends_on": "eval:(!doc.salary_slip_based_on_timesheet)",
+ "fieldname": "payroll_frequency",
+ "fieldtype": "Select",
+ "label": "Payroll Frequency",
+ "options": "\nMonthly\nFortnightly\nBimonthly\nWeekly\nDaily"
+ },
+ {
+ "fieldname": "total_working_days",
+ "fieldtype": "Float",
+ "label": "Working Days",
+ "oldfieldname": "total_days_in_month",
+ "oldfieldtype": "Int",
+ "read_only": 1,
+ "reqd": 1
+ },
+ {
+ "fieldname": "leave_without_pay",
+ "fieldtype": "Float",
+ "label": "Leave Without Pay",
+ "oldfieldname": "leave_without_pay",
+ "oldfieldtype": "Currency"
+ },
+ {
+ "fieldname": "payment_days",
+ "fieldtype": "Float",
+ "label": "Payment Days",
+ "oldfieldname": "payment_days",
+ "oldfieldtype": "Float",
+ "read_only": 1,
+ "reqd": 1
+ },
+ {
+ "fieldname": "hourly_wages",
+ "fieldtype": "Section Break"
+ },
+ {
+ "fieldname": "timesheets",
+ "fieldtype": "Table",
+ "label": "Salary Slip Timesheet",
+ "options": "Salary Slip Timesheet"
+ },
+ {
+ "fieldname": "column_break_20",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "total_working_hours",
+ "fieldtype": "Float",
+ "label": "Total Working Hours",
+ "print_hide_if_no_value": 1
+ },
+ {
+ "fieldname": "hour_rate",
+ "fieldtype": "Currency",
+ "label": "Hour Rate",
+ "options": "Company:company:default_currency",
+ "print_hide_if_no_value": 1
+ },
+ {
+ "fieldname": "section_break_26",
+ "fieldtype": "Section Break"
+ },
+ {
+ "fieldname": "bank_name",
+ "fieldtype": "Data",
+ "label": "Bank Name",
+ "oldfieldname": "bank_name",
+ "oldfieldtype": "Data",
+ "read_only": 1
+ },
+ {
+ "fieldname": "bank_account_no",
+ "fieldtype": "Data",
+ "label": "Bank Account No.",
+ "oldfieldname": "bank_account_no",
+ "oldfieldtype": "Data",
+ "read_only": 1
+ },
+ {
+ "fieldname": "section_break_32",
+ "fieldtype": "Section Break"
+ },
+ {
+ "default": "0",
+ "fieldname": "deduct_tax_for_unclaimed_employee_benefits",
+ "fieldtype": "Check",
+ "label": "Deduct Tax For Unclaimed Employee Benefits"
+ },
+ {
+ "default": "0",
+ "fieldname": "deduct_tax_for_unsubmitted_tax_exemption_proof",
+ "fieldtype": "Check",
+ "label": "Deduct Tax For Unsubmitted Tax Exemption Proof"
+ },
+ {
+ "fieldname": "earning_deduction",
+ "fieldtype": "Section Break",
+ "label": "Earning & Deduction",
+ "oldfieldtype": "Section Break"
+ },
+ {
+ "fieldname": "earning",
+ "fieldtype": "Column Break",
+ "oldfieldtype": "Column Break",
+ "width": "50%"
+ },
+ {
+ "fieldname": "earnings",
+ "fieldtype": "Table",
+ "label": "Earnings",
+ "oldfieldname": "earning_details",
+ "oldfieldtype": "Table",
+ "options": "Salary Detail"
+ },
+ {
+ "fieldname": "deduction",
+ "fieldtype": "Column Break",
+ "oldfieldtype": "Column Break",
+ "width": "50%"
+ },
+ {
+ "fieldname": "deductions",
+ "fieldtype": "Table",
+ "label": "Deductions",
+ "oldfieldname": "deduction_details",
+ "oldfieldtype": "Table",
+ "options": "Salary Detail"
+ },
+ {
+ "fieldname": "totals",
+ "fieldtype": "Section Break",
+ "oldfieldtype": "Section Break"
+ },
+ {
+ "fieldname": "gross_pay",
+ "fieldtype": "Currency",
+ "label": "Gross Pay",
+ "oldfieldname": "gross_pay",
+ "oldfieldtype": "Currency",
+ "options": "Company:company:default_currency",
+ "read_only": 1
+ },
+ {
+ "fieldname": "column_break_25",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "total_deduction",
+ "fieldtype": "Currency",
+ "label": "Total Deduction",
+ "oldfieldname": "total_deduction",
+ "oldfieldtype": "Currency",
+ "options": "Company:company:default_currency",
+ "read_only": 1
+ },
+ {
+ "depends_on": "total_loan_repayment",
+ "fieldname": "loan_repayment",
+ "fieldtype": "Section Break",
+ "label": "Loan repayment"
+ },
+ {
+ "fieldname": "loans",
+ "fieldtype": "Table",
+ "label": "Employee Loan",
+ "options": "Salary Slip Loan",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "fieldname": "section_break_43",
+ "fieldtype": "Section Break"
+ },
+ {
+ "default": "0",
+ "fieldname": "total_principal_amount",
+ "fieldtype": "Currency",
+ "label": "Total Principal Amount",
+ "options": "Company:company:default_currency",
+ "read_only": 1
+ },
+ {
+ "default": "0",
+ "fieldname": "total_interest_amount",
+ "fieldtype": "Currency",
+ "label": "Total Interest Amount",
+ "options": "Company:company:default_currency",
+ "read_only": 1
+ },
+ {
+ "fieldname": "column_break_45",
+ "fieldtype": "Column Break"
+ },
+ {
+ "default": "0",
+ "fieldname": "total_loan_repayment",
+ "fieldtype": "Currency",
+ "label": "Total Loan Repayment",
+ "options": "Company:company:default_currency",
+ "read_only": 1
+ },
+ {
+ "fieldname": "net_pay_info",
+ "fieldtype": "Section Break",
+ "label": "net pay info"
+ },
+ {
+ "description": "Gross Pay - Total Deduction - Loan Repayment",
+ "fieldname": "net_pay",
+ "fieldtype": "Currency",
+ "label": "Net Pay",
+ "oldfieldname": "net_pay",
+ "oldfieldtype": "Currency",
+ "options": "Company:company:default_currency",
+ "read_only": 1
+ },
+ {
+ "fieldname": "column_break_53",
+ "fieldtype": "Column Break"
+ },
+ {
+ "bold": 1,
+ "fieldname": "rounded_total",
+ "fieldtype": "Currency",
+ "label": "Rounded Total",
+ "options": "Company:company:default_currency",
+ "read_only": 1
+ },
+ {
+ "fieldname": "section_break_55",
+ "fieldtype": "Section Break"
+ },
+ {
+ "description": "Net Pay (in words) will be visible once you save the Salary Slip.",
+ "fieldname": "total_in_words",
+ "fieldtype": "Data",
+ "label": "Total in words",
+ "oldfieldname": "net_pay_in_words",
+ "oldfieldtype": "Data",
+ "read_only": 1
+ },
+ {
+ "fieldname": "amended_from",
+ "fieldtype": "Link",
+ "ignore_user_permissions": 1,
+ "label": "Amended From",
+ "no_copy": 1,
+ "oldfieldname": "amended_from",
+ "oldfieldtype": "Data",
+ "options": "Salary Slip",
+ "print_hide": 1,
+ "read_only": 1
+ }
+ ],
+ "icon": "fa fa-file-text",
+ "idx": 9,
+ "is_submittable": 1,
+ "links": [],
+ "modified": "2019-12-31 17:13:45.146271",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Salary Slip",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "create": 1,
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "HR User",
+ "share": 1,
+ "submit": 1,
+ "write": 1
+ },
+ {
+ "amend": 1,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "HR Manager",
+ "share": 1,
+ "submit": 1,
+ "write": 1
+ },
+ {
+ "read": 1,
+ "role": "Employee"
+ }
+ ],
+ "show_name_in_global_search": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "timeline_field": "employee",
+ "title_field": "employee_name"
+}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/salary_slip/salary_slip.py b/erpnext/hr/doctype/salary_slip/salary_slip.py
index 46be4fe..555f74c 100644
--- a/erpnext/hr/doctype/salary_slip/salary_slip.py
+++ b/erpnext/hr/doctype/salary_slip/salary_slip.py
@@ -50,7 +50,8 @@
self.calculate_net_pay()
company_currency = erpnext.get_company_currency(self.company)
- self.total_in_words = money_in_words(self.rounded_total, company_currency)
+ total = self.net_pay if self.is_rounding_total_disabled() else self.rounded_total
+ self.total_in_words = money_in_words(total, company_currency)
if frappe.db.get_single_value("HR Settings", "max_working_hours_against_timesheet"):
max_working_hours = frappe.db.get_single_value("HR Settings", "max_working_hours_against_timesheet")
@@ -90,6 +91,9 @@
if date_diff(self.end_date, self.start_date) < 0:
frappe.throw(_("To date cannot be before From date"))
+ def is_rounding_total_disabled(self):
+ return cint(frappe.db.get_single_value("HR Settings", "disable_rounded_total"))
+
def check_existing(self):
if not self.salary_slip_based_on_timesheet:
ret_exist = frappe.db.sql("""select name from `tabSalary Slip`
diff --git a/erpnext/hr/doctype/salary_structure/salary_structure.js b/erpnext/hr/doctype/salary_structure/salary_structure.js
index d56320a..9f42c91 100755
--- a/erpnext/hr/doctype/salary_structure/salary_structure.js
+++ b/erpnext/hr/doctype/salary_structure/salary_structure.js
@@ -47,9 +47,11 @@
frm.fields_dict['earnings'].grid.set_column_disp("default_amount", false);
frm.fields_dict['deductions'].grid.set_column_disp("default_amount", false);
- frm.add_custom_button(__("Preview Salary Slip"), function() {
- frm.trigger('preview_salary_slip');
- });
+ if(frm.doc.docstatus === 1) {
+ frm.add_custom_button(__("Preview Salary Slip"), function() {
+ frm.trigger('preview_salary_slip');
+ });
+ }
if(frm.doc.docstatus==1) {
frm.add_custom_button(__("Assign Salary Structure"), function() {
@@ -117,47 +119,52 @@
},
callback: function(r) {
var employees = r.message;
- var d = new frappe.ui.Dialog({
- title: __("Preview Salary Slip"),
- fields: [
- {
- "label":__("Employee"),
- "fieldname":"employee",
- "fieldtype":"Select",
- "reqd": true,
- options: employees
- }, {
- fieldname:"fetch",
- "label":__("Show Salary Slip"),
- "fieldtype":"Button"
- }
- ]
- });
- d.get_input("fetch").on("click", function() {
- var values = d.get_values();
- if(!values) return;
- var print_format;
- frm.doc.salary_slip_based_on_timesheet ?
- print_format="Salary Slip based on Timesheet" :
- print_format="Salary Slip Standard";
-
- frappe.call({
- method: "erpnext.hr.doctype.salary_structure.salary_structure.make_salary_slip",
- args: {
- source_name: frm.doc.name,
- employee: values.employee,
- as_print: 1,
- print_format: print_format,
- for_preview: 1
- },
- callback: function(r) {
- var new_window = window.open();
- new_window.document.write(r.message);
- // frappe.msgprint(r.message);
- }
+ if(!employees) return;
+ if (employees.length == 1){
+ frm.events.open_salary_slip(frm, employees[0]);
+ } else {
+ var d = new frappe.ui.Dialog({
+ title: __("Preview Salary Slip"),
+ fields: [
+ {
+ "label":__("Employee"),
+ "fieldname":"employee",
+ "fieldtype":"Select",
+ "reqd": true,
+ options: employees
+ }, {
+ fieldname:"fetch",
+ "label":__("Show Salary Slip"),
+ "fieldtype":"Button"
+ }
+ ]
});
- });
- d.show();
+ d.get_input("fetch").on("click", function() {
+ var values = d.get_values();
+ if(!values) return;
+ frm.events.open_salary_slip(frm, values.employee)
+
+ });
+ d.show();
+ }
+ }
+ });
+ },
+
+ open_salary_slip: function(frm, employee){
+ var print_format = frm.doc.salary_slip_based_on_timesheet ? "Salary Slip based on Timesheet" : "Salary Slip Standard";
+ frappe.call({
+ method: "erpnext.hr.doctype.salary_structure.salary_structure.make_salary_slip",
+ args: {
+ source_name: frm.doc.name,
+ employee: employee,
+ as_print: 1,
+ print_format: print_format,
+ for_preview: 1
+ },
+ callback: function(r) {
+ var new_window = window.open();
+ new_window.document.write(r.message);
}
});
},
diff --git a/erpnext/hr/doctype/salary_structure/salary_structure.json b/erpnext/hr/doctype/salary_structure/salary_structure.json
index 0e47278..58c4044 100644
--- a/erpnext/hr/doctype/salary_structure/salary_structure.json
+++ b/erpnext/hr/doctype/salary_structure/salary_structure.json
@@ -1,1010 +1,283 @@
{
- "allow_copy": 0,
- "allow_events_in_timeline": 0,
- "allow_guest_to_view": 0,
- "allow_import": 1,
- "allow_rename": 1,
- "autoname": "Prompt",
- "beta": 0,
- "creation": "2013-03-07 18:50:29",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "Document",
- "editable_grid": 0,
+ "actions": [],
+ "allow_import": 1,
+ "allow_rename": 1,
+ "autoname": "Prompt",
+ "creation": "2013-03-07 18:50:29",
+ "doctype": "DocType",
+ "document_type": "Document",
+ "engine": "InnoDB",
+ "field_order": [
+ "company",
+ "letter_head",
+ "column_break1",
+ "is_active",
+ "payroll_frequency",
+ "is_default",
+ "time_sheet_earning_detail",
+ "salary_slip_based_on_timesheet",
+ "column_break_17",
+ "salary_component",
+ "hour_rate",
+ "leave_encashment_amount_per_day",
+ "max_benefits",
+ "earning_deduction",
+ "earning",
+ "earnings",
+ "deduction",
+ "deductions",
+ "net_pay_detail",
+ "column_break2",
+ "total_earning",
+ "total_deduction",
+ "net_pay",
+ "account",
+ "mode_of_payment",
+ "column_break_28",
+ "payment_account",
+ "amended_from"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "company",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Company",
- "length": 0,
- "no_copy": 0,
- "options": "Company",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 1,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "label": "Company",
+ "options": "Company",
+ "remember_last_selected_value": 1,
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "letter_head",
- "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": "Letter Head",
- "length": 0,
- "no_copy": 0,
- "options": "Letter Head",
- "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
- },
+ "fieldname": "letter_head",
+ "fieldtype": "Link",
+ "label": "Letter Head",
+ "options": "Letter Head"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break1",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
+ "fieldname": "column_break1",
+ "fieldtype": "Column Break",
"width": "50%"
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "Yes",
- "fieldname": "is_active",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 1,
- "label": "Is Active",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "is_active",
- "oldfieldtype": "Select",
- "options": "\nYes\nNo",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "default": "Yes",
+ "fieldname": "is_active",
+ "fieldtype": "Select",
+ "in_list_view": 1,
+ "in_standard_filter": 1,
+ "label": "Is Active",
+ "oldfieldname": "is_active",
+ "oldfieldtype": "Select",
+ "options": "\nYes\nNo",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "Monthly",
- "depends_on": "eval:(!doc.salary_slip_based_on_timesheet)",
- "fieldname": "payroll_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": "Payroll Frequency",
- "length": 0,
- "no_copy": 0,
- "options": "\nMonthly\nFortnightly\nBimonthly\nWeekly\nDaily",
- "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
- },
+ "default": "Monthly",
+ "depends_on": "eval:(!doc.salary_slip_based_on_timesheet)",
+ "fieldname": "payroll_frequency",
+ "fieldtype": "Select",
+ "label": "Payroll Frequency",
+ "options": "\nMonthly\nFortnightly\nBimonthly\nWeekly\nDaily"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "No",
- "fieldname": "is_default",
- "fieldtype": "Select",
- "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": "Is Default",
- "length": 0,
- "no_copy": 1,
- "options": "Yes\nNo",
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "default": "No",
+ "fieldname": "is_default",
+ "fieldtype": "Select",
+ "hidden": 1,
+ "label": "Is Default",
+ "no_copy": 1,
+ "options": "Yes\nNo",
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "time_sheet_earning_detail",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "time_sheet_earning_detail",
+ "fieldtype": "Section Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
- "fieldname": "salary_slip_based_on_timesheet",
- "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": "Salary Slip Based on Timesheet",
- "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
- },
+ "default": "0",
+ "fieldname": "salary_slip_based_on_timesheet",
+ "fieldtype": "Check",
+ "label": "Salary Slip Based on Timesheet"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_17",
- "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
- },
+ "fieldname": "column_break_17",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
- "description": "Salary Component for timesheet based payroll.",
- "fieldname": "salary_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": "Salary 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
- },
+ "description": "Salary Component for timesheet based payroll.",
+ "fieldname": "salary_component",
+ "fieldtype": "Link",
+ "label": "Salary Component",
+ "options": "Salary Component"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
- "fieldname": "hour_rate",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Hour Rate",
- "length": 0,
- "no_copy": 0,
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "hour_rate",
+ "fieldtype": "Currency",
+ "label": "Hour Rate",
+ "options": "Company:company:default_currency"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "leave_encashment_amount_per_day",
- "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": "Leave Encashment Amount Per Day",
- "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
- },
+ "fieldname": "leave_encashment_amount_per_day",
+ "fieldtype": "Currency",
+ "label": "Leave Encashment Amount Per Day",
+ "options": "Company:company:default_currency"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "max_benefits",
- "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": "Max Benefits (Amount)",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "max_benefits",
+ "fieldtype": "Currency",
+ "label": "Max Benefits (Amount)",
+ "options": "Company:company:default_currency"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
- "description": "Salary breakup based on Earning and Deduction.",
- "fieldname": "earning_deduction",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "earning_deduction",
- "oldfieldtype": "Section Break",
- "permlevel": 0,
- "precision": "2",
- "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
- },
+ "description": "Salary breakup based on Earning and Deduction.",
+ "fieldname": "earning_deduction",
+ "fieldtype": "Section Break",
+ "oldfieldname": "earning_deduction",
+ "oldfieldtype": "Section Break",
+ "precision": "2"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "earning",
- "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": "Earning",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "col_brk2",
- "oldfieldtype": "Column Break",
- "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,
+ "fieldname": "earning",
+ "fieldtype": "Section Break",
+ "label": "Earning",
+ "oldfieldname": "col_brk2",
+ "oldfieldtype": "Column Break",
"width": "50%"
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
- "fieldname": "earnings",
- "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": "Earnings",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "earning_details",
- "oldfieldtype": "Table",
- "options": "Salary Detail",
- "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
- },
+ "fieldname": "earnings",
+ "fieldtype": "Table",
+ "label": "Earnings",
+ "oldfieldname": "earning_details",
+ "oldfieldtype": "Table",
+ "options": "Salary Detail"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "deduction",
- "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": "Deduction",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "col_brk3",
- "oldfieldtype": "Column Break",
- "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,
+ "fieldname": "deduction",
+ "fieldtype": "Section Break",
+ "label": "Deduction",
+ "oldfieldname": "col_brk3",
+ "oldfieldtype": "Column Break",
"width": "50%"
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "deductions",
- "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": "Deductions",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "deduction_details",
- "oldfieldtype": "Table",
- "options": "Salary Detail",
- "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
- },
+ "fieldname": "deductions",
+ "fieldtype": "Table",
+ "label": "Deductions",
+ "oldfieldname": "deduction_details",
+ "oldfieldtype": "Table",
+ "options": "Salary Detail"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
- "fieldname": "net_pay_detail",
- "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,
- "options": "Simple",
- "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
- },
+ "fieldname": "net_pay_detail",
+ "fieldtype": "Section Break",
+ "options": "Simple"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break2",
- "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,
+ "fieldname": "column_break2",
+ "fieldtype": "Column Break",
"width": "50%"
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "total_earning",
- "fieldtype": "Currency",
- "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": "Total Earning",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "total_earning",
- "oldfieldtype": "Currency",
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "total_earning",
+ "fieldtype": "Currency",
+ "hidden": 1,
+ "label": "Total Earning",
+ "oldfieldname": "total_earning",
+ "oldfieldtype": "Currency",
+ "options": "Company:company:default_currency",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "total_deduction",
- "fieldtype": "Currency",
- "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": "Total Deduction",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "total_deduction",
- "oldfieldtype": "Currency",
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "total_deduction",
+ "fieldtype": "Currency",
+ "hidden": 1,
+ "label": "Total Deduction",
+ "oldfieldname": "total_deduction",
+ "oldfieldtype": "Currency",
+ "options": "Company:company:default_currency",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "net_pay",
- "fieldtype": "Currency",
- "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": "Net Pay",
- "length": 0,
- "no_copy": 0,
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "net_pay",
+ "fieldtype": "Currency",
+ "hidden": 1,
+ "label": "Net Pay",
+ "options": "Company:company:default_currency",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "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": "Account",
- "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
- },
+ "fieldname": "account",
+ "fieldtype": "Section Break",
+ "label": "Account"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "mode_of_payment",
- "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": "Mode of Payment",
- "length": 0,
- "no_copy": 0,
- "options": "Mode of Payment",
- "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
- },
+ "fieldname": "mode_of_payment",
+ "fieldtype": "Link",
+ "label": "Mode of Payment",
+ "options": "Mode of Payment"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_28",
- "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
- },
+ "fieldname": "column_break_28",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "payment_account",
- "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": "Payment Account",
- "length": 0,
- "no_copy": 0,
- "options": "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "payment_account",
+ "fieldtype": "Link",
+ "label": "Payment Account",
+ "options": "Account"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "amended_from",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Amended From",
- "length": 0,
- "no_copy": 1,
- "options": "Salary Structure",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "fieldname": "amended_from",
+ "fieldtype": "Link",
+ "label": "Amended From",
+ "no_copy": 1,
+ "options": "Salary Structure",
+ "print_hide": 1,
+ "read_only": 1
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "icon": "fa fa-file-text",
- "idx": 1,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 1,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2019-02-18 18:51:53.932518",
- "modified_by": "Administrator",
- "module": "HR",
- "name": "Salary Structure",
- "owner": "Administrator",
+ ],
+ "icon": "fa fa-file-text",
+ "idx": 1,
+ "is_submittable": 1,
+ "links": [],
+ "modified": "2019-12-31 16:34:35.087658",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Salary Structure",
+ "owner": "Administrator",
"permissions": [
{
- "amend": 1,
- "cancel": 1,
- "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": 1,
+ "amend": 1,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "HR User",
+ "share": 1,
+ "submit": 1,
"write": 1
- },
+ },
{
- "amend": 1,
- "cancel": 1,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 1,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "HR Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 1,
+ "amend": 1,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "import": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "HR Manager",
+ "share": 1,
+ "submit": 1,
"write": 1
}
- ],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 1,
- "sort_field": "modified",
- "sort_order": "DESC",
- "timeline_field": "",
- "title_field": "",
- "track_changes": 0,
- "track_seen": 0,
- "track_views": 0
+ ],
+ "show_name_in_global_search": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC"
}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/salary_structure/salary_structure.py b/erpnext/hr/doctype/salary_structure/salary_structure.py
index f7d712d..0e1a74f 100644
--- a/erpnext/hr/doctype/salary_structure/salary_structure.py
+++ b/erpnext/hr/doctype/salary_structure/salary_structure.py
@@ -169,5 +169,10 @@
@frappe.whitelist()
def get_employees(salary_structure):
employees = frappe.get_list('Salary Structure Assignment',
- filters={'salary_structure': salary_structure}, fields=['employee'])
+ filters={'salary_structure': salary_structure, 'docstatus': 1}, fields=['employee'])
+
+ if not employees:
+ frappe.throw(_("There's no Employee with Salary Structure: {0}. \
+ Assign {1} to an Employee to preview Salary Slip").format(salary_structure, salary_structure))
+
return list(set([d.employee for d in employees]))
diff --git a/erpnext/hr/doctype/salary_structure_assignment/salary_structure_assignment.json b/erpnext/hr/doctype/salary_structure_assignment/salary_structure_assignment.json
index 55e2df9..380c889 100644
--- a/erpnext/hr/doctype/salary_structure_assignment/salary_structure_assignment.json
+++ b/erpnext/hr/doctype/salary_structure_assignment/salary_structure_assignment.json
@@ -1,524 +1,170 @@
{
- "allow_copy": 0,
- "allow_guest_to_view": 0,
- "allow_import": 1,
- "allow_rename": 0,
- "autoname": "HR-SSA-.YY.-.MM.-.#####",
- "beta": 0,
- "creation": "2018-04-13 16:38:41.769237",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "",
- "editable_grid": 1,
- "engine": "InnoDB",
+ "actions": [],
+ "allow_import": 1,
+ "autoname": "HR-SSA-.YY.-.MM.-.#####",
+ "creation": "2018-04-13 16:38:41.769237",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "employee",
+ "employee_name",
+ "department",
+ "designation",
+ "column_break_6",
+ "salary_structure",
+ "from_date",
+ "company",
+ "section_break_7",
+ "base",
+ "column_break_9",
+ "variable",
+ "amended_from"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "employee",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 1,
- "label": "Employee",
- "length": 0,
- "no_copy": 0,
- "options": "Employee",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 1,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "employee",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "in_standard_filter": 1,
+ "label": "Employee",
+ "options": "Employee",
+ "reqd": 1,
+ "search_index": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_from": "employee.employee_name",
- "fieldname": "employee_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": "Employee Name",
- "length": 0,
- "no_copy": 0,
- "options": "",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fetch_from": "employee.employee_name",
+ "fieldname": "employee_name",
+ "fieldtype": "Data",
+ "label": "Employee Name",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_from": "employee.department",
- "fieldname": "department",
- "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": 1,
- "label": "Department",
- "length": 0,
- "no_copy": 0,
- "options": "Department",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fetch_from": "employee.department",
+ "fieldname": "department",
+ "fieldtype": "Link",
+ "in_standard_filter": 1,
+ "label": "Department",
+ "options": "Department",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_from": "employee.designation",
- "fieldname": "designation",
- "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": 1,
- "label": "Designation",
- "length": 0,
- "no_copy": 0,
- "options": "Designation",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fetch_from": "employee.designation",
+ "fieldname": "designation",
+ "fieldtype": "Link",
+ "in_standard_filter": 1,
+ "label": "Designation",
+ "options": "Designation",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_6",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "column_break_6",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "salary_structure",
- "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": 1,
- "label": "Salary Structure",
- "length": 0,
- "no_copy": 0,
- "options": "Salary Structure",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 1,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "salary_structure",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "in_standard_filter": 1,
+ "label": "Salary Structure",
+ "options": "Salary Structure",
+ "reqd": 1,
+ "search_index": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "from_date",
- "fieldtype": "Date",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "From Date",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "from_date",
+ "fieldtype": "Date",
+ "label": "From Date",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "company",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Company",
- "length": 0,
- "no_copy": 0,
- "options": "Company",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "label": "Company",
+ "options": "Company",
+ "read_only": 1,
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "section_break_7",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "section_break_7",
+ "fieldtype": "Section Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "base",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Base",
- "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
- },
+ "fieldname": "base",
+ "fieldtype": "Currency",
+ "label": "Base",
+ "options": "Company:company:default_currency"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_9",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "column_break_9",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "variable",
- "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": "Variable",
- "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
- },
+ "fieldname": "variable",
+ "fieldtype": "Currency",
+ "label": "Variable",
+ "options": "Company:company:default_currency"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "amended_from",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Amended From",
- "length": 0,
- "no_copy": 1,
- "options": "Salary Structure Assignment",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "fieldname": "amended_from",
+ "fieldtype": "Link",
+ "label": "Amended From",
+ "no_copy": 1,
+ "options": "Salary Structure Assignment",
+ "print_hide": 1,
+ "read_only": 1
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 1,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2018-08-21 16:15:48.755450",
- "modified_by": "Administrator",
- "module": "HR",
- "name": "Salary Structure Assignment",
- "name_case": "",
- "owner": "Administrator",
+ ],
+ "is_submittable": 1,
+ "links": [],
+ "modified": "2019-12-31 16:35:34.415099",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Salary Structure Assignment",
+ "owner": "Administrator",
"permissions": [
{
- "amend": 0,
- "cancel": 0,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "System Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "System Manager",
+ "share": 1,
"write": 1
- },
+ },
{
- "amend": 1,
- "cancel": 1,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "HR Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 1,
+ "amend": 1,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "HR Manager",
+ "share": 1,
+ "submit": 1,
"write": 1
- },
+ },
{
- "amend": 0,
- "cancel": 0,
- "create": 1,
- "delete": 0,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "HR User",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 1,
+ "create": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "HR User",
+ "share": 1,
+ "submit": 1,
"write": 1
}
- ],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "title_field": "employee_name",
- "track_changes": 1,
- "track_seen": 0,
- "track_views": 0
+ ],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "title_field": "employee_name",
+ "track_changes": 1
}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/shift_assignment/shift_assignment.json b/erpnext/hr/doctype/shift_assignment/shift_assignment.json
index d4cd1c4..72cbba8 100644
--- a/erpnext/hr/doctype/shift_assignment/shift_assignment.json
+++ b/erpnext/hr/doctype/shift_assignment/shift_assignment.json
@@ -1,4 +1,5 @@
{
+ "actions": [],
"allow_import": 1,
"autoname": "HR-SHA-.YY.-.MM.-.#####",
"creation": "2018-04-13 16:25:04.562730",
@@ -8,12 +9,12 @@
"field_order": [
"employee",
"employee_name",
- "department",
"shift_type",
"column_break_3",
"company",
"date",
"shift_request",
+ "department",
"amended_from"
],
"fields": [
@@ -82,7 +83,8 @@
}
],
"is_submittable": 1,
- "modified": "2019-05-30 15:40:54.418427",
+ "links": [],
+ "modified": "2019-12-12 15:49:06.956901",
"modified_by": "Administrator",
"module": "HR",
"name": "Shift Assignment",
diff --git a/erpnext/hr/doctype/shift_type/shift_type.py b/erpnext/hr/doctype/shift_type/shift_type.py
index 8de92b2..4988410 100644
--- a/erpnext/hr/doctype/shift_type/shift_type.py
+++ b/erpnext/hr/doctype/shift_type/shift_type.py
@@ -11,7 +11,7 @@
from frappe.utils import cint, getdate, get_datetime
from erpnext.hr.doctype.shift_assignment.shift_assignment import get_actual_start_end_datetime_of_shift, get_employee_shift
from erpnext.hr.doctype.employee_checkin.employee_checkin import mark_attendance_and_link_log, calculate_working_hours
-from erpnext.hr.doctype.attendance.attendance import mark_absent
+from erpnext.hr.doctype.attendance.attendance import mark_attendance
from erpnext.hr.doctype.employee.employee import get_holiday_list_for_employee
class ShiftType(Document):
@@ -35,7 +35,7 @@
def get_attendance(self, logs):
"""Return attendance_status, working_hours for a set of logs belonging to a single shift.
- Assumtion:
+ Assumtion:
1. These logs belongs to an single shift, single employee and is not in a holiday date.
2. Logs are in chronological order
"""
@@ -43,10 +43,10 @@
total_working_hours, in_time, out_time = calculate_working_hours(logs, self.determine_check_in_and_check_out, self.working_hours_calculation_based_on)
if cint(self.enable_entry_grace_period) and in_time and in_time > logs[0].shift_start + timedelta(minutes=cint(self.late_entry_grace_period)):
late_entry = True
-
+
if cint(self.enable_exit_grace_period) and out_time and out_time < logs[0].shift_end - timedelta(minutes=cint(self.early_exit_grace_period)):
early_exit = True
-
+
if self.working_hours_threshold_for_absent and total_working_hours < self.working_hours_threshold_for_absent:
return 'Absent', total_working_hours, late_entry, early_exit
if self.working_hours_threshold_for_half_day and total_working_hours < self.working_hours_threshold_for_half_day:
@@ -75,7 +75,7 @@
for date in dates:
shift_details = get_employee_shift(employee, date, True)
if shift_details and shift_details.shift_type.name == self.name:
- mark_absent(employee, date, self.name)
+ mark_attendance(employee, date, self.name, 'Absent')
def get_assigned_employee(self, from_date=None, consider_default_shift=False):
filters = {'date':('>=', from_date), 'shift_type': self.name, 'docstatus': '1'}
@@ -107,15 +107,15 @@
condition_query = ''
if filter_attendance:
condition_query += """ and a.selected_date not in (
- select attendance_date from `tabAttendance`
- where docstatus = '1' and employee = %(employee)s
+ select attendance_date from `tabAttendance`
+ where docstatus = 1 and employee = %(employee)s
and attendance_date between %(start_date)s and %(end_date)s)"""
if holiday_list:
condition_query += """ and a.selected_date not in (
select holiday_date from `tabHoliday` where parenttype = 'Holiday List' and
parentfield = 'holidays' and parent = %(holiday_list)s
and holiday_date between %(start_date)s and %(end_date)s)"""
-
+
dates = frappe.db.sql("""select * from
({base_dates_query}) as a
where a.selected_date <= %(end_date)s {condition_query}
diff --git a/erpnext/hr/doctype/staffing_plan/staffing_plan.py b/erpnext/hr/doctype/staffing_plan/staffing_plan.py
index e6afbcc..595bcaa 100644
--- a/erpnext/hr/doctype/staffing_plan/staffing_plan.py
+++ b/erpnext/hr/doctype/staffing_plan/staffing_plan.py
@@ -7,6 +7,7 @@
from frappe.model.document import Document
from frappe import _
from frappe.utils import getdate, nowdate, cint, flt
+from frappe.utils.nestedset import get_descendants_of
class SubsidiaryCompanyError(frappe.ValidationError): pass
class ParentCompanyError(frappe.ValidationError): pass
@@ -131,7 +132,8 @@
return False
employee_counts = {}
- company_set = get_company_set(company)
+ company_set = get_descendants_of('Company', company)
+ company_set.append(company)
employee_counts["employee_count"] = frappe.db.get_value("Employee",
filters={
@@ -167,14 +169,4 @@
designation, from_date, to_date)
# Only a single staffing plan can be active for a designation on given date
- return staffing_plan if staffing_plan else None
-
-def get_company_set(company):
- return frappe.db.sql_list("""
- SELECT
- name
- FROM `tabCompany`
- WHERE
- parent_company=%(company)s
- OR name=%(company)s
- """, (dict(company=company)))
\ No newline at end of file
+ return staffing_plan if staffing_plan else None
\ No newline at end of file
diff --git a/erpnext/hr/doctype/travel_request/travel_request.json b/erpnext/hr/doctype/travel_request/travel_request.json
index c1c6524..441907c 100644
--- a/erpnext/hr/doctype/travel_request/travel_request.json
+++ b/erpnext/hr/doctype/travel_request/travel_request.json
@@ -1,4 +1,5 @@
{
+ "actions": [],
"autoname": "HR-TRQ-.YYYY.-.#####",
"creation": "2018-05-15 06:32:33.950356",
"doctype": "DocType",
@@ -11,8 +12,6 @@
"column_break_2",
"purpose_of_travel",
"details_of_sponsor",
- "section_break_4",
- "description",
"employee_details",
"employee",
"employee_name",
@@ -23,6 +22,8 @@
"personal_id_type",
"personal_id_number",
"passport_number",
+ "section_break_4",
+ "description",
"travel_itinerary",
"itinerary",
"costing_details",
@@ -33,7 +34,8 @@
"event_details",
"name_of_organizer",
"address_of_organizer",
- "other_details"
+ "other_details",
+ "amended_from"
],
"fields": [
{
@@ -213,7 +215,8 @@
}
],
"is_submittable": 1,
- "modified": "2019-05-25 23:15:00.609186",
+ "links": [],
+ "modified": "2019-12-12 18:42:26.451359",
"modified_by": "Administrator",
"module": "HR",
"name": "Travel Request",
diff --git a/erpnext/hr/notification/training_scheduled/training_scheduled.html b/erpnext/hr/notification/training_scheduled/training_scheduled.html
index b1aeb2c..374038a 100644
--- a/erpnext/hr/notification/training_scheduled/training_scheduled.html
+++ b/erpnext/hr/notification/training_scheduled/training_scheduled.html
@@ -1,9 +1,44 @@
-<h3>{{_("Training Event")}}</h3>
+<table class="panel-header" border="0" cellpadding="0" cellspacing="0" width="100%">
+ <tr height="10"></tr>
+ <tr>
+ <td width="15"></td>
+ <td>
+ <div class="text-medium text-muted">
+ <span>{{_("Training Event:")}} {{ doc.event_name }}</span>
+ </div>
+ </td>
+ <td width="15"></td>
+ </tr>
+ <tr height="10"></tr>
+</table>
-<p>{{ doc.introduction }}</p>
-
-<h4>{{_("Details")}}</h4>
-{{_("Event Name")}}: {{ frappe.utils.get_link_to_form(doc.doctype, doc.name) }}
-<br>{{_("Event Location")}}: {{ doc.location }}
-<br>{{_("Start Time")}}: {{ doc.start_time }}
-<br>{{_("End Time")}}: {{ doc.end_time }}
+<table class="panel-body" border="0" cellpadding="0" cellspacing="0" width="100%">
+ <tr height="10"></tr>
+ <tr>
+ <td width="15"></td>
+ <td>
+ <div>
+ {{ doc.introduction }}
+ <ul class="list-unstyled" style="line-height: 1.7">
+ <li>{{_("Event Location")}}: <b>{{ doc.location }}</b></li>
+ {% set start = frappe.utils.get_datetime(doc.start_time) %}
+ {% set end = frappe.utils.get_datetime(doc.end_time) %}
+ {% if start.date() == end.date() %}
+ <li>{{_("Date")}}: <b>{{ start.strftime("%A, %d %b %Y") }}</b></li>
+ <li>
+ {{_("Timing")}}: <b>{{ start.strftime("%I:%M %p") + ' to ' + end.strftime("%I:%M %p") }}</b>
+ </li>
+ {% else %}
+ <li>{{_("Start Time")}}: <b>{{ start.strftime("%A, %d %b %Y at %I:%M %p") }}</b>
+ </li>
+ <li>{{_("End Time")}}: <b>{{ end.strftime("%A, %d %b %Y at %I:%M %p") }}</b>
+ </li>
+ {% endif %}
+ <li>{{ _('Event Link') }}: {{ frappe.utils.get_link_to_form(doc.doctype, doc.name) }}</li>
+ </ul>
+ </div>
+ </td>
+ <td width="15"></td>
+ </tr>
+ <tr height="10"></tr>
+</table>
\ No newline at end of file
diff --git a/erpnext/hr/notification/training_scheduled/training_scheduled.json b/erpnext/hr/notification/training_scheduled/training_scheduled.json
index c07e1a6..966b887 100644
--- a/erpnext/hr/notification/training_scheduled/training_scheduled.json
+++ b/erpnext/hr/notification/training_scheduled/training_scheduled.json
@@ -1,5 +1,7 @@
{
"attach_print": 0,
+ "channel": "Email",
+ "condition": "",
"creation": "2017-08-11 03:13:40.519614",
"days_in_advance": 0,
"docstatus": 0,
@@ -9,8 +11,8 @@
"event": "Submit",
"idx": 0,
"is_standard": 1,
- "message": "<h3>{{_(\"Training Event\")}}</h3>\n\n<p>{{ doc.introduction }}</p>\n\n<h4>{{_(\"Details\")}}</h4>\n{{_(\"Event Name\")}}: {{ frappe.utils.get_link_to_form(doc.doctype, doc.name) }}\n<br>{{_(\"Event Location\")}}: {{ doc.location }}\n<br>{{_(\"Start Time\")}}: {{ doc.start_time }}\n<br>{{_(\"End Time\")}}: {{ doc.end_time }}\n",
- "modified": "2017-08-13 22:49:42.338881",
+ "message": "<table class=\"panel-header\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"100%\">\n <tr height=\"10\"></tr>\n <tr>\n <td width=\"15\"></td>\n <td>\n <div class=\"text-medium text-muted\">\n <span>{{_(\"Training Event:\")}} {{ doc.event_name }}</span>\n </div>\n </td>\n <td width=\"15\"></td>\n </tr>\n <tr height=\"10\"></tr>\n</table>\n\n<table class=\"panel-body\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"100%\">\n <tr height=\"10\"></tr>\n <tr>\n <td width=\"15\"></td>\n <td>\n <div>\n <ul class=\"list-unstyled\" style=\"line-height: 1.7\">\n <li>{{ doc.introduction }}</li>\n <li>{{_(\"Event Location\")}}: <b>{{ doc.location }}</b></li>\n {% set start = frappe.utils.get_datetime(doc.start_time) %}\n {% set end = frappe.utils.get_datetime(doc.end_time) %}\n {% if start.date() == end.date() %}\n <li>{{_(\"Date\")}}: <b>{{ start.strftime(\"%A, %d %b %Y\") }}</b></li>\n <li>\n {{_(\"Timing\")}}: <b>{{ start.strftime(\"%I:%M %p\") + ' to ' + end.strftime(\"%I:%M %p\") }}</b>\n </li>\n {% else %}\n <li>{{_(\"Start Time\")}}: <b>{{ start.strftime(\"%A, %d %b %Y at %I:%M %p\") }}</b>\n </li>\n <li>{{_(\"End Time\")}}: <b>{{ end.strftime(\"%A, %d %b %Y at %I:%M %p\") }}</b>\n </li>\n {% endif %}\n </ul>\n {{ _('Event Link') }}: {{ frappe.utils.get_link_to_form(doc.doctype, doc.name) }}\n </div>\n </td>\n <td width=\"15\"></td>\n </tr>\n <tr height=\"10\"></tr>\n</table>",
+ "modified": "2019-11-29 15:38:31.805409",
"modified_by": "Administrator",
"module": "HR",
"name": "Training Scheduled",
diff --git a/erpnext/hr/notification/training_scheduled/training_scheduled.md b/erpnext/hr/notification/training_scheduled/training_scheduled.md
index bcadf7d..374038a 100644
--- a/erpnext/hr/notification/training_scheduled/training_scheduled.md
+++ b/erpnext/hr/notification/training_scheduled/training_scheduled.md
@@ -1,9 +1,44 @@
-<h3>{{_("Training Event")}}</h3>
-<p>{{ message }}</p>
+<table class="panel-header" border="0" cellpadding="0" cellspacing="0" width="100%">
+ <tr height="10"></tr>
+ <tr>
+ <td width="15"></td>
+ <td>
+ <div class="text-medium text-muted">
+ <span>{{_("Training Event:")}} {{ doc.event_name }}</span>
+ </div>
+ </td>
+ <td width="15"></td>
+ </tr>
+ <tr height="10"></tr>
+</table>
-<h4>{{_("Details")}}</h4>
-{{_("Event Name")}}: <a href="{{ event_link }}">{{ name }}</a>
-<br>{{_("Event Location")}}: {{ location }}
-<br>{{_("Start Time")}}: {{ start_time }}
-<br>{{_("End Time")}}: {{ end_time }}
-<br>{{_("Attendance")}}: {{ attendance }}
+<table class="panel-body" border="0" cellpadding="0" cellspacing="0" width="100%">
+ <tr height="10"></tr>
+ <tr>
+ <td width="15"></td>
+ <td>
+ <div>
+ {{ doc.introduction }}
+ <ul class="list-unstyled" style="line-height: 1.7">
+ <li>{{_("Event Location")}}: <b>{{ doc.location }}</b></li>
+ {% set start = frappe.utils.get_datetime(doc.start_time) %}
+ {% set end = frappe.utils.get_datetime(doc.end_time) %}
+ {% if start.date() == end.date() %}
+ <li>{{_("Date")}}: <b>{{ start.strftime("%A, %d %b %Y") }}</b></li>
+ <li>
+ {{_("Timing")}}: <b>{{ start.strftime("%I:%M %p") + ' to ' + end.strftime("%I:%M %p") }}</b>
+ </li>
+ {% else %}
+ <li>{{_("Start Time")}}: <b>{{ start.strftime("%A, %d %b %Y at %I:%M %p") }}</b>
+ </li>
+ <li>{{_("End Time")}}: <b>{{ end.strftime("%A, %d %b %Y at %I:%M %p") }}</b>
+ </li>
+ {% endif %}
+ <li>{{ _('Event Link') }}: {{ frappe.utils.get_link_to_form(doc.doctype, doc.name) }}</li>
+ </ul>
+ </div>
+ </td>
+ <td width="15"></td>
+ </tr>
+ <tr height="10"></tr>
+</table>
\ No newline at end of file
diff --git a/erpnext/hr/report/department_analytics/department_analytics.js b/erpnext/hr/report/department_analytics/department_analytics.js
index a0b6fc7..29fedcd 100644
--- a/erpnext/hr/report/department_analytics/department_analytics.js
+++ b/erpnext/hr/report/department_analytics/department_analytics.js
@@ -2,4 +2,14 @@
// For license information, please see license.txt
frappe.query_reports["Department Analytics"] = {
+ "filters": [
+ {
+ "fieldname":"company",
+ "label": __("Company"),
+ "fieldtype": "Link",
+ "options": "Company",
+ "default": frappe.defaults.get_user_default("Company"),
+ "reqd": 1
+ },
+ ]
};
\ No newline at end of file
diff --git a/erpnext/hr/report/department_analytics/department_analytics.py b/erpnext/hr/report/department_analytics/department_analytics.py
index c4a9030..b28eac4 100644
--- a/erpnext/hr/report/department_analytics/department_analytics.py
+++ b/erpnext/hr/report/department_analytics/department_analytics.py
@@ -7,6 +7,10 @@
def execute(filters=None):
if not filters: filters = {}
+
+ if not filters["company"]:
+ frappe.throw(_('{0} is mandatory').format(_('Company')))
+
columns = get_columns()
employees = get_employees(filters)
departments_result = get_department(filters)
@@ -28,6 +32,9 @@
conditions = ""
if filters.get("department"): conditions += " and department = '%s'" % \
filters["department"].replace("'", "\\'")
+
+ if filters.get("company"): conditions += " and company = '%s'" % \
+ filters["company"].replace("'", "\\'")
return conditions
def get_employees(filters):
@@ -37,7 +44,7 @@
gender, company from `tabEmployee` where status = 'Active' %s""" % conditions, as_list=1)
def get_department(filters):
- return frappe.db.sql("""select name from `tabDepartment`""" , as_list=1)
+ return frappe.db.sql("""select name from `tabDepartment` where company = %s""", (filters["company"]), as_list=1)
def get_chart_data(departments,employees):
if not departments:
diff --git a/erpnext/hr/report/employee_leave_balance_summary/employee_leave_balance_summary.py b/erpnext/hr/report/employee_leave_balance_summary/employee_leave_balance_summary.py
index 15a5da0..777de02 100644
--- a/erpnext/hr/report/employee_leave_balance_summary/employee_leave_balance_summary.py
+++ b/erpnext/hr/report/employee_leave_balance_summary/employee_leave_balance_summary.py
@@ -75,7 +75,7 @@
leave_approvers = department_approver_map.get(employee.department_name, []).append(employee.leave_approver)
- if (len(leave_approvers) and user in leave_approvers) or (user in ["Administrator", employee.user_id]) \
+ if (leave_approvers and len(leave_approvers) and user in leave_approvers) or (user in ["Administrator", employee.user_id]) \
or ("HR Manager" in frappe.get_roles(user)):
row = frappe._dict({
'employee': employee.name,
@@ -111,10 +111,10 @@
def get_department_leave_approver_map(department=None):
conditions=''
if department:
- conditions='and department_name = %(department)s or parent_department = %(department)s'%{'department': department}
+ conditions="and (department_name = '%(department)s' or parent_department = '%(department)s')"%{'department': department}
# get current department and all its child
- department_list = frappe.db.sql_list(''' SELECT name FROM `tabDepartment` WHERE disabled=0 {0}'''.format(conditions)) #nosec
+ department_list = frappe.db.sql_list(""" SELECT name FROM `tabDepartment` WHERE disabled=0 {0}""".format(conditions)) #nosec
# retrieve approvers list from current department and from its subsequent child departments
approver_list = frappe.get_all('Department Approver', filters={
diff --git a/erpnext/hr/utils.py b/erpnext/hr/utils.py
index 1464a77..c3e8d27 100644
--- a/erpnext/hr/utils.py
+++ b/erpnext/hr/utils.py
@@ -321,11 +321,11 @@
if new_allocation == allocation.total_leaves_allocated:
continue
allocation.db_set("total_leaves_allocated", new_allocation, update_modified=False)
- create_earned_leave_ledger_entry(allocation, earned_leaves, today)
+ create_additional_leave_ledger_entry(allocation, earned_leaves, today)
-def create_earned_leave_ledger_entry(allocation, earned_leaves, date):
- ''' Create leave ledger entry based on the earned leave frequency '''
- allocation.new_leaves_allocated = earned_leaves
+def create_additional_leave_ledger_entry(allocation, leaves, date):
+ ''' Create leave ledger entry for leave types '''
+ allocation.new_leaves_allocated = leaves
allocation.from_date = date
allocation.unused_leaves = 0
allocation.create_leave_ledger_entry()
@@ -389,6 +389,7 @@
def get_holidays_for_employee(employee, start_date, end_date):
holiday_list = get_holiday_list_for_employee(employee)
+
holidays = frappe.db.sql_list('''select holiday_date from `tabHoliday`
where
parent=%(holiday_list)s
diff --git a/erpnext/hub_node/api.py b/erpnext/hub_node/api.py
index 0d01c67..2035174 100644
--- a/erpnext/hub_node/api.py
+++ b/erpnext/hub_node/api.py
@@ -70,7 +70,7 @@
field_mappings = get_field_mappings()
table_fields = [d.fieldname for d in frappe.get_meta('Item').get_table_fields()]
- hub_seller_name = frappe.db.get_value('Marketplace Settings' , 'Marketplace Settings', 'hub_seller_name')
+ hub_seller_name = frappe.db.get_value('Marketplace Settings', 'Marketplace Settings', 'hub_seller_name')
for item in items:
for fieldname in table_fields:
@@ -115,10 +115,21 @@
return valid_items
+@frappe.whitelist()
+def update_item(ref_doc, data):
+ data = json.loads(data)
+
+ data.update(dict(doctype='Hub Item', name=ref_doc))
+ try:
+ connection = get_hub_connection()
+ connection.update(data)
+ except Exception as e:
+ frappe.log_error(message=e, title='Hub Sync Error')
@frappe.whitelist()
def publish_selected_items(items_to_publish):
items_to_publish = json.loads(items_to_publish)
+ items_to_update = []
if not len(items_to_publish):
frappe.throw(_('No items to publish'))
@@ -126,14 +137,24 @@
item_code = item.get('item_code')
frappe.db.set_value('Item', item_code, 'publish_in_hub', 1)
- frappe.get_doc({
+ hub_dict = {
'doctype': 'Hub Tracked Item',
'item_code': item_code,
+ 'published': 1,
'hub_category': item.get('hub_category'),
'image_list': item.get('image_list')
- }).insert(ignore_if_duplicate=True)
+ }
+ if frappe.db.exists('Hub Tracked Item', item_code):
+ items_to_update.append(item)
+ hub_tracked_item = frappe.get_doc('Hub Tracked Item', item_code)
+ hub_tracked_item.update(hub_dict)
+ hub_tracked_item.save()
+ else:
+ frappe.get_doc(hub_dict).insert(ignore_if_duplicate=True)
- items = map_fields(items_to_publish)
+ items_to_publish = list(filter(lambda x: x not in items_to_update, items_to_publish))
+ new_items = map_fields(items_to_publish)
+ existing_items = map_fields(items_to_update)
try:
item_sync_preprocess(len(items))
@@ -141,13 +162,27 @@
# TODO: Publish Progress
connection = get_hub_connection()
- connection.insert_many(items)
+ connection.insert_many(new_items)
+ connection.bulk_update(existing_items)
item_sync_postprocess()
except Exception as e:
frappe.log_error(message=e, title='Hub Sync Error')
@frappe.whitelist()
+def unpublish_item(item_code, hub_item_name):
+ ''' Remove item listing from the marketplace '''
+
+ response = call_hub_method('unpublish_item', {
+ 'hub_item_name': hub_item_name
+ })
+
+ if response:
+ frappe.db.set_value('Item', item_code, 'publish_in_hub', 0)
+ else:
+ frappe.throw(_('Unable to update remote activity'))
+
+@frappe.whitelist()
def get_unregistered_users():
settings = frappe.get_single('Marketplace Settings')
registered_users = [user.user for user in settings.users] + ['Administrator', 'Guest']
diff --git a/erpnext/hub_node/doctype/hub_tracked_item/hub_tracked_item.json b/erpnext/hub_node/doctype/hub_tracked_item/hub_tracked_item.json
index 2e89887..7d07ba4 100644
--- a/erpnext/hub_node/doctype/hub_tracked_item/hub_tracked_item.json
+++ b/erpnext/hub_node/doctype/hub_tracked_item/hub_tracked_item.json
@@ -78,6 +78,38 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "published",
+ "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": "Published",
+ "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
+ },
+ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
@@ -120,7 +152,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2018-09-10 11:37:35.951019",
+ "modified": "2019-12-10 11:37:35.951019",
"modified_by": "Administrator",
"module": "Hub Node",
"name": "Hub Tracked Item",
diff --git a/erpnext/manufacturing/doctype/blanket_order/blanket_order.json b/erpnext/manufacturing/doctype/blanket_order/blanket_order.json
index 260e0b8..0330e5c 100644
--- a/erpnext/manufacturing/doctype/blanket_order/blanket_order.json
+++ b/erpnext/manufacturing/doctype/blanket_order/blanket_order.json
@@ -89,7 +89,8 @@
"fieldtype": "Link",
"label": "Company",
"options": "Company",
- "reqd": 1
+ "reqd": 1,
+ "search_index": 1
},
{
"fieldname": "section_break_12",
@@ -129,7 +130,7 @@
}
],
"is_submittable": 1,
- "modified": "2019-10-16 13:38:32.302316",
+ "modified": "2019-11-18 19:37:37.151686",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "Blanket Order",
diff --git a/erpnext/manufacturing/doctype/blanket_order/blanket_order.py b/erpnext/manufacturing/doctype/blanket_order/blanket_order.py
index faed707..38118bd 100644
--- a/erpnext/manufacturing/doctype/blanket_order/blanket_order.py
+++ b/erpnext/manufacturing/doctype/blanket_order/blanket_order.py
@@ -44,6 +44,8 @@
target.item_name = item.get("item_name")
target.description = item.get("description")
target.uom = item.get("stock_uom")
+ target.against_blanket_order = 1
+ target.blanket_order = source_name
target_doc = get_mapped_doc("Blanket Order", source_name, {
"Blanket Order": {
@@ -71,6 +73,8 @@
target.description = item.get("description")
target.uom = item.get("stock_uom")
target.warehouse = item.get("default_warehouse")
+ target.against_blanket_order = 1
+ target.blanket_order = source_name
target_doc = get_mapped_doc("Blanket Order", source_name, {
"Blanket Order": {
diff --git a/erpnext/manufacturing/doctype/blanket_order_item/blanket_order_item.json b/erpnext/manufacturing/doctype/blanket_order_item/blanket_order_item.json
index 099eed4..977ad54 100644
--- a/erpnext/manufacturing/doctype/blanket_order_item/blanket_order_item.json
+++ b/erpnext/manufacturing/doctype/blanket_order_item/blanket_order_item.json
@@ -1,298 +1,78 @@
{
- "allow_copy": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "beta": 0,
- "creation": "2018-05-24 07:20:04.255236",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "",
- "editable_grid": 1,
- "engine": "InnoDB",
+ "creation": "2018-05-24 07:20:04.255236",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "item_code",
+ "item_name",
+ "column_break_3",
+ "qty",
+ "rate",
+ "ordered_qty",
+ "section_break_7",
+ "terms_and_conditions"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "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": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Item Code",
- "length": 0,
- "no_copy": 0,
- "options": "Item",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "item_code",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Item Code",
+ "options": "Item",
+ "reqd": 1,
+ "search_index": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_from": "item_code.item_name",
- "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,
- "options": "",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fetch_from": "item_code.item_name",
+ "fieldname": "item_name",
+ "fieldtype": "Data",
+ "label": "Item Name"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_3",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "column_break_3",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "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": "Quantity",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "qty",
+ "fieldtype": "Float",
+ "in_list_view": 1,
+ "label": "Quantity"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "rate",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Rate",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "rate",
+ "fieldtype": "Currency",
+ "in_list_view": 1,
+ "label": "Rate",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "ordered_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": "Ordered Quantity",
- "length": 0,
- "no_copy": 1,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "ordered_qty",
+ "fieldtype": "Float",
+ "in_list_view": 1,
+ "label": "Ordered Quantity",
+ "no_copy": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "section_break_7",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "section_break_7",
+ "fieldtype": "Section Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "terms_and_conditions",
- "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": "Terms and Conditions",
- "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
+ "fieldname": "terms_and_conditions",
+ "fieldtype": "Text",
+ "label": "Terms and Conditions"
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 1,
- "max_attachments": 0,
- "modified": "2018-06-14 07:04:14.050836",
- "modified_by": "Administrator",
- "module": "Manufacturing",
- "name": "Blanket Order Item",
- "name_case": "",
- "owner": "Administrator",
- "permissions": [],
- "quick_entry": 1,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1,
- "track_seen": 0
+ ],
+ "istable": 1,
+ "modified": "2019-11-18 19:37:46.245878",
+ "modified_by": "Administrator",
+ "module": "Manufacturing",
+ "name": "Blanket Order Item",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
}
\ No newline at end of file
diff --git a/erpnext/manufacturing/doctype/bom/bom.js b/erpnext/manufacturing/doctype/bom/bom.js
index b9591d6..3acaee4 100644
--- a/erpnext/manufacturing/doctype/bom/bom.js
+++ b/erpnext/manufacturing/doctype/bom/bom.js
@@ -5,6 +5,11 @@
frappe.ui.form.on("BOM", {
setup: function(frm) {
+ frm.custom_make_buttons = {
+ 'Work Order': 'Work Order',
+ 'Quality Inspection': 'Quality Inspection'
+ };
+
frm.set_query("bom_no", "items", function() {
return {
filters: {
@@ -85,9 +90,17 @@
}
if(frm.doc.docstatus!=0) {
- frm.add_custom_button(__("Duplicate"), function() {
- frm.copy_doc();
- });
+ frm.add_custom_button(__("Work Order"), function() {
+ frm.trigger("make_work_order");
+ }, __("Create"));
+
+ if (frm.doc.inspection_required) {
+ frm.add_custom_button(__("Quality Inspection"), function() {
+ frm.trigger("make_quality_inspection");
+ }, __("Create"));
+ }
+
+ frm.page.set_inner_btn_group_as_primary(__('Create'));
}
if(frm.doc.items && frm.doc.allow_alternative_item) {
@@ -109,6 +122,41 @@
}
},
+ make_work_order: function(frm) {
+ const fields = [{
+ fieldtype: 'Float',
+ label: __('Qty To Manufacture'),
+ fieldname: 'qty',
+ reqd: 1,
+ default: 1
+ }];
+
+ frappe.prompt(fields, data => {
+ frappe.call({
+ method: "erpnext.manufacturing.doctype.work_order.work_order.make_work_order",
+ args: {
+ item: frm.doc.item,
+ qty: data.qty || 0.0,
+ project: frm.doc.project
+ },
+ freeze: true,
+ callback: function(r) {
+ if(r.message) {
+ var doc = frappe.model.sync(r.message)[0];
+ frappe.set_route("Form", doc.doctype, doc.name);
+ }
+ }
+ });
+ }, __("Enter Value"), __("Create"));
+ },
+
+ make_quality_inspection: function(frm) {
+ frappe.model.open_mapped_doc({
+ method: "erpnext.stock.doctype.quality_inspection.quality_inspection.make_quality_inspection",
+ frm: frm
+ })
+ },
+
update_cost: function(frm) {
return frappe.call({
doc: frm.doc,
diff --git a/erpnext/manufacturing/doctype/bom/bom.json b/erpnext/manufacturing/doctype/bom/bom.json
index a0faeb5..63f4f97 100644
--- a/erpnext/manufacturing/doctype/bom/bom.json
+++ b/erpnext/manufacturing/doctype/bom/bom.json
@@ -3,33 +3,36 @@
"creation": "2013-01-22 15:11:38",
"doctype": "DocType",
"document_type": "Setup",
+ "engine": "InnoDB",
"field_order": [
"item",
- "item_name",
- "image",
- "uom",
"quantity",
+ "set_rate_of_sub_assembly_item_based_on_bom",
"cb0",
"is_active",
"is_default",
- "with_operations",
- "inspection_required",
"allow_alternative_item",
- "allow_same_item_multiple_times",
- "set_rate_of_sub_assembly_item_based_on_bom",
- "quality_inspection_template",
+ "image",
+ "item_name",
+ "uom",
"currency_detail",
"company",
- "transfer_material_against",
+ "project",
"conversion_rate",
"column_break_12",
"currency",
"rm_cost_as_per",
"buying_price_list",
- "operations_section",
+ "section_break_21",
+ "with_operations",
+ "column_break_23",
+ "transfer_material_against",
"routing",
+ "operations_section",
"operations",
"materials_section",
+ "inspection_required",
+ "quality_inspection_template",
"items",
"scrap_section",
"scrap_items",
@@ -41,14 +44,9 @@
"base_operating_cost",
"base_raw_material_cost",
"base_scrap_material_cost",
- "total_cost_of_bom",
- "total_cost",
"column_break_26",
+ "total_cost",
"base_total_cost",
- "more_info_section",
- "project",
- "amended_from",
- "col_break23",
"section_break_25",
"description",
"column_break_27",
@@ -57,12 +55,14 @@
"website_section",
"show_in_website",
"route",
+ "column_break_52",
"website_image",
"thumbnail",
"sb_web_spec",
- "web_long_description",
"show_items",
- "show_operations"
+ "show_operations",
+ "web_long_description",
+ "amended_from"
],
"fields": [
{
@@ -152,7 +152,7 @@
"default": "0",
"fieldname": "inspection_required",
"fieldtype": "Check",
- "label": "Inspection Required"
+ "label": "Quality Inspection Required"
},
{
"default": "0",
@@ -161,12 +161,6 @@
"label": "Allow Alternative Item"
},
{
- "default": "0",
- "fieldname": "allow_same_item_multiple_times",
- "fieldtype": "Check",
- "label": "Allow Same Item Multiple Times"
- },
- {
"allow_on_submit": 1,
"default": "1",
"fieldname": "set_rate_of_sub_assembly_item_based_on_bom",
@@ -193,6 +187,7 @@
"reqd": 1
},
{
+ "default": "Work Order",
"fieldname": "transfer_material_against",
"fieldtype": "Select",
"label": "Transfer Material Against",
@@ -235,10 +230,10 @@
{
"fieldname": "operations_section",
"fieldtype": "Section Break",
- "label": "Operations",
"oldfieldtype": "Section Break"
},
{
+ "depends_on": "with_operations",
"fieldname": "routing",
"fieldtype": "Link",
"label": "Routing",
@@ -336,10 +331,6 @@
"read_only": 1
},
{
- "fieldname": "total_cost_of_bom",
- "fieldtype": "Section Break"
- },
- {
"fieldname": "total_cost",
"fieldtype": "Currency",
"in_list_view": 1,
@@ -360,10 +351,6 @@
"read_only": 1
},
{
- "fieldname": "more_info_section",
- "fieldtype": "Section Break"
- },
- {
"fieldname": "project",
"fieldtype": "Link",
"label": "Project",
@@ -382,10 +369,6 @@
"read_only": 1
},
{
- "fieldname": "col_break23",
- "fieldtype": "Column Break"
- },
- {
"fieldname": "section_break_25",
"fieldtype": "Section Break"
},
@@ -481,13 +464,26 @@
"fieldname": "show_operations",
"fieldtype": "Check",
"label": "Show Operations"
+ },
+ {
+ "fieldname": "section_break_21",
+ "fieldtype": "Section Break",
+ "label": "Operations"
+ },
+ {
+ "fieldname": "column_break_23",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "column_break_52",
+ "fieldtype": "Column Break"
}
],
"icon": "fa fa-sitemap",
"idx": 1,
"image_field": "image",
"is_submittable": 1,
- "modified": "2019-07-30 17:00:09.665068",
+ "modified": "2019-11-22 14:35:12.142150",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "BOM",
diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py
index c849f5b..7000d30 100644
--- a/erpnext/manufacturing/doctype/bom/bom.py
+++ b/erpnext/manufacturing/doctype/bom/bom.py
@@ -65,6 +65,7 @@
context.parents = [{'name': 'boms', 'title': _('All BOMs') }]
def on_update(self):
+ frappe.cache().hdel('bom_children', self.name)
self.check_recursion()
self.update_stock_qty()
self.update_exploded_items()
@@ -96,6 +97,7 @@
def get_routing(self):
if self.routing:
+ self.set("operations", [])
for d in frappe.get_all("BOM Operation", fields = ["*"],
filters = {'parenttype': 'Routing', 'parent': self.routing}):
child = self.append('operations', d)
@@ -289,7 +291,7 @@
if not valuation_rate:
valuation_rate = frappe.db.get_value("Item", args['item_code'], "valuation_rate")
- return valuation_rate
+ return flt(valuation_rate)
def manage_default_bom(self):
""" Uncheck others if current one is selected as default or
@@ -362,15 +364,9 @@
def validate_materials(self):
""" Validate raw material entries """
- def get_duplicates(lst):
- seen = set()
- seen_add = seen.add
- for item in lst:
- if item.item_code in seen or seen_add(item.item_code):
- yield item
-
if not self.get('items'):
frappe.throw(_("Raw Materials cannot be blank."))
+
check_list = []
for m in self.get('items'):
if m.bom_no:
@@ -379,16 +375,6 @@
frappe.throw(_("Quantity required for Item {0} in row {1}").format(m.item_code, m.idx))
check_list.append(m)
- if not self.allow_same_item_multiple_times:
- duplicate_items = list(get_duplicates(check_list))
- if duplicate_items:
- li = []
- for i in duplicate_items:
- li.append("{0} on row {1}".format(i.item_code, i.idx))
- duplicate_list = '<br>' + '<br>'.join(li)
-
- frappe.throw(_("Same item has been entered multiple times. {0}").format(duplicate_list))
-
def check_recursion(self, bom_list=[]):
""" Check whether recursion occurs in any bom"""
bom_list = self.traverse_tree()
@@ -420,8 +406,12 @@
def traverse_tree(self, bom_list=None):
def _get_children(bom_no):
- return frappe.db.sql_list("""select bom_no from `tabBOM Item`
- where parent = %s and ifnull(bom_no, '') != '' and parenttype='BOM'""", bom_no)
+ children = frappe.cache().hget('bom_children', bom_no)
+ if children is None:
+ children = frappe.db.sql_list("""SELECT `bom_no` FROM `tabBOM Item`
+ WHERE `parent`=%s AND `bom_no`!='' AND `parenttype`='BOM'""", bom_no)
+ frappe.cache().hset('bom_children', bom_no, children)
+ return children
count = 0
if not bom_list:
@@ -534,12 +524,24 @@
def get_child_exploded_items(self, bom_no, stock_qty):
""" Add all items from Flat BOM of child BOM"""
# Did not use qty_consumed_per_unit in the query, as it leads to rounding loss
- child_fb_items = frappe.db.sql("""select bom_item.item_code, bom_item.item_name,
- bom_item.description, bom_item.source_warehouse, bom_item.operation,
- bom_item.stock_uom, bom_item.stock_qty, bom_item.rate, bom_item.include_item_in_manufacturing,
- bom_item.stock_qty / ifnull(bom.quantity, 1) as qty_consumed_per_unit
- from `tabBOM Explosion Item` bom_item, tabBOM bom
- where bom_item.parent = bom.name and bom.name = %s and bom.docstatus = 1""", bom_no, as_dict = 1)
+ child_fb_items = frappe.db.sql("""
+ SELECT
+ bom_item.item_code,
+ bom_item.item_name,
+ bom_item.description,
+ bom_item.source_warehouse,
+ bom_item.operation,
+ bom_item.stock_uom,
+ bom_item.stock_qty,
+ bom_item.rate,
+ bom_item.include_item_in_manufacturing,
+ bom_item.stock_qty / ifnull(bom.quantity, 1) AS qty_consumed_per_unit
+ FROM `tabBOM Explosion Item` bom_item, tabBOM bom
+ WHERE
+ bom_item.parent = bom.name
+ AND bom.name = %s
+ AND bom.docstatus = 1
+ """, bom_no, as_dict = 1)
for d in child_fb_items:
self.add_to_cur_exploded_items(frappe._dict({
@@ -605,6 +607,7 @@
item.image,
bom.project,
item.stock_uom,
+ item.item_group,
item.allow_alternative_item,
item_default.default_warehouse,
item_default.expense_account as expense_account,
@@ -760,18 +763,21 @@
# Add non stock items cost in the additional cost
bom = frappe.get_doc('BOM', work_order.bom_no)
table = 'exploded_items' if work_order.get('use_multi_level_bom') else 'items'
+ expenses_included_in_valuation = frappe.get_cached_value("Company", work_order.company,
+ "expenses_included_in_valuation")
items = {}
for d in bom.get(table):
- items.setdefault(d.item_code, d.rate)
+ items.setdefault(d.item_code, d.amount)
non_stock_items = frappe.get_all('Item',
fields="name", filters={'name': ('in', list(items.keys())), 'ifnull(is_stock_item, 0)': 0}, as_list=1)
for name in non_stock_items:
stock_entry.append('additional_costs', {
+ 'expense_account': expenses_included_in_valuation,
'description': name[0],
- 'amount': items.get(name[0])
+ 'amount': flt(items.get(name[0])) * flt(stock_entry.fg_completed_qty) / flt(bom.quantity)
})
@frappe.whitelist()
diff --git a/erpnext/manufacturing/doctype/bom/bom_dashboard.py b/erpnext/manufacturing/doctype/bom/bom_dashboard.py
index 803ece7..361826e 100644
--- a/erpnext/manufacturing/doctype/bom/bom_dashboard.py
+++ b/erpnext/manufacturing/doctype/bom/bom_dashboard.py
@@ -17,11 +17,13 @@
},
{
'label': _('Manufacture'),
- 'items': ['BOM', 'Work Order', 'Job Card', 'Production Plan']
+ 'items': ['BOM', 'Work Order', 'Job Card']
},
{
- 'label': _('Purchase'),
+ 'label': _('Subcontract'),
'items': ['Purchase Order', 'Purchase Receipt', 'Purchase Invoice']
}
- ]
+ ],
+ 'disable_create_buttons': ["Item", "Purchase Order", "Purchase Receipt",
+ "Purchase Invoice", "Job Card", "Stock Entry", "BOM"]
}
diff --git a/erpnext/manufacturing/doctype/bom_item/bom_item.json b/erpnext/manufacturing/doctype/bom_item/bom_item.json
index febf315..f094be4 100644
--- a/erpnext/manufacturing/doctype/bom_item/bom_item.json
+++ b/erpnext/manufacturing/doctype/bom_item/bom_item.json
@@ -1,1053 +1,273 @@
{
- "allow_copy": 0,
- "allow_events_in_timeline": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "beta": 0,
"creation": "2013-02-22 01:27:49",
- "custom": 0,
- "docstatus": 0,
"doctype": "DocType",
"document_type": "Setup",
"editable_grid": 1,
+ "field_order": [
+ "item_code",
+ "item_name",
+ "operation",
+ "column_break_3",
+ "bom_no",
+ "source_warehouse",
+ "allow_alternative_item",
+ "section_break_5",
+ "description",
+ "col_break1",
+ "image",
+ "image_view",
+ "quantity_and_rate",
+ "qty",
+ "uom",
+ "col_break2",
+ "stock_qty",
+ "stock_uom",
+ "conversion_factor",
+ "rate_amount_section",
+ "rate",
+ "base_rate",
+ "column_break_21",
+ "amount",
+ "base_amount",
+ "section_break_18",
+ "scrap",
+ "qty_consumed_per_unit",
+ "section_break_27",
+ "include_item_in_manufacturing",
+ "original_item"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
"columns": 3,
"fieldname": "item_code",
"fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
"in_filter": 1,
- "in_global_search": 0,
"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": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
"reqd": 1,
- "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": 3,
"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,
- "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": "Item Name"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "operation",
"fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Item operation",
- "length": 0,
- "no_copy": 0,
- "options": "Operation",
- "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": "Operation"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "column_break_3",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "fieldtype": "Column Break"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "bom_no",
"fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
"in_filter": 1,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "BOM No",
- "length": 0,
- "no_copy": 0,
"oldfieldname": "bom_no",
"oldfieldtype": "Link",
"options": "BOM",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
"print_width": "150px",
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
"search_index": 1,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
"width": "150px"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "source_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": "Source Warehouse",
- "length": 0,
- "no_copy": 0,
- "options": "Warehouse",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "options": "Warehouse"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
"collapsible": 1,
- "columns": 0,
"fieldname": "section_break_5",
"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": "Description",
- "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": "Description"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "description",
"fieldtype": "Text Editor",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Item Description",
- "length": 0,
- "no_copy": 0,
"oldfieldname": "description",
"oldfieldtype": "Text",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
"print_width": "250px",
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
"width": "250px"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "col_break1",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "fieldtype": "Column Break"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "image",
"fieldtype": "Attach",
"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": "Image",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "print_hide": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "image_view",
"fieldtype": "Image",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Image View",
- "length": 0,
- "no_copy": 0,
- "options": "image",
- "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": "image"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "quantity_and_rate",
"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": "Quantity and Rate",
- "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": "Quantity and Rate"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
"columns": 2,
"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": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "reqd": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
"columns": 1,
"fieldname": "uom",
"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": "UOM",
- "length": 0,
- "no_copy": 0,
"options": "UOM",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "reqd": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "col_break2",
- "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": "stock_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": "Stock Qty",
- "length": 0,
- "no_copy": 0,
"oldfieldname": "stock_qty",
"oldfieldtype": "Currency",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "read_only": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "stock_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": "Stock UOM",
- "length": 0,
- "no_copy": 0,
"oldfieldname": "stock_uom",
"oldfieldtype": "Data",
"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,
- "translatable": 0,
- "unique": 0
+ "read_only": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "conversion_factor",
"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": "Conversion Factor",
- "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": "Conversion Factor"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "rate_amount_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": "Rate & Amount",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "label": "Rate & Amount"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "",
"fieldname": "rate",
"fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
"in_list_view": 1,
- "in_standard_filter": 0,
"label": "Rate",
- "length": 0,
- "no_copy": 0,
"options": "currency",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "reqd": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "base_rate",
"fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Basic Rate (Company Currency)",
- "length": 0,
- "no_copy": 0,
"options": "Company:company:default_currency",
- "permlevel": 0,
- "precision": "",
"print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "read_only": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "column_break_21",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "fieldtype": "Column Break"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "amount",
"fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
"in_list_view": 1,
- "in_standard_filter": 0,
"label": "Amount",
- "length": 0,
- "no_copy": 0,
"oldfieldname": "amount_as_per_mar",
"oldfieldtype": "Currency",
"options": "currency",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
"print_width": "150px",
"read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
"width": "150px"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "base_amount",
"fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Amount (Company Currency)",
- "length": 0,
- "no_copy": 0,
"options": "Company:company:default_currency",
- "permlevel": 0,
- "precision": "",
"print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "read_only": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "section_break_18",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "fieldtype": "Section Break"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
"columns": 1,
"fieldname": "scrap",
"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": "Scrap %",
- "length": 0,
- "no_copy": 0,
"oldfieldname": "scrap",
"oldfieldtype": "Currency",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
+ "print_hide": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "qty_consumed_per_unit",
"fieldtype": "Float",
"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": "Qty Consumed Per Unit",
- "length": 0,
- "no_copy": 0,
"oldfieldname": "qty_consumed_per_unit",
"oldfieldtype": "Float",
- "permlevel": 0,
"print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "read_only": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "section_break_27",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "fieldtype": "Section Break"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
+ "default": "0",
"fieldname": "allow_alternative_item",
"fieldtype": "Check",
- "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": "Allow Alternative Item",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "label": "Allow Alternative Item"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
+ "default": "0",
"fetch_from": "item_code.include_item_in_manufacturing",
"fieldname": "include_item_in_manufacturing",
"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 Item In Manufacturing",
- "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": "Include Item In Manufacturing"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "original_item",
"fieldtype": "Link",
"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": "Original Item",
- "length": 0,
- "no_copy": 0,
"options": "Item",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "read_only": 1
}
],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
"idx": 1,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
"istable": 1,
- "max_attachments": 0,
- "modified": "2019-02-21 19:19:54.872459",
+ "modified": "2019-11-22 11:38:52.087303",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "BOM Item",
"owner": "Administrator",
"permissions": [],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
"sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 0,
- "track_seen": 0,
- "track_views": 0
+ "sort_order": "DESC"
}
\ No newline at end of file
diff --git a/erpnext/manufacturing/doctype/bom_update_tool/bom_update_tool.py b/erpnext/manufacturing/doctype/bom_update_tool/bom_update_tool.py
index 87b8f67..31a9fdb 100644
--- a/erpnext/manufacturing/doctype/bom_update_tool/bom_update_tool.py
+++ b/erpnext/manufacturing/doctype/bom_update_tool/bom_update_tool.py
@@ -9,28 +9,30 @@
from six import string_types
from erpnext.manufacturing.doctype.bom.bom import get_boms_in_bottom_up_order
from frappe.model.document import Document
+import click
class BOMUpdateTool(Document):
def replace_bom(self):
self.validate_bom()
self.update_new_bom()
+ frappe.cache().delete_key('bom_children')
bom_list = self.get_parent_boms(self.new_bom)
updated_bom = []
-
+ with click.progressbar(bom_list) as bom_list:
+ pass
for bom in bom_list:
try:
- bom_obj = frappe.get_doc("BOM", bom)
- bom_obj.load_doc_before_save()
- updated_bom = bom_obj.update_cost_and_exploded_items(updated_bom)
+ bom_obj = frappe.get_cached_doc('BOM', bom)
+ # this is only used for versioning and we do not want
+ # to make separate db calls by using load_doc_before_save
+ # which proves to be expensive while doing bulk replace
+ bom_obj._doc_before_save = bom_obj.as_dict()
bom_obj.calculate_cost()
bom_obj.update_parent_cost()
bom_obj.db_update()
- if (getattr(bom_obj.meta, 'track_changes', False) and not bom_obj.flags.ignore_version):
+ if bom_obj.meta.get('track_changes') and not bom_obj.flags.ignore_version:
bom_obj.save_version()
-
- frappe.db.commit()
except Exception:
- frappe.db.rollback()
frappe.log_error(frappe.get_traceback())
def validate_bom(self):
@@ -42,22 +44,22 @@
frappe.throw(_("The selected BOMs are not for the same item"))
def update_new_bom(self):
- new_bom_unitcost = frappe.db.sql("""select total_cost/quantity
- from `tabBOM` where name = %s""", self.new_bom)
+ new_bom_unitcost = frappe.db.sql("""SELECT `total_cost`/`quantity`
+ FROM `tabBOM` WHERE name = %s""", self.new_bom)
new_bom_unitcost = flt(new_bom_unitcost[0][0]) if new_bom_unitcost else 0
frappe.db.sql("""update `tabBOM Item` set bom_no=%s,
rate=%s, amount=stock_qty*%s where bom_no = %s and docstatus < 2 and parenttype='BOM'""",
(self.new_bom, new_bom_unitcost, new_bom_unitcost, self.current_bom))
- def get_parent_boms(self, bom, bom_list=None):
- if not bom_list:
- bom_list = []
-
- data = frappe.db.sql(""" select distinct parent from `tabBOM Item`
- where bom_no = %s and docstatus < 2 and parenttype='BOM'""", bom)
+ def get_parent_boms(self, bom, bom_list=[]):
+ data = frappe.db.sql("""SELECT DISTINCT parent FROM `tabBOM Item`
+ WHERE bom_no = %s AND docstatus < 2 AND parenttype='BOM'""", bom)
for d in data:
+ if self.new_bom == d[0]:
+ frappe.throw(_("BOM recursion: {0} cannot be child of {1}").format(bom, self.new_bom))
+
bom_list.append(d[0])
self.get_parent_boms(d[0], bom_list)
diff --git a/erpnext/manufacturing/doctype/job_card/job_card.js b/erpnext/manufacturing/doctype/job_card/job_card.js
index 95549d5..bc8c229 100644
--- a/erpnext/manufacturing/doctype/job_card/job_card.js
+++ b/erpnext/manufacturing/doctype/job_card/job_card.js
@@ -3,6 +3,9 @@
frappe.ui.form.on('Job Card', {
refresh: function(frm) {
+ frappe.flags.pause_job = 0;
+ frappe.flags.resume_job = 0;
+
if(!frm.doc.__islocal && frm.doc.items && frm.doc.items.length) {
if (frm.doc.for_quantity != frm.doc.transferred_qty) {
frm.add_custom_button(__("Material Request"), () => {
@@ -13,44 +16,99 @@
if (frm.doc.for_quantity != frm.doc.transferred_qty) {
frm.add_custom_button(__("Material Transfer"), () => {
frm.trigger("make_stock_entry");
- });
+ }).addClass("btn-primary");
}
}
- if (frm.doc.docstatus == 0) {
- frm.trigger("make_dashboard");
+ if (frm.doc.docstatus == 0 && frm.doc.for_quantity > frm.doc.total_completed_qty
+ && (!frm.doc.items.length || frm.doc.for_quantity == frm.doc.transferred_qty)) {
+ frm.trigger("prepare_timer_buttons");
+ }
+ },
- if (!frm.doc.job_started) {
- frm.add_custom_button(__("Start Job"), () => {
- let row = frappe.model.add_child(frm.doc, 'Job Card Time Log', 'time_logs');
- row.from_time = frappe.datetime.now_datetime();
- frm.set_value('job_started', 1);
- frm.set_value('started_time' , row.from_time);
- frm.save();
- });
- } else {
- frm.add_custom_button(__("Complete Job"), () => {
- let completed_time = frappe.datetime.now_datetime();
- frm.doc.time_logs.forEach(d => {
- if (d.from_time && !d.to_time) {
- d.to_time = completed_time;
- frm.set_value('started_time' , '');
- frm.set_value('job_started', 0);
- frm.save();
+ prepare_timer_buttons: function(frm) {
+ frm.trigger("make_dashboard");
+ if (!frm.doc.job_started) {
+ frm.add_custom_button(__("Start"), () => {
+ if (!frm.doc.employee) {
+ frappe.prompt({fieldtype: 'Link', label: __('Employee'), options: "Employee",
+ fieldname: 'employee'}, d => {
+ if (d.employee) {
+ frm.set_value("employee", d.employee);
}
- })
- });
- }
+
+ frm.events.start_job(frm);
+ }, __("Enter Value"), __("Start"));
+ } else {
+ frm.events.start_job(frm);
+ }
+ }).addClass("btn-primary");
+ } else if (frm.doc.status == "On Hold") {
+ frm.add_custom_button(__("Resume"), () => {
+ frappe.flags.resume_job = 1;
+ frm.events.start_job(frm);
+ }).addClass("btn-primary");
+ } else {
+ frm.add_custom_button(__("Pause"), () => {
+ frappe.flags.pause_job = 1;
+ frm.set_value("status", "On Hold");
+ frm.events.complete_job(frm);
+ });
+
+ frm.add_custom_button(__("Complete"), () => {
+ let completed_time = frappe.datetime.now_datetime();
+ frm.trigger("hide_timer");
+
+ frappe.prompt({fieldtype: 'Float', label: __('Completed Quantity'),
+ fieldname: 'qty', reqd: 1, default: frm.doc.for_quantity}, data => {
+ frm.events.complete_job(frm, completed_time, data.qty);
+ }, __("Enter Value"), __("Complete"));
+ }).addClass("btn-primary");
}
},
+ start_job: function(frm) {
+ let row = frappe.model.add_child(frm.doc, 'Job Card Time Log', 'time_logs');
+ row.from_time = frappe.datetime.now_datetime();
+ frm.set_value('job_started', 1);
+ frm.set_value('started_time' , row.from_time);
+ frm.set_value("status", "Work In Progress");
+
+ if (!frappe.flags.resume_job) {
+ frm.set_value('current_time' , 0);
+ }
+
+ frm.save();
+ },
+
+ complete_job: function(frm, completed_time, completed_qty) {
+ frm.doc.time_logs.forEach(d => {
+ if (d.from_time && !d.to_time) {
+ d.to_time = completed_time || frappe.datetime.now_datetime();
+ d.completed_qty = completed_qty || 0;
+
+ if(frappe.flags.pause_job) {
+ let currentIncrement = moment(d.to_time).diff(moment(d.from_time),"seconds") || 0;
+ frm.set_value('current_time' , currentIncrement + (frm.doc.current_time || 0));
+ } else {
+ frm.set_value('started_time' , '');
+ frm.set_value('job_started', 0);
+ frm.set_value('current_time' , 0);
+ }
+
+ frm.save();
+ }
+ });
+ },
+
make_dashboard: function(frm) {
if(frm.doc.__islocal)
return;
frm.dashboard.refresh();
const timer = `
- <div class="stopwatch" style="font-weight:bold">
+ <div class="stopwatch" style="font-weight:bold;margin:0px 13px 0px 2px;
+ color:#545454;font-size:18px;display:inline-block;vertical-align:text-bottom;>
<span class="hours">00</span>
<span class="colon">:</span>
<span class="minutes">00</span>
@@ -58,11 +116,16 @@
<span class="seconds">00</span>
</div>`;
- var section = frm.dashboard.add_section(timer);
+ var section = frm.toolbar.page.add_inner_message(timer);
- if (frm.doc.started_time) {
- let currentIncrement = moment(frappe.datetime.now_datetime()).diff(moment(frm.doc.started_time),"seconds");
- initialiseTimer();
+ let currentIncrement = frm.doc.current_time || 0;
+ if (frm.doc.started_time || frm.doc.current_time) {
+ if (frm.doc.status == "On Hold") {
+ updateStopwatch(currentIncrement);
+ } else {
+ currentIncrement += moment(frappe.datetime.now_datetime()).diff(moment(frm.doc.started_time),"seconds");
+ initialiseTimer();
+ }
function initialiseTimer() {
const interval = setInterval(function() {
@@ -70,12 +133,12 @@
updateStopwatch(current);
}, 1000);
}
-
+
function updateStopwatch(increment) {
var hours = Math.floor(increment / 3600);
var minutes = Math.floor((increment - (hours * 3600)) / 60);
var seconds = increment - (hours * 3600) - (minutes * 60);
-
+
$(section).find(".hours").text(hours < 10 ? ("0" + hours.toString()) : hours.toString());
$(section).find(".minutes").text(minutes < 10 ? ("0" + minutes.toString()) : minutes.toString());
$(section).find(".seconds").text(seconds < 10 ? ("0" + seconds.toString()) : seconds.toString());
@@ -88,6 +151,10 @@
}
},
+ hide_timer: function(frm) {
+ frm.toolbar.page.inner_toolbar.find(".stopwatch").remove();
+ },
+
for_quantity: function(frm) {
frm.doc.items = [];
frm.call({
@@ -117,5 +184,22 @@
timer: function(frm) {
return `<button> Start </button>`
+ },
+
+ set_total_completed_qty: function(frm) {
+ frm.doc.total_completed_qty = 0;
+ frm.doc.time_logs.forEach(d => {
+ if (d.completed_qty) {
+ frm.doc.total_completed_qty += d.completed_qty;
+ }
+ });
+
+ refresh_field("total_completed_qty");
}
-});
\ No newline at end of file
+});
+
+frappe.ui.form.on('Job Card Time Log', {
+ completed_qty: function(frm) {
+ frm.events.set_total_completed_qty(frm);
+ }
+})
\ No newline at end of file
diff --git a/erpnext/manufacturing/doctype/job_card/job_card.json b/erpnext/manufacturing/doctype/job_card/job_card.json
index 39c5cce..156acce 100644
--- a/erpnext/manufacturing/doctype/job_card/job_card.json
+++ b/erpnext/manufacturing/doctype/job_card/job_card.json
@@ -1,1071 +1,350 @@
{
- "allow_copy": 0,
- "allow_events_in_timeline": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "autoname": "PO-JOB.#####",
- "beta": 0,
- "creation": "2018-07-09 17:23:29.518745",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "",
- "editable_grid": 1,
- "engine": "InnoDB",
+ "autoname": "naming_series:",
+ "creation": "2018-07-09 17:23:29.518745",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "naming_series",
+ "work_order",
+ "bom_no",
+ "workstation",
+ "operation",
+ "column_break_4",
+ "posting_date",
+ "company",
+ "remarks",
+ "production_section",
+ "production_item",
+ "item_name",
+ "for_quantity",
+ "wip_warehouse",
+ "column_break_12",
+ "employee",
+ "employee_name",
+ "status",
+ "project",
+ "timing_detail",
+ "time_logs",
+ "section_break_13",
+ "total_completed_qty",
+ "total_time_in_mins",
+ "column_break_15",
+ "section_break_8",
+ "items",
+ "more_information",
+ "operation_id",
+ "transferred_qty",
+ "requested_qty",
+ "column_break_20",
+ "barcode",
+ "job_started",
+ "started_time",
+ "current_time",
+ "amended_from"
+ ],
"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": "work_order",
- "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": "Work Order",
- "length": 0,
- "no_copy": 0,
- "options": "Work Order",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 1,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "work_order",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "in_standard_filter": 1,
+ "label": "Work Order",
+ "options": "Work Order",
+ "reqd": 1,
+ "search_index": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "bom_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": "BOM No",
- "length": 0,
- "no_copy": 0,
- "options": "BOM",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fetch_from": "work_order.bom_no",
+ "fieldname": "bom_no",
+ "fieldtype": "Link",
+ "label": "BOM No",
+ "options": "BOM",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "workstation",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Workstation",
- "length": 0,
- "no_copy": 0,
- "options": "Workstation",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "workstation",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Workstation",
+ "options": "Workstation",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "operation",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Operation",
- "length": 0,
- "no_copy": 0,
- "options": "Operation",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "operation",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Operation",
+ "options": "Operation",
+ "reqd": 1
+ },
{
- "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_4",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "column_break_4",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "Today",
- "fetch_if_empty": 0,
- "fieldname": "posting_date",
- "fieldtype": "Date",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Posting Date",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "default": "Today",
+ "fieldname": "posting_date",
+ "fieldtype": "Date",
+ "label": "Posting Date"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "company",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Company",
- "length": 0,
- "no_copy": 0,
- "options": "Company",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "label": "Company",
+ "options": "Company",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "for_quantity",
- "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": "For Quantity",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "for_quantity",
+ "fieldtype": "Float",
+ "in_list_view": 1,
+ "label": "Qty To Manufacture",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "wip_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": "WIP Warehouse",
- "length": 0,
- "no_copy": 0,
- "options": "Warehouse",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "wip_warehouse",
+ "fieldtype": "Link",
+ "label": "WIP Warehouse",
+ "options": "Warehouse",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "timing_detail",
- "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": "Timing Detail",
- "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
- },
+ "fieldname": "timing_detail",
+ "fieldtype": "Section Break",
+ "label": "Timing Detail"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "employee",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Employee",
- "length": 0,
- "no_copy": 0,
- "options": "Employee",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "employee",
+ "fieldtype": "Link",
+ "in_standard_filter": 1,
+ "label": "Employee",
+ "options": "Employee"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "time_logs",
- "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": "Time Logs",
- "length": 0,
- "no_copy": 0,
- "options": "Job Card Time Log",
- "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
- },
+ "fieldname": "time_logs",
+ "fieldtype": "Table",
+ "label": "Time Logs",
+ "options": "Job Card Time Log"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "section_break_13",
+ "fieldtype": "Section Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "total_completed_qty",
- "fieldtype": "Float",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Total Completed Qty",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "total_completed_qty",
+ "fieldtype": "Float",
+ "label": "Total Completed Qty",
+ "read_only": 1
+ },
{
- "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_15",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "column_break_15",
+ "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,
- "fieldname": "total_time_in_mins",
- "fieldtype": "Float",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Total Time in Mins",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "total_time_in_mins",
+ "fieldtype": "Float",
+ "label": "Total Time in Mins",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "section_break_8",
- "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": "Raw Materials",
- "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
- },
+ "fieldname": "section_break_8",
+ "fieldtype": "Section Break",
+ "label": "Raw Materials"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "items",
- "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": "Items",
- "length": 0,
- "no_copy": 0,
- "options": "Job Card Item",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "items",
+ "fieldtype": "Table",
+ "label": "Items",
+ "options": "Job Card Item",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "more_information",
- "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": "More Information",
- "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
- },
+ "collapsible": 1,
+ "fieldname": "more_information",
+ "fieldtype": "Section Break",
+ "label": "More Information"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "operation_id",
- "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": "Operation ID",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "operation_id",
+ "fieldtype": "Data",
+ "hidden": 1,
+ "label": "Operation ID",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "0",
- "fetch_if_empty": 0,
- "fieldname": "transferred_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": "Transferred Qty",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "default": "0",
+ "fieldname": "transferred_qty",
+ "fieldtype": "Float",
+ "label": "Transferred Qty",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "0",
- "fetch_if_empty": 0,
- "fieldname": "requested_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": "Requested Qty",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "default": "0",
+ "fieldname": "requested_qty",
+ "fieldtype": "Float",
+ "label": "Requested Qty",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "project",
- "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": "Project",
- "length": 0,
- "no_copy": 0,
- "options": "Project",
- "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
- },
+ "fieldname": "project",
+ "fieldtype": "Link",
+ "label": "Project",
+ "options": "Project"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "remarks",
- "fieldtype": "Small Text",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Remarks",
- "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
- },
+ "fieldname": "remarks",
+ "fieldtype": "Small Text",
+ "label": "Remarks"
+ },
{
- "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_20",
- "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
- },
+ "fieldname": "column_break_20",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "Open",
- "fetch_if_empty": 0,
- "fieldname": "status",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Status",
- "length": 0,
- "no_copy": 1,
- "options": "Open\nWork In Progress\nMaterial Transferred\nSubmitted\nCancelled\nCompleted",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "default": "Open",
+ "fieldname": "status",
+ "fieldtype": "Select",
+ "label": "Status",
+ "no_copy": 1,
+ "options": "Open\nWork In Progress\nMaterial Transferred\nOn Hold\nSubmitted\nCancelled\nCompleted",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "job_started",
- "fieldtype": "Check",
- "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": "Job Started",
- "length": 0,
- "no_copy": 1,
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "default": "0",
+ "fieldname": "job_started",
+ "fieldtype": "Check",
+ "hidden": 1,
+ "label": "Job Started",
+ "no_copy": 1,
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "started_time",
- "fieldtype": "Datetime",
- "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": "Started Time",
- "length": 0,
- "no_copy": 1,
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "started_time",
+ "fieldtype": "Datetime",
+ "hidden": 1,
+ "label": "Started Time",
+ "no_copy": 1,
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "amended_from",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Amended From",
- "length": 0,
- "no_copy": 1,
- "options": "Job Card",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "fieldname": "amended_from",
+ "fieldtype": "Link",
+ "label": "Amended From",
+ "no_copy": 1,
+ "options": "Job Card",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "default": "PO-JOB.#####",
+ "fieldname": "naming_series",
+ "fieldtype": "Select",
+ "label": "Naming Series",
+ "options": "PO-JOB.#####",
+ "reqd": 1
+ },
+ {
+ "fetch_from": "employee.employee_name",
+ "fieldname": "employee_name",
+ "fieldtype": "Read Only",
+ "label": "Employee Name"
+ },
+ {
+ "fieldname": "production_section",
+ "fieldtype": "Section Break",
+ "label": "Production"
+ },
+ {
+ "fieldname": "column_break_12",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fetch_from": "work_order.production_item",
+ "fieldname": "production_item",
+ "fieldtype": "Read Only",
+ "label": "Production Item"
+ },
+ {
+ "fieldname": "barcode",
+ "fieldtype": "Barcode",
+ "label": "Barcode",
+ "read_only": 1
+ },
+ {
+ "fetch_from": "work_order.item_name",
+ "fieldname": "item_name",
+ "fieldtype": "Read Only",
+ "label": "Item Name"
+ },
+ {
+ "fieldname": "current_time",
+ "fieldtype": "Int",
+ "hidden": 1,
+ "label": "Current Time",
+ "no_copy": 1,
+ "print_hide": 1,
+ "read_only": 1
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 1,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2019-03-10 17:38:37.499871",
- "modified_by": "Administrator",
- "module": "Manufacturing",
- "name": "Job Card",
- "name_case": "",
- "owner": "Administrator",
+ ],
+ "is_submittable": 1,
+ "modified": "2019-12-03 13:08:57.926201",
+ "modified_by": "Administrator",
+ "module": "Manufacturing",
+ "name": "Job Card",
+ "owner": "Administrator",
"permissions": [
{
- "amend": 1,
- "cancel": 1,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "System Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 1,
+ "amend": 1,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "System Manager",
+ "share": 1,
+ "submit": 1,
"write": 1
- },
+ },
{
- "amend": 1,
- "cancel": 1,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Manufacturing User",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 1,
+ "amend": 1,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Manufacturing User",
+ "share": 1,
+ "submit": 1,
"write": 1
- },
+ },
{
- "amend": 1,
- "cancel": 1,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Manufacturing Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 1,
+ "amend": 1,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Manufacturing Manager",
+ "share": 1,
+ "submit": 1,
"write": 1
}
- ],
- "quick_entry": 1,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "title_field": "operation",
- "track_changes": 1,
- "track_seen": 0,
- "track_views": 0
+ ],
+ "quick_entry": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "title_field": "operation",
+ "track_changes": 1
}
\ No newline at end of file
diff --git a/erpnext/manufacturing/doctype/job_card/job_card.py b/erpnext/manufacturing/doctype/job_card/job_card.py
index 9d2e620..9a2aaa5 100644
--- a/erpnext/manufacturing/doctype/job_card/job_card.py
+++ b/erpnext/manufacturing/doctype/job_card/job_card.py
@@ -4,10 +4,16 @@
from __future__ import unicode_literals
import frappe
+import datetime
from frappe import _
-from frappe.utils import flt, time_diff_in_hours, get_datetime
from frappe.model.mapper import get_mapped_doc
from frappe.model.document import Document
+from frappe.utils import (flt, cint, time_diff_in_hours, get_datetime, getdate,
+ get_time, add_to_date, time_diff, add_days, get_datetime_str)
+
+from erpnext.manufacturing.doctype.manufacturing_settings.manufacturing_settings import get_mins_between_operations
+
+class OverlapError(frappe.ValidationError): pass
class JobCard(Document):
def validate(self):
@@ -26,7 +32,7 @@
data = self.get_overlap_for(d)
if data:
frappe.throw(_("Row {0}: From Time and To Time of {1} is overlapping with {2}")
- .format(d.idx, self.name, data.name))
+ .format(d.idx, self.name, data.name), OverlapError)
if d.from_time and d.to_time:
d.time_in_mins = time_diff_in_hours(d.to_time, d.from_time) * 60
@@ -35,27 +41,120 @@
if d.completed_qty:
self.total_completed_qty += d.completed_qty
- def get_overlap_for(self, args):
- existing = frappe.db.sql("""select jc.name as name from
+ def get_overlap_for(self, args, check_next_available_slot=False):
+ production_capacity = 1
+
+ if self.workstation:
+ production_capacity = frappe.get_cached_value("Workstation",
+ self.workstation, 'production_capacity') or 1
+ validate_overlap_for = " and jc.workstation = %(workstation)s "
+
+ if self.employee:
+ # override capacity for employee
+ production_capacity = 1
+ validate_overlap_for = " and jc.employee = %(employee)s "
+
+ extra_cond = ''
+ if check_next_available_slot:
+ extra_cond = " or (%(from_time)s <= jctl.from_time and %(to_time)s <= jctl.to_time)"
+
+ existing = frappe.db.sql("""select jc.name as name, jctl.to_time from
`tabJob Card Time Log` jctl, `tabJob Card` jc where jctl.parent = jc.name and
(
(%(from_time)s > jctl.from_time and %(from_time)s < jctl.to_time) or
(%(to_time)s > jctl.from_time and %(to_time)s < jctl.to_time) or
- (%(from_time)s <= jctl.from_time and %(to_time)s >= jctl.to_time))
- and jctl.name!=%(name)s
- and jc.name!=%(parent)s
- and jc.docstatus < 2
- and jc.employee = %(employee)s """,
+ (%(from_time)s <= jctl.from_time and %(to_time)s >= jctl.to_time) {0}
+ )
+ and jctl.name != %(name)s and jc.name != %(parent)s and jc.docstatus < 2 {1}
+ order by jctl.to_time desc limit 1""".format(extra_cond, validate_overlap_for),
{
"from_time": args.from_time,
"to_time": args.to_time,
"name": args.name or "No Name",
"parent": args.parent or "No Name",
- "employee": self.employee
+ "employee": self.employee,
+ "workstation": self.workstation
}, as_dict=True)
+ if existing and production_capacity > len(existing):
+ return
+
return existing[0] if existing else None
+ def schedule_time_logs(self, row):
+ row.remaining_time_in_mins = row.time_in_mins
+ while row.remaining_time_in_mins > 0:
+ args = frappe._dict({
+ "from_time": row.planned_start_time,
+ "to_time": row.planned_end_time
+ })
+
+ self.validate_overlap_for_workstation(args, row)
+ self.check_workstation_time(row)
+
+ def validate_overlap_for_workstation(self, args, row):
+ # get the last record based on the to time from the job card
+ data = self.get_overlap_for(args, check_next_available_slot=True)
+ if data:
+ row.planned_start_time = get_datetime(data.to_time + get_mins_between_operations())
+
+ def check_workstation_time(self, row):
+ workstation_doc = frappe.get_cached_doc("Workstation", self.workstation)
+ if (not workstation_doc.working_hours or
+ cint(frappe.db.get_single_value("Manufacturing Settings", "allow_overtime"))):
+ row.remaining_time_in_mins -= time_diff_in_minutes(row.planned_end_time,
+ row.planned_start_time)
+
+ self.update_time_logs(row)
+ return
+
+ start_date = getdate(row.planned_start_time)
+ start_time = get_time(row.planned_start_time)
+
+ new_start_date = workstation_doc.validate_workstation_holiday(start_date)
+
+ if new_start_date != start_date:
+ row.planned_start_time = datetime.datetime.combine(new_start_date, start_time)
+ start_date = new_start_date
+
+ total_idx = len(workstation_doc.working_hours)
+
+ for i, time_slot in enumerate(workstation_doc.working_hours):
+ workstation_start_time = datetime.datetime.combine(start_date, get_time(time_slot.start_time))
+ workstation_end_time = datetime.datetime.combine(start_date, get_time(time_slot.end_time))
+
+ if (get_datetime(row.planned_start_time) >= workstation_start_time and
+ get_datetime(row.planned_start_time) <= workstation_end_time):
+ time_in_mins = time_diff_in_minutes(workstation_end_time, row.planned_start_time)
+
+ # If remaining time fit in workstation time logs else split hours as per workstation time
+ if time_in_mins > row.remaining_time_in_mins:
+ row.planned_end_time = add_to_date(row.planned_start_time,
+ minutes=row.remaining_time_in_mins)
+ row.remaining_time_in_mins = 0
+ else:
+ row.planned_end_time = add_to_date(row.planned_start_time, minutes=time_in_mins)
+ row.remaining_time_in_mins -= time_in_mins
+
+ self.update_time_logs(row)
+
+ if total_idx != (i+1) and row.remaining_time_in_mins > 0:
+ row.planned_start_time = datetime.datetime.combine(start_date,
+ get_time(workstation_doc.working_hours[i+1].start_time))
+
+ if row.remaining_time_in_mins > 0:
+ start_date = add_days(start_date, 1)
+ row.planned_start_time = datetime.datetime.combine(start_date,
+ get_time(workstation_doc.working_hours[0].start_time))
+
+ def update_time_logs(self, row):
+ self.append("time_logs", {
+ "from_time": row.planned_start_time,
+ "to_time": row.planned_end_time,
+ "completed_qty": 0,
+ "time_in_mins": time_diff_in_minutes(row.planned_end_time, row.planned_start_time),
+ })
+
def get_required_items(self):
if not self.get('work_order'):
return
@@ -95,8 +194,9 @@
if self.total_completed_qty <= 0.0:
frappe.throw(_("Total completed qty must be greater than zero"))
- if self.total_completed_qty > self.for_quantity:
- frappe.throw(_("Total completed qty can not be greater than for quantity"))
+ if self.total_completed_qty != self.for_quantity:
+ frappe.throw(_("The total completed qty({0}) must be equal to qty to manufacture({1})"
+ .format(frappe.bold(self.total_completed_qty),frappe.bold(self.for_quantity))))
def update_work_order(self):
if not self.work_order:
@@ -172,6 +272,8 @@
self.set_status(update_status)
def set_status(self, update_status=False):
+ if self.status == "On Hold": return
+
self.status = {
0: "Open",
1: "Submitted",
@@ -230,6 +332,7 @@
target.fg_completed_qty = source.get('for_quantity', 0) - source.get('transferred_qty', 0)
target.calculate_rate_and_amount()
target.set_missing_values()
+ target.set_stock_entry_type()
doclist = get_mapped_doc("Job Card", source_name, {
"Job Card": {
@@ -251,3 +354,48 @@
}, target_doc, set_missing_values)
return doclist
+
+def time_diff_in_minutes(string_ed_date, string_st_date):
+ return time_diff(string_ed_date, string_st_date).total_seconds() / 60
+
+@frappe.whitelist()
+def get_job_details(start, end, filters=None):
+ events = []
+
+ event_color = {
+ "Completed": "#cdf5a6",
+ "Material Transferred": "#ffdd9e",
+ "Work In Progress": "#D3D3D3"
+ }
+
+ from frappe.desk.reportview import get_filters_cond
+ conditions = get_filters_cond("Job Card", filters, [])
+
+ job_cards = frappe.db.sql(""" SELECT `tabJob Card`.name, `tabJob Card`.work_order,
+ `tabJob Card`.employee_name, `tabJob Card`.status, ifnull(`tabJob Card`.remarks, ''),
+ min(`tabJob Card Time Log`.from_time) as from_time,
+ max(`tabJob Card Time Log`.to_time) as to_time
+ FROM `tabJob Card` , `tabJob Card Time Log`
+ WHERE
+ `tabJob Card`.name = `tabJob Card Time Log`.parent {0}
+ group by `tabJob Card`.name""".format(conditions), as_dict=1)
+
+ for d in job_cards:
+ subject_data = []
+ for field in ["name", "work_order", "remarks", "employee_name"]:
+ if not d.get(field): continue
+
+ subject_data.append(d.get(field))
+
+ color = event_color.get(d.status)
+ job_card_data = {
+ 'from_time': d.from_time,
+ 'to_time': d.to_time,
+ 'name': d.name,
+ 'subject': '\n'.join(subject_data),
+ 'color': color if color else "#89bcde"
+ }
+
+ events.append(job_card_data)
+
+ return events
diff --git a/erpnext/manufacturing/doctype/job_card/job_card_calendar.js b/erpnext/manufacturing/doctype/job_card/job_card_calendar.js
new file mode 100644
index 0000000..cf07698
--- /dev/null
+++ b/erpnext/manufacturing/doctype/job_card/job_card_calendar.js
@@ -0,0 +1,21 @@
+frappe.views.calendar["Job Card"] = {
+ field_map: {
+ "start": "from_time",
+ "end": "to_time",
+ "id": "name",
+ "title": "subject",
+ "color": "color",
+ "allDay": "allDay",
+ "progress": "progress"
+ },
+ gantt: true,
+ filters: [
+ {
+ "fieldtype": "Link",
+ "fieldname": "employee",
+ "options": "Employee",
+ "label": __("Employee")
+ }
+ ],
+ get_events_method: "erpnext.manufacturing.doctype.job_card.job_card.get_job_details"
+};
diff --git a/erpnext/manufacturing/doctype/job_card_time_log/job_card_time_log.json b/erpnext/manufacturing/doctype/job_card_time_log/job_card_time_log.json
index 2aab71d..9dd54dd 100644
--- a/erpnext/manufacturing/doctype/job_card_time_log/job_card_time_log.json
+++ b/erpnext/manufacturing/doctype/job_card_time_log/job_card_time_log.json
@@ -1,208 +1,57 @@
{
- "allow_copy": 0,
- "allow_events_in_timeline": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "beta": 0,
- "creation": "2019-03-08 23:56:43.187569",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "",
- "editable_grid": 1,
- "engine": "InnoDB",
+ "creation": "2019-03-08 23:56:43.187569",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "from_time",
+ "to_time",
+ "column_break_2",
+ "time_in_mins",
+ "completed_qty"
+ ],
"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": "from_time",
- "fieldtype": "Datetime",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "From Time",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "from_time",
+ "fieldtype": "Datetime",
+ "in_list_view": 1,
+ "label": "From Time"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "to_time",
- "fieldtype": "Datetime",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "To Time",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "to_time",
+ "fieldtype": "Datetime",
+ "in_list_view": 1,
+ "label": "To Time"
+ },
{
- "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_2",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "column_break_2",
+ "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,
- "fieldname": "time_in_mins",
- "fieldtype": "Float",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Time In Mins",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "time_in_mins",
+ "fieldtype": "Float",
+ "in_list_view": 1,
+ "label": "Time In Mins",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "0",
- "fetch_if_empty": 0,
- "fieldname": "completed_qty",
- "fieldtype": "Float",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Completed Qty",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "default": "0",
+ "fieldname": "completed_qty",
+ "fieldtype": "Float",
+ "in_list_view": 1,
+ "label": "Completed Qty",
+ "reqd": 1
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 1,
- "max_attachments": 0,
- "modified": "2019-03-10 17:08:46.504910",
- "modified_by": "Administrator",
- "module": "Manufacturing",
- "name": "Job Card Time Log",
- "name_case": "",
- "owner": "Administrator",
- "permissions": [],
- "quick_entry": 1,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
- "sort_field": "modified",
- "sort_order": "ASC",
- "track_changes": 1,
- "track_seen": 0,
- "track_views": 0
+ ],
+ "istable": 1,
+ "modified": "2019-12-03 12:56:02.285448",
+ "modified_by": "Administrator",
+ "module": "Manufacturing",
+ "name": "Job Card Time Log",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "sort_field": "modified",
+ "sort_order": "ASC",
+ "track_changes": 1
}
\ No newline at end of file
diff --git a/erpnext/manufacturing/doctype/manufacturing_settings/manufacturing_settings.json b/erpnext/manufacturing/doctype/manufacturing_settings/manufacturing_settings.json
index 461b9ab..86fa7a8 100644
--- a/erpnext/manufacturing/doctype/manufacturing_settings/manufacturing_settings.json
+++ b/erpnext/manufacturing/doctype/manufacturing_settings/manufacturing_settings.json
@@ -1,585 +1,178 @@
{
- "allow_copy": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "beta": 0,
- "creation": "2014-11-27 14:12:07.542534",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "Document",
- "editable_grid": 0,
- "engine": "InnoDB",
+ "creation": "2014-11-27 14:12:07.542534",
+ "doctype": "DocType",
+ "document_type": "Document",
+ "engine": "InnoDB",
+ "field_order": [
+ "raw_materials_consumption_section",
+ "material_consumption",
+ "column_break_3",
+ "backflush_raw_materials_based_on",
+ "capacity_planning",
+ "disable_capacity_planning",
+ "allow_overtime",
+ "allow_production_on_holidays",
+ "column_break_5",
+ "capacity_planning_for_days",
+ "mins_between_operations",
+ "section_break_6",
+ "default_wip_warehouse",
+ "default_fg_warehouse",
+ "column_break_11",
+ "default_scrap_warehouse",
+ "over_production_for_sales_and_work_order_section",
+ "overproduction_percentage_for_sales_order",
+ "column_break_16",
+ "overproduction_percentage_for_work_order",
+ "other_settings_section",
+ "update_bom_costs_automatically"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "capacity_planning",
- "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": "Capacity Planning",
- "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
- },
+ "fieldname": "capacity_planning",
+ "fieldtype": "Section Break",
+ "label": "Capacity Planning"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "Disables creation of time logs against Work Orders. Operations shall not be tracked against Work Order",
- "fieldname": "disable_capacity_planning",
- "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": "Disable Capacity Planning and Time Tracking",
- "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
- },
+ "default": "0",
+ "depends_on": "eval:!doc.disable_capacity_planning",
+ "description": "Plan time logs outside Workstation Working Hours.",
+ "fieldname": "allow_overtime",
+ "fieldtype": "Check",
+ "label": "Allow Overtime"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "Plan time logs outside Workstation Working Hours.",
- "fieldname": "allow_overtime",
- "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 Overtime",
- "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
- },
+ "default": "0",
+ "depends_on": "eval:!doc.disable_capacity_planning",
+ "fieldname": "allow_production_on_holidays",
+ "fieldtype": "Check",
+ "in_list_view": 1,
+ "label": "Allow Production on Holidays"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "",
- "fieldname": "allow_production_on_holidays",
- "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": "Allow Production on Holidays",
- "length": 0,
- "no_copy": 0,
- "options": "",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "column_break_3",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_3",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "default": "30",
+ "depends_on": "eval:!doc.disable_capacity_planning",
+ "description": "Try planning operations for X days in advance.",
+ "fieldname": "capacity_planning_for_days",
+ "fieldtype": "Int",
+ "label": "Capacity Planning For (Days)"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "30",
- "description": "Try planning operations for X days in advance.",
- "fieldname": "capacity_planning_for_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": "Capacity Planning For (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
- },
+ "depends_on": "eval:!doc.disable_capacity_planning",
+ "description": "Default 10 mins",
+ "fieldname": "mins_between_operations",
+ "fieldtype": "Int",
+ "label": "Time Between Operations (in mins)"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "Default 10 mins",
- "fieldname": "mins_between_operations",
- "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": "Time Between Operations (in mins)",
- "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
- },
+ "fieldname": "section_break_6",
+ "fieldtype": "Section Break",
+ "label": "Default Warehouses for Production"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "section_break_6",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "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
- },
+ "fieldname": "overproduction_percentage_for_sales_order",
+ "fieldtype": "Percent",
+ "label": "Overproduction Percentage For Sales Order"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "overproduction_percentage_for_sales_order",
- "fieldtype": "Percent",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Overproduction Percentage For Sales Order",
- "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
- },
+ "fieldname": "overproduction_percentage_for_work_order",
+ "fieldtype": "Percent",
+ "label": "Overproduction Percentage For Work Order"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "overproduction_percentage_for_work_order",
- "fieldtype": "Percent",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Overproduction Percentage For Work Order",
- "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
- },
+ "default": "BOM",
+ "fieldname": "backflush_raw_materials_based_on",
+ "fieldtype": "Select",
+ "label": "Backflush Raw Materials Based On",
+ "options": "BOM\nMaterial Transferred for Manufacture"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "BOM",
- "fieldname": "backflush_raw_materials_based_on",
- "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": "Backflush Raw Materials Based On",
- "length": 0,
- "no_copy": 0,
- "options": "BOM\nMaterial Transferred for Manufacture",
- "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
- },
+ "default": "0",
+ "description": "Allow multiple Material Consumption against a Work Order",
+ "fieldname": "material_consumption",
+ "fieldtype": "Check",
+ "label": "Allow Multiple Material Consumption"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "Allow multiple Material Consumption against a Work Order",
- "fieldname": "material_consumption",
- "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 Multiple Material Consumption",
- "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
- },
+ "default": "0",
+ "description": "Update BOM cost automatically via Scheduler, based on latest valuation rate / price list rate / last purchase rate of raw materials.",
+ "fieldname": "update_bom_costs_automatically",
+ "fieldtype": "Check",
+ "label": "Update BOM Cost Automatically"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "Update BOM cost automatically via Scheduler, based on latest valuation rate / price list rate / last purchase rate of raw materials.",
- "fieldname": "update_bom_costs_automatically",
- "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": "Update BOM Cost Automatically",
- "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
- },
+ "fieldname": "column_break_11",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_11",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "default_wip_warehouse",
+ "fieldtype": "Link",
+ "label": "Default Work In Progress Warehouse",
+ "options": "Warehouse"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "default_wip_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": "Default Work In Progress Warehouse",
- "length": 0,
- "no_copy": 0,
- "options": "Warehouse",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "default_fg_warehouse",
+ "fieldtype": "Link",
+ "label": "Default Finished Goods Warehouse",
+ "options": "Warehouse"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "default_fg_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": "Default Finished Goods Warehouse",
- "length": 0,
- "no_copy": 0,
- "options": "Warehouse",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "default": "0",
+ "fieldname": "disable_capacity_planning",
+ "fieldtype": "Check",
+ "label": "Disable Capacity Planning"
+ },
+ {
+ "fieldname": "default_scrap_warehouse",
+ "fieldtype": "Link",
+ "label": "Default Scrap Warehouse",
+ "options": "Warehouse"
+ },
+ {
+ "fieldname": "over_production_for_sales_and_work_order_section",
+ "fieldtype": "Section Break",
+ "label": "Over Production for Sales and Work Order"
+ },
+ {
+ "fieldname": "raw_materials_consumption_section",
+ "fieldtype": "Section Break",
+ "label": "Raw Materials Consumption"
+ },
+ {
+ "fieldname": "column_break_16",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "other_settings_section",
+ "fieldtype": "Section Break",
+ "label": "Other Settings"
+ },
+ {
+ "fieldname": "column_break_5",
+ "fieldtype": "Column Break"
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "icon": "icon-wrench",
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 1,
- "istable": 0,
- "max_attachments": 0,
- "menu_index": 0,
- "modified": "2018-05-28 00:46:25.310621",
- "modified_by": "Administrator",
- "module": "Manufacturing",
- "name": "Manufacturing Settings",
- "name_case": "",
- "owner": "Administrator",
+ ],
+ "icon": "icon-wrench",
+ "issingle": 1,
+ "modified": "2019-11-26 13:10:45.569341",
+ "modified_by": "Administrator",
+ "module": "Manufacturing",
+ "name": "Manufacturing Settings",
+ "owner": "Administrator",
"permissions": [
{
- "amend": 0,
- "cancel": 0,
- "create": 1,
- "delete": 0,
- "email": 0,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 0,
- "read": 1,
- "report": 0,
- "role": "Manufacturing Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
+ "create": 1,
+ "read": 1,
+ "role": "Manufacturing Manager",
+ "share": 1,
"write": 1
}
- ],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1,
- "track_seen": 0
+ ],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
}
\ No newline at end of file
diff --git a/erpnext/manufacturing/doctype/material_request_plan_item/material_request_plan_item.json b/erpnext/manufacturing/doctype/material_request_plan_item/material_request_plan_item.json
index 39d59f0..f27197d 100644
--- a/erpnext/manufacturing/doctype/material_request_plan_item/material_request_plan_item.json
+++ b/erpnext/manufacturing/doctype/material_request_plan_item/material_request_plan_item.json
@@ -1,443 +1,135 @@
{
- "allow_copy": 0,
- "allow_events_in_timeline": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "beta": 0,
- "creation": "2017-12-01 12:12:55.048691",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "",
- "editable_grid": 1,
- "engine": "InnoDB",
+ "creation": "2017-12-01 12:12:55.048691",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "item_code",
+ "item_name",
+ "warehouse",
+ "material_request_type",
+ "column_break_4",
+ "quantity",
+ "uom",
+ "projected_qty",
+ "actual_qty",
+ "item_details",
+ "description",
+ "min_order_qty",
+ "section_break_8",
+ "sales_order",
+ "requested_qty"
+ ],
"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": "item_code",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Item Code",
- "length": 0,
- "no_copy": 0,
- "options": "Item",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "item_code",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Item Code",
+ "options": "Item",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 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,
- "options": "",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "item_name",
+ "fieldtype": "Data",
+ "label": "Item Name"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 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": 1,
- "in_standard_filter": 1,
- "label": "Warehouse",
- "length": 0,
- "no_copy": 0,
- "options": "Warehouse",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "warehouse",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "in_standard_filter": 1,
+ "label": "Warehouse",
+ "options": "Warehouse",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "material_request_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": 0,
- "label": "Material Request Type",
- "length": 0,
- "no_copy": 0,
- "options": "\nPurchase\nMaterial Transfer\nMaterial Issue\nManufacture\nCustomer Provided",
- "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
- },
+ "fieldname": "material_request_type",
+ "fieldtype": "Select",
+ "label": "Material Request Type",
+ "options": "\nPurchase\nMaterial Transfer\nMaterial Issue\nManufacture\nCustomer Provided"
+ },
{
- "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_4",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "column_break_4",
+ "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,
- "fieldname": "quantity",
- "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": "Required Quantity",
- "length": 0,
- "no_copy": 1,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "quantity",
+ "fieldtype": "Float",
+ "in_list_view": 1,
+ "label": "Required Quantity",
+ "no_copy": 1,
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 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": 1,
- "in_standard_filter": 0,
- "label": "Projected Qty",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "projected_qty",
+ "fieldtype": "Float",
+ "in_list_view": 1,
+ "label": "Projected Qty",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "collapsible_depends_on": "",
- "columns": 0,
- "depends_on": "",
- "fetch_if_empty": 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": 1,
- "in_standard_filter": 0,
- "label": "Actual Qty",
- "length": 0,
- "no_copy": 1,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "actual_qty",
+ "fieldtype": "Float",
+ "in_list_view": 1,
+ "label": "Actual Qty",
+ "no_copy": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "min_order_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": "Minimum Order Quantity",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "min_order_qty",
+ "fieldtype": "Float",
+ "in_list_view": 1,
+ "label": "Minimum Order Quantity",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "section_break_8",
- "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": "Reference",
- "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
- },
+ "collapsible": 1,
+ "fieldname": "section_break_8",
+ "fieldtype": "Section Break",
+ "label": "Reference"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "sales_order",
- "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": "Sales Order",
- "length": 0,
- "no_copy": 0,
- "options": "Sales Order",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "sales_order",
+ "fieldtype": "Link",
+ "label": "Sales Order",
+ "options": "Sales Order",
+ "read_only": 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": "requested_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": "Requested Qty",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "fieldname": "requested_qty",
+ "fieldtype": "Float",
+ "label": "Requested Qty",
+ "read_only": 1
+ },
+ {
+ "collapsible": 1,
+ "fieldname": "item_details",
+ "fieldtype": "Section Break",
+ "label": "Item Description"
+ },
+ {
+ "fieldname": "description",
+ "fieldtype": "Text Editor",
+ "label": "Description"
+ },
+ {
+ "fieldname": "uom",
+ "fieldtype": "Link",
+ "label": "UOM",
+ "options": "UOM",
+ "read_only": 1
}
- ],
- "has_web_view": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 1,
- "max_attachments": 0,
- "modified": "2019-04-08 18:15:26.849602",
- "modified_by": "Administrator",
- "module": "Manufacturing",
- "name": "Material Request Plan Item",
- "name_case": "",
- "owner": "Administrator",
- "permissions": [],
- "quick_entry": 1,
- "read_only": 0,
- "show_name_in_global_search": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1,
- "track_seen": 0,
- "track_views": 0
+ ],
+ "istable": 1,
+ "modified": "2019-11-08 15:15:43.979360",
+ "modified_by": "Administrator",
+ "module": "Manufacturing",
+ "name": "Material Request Plan Item",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
}
\ No newline at end of file
diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.js b/erpnext/manufacturing/doctype/production_plan/production_plan.js
index 4b654b4..2b168d1 100644
--- a/erpnext/manufacturing/doctype/production_plan/production_plan.js
+++ b/erpnext/manufacturing/doctype/production_plan/production_plan.js
@@ -3,6 +3,11 @@
frappe.ui.form.on('Production Plan', {
setup: function(frm) {
+ frm.custom_make_buttons = {
+ 'Work Order': 'Work Order',
+ 'Material Request': 'Material Request',
+ };
+
frm.fields_dict['po_items'].grid.get_field('warehouse').get_query = function(doc) {
return {
filters: {
@@ -66,12 +71,13 @@
}, __('Create'));
}
+ frm.page.set_inner_btn_group_as_primary(__('Create'));
frm.trigger("material_requirement");
const projected_qty_formula = ` <table class="table table-bordered" style="background-color: #f9f9f9;">
<tr><td style="padding-left:25px">
<div>
- <h3>
+ <h3 style="text-decoration: underline;">
<a href = "https://erpnext.com/docs/user/manual/en/stock/projected-quantity">
${__("Projected Quantity Formula")}
</a>
@@ -182,8 +188,8 @@
},
get_items_for_mr: function(frm) {
- const set_fields = ['actual_qty', 'item_code',
- 'item_name', 'min_order_qty', 'quantity', 'sales_order', 'warehouse', 'projected_qty', 'material_request_type'];
+ const set_fields = ['actual_qty', 'item_code','item_name', 'description', 'uom',
+ 'min_order_qty', 'quantity', 'sales_order', 'warehouse', 'projected_qty', 'material_request_type'];
frappe.call({
method: "erpnext.manufacturing.doctype.production_plan.production_plan.get_items_for_material_requests",
freeze: true,
@@ -233,7 +239,7 @@
if (item_wise_qty) {
for (var key in item_wise_qty) {
- title += __('Item {0}: {1} qty produced, ', [key, item_wise_qty[key]]);
+ title += __('Item {0}: {1} qty produced. ', [key, item_wise_qty[key]]);
}
}
diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.json b/erpnext/manufacturing/doctype/production_plan/production_plan.json
index 0be9f1a..af84481 100644
--- a/erpnext/manufacturing/doctype/production_plan/production_plan.json
+++ b/erpnext/manufacturing/doctype/production_plan/production_plan.json
@@ -1,1391 +1,321 @@
{
- "allow_copy": 0,
- "allow_events_in_timeline": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "autoname": "naming_series:",
- "beta": 0,
- "creation": "2017-10-29 11:53:09.523362",
- "custom": 0,
- "default_print_format": "",
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "Document",
- "editable_grid": 0,
- "engine": "InnoDB",
+ "actions": [],
+ "autoname": "naming_series:",
+ "creation": "2017-10-29 11:53:09.523362",
+ "doctype": "DocType",
+ "document_type": "Document",
+ "engine": "InnoDB",
+ "field_order": [
+ "naming_series",
+ "company",
+ "get_items_from",
+ "column_break1",
+ "posting_date",
+ "filters",
+ "item_code",
+ "customer",
+ "warehouse",
+ "project",
+ "column_break2",
+ "from_date",
+ "to_date",
+ "sales_orders_detail",
+ "get_sales_orders",
+ "sales_orders",
+ "material_request_detail",
+ "get_material_request",
+ "material_requests",
+ "select_items_to_manufacture_section",
+ "get_items",
+ "po_items",
+ "material_request_planning",
+ "include_non_stock_items",
+ "include_subcontracted_items",
+ "ignore_existing_ordered_qty",
+ "column_break_25",
+ "for_warehouse",
+ "download_materials_required",
+ "get_items_for_mr",
+ "section_break_27",
+ "mr_items",
+ "other_details",
+ "total_planned_qty",
+ "total_produced_qty",
+ "column_break_32",
+ "status",
+ "amended_from"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "",
- "fetch_if_empty": 0,
- "fieldname": "naming_series",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Naming Series",
- "length": 0,
- "no_copy": 0,
- "options": "MFG-PP-.YYYY.-",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "naming_series",
+ "fieldtype": "Select",
+ "label": "Naming Series",
+ "options": "MFG-PP-.YYYY.-",
+ "reqd": 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": "company",
- "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": "Company",
- "length": 0,
- "no_copy": 0,
- "options": "Company",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Company",
+ "options": "Company",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "",
- "fetch_if_empty": 0,
- "fieldname": "get_items_from",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Get Items From",
- "length": 0,
- "no_copy": 0,
- "options": "\nSales Order\nMaterial Request",
- "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
- },
+ "fieldname": "get_items_from",
+ "fieldtype": "Select",
+ "in_list_view": 1,
+ "label": "Get Items From",
+ "options": "\nSales Order\nMaterial Request"
+ },
{
- "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_break1",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "column_break1",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "Today",
- "fetch_if_empty": 0,
- "fieldname": "posting_date",
- "fieldtype": "Date",
- "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": "Posting Date",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "default": "Today",
+ "fieldname": "posting_date",
+ "fieldtype": "Date",
+ "in_list_view": 1,
+ "label": "Posting Date",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "collapsible_depends_on": "eval: doc.__islocal",
- "columns": 0,
- "depends_on": "eval: doc.get_items_from",
- "description": "",
- "fetch_if_empty": 0,
- "fieldname": "filters",
- "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": "Filters",
- "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
- },
+ "collapsible": 1,
+ "collapsible_depends_on": "eval: doc.__islocal",
+ "depends_on": "eval: doc.get_items_from",
+ "fieldname": "filters",
+ "fieldtype": "Section Break",
+ "label": "Filters"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "item_code",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Item Code",
- "length": 0,
- "no_copy": 0,
- "options": "Item",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "item_code",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Item Code",
+ "options": "Item"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval: doc.get_items_from == \"Sales Order\"",
- "fetch_if_empty": 0,
- "fieldname": "customer",
- "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": "Customer",
- "length": 0,
- "no_copy": 0,
- "options": "Customer",
- "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
- },
+ "depends_on": "eval: doc.get_items_from == \"Sales Order\"",
+ "fieldname": "customer",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Customer",
+ "options": "Customer"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval: doc.get_items_from == \"Material Request\"",
- "fetch_if_empty": 0,
- "fieldname": "warehouse",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Warehouse",
- "length": 0,
- "no_copy": 0,
- "options": "Warehouse",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "depends_on": "eval: doc.get_items_from == \"Material Request\"",
+ "fieldname": "warehouse",
+ "fieldtype": "Link",
+ "label": "Warehouse",
+ "options": "Warehouse"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval: doc.get_items_from == \"Sales Order\"",
- "fetch_if_empty": 0,
- "fieldname": "project",
- "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": "Project",
- "length": 0,
- "no_copy": 0,
- "options": "Project",
- "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
- },
+ "depends_on": "eval: doc.get_items_from == \"Sales Order\"",
+ "fieldname": "project",
+ "fieldtype": "Link",
+ "label": "Project",
+ "options": "Project"
+ },
{
- "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_break2",
- "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,
+ "fieldname": "column_break2",
+ "fieldtype": "Column Break",
"width": "50%"
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "from_date",
- "fieldtype": "Date",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "From Date",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "from_date",
+ "fieldtype": "Date",
+ "label": "From Date"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "to_date",
- "fieldtype": "Date",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "To Date",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "to_date",
+ "fieldtype": "Date",
+ "label": "To Date"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "collapsible_depends_on": "eval: doc.__islocal",
- "columns": 0,
- "depends_on": "eval: doc.get_items_from == \"Sales Order\"",
- "fetch_if_empty": 0,
- "fieldname": "sales_orders_detail",
- "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": "Sales Orders Detail",
- "length": 0,
- "no_copy": 0,
- "options": "",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "collapsible": 1,
+ "collapsible_depends_on": "eval: doc.__islocal",
+ "depends_on": "eval: doc.get_items_from == \"Sales Order\"",
+ "fieldname": "sales_orders_detail",
+ "fieldtype": "Section Break",
+ "label": "Sales Orders"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "",
- "fetch_if_empty": 0,
- "fieldname": "get_sales_orders",
- "fieldtype": "Button",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Get Sales Orders",
- "length": 0,
- "no_copy": 0,
- "options": "",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "get_sales_orders",
+ "fieldtype": "Button",
+ "label": "Get Sales Orders"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "sales_orders",
- "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": "Sales Orders",
- "length": 0,
- "no_copy": 1,
- "options": "Production Plan Sales Order",
- "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
- },
+ "fieldname": "sales_orders",
+ "fieldtype": "Table",
+ "label": "Sales Orders",
+ "no_copy": 1,
+ "options": "Production Plan Sales Order"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "collapsible_depends_on": "eval: doc.__islocal",
- "columns": 0,
- "depends_on": "eval: doc.get_items_from == \"Material Request\"",
- "fetch_if_empty": 0,
- "fieldname": "material_request_detail",
- "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": "Material Request Detail",
- "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
- },
+ "collapsible": 1,
+ "collapsible_depends_on": "eval: doc.__islocal",
+ "depends_on": "eval: doc.get_items_from == \"Material Request\"",
+ "fieldname": "material_request_detail",
+ "fieldtype": "Section Break",
+ "label": "Material Request Detail"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "",
- "fetch_if_empty": 0,
- "fieldname": "get_material_request",
- "fieldtype": "Button",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Get Material Request",
- "length": 0,
- "no_copy": 0,
- "options": "",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "get_material_request",
+ "fieldtype": "Button",
+ "label": "Get Material Request"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "material_requests",
- "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": "Material Requests",
- "length": 0,
- "no_copy": 1,
- "options": "Production Plan Material Request",
- "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
- },
+ "fieldname": "material_requests",
+ "fieldtype": "Table",
+ "label": "Material Requests",
+ "no_copy": 1,
+ "options": "Production Plan Material Request"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "",
- "fetch_if_empty": 0,
- "fieldname": "select_items_to_manufacture_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": "Select Items to Manufacture",
- "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
- },
+ "fieldname": "select_items_to_manufacture_section",
+ "fieldtype": "Section Break",
+ "label": "Select Items to Manufacture"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "get_items_from",
- "fetch_if_empty": 0,
- "fieldname": "get_items",
- "fieldtype": "Button",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Get Items For Work Order",
- "length": 0,
- "no_copy": 0,
- "options": "",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "depends_on": "get_items_from",
+ "fieldname": "get_items",
+ "fieldtype": "Button",
+ "label": "Get Items For Work Order"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "po_items",
- "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": "",
- "length": 0,
- "no_copy": 1,
- "options": "Production Plan Item",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "po_items",
+ "fieldtype": "Table",
+ "no_copy": 1,
+ "options": "Production Plan Item",
+ "reqd": 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": "material_request_planning",
- "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": "Material Request Planning",
- "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
- },
+ "fieldname": "material_request_planning",
+ "fieldtype": "Section Break",
+ "label": "Material Request Planning"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "1",
- "fetch_if_empty": 0,
- "fieldname": "include_non_stock_items",
- "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 Non Stock Items",
- "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
- },
+ "default": "1",
+ "fieldname": "include_non_stock_items",
+ "fieldtype": "Check",
+ "label": "Include Non Stock Items"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "1",
- "fetch_if_empty": 0,
- "fieldname": "include_subcontracted_items",
- "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 Subcontracted Items",
- "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
- },
+ "default": "1",
+ "fieldname": "include_subcontracted_items",
+ "fieldtype": "Check",
+ "label": "Include Subcontracted Items"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "If enabled, then system will create the material even if the raw materials are available",
- "fetch_if_empty": 0,
- "fieldname": "ignore_existing_ordered_qty",
- "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": "Ignore Existing Projected Quantity",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "default": "0",
+ "description": "To know more about projected quantity, <a href=\"https://erpnext.com/docs/user/manual/en/stock/projected-quantity\" style=\"text-decoration: underline;\" target=\"_blank\">click here</a>.",
+ "fieldname": "ignore_existing_ordered_qty",
+ "fieldtype": "Check",
+ "label": "Ignore Existing Projected Quantity"
+ },
{
- "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_25",
- "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
- },
+ "fieldname": "column_break_25",
+ "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,
- "fieldname": "for_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": "For Warehouse",
- "length": 0,
- "no_copy": 0,
- "options": "Warehouse",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "for_warehouse",
+ "fieldtype": "Link",
+ "label": "For Warehouse",
+ "options": "Warehouse"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "download_materials_required",
- "fieldtype": "Button",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Download Materials Required",
- "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
- },
+ "fieldname": "download_materials_required",
+ "fieldtype": "Button",
+ "label": "Download Required Materials"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "get_items_for_mr",
- "fieldtype": "Button",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Get Raw Materials For Production",
- "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
- },
+ "fieldname": "get_items_for_mr",
+ "fieldtype": "Button",
+ "label": "Get Raw Materials For Production"
+ },
{
- "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": "section_break_27",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "section_break_27",
+ "fieldtype": "Section Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "mr_items",
- "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": "Material Request Plan Item",
- "length": 0,
- "no_copy": 1,
- "options": "Material Request Plan Item",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "mr_items",
+ "fieldtype": "Table",
+ "label": "Material Request Plan Item",
+ "no_copy": 1,
+ "options": "Material Request Plan Item"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "",
- "fetch_if_empty": 0,
- "fieldname": "projected_qty_formula",
- "fieldtype": "HTML",
- "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 Formula",
- "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
- },
+ "collapsible": 1,
+ "fieldname": "other_details",
+ "fieldtype": "Section Break",
+ "label": "Other Details"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "other_details",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Other Details",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "default": "0",
+ "fieldname": "total_planned_qty",
+ "fieldtype": "Float",
+ "label": "Total Planned Qty",
+ "no_copy": 1,
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "0",
- "fetch_if_empty": 0,
- "fieldname": "total_planned_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": "Total Planned Qty",
- "length": 0,
- "no_copy": 1,
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "default": "0",
+ "fieldname": "total_produced_qty",
+ "fieldtype": "Float",
+ "label": "Total Produced Qty",
+ "no_copy": 1,
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "0",
- "fetch_if_empty": 0,
- "fieldname": "total_produced_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": "Total Produced Qty",
- "length": 0,
- "no_copy": 1,
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "column_break_32",
+ "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,
- "fieldname": "column_break_32",
- "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
- },
+ "default": "Draft",
+ "fieldname": "status",
+ "fieldtype": "Select",
+ "label": "Status",
+ "no_copy": 1,
+ "options": "\nDraft\nSubmitted\nNot Started\nIn Process\nCompleted\nStopped\nCancelled\nMaterial Requested",
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "Draft",
- "fetch_if_empty": 0,
- "fieldname": "status",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Status",
- "length": 0,
- "no_copy": 1,
- "options": "\nDraft\nSubmitted\nNot Started\nIn Process\nCompleted\nStopped\nCancelled\nMaterial Requested",
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "amended_from",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Amended From",
- "length": 0,
- "no_copy": 1,
- "options": "Production Plan",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "fieldname": "amended_from",
+ "fieldtype": "Link",
+ "label": "Amended From",
+ "no_copy": 1,
+ "options": "Production Plan",
+ "print_hide": 1,
+ "read_only": 1
}
- ],
- "has_web_view": 0,
- "hide_toolbar": 0,
- "icon": "fa fa-calendar",
- "idx": 0,
- "in_create": 0,
- "is_submittable": 1,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2019-04-09 12:05:14.300886",
- "modified_by": "Administrator",
- "module": "Manufacturing",
- "name": "Production Plan",
- "name_case": "",
- "owner": "Administrator",
+ ],
+ "icon": "fa fa-calendar",
+ "is_submittable": 1,
+ "links": [],
+ "modified": "2019-12-04 15:58:50.940460",
+ "modified_by": "Administrator",
+ "module": "Manufacturing",
+ "name": "Production Plan",
+ "owner": "Administrator",
"permissions": [
{
- "amend": 1,
- "cancel": 1,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 0,
- "role": "Manufacturing User",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 1,
+ "amend": 1,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "role": "Manufacturing User",
+ "share": 1,
+ "submit": 1,
"write": 1
}
- ],
- "quick_entry": 0,
- "read_only": 0,
- "show_name_in_global_search": 0,
- "sort_field": "modified",
- "sort_order": "ASC",
- "title_field": "",
- "track_changes": 0,
- "track_seen": 0,
- "track_views": 0
+ ],
+ "sort_field": "modified",
+ "sort_order": "ASC"
}
\ No newline at end of file
diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.py b/erpnext/manufacturing/doctype/production_plan/production_plan.py
index 4dc98e7..8876253 100644
--- a/erpnext/manufacturing/doctype/production_plan/production_plan.py
+++ b/erpnext/manufacturing/doctype/production_plan/production_plan.py
@@ -99,7 +99,7 @@
self.get_mr_items()
def get_so_items(self):
- so_list = [d.sales_order for d in self.get("sales_orders", []) if d.sales_order]
+ so_list = [d.sales_order for d in self.sales_orders if d.sales_order]
if not so_list:
msgprint(_("Please enter Sales Orders in the above table"))
return []
@@ -109,7 +109,7 @@
item_condition = ' and so_item.item_code = {0}'.format(frappe.db.escape(self.item_code))
items = frappe.db.sql("""select distinct parent, item_code, warehouse,
- (qty - work_order_qty) * conversion_factor as pending_qty, name
+ (qty - work_order_qty) * conversion_factor as pending_qty, description, name
from `tabSales Order Item` so_item
where parent in (%s) and docstatus = 1 and qty > work_order_qty
and exists (select name from `tabBOM` bom where bom.item=so_item.item_code
@@ -121,7 +121,7 @@
packed_items = frappe.db.sql("""select distinct pi.parent, pi.item_code, pi.warehouse as warehouse,
(((so_item.qty - so_item.work_order_qty) * pi.qty) / so_item.qty)
- as pending_qty, pi.parent_item, so_item.name
+ as pending_qty, pi.parent_item, pi.description, so_item.name
from `tabSales Order Item` so_item, `tabPacked Item` pi
where so_item.parent = pi.parent and so_item.docstatus = 1
and pi.parent_item = so_item.item_code
@@ -134,7 +134,7 @@
self.calculate_total_planned_qty()
def get_mr_items(self):
- mr_list = [d.material_request for d in self.get("material_requests", []) if d.material_request]
+ mr_list = [d.material_request for d in self.material_requests if d.material_request]
if not mr_list:
msgprint(_("Please enter Material Requests in the above table"))
return []
@@ -143,7 +143,7 @@
if self.item_code:
item_condition = " and mr_item.item_code ={0}".format(frappe.db.escape(self.item_code))
- items = frappe.db.sql("""select distinct parent, name, item_code, warehouse,
+ items = frappe.db.sql("""select distinct parent, name, item_code, warehouse, description,
(qty - ordered_qty) as pending_qty
from `tabMaterial Request Item` mr_item
where parent in (%s) and docstatus = 1 and qty > ordered_qty
@@ -162,7 +162,7 @@
'include_exploded_items': 1,
'warehouse': data.warehouse,
'item_code': data.item_code,
- 'description': item_details and item_details.description or '',
+ 'description': data.description or item_details.description,
'stock_uom': item_details and item_details.stock_uom or '',
'bom_no': item_details and item_details.bom_no or '',
'planned_qty': data.pending_qty,
@@ -174,10 +174,12 @@
if self.get_items_from == "Sales Order":
pi.sales_order = data.parent
pi.sales_order_item = data.name
+ pi.description = data.description
elif self.get_items_from == "Material Request":
pi.material_request = data.parent
pi.material_request_item = data.name
+ pi.description = data.description
def calculate_total_planned_qty(self):
self.total_planned_qty = 0
@@ -195,7 +197,6 @@
for data in self.po_items:
if data.name == production_plan_item:
data.produced_qty = produced_qty
- data.pending_qty = data.planned_qty - data.produced_qty
data.db_update()
self.calculate_total_produced_qty()
@@ -302,6 +303,7 @@
wo_list.extend(work_orders)
frappe.flags.mute_messages = False
+
if wo_list:
wo_list = ["""<a href="#Form/Work Order/%s" target="_blank">%s</a>""" % \
(p, p) for p in wo_list]
@@ -309,16 +311,15 @@
else :
msgprint(_("No Work Orders created"))
-
def make_work_order_for_sub_assembly_items(self, item):
work_orders = []
bom_data = {}
- get_sub_assembly_items(item.get("bom_no"), bom_data, item.get("qty"))
+ get_sub_assembly_items(item.get("bom_no"), bom_data)
for key, data in bom_data.items():
data.update({
- 'qty': data.get("stock_qty"),
+ 'qty': data.get("stock_qty") * item.get("qty"),
'production_plan': self.name,
'company': self.company,
'fg_warehouse': item.get("fg_warehouse"),
@@ -540,7 +541,9 @@
'projected_qty': bin_dict.get("projected_qty", 0),
'min_order_qty': row['min_order_qty'],
'material_request_type': row.get("default_material_request_type"),
- 'sales_order': sales_order
+ 'sales_order': sales_order,
+ 'description': row.get("description"),
+ 'uom': row.get("purchase_uom") or row.get("stock_uom")
}
def get_sales_orders(self):
@@ -558,7 +561,7 @@
item_filter += " and so_item.item_code = %(item)s"
open_so = frappe.db.sql("""
- select distinct so.name, so.transaction_date, so.customer, so.base_grand_total as grand_total
+ select distinct so.name, so.transaction_date, so.customer, so.base_grand_total
from `tabSales Order` so, `tabSales Order Item` so_item
where so_item.parent = so.name
and so.docstatus = 1 and so.status not in ("Stopped", "Closed")
@@ -612,6 +615,9 @@
doc['mr_items'] = []
po_items = doc.get('po_items') if doc.get('po_items') else doc.get('items')
+ if not po_items:
+ frappe.throw(_("Items are required to pull the raw materials which is associated with it."))
+
company = doc.get('company')
warehouse = doc.get('for_warehouse')
@@ -705,11 +711,11 @@
return {
"bom_no": item_details.get("bom_no"),
- "stock_uom": item_details.get("stock_uom"),
- "description": item_details.get("description")
+ "stock_uom": item_details.get("stock_uom")
+# "description": item_details.get("description")
}
-def get_sub_assembly_items(bom_no, bom_data, qty):
+def get_sub_assembly_items(bom_no, bom_data):
data = get_children('BOM', parent = bom_no)
for d in data:
if d.expandable:
@@ -726,6 +732,6 @@
})
bom_item = bom_data.get(key)
- bom_item["stock_qty"] += ((d.stock_qty * qty) / d.parent_bom_qty)
+ bom_item["stock_qty"] += d.stock_qty
- get_sub_assembly_items(bom_item.get("bom_no"), bom_data, bom_item["stock_qty"])
+ get_sub_assembly_items(bom_item.get("bom_no"), bom_data)
diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan_dashboard.py b/erpnext/manufacturing/doctype/production_plan/production_plan_dashboard.py
index 91c2855..09ec24a 100644
--- a/erpnext/manufacturing/doctype/production_plan/production_plan_dashboard.py
+++ b/erpnext/manufacturing/doctype/production_plan/production_plan_dashboard.py
@@ -6,7 +6,7 @@
'fieldname': 'production_plan',
'transactions': [
{
- 'label': _('Related'),
+ 'label': _('Transactions'),
'items': ['Work Order', 'Material Request']
},
]
diff --git a/erpnext/manufacturing/doctype/work_order/test_work_order.py b/erpnext/manufacturing/doctype/work_order/test_work_order.py
index d710e57..0a8f41f 100644
--- a/erpnext/manufacturing/doctype/work_order/test_work_order.py
+++ b/erpnext/manufacturing/doctype/work_order/test_work_order.py
@@ -5,10 +5,10 @@
from __future__ import unicode_literals
import unittest
import frappe
-from frappe.utils import flt, time_diff_in_hours, now, add_days, cint
+from frappe.utils import flt, time_diff_in_hours, now, add_months, cint, today
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory
-from erpnext.manufacturing.doctype.work_order.work_order \
- import make_stock_entry, ItemHasVariantError, stop_unstop, StockOverProductionError, OverProductionError
+from erpnext.manufacturing.doctype.work_order.work_order import (make_stock_entry,
+ ItemHasVariantError, stop_unstop, StockOverProductionError, OverProductionError, CapacityError)
from erpnext.stock.doctype.stock_entry import test_stock_entry
from erpnext.stock.utils import get_bin
from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order
@@ -17,11 +17,11 @@
class TestWorkOrder(unittest.TestCase):
def setUp(self):
+ set_perpetual_inventory(0)
self.warehouse = '_Test Warehouse 2 - _TC'
self.item = '_Test Item'
def check_planned_qty(self):
- set_perpetual_inventory(0)
planned0 = frappe.db.get_value("Bin", {"item_code": "_Test FG Item",
"warehouse": "_Test Warehouse 1 - _TC"}, "planned_qty") or 0
@@ -307,14 +307,50 @@
{'docstatus': 1, 'with_operations': 1, 'company': '_Test Company'}, ['name', 'item'])
if data:
+ frappe.db.set_value("Manufacturing Settings",
+ None, "disable_capacity_planning", 0)
+
bom, bom_item = data
bom_doc = frappe.get_doc('BOM', bom)
work_order = make_wo_order_test_record(item=bom_item, qty=1, bom_no=bom)
+ self.assertTrue(work_order.planned_end_date)
job_cards = frappe.get_all('Job Card', filters = {'work_order': work_order.name})
self.assertEqual(len(job_cards), len(bom_doc.operations))
+ def test_capcity_planning(self):
+ frappe.db.set_value("Manufacturing Settings", None, {
+ "disable_capacity_planning": 0,
+ "capacity_planning_for_days": 1
+ })
+
+ data = frappe.get_cached_value('BOM', {'docstatus': 1, 'item': '_Test FG Item 2',
+ 'with_operations': 1, 'company': '_Test Company'}, ['name', 'item'])
+
+ if data:
+ bom, bom_item = data
+
+ planned_start_date = add_months(today(), months=-1)
+ work_order = make_wo_order_test_record(item=bom_item,
+ qty=10, bom_no=bom, planned_start_date=planned_start_date)
+
+ work_order1 = make_wo_order_test_record(item=bom_item,
+ qty=30, bom_no=bom, planned_start_date=planned_start_date, do_not_submit=1)
+
+ self.assertRaises(CapacityError, work_order1.submit)
+
+ frappe.db.set_value("Manufacturing Settings", None, {
+ "capacity_planning_for_days": 30
+ })
+
+ work_order1.reload()
+ work_order1.submit()
+ self.assertTrue(work_order1.docstatus, 1)
+
+ work_order1.cancel()
+ work_order.cancel()
+
def test_work_order_with_non_transfer_item(self):
items = {'Finished Good Transfer Item': 1, '_Test FG Item': 1, '_Test FG Item 1': 0}
for item, allow_transfer in items.items():
@@ -371,14 +407,12 @@
wo_order.skip_transfer=1
wo_order.get_items_and_operations_from_bom()
wo_order.sales_order = args.sales_order or None
+ wo_order.planned_start_date = args.planned_start_date or now()
if args.source_warehouse:
for item in wo_order.get("required_items"):
item.source_warehouse = args.source_warehouse
- if args.planned_start_date:
- wo_order.planned_start_date = args.planned_start_date
-
if not args.do_not_save:
wo_order.insert()
diff --git a/erpnext/manufacturing/doctype/work_order/work_order.js b/erpnext/manufacturing/doctype/work_order/work_order.js
index cdbce33..80bd89d 100644
--- a/erpnext/manufacturing/doctype/work_order/work_order.js
+++ b/erpnext/manufacturing/doctype/work_order/work_order.js
@@ -6,6 +6,7 @@
frm.custom_make_buttons = {
'Stock Entry': 'Start',
'Pick List': 'Create Pick List',
+ 'Job Card': 'Create Job Card'
};
// Set query for warehouses
@@ -76,8 +77,7 @@
return {
query: "erpnext.controllers.queries.item_query",
filters:[
- ['is_stock_item', '=',1],
- ['default_bom', '!=', '']
+ ['is_stock_item', '=',1]
]
};
});
@@ -131,7 +131,8 @@
}
if (frm.doc.docstatus===1) {
- frm.trigger('show_progress');
+ frm.trigger('show_progress_for_items');
+ frm.trigger('show_progress_for_operations');
}
if (frm.doc.docstatus === 1
@@ -179,89 +180,72 @@
make_job_card: function(frm) {
let qty = 0;
- const fields = [{
- fieldtype: "Link",
- fieldname: "operation",
- options: "Operation",
- label: __("Operation"),
- get_query: () => {
- const filter_workstation = frm.doc.operations.filter(d => {
- if (d.status != "Completed") {
- return d;
- }
- });
+ let operations_data = [];
- return {
- filters: {
- name: ["in", (filter_workstation || []).map(d => d.operation)]
- }
- };
- },
- reqd: true
- }, {
- fieldtype: "Link",
- fieldname: "workstation",
- options: "Workstation",
- label: __("Workstation"),
- get_query: () => {
- const operation = dialog.get_value("operation");
- const filter_workstation = frm.doc.operations.filter(d => {
- if (d.operation == operation) {
- return d;
- }
- });
-
- return {
- filters: {
- name: ["in", (filter_workstation || []).map(d => d.workstation)]
- }
- };
- },
- onchange: () => {
- const operation = dialog.get_value("operation");
- const workstation = dialog.get_value("workstation");
- if (operation && workstation) {
- const row = frm.doc.operations.filter(d => d.operation == operation && d.workstation == workstation)[0];
- qty = frm.doc.qty - row.completed_qty;
-
- if (qty > 0) {
- dialog.set_value("qty", qty);
- }
- }
- },
- reqd: true
- }, {
- fieldtype: "Float",
- fieldname: "qty",
- label: __("For Quantity"),
- reqd: true
- }];
-
- const dialog = frappe.prompt(fields, function(data) {
- if (data.qty > qty) {
- frappe.throw(__("For Quantity must be less than quantity {0}", [qty]));
+ const dialog = frappe.prompt({fieldname: 'operations', fieldtype: 'Table', label: __('Operations'),
+ fields: [
+ {
+ fieldtype:'Link',
+ fieldname:'operation',
+ label: __('Operation'),
+ read_only:1,
+ in_list_view:1
+ },
+ {
+ fieldtype:'Link',
+ fieldname:'workstation',
+ label: __('Workstation'),
+ read_only:1,
+ in_list_view:1
+ },
+ {
+ fieldtype:'Data',
+ fieldname:'name',
+ label: __('Operation Id')
+ },
+ {
+ fieldtype:'Float',
+ fieldname:'pending_qty',
+ label: __('Pending Qty'),
+ },
+ {
+ fieldtype:'Float',
+ fieldname:'qty',
+ label: __('Quantity to Manufacture'),
+ read_only:0,
+ in_list_view:1,
+ },
+ ],
+ data: operations_data,
+ in_place_edit: true,
+ get_data: function() {
+ return operations_data;
}
-
- if (data.qty <= 0) {
- frappe.throw(__("For Quantity must be greater than zero"));
- }
-
+ }, function(data) {
frappe.call({
method: "erpnext.manufacturing.doctype.work_order.work_order.make_job_card",
args: {
work_order: frm.doc.name,
- operation: data.operation,
- workstation: data.workstation,
- qty: data.qty
- },
- callback: function(r){
- if (r.message) {
- var doc = frappe.model.sync(r.message)[0];
- frappe.set_route("Form", doc.doctype, doc.name);
- }
+ operations: data.operations,
}
});
- }, __("For Job Card"));
+ }, __("Job Card"), __("Create"));
+
+ var pending_qty = 0;
+ frm.doc.operations.forEach(data => {
+ if(data.completed_qty != frm.doc.qty) {
+ pending_qty = frm.doc.qty - flt(data.completed_qty);
+
+ dialog.fields_dict.operations.df.data.push({
+ 'name': data.name,
+ 'operation': data.operation,
+ 'workstation': data.workstation,
+ 'qty': pending_qty,
+ 'pending_qty': pending_qty,
+ });
+ }
+ });
+ dialog.fields_dict.operations.grid.refresh();
},
make_bom: function(frm) {
@@ -277,7 +261,7 @@
});
},
- show_progress: function(frm) {
+ show_progress_for_items: function(frm) {
var bars = [];
var message = '';
var added_min = false;
@@ -311,6 +295,44 @@
frm.dashboard.add_progress(__('Status'), bars, message);
},
+ show_progress_for_operations: function(frm) {
+ if (frm.doc.operations && frm.doc.operations.length) {
+
+ let progress_class = {
+ "Work in Progress": "progress-bar-warning",
+ "Completed": "progress-bar-success"
+ };
+
+ let bars = [];
+ let message = '';
+ let title = '';
+ let status_wise_oprtation_data = {};
+ let total_completed_qty = frm.doc.qty * frm.doc.operations.length;
+
+ frm.doc.operations.forEach(d => {
+ if (!status_wise_oprtation_data[d.status]) {
+ status_wise_oprtation_data[d.status] = [d.completed_qty, d.operation];
+ } else {
+ status_wise_oprtation_data[d.status][0] += d.completed_qty;
+ status_wise_oprtation_data[d.status][1] += ', ' + d.operation;
+ }
+ });
+
+ for (let key in status_wise_oprtation_data) {
+ title = __("{0} Operations: {1}", [key, status_wise_oprtation_data[key][1].bold()]);
+ bars.push({
+ 'title': title,
+ 'width': status_wise_oprtation_data[key][0] / total_completed_qty * 100 + '%',
+ 'progress_class': progress_class[key]
+ });
+
+ message += title + '. ';
+ }
+
+ frm.dashboard.add_progress(__('Status'), bars, message);
+ }
+ },
+
production_item: function(frm) {
if (frm.doc.production_item) {
frappe.call({
@@ -395,6 +417,11 @@
}
});
}
+ },
+
+ additional_operating_cost: function(frm) {
+ erpnext.work_order.calculate_cost(frm.doc);
+ erpnext.work_order.calculate_total_cost(frm);
}
});
@@ -534,8 +561,7 @@
},
calculate_total_cost: function(frm) {
- var variable_cost = frm.doc.actual_operating_cost ?
- flt(frm.doc.actual_operating_cost) : flt(frm.doc.planned_operating_cost);
+ let variable_cost = flt(frm.doc.actual_operating_cost) || flt(frm.doc.planned_operating_cost);
frm.set_value("total_operating_cost", (flt(frm.doc.additional_operating_cost) + variable_cost));
},
@@ -547,6 +573,7 @@
if (!r.exe) {
frm.set_value("wip_warehouse", r.message.wip_warehouse);
frm.set_value("fg_warehouse", r.message.fg_warehouse);
+ frm.set_value("scrap_warehouse", r.message.scrap_warehouse);
}
}
});
@@ -577,6 +604,8 @@
description: __('Max: {0}', [max]),
default: max
}, data => {
+ max += (max * (frm.doc.__onload.overproduction_percentage || 0.0)) / 100;
+
if (data.qty > max) {
frappe.msgprint(__('Quantity must not be more than {0}', [max]));
reject();
diff --git a/erpnext/manufacturing/doctype/work_order/work_order.json b/erpnext/manufacturing/doctype/work_order/work_order.json
index 0d073a2..6152fbb 100644
--- a/erpnext/manufacturing/doctype/work_order/work_order.json
+++ b/erpnext/manufacturing/doctype/work_order/work_order.json
@@ -1,4 +1,5 @@
{
+ "actions": [],
"allow_import": 1,
"autoname": "naming_series:",
"creation": "2013-01-10 16:34:16",
@@ -468,7 +469,8 @@
"idx": 1,
"image_field": "image",
"is_submittable": 1,
- "modified": "2019-08-28 12:29:35.315239",
+ "links": [],
+ "modified": "2019-12-04 11:20:04.695123",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "Work Order",
diff --git a/erpnext/manufacturing/doctype/work_order/work_order.py b/erpnext/manufacturing/doctype/work_order/work_order.py
index b57548e..6798dd2 100644
--- a/erpnext/manufacturing/doctype/work_order/work_order.py
+++ b/erpnext/manufacturing/doctype/work_order/work_order.py
@@ -6,13 +6,13 @@
import json
import math
from frappe import _
-from frappe.utils import flt, get_datetime, getdate, date_diff, cint, nowdate
+from frappe.utils import flt, get_datetime, getdate, date_diff, cint, nowdate, get_link_to_form
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.manufacturing.doctype.job_card.job_card 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
@@ -22,6 +22,7 @@
from frappe.model.mapper import get_mapped_doc
class OverProductionError(frappe.ValidationError): pass
+class CapacityError(frappe.ValidationError): pass
class StockOverProductionError(frappe.ValidationError): pass
class OperationTooLongError(frappe.ValidationError): pass
class ItemHasVariantError(frappe.ValidationError): pass
@@ -37,7 +38,7 @@
ms = frappe.get_doc("Manufacturing Settings")
self.set_onload("material_consumption", ms.material_consumption)
self.set_onload("backflush_raw_materials_based_on", ms.backflush_raw_materials_based_on)
-
+ self.set_onload("overproduction_percentage", ms.overproduction_percentage_for_work_order)
def validate(self):
self.validate_production_item()
@@ -216,14 +217,24 @@
self.db_set(fieldname, qty)
from erpnext.selling.doctype.sales_order.sales_order import update_produced_qty_in_so_item
- update_produced_qty_in_so_item(self.sales_order_item)
+
+ if self.sales_order and self.sales_order_item:
+ update_produced_qty_in_so_item(self.sales_order, self.sales_order_item)
if self.production_plan:
self.update_production_plan_status()
def update_production_plan_status(self):
production_plan = frappe.get_doc('Production Plan', self.production_plan)
- production_plan.run_method("update_produced_qty", self.produced_qty, self.production_plan_item)
+ produced_qty = 0
+ if self.production_plan_item:
+ total_qty = frappe.get_all("Work Order", fields = "sum(produced_qty) as produced_qty",
+ filters = {'docstatus': 1, 'production_plan': self.production_plan,
+ 'production_plan_item': self.production_plan_item}, as_list=1)
+
+ produced_qty = total_qty[0][0] if total_qty else 0
+
+ production_plan.run_method("update_produced_qty", produced_qty, self.production_plan_item)
def on_submit(self):
if not self.wip_warehouse:
@@ -250,12 +261,50 @@
self.update_reserved_qty_for_production()
def create_job_card(self):
- for row in self.operations:
+ manufacturing_settings_doc = frappe.get_doc("Manufacturing Settings")
+
+ enable_capacity_planning = not cint(manufacturing_settings_doc.disable_capacity_planning)
+ plan_days = cint(manufacturing_settings_doc.capacity_planning_for_days) or 30
+
+ for i, row in enumerate(self.operations):
+ self.set_operation_start_end_time(i, row)
+
if not row.workstation:
frappe.throw(_("Row {0}: select the workstation against the operation {1}")
.format(row.idx, row.operation))
- create_job_card(self, row, auto_create=True)
+ original_start_time = row.planned_start_time
+ job_card_doc = create_job_card(self, row,
+ enable_capacity_planning=enable_capacity_planning, auto_create=True)
+
+ if enable_capacity_planning and job_card_doc:
+ row.planned_start_time = job_card_doc.time_logs[0].from_time
+ row.planned_end_time = job_card_doc.time_logs[-1].to_time
+
+ if date_diff(row.planned_start_time, original_start_time) > plan_days:
+ frappe.throw(_("Unable to find the time slot in the next {0} days for the operation {1}.")
+ .format(plan_days, row.operation), CapacityError)
+
+ row.db_update()
+
+ planned_end_date = self.operations and self.operations[-1].planned_end_time
+ if planned_end_date:
+ self.db_set("planned_end_date", planned_end_date)
+
+ def set_operation_start_end_time(self, idx, row):
+ """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 idx==0:
+ # first operation at planned_start date
+ row.planned_start_time = self.planned_start_date
+ else:
+ row.planned_start_time = get_datetime(self.operations[idx-1].planned_end_time)\
+ + get_mins_between_operations()
+
+ row.planned_end_time = get_datetime(row.planned_start_time) + relativedelta(minutes = row.time_in_mins)
+
+ if row.planned_start_time == row.planned_end_time:
+ frappe.throw(_("Capacity Planning Error, planned start time can not be same as end time"))
def validate_cancel(self):
if self.status == "Stopped":
@@ -317,9 +366,8 @@
"""Fetch operations from BOM and set in 'Work Order'"""
self.set('operations', [])
- if not self.bom_no \
- or cint(frappe.db.get_single_value("Manufacturing Settings", "disable_capacity_planning")):
- return
+ if not self.bom_no:
+ return
if self.use_multi_level_bom:
bom_list = frappe.get_doc("BOM", self.bom_no).traverse_tree()
@@ -600,6 +648,23 @@
return res
@frappe.whitelist()
+def make_work_order(item, qty=0, project=None):
+ if not frappe.has_permission("Work Order", "write"):
+ frappe.throw(_("Not permitted"), frappe.PermissionError)
+
+ item_details = get_item_details(item, project)
+
+ wo_doc = frappe.new_doc("Work Order")
+ wo_doc.production_item = item
+ wo_doc.update(item_details)
+
+ if flt(qty) > 0:
+ wo_doc.qty = flt(qty)
+ wo_doc.get_items_and_operations_from_bom()
+
+ return wo_doc
+
+@frappe.whitelist()
def check_if_scrap_warehouse_mandatory(bom_no):
res = {"set_scrap_wh_mandatory": False }
if bom_no:
@@ -619,8 +684,7 @@
@frappe.whitelist()
def make_stock_entry(work_order_id, purpose, qty=None):
work_order = frappe.get_doc("Work Order", work_order_id)
- if not frappe.db.get_value("Warehouse", work_order.wip_warehouse, "is_group") \
- and not work_order.skip_transfer:
+ if not frappe.db.get_value("Warehouse", work_order.wip_warehouse, "is_group"):
wip_warehouse = work_order.wip_warehouse
else:
wip_warehouse = None
@@ -645,7 +709,8 @@
stock_entry.to_warehouse = work_order.fg_warehouse
stock_entry.project = work_order.project
if purpose=="Manufacture":
- additional_costs = get_additional_costs(work_order, fg_qty=stock_entry.fg_completed_qty)
+ additional_costs = get_additional_costs(work_order, fg_qty=stock_entry.fg_completed_qty,
+ company=work_order.company)
stock_entry.set("additional_costs", additional_costs)
stock_entry.set_stock_entry_type()
@@ -654,11 +719,13 @@
@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}
+ doc = frappe.get_cached_doc("Manufacturing Settings")
+
+ return {
+ "wip_warehouse": doc.default_wip_warehouse,
+ "fg_warehouse": doc.default_fg_warehouse,
+ "scrap_warehouse": doc.default_scrap_warehouse
+ }
@frappe.whitelist()
def stop_unstop(work_order, status):
@@ -688,21 +755,41 @@
return out
@frappe.whitelist()
-def make_job_card(work_order, operation, workstation, qty=0):
- work_order = frappe.get_doc('Work Order', work_order)
- row = get_work_order_operation_data(work_order, operation, workstation)
- if row:
- return create_job_card(work_order, row, qty)
+def make_job_card(work_order, operations):
+ if isinstance(operations, string_types):
+ operations = json.loads(operations)
-def create_job_card(work_order, row, qty=0, auto_create=False):
+ work_order = frappe.get_doc('Work Order', work_order)
+ for row in operations:
+ validate_operation_data(row)
+ create_job_card(work_order, row, row.get("qty"), auto_create=True)
+
+def validate_operation_data(row):
+ if row.get("qty") <= 0:
+ frappe.throw(_("Quantity to Manufacture can not be zero for the operation {0}")
+ .format(
+ frappe.bold(row.get("operation"))
+ )
+ )
+
+ if row.get("qty") > row.get("pending_qty"):
+ frappe.throw(_("For operation {0}: Quantity ({1}) can not be greter than pending quantity({2})")
+ .format(
+ frappe.bold(row.get("operation")),
+ frappe.bold(row.get("qty")),
+ frappe.bold(row.get("pending_qty"))
+ )
+ )
+
+def create_job_card(work_order, row, qty=0, enable_capacity_planning=False, auto_create=False):
doc = frappe.new_doc("Job Card")
doc.update({
'work_order': work_order.name,
- 'operation': row.operation,
- 'workstation': row.workstation,
+ 'operation': row.get("operation"),
+ 'workstation': row.get("workstation"),
'posting_date': nowdate(),
'for_quantity': qty or work_order.get('qty', 0),
- 'operation_id': row.name,
+ 'operation_id': row.get("name"),
'bom_no': work_order.bom_no,
'project': work_order.project,
'company': work_order.company,
@@ -714,8 +801,11 @@
if auto_create:
doc.flags.ignore_mandatory = True
+ if enable_capacity_planning:
+ doc.schedule_time_logs(row)
+
doc.insert()
- frappe.msgprint(_("Job card {0} created").format(doc.name))
+ frappe.msgprint(_("Job card {0} created").format(get_link_to_form("Job Card", doc.name)))
return doc
@@ -765,4 +855,4 @@
doc.set_item_locations()
- return doc
\ No newline at end of file
+ return doc
diff --git a/erpnext/manufacturing/doctype/work_order/work_order_calendar.js b/erpnext/manufacturing/doctype/work_order/work_order_calendar.js
index c44b1e2..7ce05e9 100644
--- a/erpnext/manufacturing/doctype/work_order/work_order_calendar.js
+++ b/erpnext/manufacturing/doctype/work_order/work_order_calendar.js
@@ -2,11 +2,13 @@
// For license information, please see license.txt
frappe.views.calendar["Work Order"] = {
+ fields: ["planned_start_date", "planned_end_date", "status", "produced_qty", "qty", "name", "name"],
field_map: {
"start": "planned_start_date",
"end": "planned_end_date",
"id": "name",
"title": "name",
+ "status": "status",
"allDay": "allDay",
"progress": function(data) {
return flt(data.produced_qty) / data.qty * 100;
diff --git a/erpnext/manufacturing/doctype/work_order/work_order_dashboard.py b/erpnext/manufacturing/doctype/work_order/work_order_dashboard.py
index 0d3c30e..87c090f 100644
--- a/erpnext/manufacturing/doctype/work_order/work_order_dashboard.py
+++ b/erpnext/manufacturing/doctype/work_order/work_order_dashboard.py
@@ -6,7 +6,8 @@
'fieldname': 'work_order',
'transactions': [
{
- 'items': ['Pick List', 'Stock Entry', 'Job Card']
+ 'label': _('Transactions'),
+ 'items': ['Stock Entry', 'Job Card', 'Pick List']
}
]
}
\ No newline at end of file
diff --git a/erpnext/manufacturing/doctype/work_order_operation/work_order_operation.json b/erpnext/manufacturing/doctype/work_order_operation/work_order_operation.json
index 75d42cd..3f5e18e 100644
--- a/erpnext/manufacturing/doctype/work_order_operation/work_order_operation.json
+++ b/erpnext/manufacturing/doctype/work_order_operation/work_order_operation.json
@@ -1,4 +1,5 @@
{
+ "actions": [],
"creation": "2014-10-16 14:35:41.950175",
"doctype": "DocType",
"editable_grid": 1,
@@ -68,6 +69,7 @@
"description": "Operation completed for how many finished goods?",
"fieldname": "completed_qty",
"fieldtype": "Float",
+ "in_list_view": 1,
"label": "Completed Qty",
"no_copy": 1,
"read_only": 1
@@ -188,8 +190,9 @@
}
],
"istable": 1,
- "modified": "2019-07-16 23:01:07.720337",
- "modified_by": "govindsmenokee@gmail.com",
+ "links": [],
+ "modified": "2019-12-03 19:24:29.594189",
+ "modified_by": "Administrator",
"module": "Manufacturing",
"name": "Work Order Operation",
"owner": "Administrator",
@@ -197,4 +200,4 @@
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
-}
+}
\ No newline at end of file
diff --git a/erpnext/manufacturing/doctype/workstation/workstation.json b/erpnext/manufacturing/doctype/workstation/workstation.json
index dca9891..d130391 100644
--- a/erpnext/manufacturing/doctype/workstation/workstation.json
+++ b/erpnext/manufacturing/doctype/workstation/workstation.json
@@ -1,466 +1,159 @@
{
- "allow_copy": 0,
- "allow_guest_to_view": 0,
- "allow_import": 1,
- "allow_rename": 1,
- "autoname": "field:workstation_name",
- "beta": 0,
- "creation": "2013-01-10 16:34:17",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "Setup",
- "editable_grid": 0,
+ "allow_import": 1,
+ "allow_rename": 1,
+ "autoname": "field:workstation_name",
+ "creation": "2013-01-10 16:34:17",
+ "doctype": "DocType",
+ "document_type": "Setup",
+ "field_order": [
+ "workstation_name",
+ "production_capacity",
+ "column_break_3",
+ "over_heads",
+ "hour_rate_electricity",
+ "hour_rate_consumable",
+ "column_break_11",
+ "hour_rate_rent",
+ "hour_rate_labour",
+ "hour_rate",
+ "working_hours_section",
+ "holiday_list",
+ "working_hours",
+ "workstaion_description",
+ "description"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "columns": 0,
- "fieldname": "description_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": "Description",
- "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": "workstation_name",
+ "fieldtype": "Data",
+ "in_list_view": 1,
+ "label": "Workstation Name",
+ "oldfieldname": "workstation_name",
+ "oldfieldtype": "Data",
+ "reqd": 1,
+ "unique": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "workstation_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": "Workstation Name",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "workstation_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,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "description",
- "fieldtype": "Text",
- "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,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0,
+ "fieldname": "description",
+ "fieldtype": "Text",
+ "in_list_view": 1,
+ "label": "Description",
+ "oldfieldname": "description",
+ "oldfieldtype": "Text",
"width": "300px"
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "over_heads",
- "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": "Operating Costs",
- "length": 0,
- "no_copy": 0,
- "oldfieldtype": "Section Break",
- "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": "over_heads",
+ "fieldtype": "Section Break",
+ "label": "Operating Costs",
+ "oldfieldtype": "Section Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "per hour",
- "fieldname": "hour_rate_electricity",
- "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": "Electricity Cost",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "hour_rate_electricity",
- "oldfieldtype": "Currency",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "bold": 1,
+ "description": "per hour",
+ "fieldname": "hour_rate_electricity",
+ "fieldtype": "Currency",
+ "label": "Electricity Cost",
+ "oldfieldname": "hour_rate_electricity",
+ "oldfieldtype": "Currency"
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "per hour",
- "fieldname": "hour_rate_consumable",
- "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": "Consumable Cost",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "hour_rate_consumable",
- "oldfieldtype": "Currency",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "bold": 1,
+ "description": "per hour",
+ "fieldname": "hour_rate_consumable",
+ "fieldtype": "Currency",
+ "label": "Consumable Cost",
+ "oldfieldname": "hour_rate_consumable",
+ "oldfieldtype": "Currency"
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_11",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "fieldname": "column_break_11",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "per hour",
- "fieldname": "hour_rate_rent",
- "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": "Rent Cost",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "hour_rate_rent",
- "oldfieldtype": "Currency",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "bold": 1,
+ "description": "per hour",
+ "fieldname": "hour_rate_rent",
+ "fieldtype": "Currency",
+ "label": "Rent Cost",
+ "oldfieldname": "hour_rate_rent",
+ "oldfieldtype": "Currency"
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "Wages per hour",
- "fieldname": "hour_rate_labour",
- "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": "Wages",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "hour_rate_labour",
- "oldfieldtype": "Currency",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "bold": 1,
+ "description": "Wages per hour",
+ "fieldname": "hour_rate_labour",
+ "fieldtype": "Currency",
+ "label": "Wages",
+ "oldfieldname": "hour_rate_labour",
+ "oldfieldtype": "Currency"
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "per hour",
- "fieldname": "hour_rate",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Net Hour Rate",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "hour_rate",
- "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
- },
+ "description": "per hour",
+ "fieldname": "hour_rate",
+ "fieldtype": "Currency",
+ "label": "Net Hour Rate",
+ "oldfieldname": "hour_rate",
+ "oldfieldtype": "Currency",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "working_hours_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": "Working Hours",
- "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": "working_hours_section",
+ "fieldtype": "Section Break",
+ "label": "Working Hours"
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "working_hours",
- "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": "Working Hours",
- "length": 0,
- "no_copy": 0,
- "options": "Workstation Working Hour",
- "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": "working_hours",
+ "fieldtype": "Table",
+ "label": "Working Hours",
+ "options": "Workstation Working Hour"
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "",
- "fieldname": "holiday_list",
- "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": "Holiday List",
- "length": 0,
- "no_copy": 0,
- "options": "Holiday List",
- "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": "holiday_list",
+ "fieldtype": "Link",
+ "label": "Holiday List",
+ "options": "Holiday List"
+ },
+ {
+ "default": "1",
+ "fieldname": "production_capacity",
+ "fieldtype": "Int",
+ "label": "Production Capacity",
+ "reqd": 1
+ },
+ {
+ "fieldname": "column_break_3",
+ "fieldtype": "Column Break"
+ },
+ {
+ "collapsible": 1,
+ "fieldname": "workstaion_description",
+ "fieldtype": "Section Break",
+ "label": "Description"
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "icon": "icon-wrench",
- "idx": 1,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2017-07-18 22:28:50.163219",
- "modified_by": "Administrator",
- "module": "Manufacturing",
- "name": "Workstation",
- "owner": "Administrator",
+ ],
+ "icon": "icon-wrench",
+ "idx": 1,
+ "modified": "2019-11-26 12:39:19.742052",
+ "modified_by": "Administrator",
+ "module": "Manufacturing",
+ "name": "Workstation",
+ "owner": "Administrator",
"permissions": [
{
- "amend": 0,
- "apply_user_permissions": 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": "Manufacturing User",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Manufacturing User",
+ "share": 1,
"write": 1
}
- ],
- "quick_entry": 1,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 1,
- "sort_order": "ASC",
- "track_changes": 1,
- "track_seen": 0
+ ],
+ "quick_entry": 1,
+ "show_name_in_global_search": 1,
+ "sort_order": "ASC",
+ "track_changes": 1
}
\ No newline at end of file
diff --git a/erpnext/manufacturing/doctype/workstation/workstation.py b/erpnext/manufacturing/doctype/workstation/workstation.py
index f6ab72a..3512e59 100644
--- a/erpnext/manufacturing/doctype/workstation/workstation.py
+++ b/erpnext/manufacturing/doctype/workstation/workstation.py
@@ -4,7 +4,9 @@
from __future__ import unicode_literals
import frappe
from frappe import _
-from frappe.utils import flt, cint, getdate, formatdate, comma_and, time_diff_in_seconds, to_timedelta
+from erpnext.support.doctype.issue.issue import get_holidays
+from frappe.utils import (flt, cint, getdate, formatdate,
+ comma_and, time_diff_in_seconds, to_timedelta, add_days)
from frappe.model.document import Document
from dateutil.parser import parse
@@ -43,6 +45,17 @@
where parent = %s and workstation = %s""",
(self.hour_rate, bom_no[0], self.name))
+ def validate_workstation_holiday(self, schedule_date, skip_holiday_list_check=False):
+ if not skip_holiday_list_check and (not self.holiday_list or
+ cint(frappe.db.get_single_value("Manufacturing Settings", "allow_production_on_holidays"))):
+ return schedule_date
+
+ if schedule_date in tuple(get_holidays(self.holiday_list)):
+ schedule_date = add_days(schedule_date, 1)
+ self.validate_workstation_holiday(schedule_date, skip_holiday_list_check=True)
+
+ return schedule_date
+
@frappe.whitelist()
def get_default_holiday_list():
return frappe.get_cached_value('Company', frappe.defaults.get_user_default("Company"), "default_holiday_list")
diff --git a/erpnext/manufacturing/doctype/workstation/workstation_dashboard.py b/erpnext/manufacturing/doctype/workstation/workstation_dashboard.py
index 9e0d1d1..3ddbe73 100644
--- a/erpnext/manufacturing/doctype/workstation/workstation_dashboard.py
+++ b/erpnext/manufacturing/doctype/workstation/workstation_dashboard.py
@@ -6,8 +6,14 @@
'fieldname': 'workstation',
'transactions': [
{
- 'label': _('Manufacture'),
- 'items': ['BOM', 'Routing', 'Work Order', 'Job Card', 'Operation', 'Timesheet']
+ 'label': _('Master'),
+ 'items': ['BOM', 'Routing', 'Operation']
+ },
+ {
+ 'label': _('Transaction'),
+ 'items': ['Work Order', 'Job Card', 'Timesheet']
}
- ]
+ ],
+ 'disable_create_buttons': ['BOM', 'Routing', 'Operation',
+ 'Work Order', 'Job Card', 'Timesheet']
}
diff --git a/erpnext/manufacturing/report/bom_explorer/bom_explorer.py b/erpnext/manufacturing/report/bom_explorer/bom_explorer.py
index 875d115..48907ad 100644
--- a/erpnext/manufacturing/report/bom_explorer/bom_explorer.py
+++ b/erpnext/manufacturing/report/bom_explorer/bom_explorer.py
@@ -14,7 +14,7 @@
def get_data(filters, data):
get_exploded_items(filters.bom, data)
-def get_exploded_items(bom, data, indent=0):
+def get_exploded_items(bom, data, indent=0, qty=1):
exploded_items = frappe.get_all("BOM Item",
filters={"parent": bom},
fields= ['qty','bom_no','qty','scrap','item_code','item_name','description','uom'])
@@ -26,13 +26,13 @@
'item_name': item.item_name,
'indent': indent,
'bom': item.bom_no,
- 'qty': item.qty,
+ 'qty': item.qty * qty,
'uom': item.uom,
'description': item.description,
'scrap': item.scrap
})
if item.bom_no:
- get_exploded_items(item.bom_no, data, indent=indent+1)
+ get_exploded_items(item.bom_no, data, indent=indent+1, qty=item.qty)
def get_columns():
return [
diff --git a/erpnext/manufacturing/report/bom_stock_calculated/bom_stock_calculated.py b/erpnext/manufacturing/report/bom_stock_calculated/bom_stock_calculated.py
index be016ad..f7b407b 100644
--- a/erpnext/manufacturing/report/bom_stock_calculated/bom_stock_calculated.py
+++ b/erpnext/manufacturing/report/bom_stock_calculated/bom_stock_calculated.py
@@ -4,6 +4,7 @@
from __future__ import unicode_literals
import frappe
from frappe import _
+from frappe.utils.data import comma_and
def execute(filters=None):
# if not filters: filters = {}
@@ -13,35 +14,36 @@
data = get_bom_stock(filters)
qty_to_make = filters.get("qty_to_make")
+ manufacture_details = get_manufacturer_records()
for row in data:
- item_map = get_item_details(row.item_code)
reqd_qty = qty_to_make * row.actual_qty
last_pur_price = frappe.db.get_value("Item", row.item_code, "last_purchase_rate")
- if row.to_build > 0:
- diff_qty = row.to_build - reqd_qty
- summ_data.append([row.item_code, row.description, item_map[row.item_code]["manufacturer"], item_map[row.item_code]["manufacturer_part_no"], row.actual_qty, row.to_build, reqd_qty, diff_qty, last_pur_price])
- else:
- diff_qty = 0 - reqd_qty
- summ_data.append([row.item_code, row.description, item_map[row.item_code]["manufacturer"], item_map[row.item_code]["manufacturer_part_no"], row.actual_qty, "0.000", reqd_qty, diff_qty, last_pur_price])
+ summ_data.append(get_report_data(last_pur_price, reqd_qty, row, manufacture_details))
return columns, summ_data
+def get_report_data(last_pur_price, reqd_qty, row, manufacture_details):
+ to_build = row.to_build if row.to_build > 0 else 0
+ diff_qty = to_build - reqd_qty
+ return [row.item_code, row.description,
+ comma_and(manufacture_details.get(row.item_code, {}).get('manufacturer', []), add_quotes=False),
+ comma_and(manufacture_details.get(row.item_code, {}).get('manufacturer_part', []), add_quotes=False),
+ row.actual_qty, str(to_build),
+ reqd_qty, diff_qty, last_pur_price]
+
def get_columns():
"""return columns"""
columns = [
_("Item") + ":Link/Item:100",
_("Description") + "::150",
- _("Manufacturer") + "::100",
- _("Manufacturer Part Number") + "::100",
+ _("Manufacturer") + "::250",
+ _("Manufacturer Part Number") + "::250",
_("Qty") + ":Float:50",
_("Stock Qty") + ":Float:100",
_("Reqd Qty")+ ":Float:100",
_("Diff Qty")+ ":Float:100",
_("Last Purchase Price")+ ":Float:100",
-
-
]
-
return columns
def get_bom_stock(filters):
@@ -85,7 +87,12 @@
GROUP BY bom_item.item_code""".format(qty_field=qty_field, table=table, conditions=conditions, bom=bom), as_dict=1)
-def get_item_details(item_code):
- items = frappe.db.sql("""select it.item_group, it.item_name, it.stock_uom, it.name, it.brand, it.description, it.manufacturer_part_no, it.manufacturer from tabItem it where it.item_code = %s""", item_code, as_dict=1)
+def get_manufacturer_records():
+ details = frappe.get_list('Item Manufacturer', fields = ["manufacturer", "manufacturer_part_no, parent"])
+ manufacture_details = frappe._dict()
+ for detail in details:
+ dic = manufacture_details.setdefault(detail.get('parent'), {})
+ dic.setdefault('manufacturer', []).append(detail.get('manufacturer'))
+ dic.setdefault('manufacturer_part', []).append(detail.get('manufacturer_part_no'))
- return dict((d.name, d) for d in items)
+ return manufacture_details
\ No newline at end of file
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index ee6bdff..cea4662 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -586,6 +586,7 @@
erpnext.patches.v11_1.setup_guardian_role
execute:frappe.delete_doc('DocType', 'Notification Control')
erpnext.patches.v12_0.set_gst_category
+erpnext.patches.v12_0.update_gst_category
erpnext.patches.v11_0.remove_barcodes_field_from_copy_fields_to_variants
erpnext.patches.v12_0.set_task_status
erpnext.patches.v11_0.make_italian_localization_fields # 26-03-2019
@@ -638,6 +639,21 @@
erpnext.patches.v12_0.rename_bank_account_field_in_journal_entry_account
erpnext.patches.v12_0.create_default_energy_point_rules
erpnext.patches.v12_0.set_produced_qty_field_in_sales_order_for_work_order
-erpnext.patches.v12_0.generate_leave_ledger_entries
erpnext.patches.v12_0.set_default_shopify_app_type
+erpnext.patches.v12_0.set_cwip_and_delete_asset_settings
+erpnext.patches.v12_0.set_expense_account_in_landed_cost_voucher_taxes
erpnext.patches.v12_0.replace_accounting_with_accounts_in_home_settings
+erpnext.patches.v12_0.set_payment_entry_status
+erpnext.patches.v12_0.update_owner_fields_in_acc_dimension_custom_fields
+erpnext.patches.v12_0.set_default_for_add_taxes_from_item_tax_template
+erpnext.patches.v12_0.add_export_type_field_in_party_master
+erpnext.patches.v12_0.remove_denied_leaves_from_leave_ledger
+erpnext.patches.v12_0.update_price_or_product_discount
+erpnext.patches.v12_0.set_production_capacity_in_workstation
+erpnext.patches.v12_0.set_employee_preferred_emails
+erpnext.patches.v12_0.set_against_blanket_order_in_sales_and_purchase_order
+erpnext.patches.v12_0.set_cost_center_in_child_table_of_expense_claim
+erpnext.patches.v12_0.set_lead_title_field
+erpnext.patches.v12_0.set_permission_einvoicing
+erpnext.patches.v12_0.set_published_in_hub_tracked_item
+erpnext.patches.v12_0.set_job_offer_applicant_email
diff --git a/erpnext/patches/v11_0/make_asset_finance_book_against_old_entries.py b/erpnext/patches/v11_0/make_asset_finance_book_against_old_entries.py
index 1c8bd68..ee709ac 100644
--- a/erpnext/patches/v11_0/make_asset_finance_book_against_old_entries.py
+++ b/erpnext/patches/v11_0/make_asset_finance_book_against_old_entries.py
@@ -17,10 +17,6 @@
frappe.db.sql(""" update `tabAsset` ast, `tabWarehouse` wh
set ast.location = wh.warehouse_name where ast.warehouse = wh.name""")
- frappe.db.sql(""" update `tabAsset Movement` ast_mv
- set ast_mv.source_location = (select warehouse_name from `tabWarehouse` where name = ast_mv.source_warehouse),
- ast_mv.target_location = (select warehouse_name from `tabWarehouse` where name = ast_mv.target_warehouse)""")
-
for d in frappe.get_all('Asset'):
doc = frappe.get_doc('Asset', d.name)
if doc.calculate_depreciation:
diff --git a/erpnext/patches/v11_0/rename_bom_wo_fields.py b/erpnext/patches/v11_0/rename_bom_wo_fields.py
index c8106a6..b4a740f 100644
--- a/erpnext/patches/v11_0/rename_bom_wo_fields.py
+++ b/erpnext/patches/v11_0/rename_bom_wo_fields.py
@@ -15,13 +15,6 @@
rename_field(doctype, "allow_transfer_for_manufacture", "include_item_in_manufacturing")
- if frappe.db.has_column('BOM', 'allow_same_item_multiple_times'):
- frappe.db.sql(""" UPDATE tabBOM
- SET
- allow_same_item_multiple_times = 0
- WHERE
- trim(coalesce(allow_same_item_multiple_times, '')) = '' """)
-
for doctype in ['BOM', 'Work Order']:
frappe.reload_doc('manufacturing', 'doctype', frappe.scrub(doctype))
diff --git a/erpnext/patches/v11_0/update_delivery_trip_status.py b/erpnext/patches/v11_0/update_delivery_trip_status.py
index 64b3063..42f017e 100755
--- a/erpnext/patches/v11_0/update_delivery_trip_status.py
+++ b/erpnext/patches/v11_0/update_delivery_trip_status.py
@@ -1,27 +1,28 @@
-# Copyright (c) 2017, Frappe and Contributors
-# License: GNU General Public License v3. See license.txt
-
-from __future__ import unicode_literals
-import frappe
-
-def execute():
- frappe.reload_doc('stock', 'doctype', 'delivery_trip')
- frappe.reload_doc('stock', 'doctype', 'delivery_stop', force=True)
-
- for trip in frappe.get_all("Delivery Trip"):
- trip_doc = frappe.get_doc("Delivery Trip", trip.name)
-
- status = {
- 0: "Draft",
- 1: "Scheduled",
- 2: "Cancelled"
- }[trip_doc.docstatus]
-
- if trip_doc.docstatus == 1:
- visited_stops = [stop.visited for stop in trip_doc.delivery_stops]
- if all(visited_stops):
- status = "Completed"
- elif any(visited_stops):
- status = "In Transit"
-
- frappe.db.set_value("Delivery Trip", trip.name, "status", status, update_modified=False)
+# Copyright (c) 2017, Frappe and Contributors
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+import frappe
+
+def execute():
+ frappe.reload_doc('setup', 'doctype', 'global_defaults', force=True)
+ frappe.reload_doc('stock', 'doctype', 'delivery_trip')
+ frappe.reload_doc('stock', 'doctype', 'delivery_stop', force=True)
+
+ for trip in frappe.get_all("Delivery Trip"):
+ trip_doc = frappe.get_doc("Delivery Trip", trip.name)
+
+ status = {
+ 0: "Draft",
+ 1: "Scheduled",
+ 2: "Cancelled"
+ }[trip_doc.docstatus]
+
+ if trip_doc.docstatus == 1:
+ visited_stops = [stop.visited for stop in trip_doc.delivery_stops]
+ if all(visited_stops):
+ status = "Completed"
+ elif any(visited_stops):
+ status = "In Transit"
+
+ frappe.db.set_value("Delivery Trip", trip.name, "status", status, update_modified=False)
diff --git a/erpnext/patches/v12_0/add_export_type_field_in_party_master.py b/erpnext/patches/v12_0/add_export_type_field_in_party_master.py
new file mode 100644
index 0000000..5bb6e3f
--- /dev/null
+++ b/erpnext/patches/v12_0/add_export_type_field_in_party_master.py
@@ -0,0 +1,42 @@
+from __future__ import unicode_literals
+import frappe
+from erpnext.regional.india.setup import make_custom_fields
+
+def execute():
+
+ company = frappe.get_all('Company', filters = {'country': 'India'})
+ if not company:
+ return
+
+ make_custom_fields()
+
+ frappe.reload_doctype('Tax Category')
+ frappe.reload_doctype('Sales Taxes and Charges Template')
+ frappe.reload_doctype('Purchase Taxes and Charges Template')
+
+ # Create tax category with inter state field checked
+ tax_category = frappe.db.get_value('Tax Category', {'name': 'OUT OF STATE'}, 'name')
+
+ if not tax_category:
+ inter_state_category = frappe.get_doc({
+ 'doctype': 'Tax Category',
+ 'title': 'OUT OF STATE',
+ 'is_inter_state': 1
+ }).insert()
+
+ tax_category = inter_state_category.name
+
+ for doctype in ('Sales Taxes and Charges Template', 'Purchase Taxes and Charges Template'):
+ if not frappe.get_meta(doctype).has_field('is_inter_state'): continue
+
+ template = frappe.db.get_value(doctype, {'is_inter_state': 1, 'disabled': 0}, ['name'])
+ if template:
+ frappe.db.set_value(doctype, template, 'tax_category', tax_category)
+
+ frappe.db.sql("""
+ DELETE FROM `tabCustom Field`
+ WHERE fieldname = 'is_inter_state'
+ AND dt IN ('Sales Taxes and Charges Template', 'Purchase Taxes and Charges Template')
+ """)
+
+
diff --git a/erpnext/patches/v12_0/move_item_tax_to_item_tax_template.py b/erpnext/patches/v12_0/move_item_tax_to_item_tax_template.py
index 412f320..5a12795 100644
--- a/erpnext/patches/v12_0/move_item_tax_to_item_tax_template.py
+++ b/erpnext/patches/v12_0/move_item_tax_to_item_tax_template.py
@@ -1,20 +1,30 @@
import frappe
import json
from six import iteritems
+from frappe.model.naming import make_autoname
def execute():
if "tax_type" not in frappe.db.get_table_columns("Item Tax"):
return
old_item_taxes = {}
item_tax_templates = {}
- rename_template_to_untitled = []
+
+ frappe.reload_doc("accounts", "doctype", "item_tax_template_detail", force=1)
+ frappe.reload_doc("accounts", "doctype", "item_tax_template", force=1)
+ existing_templates = frappe.db.sql("""select template.name, details.tax_type, details.tax_rate
+ from `tabItem Tax Template` template, `tabItem Tax Template Detail` details
+ where details.parent=template.name
+ """, as_dict=1)
+
+ if len(existing_templates):
+ for d in existing_templates:
+ item_tax_templates.setdefault(d.name, {})
+ item_tax_templates[d.name][d.tax_type] = d.tax_rate
for d in frappe.db.sql("""select parent as item_code, tax_type, tax_rate from `tabItem Tax`""", as_dict=1):
old_item_taxes.setdefault(d.item_code, [])
old_item_taxes[d.item_code].append(d)
- frappe.reload_doc("accounts", "doctype", "item_tax_template_detail", force=1)
- frappe.reload_doc("accounts", "doctype", "item_tax_template", force=1)
frappe.reload_doc("stock", "doctype", "item", force=1)
frappe.reload_doc("stock", "doctype", "item_tax", force=1)
frappe.reload_doc("selling", "doctype", "quotation_item", force=1)
@@ -27,6 +37,8 @@
frappe.reload_doc("accounts", "doctype", "purchase_invoice_item", force=1)
frappe.reload_doc("accounts", "doctype", "accounts_settings", force=1)
+ frappe.db.auto_commit_on_many_writes = True
+
# for each item that have item tax rates
for item_code in old_item_taxes.keys():
# make current item's tax map
@@ -34,8 +46,7 @@
for d in old_item_taxes[item_code]:
item_tax_map[d.tax_type] = d.tax_rate
- item_tax_template_name = get_item_tax_template(item_tax_templates, rename_template_to_untitled,
- item_tax_map, item_code)
+ item_tax_template_name = get_item_tax_template(item_tax_templates, item_tax_map, item_code)
# update the item tax table
item = frappe.get_doc("Item", item_code)
@@ -49,53 +60,75 @@
'Quotation', 'Sales Order', 'Delivery Note', 'Sales Invoice',
'Supplier Quotation', 'Purchase Order', 'Purchase Receipt', 'Purchase Invoice'
]
- for dt in doctypes:
- for d in frappe.db.sql("""select name, parent, item_code, item_tax_rate from `tab{0} Item`
- where ifnull(item_tax_rate, '') not in ('', '{{}}')""".format(dt), as_dict=1):
- item_tax_map = json.loads(d.item_tax_rate)
- item_tax_template = get_item_tax_template(item_tax_templates, rename_template_to_untitled,
- item_tax_map, d.item_code, d.parent)
- frappe.db.set_value(dt + " Item", d.name, "item_tax_template", item_tax_template)
- idx = 1
- for oldname in rename_template_to_untitled:
- frappe.rename_doc("Item Tax Template", oldname, "Untitled {}".format(idx))
- idx += 1
+ for dt in doctypes:
+ for d in frappe.db.sql("""select name, parenttype, parent, item_code, item_tax_rate from `tab{0} Item`
+ where ifnull(item_tax_rate, '') not in ('', '{{}}')
+ and item_tax_template is NULL""".format(dt), as_dict=1):
+ item_tax_map = json.loads(d.item_tax_rate)
+ item_tax_template_name = get_item_tax_template(item_tax_templates,
+ item_tax_map, d.item_code, d.parenttype, d.parent)
+ frappe.db.set_value(dt + " Item", d.name, "item_tax_template", item_tax_template_name)
+
+ frappe.db.auto_commit_on_many_writes = False
settings = frappe.get_single("Accounts Settings")
settings.add_taxes_from_item_tax_template = 0
settings.determine_address_tax_category_from = "Billing Address"
settings.save()
-def get_item_tax_template(item_tax_templates, rename_template_to_untitled, item_tax_map, item_code, parent=None):
+def get_item_tax_template(item_tax_templates, item_tax_map, item_code, parenttype=None, parent=None):
# search for previously created item tax template by comparing tax maps
for template, item_tax_template_map in iteritems(item_tax_templates):
if item_tax_map == item_tax_template_map:
- if not parent:
- rename_template_to_untitled.append(template)
return template
# if no item tax template found, create one
item_tax_template = frappe.new_doc("Item Tax Template")
- item_tax_template.title = "{}--{}".format(parent, item_code) if parent else "Item-{}".format(item_code)
+ item_tax_template.title = make_autoname("Item Tax Template-.####")
+
for tax_type, tax_rate in iteritems(item_tax_map):
- if not frappe.db.exists("Account", tax_type):
+ account_details = frappe.db.get_value("Account", tax_type, ['name', 'account_type'], as_dict=1)
+ if account_details:
+ if account_details.account_type not in ('Tax', 'Chargeable', 'Income Account', 'Expense Account', 'Expenses Included In Valuation'):
+ frappe.db.set_value('Account', account_details.name, 'account_type', 'Chargeable')
+ else:
parts = tax_type.strip().split(" - ")
account_name = " - ".join(parts[:-1])
- company = frappe.db.get_value("Company", filters={"abbr": parts[-1]})
+ company = get_company(parts[-1], parenttype, parent)
parent_account = frappe.db.get_value("Account",
filters={"account_type": "Tax", "root_type": "Liability", "is_group": 0, "company": company}, fieldname="parent_account")
-
- frappe.get_doc({
- "doctype": "Account",
+ if not parent_account:
+ parent_account = frappe.db.get_value("Account",
+ filters={"account_type": "Tax", "root_type": "Liability", "is_group": 1, "company": company})
+ filters = {
"account_name": account_name,
"company": company,
"account_type": "Tax",
"parent_account": parent_account
- }).insert()
+ }
+ tax_type = frappe.db.get_value("Account", filters)
+ if not tax_type:
+ account = frappe.new_doc("Account")
+ account.update(filters)
+ account.insert()
+ tax_type = account.name
item_tax_template.append("taxes", {"tax_type": tax_type, "tax_rate": tax_rate})
item_tax_templates.setdefault(item_tax_template.title, {})
item_tax_templates[item_tax_template.title][tax_type] = tax_rate
item_tax_template.save()
return item_tax_template.name
+
+def get_company(company_abbr, parenttype=None, parent=None):
+ if parenttype and parent:
+ company = frappe.get_cached_value(parenttype, parent, 'company')
+ else:
+ company = frappe.db.get_value("Company", filters={"abbr": company_abbr})
+
+ if not company:
+ companies = frappe.get_all('Company')
+ if len(companies) == 1:
+ company = companies[0].name
+
+ return company
diff --git a/erpnext/patches/v12_0/remove_denied_leaves_from_leave_ledger.py b/erpnext/patches/v12_0/remove_denied_leaves_from_leave_ledger.py
new file mode 100644
index 0000000..7859606
--- /dev/null
+++ b/erpnext/patches/v12_0/remove_denied_leaves_from_leave_ledger.py
@@ -0,0 +1,28 @@
+# Copyright (c) 2018, Frappe and Contributors
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe.utils import getdate, today
+
+def execute():
+ ''' Delete leave ledger entry created
+ via leave applications with status != Approved '''
+ if not frappe.db.a_row_exists("Leave Ledger Entry"):
+ return
+
+ leave_application_list = get_denied_leave_application_list()
+ if leave_application_list:
+ delete_denied_leaves_from_leave_ledger_entry(leave_application_list)
+
+def get_denied_leave_application_list():
+ return frappe.db.sql_list(''' Select name from `tabLeave Application` where status <> 'Approved' ''')
+
+def delete_denied_leaves_from_leave_ledger_entry(leave_application_list):
+ if leave_application_list:
+ frappe.db.sql(''' Delete
+ FROM `tabLeave Ledger Entry`
+ WHERE
+ transaction_type = 'Leave Application'
+ AND transaction_name in (%s) ''' % (', '.join(['%s'] * len(leave_application_list))), #nosec
+ tuple(leave_application_list))
\ No newline at end of file
diff --git a/erpnext/patches/v12_0/set_against_blanket_order_in_sales_and_purchase_order.py b/erpnext/patches/v12_0/set_against_blanket_order_in_sales_and_purchase_order.py
new file mode 100644
index 0000000..3fccbfa
--- /dev/null
+++ b/erpnext/patches/v12_0/set_against_blanket_order_in_sales_and_purchase_order.py
@@ -0,0 +1,12 @@
+import frappe
+def execute():
+
+ frappe.reload_doc('selling', 'doctype', frappe.scrub('Sales Order Item'))
+ frappe.reload_doc('buying', 'doctype', frappe.scrub('Purchase Order Item'))
+
+ for doctype in ['Sales Order Item', 'Purchase Order Item']:
+ frappe.db.sql("""
+ UPDATE `tab{0}`
+ SET against_blanket_order = 1
+ WHERE ifnull(blanket_order, '') != ''
+ """.format(doctype))
diff --git a/erpnext/patches/v12_0/set_cost_center_in_child_table_of_expense_claim.py b/erpnext/patches/v12_0/set_cost_center_in_child_table_of_expense_claim.py
new file mode 100644
index 0000000..8ba0d79
--- /dev/null
+++ b/erpnext/patches/v12_0/set_cost_center_in_child_table_of_expense_claim.py
@@ -0,0 +1,8 @@
+import frappe
+def execute():
+ frappe.reload_doc('hr', 'doctype', 'expense_claim_detail')
+ frappe.db.sql("""
+ UPDATE `tabExpense Claim Detail` child, `tabExpense Claim` par
+ SET child.cost_center = par.cost_center
+ WHERE child.parent = par.name
+ """)
\ No newline at end of file
diff --git a/erpnext/patches/v12_0/set_cwip_and_delete_asset_settings.py b/erpnext/patches/v12_0/set_cwip_and_delete_asset_settings.py
new file mode 100644
index 0000000..4d4fc7c
--- /dev/null
+++ b/erpnext/patches/v12_0/set_cwip_and_delete_asset_settings.py
@@ -0,0 +1,17 @@
+from __future__ import unicode_literals
+import frappe
+from frappe.utils import cint
+
+
+def execute():
+ '''Get 'Disable CWIP Accounting value' from Asset Settings, set it in 'Enable Capital Work in Progress Accounting' field
+ in Company, delete Asset Settings '''
+
+ if frappe.db.exists("DocType", "Asset Settings"):
+ frappe.reload_doctype("Asset Category")
+ cwip_value = frappe.db.get_single_value("Asset Settings", "disable_cwip_accounting")
+
+ frappe.db.sql("""UPDATE `tabAsset Category` SET enable_cwip_accounting = %s""", cint(cwip_value))
+
+ frappe.db.sql("""DELETE FROM `tabSingles` where doctype = 'Asset Settings'""")
+ frappe.delete_doc_if_exists("DocType", "Asset Settings")
\ No newline at end of file
diff --git a/erpnext/patches/v12_0/set_default_for_add_taxes_from_item_tax_template.py b/erpnext/patches/v12_0/set_default_for_add_taxes_from_item_tax_template.py
new file mode 100644
index 0000000..06ee798
--- /dev/null
+++ b/erpnext/patches/v12_0/set_default_for_add_taxes_from_item_tax_template.py
@@ -0,0 +1,5 @@
+import frappe
+
+def execute():
+ frappe.db.set_value("Accounts Settings", None, "add_taxes_from_item_tax_template", 1)
+ frappe.db.set_default("add_taxes_from_item_tax_template", 1)
\ No newline at end of file
diff --git a/erpnext/patches/v12_0/set_employee_preferred_emails.py b/erpnext/patches/v12_0/set_employee_preferred_emails.py
new file mode 100644
index 0000000..f6eb12e
--- /dev/null
+++ b/erpnext/patches/v12_0/set_employee_preferred_emails.py
@@ -0,0 +1,16 @@
+import frappe
+
+
+def execute():
+ employees = frappe.get_all("Employee",
+ filters={"prefered_email": ""},
+ fields=["name", "prefered_contact_email", "company_email", "personal_email", "user_id"])
+
+ for employee in employees:
+ if not employee.prefered_contact_email:
+ continue
+
+ preferred_email_field = frappe.scrub(employee.prefered_contact_email)
+
+ preferred_email = employee.get(preferred_email_field)
+ frappe.db.set_value("Employee", employee.name, "prefered_email", preferred_email, update_modified=False)
diff --git a/erpnext/patches/v12_0/set_expense_account_in_landed_cost_voucher_taxes.py b/erpnext/patches/v12_0/set_expense_account_in_landed_cost_voucher_taxes.py
new file mode 100644
index 0000000..a996a69
--- /dev/null
+++ b/erpnext/patches/v12_0/set_expense_account_in_landed_cost_voucher_taxes.py
@@ -0,0 +1,33 @@
+from __future__ import unicode_literals
+import frappe
+from six import iteritems
+
+def execute():
+ frappe.reload_doctype('Landed Cost Taxes and Charges')
+
+ company_account_map = frappe._dict(frappe.db.sql("""
+ SELECT name, expenses_included_in_valuation from `tabCompany`
+ """))
+
+ for company, account in iteritems(company_account_map):
+ frappe.db.sql("""
+ UPDATE
+ `tabLanded Cost Taxes and Charges` t, `tabLanded Cost Voucher` l
+ SET
+ t.expense_account = %s
+ WHERE
+ l.docstatus = 1
+ AND l.company = %s
+ AND t.parent = l.name
+ """, (account, company))
+
+ frappe.db.sql("""
+ UPDATE
+ `tabLanded Cost Taxes and Charges` t, `tabStock Entry` s
+ SET
+ t.expense_account = %s
+ WHERE
+ s.docstatus = 1
+ AND s.company = %s
+ AND t.parent = s.name
+ """, (account, company))
\ No newline at end of file
diff --git a/erpnext/patches/v12_0/set_gst_category.py b/erpnext/patches/v12_0/set_gst_category.py
index 54bc5b3..55bbdee 100644
--- a/erpnext/patches/v12_0/set_gst_category.py
+++ b/erpnext/patches/v12_0/set_gst_category.py
@@ -7,6 +7,8 @@
if not company:
return
+ frappe.reload_doc('accounts', 'doctype', 'Tax Category')
+
make_custom_fields()
for doctype in ['Sales Invoice', 'Purchase Invoice']:
diff --git a/erpnext/patches/v12_0/set_job_offer_applicant_email.py b/erpnext/patches/v12_0/set_job_offer_applicant_email.py
new file mode 100644
index 0000000..7dd8492
--- /dev/null
+++ b/erpnext/patches/v12_0/set_job_offer_applicant_email.py
@@ -0,0 +1,12 @@
+import frappe
+
+
+def execute():
+ frappe.reload_doc("hr", "doctype", "job_offer")
+
+ frappe.db.sql("""
+ UPDATE
+ `tabJob Offer` AS offer
+ SET
+ applicant_email = (SELECT email_id FROM `tabJob Applicant` WHERE name = offer.job_applicant)
+ """)
diff --git a/erpnext/patches/v12_0/set_lead_title_field.py b/erpnext/patches/v12_0/set_lead_title_field.py
new file mode 100644
index 0000000..86e0003
--- /dev/null
+++ b/erpnext/patches/v12_0/set_lead_title_field.py
@@ -0,0 +1,11 @@
+import frappe
+
+
+def execute():
+ frappe.reload_doc("crm", "doctype", "lead")
+ frappe.db.sql("""
+ UPDATE
+ `tabLead`
+ SET
+ title = IF(organization_lead = 1, company_name, lead_name)
+ """)
diff --git a/erpnext/patches/v12_0/set_payment_entry_status.py b/erpnext/patches/v12_0/set_payment_entry_status.py
new file mode 100644
index 0000000..fafbec6
--- /dev/null
+++ b/erpnext/patches/v12_0/set_payment_entry_status.py
@@ -0,0 +1,9 @@
+import frappe
+
+def execute():
+ frappe.reload_doctype("Payment Entry")
+ frappe.db.sql("""update `tabPayment Entry` set status = CASE
+ WHEN docstatus = 1 THEN 'Submitted'
+ WHEN docstatus = 2 THEN 'Cancelled'
+ ELSE 'Draft'
+ END;""")
\ No newline at end of file
diff --git a/erpnext/patches/v12_0/set_permission_einvoicing.py b/erpnext/patches/v12_0/set_permission_einvoicing.py
new file mode 100644
index 0000000..1095c8c
--- /dev/null
+++ b/erpnext/patches/v12_0/set_permission_einvoicing.py
@@ -0,0 +1,15 @@
+import frappe
+from erpnext.regional.italy.setup import make_custom_fields
+from frappe.permissions import add_permission, update_permission_property
+
+def execute():
+ company = frappe.get_all('Company', filters = {'country': 'Italy'})
+
+ if not company:
+ return
+
+ make_custom_fields()
+
+ add_permission('Import Supplier Invoice', 'Accounts Manager', 0)
+ update_permission_property('Import Supplier Invoice', 'Accounts Manager', 0, 'write', 1)
+ update_permission_property('Import Supplier Invoice', 'Accounts Manager', 0, 'create', 1)
\ No newline at end of file
diff --git a/erpnext/patches/v12_0/set_produced_qty_field_in_sales_order_for_work_order.py b/erpnext/patches/v12_0/set_produced_qty_field_in_sales_order_for_work_order.py
index 44d8fa7..0702673 100644
--- a/erpnext/patches/v12_0/set_produced_qty_field_in_sales_order_for_work_order.py
+++ b/erpnext/patches/v12_0/set_produced_qty_field_in_sales_order_for_work_order.py
@@ -3,8 +3,12 @@
from erpnext.selling.doctype.sales_order.sales_order import update_produced_qty_in_so_item
def execute():
- frappe.reload_doctype('Sales Order Item')
- frappe.reload_doctype('Sales Order')
- sales_order_items = frappe.db.get_all('Sales Order Item', ['name'])
- for so_item in sales_order_items:
- update_produced_qty_in_so_item(so_item.get('name'))
\ No newline at end of file
+ frappe.reload_doctype('Sales Order Item')
+ frappe.reload_doctype('Sales Order')
+
+ for d in frappe.get_all('Work Order',
+ fields = ['sales_order', 'sales_order_item'],
+ filters={'sales_order': ('!=', ''), 'sales_order_item': ('!=', '')}):
+
+ # update produced qty in sales order
+ update_produced_qty_in_so_item(d.sales_order, d.sales_order_item)
\ No newline at end of file
diff --git a/erpnext/patches/v12_0/set_production_capacity_in_workstation.py b/erpnext/patches/v12_0/set_production_capacity_in_workstation.py
new file mode 100644
index 0000000..bae1e28
--- /dev/null
+++ b/erpnext/patches/v12_0/set_production_capacity_in_workstation.py
@@ -0,0 +1,8 @@
+from __future__ import unicode_literals
+import frappe
+
+def execute():
+ frappe.reload_doc("manufacturing", "doctype", "workstation")
+
+ frappe.db.sql(""" UPDATE `tabWorkstation`
+ SET production_capacity = 1 """)
\ No newline at end of file
diff --git a/erpnext/patches/v12_0/set_published_in_hub_tracked_item.py b/erpnext/patches/v12_0/set_published_in_hub_tracked_item.py
new file mode 100644
index 0000000..e54c7f3
--- /dev/null
+++ b/erpnext/patches/v12_0/set_published_in_hub_tracked_item.py
@@ -0,0 +1,12 @@
+from __future__ import unicode_literals
+import frappe
+
+def execute():
+ frappe.reload_doc("Hub Node", "doctype", "Hub Tracked Item")
+ if not frappe.db.a_row_exists("Hub Tracked Item"):
+ return
+
+ frappe.db.sql('''
+ Update `tabHub Tracked Item`
+ SET published = 1
+ ''')
diff --git a/erpnext/patches/v12_0/update_gst_category.py b/erpnext/patches/v12_0/update_gst_category.py
new file mode 100644
index 0000000..963edad
--- /dev/null
+++ b/erpnext/patches/v12_0/update_gst_category.py
@@ -0,0 +1,19 @@
+from __future__ import unicode_literals
+import frappe
+
+def execute():
+
+ company = frappe.get_all('Company', filters = {'country': 'India'})
+ if not company:
+ return
+
+ frappe.db.sql(""" UPDATE `tabSales Invoice` set gst_category = 'Unregistered'
+ where gst_category = 'Registered Regular'
+ and ifnull(customer_gstin, '')=''
+ and ifnull(billing_address_gstin,'')=''
+ """)
+
+ frappe.db.sql(""" UPDATE `tabPurchase Invoice` set gst_category = 'Unregistered'
+ where gst_category = 'Registered Regular'
+ and ifnull(supplier_gstin, '')=''
+ """)
\ No newline at end of file
diff --git a/erpnext/patches/v12_0/update_owner_fields_in_acc_dimension_custom_fields.py b/erpnext/patches/v12_0/update_owner_fields_in_acc_dimension_custom_fields.py
new file mode 100644
index 0000000..e4dcecd
--- /dev/null
+++ b/erpnext/patches/v12_0/update_owner_fields_in_acc_dimension_custom_fields.py
@@ -0,0 +1,17 @@
+from __future__ import unicode_literals
+import frappe
+from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_doctypes_with_dimensions
+
+def execute():
+ accounting_dimensions = frappe.db.sql("""select fieldname from
+ `tabAccounting Dimension`""", as_dict=1)
+
+ doclist = get_doctypes_with_dimensions()
+
+ for dimension in accounting_dimensions:
+ frappe.db.sql("""
+ UPDATE `tabCustom Field`
+ SET owner = 'Administrator'
+ WHERE fieldname = %s
+ AND dt IN (%s)""" % #nosec
+ ('%s', ', '.join(['%s']* len(doclist))), tuple([dimension.fieldname] + doclist))
\ No newline at end of file
diff --git a/erpnext/patches/v12_0/update_price_or_product_discount.py b/erpnext/patches/v12_0/update_price_or_product_discount.py
new file mode 100644
index 0000000..3a8cd43
--- /dev/null
+++ b/erpnext/patches/v12_0/update_price_or_product_discount.py
@@ -0,0 +1,8 @@
+from __future__ import unicode_literals
+import frappe
+
+def execute():
+ frappe.reload_doc("accounts", "doctype", "pricing_rule")
+
+ frappe.db.sql(""" UPDATE `tabPricing Rule` SET price_or_product_discount = 'Price'
+ WHERE ifnull(price_or_product_discount,'') = '' """)
diff --git a/erpnext/patches/v8_7/set_offline_in_pos_settings.py b/erpnext/patches/v8_7/set_offline_in_pos_settings.py
index b24fe37..7d2882e 100644
--- a/erpnext/patches/v8_7/set_offline_in_pos_settings.py
+++ b/erpnext/patches/v8_7/set_offline_in_pos_settings.py
@@ -5,6 +5,7 @@
import frappe
def execute():
+ frappe.reload_doc('accounts', 'doctype', 'pos_field')
frappe.reload_doc('accounts', 'doctype', 'pos_settings')
doc = frappe.get_doc('POS Settings')
diff --git a/erpnext/patches/v8_9/add_setup_progress_actions.py b/erpnext/patches/v8_9/add_setup_progress_actions.py
index fe12311..7750107 100644
--- a/erpnext/patches/v8_9/add_setup_progress_actions.py
+++ b/erpnext/patches/v8_9/add_setup_progress_actions.py
@@ -5,6 +5,9 @@
def execute():
"""Add setup progress actions"""
+ if not frappe.db.exists('DocType', 'Setup Progress') or not frappe.db.exists('DocType', 'Setup Progress Action'):
+ return
+
frappe.reload_doc("setup", "doctype", "setup_progress")
frappe.reload_doc("setup", "doctype", "setup_progress_action")
diff --git a/erpnext/portal/doctype/homepage/test_homepage.py b/erpnext/portal/doctype/homepage/test_homepage.py
index b262c46..bf5c402 100644
--- a/erpnext/portal/doctype/homepage/test_homepage.py
+++ b/erpnext/portal/doctype/homepage/test_homepage.py
@@ -5,7 +5,7 @@
import frappe
import unittest
-from frappe.tests.test_website import set_request
+from frappe.utils import set_request
from frappe.website.render import render
class TestHomepage(unittest.TestCase):
diff --git a/erpnext/portal/doctype/homepage_section/test_homepage_section.py b/erpnext/portal/doctype/homepage_section/test_homepage_section.py
index c52b7a9..5b3196d 100644
--- a/erpnext/portal/doctype/homepage_section/test_homepage_section.py
+++ b/erpnext/portal/doctype/homepage_section/test_homepage_section.py
@@ -6,7 +6,7 @@
import frappe
import unittest
from bs4 import BeautifulSoup
-from frappe.tests.test_website import set_request
+from frappe.utils import set_request
from frappe.website.render import render
class TestHomepageSection(unittest.TestCase):
diff --git a/erpnext/portal/product_configurator/test_product_configurator.py b/erpnext/portal/product_configurator/test_product_configurator.py
index a534e5f..97042db 100644
--- a/erpnext/portal/product_configurator/test_product_configurator.py
+++ b/erpnext/portal/product_configurator/test_product_configurator.py
@@ -2,7 +2,7 @@
from bs4 import BeautifulSoup
import frappe, unittest
-from frappe.tests.test_website import set_request, get_html_for_route
+from frappe.utils import set_request, get_html_for_route
from frappe.website.render import render
from erpnext.portal.product_configurator.utils import get_products_for_website
from erpnext.stock.doctype.item.test_item import make_item_variant
diff --git a/erpnext/portal/product_configurator/utils.py b/erpnext/portal/product_configurator/utils.py
index 61c50e5..0993e69 100644
--- a/erpnext/portal/product_configurator/utils.py
+++ b/erpnext/portal/product_configurator/utils.py
@@ -52,7 +52,6 @@
def get_products_for_website(field_filters=None, attribute_filters=None, search=None):
-
if attribute_filters:
item_codes = get_item_codes_by_attributes(attribute_filters)
items_by_attributes = get_items([['name', 'in', item_codes]])
@@ -302,6 +301,8 @@
if isinstance(filters, dict):
filters = [['Item', fieldname, '=', value] for fieldname, value in filters.items()]
+ enabled_items_filter = get_conditions({ 'disabled': 0 }, 'and')
+
show_in_website_condition = ''
if products_settings.hide_variants:
show_in_website_condition = get_conditions({'show_in_website': 1 }, 'and')
@@ -313,19 +314,32 @@
search_condition = ''
if search:
+ # Default fields to search from
+ default_fields = {'name', 'item_name', 'description', 'item_group'}
+
+ # Get meta search fields
+ meta = frappe.get_meta("Item")
+ meta_fields = set(meta.get_search_fields())
+
+ # Join the meta fields and default fields set
+ search_fields = default_fields.union(meta_fields)
+ try:
+ if frappe.db.count('Item', cache=True) > 50000:
+ search_fields.remove('description')
+ except KeyError:
+ pass
+
+ # Build or filters for query
search = '%{}%'.format(search)
- or_filters = [
- ['name', 'like', search],
- ['item_name', 'like', search],
- ['description', 'like', search],
- ['item_group', 'like', search]
- ]
+ or_filters = [[field, 'like', search] for field in search_fields]
+
search_condition = get_conditions(or_filters, 'or')
filter_condition = get_conditions(filters, 'and')
where_conditions = ' and '.join(
- [condition for condition in [show_in_website_condition, search_condition, filter_condition] if condition]
+ [condition for condition in [enabled_items_filter, show_in_website_condition, \
+ search_condition, filter_condition] if condition]
)
left_joins = []
diff --git a/erpnext/projects/doctype/project/project.js b/erpnext/projects/doctype/project/project.js
index beba2bb..3570a0f 100644
--- a/erpnext/projects/doctype/project/project.js
+++ b/erpnext/projects/doctype/project/project.js
@@ -4,19 +4,18 @@
setup(frm) {
frm.make_methods = {
'Timesheet': () => {
- let doctype = 'Timesheet';
- frappe.model.with_doctype(doctype, () => {
- let new_doc = frappe.model.get_new_doc(doctype);
-
- // add a new row and set the project
- let time_log = frappe.model.get_new_doc('Timesheet Detail');
- time_log.project = frm.doc.name;
- new_doc.time_logs = [time_log];
-
- frappe.ui.form.make_quick_entry(doctype, null, null, new_doc);
- });
+ open_form(frm, "Timesheet", "Timesheet Detail", "time_logs");
},
- }
+ 'Purchase Order': () => {
+ open_form(frm, "Purchase Order", "Purchase Order Item", "items");
+ },
+ 'Purchase Receipt': () => {
+ open_form(frm, "Purchase Receipt", "Purchase Receipt Item", "items");
+ },
+ 'Purchase Invoice': () => {
+ open_form(frm, "Purchase Invoice", "Purchase Invoice Item", "items");
+ },
+ };
},
onload: function (frm) {
var so = frappe.meta.get_docfield("Project", "sales_order");
@@ -25,15 +24,15 @@
return {
"customer": frm.doc.customer,
"project_name": frm.doc.name
- }
- }
+ };
+ };
frm.set_query('customer', 'erpnext.controllers.queries.customer_query');
frm.set_query("user", "users", function () {
return {
query: "erpnext.projects.doctype.project.project.get_users_for_project"
- }
+ };
});
// sales order
@@ -48,8 +47,35 @@
return {
filters: filters
- }
+ };
});
+ },
+
+ refresh: function (frm) {
+ if (frm.doc.__islocal) {
+ frm.web_link && frm.web_link.remove();
+ } else {
+ frm.add_web_link("/projects?project=" + encodeURIComponent(frm.doc.name));
+
+ frm.trigger('show_dashboard');
+ }
+ frm.events.set_buttons(frm);
+ },
+
+ set_buttons: function(frm) {
+ if (!frm.is_new()) {
+ frm.add_custom_button(__('Duplicate Project with Tasks'), () => {
+ frm.events.create_duplicate(frm);
+ });
+
+ frm.add_custom_button(__('Completed'), () => {
+ frm.events.set_status(frm, 'Completed');
+ }, __('Set Status'));
+
+ frm.add_custom_button(__('Cancelled'), () => {
+ frm.events.set_status(frm, 'Cancelled');
+ }, __('Set Status'));
+ }
if (frappe.model.can_read("Task")) {
frm.add_custom_button(__("Gantt Chart"), function () {
@@ -69,27 +95,20 @@
}
},
- refresh: function (frm) {
- if (frm.doc.__islocal) {
- frm.web_link && frm.web_link.remove();
- } else {
- frm.add_web_link("/projects?project=" + encodeURIComponent(frm.doc.name));
-
- frm.trigger('show_dashboard');
- }
- frm.events.set_buttons(frm);
- },
-
- set_buttons: function(frm) {
- if (!frm.is_new()) {
- frm.add_custom_button(__('Completed'), () => {
- frm.events.set_status(frm, 'Completed');
- }, __('Set Status'));
-
- frm.add_custom_button(__('Cancelled'), () => {
- frm.events.set_status(frm, 'Cancelled');
- }, __('Set Status'));
- }
+ create_duplicate: function(frm) {
+ return new Promise(resolve => {
+ frappe.prompt('Project Name', (data) => {
+ frappe.xcall('erpnext.projects.doctype.project.project.create_duplicate_project',
+ {
+ prev_doc: frm.doc,
+ project_name: data.value
+ }).then(() => {
+ frappe.set_route('Form', "Project", data.value);
+ frappe.show_alert(__("Duplicate project has been created"));
+ });
+ resolve();
+ });
+ });
},
set_status: function(frm, status) {
@@ -100,3 +119,20 @@
},
});
+
+function open_form(frm, doctype, child_doctype, parentfield) {
+ frappe.model.with_doctype(doctype, () => {
+ let new_doc = frappe.model.get_new_doc(doctype);
+
+ // add a new row and set the project
+ let new_child_doc = frappe.model.get_new_doc(child_doctype);
+ new_child_doc.project = frm.doc.name;
+ new_child_doc.parent = new_doc.name;
+ new_child_doc.parentfield = parentfield;
+ new_child_doc.parenttype = doctype;
+ new_doc[parentfield] = [new_child_doc];
+
+ frappe.ui.form.make_quick_entry(doctype, null, null, new_doc);
+ });
+
+}
\ No newline at end of file
diff --git a/erpnext/projects/doctype/project/project.py b/erpnext/projects/doctype/project/project.py
index 783bcf3..bf6e21a 100644
--- a/erpnext/projects/doctype/project/project.py
+++ b/erpnext/projects/doctype/project/project.py
@@ -323,6 +323,37 @@
if get_time(nowtime()) >= get_time(time):
return True
+
+@frappe.whitelist()
+def create_duplicate_project(prev_doc, project_name):
+ ''' Create duplicate project based on the old project '''
+ import json
+ prev_doc = json.loads(prev_doc)
+
+ if project_name == prev_doc.get('name'):
+ frappe.throw(_("Use a name that is different from previous project name"))
+
+ # change the copied doc name to new project name
+ project = frappe.copy_doc(prev_doc)
+ project.name = project_name
+ project.project_template = ''
+ project.project_name = project_name
+ project.insert()
+
+ # fetch all the task linked with the old project
+ task_list = frappe.get_all("Task", filters={
+ 'project': prev_doc.get('name')
+ }, fields=['name'])
+
+ # Create duplicate task for all the task
+ for task in task_list:
+ task = frappe.get_doc('Task', task)
+ new_task = frappe.copy_doc(task)
+ new_task.project = project.name
+ new_task.insert()
+
+ project.db_set('project_template', prev_doc.get('project_template'))
+
def get_projects_for_collect_progress(frequency, fields):
fields.extend(["name"])
diff --git a/erpnext/projects/doctype/task/task.py b/erpnext/projects/doctype/task/task.py
index 90e9f05..45f2681 100755
--- a/erpnext/projects/doctype/task/task.py
+++ b/erpnext/projects/doctype/task/task.py
@@ -7,9 +7,10 @@
import frappe
from frappe import _, throw
-from frappe.utils import add_days, cstr, date_diff, get_link_to_form, getdate
+from frappe.utils import add_days, cstr, date_diff, get_link_to_form, getdate, today
from frappe.utils.nestedset import NestedSet
from frappe.desk.form.assign_to import close_all_assignments, clear
+from frappe.utils import date_diff
class CircularReferenceError(frappe.ValidationError): pass
class EndDateCannotBeGreaterThanProjectEndDateError(frappe.ValidationError): pass
@@ -28,16 +29,29 @@
def validate(self):
self.validate_dates()
+ self.validate_parent_project_dates()
self.validate_progress()
self.validate_status()
self.update_depends_on()
def validate_dates(self):
if self.exp_start_date and self.exp_end_date and getdate(self.exp_start_date) > getdate(self.exp_end_date):
- frappe.throw(_("'Expected Start Date' can not be greater than 'Expected End Date'"))
+ frappe.throw(_("{0} can not be greater than {1}").format(frappe.bold("Expected Start Date"), \
+ frappe.bold("Expected End Date")))
if self.act_start_date and self.act_end_date and getdate(self.act_start_date) > getdate(self.act_end_date):
- frappe.throw(_("'Actual Start Date' can not be greater than 'Actual End Date'"))
+ frappe.throw(_("{0} can not be greater than {1}").format(frappe.bold("Actual Start Date"), \
+ frappe.bold("Actual End Date")))
+
+ def validate_parent_project_dates(self):
+ if not self.project or frappe.flags.in_test:
+ return
+
+ expected_end_date = frappe.db.get_value("Project", self.project, "expected_end_date")
+
+ if expected_end_date:
+ validate_project_dates(getdate(expected_end_date), self, "exp_start_date", "exp_end_date", "Expected")
+ validate_project_dates(getdate(expected_end_date), self, "act_start_date", "act_end_date", "Actual")
def validate_status(self):
if self.status!=self.get_db_value("status") and self.status == "Completed":
@@ -198,8 +212,11 @@
task.save()
def set_tasks_as_overdue():
- tasks = frappe.get_all("Task", filters={'status':['not in',['Cancelled', 'Completed']]})
+ tasks = frappe.get_all("Task", filters={'status':['not in',['Cancelled', 'Closed']]})
for task in tasks:
+ if frappe.db.get_value("Task", task.name, "status") in 'Pending Review':
+ if getdate(frappe.db.get_value("Task", task.name, "review_date")) < getdate(today()):
+ continue
frappe.get_doc("Task", task.name).update_status()
@frappe.whitelist()
@@ -255,3 +272,10 @@
def on_doctype_update():
frappe.db.add_index("Task", ["lft", "rgt"])
+
+def validate_project_dates(project_end_date, task, task_start, task_end, actual_or_expected_date):
+ if task.get(task_start) and date_diff(project_end_date, getdate(task.get(task_start))) < 0:
+ frappe.throw(_("Task's {0} Start Date cannot be after Project's End Date.").format(actual_or_expected_date))
+
+ if task.get(task_end) and date_diff(project_end_date, getdate(task.get(task_end))) < 0:
+ frappe.throw(_("Task's {0} End Date cannot be after Project's End Date.").format(actual_or_expected_date))
diff --git a/erpnext/projects/doctype/timesheet/timesheet.py b/erpnext/projects/doctype/timesheet/timesheet.py
index 9ee2927..e908216 100644
--- a/erpnext/projects/doctype/timesheet/timesheet.py
+++ b/erpnext/projects/doctype/timesheet/timesheet.py
@@ -188,6 +188,9 @@
}, as_dict=True)
# check internal overlap
for time_log in self.time_logs:
+ if not (time_log.from_time and time_log.to_time
+ and args.from_time and args.to_time): continue
+
if (fieldname != 'workstation' or args.get(fieldname) == time_log.get(fieldname)) and \
args.idx != time_log.idx and ((args.from_time > time_log.from_time and args.from_time < time_log.to_time) or
(args.to_time > time_log.from_time and args.to_time < time_log.to_time) or
@@ -353,17 +356,35 @@
def get_timesheets_list(doctype, txt, filters, limit_start, limit_page_length=20, order_by="modified"):
user = frappe.session.user
# find customer name from contact.
- customer = frappe.db.sql('''SELECT dl.link_name FROM `tabContact` AS c inner join \
- `tabDynamic Link` AS dl ON c.first_name=dl.link_name WHERE c.email_id=%s''',user)
+ customer = ''
+ timesheets = []
+
+ contact = frappe.db.exists('Contact', {'user': user})
+ if contact:
+ # find customer
+ contact = frappe.get_doc('Contact', contact)
+ customer = contact.get_link_for('Customer')
if customer:
- # find list of Sales Invoice for made for customer.
- sales_invoice = frappe.db.sql('''SELECT name FROM `tabSales Invoice` WHERE customer = %s''',customer)
+ sales_invoices = [d.name for d in frappe.get_all('Sales Invoice', filters={'customer': customer})] or [None]
+ projects = [d.name for d in frappe.get_all('Project', filters={'customer': customer})]
# Return timesheet related data to web portal.
- return frappe. db.sql('''SELECT ts.name, tsd.activity_type, ts.status, ts.total_billable_hours, \
- tsd.sales_invoice, tsd.project FROM `tabTimesheet` AS ts inner join `tabTimesheet Detail` \
- AS tsd ON tsd.parent = ts.name where tsd.sales_invoice IN %s order by\
- end_date asc limit {0} , {1}'''.format(limit_start, limit_page_length), [sales_invoice], as_dict = True)
+ timesheets = frappe.db.sql('''
+ SELECT
+ ts.name, tsd.activity_type, ts.status, ts.total_billable_hours,
+ COALESCE(ts.sales_invoice, tsd.sales_invoice) AS sales_invoice, tsd.project
+ FROM `tabTimesheet` ts, `tabTimesheet Detail` tsd
+ WHERE tsd.parent = ts.name AND
+ (
+ ts.sales_invoice IN %(sales_invoices)s OR
+ tsd.sales_invoice IN %(sales_invoices)s OR
+ tsd.project IN %(projects)s
+ )
+ ORDER BY `end_date` ASC
+ LIMIT {0}, {1}
+ '''.format(limit_start, limit_page_length), dict(sales_invoices=sales_invoices, projects=projects), as_dict=True) #nosec
+
+ return timesheets
def get_list_context(context=None):
return {
diff --git a/erpnext/public/js/controllers/accounts.js b/erpnext/public/js/controllers/accounts.js
index 3dfc891..f4eaad5 100644
--- a/erpnext/public/js/controllers/accounts.js
+++ b/erpnext/public/js/controllers/accounts.js
@@ -64,7 +64,7 @@
}
})
}
- }
+ }
});
frappe.ui.form.on('Sales Invoice Payment', {
@@ -355,4 +355,4 @@
out += '</table></td></tr></table></div>';
}
return out;
-}
+}
\ No newline at end of file
diff --git a/erpnext/public/js/controllers/buying.js b/erpnext/public/js/controllers/buying.js
index 02c3058..3d4c4a6 100644
--- a/erpnext/public/js/controllers/buying.js
+++ b/erpnext/public/js/controllers/buying.js
@@ -30,7 +30,7 @@
&& frappe.meta.has_field(this.frm.doc.doctype, "disable_rounded_total")) {
var df = frappe.meta.get_docfield(this.frm.doc.doctype, "disable_rounded_total");
- var disable = df.default || cint(frappe.sys_defaults.disable_rounded_total);
+ var disable = cint(df.default) || cint(frappe.sys_defaults.disable_rounded_total);
this.frm.set_value("disable_rounded_total", disable);
}
@@ -107,6 +107,12 @@
filters:{ 'item_code': row.item_code }
}
});
+
+ if(this.frm.fields_dict["items"].grid.get_field('item_code')) {
+ this.frm.set_query("item_tax_template", "items", function(doc, cdt, cdn) {
+ return me.set_query_for_item_tax_template(doc, cdt, cdn)
+ });
+ }
},
refresh: function(doc) {
diff --git a/erpnext/public/js/controllers/taxes_and_totals.js b/erpnext/public/js/controllers/taxes_and_totals.js
index 2ece711..28fb649 100644
--- a/erpnext/public/js/controllers/taxes_and_totals.js
+++ b/erpnext/public/js/controllers/taxes_and_totals.js
@@ -388,9 +388,14 @@
var diff = me.frm.doc.total + non_inclusive_tax_amount
- flt(last_tax.total, precision("grand_total"));
+ if(me.discount_amount_applied && me.frm.doc.discount_amount) {
+ diff -= flt(me.frm.doc.discount_amount);
+ }
+
+ diff = flt(diff, precision("rounding_adjustment"));
+
if ( diff && Math.abs(diff) <= (5.0 / Math.pow(10, precision("tax_amount", last_tax))) ) {
- this.frm.doc.rounding_adjustment = flt(flt(this.frm.doc.rounding_adjustment) + diff,
- precision("rounding_adjustment"));
+ me.frm.doc.rounding_adjustment = diff;
}
}
}
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index ca492ba..8cfde8c 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -500,6 +500,9 @@
() => {
var d = locals[cdt][cdn];
me.add_taxes_from_item_tax_template(d.item_tax_rate);
+ if (d.free_item_data) {
+ me.apply_product_discount(d.free_item_data);
+ }
},
() => me.frm.script_manager.trigger("price_list_rate", cdt, cdn),
() => me.toggle_conversion_factor(item),
@@ -516,7 +519,7 @@
}
},
() => me.conversion_factor(doc, cdt, cdn, true),
- () => me.validate_pricing_rule(item)
+ () => me.remove_pricing_rule(item)
]);
}
}
@@ -965,7 +968,7 @@
qty: function(doc, cdt, cdn) {
let item = frappe.get_doc(cdt, cdn);
- this.conversion_factor(doc, cdt, cdn, true);
+ this.conversion_factor(doc, cdt, cdn, false);
this.apply_pricing_rule(item, true);
},
@@ -1174,7 +1177,7 @@
callback: function(r) {
if (!r.exc && r.message) {
r.message.forEach(row_item => {
- me.validate_pricing_rule(row_item);
+ me.remove_pricing_rule(row_item);
});
me._set_values_for_item_list(r.message);
me.calculate_taxes_and_totals();
@@ -1283,6 +1286,8 @@
_set_values_for_item_list: function(children) {
var me = this;
var price_list_rate_changed = false;
+ var items_rule_dict = {};
+
for(var i=0, l=children.length; i<l; i++) {
var d = children[i];
var existing_pricing_rule = frappe.model.get_value(d.doctype, d.name, "pricing_rules");
@@ -1299,14 +1304,57 @@
// if pricing rule set as blank from an existing value, apply price_list
if(!me.frm.doc.ignore_pricing_rule && existing_pricing_rule && !d.pricing_rules) {
me.apply_price_list(frappe.get_doc(d.doctype, d.name));
- } else {
- me.validate_pricing_rule(frappe.get_doc(d.doctype, d.name));
+ } else if(!d.pricing_rules) {
+ me.remove_pricing_rule(frappe.get_doc(d.doctype, d.name));
+ }
+
+ if (d.free_item_data) {
+ me.apply_product_discount(d.free_item_data);
+ }
+
+ if (d.apply_rule_on_other_items) {
+ items_rule_dict[d.name] = d;
}
}
+ me.apply_rule_on_other_items(items_rule_dict);
+
if(!price_list_rate_changed) me.calculate_taxes_and_totals();
},
+ apply_rule_on_other_items: function(args) {
+ const me = this;
+ const fields = ["discount_percentage", "discount_amount", "rate"];
+
+ for(var k in args) {
+ let data = args[k];
+
+ me.frm.doc.items.forEach(d => {
+ if (in_list(data.apply_rule_on_other_items, d[data.apply_rule_on])) {
+ for(var k in data) {
+ if (in_list(fields, k)) {
+ frappe.model.set_value(d.doctype, d.name, k, data[k]);
+ }
+ }
+ }
+ });
+ }
+ },
+
+ apply_product_discount: function(free_item_data) {
+ const items = this.frm.doc.items.filter(d => (d.item_code == free_item_data.item_code
+ && d.is_free_item)) || [];
+
+ if (!items.length) {
+ let row_to_modify = frappe.model.add_child(this.frm.doc,
+ this.frm.doc.doctype + ' Item', 'items');
+
+ for (let key in free_item_data) {
+ row_to_modify[key] = free_item_data[key];
+ }
+ }
+ },
+
apply_price_list: function(item, reset_plc_conversion) {
// We need to reset plc_conversion_rate sometimes because the call to
// `erpnext.stock.get_item_details.apply_price_list` is sensitive to its value
@@ -1348,33 +1396,12 @@
});
},
- validate_pricing_rule: function(item) {
+ remove_pricing_rule: function(item) {
let me = this;
- const fields = ["discount_percentage", "discount_amount", "pricing_rules"];
+ const fields = ["discount_percentage",
+ "discount_amount", "margin_rate_or_amount", "rate_with_margin"];
- if (item.pricing_rules) {
- frappe.call({
- method: "erpnext.accounts.doctype.pricing_rule.utils.validate_pricing_rule_for_different_cond",
- args: {
- doc: me.frm.doc
- },
- callback: function(r) {
- if (r.message) {
- r.message.items.forEach(d => {
- me.frm.doc.items.forEach(row => {
- if(d.name == row.name) {
- fields.forEach(f => {
- row[f] = d[f];
- });
- }
- });
- });
-
- me.trigger_price_list_rate();
- }
- }
- });
- } else if(item.remove_free_item) {
+ if(item.remove_free_item) {
var items = [];
me.frm.doc.items.forEach(d => {
@@ -1392,6 +1419,12 @@
fields.forEach(f => {
row[f] = 0;
});
+
+ ["pricing_rules", "margin_type"].forEach(field => {
+ if (row[field]) {
+ row[field] = '';
+ }
+ })
}
});
@@ -1667,6 +1700,29 @@
}
},
+ set_query_for_item_tax_template: function(doc, cdt, cdn) {
+
+ var item = frappe.get_doc(cdt, cdn);
+ if(!item.item_code) {
+ frappe.throw(__("Please enter Item Code to get item taxes"));
+ } else {
+
+ let filters = {
+ 'item_code': item.item_code,
+ 'valid_from': doc.transaction_date || doc.bill_date || doc.posting_date,
+ 'item_group': item.item_group,
+ }
+
+ if (doc.tax_category)
+ filters['tax_category'] = doc.tax_category;
+
+ return {
+ query: "erpnext.controllers.queries.get_tax_template",
+ filters: filters
+ }
+ }
+ },
+
payment_terms_template: function() {
var me = this;
const doc = this.frm.doc;
@@ -1711,6 +1767,14 @@
}
},
+ against_blanket_order: function(doc, cdt, cdn) {
+ var item = locals[cdt][cdn];
+ if(!item.against_blanket_order) {
+ frappe.model.set_value(this.frm.doctype + " Item", item.name, "blanket_order", null);
+ frappe.model.set_value(this.frm.doctype + " Item", item.name, "blanket_order_rate", 0.00);
+ }
+ },
+
blanket_order: function(doc, cdt, cdn) {
var me = this;
var item = locals[cdt][cdn];
@@ -1741,14 +1805,28 @@
}
},
+ set_reserve_warehouse: function() {
+ this.autofill_warehouse("reserve_warehouse");
+ },
+
set_warehouse: function() {
+ this.autofill_warehouse("warehouse");
+ },
+
+ autofill_warehouse : function (warehouse_field) {
+ // set warehouse in all child table rows
var me = this;
- if(this.frm.doc.set_warehouse) {
- $.each(this.frm.doc.items || [], function(i, item) {
- frappe.model.set_value(me.frm.doctype + " Item", item.name, "warehouse", me.frm.doc.set_warehouse);
+ let warehouse = (warehouse_field === "warehouse") ? me.frm.doc.set_warehouse : me.frm.doc.set_reserve_warehouse;
+ let child_table = (warehouse_field === "warehouse") ? me.frm.doc.items : me.frm.doc.supplied_items;
+ let doctype = (warehouse_field === "warehouse") ? (me.frm.doctype + " Item") : (me.frm.doctype + " Item Supplied");
+
+ if(warehouse) {
+ $.each(child_table || [], function(i, item) {
+ frappe.model.set_value(doctype, item.name, warehouse_field, warehouse);
});
}
},
+
coupon_code: function() {
var me = this;
frappe.run_serially([
@@ -1760,14 +1838,44 @@
}
});
-erpnext.show_serial_batch_selector = function(frm, d, callback, on_close, show_dialog) {
+erpnext.show_serial_batch_selector = function (frm, d, callback, on_close, show_dialog) {
+ let warehouse, receiving_stock, existing_stock;
+ if (frm.doc.is_return) {
+ if (["Purchase Receipt", "Purchase Invoice"].includes(frm.doc.doctype)) {
+ existing_stock = true;
+ warehouse = d.warehouse;
+ } else if (["Delivery Note", "Sales Invoice"].includes(frm.doc.doctype)) {
+ receiving_stock = true;
+ }
+ } else {
+ if (frm.doc.doctype == "Stock Entry") {
+ if (frm.doc.purpose == "Material Receipt") {
+ receiving_stock = true;
+ } else {
+ existing_stock = true;
+ warehouse = d.s_warehouse;
+ }
+ } else {
+ existing_stock = true;
+ warehouse = d.warehouse;
+ }
+ }
+
+ if (!warehouse) {
+ if (receiving_stock) {
+ warehouse = ["like", ""];
+ } else if (existing_stock) {
+ warehouse = ["!=", ""];
+ }
+ }
+
frappe.require("assets/erpnext/js/utils/serial_no_batch_selector.js", function() {
new erpnext.SerialNoBatchSelector({
frm: frm,
item: d,
warehouse_details: {
type: "Warehouse",
- name: d.warehouse
+ name: warehouse
},
callback: callback,
on_close: on_close
diff --git a/erpnext/public/js/financial_statements.js b/erpnext/public/js/financial_statements.js
index 63e057c..dead309 100644
--- a/erpnext/public/js/financial_statements.js
+++ b/erpnext/public/js/financial_statements.js
@@ -4,7 +4,7 @@
"filters": get_filters(),
"formatter": function(value, row, column, data, default_formatter) {
if (column.fieldname=="account") {
- value = data.account_name;
+ value = data.account_name || value;
column.link_onclick =
"erpnext.financial_statements.open_general_ledger(" + JSON.stringify(data) + ")";
diff --git a/erpnext/public/js/hub/PageContainer.vue b/erpnext/public/js/hub/PageContainer.vue
index f151add..54c3597 100644
--- a/erpnext/public/js/hub/PageContainer.vue
+++ b/erpnext/public/js/hub/PageContainer.vue
@@ -24,7 +24,7 @@
function get_route_map() {
const read_only_routes = {
'marketplace/home': Home,
- 'marketplace/search/:keyword': Search,
+ 'marketplace/search/:category/:keyword': Search,
'marketplace/category/:category': Category,
'marketplace/item/:item': Item,
'marketplace/seller/:seller': Seller,
diff --git a/erpnext/public/js/hub/components/edit_details_dialog.js b/erpnext/public/js/hub/components/edit_details_dialog.js
new file mode 100644
index 0000000..97c5f83
--- /dev/null
+++ b/erpnext/public/js/hub/components/edit_details_dialog.js
@@ -0,0 +1,41 @@
+function edit_details_dialog(params) {
+ let dialog = new frappe.ui.Dialog({
+ title: __('Update Details'),
+ fields: [
+ {
+ label: 'Item Name',
+ fieldname: 'item_name',
+ fieldtype: 'Data',
+ default: params.defaults.item_name,
+ reqd: 1
+ },
+ {
+ label: 'Hub Category',
+ fieldname: 'hub_category',
+ fieldtype: 'Autocomplete',
+ default: params.defaults.hub_category,
+ options: [],
+ reqd: 1
+ },
+ {
+ label: 'Description',
+ fieldname: 'description',
+ fieldtype: 'Text',
+ default: params.defaults.description,
+ options: [],
+ reqd: 1
+ }
+ ],
+ primary_action_label: params.primary_action.label || __('Update Details'),
+ primary_action: params.primary_action.fn
+ });
+
+ hub.call('get_categories').then(categories => {
+ categories = categories.map(d => d.name);
+ dialog.fields_dict.hub_category.set_data(categories);
+ });
+
+ return dialog;
+}
+
+export { edit_details_dialog };
diff --git a/erpnext/public/js/hub/components/item_publish_dialog.js b/erpnext/public/js/hub/components/item_publish_dialog.js
index e49ba53..08de5b3 100644
--- a/erpnext/public/js/hub/components/item_publish_dialog.js
+++ b/erpnext/public/js/hub/components/item_publish_dialog.js
@@ -3,24 +3,24 @@
title: __('Edit Publishing Details'),
fields: [
{
- "label": "Item Code",
- "fieldname": "item_code",
- "fieldtype": "Data",
- "read_only": 1
+ label: __('Item Code'),
+ fieldname: 'item_code',
+ fieldtype: 'Data',
+ read_only: 1
},
{
- "label": "Hub Category",
- "fieldname": "hub_category",
- "fieldtype": "Autocomplete",
- "options": [],
- "reqd": 1
+ label: __('Hub Category'),
+ fieldname: 'hub_category',
+ fieldtype: 'Autocomplete',
+ options: [],
+ reqd: 1
},
{
- "label": "Images",
- "fieldname": "image_list",
- "fieldtype": "MultiSelect",
- "options": [],
- "reqd": 1
+ label: __('Images'),
+ fieldname: 'image_list',
+ fieldtype: 'MultiSelect',
+ options: [],
+ reqd: 1
}
],
primary_action_label: primary_action.label || __('Set Details'),
@@ -28,15 +28,12 @@
secondary_action: secondary_action.fn
});
- hub.call('get_categories')
- .then(categories => {
- categories = categories.map(d => d.name);
- dialog.fields_dict.hub_category.set_data(categories);
- });
+ hub.call('get_categories').then(categories => {
+ categories = categories.map(d => d.name);
+ dialog.fields_dict.hub_category.set_data(categories);
+ });
return dialog;
}
-export {
- ItemPublishDialog
-}
+export { ItemPublishDialog };
diff --git a/erpnext/public/js/hub/pages/Category.vue b/erpnext/public/js/hub/pages/Category.vue
index 3a0e6bf..057fe8b 100644
--- a/erpnext/public/js/hub/pages/Category.vue
+++ b/erpnext/public/js/hub/pages/Category.vue
@@ -3,6 +3,12 @@
class="marketplace-page"
:data-page-name="page_name"
>
+ <search-input
+ :placeholder="search_placeholder"
+ :on_search="set_search_route"
+ v-model="search_value"
+ />
+
<h5>{{ page_title }}</h5>
<item-cards-container
@@ -26,7 +32,13 @@
item_id_fieldname: 'name',
// Constants
- empty_state_message: __(`No items in this category yet.`)
+ empty_state_message: __(`No items in this category yet.`),
+
+ search_value: '',
+
+ // Constants
+ search_placeholder: __('Search for anything ...'),
+
};
},
computed: {
@@ -35,6 +47,7 @@
}
},
created() {
+ this.search_value = '';
this.get_items();
},
methods: {
@@ -51,7 +64,11 @@
go_to_item_details_page(hub_item_name) {
frappe.set_route(`marketplace/item/${hub_item_name}`);
- }
+ },
+
+ set_search_route() {
+ frappe.set_route('marketplace', 'search', this.category, this.search_value);
+ },
}
}
</script>
diff --git a/erpnext/public/js/hub/pages/Home.vue b/erpnext/public/js/hub/pages/Home.vue
index 3536569..8fe8245 100644
--- a/erpnext/public/js/hub/pages/Home.vue
+++ b/erpnext/public/js/hub/pages/Home.vue
@@ -58,6 +58,13 @@
this.search_value = '';
this.get_items();
},
+ mounted() {
+ frappe.route.on('change', () => {
+ if (frappe.get_route_str() === 'marketplace/home') {
+ this.get_items();
+ }
+ })
+ },
methods: {
get_items() {
hub.call('get_data_for_homepage', frappe.defaults ? {
@@ -98,7 +105,7 @@
},
set_search_route() {
- frappe.set_route('marketplace', 'search', this.search_value);
+ frappe.set_route('marketplace', 'search', 'All', this.search_value);
},
}
}
diff --git a/erpnext/public/js/hub/pages/Item.vue b/erpnext/public/js/hub/pages/Item.vue
index 841d004..51ade42 100644
--- a/erpnext/public/js/hub/pages/Item.vue
+++ b/erpnext/public/js/hub/pages/Item.vue
@@ -1,10 +1,5 @@
<template>
- <div
- class="marketplace-page"
- :data-page-name="page_name"
- v-if="init || item"
- >
-
+ <div class="marketplace-page" :data-page-name="page_name" v-if="init || item">
<detail-view
:title="title"
:image="image"
@@ -12,20 +7,15 @@
:menu_items="menu_items"
:show_skeleton="init"
>
- <detail-header-item slot="detail-header-item"
- :value="item_subtitle"
- ></detail-header-item>
- <detail-header-item slot="detail-header-item"
- :value="item_views_and_ratings"
- ></detail-header-item>
+ <detail-header-item slot="detail-header-item" :value="item_subtitle"></detail-header-item>
+ <detail-header-item slot="detail-header-item" :value="item_views_and_ratings"></detail-header-item>
- <button v-if="primary_action" slot="detail-header-item"
+ <button
+ v-if="primary_action"
+ slot="detail-header-item"
class="btn btn-primary btn-sm margin-top"
@click="primary_action.action"
- >
- {{ primary_action.label }}
- </button>
-
+ >{{ primary_action.label }}</button>
</detail-view>
<review-area v-if="!init" :hub_item_name="hub_item_name"></review-area>
@@ -35,6 +25,7 @@
<script>
import ReviewArea from '../components/ReviewArea.vue';
import { get_rating_html } from '../components/reviews';
+import { edit_details_dialog } from '../components/edit_details_dialog';
export default {
name: 'item-page',
@@ -51,21 +42,20 @@
item: null,
title: null,
image: null,
- sections: [],
-
+ sections: []
};
},
computed: {
is_own_item() {
let is_own_item = false;
- if(this.item) {
- if(this.item.hub_seller === hub.settings.hub_seller_name) {
+ if (this.item) {
+ if (this.item.hub_seller === hub.settings.hub_seller_name) {
is_own_item = true;
}
}
return is_own_item;
},
- menu_items(){
+ menu_items() {
return [
{
label: __('Save Item'),
@@ -92,11 +82,11 @@
condition: hub.is_user_registered() && this.is_own_item,
action: this.unpublish_item
}
- ]
+ ];
},
item_subtitle() {
- if(!this.item) {
+ if (!this.item) {
return '';
}
@@ -105,25 +95,31 @@
const rating = this.item.average_rating;
if (rating > 0) {
- subtitle_items.push(rating + `<i class='fa fa-fw fa-star-o'></i>`)
+ subtitle_items.push(rating + `<i class='fa fa-fw fa-star-o'></i>`);
}
- subtitle_items.push({value:this.item.company,on_click:this.go_to_seller_profile_page});
+ subtitle_items.push({
+ value: this.item.company,
+ on_click: this.go_to_seller_profile_page
+ });
return subtitle_items;
},
item_views_and_ratings() {
- if(!this.item) {
+ if (!this.item) {
return '';
}
let stats = __('No views yet');
- if(this.item.view_count) {
+ if (this.item.view_count) {
const views_message = __(`${this.item.view_count} Views`);
const rating_html = get_rating_html(this.item.average_rating);
- const rating_count = this.item.no_of_ratings > 0 ? `${this.item.no_of_ratings} reviews` : __('No reviews yet');
+ const rating_count =
+ this.item.no_of_ratings > 0
+ ? `${this.item.no_of_ratings} reviews`
+ : __('No reviews yet');
stats = [views_message, rating_html, rating_count];
}
@@ -136,7 +132,7 @@
return {
label: __('Contact Seller'),
action: this.contact_seller.bind(this)
- }
+ };
} else {
return undefined;
}
@@ -156,7 +152,7 @@
setTimeout(() => {
hub.call('add_item_view', {
hub_item_name: this.hub_item_name
- })
+ });
// .then(() => {
// erpnext.hub.item_view_cache.push(this.hub_item_name);
// });
@@ -165,14 +161,15 @@
},
methods: {
get_item_details() {
- this.item_received = hub.call('get_item_details', { hub_item_name: this.hub_item_name })
+ this.item_received = hub
+ .call('get_item_details', { hub_item_name: this.hub_item_name })
.then(item => {
- this.init = false;
- this.item = item;
+ this.init = false;
+ this.item = item;
- this.build_data();
- this.make_dialogs();
- });
+ this.build_data();
+ this.make_dialogs();
+ });
},
go_to_seller_profile_page(seller_name) {
frappe.set_route(`marketplace/seller/${seller_name}`);
@@ -200,36 +197,37 @@
make_dialogs() {
this.make_contact_seller_dialog();
this.make_report_item_dialog();
+ this.make_editing_dialog();
},
add_to_saved_items() {
hub.call('add_item_to_user_saved_items', {
- hub_item_name: this.hub_item_name,
- hub_user: frappe.session.user
- })
- .then(() => {
- const saved_items_link = `<b><a href="#marketplace/saved-items">${__('Saved')}</a></b>`
- frappe.show_alert(saved_items_link);
- erpnext.hub.trigger('action:item_save');
- })
- .catch(e => {
- console.error(e);
- });
+ hub_item_name: this.hub_item_name,
+ hub_user: frappe.session.user
+ })
+ .then(() => {
+ const saved_items_link = `<b><a href="#marketplace/saved-items">${__('Saved')}</a></b>`;
+ frappe.show_alert(saved_items_link);
+ erpnext.hub.trigger('action:item_save');
+ })
+ .catch(e => {
+ console.error(e);
+ });
},
add_to_featured_items() {
hub.call('add_item_to_seller_featured_items', {
- hub_item_name: this.hub_item_name,
- hub_user: frappe.session.user
- },)
- .then(() => {
- const featured_items_link = `<b><a href="#marketplace/featured-items">${__('Added to Featured Items')}</a></b>`
- frappe.show_alert(featured_items_link);
- erpnext.hub.trigger('action:item_feature');
- })
- .catch(e => {
- console.error(e);
- });
+ hub_item_name: this.hub_item_name,
+ hub_user: frappe.session.user
+ })
+ .then(() => {
+ const featured_items_link = `<b><a href="#marketplace/featured-items">${__('Added to Featured Items')}</a></b>`;
+ frappe.show_alert(featured_items_link);
+ erpnext.hub.trigger('action:item_feature');
+ })
+ .catch(e => {
+ console.error(e);
+ });
},
make_contact_seller_dialog() {
@@ -252,13 +250,13 @@
if (!message) return;
hub.call('send_message', {
- hub_item: this.item.name,
- message
- })
+ hub_item: this.item.name,
+ message
+ })
.then(() => {
this.contact_seller_dialog.hide();
frappe.set_route('marketplace', 'buying', this.item.name);
- erpnext.hub.trigger('action:send_message')
+ erpnext.hub.trigger('action:send_message');
});
}
});
@@ -275,7 +273,10 @@
}
],
primary_action: ({ message }) => {
- hub.call('add_reported_item', { hub_item_name: this.item.name, message })
+ hub.call('add_reported_item', {
+ hub_item_name: this.item.name,
+ message
+ })
.then(() => {
d.hide();
frappe.show_alert(__('Item Reported'));
@@ -284,26 +285,72 @@
});
},
+ make_editing_dialog() {
+ this.edit_dialog = edit_details_dialog({
+ primary_action: {
+ fn: values => {
+ this.update_details(values);
+ this.edit_dialog.hide();
+ }
+ },
+ defaults: {
+ item_name: this.item.item_name,
+ hub_category: this.item.hub_category,
+ description: this.item.description
+ }
+ });
+ },
+
+ update_details(values) {
+ frappe.call('erpnext.hub_node.api.update_item', {
+ ref_doc: this.item.name,
+ data: values
+ })
+ .then(r => {
+ return this.get_item_details();
+ })
+ .then(() => {
+ frappe.show_alert(__(`${this.item.item_name} Updated`));
+ });
+ },
+
contact_seller() {
this.contact_seller_dialog.show();
},
report_item() {
if (!hub.is_seller_registered()) {
- frappe.throw(__('Please login as a Marketplace User to report this item.'));
+ frappe.throw(
+ __('Please login as a Marketplace User to report this item.')
+ );
}
this.report_item_dialog.show();
},
edit_details() {
- frappe.msgprint(__('This feature is under development...'));
+ if (!hub.is_seller_registered()) {
+ frappe.throw(
+ __('Please login as a Marketplace User to edit this item.')
+ );
+ }
+ this.edit_dialog.show();
},
unpublish_item() {
- frappe.msgprint(__('This feature is under development...'));
+ frappe.confirm(__(`Unpublish {0}?`, [this.item.item_name]), () => {
+ frappe
+ .call('erpnext.hub_node.api.unpublish_item', {
+ item_code: this.item.item_code,
+ hub_item_name: this.hub_item_name
+ })
+ .then(r => {
+ frappe.set_route(`marketplace/home`);
+ frappe.show_alert(__('Item listing removed'));
+ });
+ });
}
}
-}
+};
</script>
<style scoped></style>
diff --git a/erpnext/public/js/hub/pages/Search.vue b/erpnext/public/js/hub/pages/Search.vue
index 5118a81..1032842 100644
--- a/erpnext/public/js/hub/pages/Search.vue
+++ b/erpnext/public/js/hub/pages/Search.vue
@@ -29,8 +29,10 @@
return {
page_name: frappe.get_route()[1],
items: [],
- search_value: frappe.get_route()[2],
+ category: frappe.get_route()[2],
+ search_value: frappe.get_route()[3],
item_id_fieldname: 'name',
+ filters: {},
// Constants
search_placeholder: __('Search for anything ...'),
@@ -40,7 +42,7 @@
computed: {
page_title() {
return this.items.length
- ? __(`Results for "${this.search_value}"`)
+ ? __(`Results for "${this.search_value}" ${this.category !== 'All'? `in category ${this.category}` : ''}`)
: __('No Items found.');
}
},
@@ -49,14 +51,20 @@
},
methods: {
get_items() {
- hub.call('get_items', { keyword: this.search_value })
+ if (this.category !== 'All') {
+ this.filters['hub_category'] = this.category;
+ }
+ hub.call('get_items', {
+ keyword: this.search_value,
+ filters: this.filters
+ })
.then((items) => {
this.items = items;
})
},
set_route_and_get_items() {
- frappe.set_route('marketplace', 'search', this.search_value);
+ frappe.set_route('marketplace', 'search', this.category, this.search_value);
this.get_items();
},
diff --git a/erpnext/public/js/queries.js b/erpnext/public/js/queries.js
index 84d2113..560a561 100644
--- a/erpnext/public/js/queries.js
+++ b/erpnext/public/js/queries.js
@@ -65,7 +65,7 @@
frappe.throw(__("Please set {0}",
[__(frappe.meta.get_label(doc.doctype, frappe.dynamic_link.fieldname, doc.name))]));
}
- console.log(frappe.dynamic_link)
+
return {
query: 'frappe.contacts.doctype.address.address.address_query',
filters: {
diff --git a/erpnext/public/js/templates/address_list.html b/erpnext/public/js/templates/address_list.html
index 2379ef6..0f967b6 100644
--- a/erpnext/public/js/templates/address_list.html
+++ b/erpnext/public/js/templates/address_list.html
@@ -1,23 +1,22 @@
<div class="clearfix"></div>
{% for(var i=0, l=addr_list.length; i<l; i++) { %}
- <div class="address-box">
- <p class="h6">
- {%= i+1 %}. {%= addr_list[i].address_type!="Other" ? __(addr_list[i].address_type) : addr_list[i].address_title %}
- {% if(addr_list[i].is_primary_address) { %}
- <span class="text-muted">({%= __("Primary") %})</span>{% } %}
- {% if(addr_list[i].is_shipping_address) { %}
- <span class="text-muted">({%= __("Shipping") %})</span>{% } %}
+<div class="address-box">
+ <p class="h6">
+ {%= i+1 %}. {%= addr_list[i].address_title %}{% if(addr_list[i].address_type!="Other") { %}
+ <span class="text-muted">({%= __(addr_list[i].address_type) %})</span>{% } %}
+ {% if(addr_list[i].is_primary_address) { %}
+ <span class="text-muted">({%= __("Primary") %})</span>{% } %}
+ {% if(addr_list[i].is_shipping_address) { %}
+ <span class="text-muted">({%= __("Shipping") %})</span>{% } %}
- <a href="#Form/Address/{%= encodeURIComponent(addr_list[i].name) %}"
- class="btn btn-default btn-xs pull-right"
- style="margin-top:-3px; margin-right: -5px;">
- {%= __("Edit") %}</a>
- </p>
- <p>{%= addr_list[i].display %}</p>
- </div>
+ <a href="#Form/Address/{%= encodeURIComponent(addr_list[i].name) %}" class="btn btn-default btn-xs pull-right"
+ style="margin-top:-3px; margin-right: -5px;">
+ {%= __("Edit") %}</a>
+ </p>
+ <p>{%= addr_list[i].display %}</p>
+</div>
{% } %}
{% if(!addr_list.length) { %}
<p class="text-muted small">{%= __("No address added yet.") %}</p>
{% } %}
-<p><button class="btn btn-xs btn-default btn-address">{{ __("New Address") }}</button></p>
-
+<p><button class="btn btn-xs btn-default btn-address">{{ __("New Address") }}</button></p>
\ No newline at end of file
diff --git a/erpnext/public/js/utils.js b/erpnext/public/js/utils.js
index ffc5e6a..3f444f8 100755
--- a/erpnext/public/js/utils.js
+++ b/erpnext/public/js/utils.js
@@ -63,14 +63,33 @@
let callback = '';
let on_close = '';
- if (grid_row.doc.serial_no) {
- grid_row.doc.has_serial_no = true;
- }
-
- me.show_serial_batch_selector(grid_row.frm, grid_row.doc,
- callback, on_close, true);
+ frappe.model.get_value('Item', {'name':grid_row.doc.item_code}, 'has_serial_no',
+ (data) => {
+ if(data) {
+ grid_row.doc.has_serial_no = data.has_serial_no;
+ me.show_serial_batch_selector(grid_row.frm, grid_row.doc,
+ callback, on_close, true);
+ }
+ }
+ );
});
},
+
+ route_to_adjustment_jv: (args) => {
+ frappe.model.with_doctype('Journal Entry', () => {
+ // route to adjustment Journal Entry to handle Account Balance and Stock Value mismatch
+ let journal_entry = frappe.model.get_new_doc('Journal Entry');
+
+ args.accounts.forEach((je_account) => {
+ let child_row = frappe.model.add_child(journal_entry, "accounts");
+ child_row.account = je_account.account;
+ child_row.debit_in_account_currency = je_account.debit_in_account_currency;
+ child_row.credit_in_account_currency = je_account.credit_in_account_currency;
+ child_row.party_type = "" ;
+ });
+ frappe.set_route('Form','Journal Entry', journal_entry.name);
+ });
+ }
});
@@ -439,7 +458,8 @@
fieldname:"item_code",
options: 'Item',
in_list_view: 1,
- read_only: 1,
+ read_only: 0,
+ disabled: 0,
label: __('Item Code')
}, {
fieldtype:'Float',
@@ -482,6 +502,7 @@
frm.doc[opts.child_docname].forEach(d => {
dialog.fields_dict.trans_items.df.data.push({
"docname": d.name,
+ "name": d.name,
"item_code": d.item_code,
"qty": d.qty,
"rate": d.rate,
diff --git a/erpnext/public/js/utils/party.js b/erpnext/public/js/utils/party.js
index a8d3888..99c1b8a 100644
--- a/erpnext/public/js/utils/party.js
+++ b/erpnext/public/js/utils/party.js
@@ -7,6 +7,21 @@
if(!method) {
method = "erpnext.accounts.party.get_party_details";
}
+
+ if (args) {
+ if (in_list(['Sales Invoice', 'Sales Order', 'Delivery Note'], frm.doc.doctype)) {
+ if (frm.doc.company_address && (!args.company_address)) {
+ args.company_address = frm.doc.company_address;
+ }
+ }
+
+ if (in_list(['Purchase Invoice', 'Purchase Order', 'Purchase Receipt'], frm.doc.doctype)) {
+ if (frm.doc.shipping_address && (!args.shipping_address)) {
+ args.shipping_address = frm.doc.shipping_address;
+ }
+ }
+ }
+
if(!args) {
if((frm.doctype != "Purchase Order" && frm.doc.customer)
|| (frm.doc.party_name && in_list(['Quotation', 'Opportunity'], frm.doc.doctype))) {
@@ -30,6 +45,35 @@
};
}
+ if (in_list(['Sales Invoice', 'Sales Order', 'Delivery Note'], frm.doc.doctype)) {
+ if (!args) {
+ args = {
+ party: frm.doc.customer || frm.doc.party_name,
+ party_type: 'Customer'
+ }
+ }
+ if (frm.doc.company_address && (!args.company_address)) {
+ args.company_address = frm.doc.company_address;
+ }
+
+ if (frm.doc.shipping_address_name &&(!args.shipping_address_name)) {
+ args.shipping_address_name = frm.doc.shipping_address_name;
+ }
+ }
+
+ if (in_list(['Purchase Invoice', 'Purchase Order', 'Purchase Receipt'], frm.doc.doctype)) {
+ if (!args) {
+ args = {
+ party: frm.doc.supplier,
+ party_type: 'Supplier'
+ }
+ }
+
+ if (frm.doc.shipping_address && (!args.shipping_address)) {
+ args.shipping_address = frm.doc.shipping_address;
+ }
+ }
+
if (args) {
args.posting_date = frm.doc.posting_date || frm.doc.transaction_date;
}
diff --git a/erpnext/public/js/utils/serial_no_batch_selector.js b/erpnext/public/js/utils/serial_no_batch_selector.js
index 41a59d0..e64d545 100644
--- a/erpnext/public/js/utils/serial_no_batch_selector.js
+++ b/erpnext/public/js/utils/serial_no_batch_selector.js
@@ -139,7 +139,7 @@
this.dialog.set_value('serial_no', d.serial_no);
}
- if (d.batch_no) {
+ if (d.has_batch_no && d.batch_no) {
this.frm.doc.items.forEach(data => {
if(data.item_code == d.item_code) {
this.dialog.fields_dict.batches.df.data.push({
@@ -389,12 +389,14 @@
let serial_no_filters = {
item_code: me.item_code,
+ batch_no: this.doc.batch_no || null,
delivery_document_no: ""
}
if (me.warehouse_details.name) {
serial_no_filters['warehouse'] = me.warehouse_details.name;
}
+
return [
{fieldtype: 'Section Break', label: __('Serial Numbers')},
{
diff --git a/erpnext/public/less/erpnext.less b/erpnext/public/less/erpnext.less
index 8ed5f1a..abe4868 100644
--- a/erpnext/public/less/erpnext.less
+++ b/erpnext/public/less/erpnext.less
@@ -426,7 +426,7 @@
.collapse-btn {
cursor: pointer;
}
-
+
@media (max-width: @screen-xs) {
.page-actions {
max-width: 110px;
diff --git a/erpnext/quality_management/doctype/quality_action_resolution/quality_action_resolution.json b/erpnext/quality_management/doctype/quality_action_resolution/quality_action_resolution.json
index 74370cc..a4e6aed 100644
--- a/erpnext/quality_management/doctype/quality_action_resolution/quality_action_resolution.json
+++ b/erpnext/quality_management/doctype/quality_action_resolution/quality_action_resolution.json
@@ -13,7 +13,7 @@
"fieldname": "problem",
"fieldtype": "Long Text",
"in_list_view": 1,
- "label": "Problem"
+ "label": "Review"
},
{
"fieldname": "sb_00",
diff --git a/erpnext/quality_management/doctype/quality_procedure_process/quality_procedure_process.json b/erpnext/quality_management/doctype/quality_procedure_process/quality_procedure_process.json
index f5c0fbc..0a67fa5 100644
--- a/erpnext/quality_management/doctype/quality_procedure_process/quality_procedure_process.json
+++ b/erpnext/quality_management/doctype/quality_procedure_process/quality_procedure_process.json
@@ -18,7 +18,7 @@
"fieldname": "procedure",
"fieldtype": "Link",
"in_list_view": 1,
- "label": "Procedure",
+ "label": "Child Procedure",
"options": "Quality Procedure"
}
],
diff --git a/erpnext/regional/__init__.py b/erpnext/regional/__init__.py
index 7388ea0..630d5fa 100644
--- a/erpnext/regional/__init__.py
+++ b/erpnext/regional/__init__.py
@@ -10,3 +10,21 @@
region = get_region(doc.company)
if region in ["Nepal", "France"] and doc.docstatus != 0:
frappe.throw(_("Deletion is not permitted for country {0}".format(region)))
+
+def create_transaction_log(doc, method):
+ """
+ Appends the transaction to a chain of hashed logs for legal resons.
+ Called on submit of Sales Invoice and Payment Entry.
+ """
+ region = get_region()
+ if region not in ["France", "Germany"]:
+ return
+
+ data = str(doc.as_dict())
+
+ frappe.get_doc({
+ "doctype": "Transaction Log",
+ "reference_doctype": doc.doctype,
+ "document_name": doc.name,
+ "data": data
+ }).insert(ignore_permissions=True)
diff --git a/erpnext/regional/doctype/gst_hsn_code/gst_hsn_code.js b/erpnext/regional/doctype/gst_hsn_code/gst_hsn_code.js
index e7cc919..7ff4de4 100644
--- a/erpnext/regional/doctype/gst_hsn_code/gst_hsn_code.js
+++ b/erpnext/regional/doctype/gst_hsn_code/gst_hsn_code.js
@@ -3,6 +3,26 @@
frappe.ui.form.on('GST HSN Code', {
refresh: function(frm) {
-
+ if(! frm.doc.__islocal && frm.doc.taxes.length){
+ frm.add_custom_button(__('Update Taxes for Items'), function(){
+ frappe.confirm(
+ 'Are you sure? It will overwrite taxes for all items with HSN Code <b>'+frm.doc.name+'</b>.',
+ function(){
+ frappe.call({
+ args:{
+ taxes: frm.doc.taxes,
+ hsn_code: frm.doc.name
+ },
+ method: 'erpnext.regional.doctype.gst_hsn_code.gst_hsn_code.update_taxes_in_item_master',
+ callback: function(r) {
+ if(r.message){
+ frappe.show_alert(__('Item taxes updated'));
+ }
+ }
+ });
+ }
+ );
+ });
+ }
}
-});
+});
\ No newline at end of file
diff --git a/erpnext/regional/doctype/gst_hsn_code/gst_hsn_code.json b/erpnext/regional/doctype/gst_hsn_code/gst_hsn_code.json
index 2a2145c..06dab37 100644
--- a/erpnext/regional/doctype/gst_hsn_code/gst_hsn_code.json
+++ b/erpnext/regional/doctype/gst_hsn_code/gst_hsn_code.json
@@ -1,104 +1,46 @@
{
- "allow_copy": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "autoname": "field:hsn_code",
- "beta": 0,
- "creation": "2017-06-21 10:48:56.422086",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "",
- "editable_grid": 1,
- "engine": "InnoDB",
+ "autoname": "field:hsn_code",
+ "creation": "2017-06-21 10:48:56.422086",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "hsn_code",
+ "description",
+ "taxes"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "hsn_code",
- "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": "HSN Code",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
+ "fieldname": "hsn_code",
+ "fieldtype": "Data",
+ "in_list_view": 1,
+ "label": "HSN Code",
+ "reqd": 1,
+ "unique": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "description",
- "fieldtype": "Small Text",
- "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,
- "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": "description",
+ "fieldtype": "Small Text",
+ "in_list_view": 1,
+ "label": "Description"
+ },
+ {
+ "fieldname": "taxes",
+ "fieldtype": "Table",
+ "label": "Taxes",
+ "options": "Item Tax"
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2017-09-29 14:38:52.220743",
- "modified_by": "Administrator",
- "module": "Regional",
- "name": "GST HSN Code",
- "name_case": "",
- "owner": "Administrator",
- "permissions": [],
- "quick_entry": 1,
- "read_only": 0,
- "read_only_onload": 0,
- "search_fields": "hsn_code, description",
- "show_name_in_global_search": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "title_field": "hsn_code",
- "track_changes": 1,
- "track_seen": 0
+ ],
+ "modified": "2019-11-01 11:18:59.556931",
+ "modified_by": "Administrator",
+ "module": "Regional",
+ "name": "GST HSN Code",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "search_fields": "hsn_code, description",
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "title_field": "hsn_code",
+ "track_changes": 1
}
\ No newline at end of file
diff --git a/erpnext/regional/doctype/gst_hsn_code/gst_hsn_code.py b/erpnext/regional/doctype/gst_hsn_code/gst_hsn_code.py
index 9637c2e..86cd4d1 100644
--- a/erpnext/regional/doctype/gst_hsn_code/gst_hsn_code.py
+++ b/erpnext/regional/doctype/gst_hsn_code/gst_hsn_code.py
@@ -8,3 +8,26 @@
class GSTHSNCode(Document):
pass
+
+@frappe.whitelist()
+def update_taxes_in_item_master(taxes, hsn_code):
+ items = frappe.get_list("Item", filters={
+ 'gst_hsn_code': hsn_code
+ })
+
+ taxes = frappe.parse_json(taxes)
+ frappe.enqueue(update_item_document, items=items, taxes=taxes)
+ return 1
+
+def update_item_document(items, taxes):
+ for item in items:
+ item_to_be_updated=frappe.get_doc("Item", item.name)
+ item_to_be_updated.taxes = []
+ for tax in taxes:
+ tax = frappe._dict(tax)
+ item_to_be_updated.append("taxes", {
+ 'item_tax_template': tax.item_tax_template,
+ 'tax_category': tax.tax_category,
+ 'valid_from': tax.valid_from
+ })
+ item_to_be_updated.save()
\ No newline at end of file
diff --git a/erpnext/regional/doctype/gstr_3b_report/test_gstr_3b_report.py b/erpnext/regional/doctype/gstr_3b_report/test_gstr_3b_report.py
index fef73d9..fa6fb70 100644
--- a/erpnext/regional/doctype/gstr_3b_report/test_gstr_3b_report.py
+++ b/erpnext/regional/doctype/gstr_3b_report/test_gstr_3b_report.py
@@ -64,7 +64,8 @@
self.assertEqual(output["inter_sup"]["unreg_details"][0]["iamt"], 18),
self.assertEqual(output["sup_details"]["osup_nil_exmp"]["txval"], 100),
self.assertEqual(output["inward_sup"]["isup_details"][0]["inter"], 250)
- self.assertEqual(output["itc_elg"]["itc_avl"][4]["iamt"], 45)
+ self.assertEqual(output["itc_elg"]["itc_avl"][4]["samt"], 22.50)
+ self.assertEqual(output["itc_elg"]["itc_avl"][4]["camt"], 22.50)
def make_sales_invoice():
si = create_sales_invoice(company="_Test Company GST",
@@ -158,10 +159,18 @@
pi.append("taxes", {
"charge_type": "On Net Total",
- "account_head": "IGST - _GST",
+ "account_head": "CGST - _GST",
"cost_center": "Main - _GST",
- "description": "IGST @ 18.0",
- "rate": 18
+ "description": "CGST @ 9.0",
+ "rate": 9
+ })
+
+ pi.append("taxes", {
+ "charge_type": "On Net Total",
+ "account_head": "SGST - _GST",
+ "cost_center": "Main - _GST",
+ "description": "SGST @ 9.0",
+ "rate": 9
})
pi.submit()
diff --git a/erpnext/assets/doctype/asset_settings/__init__.py b/erpnext/regional/doctype/import_supplier_invoice/__init__.py
similarity index 100%
copy from erpnext/assets/doctype/asset_settings/__init__.py
copy to erpnext/regional/doctype/import_supplier_invoice/__init__.py
diff --git a/erpnext/regional/doctype/import_supplier_invoice/import_supplier_invoice.js b/erpnext/regional/doctype/import_supplier_invoice/import_supplier_invoice.js
new file mode 100644
index 0000000..c2d6edf
--- /dev/null
+++ b/erpnext/regional/doctype/import_supplier_invoice/import_supplier_invoice.js
@@ -0,0 +1,46 @@
+// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
+// License: GNU General Public License v3. See license.txt
+
+frappe.ui.form.on('Import Supplier Invoice', {
+ onload: function(frm) {
+ frappe.realtime.on("import_invoice_update", function (data) {
+ frm.dashboard.show_progress(data.title, (data.count / data.total) * 100, data.message);
+ if (data.count == data.total) {
+ window.setTimeout(title => frm.dashboard.hide_progress(title), 1500, data.title);
+ }
+ });
+ },
+ setup: function(frm) {
+ frm.set_query("tax_account", function(doc) {
+ return {
+ filters: {
+ account_type: 'Tax',
+ company: doc.company
+ }
+ };
+ });
+
+ frm.set_query("default_buying_price_list", function(doc) {
+ return {
+ filters: {
+ currency: frappe.get_doc(":Company", doc.company).default_currency
+ }
+ };
+ });
+ },
+
+ refresh: function(frm) {
+ frm.trigger("toggle_read_only_fields");
+ },
+
+ toggle_read_only_fields: function(frm) {
+ if (in_list(["File Import Completed", "Processing File Data"], frm.doc.status)) {
+ cur_frm.set_read_only();
+ cur_frm.refresh_fields();
+ frm.set_df_property("import_invoices", "hidden", 1);
+ } else {
+ frm.set_df_property("import_invoices", "hidden", 0);
+ }
+ }
+
+});
\ No newline at end of file
diff --git a/erpnext/regional/doctype/import_supplier_invoice/import_supplier_invoice.json b/erpnext/regional/doctype/import_supplier_invoice/import_supplier_invoice.json
new file mode 100644
index 0000000..59e955c
--- /dev/null
+++ b/erpnext/regional/doctype/import_supplier_invoice/import_supplier_invoice.json
@@ -0,0 +1,105 @@
+{
+ "actions": [],
+ "creation": "2019-10-15 12:33:21.845329",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "invoice_series",
+ "company",
+ "item_code",
+ "column_break_5",
+ "supplier_group",
+ "tax_account",
+ "default_buying_price_list",
+ "upload_xml_invoices_section",
+ "zip_file",
+ "import_invoices",
+ "status"
+ ],
+ "fields": [
+ {
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Company",
+ "options": "Company",
+ "reqd": 1
+ },
+ {
+ "fieldname": "item_code",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Item Code",
+ "options": "Item",
+ "reqd": 1
+ },
+ {
+ "fieldname": "supplier_group",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Supplier Group",
+ "options": "Supplier Group",
+ "reqd": 1
+ },
+ {
+ "fieldname": "tax_account",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Tax Account",
+ "options": "Account",
+ "reqd": 1
+ },
+ {
+ "fieldname": "column_break_5",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "zip_file",
+ "fieldtype": "Attach",
+ "label": "Zip File"
+ },
+ {
+ "description": "Click on Import Invoices button once the zip file has been attached to the document. Any errors related to processing will be shown in the Error Log.",
+ "fieldname": "import_invoices",
+ "fieldtype": "Button",
+ "label": "Import Invoices",
+ "options": "process_file_data"
+ },
+ {
+ "fieldname": "status",
+ "fieldtype": "Data",
+ "label": "Status",
+ "read_only": 1
+ },
+ {
+ "fieldname": "invoice_series",
+ "fieldtype": "Select",
+ "label": "Invoice Series",
+ "options": "ACC-PINV-.YYYY.-",
+ "reqd": 1
+ },
+ {
+ "fieldname": "default_buying_price_list",
+ "fieldtype": "Link",
+ "label": "Default Buying Price List",
+ "options": "Price List",
+ "reqd": 1
+ },
+ {
+ "fieldname": "upload_xml_invoices_section",
+ "fieldtype": "Section Break",
+ "label": "Upload XML Invoices"
+ }
+ ],
+ "links": [],
+ "modified": "2019-12-10 16:37:26.793398",
+ "modified_by": "Administrator",
+ "module": "Regional",
+ "name": "Import Supplier Invoice",
+ "owner": "Administrator",
+ "permissions": [],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/regional/doctype/import_supplier_invoice/import_supplier_invoice.py b/erpnext/regional/doctype/import_supplier_invoice/import_supplier_invoice.py
new file mode 100644
index 0000000..72fe17f
--- /dev/null
+++ b/erpnext/regional/doctype/import_supplier_invoice/import_supplier_invoice.py
@@ -0,0 +1,402 @@
+# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+
+from decimal import Decimal
+import json
+import re
+import traceback
+import zipfile
+import frappe, erpnext
+from frappe import _
+from frappe.model.document import Document
+from frappe.custom.doctype.custom_field.custom_field import create_custom_field
+from frappe.utils.data import format_datetime
+from bs4 import BeautifulSoup as bs
+from frappe.utils import cint, flt, today, nowdate, add_days, get_files_path, get_datetime_str
+import dateutil
+from frappe.utils.file_manager import save_file
+
+class ImportSupplierInvoice(Document):
+ def validate(self):
+ if not frappe.db.get_value("Stock Settings", fieldname="stock_uom"):
+ frappe.throw(_("Please set default UOM in Stock Settings"))
+
+ def autoname(self):
+ if not self.name:
+ self.name = "Import Invoice on " + format_datetime(self.creation)
+
+ def import_xml_data(self):
+ import_file = frappe.get_doc("File", {"file_url": self.zip_file})
+ self.publish("File Import", _("Processing XML Files"), 1, 3)
+
+ self.file_count = 0
+ self.purchase_invoices_count = 0
+ self.default_uom = frappe.db.get_value("Stock Settings", fieldname="stock_uom")
+
+ with zipfile.ZipFile(get_full_path(self.zip_file)) as zf:
+ for file_name in zf.namelist():
+ content = get_file_content(file_name, zf)
+ file_content = bs(content, "xml")
+ self.prepare_data_for_import(file_content, file_name, content)
+
+ if self.purchase_invoices_count == self.file_count:
+ self.status = "File Import Completed"
+ self.publish("File Import", _("XML Files Processed"), 2, 3)
+ else:
+ self.status = "Partially Completed - Check Error Log"
+ self.publish("File Import", _("XML Files Processed"), 2, 3)
+
+ self.save()
+ self.publish("File Import", _("XML Files Processed"), 3, 3)
+
+ def prepare_data_for_import(self, file_content, file_name, encoded_content):
+ for line in file_content.find_all("DatiGeneraliDocumento"):
+ invoices_args = {
+ "company": self.company,
+ "naming_series": self.invoice_series,
+ "document_type": line.TipoDocumento.text,
+ "bill_date": get_datetime_str(line.Data.text),
+ "invoice_no": line.Numero.text,
+ "total_discount": 0,
+ "items": [],
+ "buying_price_list": self.default_buying_price_list
+ }
+
+ if not invoices_args.get("invoice_no", ''): return
+
+ supp_dict = get_supplier_details(file_content)
+ invoices_args["destination_code"] = get_destination_code_from_file(file_content)
+ self.prepare_items_for_invoice(file_content, invoices_args)
+ invoices_args["taxes"] = get_taxes_from_file(file_content, self.tax_account)
+ invoices_args["terms"] = get_payment_terms_from_file(file_content)
+
+ supplier_name = create_supplier(self.supplier_group, supp_dict)
+ address = create_address(supplier_name, supp_dict)
+ pi_name = create_purchase_invoice(supplier_name, file_name, invoices_args, self.name)
+
+ self.file_count += 1
+ if pi_name:
+ self.purchase_invoices_count += 1
+ file_save = save_file(file_name, encoded_content, "Purchase Invoice",
+ pi_name, folder=None, decode=False, is_private=0, df=None)
+
+ def prepare_items_for_invoice(self, file_content, invoices_args):
+ qty = 1
+ rate, tax_rate = [0 ,0]
+ uom = self.default_uom
+
+ #read file for item information
+ for line in file_content.find_all("DettaglioLinee"):
+ if line.find("PrezzoUnitario") and line.find("PrezzoTotale"):
+ rate = flt(line.PrezzoUnitario.text) or 0
+ line_total = flt(line.PrezzoTotale.text) or 0
+
+ if rate and flt(line_total) / rate != 1.0 and line.find("Quantita"):
+ qty = flt(line.Quantita.text) or 0
+ if line.find("UnitaMisura"):
+ uom = create_uom(line.UnitaMisura.text)
+
+ if (rate < 0 and line_total < 0):
+ qty *= -1
+ invoices_args["return_invoice"] = 1
+
+ if line.find("AliquotaIVA"):
+ tax_rate = flt(line.AliquotaIVA.text)
+
+ line_str = re.sub('[^A-Za-z0-9]+', '-', line.Descrizione.text)
+ item_name = line_str[0:140]
+
+ invoices_args['items'].append({
+ "item_code": self.item_code,
+ "item_name": item_name,
+ "description": line_str,
+ "qty": qty,
+ "uom": uom,
+ "rate": abs(rate),
+ "conversion_factor": 1.0,
+ "tax_rate": tax_rate
+ })
+
+ for disc_line in line.find_all("ScontoMaggiorazione"):
+ if disc_line.find("Percentuale"):
+ invoices_args["total_discount"] += flt((flt(disc_line.Percentuale.text) / 100) * (rate * qty))
+
+ def process_file_data(self):
+ self.status = "Processing File Data"
+ self.save()
+ frappe.enqueue_doc(self.doctype, self.name, "import_xml_data", queue="long", timeout=3600)
+
+ def publish(self, title, message, count, total):
+ frappe.publish_realtime("import_invoice_update", {"title": title, "message": message, "count": count, "total": total})
+
+def get_file_content(file_name, zip_file_object):
+ content = ''
+ encoded_content = zip_file_object.read(file_name)
+
+ try:
+ content = encoded_content.decode("utf-8-sig")
+ except UnicodeDecodeError:
+ try:
+ content = encoded_content.decode("utf-16")
+ except UnicodeDecodeError as e:
+ frappe.log_error(message=e, title="UTF-16 encoding error for File Name: " + file_name)
+
+ return content
+
+def get_supplier_details(file_content):
+ supplier_info = {}
+ for line in file_content.find_all("CedentePrestatore"):
+ supplier_info['tax_id'] = line.DatiAnagrafici.IdPaese.text + line.DatiAnagrafici.IdCodice.text
+ if line.find("CodiceFiscale"):
+ supplier_info['fiscal_code'] = line.DatiAnagrafici.CodiceFiscale.text
+
+ if line.find("RegimeFiscale"):
+ supplier_info['fiscal_regime'] = line.DatiAnagrafici.RegimeFiscale.text
+
+ if line.find("Denominazione"):
+ supplier_info['supplier'] = line.DatiAnagrafici.Anagrafica.Denominazione.text
+
+ if line.find("Nome"):
+ supplier_info['supplier'] = (line.DatiAnagrafici.Anagrafica.Nome.text
+ + " " + line.DatiAnagrafici.Anagrafica.Cognome.text)
+
+ supplier_info['address_line1'] = line.Sede.Indirizzo.text
+ supplier_info['city'] = line.Sede.Comune.text
+ if line.find("Provincia"):
+ supplier_info['province'] = line.Sede.Provincia.text
+
+ supplier_info['pin_code'] = line.Sede.CAP.text
+ supplier_info['country'] = get_country(line.Sede.Nazione.text)
+
+ return supplier_info
+
+def get_taxes_from_file(file_content, tax_account):
+ taxes = []
+ #read file for taxes information
+ for line in file_content.find_all("DatiRiepilogo"):
+ if line.find("AliquotaIVA"):
+ if line.find("EsigibilitaIVA"):
+ descr = line.EsigibilitaIVA.text
+ else:
+ descr = "None"
+ taxes.append({
+ "charge_type": "Actual",
+ "account_head": tax_account,
+ "tax_rate": flt(line.AliquotaIVA.text) or 0,
+ "description": descr,
+ "tax_amount": flt(line.Imposta.text) if len(line.find("Imposta"))!=0 else 0
+ })
+
+ return taxes
+
+def get_payment_terms_from_file(file_content):
+ terms = []
+ #Get mode of payment dict from setup
+ mop_options = frappe.get_meta('Mode of Payment').fields[4].options
+ mop_str = re.sub('\n', ',', mop_options)
+ mop_dict = dict(item.split("-") for item in mop_str.split(","))
+ #read file for payment information
+ for line in file_content.find_all("DettaglioPagamento"):
+ mop_code = line.ModalitaPagamento.text + '-' + mop_dict.get(line.ModalitaPagamento.text)
+ if line.find("DataScadenzaPagamento"):
+ due_date = dateutil.parser.parse(line.DataScadenzaPagamento.text).strftime("%Y-%m-%d")
+ else:
+ due_date = today()
+ terms.append({
+ "mode_of_payment_code": mop_code,
+ "bank_account_iban": line.IBAN.text if line.find("IBAN") else "",
+ "due_date": due_date,
+ "payment_amount": line.ImportoPagamento.text
+ })
+
+ return terms
+
+def get_destination_code_from_file(file_content):
+ destination_code = ''
+ for line in file_content.find_all("DatiTrasmissione"):
+ destination_code = line.CodiceDestinatario.text
+
+ return destination_code
+
+def create_supplier(supplier_group, args):
+ args = frappe._dict(args)
+
+ existing_supplier_name = frappe.db.get_value("Supplier",
+ filters={"tax_id": args.tax_id}, fieldname="name")
+ if existing_supplier_name:
+ pass
+ else:
+ existing_supplier_name = frappe.db.get_value("Supplier",
+ filters={"name": args.supplier}, fieldname="name")
+
+ if existing_supplier_name:
+ filters = [
+ ["Dynamic Link", "link_doctype", "=", "Supplier"],
+ ["Dynamic Link", "link_name", "=", args.existing_supplier_name],
+ ["Dynamic Link", "parenttype", "=", "Contact"]
+ ]
+
+ if not frappe.get_list("Contact", filters):
+ new_contact = frappe.new_doc("Contact")
+ new_contact.first_name = args.supplier
+ new_contact.append('links', {
+ "link_doctype": "Supplier",
+ "link_name": existing_supplier_name
+ })
+ new_contact.insert(ignore_mandatory=True)
+
+ return existing_supplier_name
+ else:
+
+ new_supplier = frappe.new_doc("Supplier")
+ new_supplier.supplier_name = args.supplier
+ new_supplier.supplier_group = supplier_group
+ new_supplier.tax_id = args.tax_id
+ new_supplier.fiscal_code = args.fiscal_code
+ new_supplier.fiscal_regime = args.fiscal_regime
+ new_supplier.save()
+
+ new_contact = frappe.new_doc("Contact")
+ new_contact.first_name = args.supplier
+ new_contact.append('links', {
+ "link_doctype": "Supplier",
+ "link_name": new_supplier.name
+ })
+
+ new_contact.insert(ignore_mandatory=True)
+
+ return new_supplier.name
+
+def create_address(supplier_name, args):
+ args = frappe._dict(args)
+
+ filters = [
+ ["Dynamic Link", "link_doctype", "=", "Supplier"],
+ ["Dynamic Link", "link_name", "=", supplier_name],
+ ["Dynamic Link", "parenttype", "=", "Address"]
+ ]
+
+ existing_address = frappe.get_list("Address", filters)
+
+ if args.address_line1:
+ new_address_doc = frappe.new_doc("Address")
+ new_address_doc.address_line1 = args.address_line1
+
+ if args.city:
+ new_address_doc.city = args.city
+ else:
+ new_address_doc.city = "Not Provided"
+
+ for field in ["province", "pincode", "country"]:
+ if args.get(field):
+ new_address_doc.set(field, args.get(field))
+
+ for address in existing_address:
+ address_doc = frappe.get_doc("Address", address["name"])
+ if (address_doc.address_line1 == new_address_doc.address_line1 and
+ address_doc.pincode == new_address_doc.pincode):
+ return address
+
+ new_address_doc.append("links", {
+ "link_doctype": "Supplier",
+ "link_name": supplier_name
+ })
+ new_address_doc.address_type = "Billing"
+ new_address_doc.insert(ignore_mandatory=True)
+ return new_address_doc.name
+ else:
+ return None
+
+def create_purchase_invoice(supplier_name, file_name, args, name):
+ args = frappe._dict(args)
+ pi = frappe.get_doc({
+ "doctype": "Purchase Invoice",
+ "company": args.company,
+ "currency": erpnext.get_company_currency(args.company),
+ "naming_series": args.naming_series,
+ "supplier": supplier_name,
+ "is_return": args.is_return,
+ "posting_date": today(),
+ "bill_no": args.bill_no,
+ "buying_price_list": args.buying_price_list,
+ "bill_date": args.bill_date,
+ "destination_code": args.destination_code,
+ "document_type": args.document_type,
+ "disable_rounded_total": 1,
+ "items": args["items"],
+ "taxes": args["taxes"]
+ })
+
+ try:
+ pi.set_missing_values()
+ pi.insert(ignore_mandatory=True)
+
+ #if discount exists in file, apply any discount on grand total
+ if args.total_discount > 0:
+ pi.apply_discount_on = "Grand Total"
+ pi.discount_amount = args.total_discount
+ pi.save()
+ #adjust payment amount to match with grand total calculated
+ calc_total = 0
+ adj = 0
+ for term in args.terms:
+ calc_total += flt(term["payment_amount"])
+ if flt(calc_total - flt(pi.grand_total)) != 0:
+ adj = calc_total - flt(pi.grand_total)
+ pi.payment_schedule = []
+ for term in args.terms:
+ pi.append('payment_schedule',{"mode_of_payment_code": term["mode_of_payment_code"],
+ "bank_account_iban": term["bank_account_iban"],
+ "due_date": term["due_date"],
+ "payment_amount": flt(term["payment_amount"]) - adj })
+ adj = 0
+ pi.imported_grand_total = calc_total
+ pi.save()
+ return pi.name
+ except Exception as e:
+ frappe.db.set_value("Import Supplier Invoice", name, "status", "Error")
+ frappe.log_error(message=e,
+ title="Create Purchase Invoice: " + args.get("bill_no") + "File Name: " + file_name)
+ return None
+
+def get_country(code):
+ existing_country_name = frappe.db.get_value("Country",
+ filters={"code": code}, fieldname="name")
+ if existing_country_name:
+ return existing_country_name
+ else:
+ frappe.throw(_("Country Code in File does not match with country code set up in the system"))
+
+def create_uom(uom):
+ existing_uom = frappe.db.get_value("UOM",
+ filters={"uom_name": uom}, fieldname="uom_name")
+ if existing_uom:
+ return existing_uom
+ else:
+ new_uom = frappe.new_doc("UOM")
+ new_uom.uom_name = uom
+ new_uom.save()
+ return new_uom.uom_name
+
+def get_full_path(file_name):
+ """Returns file path from given file name"""
+ file_path = file_name
+
+ if "/" not in file_path:
+ file_path = "/files/" + file_path
+
+ if file_path.startswith("/private/files/"):
+ file_path = get_files_path(*file_path.split("/private/files/", 1)[1].split("/"), is_private=1)
+
+ elif file_path.startswith("/files/"):
+ file_path = get_files_path(*file_path.split("/files/", 1)[1].split("/"))
+
+ elif file_path.startswith("http"):
+ pass
+
+ elif not self.file_url:
+ frappe.throw(_("There is some problem with the file url: {0}").format(file_path))
+
+ return file_path
\ No newline at end of file
diff --git a/erpnext/regional/doctype/import_supplier_invoice/test_import_supplier_invoice.py b/erpnext/regional/doctype/import_supplier_invoice/test_import_supplier_invoice.py
new file mode 100644
index 0000000..d1caf77
--- /dev/null
+++ b/erpnext/regional/doctype/import_supplier_invoice/test_import_supplier_invoice.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+# import frappe
+import unittest
+
+class TestImportSupplierInvoice(unittest.TestCase):
+ pass
diff --git a/erpnext/regional/france/utils.py b/erpnext/regional/france/utils.py
index e4b72f6..424615d 100644
--- a/erpnext/regional/france/utils.py
+++ b/erpnext/regional/france/utils.py
@@ -3,22 +3,6 @@
from __future__ import unicode_literals
import frappe
-from frappe import _
-from erpnext import get_region
-
-def create_transaction_log(doc, method):
- region = get_region()
- if region not in ["France"]:
- return
- else:
- data = str(doc.as_dict())
-
- frappe.get_doc({
- "doctype": "Transaction Log",
- "reference_doctype": doc.doctype,
- "document_name": doc.name,
- "data": data
- }).insert(ignore_permissions=True)
# don't remove this function it is used in tests
def test_method():
diff --git a/erpnext/regional/germany/address_template.html b/erpnext/regional/germany/address_template.html
index 0df7867..7fa4c32 100644
--- a/erpnext/regional/germany/address_template.html
+++ b/erpnext/regional/germany/address_template.html
@@ -1,8 +1,8 @@
{{ address_line1 }}<br>
{% if address_line2 %}{{ address_line2 }}<br>{% endif -%}
-{{ pincode }} {{ city }}<br>
-{% if country %}{{ country }}<br>{% endif -%}
-<br>
-{% if phone %}Tel: {{ phone }}<br>{% endif -%}
-{% if fax %}Fax: {{ fax }}<br>{% endif -%}
-{% if email_id %}E-Mail: {{ email_id }}<br>{% endif -%}
+{% if country in ["Germany", "Deutschland"] %}
+ {{ pincode }} {{ city }}
+{% else %}
+ {{ pincode }} {{ city | upper }}<br>
+ {{ country | upper }}
+{% endif %}
diff --git a/erpnext/regional/india/__init__.py b/erpnext/regional/india/__init__.py
index 46c874b..0ed98b7 100644
--- a/erpnext/regional/india/__init__.py
+++ b/erpnext/regional/india/__init__.py
@@ -1,4 +1,5 @@
from __future__ import unicode_literals
+from six import iteritems
states = [
'',
@@ -79,4 +80,6 @@
"Uttar Pradesh": "09",
"Uttarakhand": "05",
"West Bengal": "19",
-}
\ No newline at end of file
+}
+
+number_state_mapping = {v: k for k, v in iteritems(state_numbers)}
\ No newline at end of file
diff --git a/erpnext/regional/india/setup.py b/erpnext/regional/india/setup.py
index 756c17d..14fdba0 100644
--- a/erpnext/regional/india/setup.py
+++ b/erpnext/regional/india/setup.py
@@ -107,7 +107,12 @@
dict(fieldname='gst_category', label='GST Category',
fieldtype='Select', insert_after='gst_section', print_hide=1,
options='\nRegistered Regular\nRegistered Composition\nUnregistered\nSEZ\nOverseas\nUIN Holders',
- fetch_from='supplier.gst_category', fetch_if_empty=1)
+ fetch_from='supplier.gst_category', fetch_if_empty=1),
+ dict(fieldname='export_type', label='Export Type',
+ fieldtype='Select', insert_after='gst_category', print_hide=1,
+ depends_on='eval:in_list(["SEZ", "Overseas"], doc.gst_category)',
+ options='\nWith Payment of Tax\nWithout Payment of Tax', fetch_from='supplier.export_type',
+ fetch_if_empty=1),
]
sales_invoice_gst_category = [
@@ -116,20 +121,21 @@
dict(fieldname='gst_category', label='GST Category',
fieldtype='Select', insert_after='gst_section', print_hide=1,
options='\nRegistered Regular\nRegistered Composition\nUnregistered\nSEZ\nOverseas\nConsumer\nDeemed Export\nUIN Holders',
- fetch_from='customer.gst_category', fetch_if_empty=1)
+ fetch_from='customer.gst_category', fetch_if_empty=1),
+ dict(fieldname='export_type', label='Export Type',
+ fieldtype='Select', insert_after='gst_category', print_hide=1,
+ depends_on='eval:in_list(["SEZ", "Overseas", "Deemed Export"], doc.gst_category)',
+ options='\nWith Payment of Tax\nWithout Payment of Tax', fetch_from='customer.export_type',
+ fetch_if_empty=1),
]
invoice_gst_fields = [
dict(fieldname='invoice_copy', label='Invoice Copy',
- fieldtype='Select', insert_after='gst_category', print_hide=1, allow_on_submit=1,
+ fieldtype='Select', insert_after='export_type', print_hide=1, allow_on_submit=1,
options='Original for Recipient\nDuplicate for Transporter\nDuplicate for Supplier\nTriplicate for Supplier'),
dict(fieldname='reverse_charge', label='Reverse Charge',
fieldtype='Select', insert_after='invoice_copy', print_hide=1,
options='Y\nN', default='N'),
- dict(fieldname='export_type', label='Export Type',
- fieldtype='Select', insert_after='reverse_charge', print_hide=1,
- depends_on='eval:in_list(["SEZ", "Overseas", "Deemed Export"], doc.gst_category)',
- options='\nWith Payment of Tax\nWithout Payment of Tax'),
dict(fieldname='ecommerce_gstin', label='E-commerce GSTIN',
fieldtype='Data', insert_after='export_type', print_hide=1),
dict(fieldname='gst_col_break', fieldtype='Column Break', insert_after='ecommerce_gstin'),
@@ -142,13 +148,13 @@
purchase_invoice_gst_fields = [
dict(fieldname='supplier_gstin', label='Supplier GSTIN',
fieldtype='Data', insert_after='supplier_address',
- fetch_from='supplier_address.gstin', print_hide=1),
+ fetch_from='supplier_address.gstin', print_hide=1, read_only=1),
dict(fieldname='company_gstin', label='Company GSTIN',
fieldtype='Data', insert_after='shipping_address_display',
- fetch_from='shipping_address.gstin', print_hide=1),
+ fetch_from='shipping_address.gstin', print_hide=1, read_only=1),
dict(fieldname='place_of_supply', label='Place of Supply',
fieldtype='Data', insert_after='shipping_address',
- print_hide=1, read_only=0),
+ print_hide=1, read_only=1),
]
purchase_invoice_itc_fields = [
@@ -167,17 +173,17 @@
sales_invoice_gst_fields = [
dict(fieldname='billing_address_gstin', label='Billing Address GSTIN',
- fieldtype='Data', insert_after='customer_address',
+ fieldtype='Data', insert_after='customer_address', read_only=1,
fetch_from='customer_address.gstin', print_hide=1),
dict(fieldname='customer_gstin', label='Customer GSTIN',
fieldtype='Data', insert_after='shipping_address_name',
fetch_from='shipping_address_name.gstin', print_hide=1),
dict(fieldname='place_of_supply', label='Place of Supply',
fieldtype='Data', insert_after='customer_gstin',
- print_hide=1, read_only=0),
+ print_hide=1, read_only=1),
dict(fieldname='company_gstin', label='Company GSTIN',
fieldtype='Data', insert_after='company_address',
- fetch_from='company_address.gstin', print_hide=1),
+ fetch_from='company_address.gstin', print_hide=1, read_only=1),
]
sales_invoice_shipping_fields = [
@@ -194,7 +200,11 @@
inter_state_gst_field = [
dict(fieldname='is_inter_state', label='Is Inter State',
- fieldtype='Check', insert_after='disabled', print_hide=1)
+ fieldtype='Check', insert_after='disabled', print_hide=1),
+ dict(fieldname='tax_category_column_break', fieldtype='Column Break',
+ insert_after='is_inter_state'),
+ dict(fieldname='gst_state', label='Source State', fieldtype='Select',
+ options='\n'.join(states), insert_after='company')
]
ewaybill_fields = [
@@ -374,8 +384,7 @@
'Sales Invoice': sales_invoice_gst_category + invoice_gst_fields + sales_invoice_shipping_fields + sales_invoice_gst_fields + si_ewaybill_fields,
'Delivery Note': sales_invoice_gst_fields + ewaybill_fields + sales_invoice_shipping_fields,
'Sales Order': sales_invoice_gst_fields,
- 'Sales Taxes and Charges Template': inter_state_gst_field,
- 'Purchase Taxes and Charges Template': inter_state_gst_field,
+ 'Tax Category': inter_state_gst_field,
'Item': [
dict(fieldname='gst_hsn_code', label='HSN/SAC',
fieldtype='Link', options='GST HSN Code', insert_after='item_group'),
@@ -459,6 +468,15 @@
'insert_after': 'gst_transporter_id',
'options': 'Registered Regular\nRegistered Composition\nUnregistered\nSEZ\nOverseas\nUIN Holders',
'default': 'Unregistered'
+ },
+ {
+ 'fieldname': 'export_type',
+ 'label': 'Export Type',
+ 'fieldtype': 'Select',
+ 'insert_after': 'gst_category',
+ 'default': 'Without Payment of Tax',
+ 'depends_on':'eval:in_list(["SEZ", "Overseas"], doc.gst_category)',
+ 'options': '\nWith Payment of Tax\nWithout Payment of Tax'
}
],
'Customer': [
@@ -469,6 +487,15 @@
'insert_after': 'customer_type',
'options': 'Registered Regular\nRegistered Composition\nUnregistered\nSEZ\nOverseas\nConsumer\nDeemed Export\nUIN Holders',
'default': 'Unregistered'
+ },
+ {
+ 'fieldname': 'export_type',
+ 'label': 'Export Type',
+ 'fieldtype': 'Select',
+ 'insert_after': 'gst_category',
+ 'default': 'Without Payment of Tax',
+ 'depends_on':'eval:in_list(["SEZ", "Overseas", "Deemed Export"], doc.gst_category)',
+ 'options': '\nWith Payment of Tax\nWithout Payment of Tax'
}
]
}
diff --git a/erpnext/regional/india/taxes.js b/erpnext/regional/india/taxes.js
new file mode 100644
index 0000000..1e59032
--- /dev/null
+++ b/erpnext/regional/india/taxes.js
@@ -0,0 +1,41 @@
+erpnext.setup_auto_gst_taxation = (doctype) => {
+ frappe.ui.form.on(doctype, {
+ company_address: function(frm) {
+ frm.trigger('get_tax_template');
+ },
+ shipping_address: function(frm) {
+ frm.trigger('get_tax_template');
+ },
+ tax_category: function(frm) {
+ frm.trigger('get_tax_template');
+ },
+ get_tax_template: function(frm) {
+ let party_details = {
+ 'shipping_address': frm.doc.shipping_address || '',
+ 'shipping_address_name': frm.doc.shipping_address_name || '',
+ 'customer_address': frm.doc.customer_address || '',
+ 'customer': frm.doc.customer,
+ 'supplier': frm.doc.supplier,
+ 'supplier_gstin': frm.doc.supplier_gstin,
+ 'company_gstin': frm.doc.company_gstin,
+ 'tax_category': frm.doc.tax_category
+ };
+
+ frappe.call({
+ method: 'erpnext.regional.india.utils.get_regional_address_details',
+ args: {
+ party_details: JSON.stringify(party_details),
+ doctype: frm.doc.doctype,
+ company: frm.doc.company,
+ return_taxes: 1
+ },
+ callback: function(r) {
+ if(r.message) {
+ frm.set_value('taxes_and_charges', r.message.taxes_and_charges);
+ }
+ }
+ });
+ }
+ });
+};
+
diff --git a/erpnext/regional/india/utils.py b/erpnext/regional/india/utils.py
index 0bc277f..0f9156a 100644
--- a/erpnext/regional/india/utils.py
+++ b/erpnext/regional/india/utils.py
@@ -7,6 +7,8 @@
from erpnext.controllers.accounts_controller import get_taxes_and_charges
from erpnext.hr.utils import get_salary_assignment
from erpnext.hr.doctype.salary_structure.salary_structure import make_salary_slip
+from erpnext.regional.india import number_state_mapping
+from six import string_types
def validate_gstin_for_india(doc, method):
if hasattr(doc, 'gst_state') and doc.gst_state:
@@ -46,6 +48,14 @@
frappe.throw(_("Invalid GSTIN! First 2 digits of GSTIN should match with State number {0}.")
.format(doc.gst_state_number))
+def update_gst_category(doc, method):
+ for link in doc.links:
+ if link.link_doctype in ['Customer', 'Supplier']:
+ if doc.get('gstin'):
+ frappe.db.sql("""
+ UPDATE `tab{0}` SET gst_category = %s WHERE name = %s AND gst_category = 'Unregistered'
+ """.format(link.link_doctype), ("Registered Regular", link.link_name)) #nosec
+
def set_gst_state_and_state_number(doc):
if not doc.gst_state:
if not doc.state:
@@ -72,8 +82,8 @@
total += digit
factor = 2 if factor == 1 else 1
if gstin[-1] != code_point_chars[((mod - (total % mod)) % mod)]:
- frappe.throw(_("Invalid {0}! The check digit validation has failed. " +
- "Please ensure you've typed the {0} correctly.".format(label)))
+ frappe.throw(_("""Invalid {0}! The check digit validation has failed.
+ Please ensure you've typed the {0} correctly.""".format(label)))
def get_itemised_tax_breakup_header(item_doctype, tax_accounts):
if frappe.get_meta(item_doctype).has_field('gst_hsn_code'):
@@ -122,44 +132,108 @@
'''test function'''
return 'overridden'
-def get_place_of_supply(out, doctype):
+def get_place_of_supply(party_details, doctype):
if not frappe.get_meta('Address').has_field('gst_state'): return
- if doctype in ("Sales Invoice", "Delivery Note"):
- address_name = out.shipping_address_name or out.customer_address
- elif doctype == "Purchase Invoice":
- address_name = out.shipping_address or out.supplier_address
+ if doctype in ("Sales Invoice", "Delivery Note", "Sales Order"):
+ address_name = party_details.shipping_address_name or party_details.customer_address
+ elif doctype in ("Purchase Invoice", "Purchase Order", "Purchase Receipt"):
+ address_name = party_details.shipping_address or party_details.supplier_address
if address_name:
address = frappe.db.get_value("Address", address_name, ["gst_state", "gst_state_number"], as_dict=1)
if address and address.gst_state and address.gst_state_number:
return cstr(address.gst_state_number) + "-" + cstr(address.gst_state)
-def get_regional_address_details(out, doctype, company):
- out.place_of_supply = get_place_of_supply(out, doctype)
+@frappe.whitelist()
+def get_regional_address_details(party_details, doctype, company, return_taxes=None):
- if not out.place_of_supply: return
+ if isinstance(party_details, string_types):
+ party_details = json.loads(party_details)
+ party_details = frappe._dict(party_details)
- if doctype in ("Sales Invoice", "Delivery Note"):
+ party_details.place_of_supply = get_place_of_supply(party_details, doctype)
+ if doctype in ("Sales Invoice", "Delivery Note", "Sales Order"):
master_doctype = "Sales Taxes and Charges Template"
- if not out.company_gstin:
- return
- elif doctype == "Purchase Invoice":
- master_doctype = "Purchase Taxes and Charges Template"
- if not out.supplier_gstin:
+
+ get_tax_template_for_sez(party_details, master_doctype, company, 'Customer')
+ get_tax_template_based_on_category(master_doctype, company, party_details)
+
+ if party_details.get('taxes_and_charges') and return_taxes:
+ return party_details
+
+ if not party_details.company_gstin:
return
- if ((doctype in ("Sales Invoice", "Delivery Note") and out.company_gstin
- and out.company_gstin[:2] != out.place_of_supply[:2]) or (doctype == "Purchase Invoice"
- and out.supplier_gstin and out.supplier_gstin[:2] != out.place_of_supply[:2])):
- default_tax = frappe.db.get_value(master_doctype, {"company": company, "is_inter_state":1, "disabled":0})
+ elif doctype in ("Purchase Invoice", "Purchase Order", "Purchase Receipt"):
+ master_doctype = "Purchase Taxes and Charges Template"
+
+ get_tax_template_for_sez(party_details, master_doctype, company, 'Supplier')
+ get_tax_template_based_on_category(master_doctype, company, party_details)
+
+ if party_details.get('taxes_and_charges') and return_taxes:
+ return party_details
+
+ if not party_details.supplier_gstin:
+ return
+
+ if not party_details.place_of_supply: return
+
+ if not party_details.company_gstin: return
+
+ if ((doctype in ("Sales Invoice", "Delivery Note", "Sales Order") and party_details.company_gstin
+ and party_details.company_gstin[:2] != party_details.place_of_supply[:2]) or (doctype in ("Purchase Invoice",
+ "Purchase Order", "Purchase Receipt") and party_details.supplier_gstin and party_details.supplier_gstin[:2] != party_details.place_of_supply[:2])):
+ default_tax = get_tax_template(master_doctype, company, 1, party_details.company_gstin[:2])
else:
- default_tax = frappe.db.get_value(master_doctype, {"company": company, "disabled":0, "is_default": 1})
+ default_tax = get_tax_template(master_doctype, company, 0, party_details.company_gstin[:2])
if not default_tax:
return
- out["taxes_and_charges"] = default_tax
- out.taxes = get_taxes_and_charges(master_doctype, default_tax)
+ party_details["taxes_and_charges"] = default_tax
+ party_details.taxes = get_taxes_and_charges(master_doctype, default_tax)
+
+ if return_taxes:
+ return party_details
+
+def get_tax_template_based_on_category(master_doctype, company, party_details):
+ if not party_details.get('tax_category'):
+ return
+
+ default_tax = frappe.db.get_value(master_doctype, {'company': company, 'tax_category': party_details.get('tax_category')},
+ 'name')
+
+ if default_tax:
+ party_details["taxes_and_charges"] = default_tax
+ party_details.taxes = get_taxes_and_charges(master_doctype, default_tax)
+
+def get_tax_template(master_doctype, company, is_inter_state, state_code):
+ tax_categories = frappe.get_all('Tax Category', fields = ['name', 'is_inter_state', 'gst_state'],
+ filters = {'is_inter_state': is_inter_state})
+
+ default_tax = ''
+
+ for tax_category in tax_categories:
+ if tax_category.gst_state == number_state_mapping[state_code] or \
+ (not default_tax and not tax_category.gst_state):
+ default_tax = frappe.db.get_value(master_doctype,
+ {'disabled': 0, 'tax_category': tax_category.name}, 'name')
+
+ return default_tax
+
+def get_tax_template_for_sez(party_details, master_doctype, company, party_type):
+
+ gst_details = frappe.db.get_value(party_type, {'name': party_details.get(frappe.scrub(party_type))},
+ ['gst_category', 'export_type'], as_dict=1)
+
+ if gst_details:
+ if gst_details.gst_category == 'SEZ' and gst_details.export_type == 'With Payment of Tax':
+ default_tax = frappe.db.get_value(master_doctype, {"company": company, "is_inter_state":1, "disabled":0,
+ "gst_state": number_state_mapping[party_details.company_gstin[:2]]})
+
+ party_details["taxes_and_charges"] = default_tax
+ party_details.taxes = get_taxes_and_charges(master_doctype, default_tax)
+
def calculate_annual_eligible_hra_exemption(doc):
basic_component = frappe.get_cached_value('Company', doc.company, "basic_component")
@@ -555,7 +629,7 @@
filters={"parent": "GST Settings", "company": company},
fields=["cgst_account", "sgst_account", "igst_account", "cess_account"])
- if not gst_settings_accounts:
+ if not gst_settings_accounts and not frappe.flags.in_test:
frappe.throw(_("Please set GST Accounts in GST Settings"))
for d in gst_settings_accounts:
diff --git a/erpnext/regional/italy/e-invoice.xml b/erpnext/regional/italy/e-invoice.xml
index 049a7eb..69b8e3e 100644
--- a/erpnext/regional/italy/e-invoice.xml
+++ b/erpnext/regional/italy/e-invoice.xml
@@ -205,7 +205,9 @@
{%- endif %}
<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.vat_collectability %}
+ <EsigibilitaIVA>{{ doc.vat_collectability.split("-")[0] }}</EsigibilitaIVA>
+ {%- endif %}
{%- if data.tax_exemption_law %}
<RiferimentoNormativo>{{ data.tax_exemption_law }}</RiferimentoNormativo>
{%- endif %}
diff --git a/erpnext/regional/italy/setup.py b/erpnext/regional/italy/setup.py
index 1526d6f..2d0ad66 100644
--- a/erpnext/regional/italy/setup.py
+++ b/erpnext/regional/italy/setup.py
@@ -155,6 +155,31 @@
fetch_from="country.code"),
dict(fieldname='state_code', label='State Code',
fieldtype='Data', insert_after='state', print_hide=1)
+ ],
+ 'Purchase Invoice': [
+ dict(fieldname='document_type', label='Document Type',
+ fieldtype='Data', insert_after='company', print_hide=1, read_only=1
+ ),
+ dict(fieldname='destination_code', label='Destination Code',
+ fieldtype='Data', insert_after='company', print_hide=1, read_only=1
+ ),
+ dict(fieldname='imported_grand_total', label='Imported Grand Total',
+ fieldtype='Data', insert_after='update_auto_repeat_reference', print_hide=1, read_only=1
+ )
+ ],
+ 'Purchase Taxes and Charges': [
+ dict(fieldname='tax_rate', label='Tax Rate',
+ fieldtype='Data', insert_after='parenttype', print_hide=1, read_only=0
+ )
+ ],
+ 'Supplier': [
+ dict(fieldname='fiscal_code', label='Fiscal Code',
+ fieldtype='Data', insert_after='tax_id', print_hide=1, read_only=1
+ ),
+ dict(fieldname='fiscal_regime', label='Fiscal Regime',
+ fieldtype='Select', insert_after='fiscal_code', print_hide=1, read_only=1,
+ options= "\nRF01\nRF02\nRF04\nRF05\nRF06\nRF07\nRF08\nRF09\nRF10\nRF11\nRF12\nRF13\nRF14\nRF15\nRF16\nRF17\nRF18\nRF19"
+ )
]
}
diff --git a/erpnext/regional/italy/utils.py b/erpnext/regional/italy/utils.py
index bc8d00d..2af72f8 100644
--- a/erpnext/regional/italy/utils.py
+++ b/erpnext/regional/italy/utils.py
@@ -13,6 +13,8 @@
def update_itemised_tax_data(doc):
if not doc.taxes: return
+ if doc.doctype == "Purchase Invoice": return
+
itemised_tax = get_itemised_tax(doc.taxes)
for row in doc.items:
diff --git a/erpnext/assets/doctype/asset_settings/__init__.py b/erpnext/regional/print_format/purchase_einvoice/__init__.py
similarity index 100%
copy from erpnext/assets/doctype/asset_settings/__init__.py
copy to erpnext/regional/print_format/purchase_einvoice/__init__.py
diff --git a/erpnext/regional/print_format/purchase_einvoice/purchase_einvoice.json b/erpnext/regional/print_format/purchase_einvoice/purchase_einvoice.json
new file mode 100644
index 0000000..88f31dd
--- /dev/null
+++ b/erpnext/regional/print_format/purchase_einvoice/purchase_einvoice.json
@@ -0,0 +1,23 @@
+{
+ "align_labels_right": 0,
+ "creation": "2019-10-16 00:47:08.877767",
+ "custom_format": 0,
+ "disabled": 1,
+ "doc_type": "Purchase Invoice",
+ "docstatus": 0,
+ "doctype": "Print Format",
+ "font": "Default",
+ "format_data": "[{\"fieldname\": \"print_heading_template\", \"fieldtype\": \"Custom HTML\", \"options\": \"<div class=\\\"print-heading\\\">\\t\\t\\t\\t<h2>Purchase Invoice<br><small>{{ doc.name }}</small>\\t\\t\\t\\t</h2></div>\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldname\": \"_custom_html\", \"print_hide\": 0, \"label\": \"Custom HTML\", \"fieldtype\": \"HTML\", \"options\": \"<table border=\\\"1\\\" width=\\\"100%\\\">\\n<head>\\n<th>\\nCedente/prestatore (fornitore)\\n</th>\\n<th>\\nCessionario/committente (cliente)\\n</th>\\n</head>\\n<body>\\n<tr>\\n<td style=\\\"width: 50%;white-space:nowrap;\\\">\\n<p>Identificstivo fiscale ai fini IVA: {{frappe.db.get_value(\\\"Supplier\\\", doc.supplier, \\\"tax_id\\\")}}</p>\\n<p>Codice fiscale: {{frappe.db.get_value(\\\"Supplier\\\", doc.supplier, \\\"fiscal_code\\\")}}</p>\\n<p>Denominazione: {{frappe.db.get_value(\\\"Supplier\\\", doc.supplier, \\\"supplier_name\\\")}}</p>\\n<p>Regime fiscale: {{frappe.db.get_value(\\\"Supplier\\\", doc.supplier, \\\"fiscal_regime\\\")}}</p>\\n<p>Indrizo: {{frappe.db.get_value(\\\"Address\\\", doc.supplier_address, \\\"address_line1\\\")}}</p>\\n<p>Commune: {{frappe.db.get_value(\\\"Address\\\", doc.supplier_address, \\\"city\\\")}} Provincia: {{frappe.db.get_value(\\\"Address\\\", doc.supplier_address, \\\"state_code\\\")}}</p>\\n<p>Cap: {{(frappe.db.get_value(\\\"Address\\\", doc.supplier_address, \\\"pincode\\\")) or \\\" \\\"}} Nazione: {{frappe.db.get_value(\\\"Address\\\", doc.supplier_address, \\\"country\\\")}}</p>\\n</td>\\n<td style=\\\"width: 50%;white-space:nowrap;\\\">\\n<p>Identificstivo fiscale ai fini IVA: {{frappe.db.get_value(\\\"Company\\\", doc.company, \\\"tax_id\\\")}}</p>\\n<p>Codice fiscale: {{frappe.db.get_value(\\\"Company\\\", doc.company, \\\"fiscal_code\\\")}}</p>\\n<p>Denominazione: {{doc.company}}</p>\\n<p>Indrizo: {{frappe.db.get_value(\\\"Address\\\", doc.shipping_address, \\\"address_line1\\\")}}</p>\\n<p>Commune: {{frappe.db.get_value(\\\"Address\\\", doc.shipping_address, \\\"city\\\")}} Provincia: {{frappe.db.get_value(\\\"Address\\\", doc.shipping_address, \\\"state_code\\\")}}</p>\\n<p>Cap: {{frappe.db.get_value(\\\"Address\\\", doc.shipping_address, \\\"pincode\\\")}} Nazione: {{frappe.db.get_value(\\\"Address\\\", doc.shipping_address, \\\"country\\\")}}</p>\\n</td>\\n</td>\\n</tr>\\n</body>\\n</table>\\n<br>\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldname\": \"_custom_html\", \"print_hide\": 0, \"label\": \"Custom HTML\", \"fieldtype\": \"HTML\", \"options\": \"<table border=\\\"1\\\" width=\\\"100%\\\">\\n<head>\\n<th>\\nTipologla\\n</th>\\n<th>\\nArt. 73\\n</th>\\n<th>\\nNumero documento\\n</th>\\n<th>\\nData documento\\n</th>\\n<th>\\nCodice destinatario\\n</th>\\n</head>\\n<body>\\n<tr>\\n<td style=\\\"width: 20%;white-space:nowrap;\\\">\\n{{doc.document_type or \\\" \\\"}}\\n</td>\\n<td style=\\\"width: 10%;white-space:nowrap;\\\">\\n{{\\\" \\\"}}\\n</td>\\n<td style=\\\"width: 20%;white-space:nowrap;\\\">\\n{{doc.bill_no or \\\" \\\"}}\\n</td>\\n<td style=\\\"width: 20%;white-space:nowrap;\\\">\\n{{doc.get_formatted(\\\"bill_date\\\") or \\\" \\\"}}\\n</td>\\n<td style=\\\"width: 30%;white-space:nowrap;\\\">\\n{{doc.destination_code or \\\" \\\"}}\\n</td>\\n</tr>\\n</body>\\n</table>\\n<br>\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldname\": \"_custom_html\", \"print_hide\": 0, \"label\": \"Custom HTML\", \"fieldtype\": \"HTML\", \"options\": \"<table border=\\\"1\\\" width=\\\"100%\\\">\\n<head>\\n<th>\\nDescrizione\\n</th>\\n<th>\\nQuantita\\n</th>\\n<th>\\nPrezzo unitario\\n</th>\\n<th>\\nUM\\n</th>\\n<th>\\n%IVA\\n</th>\\n<th>\\nPrezzo totale\\n</th>\\n</head>\\n\\n<body>\\n{%- for row in doc.items -%}\\n<tr>\\n<td style=\\\"width: 30%;\\\">\\n{{row.description or \\\" \\\"}}\\n</td>\\n<td style=\\\"width: 15%;white-space:nowrap;\\\">\\n{{row.get_formatted(\\\"qty\\\", doc)}}\\n</td>\\n<td style=\\\"width: 15%;white-space:nowrap;\\\">\\n{{row.get_formatted(\\\"rate\\\", doc)}}\\n</td>\\n<td style=\\\"width: 5%;white-space:nowrap;\\\">\\n{{row.get_formatted(\\\"uom\\\", doc)}}\\n</td>\\n<td style=\\\"width: 15%;white-space:nowrap;\\\">\\n{{row.get_formatted(\\\"tax_rate\\\", doc)}}\\n</td>\\n<td style=\\\"width: 20%;white-space:nowrap;\\\">\\n{{row.get_formatted(\\\"amount\\\", doc)}}\\n</td>\\n{%- endfor -%}\\n</body>\\n</table>\\n<br>\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldname\": \"_custom_html\", \"print_hide\": 0, \"label\": \"Custom HTML\", \"fieldtype\": \"HTML\", \"options\": \"<table border=\\\"1\\\" width=\\\"100%\\\">\\n<head>\\n<th>\\nesigibilita immediata / riferimenti normativi\\n</th>\\n<th>\\n%IVA\\n</th>\\n<th>\\nSpese accessorie\\n</th>\\n<th>\\nArr.\\n</th>\\n<th>\\nTotale imponibile\\n</th>\\n<th>\\nTotale Imposta\\n</th>\\n</head>\\n\\n<body>\\n{%- for row in doc.taxes -%}\\n<tr>\\n<td style=\\\"width: 30%;white-space:nowrap;\\\">\\n{% if 'None' in row.description %}\\n {{ \\\" \\\" }}\\n{% else %}\\n{{row.description}}\\n{% endif %}\\n</td>\\n<td style=\\\"width: 10%;white-space:nowrap;\\\">\\n{{row.get_formatted(\\\"tax_rate\\\", doc)}}\\n</td>\\n<td style=\\\"width: 10%;white-space:nowrap;\\\">\\n{{\\\"0,00\\\"}}\\n</td>\\n<td style=\\\"width: 10%;white-space:nowrap;\\\">\\n{{\\\" \\\"}}\\n</td>\\n<td style=\\\"width: 20%;white-space:nowrap;\\\">\\n{{doc.get_formatted(\\\"base_net_total\\\")}}\\n</td>\\n<td style=\\\"width: 20%;white-space:nowrap;\\\">\\n{{row.get_formatted(\\\"tax_amount\\\", doc)}}\\n</td>\\n{%- endfor -%}\\n</body>\\n</table>\\n<br>\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldname\": \"_custom_html\", \"print_hide\": 0, \"label\": \"Custom HTML\", \"fieldtype\": \"HTML\", \"options\": \"<table border=\\\"1\\\" width=\\\"100%\\\">\\n<head>\\n<th>\\nImporto bolio\\n</th>\\n<th>\\nSconto/Magglorazione\\n</th>\\n<th>\\nArr.\\n</th>\\n<th>\\nTotale documento\\n</th>\\n</head>\\n\\n<body>\\n<tr>\\n<td style=\\\"width: 20%;white-space:nowrap;\\\">\\n{{\\\" \\\"}}\\n</td>\\n<td style=\\\"width: 30%;white-space:nowrap;\\\">\\n{{\\\" \\\"}}\\n</td>\\n<td style=\\\"width: 10%;white-space:nowrap;\\\">\\n{{\\\" \\\"}}\\n</td>\\n<td style=\\\"width: 40%;white-space:nowrap;\\\">\\n{{doc.get_formatted(\\\"base_grand_total\\\")}}\\n</td>\\n</body>\\n</table>\\n<br>\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldname\": \"_custom_html\", \"print_hide\": 0, \"label\": \"Custom HTML\", \"fieldtype\": \"HTML\", \"options\": \"<table border=\\\"1\\\" width=\\\"100%\\\">\\n<head>\\n<th>\\nModalita pagamento\\n</th>\\n<th>\\nIBAN\\n</th>\\n<th>\\nInstituto\\n</th>\\n<th>\\nData scadenza\\n</th>\\n<th>\\nImporto\\n</th>\\n</head>\\n\\n<body>\\n{%- for row in doc.payment_schedule -%}\\n<tr>\\n<td style=\\\"width: 20%;white-space:nowrap;\\\">\\n{{row.get_formatted(\\\"mode_of_payment_code\\\",doc)}}\\n</td>\\n<td style=\\\"width: 20%;white-space:nowrap;\\\">\\n{{row.get_formatted(\\\"bank_account_iban\\\",doc)}}\\n</td>\\n<td style=\\\"width: 20%;white-space:nowrap;\\\">\\n{{\\\" \\\"}}\\n</td>\\n<td style=\\\"width: 20%;white-space:nowrap;\\\">\\n{{row.get_formatted(\\\"due_date\\\",doc)}}\\n</td>\\n<td style=\\\"width: 20%;white-space:nowrap;\\\">\\n{{row.get_formatted(\\\"payment_amount\\\",doc)}}\\n</td>\\n{%- endfor -%}\\n</body>\\n</table>\"}]",
+ "idx": 0,
+ "line_breaks": 0,
+ "modified": "2019-10-16 23:32:37.709344",
+ "modified_by": "Administrator",
+ "module": "Regional",
+ "name": "Purchase eInvoice",
+ "owner": "Administrator",
+ "print_format_builder": 1,
+ "print_format_type": "Jinja",
+ "raw_printing": 0,
+ "show_section_headings": 0,
+ "standard": "Yes"
+}
\ No newline at end of file
diff --git a/erpnext/regional/report/datev/datev.py b/erpnext/regional/report/datev/datev.py
index ee8735f..bd70639 100644
--- a/erpnext/regional/report/datev/datev.py
+++ b/erpnext/regional/report/datev/datev.py
@@ -10,17 +10,26 @@
from __future__ import unicode_literals
import datetime
import json
+import zlib
+import zipfile
+import six
+from six import BytesIO
from six import string_types
import frappe
from frappe import _
import pandas as pd
+from .datev_constants import DataCategory
+from .datev_constants import Transactions
+from .datev_constants import DebtorsCreditors
+from .datev_constants import AccountNames
+from .datev_constants import QUERY_REPORT_COLUMNS
def execute(filters=None):
"""Entry point for frappe."""
validate(filters)
- result = get_gl_entries(filters, as_dict=0)
- columns = get_columns()
+ result = get_transactions(filters, as_dict=0)
+ columns = QUERY_REPORT_COLUMNS
return columns, result
@@ -41,65 +50,8 @@
except frappe.DoesNotExistError:
frappe.throw(_('Please create <b>DATEV Settings</b> for Company <b>{}</b>.').format(filters.get('company')))
-def get_columns():
- """Return the list of columns that will be shown in query report."""
- columns = [
- {
- "label": "Umsatz (ohne Soll/Haben-Kz)",
- "fieldname": "Umsatz (ohne Soll/Haben-Kz)",
- "fieldtype": "Currency",
- },
- {
- "label": "Soll/Haben-Kennzeichen",
- "fieldname": "Soll/Haben-Kennzeichen",
- "fieldtype": "Data",
- },
- {
- "label": "Kontonummer",
- "fieldname": "Kontonummer",
- "fieldtype": "Data",
- },
- {
- "label": "Gegenkonto (ohne BU-Schlüssel)",
- "fieldname": "Gegenkonto (ohne BU-Schlüssel)",
- "fieldtype": "Data",
- },
- {
- "label": "Belegdatum",
- "fieldname": "Belegdatum",
- "fieldtype": "Date",
- },
- {
- "label": "Buchungstext",
- "fieldname": "Buchungstext",
- "fieldtype": "Text",
- },
- {
- "label": "Beleginfo - Art 1",
- "fieldname": "Beleginfo - Art 1",
- "fieldtype": "Data",
- },
- {
- "label": "Beleginfo - Inhalt 1",
- "fieldname": "Beleginfo - Inhalt 1",
- "fieldtype": "Data",
- },
- {
- "label": "Beleginfo - Art 2",
- "fieldname": "Beleginfo - Art 2",
- "fieldtype": "Data",
- },
- {
- "label": "Beleginfo - Inhalt 2",
- "fieldname": "Beleginfo - Inhalt 2",
- "fieldtype": "Data",
- }
- ]
- return columns
-
-
-def get_gl_entries(filters, as_dict):
+def get_transactions(filters, as_dict=1):
"""
Get a list of accounting entries.
@@ -111,7 +63,7 @@
as_dict -- return as list of dicts [0,1]
"""
gl_entries = frappe.db.sql("""
- select
+ SELECT
/* either debit or credit amount; always positive */
case gl.debit when 0 then gl.credit else gl.debit end as 'Umsatz (ohne Soll/Haben-Kz)',
@@ -132,7 +84,7 @@
gl.against_voucher_type as 'Beleginfo - Art 2',
gl.against_voucher as 'Beleginfo - Inhalt 2'
- from `tabGL Entry` gl
+ FROM `tabGL Entry` gl
/* Statistisches Konto (Debitoren/Kreditoren) */
left join `tabParty Account` pa
@@ -155,15 +107,127 @@
left join `tabAccount` acc_against_pa
on pa.account = acc_against_pa.name
- where gl.company = %(company)s
- and DATE(gl.posting_date) >= %(from_date)s
- and DATE(gl.posting_date) <= %(to_date)s
- order by 'Belegdatum', gl.voucher_no""", filters, as_dict=as_dict)
+ WHERE gl.company = %(company)s
+ AND DATE(gl.posting_date) >= %(from_date)s
+ AND DATE(gl.posting_date) <= %(to_date)s
+ ORDER BY 'Belegdatum', gl.voucher_no""", filters, as_dict=as_dict, as_utf8=1)
return gl_entries
-def get_datev_csv(data, filters):
+def get_customers(filters):
+ """
+ Get a list of Customers.
+
+ Arguments:
+ filters -- dict of filters to be passed to the sql query
+ """
+ return frappe.db.sql("""
+ SELECT
+
+ acc.account_number as 'Konto',
+ cus.customer_name as 'Name (Adressatentyp Unternehmen)',
+ case cus.customer_type when 'Individual' then 1 when 'Company' then 2 else 0 end as 'Adressatentyp',
+ adr.address_line1 as 'Straße',
+ adr.pincode as 'Postleitzahl',
+ adr.city as 'Ort',
+ UPPER(country.code) as 'Land',
+ adr.address_line2 as 'Adresszusatz',
+ con.email_id as 'E-Mail',
+ coalesce(con.mobile_no, con.phone) as 'Telefon',
+ cus.website as 'Internet',
+ cus.tax_id as 'Steuernummer',
+ ccl.credit_limit as 'Kreditlimit (Debitor)'
+
+ FROM `tabParty Account` par
+
+ left join `tabAccount` acc
+ on acc.name = par.account
+
+ left join `tabCustomer` cus
+ on cus.name = par.parent
+
+ left join `tabAddress` adr
+ on adr.name = cus.customer_primary_address
+
+ left join `tabCountry` country
+ on country.name = adr.country
+
+ left join `tabContact` con
+ on con.name = cus.customer_primary_contact
+
+ left join `tabCustomer Credit Limit` ccl
+ on ccl.parent = cus.name
+ and ccl.company = par.company
+
+ WHERE par.company = %(company)s
+ AND par.parenttype = 'Customer'""", filters, as_dict=1, as_utf8=1)
+
+
+def get_suppliers(filters):
+ """
+ Get a list of Suppliers.
+
+ Arguments:
+ filters -- dict of filters to be passed to the sql query
+ """
+ return frappe.db.sql("""
+ SELECT
+
+ acc.account_number as 'Konto',
+ sup.supplier_name as 'Name (Adressatentyp Unternehmen)',
+ case sup.supplier_type when 'Individual' then '1' when 'Company' then '2' else '0' end as 'Adressatentyp',
+ adr.address_line1 as 'Straße',
+ adr.pincode as 'Postleitzahl',
+ adr.city as 'Ort',
+ UPPER(country.code) as 'Land',
+ adr.address_line2 as 'Adresszusatz',
+ con.email_id as 'E-Mail',
+ coalesce(con.mobile_no, con.phone) as 'Telefon',
+ sup.website as 'Internet',
+ sup.tax_id as 'Steuernummer',
+ case sup.on_hold when 1 then sup.release_date else null end as 'Zahlungssperre bis'
+
+ FROM `tabParty Account` par
+
+ left join `tabAccount` acc
+ on acc.name = par.account
+
+ left join `tabSupplier` sup
+ on sup.name = par.parent
+
+ left join `tabDynamic Link` dyn_adr
+ on dyn_adr.link_name = sup.name
+ and dyn_adr.link_doctype = 'Supplier'
+ and dyn_adr.parenttype = 'Address'
+
+ left join `tabAddress` adr
+ on adr.name = dyn_adr.parent
+ and adr.is_primary_address = '1'
+
+ left join `tabCountry` country
+ on country.name = adr.country
+
+ left join `tabDynamic Link` dyn_con
+ on dyn_con.link_name = sup.name
+ and dyn_con.link_doctype = 'Supplier'
+ and dyn_con.parenttype = 'Contact'
+
+ left join `tabContact` con
+ on con.name = dyn_con.parent
+ and con.is_primary_contact = '1'
+
+ WHERE par.company = %(company)s
+ AND par.parenttype = 'Supplier'""", filters, as_dict=1, as_utf8=1)
+
+
+def get_account_names(filters):
+ return frappe.get_list("Account",
+ fields=["account_number as Konto", "name as Kontenbeschriftung"],
+ filters={"company": filters.get("company"), "is_group": "0"})
+
+
+def get_datev_csv(data, filters, csv_class):
"""
Fill in missing columns and return a CSV in DATEV Format.
@@ -174,7 +238,46 @@
Arguments:
data -- array of dictionaries
filters -- dict
+ csv_class -- defines DATA_CATEGORY, FORMAT_NAME and COLUMNS
"""
+ header = get_header(filters, csv_class)
+
+ empty_df = pd.DataFrame(columns=csv_class.COLUMNS)
+ data_df = pd.DataFrame.from_records(data)
+
+ result = empty_df.append(data_df, sort=True)
+
+ if csv_class.DATA_CATEGORY == DataCategory.TRANSACTIONS:
+ result['Belegdatum'] = pd.to_datetime(result['Belegdatum'])
+
+ if csv_class.DATA_CATEGORY == DataCategory.ACCOUNT_NAMES:
+ result['Sprach-ID'] = 'de-DE'
+
+ header = ';'.join(header).encode('latin_1')
+ data = result.to_csv(
+ # Reason for str(';'): https://github.com/pandas-dev/pandas/issues/6035
+ sep=str(';'),
+ # European decimal seperator
+ decimal=',',
+ # Windows "ANSI" encoding
+ encoding='latin_1',
+ # format date as DDMM
+ date_format='%d%m',
+ # Windows line terminator
+ line_terminator='\r\n',
+ # Do not number rows
+ index=False,
+ # Use all columns defined above
+ columns=csv_class.COLUMNS
+ )
+
+ if not six.PY2:
+ data = data.encode('latin_1')
+
+ return header + b'\r\n' + data
+
+
+def get_header(filters, csv_class):
header = [
# A = DATEV format
# DTVF = created by DATEV software,
@@ -185,18 +288,8 @@
# 510 = 5.10,
# 720 = 7.20
"510",
- # C = Data category
- # 21 = Transaction batch (Buchungsstapel),
- # 67 = Buchungstextkonstanten,
- # 16 = Debitors/Creditors,
- # 20 = Account names (Kontenbeschriftungen)
- "21",
- # D = Format name
- # Buchungsstapel,
- # Buchungstextkonstanten,
- # Debitoren/Kreditoren,
- # Kontenbeschriftungen
- "Buchungsstapel",
+ csv_class.DATA_CATEGORY,
+ csv_class.FORMAT_NAME,
# E = Format version (regarding format name)
"",
# F = Generated on
@@ -224,16 +317,17 @@
# P = Transaction batch end date (YYYYMMDD)
frappe.utils.formatdate(filters.get('to_date'), "yyyyMMdd"),
# Q = Description (for example, "January - February 2019 Transactions")
- "{} - {} Buchungsstapel".format(
- frappe.utils.formatdate(filters.get('from_date'), "MMMM yyyy"),
- frappe.utils.formatdate(filters.get('to_date'), "MMMM yyyy")
+ "{} - {} {}".format(
+ frappe.utils.formatdate(filters.get('from_date'), "MMMM yyyy"),
+ frappe.utils.formatdate(filters.get('to_date'), "MMMM yyyy"),
+ csv_class.FORMAT_NAME
),
# R = Diktatkürzel
"",
# S = Buchungstyp
# 1 = Transaction batch (Buchungsstapel),
# 2 = Annual financial statement (Jahresabschluss)
- "1",
+ "1" if csv_class.DATA_CATEGORY == DataCategory.TRANSACTIONS else "",
# T = Rechnungslegungszweck
"",
# U = Festschreibung
@@ -241,185 +335,8 @@
# V = Kontoführungs-Währungskennzeichen des Geldkontos
frappe.get_value("Company", filters.get("company"), "default_currency")
]
- columns = [
- # All possible columns must tbe listed here, because DATEV requires them to
- # be present in the CSV.
- # ---
- # Umsatz
- "Umsatz (ohne Soll/Haben-Kz)",
- "Soll/Haben-Kennzeichen",
- "WKZ Umsatz",
- "Kurs",
- "Basis-Umsatz",
- "WKZ Basis-Umsatz",
- # Konto/Gegenkonto
- "Kontonummer",
- "Gegenkonto (ohne BU-Schlüssel)",
- "BU-Schlüssel",
- # Datum
- "Belegdatum",
- # Belegfelder
- "Belegfeld 1",
- "Belegfeld 2",
- # Weitere Felder
- "Skonto",
- "Buchungstext",
- # OPOS-Informationen
- "Postensperre",
- "Diverse Adressnummer",
- "Geschäftspartnerbank",
- "Sachverhalt",
- "Zinssperre",
- # Digitaler Beleg
- "Beleglink",
- # Beleginfo
- "Beleginfo - Art 1",
- "Beleginfo - Inhalt 1",
- "Beleginfo - Art 2",
- "Beleginfo - Inhalt 2",
- "Beleginfo - Art 3",
- "Beleginfo - Inhalt 3",
- "Beleginfo - Art 4",
- "Beleginfo - Inhalt 4",
- "Beleginfo - Art 5",
- "Beleginfo - Inhalt 5",
- "Beleginfo - Art 6",
- "Beleginfo - Inhalt 6",
- "Beleginfo - Art 7",
- "Beleginfo - Inhalt 7",
- "Beleginfo - Art 8",
- "Beleginfo - Inhalt 8",
- # Kostenrechnung
- "Kost 1 - Kostenstelle",
- "Kost 2 - Kostenstelle",
- "Kost-Menge",
- # Steuerrechnung
- "EU-Land u. UStID",
- "EU-Steuersatz",
- "Abw. Versteuerungsart",
- # L+L Sachverhalt
- "Sachverhalt L+L",
- "Funktionsergänzung L+L",
- # Funktion Steuerschlüssel 49
- "BU 49 Hauptfunktionstyp",
- "BU 49 Hauptfunktionsnummer",
- "BU 49 Funktionsergänzung",
- # Zusatzinformationen
- "Zusatzinformation - Art 1",
- "Zusatzinformation - Inhalt 1",
- "Zusatzinformation - Art 2",
- "Zusatzinformation - Inhalt 2",
- "Zusatzinformation - Art 3",
- "Zusatzinformation - Inhalt 3",
- "Zusatzinformation - Art 4",
- "Zusatzinformation - Inhalt 4",
- "Zusatzinformation - Art 5",
- "Zusatzinformation - Inhalt 5",
- "Zusatzinformation - Art 6",
- "Zusatzinformation - Inhalt 6",
- "Zusatzinformation - Art 7",
- "Zusatzinformation - Inhalt 7",
- "Zusatzinformation - Art 8",
- "Zusatzinformation - Inhalt 8",
- "Zusatzinformation - Art 9",
- "Zusatzinformation - Inhalt 9",
- "Zusatzinformation - Art 10",
- "Zusatzinformation - Inhalt 10",
- "Zusatzinformation - Art 11",
- "Zusatzinformation - Inhalt 11",
- "Zusatzinformation - Art 12",
- "Zusatzinformation - Inhalt 12",
- "Zusatzinformation - Art 13",
- "Zusatzinformation - Inhalt 13",
- "Zusatzinformation - Art 14",
- "Zusatzinformation - Inhalt 14",
- "Zusatzinformation - Art 15",
- "Zusatzinformation - Inhalt 15",
- "Zusatzinformation - Art 16",
- "Zusatzinformation - Inhalt 16",
- "Zusatzinformation - Art 17",
- "Zusatzinformation - Inhalt 17",
- "Zusatzinformation - Art 18",
- "Zusatzinformation - Inhalt 18",
- "Zusatzinformation - Art 19",
- "Zusatzinformation - Inhalt 19",
- "Zusatzinformation - Art 20",
- "Zusatzinformation - Inhalt 20",
- # Mengenfelder LuF
- "Stück",
- "Gewicht",
- # Forderungsart
- "Zahlweise",
- "Forderungsart",
- "Veranlagungsjahr",
- "Zugeordnete Fälligkeit",
- # Weitere Felder
- "Skontotyp",
- # Anzahlungen
- "Auftragsnummer",
- "Buchungstyp",
- "USt-Schlüssel (Anzahlungen)",
- "EU-Land (Anzahlungen)",
- "Sachverhalt L+L (Anzahlungen)",
- "EU-Steuersatz (Anzahlungen)",
- "Erlöskonto (Anzahlungen)",
- # Stapelinformationen
- "Herkunft-Kz",
- # Technische Identifikation
- "Buchungs GUID",
- # Kostenrechnung
- "Kost-Datum",
- # OPOS-Informationen
- "SEPA-Mandatsreferenz",
- "Skontosperre",
- # Gesellschafter und Sonderbilanzsachverhalt
- "Gesellschaftername",
- "Beteiligtennummer",
- "Identifikationsnummer",
- "Zeichnernummer",
- # OPOS-Informationen
- "Postensperre bis",
- # Gesellschafter und Sonderbilanzsachverhalt
- "Bezeichnung SoBil-Sachverhalt",
- "Kennzeichen SoBil-Buchung",
- # Stapelinformationen
- "Festschreibung",
- # Datum
- "Leistungsdatum",
- "Datum Zuord. Steuerperiode",
- # OPOS-Informationen
- "Fälligkeit",
- # Konto/Gegenkonto
- "Generalumkehr (GU)",
- # Steuersatz für Steuerschlüssel
- "Steuersatz",
- "Land"
- ]
+ return header
- empty_df = pd.DataFrame(columns=columns)
- data_df = pd.DataFrame.from_records(data)
-
- result = empty_df.append(data_df)
- result['Belegdatum'] = pd.to_datetime(result['Belegdatum'])
-
- header = ';'.join(header).encode('latin_1')
- data = result.to_csv(
- sep=b';',
- # European decimal seperator
- decimal=',',
- # Windows "ANSI" encoding
- encoding='latin_1',
- # format date as DDMM
- date_format='%d%m',
- # Windows line terminator
- line_terminator=b'\r\n',
- # Do not number rows
- index=False,
- # Use all columns defined above
- columns=columns
- )
-
- return header + b'\r\n' + data
@frappe.whitelist()
def download_datev_csv(filters=None):
@@ -438,8 +355,31 @@
filters = json.loads(filters)
validate(filters)
- data = get_gl_entries(filters, as_dict=1)
- frappe.response['result'] = get_datev_csv(data, filters)
- frappe.response['doctype'] = 'EXTF_Buchungsstapel'
- frappe.response['type'] = 'csv'
+ # This is where my zip will be written
+ zip_buffer = BytesIO()
+ # This is my zip file
+ datev_zip = zipfile.ZipFile(zip_buffer, mode='w', compression=zipfile.ZIP_DEFLATED)
+
+ transactions = get_transactions(filters)
+ transactions_csv = get_datev_csv(transactions, filters, csv_class=Transactions)
+ datev_zip.writestr('EXTF_Buchungsstapel.csv', transactions_csv)
+
+ account_names = get_account_names(filters)
+ account_names_csv = get_datev_csv(account_names, filters, csv_class=AccountNames)
+ datev_zip.writestr('EXTF_Kontenbeschriftungen.csv', account_names_csv)
+
+ customers = get_customers(filters)
+ customers_csv = get_datev_csv(customers, filters, csv_class=DebtorsCreditors)
+ datev_zip.writestr('EXTF_Kunden.csv', customers_csv)
+
+ suppliers = get_suppliers(filters)
+ suppliers_csv = get_datev_csv(suppliers, filters, csv_class=DebtorsCreditors)
+ datev_zip.writestr('EXTF_Lieferanten.csv', suppliers_csv)
+
+ # You must call close() before exiting your program or essential records will not be written.
+ datev_zip.close()
+
+ frappe.response['filecontent'] = zip_buffer.getvalue()
+ frappe.response['filename'] = 'DATEV.zip'
+ frappe.response['type'] = 'binary'
diff --git a/erpnext/regional/report/datev/datev_constants.py b/erpnext/regional/report/datev/datev_constants.py
new file mode 100644
index 0000000..1c9bd23
--- /dev/null
+++ b/erpnext/regional/report/datev/datev_constants.py
@@ -0,0 +1,512 @@
+# coding: utf-8
+"""Constants used in datev.py."""
+
+TRANSACTION_COLUMNS = [
+ # All possible columns must tbe listed here, because DATEV requires them to
+ # be present in the CSV.
+ # ---
+ # Umsatz
+ "Umsatz (ohne Soll/Haben-Kz)",
+ "Soll/Haben-Kennzeichen",
+ "WKZ Umsatz",
+ "Kurs",
+ "Basis-Umsatz",
+ "WKZ Basis-Umsatz",
+ # Konto/Gegenkonto
+ "Kontonummer",
+ "Gegenkonto (ohne BU-Schlüssel)",
+ "BU-Schlüssel",
+ # Datum
+ "Belegdatum",
+ # Belegfelder
+ "Belegfeld 1",
+ "Belegfeld 2",
+ # Weitere Felder
+ "Skonto",
+ "Buchungstext",
+ # OPOS-Informationen
+ "Postensperre",
+ "Diverse Adressnummer",
+ "Geschäftspartnerbank",
+ "Sachverhalt",
+ "Zinssperre",
+ # Digitaler Beleg
+ "Beleglink",
+ # Beleginfo
+ "Beleginfo - Art 1",
+ "Beleginfo - Inhalt 1",
+ "Beleginfo - Art 2",
+ "Beleginfo - Inhalt 2",
+ "Beleginfo - Art 3",
+ "Beleginfo - Inhalt 3",
+ "Beleginfo - Art 4",
+ "Beleginfo - Inhalt 4",
+ "Beleginfo - Art 5",
+ "Beleginfo - Inhalt 5",
+ "Beleginfo - Art 6",
+ "Beleginfo - Inhalt 6",
+ "Beleginfo - Art 7",
+ "Beleginfo - Inhalt 7",
+ "Beleginfo - Art 8",
+ "Beleginfo - Inhalt 8",
+ # Kostenrechnung
+ "Kost 1 - Kostenstelle",
+ "Kost 2 - Kostenstelle",
+ "Kost-Menge",
+ # Steuerrechnung
+ "EU-Land u. UStID",
+ "EU-Steuersatz",
+ "Abw. Versteuerungsart",
+ # L+L Sachverhalt
+ "Sachverhalt L+L",
+ "Funktionsergänzung L+L",
+ # Funktion Steuerschlüssel 49
+ "BU 49 Hauptfunktionstyp",
+ "BU 49 Hauptfunktionsnummer",
+ "BU 49 Funktionsergänzung",
+ # Zusatzinformationen
+ "Zusatzinformation - Art 1",
+ "Zusatzinformation - Inhalt 1",
+ "Zusatzinformation - Art 2",
+ "Zusatzinformation - Inhalt 2",
+ "Zusatzinformation - Art 3",
+ "Zusatzinformation - Inhalt 3",
+ "Zusatzinformation - Art 4",
+ "Zusatzinformation - Inhalt 4",
+ "Zusatzinformation - Art 5",
+ "Zusatzinformation - Inhalt 5",
+ "Zusatzinformation - Art 6",
+ "Zusatzinformation - Inhalt 6",
+ "Zusatzinformation - Art 7",
+ "Zusatzinformation - Inhalt 7",
+ "Zusatzinformation - Art 8",
+ "Zusatzinformation - Inhalt 8",
+ "Zusatzinformation - Art 9",
+ "Zusatzinformation - Inhalt 9",
+ "Zusatzinformation - Art 10",
+ "Zusatzinformation - Inhalt 10",
+ "Zusatzinformation - Art 11",
+ "Zusatzinformation - Inhalt 11",
+ "Zusatzinformation - Art 12",
+ "Zusatzinformation - Inhalt 12",
+ "Zusatzinformation - Art 13",
+ "Zusatzinformation - Inhalt 13",
+ "Zusatzinformation - Art 14",
+ "Zusatzinformation - Inhalt 14",
+ "Zusatzinformation - Art 15",
+ "Zusatzinformation - Inhalt 15",
+ "Zusatzinformation - Art 16",
+ "Zusatzinformation - Inhalt 16",
+ "Zusatzinformation - Art 17",
+ "Zusatzinformation - Inhalt 17",
+ "Zusatzinformation - Art 18",
+ "Zusatzinformation - Inhalt 18",
+ "Zusatzinformation - Art 19",
+ "Zusatzinformation - Inhalt 19",
+ "Zusatzinformation - Art 20",
+ "Zusatzinformation - Inhalt 20",
+ # Mengenfelder LuF
+ "Stück",
+ "Gewicht",
+ # Forderungsart
+ "Zahlweise",
+ "Forderungsart",
+ "Veranlagungsjahr",
+ "Zugeordnete Fälligkeit",
+ # Weitere Felder
+ "Skontotyp",
+ # Anzahlungen
+ "Auftragsnummer",
+ "Buchungstyp",
+ "USt-Schlüssel (Anzahlungen)",
+ "EU-Land (Anzahlungen)",
+ "Sachverhalt L+L (Anzahlungen)",
+ "EU-Steuersatz (Anzahlungen)",
+ "Erlöskonto (Anzahlungen)",
+ # Stapelinformationen
+ "Herkunft-Kz",
+ # Technische Identifikation
+ "Buchungs GUID",
+ # Kostenrechnung
+ "Kost-Datum",
+ # OPOS-Informationen
+ "SEPA-Mandatsreferenz",
+ "Skontosperre",
+ # Gesellschafter und Sonderbilanzsachverhalt
+ "Gesellschaftername",
+ "Beteiligtennummer",
+ "Identifikationsnummer",
+ "Zeichnernummer",
+ # OPOS-Informationen
+ "Postensperre bis",
+ # Gesellschafter und Sonderbilanzsachverhalt
+ "Bezeichnung SoBil-Sachverhalt",
+ "Kennzeichen SoBil-Buchung",
+ # Stapelinformationen
+ "Festschreibung",
+ # Datum
+ "Leistungsdatum",
+ "Datum Zuord. Steuerperiode",
+ # OPOS-Informationen
+ "Fälligkeit",
+ # Konto/Gegenkonto
+ "Generalumkehr (GU)",
+ # Steuersatz für Steuerschlüssel
+ "Steuersatz",
+ "Land"
+]
+
+DEBTOR_CREDITOR_COLUMNS = [
+ # All possible columns must tbe listed here, because DATEV requires them to
+ # be present in the CSV.
+ # Columns "Leerfeld" have been replaced with "Leerfeld #" to not confuse pandas
+ # ---
+ "Konto",
+ "Name (Adressatentyp Unternehmen)",
+ "Unternehmensgegenstand",
+ "Name (Adressatentyp natürl. Person)",
+ "Vorname (Adressatentyp natürl. Person)",
+ "Name (Adressatentyp keine Angabe)",
+ "Adressatentyp",
+ "Kurzbezeichnung",
+ "EU-Land",
+ "EU-USt-IdNr.",
+ "Anrede",
+ "Titel/Akad. Grad",
+ "Adelstitel",
+ "Namensvorsatz",
+ "Adressart",
+ "Straße",
+ "Postfach",
+ "Postleitzahl",
+ "Ort",
+ "Land",
+ "Versandzusatz",
+ "Adresszusatz",
+ "Abweichende Anrede",
+ "Abw. Zustellbezeichnung 1",
+ "Abw. Zustellbezeichnung 2",
+ "Kennz. Korrespondenzadresse",
+ "Adresse gültig von",
+ "Adresse gültig bis",
+ "Telefon",
+ "Bemerkung (Telefon)",
+ "Telefon Geschäftsleitung",
+ "Bemerkung (Telefon GL)",
+ "E-Mail",
+ "Bemerkung (E-Mail)",
+ "Internet",
+ "Bemerkung (Internet)",
+ "Fax",
+ "Bemerkung (Fax)",
+ "Sonstige",
+ "Bemerkung (Sonstige)",
+ "Bankleitzahl 1",
+ "Bankbezeichnung 1",
+ "Bankkonto-Nummer 1",
+ "Länderkennzeichen 1",
+ "IBAN 1",
+ "Leerfeld 1",
+ "SWIFT-Code 1",
+ "Abw. Kontoinhaber 1",
+ "Kennz. Haupt-Bankverb. 1",
+ "Bankverb. 1 Gültig von",
+ "Bankverb. 1 Gültig bis",
+ "Bankleitzahl 2",
+ "Bankbezeichnung 2",
+ "Bankkonto-Nummer 2",
+ "Länderkennzeichen 2",
+ "IBAN 2",
+ "Leerfeld 2",
+ "SWIFT-Code 2",
+ "Abw. Kontoinhaber 2",
+ "Kennz. Haupt-Bankverb. 2",
+ "Bankverb. 2 gültig von",
+ "Bankverb. 2 gültig bis",
+ "Bankleitzahl 3",
+ "Bankbezeichnung 3",
+ "Bankkonto-Nummer 3",
+ "Länderkennzeichen 3",
+ "IBAN 3",
+ "Leerfeld 3",
+ "SWIFT-Code 3",
+ "Abw. Kontoinhaber 3",
+ "Kennz. Haupt-Bankverb. 3",
+ "Bankverb. 3 gültig von",
+ "Bankverb. 3 gültig bis",
+ "Bankleitzahl 4",
+ "Bankbezeichnung 4",
+ "Bankkonto-Nummer 4",
+ "Länderkennzeichen 4",
+ "IBAN 4",
+ "Leerfeld 4",
+ "SWIFT-Code 4",
+ "Abw. Kontoinhaber 4",
+ "Kennz. Haupt-Bankverb. 4",
+ "Bankverb. 4 Gültig von",
+ "Bankverb. 4 Gültig bis",
+ "Bankleitzahl 5",
+ "Bankbezeichnung 5",
+ "Bankkonto-Nummer 5",
+ "Länderkennzeichen 5",
+ "IBAN 5",
+ "Leerfeld 5",
+ "SWIFT-Code 5",
+ "Abw. Kontoinhaber 5",
+ "Kennz. Haupt-Bankverb. 5",
+ "Bankverb. 5 gültig von",
+ "Bankverb. 5 gültig bis",
+ "Leerfeld 6",
+ "Briefanrede",
+ "Grußformel",
+ "Kundennummer",
+ "Steuernummer",
+ "Sprache",
+ "Ansprechpartner",
+ "Vertreter",
+ "Sachbearbeiter",
+ "Diverse-Konto",
+ "Ausgabeziel",
+ "Währungssteuerung",
+ "Kreditlimit (Debitor)",
+ "Zahlungsbedingung",
+ "Fälligkeit in Tagen (Debitor)",
+ "Skonto in Prozent (Debitor)",
+ "Kreditoren-Ziel 1 (Tage)",
+ "Kreditoren-Skonto 1 (%)",
+ "Kreditoren-Ziel 2 (Tage)",
+ "Kreditoren-Skonto 2 (%)",
+ "Kreditoren-Ziel 3 Brutto (Tage)",
+ "Kreditoren-Ziel 4 (Tage)",
+ "Kreditoren-Skonto 4 (%)",
+ "Kreditoren-Ziel 5 (Tage)",
+ "Kreditoren-Skonto 5 (%)",
+ "Mahnung",
+ "Kontoauszug",
+ "Mahntext 1",
+ "Mahntext 2",
+ "Mahntext 3",
+ "Kontoauszugstext",
+ "Mahnlimit Betrag",
+ "Mahnlimit %",
+ "Zinsberechnung",
+ "Mahnzinssatz 1",
+ "Mahnzinssatz 2",
+ "Mahnzinssatz 3",
+ "Lastschrift",
+ "Verfahren",
+ "Mandantenbank",
+ "Zahlungsträger",
+ "Indiv. Feld 1",
+ "Indiv. Feld 2",
+ "Indiv. Feld 3",
+ "Indiv. Feld 4",
+ "Indiv. Feld 5",
+ "Indiv. Feld 6",
+ "Indiv. Feld 7",
+ "Indiv. Feld 8",
+ "Indiv. Feld 9",
+ "Indiv. Feld 10",
+ "Indiv. Feld 11",
+ "Indiv. Feld 12",
+ "Indiv. Feld 13",
+ "Indiv. Feld 14",
+ "Indiv. Feld 15",
+ "Abweichende Anrede (Rechnungsadresse)",
+ "Adressart (Rechnungsadresse)",
+ "Straße (Rechnungsadresse)",
+ "Postfach (Rechnungsadresse)",
+ "Postleitzahl (Rechnungsadresse)",
+ "Ort (Rechnungsadresse)",
+ "Land (Rechnungsadresse)",
+ "Versandzusatz (Rechnungsadresse)",
+ "Adresszusatz (Rechnungsadresse)",
+ "Abw. Zustellbezeichnung 1 (Rechnungsadresse)",
+ "Abw. Zustellbezeichnung 2 (Rechnungsadresse)",
+ "Adresse Gültig von (Rechnungsadresse)",
+ "Adresse Gültig bis (Rechnungsadresse)",
+ "Bankleitzahl 6",
+ "Bankbezeichnung 6",
+ "Bankkonto-Nummer 6",
+ "Länderkennzeichen 6",
+ "IBAN 6",
+ "Leerfeld 7",
+ "SWIFT-Code 6",
+ "Abw. Kontoinhaber 6",
+ "Kennz. Haupt-Bankverb. 6",
+ "Bankverb 6 gültig von",
+ "Bankverb 6 gültig bis",
+ "Bankleitzahl 7",
+ "Bankbezeichnung 7",
+ "Bankkonto-Nummer 7",
+ "Länderkennzeichen 7",
+ "IBAN 7",
+ "Leerfeld 8",
+ "SWIFT-Code 7",
+ "Abw. Kontoinhaber 7",
+ "Kennz. Haupt-Bankverb. 7",
+ "Bankverb 7 gültig von",
+ "Bankverb 7 gültig bis",
+ "Bankleitzahl 8",
+ "Bankbezeichnung 8",
+ "Bankkonto-Nummer 8",
+ "Länderkennzeichen 8",
+ "IBAN 8",
+ "Leerfeld 9",
+ "SWIFT-Code 8",
+ "Abw. Kontoinhaber 8",
+ "Kennz. Haupt-Bankverb. 8",
+ "Bankverb 8 gültig von",
+ "Bankverb 8 gültig bis",
+ "Bankleitzahl 9",
+ "Bankbezeichnung 9",
+ "Bankkonto-Nummer 9",
+ "Länderkennzeichen 9",
+ "IBAN 9",
+ "Leerfeld 10",
+ "SWIFT-Code 9",
+ "Abw. Kontoinhaber 9",
+ "Kennz. Haupt-Bankverb. 9",
+ "Bankverb 9 gültig von",
+ "Bankverb 9 gültig bis",
+ "Bankleitzahl 10",
+ "Bankbezeichnung 10",
+ "Bankkonto-Nummer 10",
+ "Länderkennzeichen 10",
+ "IBAN 10",
+ "Leerfeld 11",
+ "SWIFT-Code 10",
+ "Abw. Kontoinhaber 10",
+ "Kennz. Haupt-Bankverb. 10",
+ "Bankverb 10 gültig von",
+ "Bankverb 10 gültig bis",
+ "Nummer Fremdsystem",
+ "Insolvent",
+ "SEPA-Mandatsreferenz 1",
+ "SEPA-Mandatsreferenz 2",
+ "SEPA-Mandatsreferenz 3",
+ "SEPA-Mandatsreferenz 4",
+ "SEPA-Mandatsreferenz 5",
+ "SEPA-Mandatsreferenz 6",
+ "SEPA-Mandatsreferenz 7",
+ "SEPA-Mandatsreferenz 8",
+ "SEPA-Mandatsreferenz 9",
+ "SEPA-Mandatsreferenz 10",
+ "Verknüpftes OPOS-Konto",
+ "Mahnsperre bis",
+ "Lastschriftsperre bis",
+ "Zahlungssperre bis",
+ "Gebührenberechnung",
+ "Mahngebühr 1",
+ "Mahngebühr 2",
+ "Mahngebühr 3",
+ "Pauschalberechnung",
+ "Verzugspauschale 1",
+ "Verzugspauschale 2",
+ "Verzugspauschale 3",
+ "Alternativer Suchname",
+ "Status",
+ "Anschrift manuell geändert (Korrespondenzadresse)",
+ "Anschrift individuell (Korrespondenzadresse)",
+ "Anschrift manuell geändert (Rechnungsadresse)",
+ "Anschrift individuell (Rechnungsadresse)",
+ "Fristberechnung bei Debitor",
+ "Mahnfrist 1",
+ "Mahnfrist 2",
+ "Mahnfrist 3",
+ "Letzte Frist"
+]
+
+ACCOUNT_NAME_COLUMNS = [
+ # Account number
+ "Konto",
+ # Account name
+ "Kontenbeschriftung",
+ # Language of the account name
+ # "de-DE" or "en-GB"
+ "Sprach-ID"
+]
+
+QUERY_REPORT_COLUMNS = [
+ {
+ "label": "Umsatz (ohne Soll/Haben-Kz)",
+ "fieldname": "Umsatz (ohne Soll/Haben-Kz)",
+ "fieldtype": "Currency",
+ },
+ {
+ "label": "Soll/Haben-Kennzeichen",
+ "fieldname": "Soll/Haben-Kennzeichen",
+ "fieldtype": "Data",
+ },
+ {
+ "label": "Kontonummer",
+ "fieldname": "Kontonummer",
+ "fieldtype": "Data",
+ },
+ {
+ "label": "Gegenkonto (ohne BU-Schlüssel)",
+ "fieldname": "Gegenkonto (ohne BU-Schlüssel)",
+ "fieldtype": "Data",
+ },
+ {
+ "label": "Belegdatum",
+ "fieldname": "Belegdatum",
+ "fieldtype": "Date",
+ },
+ {
+ "label": "Buchungstext",
+ "fieldname": "Buchungstext",
+ "fieldtype": "Text",
+ },
+ {
+ "label": "Beleginfo - Art 1",
+ "fieldname": "Beleginfo - Art 1",
+ "fieldtype": "Data",
+ },
+ {
+ "label": "Beleginfo - Inhalt 1",
+ "fieldname": "Beleginfo - Inhalt 1",
+ "fieldtype": "Data",
+ },
+ {
+ "label": "Beleginfo - Art 2",
+ "fieldname": "Beleginfo - Art 2",
+ "fieldtype": "Data",
+ },
+ {
+ "label": "Beleginfo - Inhalt 2",
+ "fieldname": "Beleginfo - Inhalt 2",
+ "fieldtype": "Data",
+ }
+]
+
+class DataCategory():
+ """Field of the CSV Header."""
+
+ DEBTORS_CREDITORS = "16"
+ ACCOUNT_NAMES = "20"
+ TRANSACTIONS = "21"
+ POSTING_TEXT_CONSTANTS = "67"
+
+class FormatName():
+ """Field of the CSV Header, corresponds to DataCategory."""
+
+ DEBTORS_CREDITORS = "Debitoren/Kreditoren"
+ ACCOUNT_NAMES = "Kontenbeschriftungen"
+ TRANSACTIONS = "Buchungsstapel"
+ POSTING_TEXT_CONSTANTS = "Buchungstextkonstanten"
+
+class Transactions():
+ DATA_CATEGORY = DataCategory.TRANSACTIONS
+ FORMAT_NAME = FormatName.TRANSACTIONS
+ COLUMNS = TRANSACTION_COLUMNS
+
+class DebtorsCreditors():
+ DATA_CATEGORY = DataCategory.DEBTORS_CREDITORS
+ FORMAT_NAME = FormatName.DEBTORS_CREDITORS
+ COLUMNS = DEBTOR_CREDITOR_COLUMNS
+
+class AccountNames():
+ DATA_CATEGORY = DataCategory.ACCOUNT_NAMES
+ FORMAT_NAME = FormatName.ACCOUNT_NAMES
+ COLUMNS = ACCOUNT_NAME_COLUMNS
diff --git a/erpnext/regional/report/datev/test_datev.py b/erpnext/regional/report/datev/test_datev.py
new file mode 100644
index 0000000..3cc65fe
--- /dev/null
+++ b/erpnext/regional/report/datev/test_datev.py
@@ -0,0 +1,244 @@
+# coding=utf-8
+from __future__ import unicode_literals
+
+import os
+import json
+import zipfile
+from six import BytesIO
+from unittest import TestCase
+
+import frappe
+from frappe.utils import getdate, today, now_datetime, cstr
+from frappe.test_runner import make_test_objects
+from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
+from erpnext.accounts.doctype.account.chart_of_accounts.chart_of_accounts import create_charts
+
+from erpnext.regional.report.datev.datev import validate
+from erpnext.regional.report.datev.datev import get_transactions
+from erpnext.regional.report.datev.datev import get_customers
+from erpnext.regional.report.datev.datev import get_suppliers
+from erpnext.regional.report.datev.datev import get_account_names
+from erpnext.regional.report.datev.datev import get_datev_csv
+from erpnext.regional.report.datev.datev import get_header
+from erpnext.regional.report.datev.datev import download_datev_csv
+
+from erpnext.regional.report.datev.datev_constants import DataCategory
+from erpnext.regional.report.datev.datev_constants import Transactions
+from erpnext.regional.report.datev.datev_constants import DebtorsCreditors
+from erpnext.regional.report.datev.datev_constants import AccountNames
+from erpnext.regional.report.datev.datev_constants import QUERY_REPORT_COLUMNS
+
+def make_company(company_name, abbr):
+ if not frappe.db.exists("Company", company_name):
+ company = frappe.get_doc({
+ "doctype": "Company",
+ "company_name": company_name,
+ "abbr": abbr,
+ "default_currency": "EUR",
+ "country": "Germany",
+ "create_chart_of_accounts_based_on": "Standard Template",
+ "chart_of_accounts": "SKR04 mit Kontonummern"
+ })
+ company.insert()
+ else:
+ company = frappe.get_doc("Company", company_name)
+
+ # indempotent
+ company.create_default_warehouses()
+
+ if not frappe.db.get_value("Cost Center", {"is_group": 0, "company": company.name}):
+ company.create_default_cost_center()
+
+ company.save()
+ return company
+
+def setup_fiscal_year():
+ fiscal_year = None
+ year = cstr(now_datetime().year)
+ if not frappe.db.get_value("Fiscal Year", {"year": year}, "name"):
+ try:
+ fiscal_year = frappe.get_doc({
+ "doctype": "Fiscal Year",
+ "year": year,
+ "year_start_date": "{0}-01-01".format(year),
+ "year_end_date": "{0}-12-31".format(year)
+ })
+ fiscal_year.insert()
+ except frappe.NameError:
+ pass
+
+ if fiscal_year:
+ fiscal_year.set_as_default()
+
+def make_customer_with_account(customer_name, company):
+ acc_name = frappe.db.get_value("Account", {
+ "account_name": customer_name,
+ "company": company.name
+ }, "name")
+
+ if not acc_name:
+ acc = frappe.get_doc({
+ "doctype": "Account",
+ "parent_account": "1 - Forderungen aus Lieferungen und Leistungen - _TG",
+ "account_name": customer_name,
+ "company": company.name,
+ "account_type": "Receivable",
+ "account_number": "10001"
+ })
+ acc.insert()
+ acc_name = acc.name
+
+ if not frappe.db.exists("Customer", customer_name):
+ customer = frappe.get_doc({
+ "doctype": "Customer",
+ "customer_name": customer_name,
+ "customer_type": "Company",
+ "accounts": [{
+ "company": company.name,
+ "account": acc_name
+ }]
+ })
+ customer.insert()
+ else:
+ customer = frappe.get_doc("Customer", customer_name)
+
+ return customer
+
+def make_item(item_code, company):
+ warehouse_name = frappe.db.get_value("Warehouse", {
+ "warehouse_name": "Stores",
+ "company": company.name
+ }, "name")
+
+ if not frappe.db.exists("Item", item_code):
+ item = frappe.get_doc({
+ "doctype": "Item",
+ "item_code": item_code,
+ "item_name": item_code,
+ "description": item_code,
+ "item_group": "All Item Groups",
+ "is_stock_item": 0,
+ "is_purchase_item": 0,
+ "is_customer_provided_item": 0,
+ "item_defaults": [{
+ "default_warehouse": warehouse_name,
+ "company": company.name
+ }]
+ })
+ item.insert()
+ else:
+ item = frappe.get_doc("Item", item_code)
+ return item
+
+def make_datev_settings(company):
+ if not frappe.db.exists("DATEV Settings", company.name):
+ frappe.get_doc({
+ "doctype": "DATEV Settings",
+ "client": company.name,
+ "client_number": "12345",
+ "consultant_number": "67890"
+ }).insert()
+
+
+class TestDatev(TestCase):
+ def setUp(self):
+ self.company = make_company("_Test GmbH", "_TG")
+ self.customer = make_customer_with_account("_Test Kunde GmbH", self.company)
+ self.filters = {
+ "company": self.company.name,
+ "from_date": today(),
+ "to_date": today()
+ }
+
+ make_datev_settings(self.company)
+ item = make_item("_Test Item", self.company)
+ setup_fiscal_year()
+
+ warehouse = frappe.db.get_value("Item Default", {
+ "parent": item.name,
+ "company": self.company.name
+ }, "default_warehouse")
+
+ income_account = frappe.db.get_value("Account", {
+ "account_number": "4200",
+ "company": self.company.name
+ }, "name")
+
+ tax_account = frappe.db.get_value("Account", {
+ "account_number": "3806",
+ "company": self.company.name
+ }, "name")
+
+ si = create_sales_invoice(
+ company=self.company.name,
+ customer=self.customer.name,
+ currency=self.company.default_currency,
+ debit_to=self.customer.accounts[0].account,
+ income_account="4200 - Erlöse - _TG",
+ expense_account="6990 - Herstellungskosten - _TG",
+ cost_center=self.company.cost_center,
+ warehouse=warehouse,
+ item=item.name,
+ do_not_save=1
+ )
+
+ si.append("taxes", {
+ "charge_type": "On Net Total",
+ "account_head": tax_account,
+ "description": "Umsatzsteuer 19 %",
+ "rate": 19
+ })
+
+ si.save()
+ si.submit()
+
+ def test_columns(self):
+ def is_subset(get_data, allowed_keys):
+ """
+ Validate that the dict contains only allowed keys.
+
+ Params:
+ get_data -- Function that returns a list of dicts.
+ allowed_keys -- List of allowed keys
+ """
+ data = get_data(self.filters)
+ if data == []:
+ # No data and, therefore, no columns is okay
+ return True
+ actual_set = set(data[0].keys())
+ # allowed set must be interpreted as unicode to match the actual set
+ allowed_set = set({frappe.as_unicode(key) for key in allowed_keys})
+ return actual_set.issubset(allowed_set)
+
+ self.assertTrue(is_subset(get_transactions, Transactions.COLUMNS))
+ self.assertTrue(is_subset(get_customers, DebtorsCreditors.COLUMNS))
+ self.assertTrue(is_subset(get_suppliers, DebtorsCreditors.COLUMNS))
+ self.assertTrue(is_subset(get_account_names, AccountNames.COLUMNS))
+
+ def test_header(self):
+ self.assertTrue(Transactions.DATA_CATEGORY in get_header(self.filters, Transactions))
+ self.assertTrue(AccountNames.DATA_CATEGORY in get_header(self.filters, AccountNames))
+ self.assertTrue(DebtorsCreditors.DATA_CATEGORY in get_header(self.filters, DebtorsCreditors))
+
+ def test_csv(self):
+ test_data = [{
+ "Umsatz (ohne Soll/Haben-Kz)": 100,
+ "Soll/Haben-Kennzeichen": "H",
+ "Kontonummer": "4200",
+ "Gegenkonto (ohne BU-Schlüssel)": "10000",
+ "Belegdatum": today(),
+ "Buchungstext": "No remark",
+ "Beleginfo - Art 1": "Sales Invoice",
+ "Beleginfo - Inhalt 1": "SINV-0001"
+ }]
+ get_datev_csv(data=test_data, filters=self.filters, csv_class=Transactions)
+
+ def test_download(self):
+ """Assert that the returned file is a ZIP file."""
+ download_datev_csv(self.filters)
+
+ # zipfile.is_zipfile() expects a file-like object
+ zip_buffer = BytesIO()
+ zip_buffer.write(frappe.response['filecontent'])
+
+ self.assertTrue(zipfile.is_zipfile(zip_buffer))
diff --git a/erpnext/regional/report/gstr_1/gstr_1.js b/erpnext/regional/report/gstr_1/gstr_1.js
index 9682768..1a7ff2b 100644
--- a/erpnext/regional/report/gstr_1/gstr_1.js
+++ b/erpnext/regional/report/gstr_1/gstr_1.js
@@ -52,17 +52,28 @@
],
onload: function (report) {
- report.page.add_inner_button(__("Download as Json"), function () {
+ report.page.add_inner_button(__("Download as JSON"), function () {
var filters = report.get_values();
- const args = {
- cmd: 'erpnext.regional.report.gstr_1.gstr_1.get_json',
- data: report.data,
- report_name: report.report_name,
- filters: filters
- };
-
- open_url_post(frappe.request.url, args);
+ frappe.call({
+ method: 'erpnext.regional.report.gstr_1.gstr_1.get_json',
+ args: {
+ data: report.data,
+ report_name: report.report_name,
+ filters: filters
+ },
+ callback: function(r) {
+ if (r.message) {
+ const args = {
+ cmd: 'erpnext.regional.report.gstr_1.gstr_1.download_json_file',
+ data: r.message.data,
+ report_name: r.message.report_name,
+ report_type: r.message.report_type
+ };
+ open_url_post(frappe.request.url, args);
+ }
+ }
+ });
});
}
}
diff --git a/erpnext/regional/report/gstr_1/gstr_1.py b/erpnext/regional/report/gstr_1/gstr_1.py
index 922619c..4f9cc7f 100644
--- a/erpnext/regional/report/gstr_1/gstr_1.py
+++ b/erpnext/regional/report/gstr_1/gstr_1.py
@@ -116,7 +116,7 @@
taxable_value = 0
for item_code, net_amount in self.invoice_items.get(invoice).items():
if item_code in items:
- if self.item_tax_rate.get(invoice) and tax_rate in self.item_tax_rate.get(invoice, {}).get(item_code):
+ if self.item_tax_rate.get(invoice) and tax_rate in self.item_tax_rate.get(invoice, {}).get(item_code, []):
taxable_value += abs(net_amount)
elif not self.item_tax_rate.get(invoice):
taxable_value += abs(net_amount)
@@ -532,16 +532,9 @@
self.columns = self.invoice_columns + self.tax_columns + self.other_columns
@frappe.whitelist()
-def get_json():
- data = frappe._dict(frappe.local.form_dict)
-
- del data["cmd"]
- if "csrf_token" in data:
- del data["csrf_token"]
-
- filters = json.loads(data["filters"])
- report_data = json.loads(data["data"])
- report_name = data["report_name"]
+def get_json(filters, report_name, data):
+ filters = json.loads(filters)
+ report_data = json.loads(data)
gstin = get_company_gstin_number(filters["company"])
fp = "%02d%s" % (getdate(filters["to_date"]).month, getdate(filters["to_date"]).year)
@@ -575,7 +568,11 @@
out = get_export_json(res)
gst_json["exp"] = out
- download_json_file(report_name, filters["type_of_business"], gst_json)
+ return {
+ 'report_name': report_name,
+ 'report_type': filters['type_of_business'],
+ 'data': gst_json
+ }
def get_b2b_json(res, gstin):
inv_type, out = {"Registered Regular": "R", "Deemed Export": "DE", "URD": "URD", "SEZ": "SEZ"}, []
@@ -722,11 +719,15 @@
if gstin:
return gstin[0]["gstin"]
else:
- frappe.throw(_("Please set valid GSTIN No. in Company Address"))
+ frappe.throw(_("Please set valid GSTIN No. in Company Address for company {0}".format(
+ frappe.bold(company)
+ )))
-def download_json_file(filename, report_type, data):
+@frappe.whitelist()
+def download_json_file():
''' download json content in a file '''
- frappe.response['filename'] = frappe.scrub("{0} {1}".format(filename, report_type)) + '.json'
- frappe.response['filecontent'] = json.dumps(data)
+ data = frappe._dict(frappe.local.form_dict)
+ frappe.response['filename'] = frappe.scrub("{0} {1}".format(data['report_name'], data['report_type'])) + '.json'
+ frappe.response['filecontent'] = data['data']
frappe.response['content_type'] = 'application/json'
frappe.response['type'] = 'download'
diff --git a/erpnext/regional/report/gstr_2/gstr_2.py b/erpnext/regional/report/gstr_2/gstr_2.py
index a362269..f326fe0 100644
--- a/erpnext/regional/report/gstr_2/gstr_2.py
+++ b/erpnext/regional/report/gstr_2/gstr_2.py
@@ -44,12 +44,16 @@
for inv, items_based_on_rate in self.items_based_on_tax_rate.items():
invoice_details = self.invoices.get(inv)
for rate, items in items_based_on_rate.items():
- row, taxable_value = self.get_row_data_for_invoice(inv, invoice_details, rate, items)
- tax_amount = taxable_value * rate / 100
- if inv in self.igst_invoices:
- row += [tax_amount, 0, 0]
+ if inv not in self.igst_invoices:
+ rate = rate / 2
+ row, taxable_value = self.get_row_data_for_invoice(inv, invoice_details, rate, items)
+ tax_amount = taxable_value * rate / 100
+ row += [0, tax_amount, tax_amount]
else:
- row += [0, tax_amount / 2, tax_amount / 2]
+ row, taxable_value = self.get_row_data_for_invoice(inv, invoice_details, rate, items)
+ tax_amount = taxable_value * rate / 100
+ row += [tax_amount, 0, 0]
+
row += [
self.invoice_cess.get(inv),
diff --git a/erpnext/assets/doctype/asset_settings/__init__.py b/erpnext/regional/turkey/__init__.py
similarity index 100%
copy from erpnext/assets/doctype/asset_settings/__init__.py
copy to erpnext/regional/turkey/__init__.py
diff --git a/erpnext/selling/doctype/customer/customer.js b/erpnext/selling/doctype/customer/customer.js
index 458a56c..aa1b92f 100644
--- a/erpnext/selling/doctype/customer/customer.js
+++ b/erpnext/selling/doctype/customer/customer.js
@@ -5,13 +5,13 @@
setup: function(frm) {
frm.make_methods = {
- 'Quotation': () => erpnext.utils.create_new_doc('Quotation', {
- 'quotation_to': frm.doc.doctype,
- 'party_name': frm.doc.name
+ 'Quotation': () => frappe.model.open_mapped_doc({
+ method: "erpnext.selling.doctype.customer.customer.make_quotation",
+ frm: cur_frm
}),
- 'Opportunity': () => erpnext.utils.create_new_doc('Opportunity', {
- 'opportunity_from': frm.doc.doctype,
- 'party_name': frm.doc.name
+ 'Opportunity': () => frappe.model.open_mapped_doc({
+ method: "erpnext.selling.doctype.customer.customer.make_opportunity",
+ frm: cur_frm
})
}
@@ -49,9 +49,9 @@
})
frm.set_query('customer_primary_address', function(doc) {
return {
- query: "erpnext.selling.doctype.customer.customer.get_customer_primary_address",
filters: {
- 'customer': doc.name
+ 'link_doctype': 'Customer',
+ 'link_name': doc.name
}
}
})
diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py
index a8e3ce4..136236c 100644
--- a/erpnext/selling/doctype/customer/customer.py
+++ b/erpnext/selling/doctype/customer/customer.py
@@ -12,6 +12,7 @@
from erpnext.accounts.party import validate_party_accounts, get_dashboard_info, get_timeline_data # keep this
from frappe.contacts.address_and_contact import load_address_and_contact, delete_contact_and_address
from frappe.model.rename_doc import update_linked_doctypes
+from frappe.model.mapper import get_mapped_doc
class Customer(TransactionBase):
def get_feed(self):
@@ -204,6 +205,100 @@
else:
frappe.msgprint(_("Multiple Loyalty Program found for the Customer. Please select manually."))
+ def create_onboarding_docs(self, args):
+ defaults = frappe.defaults.get_defaults()
+ for i in range(1, args.get('max_count')):
+ customer = args.get('customer_name_' + str(i))
+ if customer:
+ try:
+ doc = frappe.get_doc({
+ 'doctype': self.doctype,
+ 'customer_name': customer,
+ 'customer_type': 'Company',
+ 'customer_group': _('Commercial'),
+ 'territory': defaults.get('country'),
+ 'company': defaults.get('company')
+ }).insert()
+
+ if args.get('customer_email_' + str(i)):
+ create_contact(customer, self.doctype,
+ doc.name, args.get("customer_email_" + str(i)))
+ except frappe.NameError:
+ pass
+
+def create_contact(contact, party_type, party, email):
+ """Create contact based on given contact name"""
+ contact = contact.split(' ')
+
+ contact = frappe.get_doc({
+ 'doctype': 'Contact',
+ 'first_name': contact[0],
+ 'last_name': len(contact) > 1 and contact[1] or ""
+ })
+ contact.append('email_ids', dict(email_id=email, is_primary=1))
+ contact.append('links', dict(link_doctype=party_type, link_name=party))
+ contact.insert()
+
+@frappe.whitelist()
+def make_quotation(source_name, target_doc=None):
+
+ def set_missing_values(source, target):
+ _set_missing_values(source, target)
+
+ target_doc = get_mapped_doc("Customer", source_name,
+ {"Customer": {
+ "doctype": "Quotation",
+ "field_map": {
+ "name":"party_name"
+ }
+ }}, target_doc, set_missing_values)
+
+ target_doc.quotation_to = "Customer"
+ target_doc.run_method("set_missing_values")
+ target_doc.run_method("set_other_charges")
+ target_doc.run_method("calculate_taxes_and_totals")
+
+ price_list = frappe.get_value("Customer", source_name, 'default_price_list')
+ if price_list:
+ target_doc.selling_price_list = price_list
+
+ return target_doc
+
+@frappe.whitelist()
+def make_opportunity(source_name, target_doc=None):
+ def set_missing_values(source, target):
+ _set_missing_values(source, target)
+
+ target_doc = get_mapped_doc("Customer", source_name,
+ {"Customer": {
+ "doctype": "Opportunity",
+ "field_map": {
+ "name": "party_name",
+ "doctype": "opportunity_from",
+ }
+ }}, target_doc, set_missing_values)
+
+ return target_doc
+
+def _set_missing_values(source, target):
+ address = frappe.get_all('Dynamic Link', {
+ 'link_doctype': source.doctype,
+ 'link_name': source.name,
+ 'parenttype': 'Address',
+ }, ['parent'], limit=1)
+
+ contact = frappe.get_all('Dynamic Link', {
+ 'link_doctype': source.doctype,
+ 'link_name': source.name,
+ 'parenttype': 'Contact',
+ }, ['parent'], limit=1)
+
+ if address:
+ target.customer_address = address[0].parent
+
+ if contact:
+ target.contact_person = contact[0].parent
+
@frappe.whitelist()
def get_loyalty_programs(doc):
''' returns applicable loyalty programs for a customer '''
@@ -397,15 +492,3 @@
'customer': customer,
'txt': '%%%s%%' % txt
})
-
-def get_customer_primary_address(doctype, txt, searchfield, start, page_len, filters):
- customer = frappe.db.escape(filters.get('customer'))
- return frappe.db.sql("""
- select `tabAddress`.name from `tabAddress`, `tabDynamic Link`
- where `tabAddress`.name = `tabDynamic Link`.parent and `tabDynamic Link`.link_name = %(customer)s
- and `tabDynamic Link`.link_doctype = 'Customer'
- and `tabAddress`.name like %(txt)s
- """, {
- 'customer': customer,
- 'txt': '%%%s%%' % txt
- })
diff --git a/erpnext/selling/doctype/customer_credit_limit/customer_credit_limit.json b/erpnext/selling/doctype/customer_credit_limit/customer_credit_limit.json
index c28021c..800cb57 100644
--- a/erpnext/selling/doctype/customer_credit_limit/customer_credit_limit.json
+++ b/erpnext/selling/doctype/customer_credit_limit/customer_credit_limit.json
@@ -1,4 +1,5 @@
{
+ "actions": [],
"creation": "2019-08-28 17:29:42.115592",
"doctype": "DocType",
"editable_grid": 1,
@@ -34,11 +35,12 @@
"fieldname": "bypass_credit_limit_check",
"fieldtype": "Check",
"in_list_view": 1,
- "label": "Bypass Credit Limit Check"
+ "label": "Bypass Credit Limit Check at Sales Order"
}
],
"istable": 1,
- "modified": "2019-09-24 15:05:26.069911",
+ "links": [],
+ "modified": "2019-12-31 15:43:05.822328",
"modified_by": "Administrator",
"module": "Selling",
"name": "Customer Credit Limit",
diff --git a/erpnext/selling/doctype/quotation/quotation.json b/erpnext/selling/doctype/quotation/quotation.json
index ea04715..8e21927 100644
--- a/erpnext/selling/doctype/quotation/quotation.json
+++ b/erpnext/selling/doctype/quotation/quotation.json
@@ -1,3509 +1,1029 @@
{
- "allow_copy": 0,
- "allow_events_in_timeline": 0,
- "allow_guest_to_view": 0,
- "allow_import": 1,
- "allow_rename": 0,
- "autoname": "naming_series:",
- "beta": 0,
- "creation": "2013-05-24 19:29:08",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "Document",
- "editable_grid": 1,
- "fields": [
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "customer_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": "",
- "length": 0,
- "no_copy": 0,
- "options": "fa fa-user",
- "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
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "{customer_name}",
- "fieldname": "title",
- "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": "Title",
- "length": 0,
- "no_copy": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "",
- "fieldname": "naming_series",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Series",
- "length": 0,
- "no_copy": 1,
- "oldfieldname": "naming_series",
- "oldfieldtype": "Select",
- "options": "SAL-QTN-.YYYY.-",
- "permlevel": 0,
- "print_hide": 1,
- "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": 1,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "Customer",
- "fetch_if_empty": 0,
- "fieldname": "quotation_to",
- "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": 1,
- "label": "Quotation To",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "quotation_to",
- "oldfieldtype": "Select",
- "options": "DocType",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 1,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
- "fetch_if_empty": 0,
- "fieldname": "party_name",
- "fieldtype": "Dynamic Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 1,
- "in_list_view": 0,
- "in_standard_filter": 1,
- "label": "Party",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "customer",
- "oldfieldtype": "Link",
- "options": "quotation_to",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 1,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 1,
- "collapsible": 0,
- "columns": 0,
- "fetch_from": "",
- "fieldname": "customer_name",
- "fieldtype": "Data",
- "hidden": 1,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 1,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Customer Name",
- "length": 0,
- "no_copy": 0,
- "options": "",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break1",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "oldfieldtype": "Column Break",
- "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,
- "width": "50%"
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "amended_from",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 1,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Amended From",
- "length": 0,
- "no_copy": 1,
- "oldfieldname": "amended_from",
- "oldfieldtype": "Data",
- "options": "Quotation",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
- "width": "150px"
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "",
- "fieldname": "company",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Company",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "company",
- "oldfieldtype": "Link",
- "options": "Company",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 1,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
- "width": "150px"
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "Today",
- "fieldname": "transaction_date",
- "fieldtype": "Date",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 1,
- "label": "Date",
- "length": 0,
- "no_copy": 1,
- "oldfieldname": "transaction_date",
- "oldfieldtype": "Date",
- "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": 1,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
- "width": "100px"
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "valid_till",
- "fieldtype": "Date",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Valid Till",
- "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
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "Sales",
- "fieldname": "order_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": "Order Type",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "order_type",
- "oldfieldtype": "Select",
- "options": "\nSales\nMaintenance\nShopping Cart",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "collapsible_depends_on": "",
- "columns": 0,
- "depends_on": "party_name",
- "fieldname": "contact_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": "Address and Contact",
- "length": 0,
- "no_copy": 0,
- "options": "fa fa-bullhorn",
- "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
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "customer_address",
- "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": "Customer Address",
- "length": 0,
- "no_copy": 0,
- "options": "Address",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "address_display",
- "fieldtype": "Small Text",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Address",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "customer_address",
- "oldfieldtype": "Small Text",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
- "fieldname": "contact_person",
- "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": "Contact Person",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "contact_person",
- "oldfieldtype": "Link",
- "options": "Contact",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "contact_display",
- "fieldtype": "Small Text",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 1,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Contact",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "contact_mobile",
- "fieldtype": "Small Text",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Mobile No",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "contact_email",
- "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": "Contact Email",
- "length": 0,
- "no_copy": 0,
- "options": "Email",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:doc.quotaion_to=='Customer' && doc.party_name",
- "fieldname": "col_break98",
- "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,
- "width": "50%"
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "shipping_address_name",
- "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": "Shipping Address",
- "length": 0,
- "no_copy": 0,
- "options": "Address",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "shipping_address",
- "fieldtype": "Small Text",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Shipping Address",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:doc.quotaion_to=='Customer' && doc.party_name",
- "description": "",
- "fieldname": "customer_group",
- "fieldtype": "Link",
- "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": "Customer Group",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "customer_group",
- "oldfieldtype": "Link",
- "options": "Customer Group",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "",
- "fieldname": "territory",
- "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": "Territory",
- "length": 0,
- "no_copy": 0,
- "options": "Territory",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "columns": 0,
- "fieldname": "currency_and_price_list",
- "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": "Currency and Price List",
- "length": 0,
- "no_copy": 0,
- "options": "fa fa-tag",
- "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
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "currency",
- "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": "Currency",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "currency",
- "oldfieldtype": "Select",
- "options": "Currency",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
- "width": "100px"
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "Rate at which customer's currency is converted to company's base currency",
- "fieldname": "conversion_rate",
- "fieldtype": "Float",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Exchange Rate",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "conversion_rate",
- "oldfieldtype": "Currency",
- "permlevel": 0,
- "precision": "9",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
- "width": "100px"
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break2",
- "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,
- "width": "50%"
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "selling_price_list",
- "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": "Price List",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "price_list_name",
- "oldfieldtype": "Select",
- "options": "Price List",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
- "width": "100px"
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "price_list_currency",
- "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": "Price List Currency",
- "length": 0,
- "no_copy": 0,
- "options": "Currency",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "Rate at which Price list currency is converted to company's base currency",
- "fieldname": "plc_conversion_rate",
- "fieldtype": "Float",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Price List Exchange Rate",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "9",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "ignore_pricing_rule",
- "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": "Ignore Pricing Rule",
- "length": 0,
- "no_copy": 1,
- "permlevel": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "items_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": "",
- "length": 0,
- "no_copy": 0,
- "oldfieldtype": "Section Break",
- "options": "fa fa-shopping-cart",
- "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
- },
- {
- "allow_bulk_edit": 1,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "items",
- "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": "Items",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "quotation_details",
- "oldfieldtype": "Table",
- "options": "Quotation Item",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
- "width": "40px"
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "pricing_rule_details",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Pricing Rules",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "pricing_rules",
- "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": "Pricing Rule Detail",
- "length": 0,
- "no_copy": 0,
- "options": "Pricing Rule Detail",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "sec_break23",
- "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,
- "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": "total_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": "Total Quantity",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "base_total",
- "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": "Total (Company Currency)",
- "length": 0,
- "no_copy": 0,
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "base_net_total",
- "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": "Net Total (Company Currency)",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "net_total",
- "oldfieldtype": "Currency",
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
- "width": "100px"
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_28",
- "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
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "total",
- "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": "Total",
- "length": 0,
- "no_copy": 0,
- "options": "currency",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "net_total",
- "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": "Net Total",
- "length": 0,
- "no_copy": 0,
- "options": "currency",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "total_net_weight",
- "fieldtype": "Float",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Total Net Weight",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "taxes_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": "Taxes and Charges",
- "length": 0,
- "no_copy": 0,
- "oldfieldtype": "Section Break",
- "options": "fa fa-money",
- "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
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "tax_category",
- "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": "Tax Category",
- "length": 0,
- "no_copy": 0,
- "options": "Tax Category",
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_34",
- "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
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "shipping_rule",
- "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": "Shipping Rule",
- "length": 0,
- "no_copy": 0,
- "oldfieldtype": "Button",
- "options": "Shipping Rule",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "section_break_36",
- "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,
- "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": "taxes_and_charges",
- "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": "Sales Taxes and Charges Template",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "charge",
- "oldfieldtype": "Link",
- "options": "Sales Taxes and Charges Template",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "taxes",
- "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": "Sales Taxes and Charges",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "other_charges",
- "oldfieldtype": "Table",
- "options": "Sales Taxes and Charges",
- "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
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "columns": 0,
- "fieldname": "sec_tax_breakup",
- "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": "Tax Breakup",
- "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
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "other_charges_calculation",
- "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": "Taxes and Charges Calculation",
- "length": 0,
- "no_copy": 1,
- "oldfieldtype": "HTML",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "section_break_39",
- "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,
- "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": "base_total_taxes_and_charges",
- "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": "Total Taxes and Charges (Company Currency)",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "other_charges_total",
- "oldfieldtype": "Currency",
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_42",
- "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
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "total_taxes_and_charges",
- "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": "Total Taxes and Charges",
- "length": 0,
- "no_copy": 0,
- "options": "currency",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "collapsible_depends_on": "discount_amount",
- "columns": 0,
- "fieldname": "section_break_44",
- "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": "Additional Discount and Coupon Code",
- "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
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "coupon_code",
- "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": "Coupon Code",
- "length": 0,
- "no_copy": 0,
- "options": "Coupon Code",
- "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
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "referral_sales_partner",
- "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": "Referral Sales Partner",
- "length": 0,
- "no_copy": 0,
- "options": "Sales Partner",
- "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
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "Grand Total",
- "fieldname": "apply_discount_on",
- "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": "Apply Additional Discount On",
- "length": 0,
- "no_copy": 0,
- "options": "\nGrand Total\nNet Total",
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "base_discount_amount",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Additional Discount Amount (Company Currency)",
- "length": 0,
- "no_copy": 0,
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_46",
- "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
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "additional_discount_percentage",
- "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": "Additional Discount Percentage",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "discount_amount",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Additional Discount Amount",
- "length": 0,
- "no_copy": 0,
- "options": "currency",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "totals",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "",
- "length": 0,
- "no_copy": 0,
- "oldfieldtype": "Section Break",
- "options": "fa fa-money",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "base_grand_total",
- "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": "Grand Total (Company Currency)",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "grand_total",
- "oldfieldtype": "Currency",
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
- "width": "200px"
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "base_rounding_adjustment",
- "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": "Rounding Adjustment (Company Currency)",
- "length": 0,
- "no_copy": 1,
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "In Words will be visible once you save the Quotation.",
- "fieldname": "base_in_words",
- "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": "In Words (Company Currency)",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "in_words",
- "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,
- "translatable": 0,
- "unique": 0,
- "width": "200px"
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "base_rounded_total",
- "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": "Rounded Total (Company Currency)",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "rounded_total",
- "oldfieldtype": "Currency",
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
- "width": "200px"
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break3",
- "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,
- "oldfieldtype": "Column Break",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0,
- "width": "50%"
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "grand_total",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Grand Total",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "grand_total_export",
- "oldfieldtype": "Currency",
- "options": "currency",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
- "width": "200px"
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "rounding_adjustment",
- "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": "Rounding Adjustment",
- "length": 0,
- "no_copy": 1,
- "options": "currency",
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 1,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "rounded_total",
- "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": "Rounded Total",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "rounded_total_export",
- "oldfieldtype": "Currency",
- "options": "currency",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
- "width": "200px"
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "in_words",
- "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": "In Words",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "in_words_export",
- "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,
- "translatable": 0,
- "unique": 0,
- "width": "200px"
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "collapsible_depends_on": "",
- "columns": 0,
- "depends_on": "",
- "fieldname": "payment_schedule_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": "Payment Terms",
- "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
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "payment_terms_template",
- "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": "Payment Terms Template",
- "length": 0,
- "no_copy": 0,
- "options": "Payment Terms Template",
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "payment_schedule",
- "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": "Payment Schedule",
- "length": 0,
- "no_copy": 1,
- "options": "Payment Schedule",
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "collapsible_depends_on": "terms",
- "columns": 0,
- "fieldname": "terms_section_break",
- "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": "Terms and Conditions",
- "length": 0,
- "no_copy": 0,
- "oldfieldtype": "Section Break",
- "options": "fa fa-legal",
- "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
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "tc_name",
- "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": "Terms",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "tc_name",
- "oldfieldtype": "Link",
- "options": "Terms and Conditions",
- "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
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "terms",
- "fieldtype": "Text Editor",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Term Details",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "terms",
- "oldfieldtype": "Text Editor",
- "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
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "columns": 0,
- "fieldname": "print_settings",
- "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": "Print Settings",
- "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
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "letter_head",
- "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": "Letter Head",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "letter_head",
- "oldfieldtype": "Select",
- "options": "Letter Head",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "group_same_items",
- "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": "Group same items",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_73",
- "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
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "select_print_heading",
- "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": "Print Heading",
- "length": 0,
- "no_copy": 1,
- "oldfieldname": "select_print_heading",
- "oldfieldtype": "Link",
- "options": "Print Heading",
- "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
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "language",
- "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": "Print Language",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "subscription_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": "Auto Repeat Section",
- "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
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "auto_repeat",
- "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": "Auto Repeat",
- "length": 0,
- "no_copy": 1,
- "options": "Auto Repeat",
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval: doc.auto_repeat",
- "fieldname": "update_auto_repeat_reference",
- "fieldtype": "Button",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Update Auto Repeat Reference",
- "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
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "columns": 0,
- "fieldname": "more_info",
- "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": "More Information",
- "length": 0,
- "no_copy": 0,
- "oldfieldtype": "Section Break",
- "options": "fa fa-file-text",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "campaign",
- "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": "Campaign",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "campaign",
- "oldfieldtype": "Link",
- "options": "Campaign",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "source",
- "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": "Source",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "source",
- "oldfieldtype": "Select",
- "options": "Lead Source",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:doc.status===\"Lost\"",
- "fieldname": "order_lost_reason",
- "fieldtype": "Small Text",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Detailed Reason",
- "length": 0,
- "no_copy": 1,
- "oldfieldname": "order_lost_reason",
- "oldfieldtype": "Small Text",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break4",
- "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,
- "oldfieldtype": "Column Break",
- "permlevel": 0,
- "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,
- "translatable": 0,
- "unique": 0,
- "width": "50%"
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "Draft",
- "fieldname": "status",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Status",
- "length": 0,
- "no_copy": 1,
- "oldfieldname": "status",
- "oldfieldtype": "Select",
- "options": "Draft\nOpen\nReplied\nOrdered\nLost\nCancelled",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "enq_det",
- "fieldtype": "Text",
- "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": "Opportunity Item",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "enq_det",
- "oldfieldtype": "Text",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "supplier_quotation",
- "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": "Supplier Quotation",
- "length": 0,
- "no_copy": 0,
- "options": "Supplier Quotation",
- "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
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "opportunity",
- "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": "Opportunity",
- "length": 0,
- "no_copy": 0,
- "options": "Opportunity",
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "lost_reasons",
- "fieldtype": "Table MultiSelect",
- "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": "Lost Reasons",
- "length": 0,
- "no_copy": 0,
- "options": "Lost Reason Detail",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- }
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "icon": "fa fa-shopping-cart",
- "idx": 82,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 1,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 1,
- "menu_index": 0,
- "modified": "2019-10-14 01:00:21.545591",
- "modified_by": "Administrator",
- "module": "Selling",
- "name": "Quotation",
- "owner": "Administrator",
- "permissions": [
- {
- "amend": 1,
- "cancel": 1,
- "create": 1,
- "delete": 1,
- "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": 1,
- "submit": 1,
- "write": 1
- },
- {
- "amend": 0,
- "cancel": 0,
- "create": 0,
- "delete": 0,
- "email": 0,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "match": "",
- "permlevel": 1,
- "print": 0,
- "read": 1,
- "report": 1,
- "role": "Sales User",
- "set_user_permissions": 0,
- "share": 0,
- "submit": 0,
- "write": 0
- },
- {
- "amend": 0,
- "cancel": 0,
- "create": 0,
- "delete": 0,
- "email": 0,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "match": "",
- "permlevel": 1,
- "print": 0,
- "read": 1,
- "report": 1,
- "role": "Sales Manager",
- "set_user_permissions": 0,
- "share": 0,
- "submit": 0,
- "write": 1
- },
- {
- "amend": 1,
- "cancel": 1,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "if_owner": 0,
- "import": 1,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Sales Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 1,
- "write": 1
- },
- {
- "amend": 1,
- "cancel": 1,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Maintenance Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 1,
- "write": 1
- },
- {
- "amend": 0,
- "cancel": 0,
- "create": 0,
- "delete": 0,
- "email": 0,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "match": "",
- "permlevel": 1,
- "print": 0,
- "read": 1,
- "report": 1,
- "role": "Maintenance Manager",
- "set_user_permissions": 0,
- "share": 0,
- "submit": 0,
- "write": 0
- },
- {
- "amend": 1,
- "cancel": 1,
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Maintenance User",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 1,
- "write": 1
- },
- {
- "amend": 0,
- "cancel": 0,
- "create": 0,
- "delete": 0,
- "email": 0,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "match": "",
- "permlevel": 1,
- "print": 0,
- "read": 1,
- "report": 1,
- "role": "Maintenance User",
- "set_user_permissions": 0,
- "share": 0,
- "submit": 0,
- "write": 0
- }
- ],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 1,
- "search_fields": "status,transaction_date,party_name,order_type",
- "show_name_in_global_search": 1,
- "sort_field": "modified",
- "sort_order": "DESC",
- "timeline_field": "party_name",
- "title_field": "title",
- "track_changes": 0,
- "track_seen": 0,
- "track_views": 0
+ "actions": [],
+ "allow_import": 1,
+ "autoname": "naming_series:",
+ "creation": "2013-05-24 19:29:08",
+ "doctype": "DocType",
+ "document_type": "Document",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "customer_section",
+ "title",
+ "naming_series",
+ "quotation_to",
+ "party_name",
+ "customer_name",
+ "column_break1",
+ "amended_from",
+ "company",
+ "transaction_date",
+ "valid_till",
+ "order_type",
+ "contact_section",
+ "customer_address",
+ "address_display",
+ "contact_person",
+ "contact_display",
+ "contact_mobile",
+ "contact_email",
+ "col_break98",
+ "shipping_address_name",
+ "shipping_address",
+ "customer_group",
+ "territory",
+ "currency_and_price_list",
+ "currency",
+ "conversion_rate",
+ "column_break2",
+ "selling_price_list",
+ "price_list_currency",
+ "plc_conversion_rate",
+ "ignore_pricing_rule",
+ "items_section",
+ "items",
+ "pricing_rule_details",
+ "pricing_rules",
+ "sec_break23",
+ "total_qty",
+ "base_total",
+ "base_net_total",
+ "column_break_28",
+ "total",
+ "net_total",
+ "total_net_weight",
+ "taxes_section",
+ "tax_category",
+ "column_break_34",
+ "shipping_rule",
+ "section_break_36",
+ "taxes_and_charges",
+ "taxes",
+ "sec_tax_breakup",
+ "other_charges_calculation",
+ "section_break_39",
+ "base_total_taxes_and_charges",
+ "column_break_42",
+ "total_taxes_and_charges",
+ "section_break_44",
+ "coupon_code",
+ "referral_sales_partner",
+ "apply_discount_on",
+ "base_discount_amount",
+ "column_break_46",
+ "additional_discount_percentage",
+ "discount_amount",
+ "totals",
+ "base_grand_total",
+ "base_rounding_adjustment",
+ "base_in_words",
+ "base_rounded_total",
+ "column_break3",
+ "grand_total",
+ "rounding_adjustment",
+ "rounded_total",
+ "in_words",
+ "payment_schedule_section",
+ "payment_terms_template",
+ "payment_schedule",
+ "terms_section_break",
+ "tc_name",
+ "terms",
+ "print_settings",
+ "letter_head",
+ "group_same_items",
+ "column_break_73",
+ "select_print_heading",
+ "language",
+ "subscription_section",
+ "auto_repeat",
+ "update_auto_repeat_reference",
+ "more_info",
+ "campaign",
+ "source",
+ "order_lost_reason",
+ "column_break4",
+ "status",
+ "enq_det",
+ "supplier_quotation",
+ "opportunity",
+ "lost_reasons"
+ ],
+ "fields": [
+ {
+ "fieldname": "customer_section",
+ "fieldtype": "Section Break",
+ "options": "fa fa-user"
+ },
+ {
+ "allow_on_submit": 1,
+ "default": "{customer_name}",
+ "fieldname": "title",
+ "fieldtype": "Data",
+ "hidden": 1,
+ "label": "Title",
+ "no_copy": 1,
+ "print_hide": 1
+ },
+ {
+ "fieldname": "naming_series",
+ "fieldtype": "Select",
+ "label": "Series",
+ "no_copy": 1,
+ "oldfieldname": "naming_series",
+ "oldfieldtype": "Select",
+ "options": "SAL-QTN-.YYYY.-",
+ "print_hide": 1,
+ "reqd": 1,
+ "set_only_once": 1
+ },
+ {
+ "default": "Customer",
+ "fieldname": "quotation_to",
+ "fieldtype": "Link",
+ "in_standard_filter": 1,
+ "label": "Quotation To",
+ "oldfieldname": "quotation_to",
+ "oldfieldtype": "Select",
+ "options": "DocType",
+ "print_hide": 1,
+ "reqd": 1
+ },
+ {
+ "bold": 1,
+ "fieldname": "party_name",
+ "fieldtype": "Dynamic Link",
+ "in_global_search": 1,
+ "in_standard_filter": 1,
+ "label": "Party",
+ "oldfieldname": "customer",
+ "oldfieldtype": "Link",
+ "options": "quotation_to",
+ "print_hide": 1,
+ "search_index": 1
+ },
+ {
+ "bold": 1,
+ "fieldname": "customer_name",
+ "fieldtype": "Data",
+ "hidden": 1,
+ "in_global_search": 1,
+ "label": "Customer Name",
+ "read_only": 1
+ },
+ {
+ "fieldname": "column_break1",
+ "fieldtype": "Column Break",
+ "oldfieldtype": "Column Break",
+ "width": "50%"
+ },
+ {
+ "fieldname": "amended_from",
+ "fieldtype": "Link",
+ "ignore_user_permissions": 1,
+ "label": "Amended From",
+ "no_copy": 1,
+ "oldfieldname": "amended_from",
+ "oldfieldtype": "Data",
+ "options": "Quotation",
+ "print_hide": 1,
+ "read_only": 1,
+ "width": "150px"
+ },
+ {
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "label": "Company",
+ "oldfieldname": "company",
+ "oldfieldtype": "Link",
+ "options": "Company",
+ "print_hide": 1,
+ "remember_last_selected_value": 1,
+ "reqd": 1,
+ "width": "150px"
+ },
+ {
+ "default": "Today",
+ "fieldname": "transaction_date",
+ "fieldtype": "Date",
+ "in_list_view": 1,
+ "in_standard_filter": 1,
+ "label": "Date",
+ "no_copy": 1,
+ "oldfieldname": "transaction_date",
+ "oldfieldtype": "Date",
+ "reqd": 1,
+ "search_index": 1,
+ "width": "100px"
+ },
+ {
+ "fieldname": "valid_till",
+ "fieldtype": "Date",
+ "label": "Valid Till"
+ },
+ {
+ "default": "Sales",
+ "fieldname": "order_type",
+ "fieldtype": "Select",
+ "in_standard_filter": 1,
+ "label": "Order Type",
+ "oldfieldname": "order_type",
+ "oldfieldtype": "Select",
+ "options": "\nSales\nMaintenance\nShopping Cart",
+ "print_hide": 1,
+ "reqd": 1
+ },
+ {
+ "collapsible": 1,
+ "depends_on": "party_name",
+ "fieldname": "contact_section",
+ "fieldtype": "Section Break",
+ "label": "Address and Contact",
+ "options": "fa fa-bullhorn"
+ },
+ {
+ "fieldname": "customer_address",
+ "fieldtype": "Link",
+ "label": "Customer Address",
+ "options": "Address",
+ "print_hide": 1
+ },
+ {
+ "fieldname": "address_display",
+ "fieldtype": "Small Text",
+ "label": "Address",
+ "oldfieldname": "customer_address",
+ "oldfieldtype": "Small Text",
+ "read_only": 1
+ },
+ {
+ "fieldname": "contact_person",
+ "fieldtype": "Link",
+ "label": "Contact Person",
+ "oldfieldname": "contact_person",
+ "oldfieldtype": "Link",
+ "options": "Contact",
+ "print_hide": 1
+ },
+ {
+ "fieldname": "contact_display",
+ "fieldtype": "Small Text",
+ "in_global_search": 1,
+ "label": "Contact",
+ "read_only": 1
+ },
+ {
+ "fieldname": "contact_mobile",
+ "fieldtype": "Small Text",
+ "label": "Mobile No",
+ "read_only": 1
+ },
+ {
+ "fieldname": "contact_email",
+ "fieldtype": "Data",
+ "hidden": 1,
+ "label": "Contact Email",
+ "options": "Email",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "depends_on": "eval:doc.quotaion_to=='Customer' && doc.party_name",
+ "fieldname": "col_break98",
+ "fieldtype": "Column Break",
+ "width": "50%"
+ },
+ {
+ "fieldname": "shipping_address_name",
+ "fieldtype": "Link",
+ "label": "Shipping Address",
+ "options": "Address",
+ "print_hide": 1
+ },
+ {
+ "fieldname": "shipping_address",
+ "fieldtype": "Small Text",
+ "label": "Shipping Address",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "depends_on": "eval:doc.quotaion_to=='Customer' && doc.party_name",
+ "fieldname": "customer_group",
+ "fieldtype": "Link",
+ "hidden": 1,
+ "label": "Customer Group",
+ "oldfieldname": "customer_group",
+ "oldfieldtype": "Link",
+ "options": "Customer Group",
+ "print_hide": 1
+ },
+ {
+ "fieldname": "territory",
+ "fieldtype": "Link",
+ "label": "Territory",
+ "options": "Territory",
+ "print_hide": 1
+ },
+ {
+ "collapsible": 1,
+ "fieldname": "currency_and_price_list",
+ "fieldtype": "Section Break",
+ "label": "Currency and Price List",
+ "options": "fa fa-tag"
+ },
+ {
+ "fieldname": "currency",
+ "fieldtype": "Link",
+ "label": "Currency",
+ "oldfieldname": "currency",
+ "oldfieldtype": "Select",
+ "options": "Currency",
+ "print_hide": 1,
+ "reqd": 1,
+ "width": "100px"
+ },
+ {
+ "description": "Rate at which customer's currency is converted to company's base currency",
+ "fieldname": "conversion_rate",
+ "fieldtype": "Float",
+ "label": "Exchange Rate",
+ "oldfieldname": "conversion_rate",
+ "oldfieldtype": "Currency",
+ "precision": "9",
+ "print_hide": 1,
+ "reqd": 1,
+ "width": "100px"
+ },
+ {
+ "fieldname": "column_break2",
+ "fieldtype": "Column Break",
+ "width": "50%"
+ },
+ {
+ "fieldname": "selling_price_list",
+ "fieldtype": "Link",
+ "label": "Price List",
+ "oldfieldname": "price_list_name",
+ "oldfieldtype": "Select",
+ "options": "Price List",
+ "print_hide": 1,
+ "reqd": 1,
+ "width": "100px"
+ },
+ {
+ "fieldname": "price_list_currency",
+ "fieldtype": "Link",
+ "label": "Price List Currency",
+ "options": "Currency",
+ "print_hide": 1,
+ "read_only": 1,
+ "reqd": 1
+ },
+ {
+ "description": "Rate at which Price list currency is converted to company's base currency",
+ "fieldname": "plc_conversion_rate",
+ "fieldtype": "Float",
+ "label": "Price List Exchange Rate",
+ "precision": "9",
+ "print_hide": 1,
+ "reqd": 1
+ },
+ {
+ "default": "0",
+ "fieldname": "ignore_pricing_rule",
+ "fieldtype": "Check",
+ "label": "Ignore Pricing Rule",
+ "no_copy": 1,
+ "permlevel": 1,
+ "print_hide": 1
+ },
+ {
+ "fieldname": "items_section",
+ "fieldtype": "Section Break",
+ "oldfieldtype": "Section Break",
+ "options": "fa fa-shopping-cart"
+ },
+ {
+ "allow_bulk_edit": 1,
+ "fieldname": "items",
+ "fieldtype": "Table",
+ "label": "Items",
+ "oldfieldname": "quotation_details",
+ "oldfieldtype": "Table",
+ "options": "Quotation Item",
+ "reqd": 1,
+ "width": "40px"
+ },
+ {
+ "fieldname": "pricing_rule_details",
+ "fieldtype": "Section Break",
+ "label": "Pricing Rules"
+ },
+ {
+ "fieldname": "pricing_rules",
+ "fieldtype": "Table",
+ "label": "Pricing Rule Detail",
+ "options": "Pricing Rule Detail",
+ "read_only": 1
+ },
+ {
+ "fieldname": "sec_break23",
+ "fieldtype": "Section Break"
+ },
+ {
+ "fieldname": "total_qty",
+ "fieldtype": "Float",
+ "label": "Total Quantity",
+ "read_only": 1
+ },
+ {
+ "fieldname": "base_total",
+ "fieldtype": "Currency",
+ "label": "Total (Company Currency)",
+ "options": "Company:company:default_currency",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "fieldname": "base_net_total",
+ "fieldtype": "Currency",
+ "label": "Net Total (Company Currency)",
+ "oldfieldname": "net_total",
+ "oldfieldtype": "Currency",
+ "options": "Company:company:default_currency",
+ "print_hide": 1,
+ "read_only": 1,
+ "width": "100px"
+ },
+ {
+ "fieldname": "column_break_28",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "total",
+ "fieldtype": "Currency",
+ "label": "Total",
+ "options": "currency",
+ "read_only": 1
+ },
+ {
+ "fieldname": "net_total",
+ "fieldtype": "Currency",
+ "label": "Net Total",
+ "options": "currency",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "fieldname": "total_net_weight",
+ "fieldtype": "Float",
+ "label": "Total Net Weight",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "fieldname": "taxes_section",
+ "fieldtype": "Section Break",
+ "label": "Taxes and Charges",
+ "oldfieldtype": "Section Break",
+ "options": "fa fa-money"
+ },
+ {
+ "fieldname": "tax_category",
+ "fieldtype": "Link",
+ "label": "Tax Category",
+ "options": "Tax Category",
+ "print_hide": 1
+ },
+ {
+ "fieldname": "column_break_34",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "shipping_rule",
+ "fieldtype": "Link",
+ "label": "Shipping Rule",
+ "oldfieldtype": "Button",
+ "options": "Shipping Rule",
+ "print_hide": 1
+ },
+ {
+ "fieldname": "section_break_36",
+ "fieldtype": "Section Break"
+ },
+ {
+ "fieldname": "taxes_and_charges",
+ "fieldtype": "Link",
+ "label": "Sales Taxes and Charges Template",
+ "oldfieldname": "charge",
+ "oldfieldtype": "Link",
+ "options": "Sales Taxes and Charges Template",
+ "print_hide": 1
+ },
+ {
+ "fieldname": "taxes",
+ "fieldtype": "Table",
+ "label": "Sales Taxes and Charges",
+ "oldfieldname": "other_charges",
+ "oldfieldtype": "Table",
+ "options": "Sales Taxes and Charges"
+ },
+ {
+ "collapsible": 1,
+ "fieldname": "sec_tax_breakup",
+ "fieldtype": "Section Break",
+ "label": "Tax Breakup"
+ },
+ {
+ "fieldname": "other_charges_calculation",
+ "fieldtype": "Long Text",
+ "label": "Taxes and Charges Calculation",
+ "no_copy": 1,
+ "oldfieldtype": "HTML",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "fieldname": "section_break_39",
+ "fieldtype": "Section Break"
+ },
+ {
+ "fieldname": "base_total_taxes_and_charges",
+ "fieldtype": "Currency",
+ "label": "Total Taxes and Charges (Company Currency)",
+ "oldfieldname": "other_charges_total",
+ "oldfieldtype": "Currency",
+ "options": "Company:company:default_currency",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "fieldname": "column_break_42",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "total_taxes_and_charges",
+ "fieldtype": "Currency",
+ "label": "Total Taxes and Charges",
+ "options": "currency",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "collapsible": 1,
+ "collapsible_depends_on": "discount_amount",
+ "fieldname": "section_break_44",
+ "fieldtype": "Section Break",
+ "label": "Additional Discount and Coupon Code"
+ },
+ {
+ "fieldname": "coupon_code",
+ "fieldtype": "Link",
+ "label": "Coupon Code",
+ "options": "Coupon Code"
+ },
+ {
+ "fieldname": "referral_sales_partner",
+ "fieldtype": "Link",
+ "label": "Referral Sales Partner",
+ "options": "Sales Partner"
+ },
+ {
+ "default": "Grand Total",
+ "fieldname": "apply_discount_on",
+ "fieldtype": "Select",
+ "label": "Apply Additional Discount On",
+ "options": "\nGrand Total\nNet Total",
+ "print_hide": 1
+ },
+ {
+ "fieldname": "base_discount_amount",
+ "fieldtype": "Currency",
+ "label": "Additional Discount Amount (Company Currency)",
+ "options": "Company:company:default_currency",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "fieldname": "column_break_46",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "additional_discount_percentage",
+ "fieldtype": "Float",
+ "label": "Additional Discount Percentage",
+ "print_hide": 1
+ },
+ {
+ "fieldname": "discount_amount",
+ "fieldtype": "Currency",
+ "label": "Additional Discount Amount",
+ "options": "currency",
+ "print_hide": 1
+ },
+ {
+ "fieldname": "totals",
+ "fieldtype": "Section Break",
+ "oldfieldtype": "Section Break",
+ "options": "fa fa-money",
+ "print_hide": 1
+ },
+ {
+ "fieldname": "base_grand_total",
+ "fieldtype": "Currency",
+ "label": "Grand Total (Company Currency)",
+ "oldfieldname": "grand_total",
+ "oldfieldtype": "Currency",
+ "options": "Company:company:default_currency",
+ "print_hide": 1,
+ "read_only": 1,
+ "width": "200px"
+ },
+ {
+ "fieldname": "base_rounding_adjustment",
+ "fieldtype": "Currency",
+ "label": "Rounding Adjustment (Company Currency)",
+ "no_copy": 1,
+ "options": "Company:company:default_currency",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "description": "In Words will be visible once you save the Quotation.",
+ "fieldname": "base_in_words",
+ "fieldtype": "Data",
+ "label": "In Words (Company Currency)",
+ "oldfieldname": "in_words",
+ "oldfieldtype": "Data",
+ "print_hide": 1,
+ "read_only": 1,
+ "width": "200px"
+ },
+ {
+ "fieldname": "base_rounded_total",
+ "fieldtype": "Currency",
+ "label": "Rounded Total (Company Currency)",
+ "oldfieldname": "rounded_total",
+ "oldfieldtype": "Currency",
+ "options": "Company:company:default_currency",
+ "print_hide": 1,
+ "read_only": 1,
+ "width": "200px"
+ },
+ {
+ "fieldname": "column_break3",
+ "fieldtype": "Column Break",
+ "oldfieldtype": "Column Break",
+ "print_hide": 1,
+ "width": "50%"
+ },
+ {
+ "fieldname": "grand_total",
+ "fieldtype": "Currency",
+ "in_list_view": 1,
+ "label": "Grand Total",
+ "oldfieldname": "grand_total_export",
+ "oldfieldtype": "Currency",
+ "options": "currency",
+ "read_only": 1,
+ "width": "200px"
+ },
+ {
+ "fieldname": "rounding_adjustment",
+ "fieldtype": "Currency",
+ "label": "Rounding Adjustment",
+ "no_copy": 1,
+ "options": "currency",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "bold": 1,
+ "fieldname": "rounded_total",
+ "fieldtype": "Currency",
+ "label": "Rounded Total",
+ "oldfieldname": "rounded_total_export",
+ "oldfieldtype": "Currency",
+ "options": "currency",
+ "read_only": 1,
+ "width": "200px"
+ },
+ {
+ "fieldname": "in_words",
+ "fieldtype": "Data",
+ "label": "In Words",
+ "oldfieldname": "in_words_export",
+ "oldfieldtype": "Data",
+ "print_hide": 1,
+ "read_only": 1,
+ "width": "200px"
+ },
+ {
+ "fieldname": "payment_schedule_section",
+ "fieldtype": "Section Break",
+ "label": "Payment Terms"
+ },
+ {
+ "fieldname": "payment_terms_template",
+ "fieldtype": "Link",
+ "label": "Payment Terms Template",
+ "options": "Payment Terms Template",
+ "print_hide": 1
+ },
+ {
+ "fieldname": "payment_schedule",
+ "fieldtype": "Table",
+ "label": "Payment Schedule",
+ "no_copy": 1,
+ "options": "Payment Schedule",
+ "print_hide": 1
+ },
+ {
+ "collapsible": 1,
+ "collapsible_depends_on": "terms",
+ "fieldname": "terms_section_break",
+ "fieldtype": "Section Break",
+ "label": "Terms and Conditions",
+ "oldfieldtype": "Section Break",
+ "options": "fa fa-legal"
+ },
+ {
+ "fieldname": "tc_name",
+ "fieldtype": "Link",
+ "label": "Terms",
+ "oldfieldname": "tc_name",
+ "oldfieldtype": "Link",
+ "options": "Terms and Conditions",
+ "print_hide": 1,
+ "report_hide": 1
+ },
+ {
+ "fieldname": "terms",
+ "fieldtype": "Text Editor",
+ "label": "Term Details",
+ "oldfieldname": "terms",
+ "oldfieldtype": "Text Editor"
+ },
+ {
+ "collapsible": 1,
+ "fieldname": "print_settings",
+ "fieldtype": "Section Break",
+ "label": "Print Settings"
+ },
+ {
+ "allow_on_submit": 1,
+ "fieldname": "letter_head",
+ "fieldtype": "Link",
+ "label": "Letter Head",
+ "oldfieldname": "letter_head",
+ "oldfieldtype": "Select",
+ "options": "Letter Head",
+ "print_hide": 1
+ },
+ {
+ "allow_on_submit": 1,
+ "default": "0",
+ "fieldname": "group_same_items",
+ "fieldtype": "Check",
+ "label": "Group same items",
+ "print_hide": 1
+ },
+ {
+ "fieldname": "column_break_73",
+ "fieldtype": "Column Break"
+ },
+ {
+ "allow_on_submit": 1,
+ "fieldname": "select_print_heading",
+ "fieldtype": "Link",
+ "label": "Print Heading",
+ "no_copy": 1,
+ "oldfieldname": "select_print_heading",
+ "oldfieldtype": "Link",
+ "options": "Print Heading",
+ "print_hide": 1,
+ "report_hide": 1
+ },
+ {
+ "fieldname": "language",
+ "fieldtype": "Data",
+ "label": "Print Language",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "fieldname": "subscription_section",
+ "fieldtype": "Section Break",
+ "label": "Auto Repeat Section"
+ },
+ {
+ "fieldname": "auto_repeat",
+ "fieldtype": "Link",
+ "label": "Auto Repeat",
+ "no_copy": 1,
+ "options": "Auto Repeat",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "allow_on_submit": 1,
+ "depends_on": "eval: doc.auto_repeat",
+ "fieldname": "update_auto_repeat_reference",
+ "fieldtype": "Button",
+ "label": "Update Auto Repeat Reference"
+ },
+ {
+ "collapsible": 1,
+ "fieldname": "more_info",
+ "fieldtype": "Section Break",
+ "label": "More Information",
+ "oldfieldtype": "Section Break",
+ "options": "fa fa-file-text",
+ "print_hide": 1
+ },
+ {
+ "fieldname": "campaign",
+ "fieldtype": "Link",
+ "label": "Campaign",
+ "oldfieldname": "campaign",
+ "oldfieldtype": "Link",
+ "options": "Campaign",
+ "print_hide": 1
+ },
+ {
+ "fieldname": "source",
+ "fieldtype": "Link",
+ "label": "Source",
+ "oldfieldname": "source",
+ "oldfieldtype": "Select",
+ "options": "Lead Source",
+ "print_hide": 1
+ },
+ {
+ "allow_on_submit": 1,
+ "depends_on": "eval:doc.status===\"Lost\"",
+ "fieldname": "order_lost_reason",
+ "fieldtype": "Small Text",
+ "label": "Detailed Reason",
+ "no_copy": 1,
+ "oldfieldname": "order_lost_reason",
+ "oldfieldtype": "Small Text",
+ "print_hide": 1
+ },
+ {
+ "fieldname": "column_break4",
+ "fieldtype": "Column Break",
+ "oldfieldtype": "Column Break",
+ "print_hide": 1,
+ "width": "50%"
+ },
+ {
+ "default": "Draft",
+ "fieldname": "status",
+ "fieldtype": "Select",
+ "in_list_view": 1,
+ "label": "Status",
+ "no_copy": 1,
+ "oldfieldname": "status",
+ "oldfieldtype": "Select",
+ "options": "Draft\nOpen\nReplied\nOrdered\nLost\nCancelled\nExpired",
+ "print_hide": 1,
+ "read_only": 1,
+ "reqd": 1
+ },
+ {
+ "fieldname": "enq_det",
+ "fieldtype": "Text",
+ "hidden": 1,
+ "label": "Opportunity Item",
+ "oldfieldname": "enq_det",
+ "oldfieldtype": "Text",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "fieldname": "supplier_quotation",
+ "fieldtype": "Link",
+ "label": "Supplier Quotation",
+ "options": "Supplier Quotation"
+ },
+ {
+ "fieldname": "opportunity",
+ "fieldtype": "Link",
+ "label": "Opportunity",
+ "options": "Opportunity",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "allow_on_submit": 1,
+ "fieldname": "lost_reasons",
+ "fieldtype": "Table MultiSelect",
+ "label": "Lost Reasons",
+ "options": "Lost Reason Detail",
+ "read_only": 1
}
+ ],
+ "icon": "fa fa-shopping-cart",
+ "idx": 82,
+ "is_submittable": 1,
+ "links": [],
+ "max_attachments": 1,
+ "modified": "2019-12-30 19:14:56.630270",
+ "modified_by": "Administrator",
+ "module": "Selling",
+ "name": "Quotation",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "amend": 1,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Sales User",
+ "share": 1,
+ "submit": 1,
+ "write": 1
+ },
+ {
+ "permlevel": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Sales User"
+ },
+ {
+ "permlevel": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Sales Manager",
+ "write": 1
+ },
+ {
+ "amend": 1,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "import": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Sales Manager",
+ "share": 1,
+ "submit": 1,
+ "write": 1
+ },
+ {
+ "amend": 1,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Maintenance Manager",
+ "share": 1,
+ "submit": 1,
+ "write": 1
+ },
+ {
+ "permlevel": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Maintenance Manager"
+ },
+ {
+ "amend": 1,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Maintenance User",
+ "share": 1,
+ "submit": 1,
+ "write": 1
+ },
+ {
+ "permlevel": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Maintenance User"
+ }
+ ],
+ "search_fields": "status,transaction_date,party_name,order_type",
+ "show_name_in_global_search": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "timeline_field": "party_name",
+ "title_field": "title"
+}
\ No newline at end of file
diff --git a/erpnext/selling/doctype/quotation/quotation.py b/erpnext/selling/doctype/quotation/quotation.py
index 4a56e40..9ebef0d 100644
--- a/erpnext/selling/doctype/quotation/quotation.py
+++ b/erpnext/selling/doctype/quotation/quotation.py
@@ -26,7 +26,6 @@
super(Quotation, self).validate()
self.set_status()
self.update_opportunity()
- self.validate_order_type()
self.validate_uom_is_integer("stock_uom", "qty")
self.validate_valid_till()
self.set_customer_name()
@@ -40,9 +39,6 @@
def has_sales_order(self):
return frappe.db.get_value("Sales Order Item", {"prevdoc_docname": self.name, "docstatus": 1})
- def validate_order_type(self):
- super(Quotation, self).validate_order_type()
-
def update_lead(self):
if self.quotation_to == "Lead" and self.party_name:
frappe.get_doc("Lead", self.party_name).set_status(update=True)
@@ -185,6 +181,10 @@
return doclist
+def set_expired_status():
+ frappe.db.sql("""UPDATE `tabQuotation` SET `status` = 'Expired'
+ WHERE `status` != "Expired" AND `valid_till` < %s""", (nowdate()))
+
@frappe.whitelist()
def make_sales_invoice(source_name, target_doc=None):
return _make_sales_invoice(source_name, target_doc)
diff --git a/erpnext/selling/doctype/quotation/quotation_list.js b/erpnext/selling/doctype/quotation/quotation_list.js
index 5f4e254..802c0ba 100644
--- a/erpnext/selling/doctype/quotation/quotation_list.js
+++ b/erpnext/selling/doctype/quotation/quotation_list.js
@@ -14,15 +14,13 @@
get_indicator: function(doc) {
if(doc.status==="Open") {
- if (doc.valid_till && doc.valid_till < frappe.datetime.nowdate()) {
- return [__("Expired"), "darkgrey", "valid_till,<," + frappe.datetime.nowdate()];
- } else {
- return [__("Open"), "orange", "status,=,Open"];
- }
+ return [__("Open"), "orange", "status,=,Open"];
} else if(doc.status==="Ordered") {
return [__("Ordered"), "green", "status,=,Ordered"];
} else if(doc.status==="Lost") {
return [__("Lost"), "darkgrey", "status,=,Lost"];
+ } else if(doc.status==="Expired") {
+ return [__("Expired"), "darkgrey", "status,=,Expired"];
}
}
};
diff --git a/erpnext/selling/doctype/quotation/test_quotation.py b/erpnext/selling/doctype/quotation/test_quotation.py
index 7ee4a76..ee6b429 100644
--- a/erpnext/selling/doctype/quotation/test_quotation.py
+++ b/erpnext/selling/doctype/quotation/test_quotation.py
@@ -201,6 +201,28 @@
sec_qo = make_quotation(item_list=qo_item2, do_not_submit=True)
sec_qo.submit()
+ def test_quotation_expiry(self):
+ from erpnext.selling.doctype.quotation.quotation import set_expired_status
+
+ quotation_item = [
+ {
+ "item_code": "_Test Item",
+ "warehouse":"",
+ "qty": 1,
+ "rate": 500
+ }
+ ]
+
+ yesterday = add_days(nowdate(), -1)
+ expired_quotation = make_quotation(item_list=quotation_item, transaction_date=yesterday, do_not_submit=True)
+ expired_quotation.valid_till = yesterday
+ expired_quotation.save()
+ expired_quotation.submit()
+ set_expired_status()
+ expired_quotation.reload()
+ self.assertEqual(expired_quotation.status, "Expired")
+
+
test_records = frappe.get_test_records('Quotation')
def get_quotation_dict(party_name=None, item_code=None):
@@ -258,3 +280,5 @@
qo.submit()
return qo
+
+
diff --git a/erpnext/selling/doctype/sales_order/regional/india.js b/erpnext/selling/doctype/sales_order/regional/india.js
new file mode 100644
index 0000000..c11cfcc
--- /dev/null
+++ b/erpnext/selling/doctype/sales_order/regional/india.js
@@ -0,0 +1,3 @@
+{% include "erpnext/regional/india/taxes.js" %}
+
+erpnext.setup_auto_gst_taxation('Sales Order');
diff --git a/erpnext/selling/doctype/sales_order/sales_order.js b/erpnext/selling/doctype/sales_order/sales_order.js
index a2b8544..fa765df 100644
--- a/erpnext/selling/doctype/sales_order/sales_order.js
+++ b/erpnext/selling/doctype/sales_order/sales_order.js
@@ -6,13 +6,14 @@
frappe.ui.form.on("Sales Order", {
setup: function(frm) {
frm.custom_make_buttons = {
- 'Delivery Note': 'Delivery',
+ 'Delivery Note': 'Delivery Note',
'Pick List': 'Pick List',
'Sales Invoice': 'Invoice',
'Material Request': 'Material Request',
'Purchase Order': 'Purchase Order',
'Project': 'Project',
- 'Payment Entry': "Payment"
+ 'Payment Entry': "Payment",
+ 'Work Order': "Work Order"
}
frm.add_fetch('customer', 'tax_id', 'tax_id');
@@ -112,7 +113,6 @@
let allow_delivery = false;
if (doc.docstatus==1) {
- this.frm.add_custom_button(__('Pick List'), () => this.create_pick_list(), __('Create'));
if(this.frm.has_perm("submit")) {
if(doc.status === 'On Hold') {
@@ -135,8 +135,7 @@
}
if(doc.status !== 'Closed') {
if(doc.status !== 'On Hold') {
-
- allow_delivery = this.frm.doc.items.some(item => item.delivered_by_supplier === 0 && item.qty > flt(item.delivered_qty))
+ allow_delivery = this.frm.doc.items.some(item => item.delivered_by_supplier === 0 && item.qty > flt(item.delivered_qty))
&& !this.frm.doc.skip_delivery_note
if (this.frm.has_perm("submit")) {
@@ -148,9 +147,11 @@
}
}
+ this.frm.add_custom_button(__('Pick List'), () => this.create_pick_list(), __('Create'));
+
// delivery note
if(flt(doc.per_delivered, 6) < 100 && ["Sales", "Shopping Cart"].indexOf(doc.order_type)!==-1 && allow_delivery) {
- this.frm.add_custom_button(__('Delivery'), () => this.make_delivery_note_based_on_delivery_date(), __('Create'));
+ this.frm.add_custom_button(__('Delivery Note'), () => this.make_delivery_note_based_on_delivery_date(), __('Create'));
this.frm.add_custom_button(__('Work Order'), () => this.make_work_order(), __('Create'));
}
@@ -202,7 +203,7 @@
}
}
// payment request
- if(flt(doc.per_billed)==0) {
+ if(flt(doc.per_billed)<100) {
this.frm.add_custom_button(__('Payment Request'), () => this.make_payment_request(), __('Create'));
this.frm.add_custom_button(__('Payment'), () => this.make_payment_entry(), __('Create'));
}
@@ -361,7 +362,7 @@
},
toggle_delivery_date: function() {
- this.frm.fields_dict.items.grid.toggle_reqd("delivery_date",
+ this.frm.fields_dict.items.grid.toggle_reqd("delivery_date",
(this.frm.doc.order_type == "Sales" && !this.frm.doc.skip_delivery_note));
},
@@ -695,4 +696,4 @@
});
}
});
-$.extend(cur_frm.cscript, new erpnext.selling.SalesOrderController({frm: cur_frm}));
\ No newline at end of file
+$.extend(cur_frm.cscript, new erpnext.selling.SalesOrderController({frm: cur_frm}));
diff --git a/erpnext/selling/doctype/sales_order/sales_order.json b/erpnext/selling/doctype/sales_order/sales_order.json
index ccc48e1..54e87f7 100644
--- a/erpnext/selling/doctype/sales_order/sales_order.json
+++ b/erpnext/selling/doctype/sales_order/sales_order.json
@@ -1,4 +1,5 @@
{
+ "actions": [],
"allow_import": 1,
"autoname": "naming_series:",
"creation": "2013-06-18 12:39:59",
@@ -31,8 +32,8 @@
"contact_phone",
"contact_mobile",
"contact_email",
- "company_address_display",
"company_address",
+ "company_address_display",
"col_break46",
"shipping_address_name",
"shipping_address",
@@ -342,12 +343,13 @@
{
"fieldname": "company_address_display",
"fieldtype": "Small Text",
+ "label": "Company Address",
"read_only": 1
},
{
"fieldname": "company_address",
"fieldtype": "Link",
- "label": "Company Address",
+ "label": "Company Address Name",
"options": "Address"
},
{
@@ -618,7 +620,7 @@
},
{
"fieldname": "other_charges_calculation",
- "fieldtype": "Text",
+ "fieldtype": "Long Text",
"label": "Taxes and Charges Calculation",
"no_copy": 1,
"oldfieldtype": "HTML",
@@ -1193,7 +1195,8 @@
"icon": "fa fa-file-text",
"idx": 105,
"is_submittable": 1,
- "modified": "2019-10-22 14:26:42.767189",
+ "links": [],
+ "modified": "2019-12-30 19:15:28.605085",
"modified_by": "Administrator",
"module": "Selling",
"name": "Sales Order",
diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py
index c4c3c0f..e7cbf40 100755
--- a/erpnext/selling/doctype/sales_order/sales_order.py
+++ b/erpnext/selling/doctype/sales_order/sales_order.py
@@ -34,7 +34,6 @@
def validate(self):
super(SalesOrder, self).validate()
- self.validate_order_type()
self.validate_delivery_date()
self.validate_proj_cust()
self.validate_po()
@@ -100,9 +99,6 @@
frappe.msgprint(_("Quotation {0} not of type {1}")
.format(d.prevdoc_docname, self.order_type))
- def validate_order_type(self):
- super(SalesOrder, self).validate_order_type()
-
def validate_delivery_date(self):
if self.order_type == 'Sales' and not self.skip_delivery_note:
delivery_date_list = [d.delivery_date for d in self.get("items") if d.delivery_date]
@@ -380,6 +376,9 @@
def get_work_order_items(self, for_raw_material_request=0):
'''Returns items with BOM that already do not have a linked work order'''
items = []
+ item_codes = [i.item_code for i in self.items]
+ product_bundle_parents = [pb.new_item_code for pb in frappe.get_all("Product Bundle", {"new_item_code": ["in", item_codes]}, ["new_item_code"])]
+
for table in [self.items, self.packed_items]:
for i in table:
bom = get_default_bom_item(i.item_code)
@@ -391,7 +390,7 @@
else:
pending_qty = stock_qty
- if pending_qty:
+ if pending_qty and i.item_code not in product_bundle_parents:
if bom:
items.append(dict(
name= i.name,
@@ -420,7 +419,7 @@
def _get_delivery_date(ref_doc_delivery_date, red_doc_transaction_date, transaction_date):
delivery_date = get_next_schedule_date(ref_doc_delivery_date,
- auto_repeat_doc.frequency, cint(auto_repeat_doc.repeat_on_day))
+ auto_repeat_doc.frequency, auto_repeat_doc.start_date, cint(auto_repeat_doc.repeat_on_day))
if delivery_date <= transaction_date:
delivery_date_diff = frappe.utils.date_diff(ref_doc_delivery_date, red_doc_transaction_date)
@@ -578,8 +577,12 @@
target.run_method("set_po_nos")
target.run_method("calculate_taxes_and_totals")
- # set company address
- target.update(get_company_address(target.company))
+ if source.company_address:
+ target.update({'company_address': source.company_address})
+ else:
+ # set company address
+ target.update(get_company_address(target.company))
+
if target.company_address:
target.update(get_fetch_values("Delivery Note", 'company_address', target.company_address))
@@ -645,8 +648,12 @@
target.run_method("set_po_nos")
target.run_method("calculate_taxes_and_totals")
- # set company address
- target.update(get_company_address(target.company))
+ if source.company_address:
+ target.update({'company_address': source.company_address})
+ else:
+ # set company address
+ target.update(get_company_address(target.company))
+
if target.company_address:
target.update(get_fetch_values("Sales Invoice", 'company_address', target.company_address))
@@ -834,6 +841,10 @@
for item in sales_order.items:
if item.supplier and item.supplier not in suppliers:
suppliers.append(item.supplier)
+
+ if not suppliers:
+ frappe.throw(_("Please set a Supplier against the Items to be considered in the Purchase Order."))
+
for supplier in suppliers:
po =frappe.get_list("Purchase Order", filters={"sales_order":source_name, "supplier":supplier, "docstatus": ("<", "2")})
if len(po) == 0:
@@ -1038,14 +1049,18 @@
return doc
-def update_produced_qty_in_so_item(sales_order_item):
+def update_produced_qty_in_so_item(sales_order, sales_order_item):
#for multiple work orders against same sales order item
linked_wo_with_so_item = frappe.db.get_all('Work Order', ['produced_qty'], {
'sales_order_item': sales_order_item,
+ 'sales_order': sales_order,
'docstatus': 1
})
- if len(linked_wo_with_so_item) > 0:
- total_produced_qty = 0
- for wo in linked_wo_with_so_item:
- total_produced_qty += flt(wo.get('produced_qty'))
- frappe.db.set_value('Sales Order Item', sales_order_item, 'produced_qty', total_produced_qty)
\ No newline at end of file
+
+ total_produced_qty = 0
+ for wo in linked_wo_with_so_item:
+ total_produced_qty += flt(wo.get('produced_qty'))
+
+ if not total_produced_qty and frappe.flags.in_patch: return
+
+ frappe.db.set_value('Sales Order Item', sales_order_item, 'produced_qty', total_produced_qty)
\ No newline at end of file
diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py
index bd07841..d8e9a63 100644
--- a/erpnext/selling/doctype/sales_order/test_sales_order.py
+++ b/erpnext/selling/doctype/sales_order/test_sales_order.py
@@ -12,6 +12,7 @@
from erpnext.controllers.accounts_controller import update_child_qty_rate
import json
from erpnext.selling.doctype.sales_order.sales_order import make_raw_material_request
+from erpnext.manufacturing.doctype.blanket_order.test_blanket_order import make_blanket_order
class TestSalesOrder(unittest.TestCase):
def tearDown(self):
@@ -320,7 +321,12 @@
create_dn_against_so(so.name, 4)
make_sales_invoice(so.name)
- trans_item = json.dumps([{'item_code' : '_Test Item 2', 'rate' : 200, 'qty' : 7}])
+ first_item_of_so = so.get("items")[0]
+ trans_item = json.dumps([
+ {'item_code' : first_item_of_so.item_code, 'rate' : first_item_of_so.rate, \
+ 'qty' : first_item_of_so.qty, 'docname': first_item_of_so.name},
+ {'item_code' : '_Test Item 2', 'rate' : 200, 'qty' : 7}
+ ])
update_child_qty_rate('Sales Order', trans_item, so.name)
so.reload()
@@ -329,6 +335,48 @@
self.assertEqual(so.get("items")[-1].qty, 7)
self.assertEqual(so.get("items")[-1].amount, 1400)
self.assertEqual(so.status, 'To Deliver and Bill')
+
+ def test_remove_item_in_update_child_qty_rate(self):
+ so = make_sales_order(**{
+ "item_list": [{
+ "item_code": '_Test Item',
+ "qty": 5,
+ "rate":1000
+ }]
+ })
+ create_dn_against_so(so.name, 2)
+ make_sales_invoice(so.name)
+
+ # add an item so as to try removing items
+ trans_item = json.dumps([
+ {"item_code": '_Test Item', "qty": 5, "rate":1000, "docname": so.get("items")[0].name},
+ {"item_code": '_Test Item 2', "qty": 2, "rate":500}
+ ])
+ update_child_qty_rate('Sales Order', trans_item, so.name)
+ so.reload()
+ self.assertEqual(len(so.get("items")), 2)
+
+ # check if delivered items can be removed
+ trans_item = json.dumps([{
+ "item_code": '_Test Item 2',
+ "qty": 2,
+ "rate":500,
+ "docname": so.get("items")[1].name
+ }])
+ self.assertRaises(frappe.ValidationError, update_child_qty_rate, 'Sales Order', trans_item, so.name)
+
+ #remove last added item
+ trans_item = json.dumps([{
+ "item_code": '_Test Item',
+ "qty": 5,
+ "rate":1000,
+ "docname": so.get("items")[0].name
+ }])
+ update_child_qty_rate('Sales Order', trans_item, so.name)
+
+ so.reload()
+ self.assertEqual(len(so.get("items")), 1)
+ self.assertEqual(so.status, 'To Deliver and Bill')
def test_update_child_qty_rate(self):
@@ -819,6 +867,25 @@
mr_doc = frappe.get_doc('Material Request',mr.get('name'))
self.assertEqual(mr_doc.items[0].sales_order, so.name)
+ def test_so_optional_blanket_order(self):
+ """
+ Expected result: Blanket order Ordered Quantity should only be affected on Sales Order with against_blanket_order = 1.
+ Second Sales Order should not add on to Blanket Orders Ordered Quantity.
+ """
+
+ bo = make_blanket_order(blanket_order_type = "Selling", quantity = 10, rate = 10)
+
+ so = make_sales_order(item_code= "_Test Item", qty = 5, against_blanket_order = 1)
+ so_doc = frappe.get_doc('Sales Order', so.get('name'))
+ # To test if the SO has a Blanket Order
+ self.assertTrue(so_doc.items[0].blanket_order)
+
+ so = make_sales_order(item_code= "_Test Item", qty = 5, against_blanket_order = 0)
+ so_doc = frappe.get_doc('Sales Order', so.get('name'))
+ # To test if the SO does NOT have a Blanket Order
+ self.assertEqual(so_doc.items[0].blanket_order, None)
+
+
def make_sales_order(**args):
so = frappe.new_doc("Sales Order")
args = frappe._dict(args)
@@ -845,7 +912,8 @@
"warehouse": args.warehouse,
"qty": args.qty or 10,
"uom": args.uom or None,
- "rate": args.rate or 100
+ "rate": args.rate or 100,
+ "against_blanket_order": args.against_blanket_order
})
so.delivery_date = add_days(so.transaction_date, 10)
diff --git a/erpnext/selling/doctype/sales_order_item/sales_order_item.json b/erpnext/selling/doctype/sales_order_item/sales_order_item.json
index 3fd1e64..4c8973e 100644
--- a/erpnext/selling/doctype/sales_order_item/sales_order_item.json
+++ b/erpnext/selling/doctype/sales_order_item/sales_order_item.json
@@ -68,6 +68,7 @@
"target_warehouse",
"prevdoc_docname",
"col_break4",
+ "against_blanket_order",
"blanket_order",
"blanket_order_rate",
"planning_section",
@@ -76,10 +77,12 @@
"ordered_qty",
"planned_qty",
"column_break_69",
- "delivered_qty",
"work_order_qty",
+ "delivered_qty",
"produced_qty",
"returned_qty",
+ "shopping_cart_section",
+ "additional_notes",
"section_break_63",
"page_break",
"item_tax_rate",
@@ -574,6 +577,7 @@
"report_hide": 1
},
{
+ "depends_on": "eval:doc.against_blanket_order",
"fieldname": "blanket_order",
"fieldtype": "Link",
"label": "Blanket Order",
@@ -581,6 +585,7 @@
"options": "Blanket Order"
},
{
+ "depends_on": "eval:doc.against_blanket_order",
"fieldname": "blanket_order_rate",
"fieldtype": "Currency",
"label": "Blanket Order Rate",
@@ -741,11 +746,28 @@
"fieldname": "image_section",
"fieldtype": "Section Break",
"label": "Image"
+ },
+ {
+ "collapsible": 1,
+ "fieldname": "shopping_cart_section",
+ "fieldtype": "Section Break",
+ "label": "Shopping Cart"
+ },
+ {
+ "fieldname": "additional_notes",
+ "fieldtype": "Text",
+ "label": "Additional Notes"
+ },
+ {
+ "default": "0",
+ "fieldname": "against_blanket_order",
+ "fieldtype": "Check",
+ "label": "Against Blanket Order"
}
],
"idx": 1,
"istable": 1,
- "modified": "2019-10-10 08:46:26.244823",
+ "modified": "2019-12-12 18:06:26.238169",
"modified_by": "Administrator",
"module": "Selling",
"name": "Sales Order Item",
diff --git a/erpnext/selling/doctype/selling_settings/selling_settings.json b/erpnext/selling/doctype/selling_settings/selling_settings.json
index dc2c4ce..c04bfd2 100644
--- a/erpnext/selling/doctype/selling_settings/selling_settings.json
+++ b/erpnext/selling/doctype/selling_settings/selling_settings.json
@@ -1,611 +1,158 @@
{
- "allow_copy": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "beta": 0,
- "creation": "2013-06-25 10:25:16",
- "custom": 0,
- "description": "Settings for Selling Module",
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "Other",
- "editable_grid": 0,
- "engine": "InnoDB",
+ "creation": "2013-06-25 10:25:16",
+ "description": "Settings for Selling Module",
+ "doctype": "DocType",
+ "document_type": "Other",
+ "engine": "InnoDB",
+ "field_order": [
+ "cust_master_name",
+ "campaign_naming_by",
+ "customer_group",
+ "territory",
+ "selling_price_list",
+ "close_opportunity_after_days",
+ "default_valid_till",
+ "column_break_5",
+ "so_required",
+ "dn_required",
+ "sales_update_frequency",
+ "maintain_same_sales_rate",
+ "editable_price_list_rate",
+ "allow_multiple_items",
+ "allow_against_multiple_purchase_orders",
+ "validate_selling_price",
+ "hide_tax_id"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "Customer Name",
- "fieldname": "cust_master_name",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Customer Naming By",
- "length": 0,
- "no_copy": 0,
- "options": "Customer Name\nNaming Series",
- "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
- },
+ "default": "Customer Name",
+ "fieldname": "cust_master_name",
+ "fieldtype": "Select",
+ "in_list_view": 1,
+ "label": "Customer Naming By",
+ "options": "Customer Name\nNaming Series"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "campaign_naming_by",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Campaign Naming By",
- "length": 0,
- "no_copy": 0,
- "options": "Campaign Name\nNaming Series",
- "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
- },
+ "fieldname": "campaign_naming_by",
+ "fieldtype": "Select",
+ "in_list_view": 1,
+ "label": "Campaign Naming By",
+ "options": "Campaign Name\nNaming Series"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "",
- "fieldname": "customer_group",
- "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": "Default Customer Group",
- "length": 0,
- "no_copy": 0,
- "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
- },
+ "fieldname": "customer_group",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Default Customer Group",
+ "options": "Customer Group"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "description": "",
- "fieldname": "territory",
- "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": "Default Territory",
- "length": 0,
- "no_copy": 0,
- "options": "Territory",
- "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
- },
+ "fieldname": "territory",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Default Territory",
+ "options": "Territory"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "selling_price_list",
- "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": "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
- },
+ "fieldname": "selling_price_list",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Default Price List",
+ "options": "Price List"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "15",
- "description": "Auto close Opportunity after 15 days",
- "fieldname": "close_opportunity_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": "Close Opportunity After 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
- },
+ "default": "15",
+ "description": "Auto close Opportunity after 15 days",
+ "fieldname": "close_opportunity_after_days",
+ "fieldtype": "Int",
+ "label": "Close Opportunity After Days"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "default_valid_till",
- "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": "Default Quotation Validity 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
- },
+ "fieldname": "default_valid_till",
+ "fieldtype": "Data",
+ "label": "Default Quotation Validity Days"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_5",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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
- },
+ "fieldname": "column_break_5",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "so_required",
- "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": "Sales Order Required",
- "length": 0,
- "no_copy": 0,
- "options": "No\nYes",
- "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
- },
+ "fieldname": "so_required",
+ "fieldtype": "Select",
+ "label": "Sales Order Required",
+ "options": "No\nYes"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "dn_required",
- "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": "Delivery Note Required",
- "length": 0,
- "no_copy": 0,
- "options": "No\nYes",
- "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
- },
+ "fieldname": "dn_required",
+ "fieldtype": "Select",
+ "label": "Delivery Note Required",
+ "options": "No\nYes"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "Each Transaction",
- "description": "How often should project and company be updated based on Sales Transactions.",
- "fieldname": "sales_update_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": "Sales Update Frequency",
- "length": 0,
- "no_copy": 0,
- "options": "Each Transaction\nDaily\nMonthly",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "default": "Each Transaction",
+ "description": "How often should project and company be updated based on Sales Transactions.",
+ "fieldname": "sales_update_frequency",
+ "fieldtype": "Select",
+ "label": "Sales Update Frequency",
+ "options": "Each Transaction\nDaily\nMonthly",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "maintain_same_sales_rate",
- "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": "Maintain Same Rate Throughout Sales Cycle",
- "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
- },
+ "default": "0",
+ "fieldname": "maintain_same_sales_rate",
+ "fieldtype": "Check",
+ "label": "Maintain Same Rate Throughout Sales Cycle"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "editable_price_list_rate",
- "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 user to edit Price List Rate in transactions",
- "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
- },
+ "default": "0",
+ "fieldname": "editable_price_list_rate",
+ "fieldtype": "Check",
+ "label": "Allow user to edit Price List Rate in transactions"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "allow_multiple_items",
- "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 Item to be added multiple times in a transaction",
- "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
- },
+ "default": "0",
+ "fieldname": "allow_multiple_items",
+ "fieldtype": "Check",
+ "label": "Allow Item to be added multiple times in a transaction"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "allow_against_multiple_purchase_orders",
- "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 multiple Sales Orders against a Customer's Purchase Order",
- "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
- },
+ "default": "0",
+ "fieldname": "allow_against_multiple_purchase_orders",
+ "fieldtype": "Check",
+ "label": "Allow multiple Sales Orders against a Customer's Purchase Order"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "validate_selling_price",
- "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": "Validate Selling Price for Item against Purchase Rate or Valuation Rate",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "default": "0",
+ "fieldname": "validate_selling_price",
+ "fieldtype": "Check",
+ "label": "Validate Selling Price for Item against Purchase Rate or Valuation Rate"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "hide_tax_id",
- "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": "Hide Customer's Tax Id from Sales Transactions",
- "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
+ "default": "0",
+ "fieldname": "hide_tax_id",
+ "fieldtype": "Check",
+ "label": "Hide Customer's Tax Id from Sales Transactions"
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "icon": "fa fa-cog",
- "idx": 1,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 1,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2018-06-25 12:56:16.332039",
- "modified_by": "Administrator",
- "module": "Selling",
- "name": "Selling Settings",
- "owner": "Administrator",
+ ],
+ "icon": "fa fa-cog",
+ "idx": 1,
+ "issingle": 1,
+ "modified": "2019-12-09 13:38:36.486298",
+ "modified_by": "Administrator",
+ "module": "Selling",
+ "name": "Selling Settings",
+ "owner": "Administrator",
"permissions": [
{
- "amend": 0,
- "cancel": 0,
- "create": 1,
- "delete": 0,
- "email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 0,
- "role": "System Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
+ "create": 1,
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "role": "System Manager",
+ "share": 1,
"write": 1
}
- ],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 0,
- "track_seen": 0,
- "track_views": 0
-}
+ ],
+ "sort_field": "modified",
+ "sort_order": "DESC"
+}
\ No newline at end of file
diff --git a/erpnext/selling/doctype/selling_settings/test_selling_settings.py b/erpnext/selling/doctype/selling_settings/test_selling_settings.py
new file mode 100644
index 0000000..961a54d
--- /dev/null
+++ b/erpnext/selling/doctype/selling_settings/test_selling_settings.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+# import frappe
+import unittest
+
+class TestSellingSettings(unittest.TestCase):
+ pass
diff --git a/erpnext/selling/onboarding_slide/add_a_few_customers/add_a_few_customers.json b/erpnext/selling/onboarding_slide/add_a_few_customers/add_a_few_customers.json
new file mode 100644
index 0000000..92d00bc
--- /dev/null
+++ b/erpnext/selling/onboarding_slide/add_a_few_customers/add_a_few_customers.json
@@ -0,0 +1,49 @@
+{
+ "add_more_button": 1,
+ "app": "ERPNext",
+ "creation": "2019-11-15 14:44:10.065014",
+ "docstatus": 0,
+ "doctype": "Onboarding Slide",
+ "domains": [],
+ "help_links": [
+ {
+ "label": "Learn More",
+ "video_id": "zsrrVDk6VBs"
+ }
+ ],
+ "idx": 0,
+ "image_src": "",
+ "is_completed": 0,
+ "max_count": 3,
+ "modified": "2019-12-09 17:54:01.686006",
+ "modified_by": "Administrator",
+ "name": "Add A Few Customers",
+ "owner": "Administrator",
+ "ref_doctype": "Customer",
+ "slide_desc": "",
+ "slide_fields": [
+ {
+ "align": "",
+ "fieldname": "customer_name",
+ "fieldtype": "Data",
+ "label": "Customer Name",
+ "placeholder": "",
+ "reqd": 1
+ },
+ {
+ "align": "",
+ "fieldtype": "Column Break",
+ "reqd": 0
+ },
+ {
+ "align": "",
+ "fieldname": "customer_email",
+ "fieldtype": "Data",
+ "label": "Email ID",
+ "reqd": 1
+ }
+ ],
+ "slide_order": 40,
+ "slide_title": "Add A Few Customers",
+ "slide_type": "Create"
+}
\ No newline at end of file
diff --git a/erpnext/selling/page/point_of_sale/point_of_sale.js b/erpnext/selling/page/point_of_sale/point_of_sale.js
index d2c2d70..df48783 100644
--- a/erpnext/selling/page/point_of_sale/point_of_sale.js
+++ b/erpnext/selling/page/point_of_sale/point_of_sale.js
@@ -1,5 +1,6 @@
/* global Clusterize */
frappe.provide('erpnext.pos');
+frappe.provide('erpnext.queries');
frappe.pages['point-of-sale'].on_page_load = function(wrapper) {
frappe.ui.make_app_page({
@@ -286,14 +287,14 @@
if (in_list(['serial_no', 'batch_no'], field)) {
args[field] = value;
}
-
+
// add to cur_frm
const item = this.frm.add_child('items', args);
frappe.flags.hide_serial_batch_dialog = true;
frappe.run_serially([
() => {
- this.frm.script_manager.trigger('item_code', item.doctype, item.name)
+ return this.frm.script_manager.trigger('item_code', item.doctype, item.name)
.then(() => {
this.frm.script_manager.trigger('qty', item.doctype, item.name)
.then(() => {
@@ -451,7 +452,7 @@
change_pos_profile() {
return new Promise((resolve) => {
- const on_submit = ({ pos_profile, set_as_default }) => {
+ const on_submit = ({ company, pos_profile, set_as_default }) => {
if (pos_profile) {
this.pos_profile = pos_profile;
}
@@ -461,7 +462,7 @@
method: "erpnext.accounts.doctype.pos_profile.pos_profile.set_default_profile",
args: {
'pos_profile': pos_profile,
- 'company': this.frm.doc.company
+ 'company': company
}
}).then(() => {
this.on_change_pos_profile();
@@ -471,7 +472,42 @@
}
}
- frappe.prompt(this.get_prompt_fields(),
+
+ let me = this;
+
+ var dialog = frappe.prompt([{
+ fieldtype: 'Link',
+ label: __('Company'),
+ options: 'Company',
+ fieldname: 'company',
+ default: me.frm.doc.company,
+ reqd: 1,
+ onchange: function(e) {
+ me.get_default_pos_profile(this.value).then((r) => {
+ dialog.set_value('pos_profile', (r && r.name)? r.name : '');
+ });
+ }
+ },
+ {
+ fieldtype: 'Link',
+ label: __('POS Profile'),
+ options: 'POS Profile',
+ fieldname: 'pos_profile',
+ default: me.frm.doc.pos_profile,
+ reqd: 1,
+ get_query: () => {
+ return {
+ query: 'erpnext.accounts.doctype.pos_profile.pos_profile.pos_profile_query',
+ filters: {
+ company: dialog.get_value('company')
+ }
+ };
+ }
+ }, {
+ fieldtype: 'Check',
+ label: __('Set as default'),
+ fieldname: 'set_as_default'
+ }],
on_submit,
__('Select POS Profile')
);
@@ -494,26 +530,9 @@
]);
}
- get_prompt_fields() {
- return [{
- fieldtype: 'Link',
- label: __('POS Profile'),
- options: 'POS Profile',
- fieldname: 'pos_profile',
- reqd: 1,
- get_query: () => {
- return {
- query: 'erpnext.accounts.doctype.pos_profile.pos_profile.pos_profile_query',
- filters: {
- company: this.frm.doc.company
- }
- };
- }
- }, {
- fieldtype: 'Check',
- label: __('Set as default'),
- fieldname: 'set_as_default'
- }];
+ get_default_pos_profile(company) {
+ return frappe.xcall("erpnext.stock.get_item_details.get_pos_profile",
+ {'company': company})
}
setup_company() {
@@ -538,6 +557,7 @@
if (this.cart) {
this.cart.frm = this.frm;
this.cart.reset();
+ this.cart.reset_pos_field_value();
} else {
this.make_items();
this.make_cart();
@@ -611,6 +631,7 @@
this.frm.allow_edit_rate = r.message.allow_edit_rate;
this.frm.allow_edit_discount = r.message.allow_edit_discount;
this.frm.doc.campaign = r.message.campaign;
+ this.frm.allow_print_before_pay = r.message.allow_print_before_pay;
}
}
@@ -623,11 +644,6 @@
var me = this;
this.page.clear_menu();
- // for mobile
- // this.page.add_menu_item(__("Pay"), function () {
- //
- // }).addClass('visible-xs');
-
this.page.add_menu_item(__("Form View"), function () {
frappe.model.sync(me.frm.doc);
frappe.set_route("Form", me.frm.doc.doctype, me.frm.doc.name);
@@ -657,7 +673,7 @@
}
set_form_action() {
- if(this.frm.doc.docstatus == 1 || (this.frm.doc.allow_print_before_pay == 1&&this.frm.doc.items.length>0)){
+ if(this.frm.doc.docstatus == 1 || (this.frm.allow_print_before_pay == 1 && this.frm.doc.items.length > 0)){
this.page.set_secondary_action(__("Print"), async() => {
if(this.frm.doc.docstatus != 1 ){
await this.frm.save();
@@ -695,6 +711,7 @@
make() {
this.make_dom();
this.make_customer_field();
+ this.make_pos_fields();
this.make_loyalty_points();
this.make_numpad();
}
@@ -704,6 +721,13 @@
<div class="pos-cart">
<div class="customer-field">
</div>
+ <div class="pos-field-section" style="margin-bottom:12px; display:none">
+ <a class="h6 uppercase more-fields-section" disabled> ${__("More Information")} </a>
+ <i class="octicon octicon-chevron-down pos-fields-octicon collapse-indicator"
+ style="color:#cacaca; cursor: pointer"></i>
+ <div class="pos-fields" style ="margin-top:12px">
+ </div>
+ </div>
<div class="cart-wrapper">
<div class="list-item-table">
<div class="list-item list-item--head">
@@ -792,6 +816,22 @@
}
}
+ reset_pos_field_value() {
+ let value = '';
+ if (this.custom_pos_fields) {
+ this.custom_pos_fields.forEach(r => {
+ value = this.frm.doc[r.fieldname] || r.default_value || '';
+
+ if (this.fields) {
+ this.fields[r.fieldname].set_value(value);
+ }
+ })
+ }
+
+ this.wrapper.find('.pos-fields').toggle(false);
+ this.wrapper.find('.pos-fields-octicon').toggle(true);
+ }
+
get_grand_total() {
let total = this.get_total_template('Grand Total', 'grand-total-value');
@@ -930,6 +970,67 @@
this.customer_field.set_value(this.frm.doc.customer);
}
+ make_pos_fields() {
+ const me = this;
+
+ this.fields = {};
+ this.wrapper.find('.pos-fields-octicon, .more-fields-section').click(() => {
+ this.wrapper.find('.pos-fields').toggle();
+ this.wrapper.find('.pos-fields-octicon').toggleClass('octicon-chevron-down').toggleClass('octicon-chevron-up');
+ });
+ this.wrapper.find('.pos-fields').toggle(false);
+
+ return new Promise(res => {
+ frappe.call({
+ method: "erpnext.selling.page.point_of_sale.point_of_sale.get_pos_fields",
+ freeze: true,
+ }).then(r => {
+ if(r.message.length) {
+ this.wrapper.find('.pos-field-section').css('display','block');
+ this.custom_pos_fields = r.message;
+ if (r.message.length < 3) {
+ this.wrapper.find('.pos-fields').toggle(true);
+ this.wrapper.find('.pos-fields-octicon').toggleClass('octicon-chevron-down').toggleClass('octicon-chevron-up');
+ }
+
+ r.message.forEach(field => {
+ this.fields[field.fieldname] = frappe.ui.form.make_control({
+ df: {
+ fieldtype: field.fieldtype,
+ label: field.label,
+ fieldname: field.fieldname,
+ options: field.options,
+ reqd: field.reqd || 0,
+ read_only: field.read_only || 0,
+ default: field.default_value,
+ onchange: function() {
+ if (this.value) {
+ me.frm.set_value(this.df.fieldname, this.value);
+ }
+ },
+ get_query: () => {
+ return this.get_query_for_pos_fields(field.fieldname)
+ },
+ },
+ parent: this.wrapper.find('.pos-fields'),
+ render_input: true
+ });
+
+ if (this.frm.doc[field.fieldname]) {
+ this.fields[field.fieldname].set_value(this.frm.doc[field.fieldname]);
+ }
+ });
+ }
+ });
+ });
+ }
+
+ get_query_for_pos_fields(field) {
+ if (this.frm.fields_dict && this.frm.fields_dict[field]
+ && this.frm.fields_dict[field].get_query) {
+ return this.frm.fields_dict[field].get_query(this.frm.doc);
+ }
+ }
make_loyalty_points() {
this.available_loyalty_points = frappe.ui.form.make_control({
diff --git a/erpnext/selling/page/point_of_sale/point_of_sale.py b/erpnext/selling/page/point_of_sale/point_of_sale.py
index a9d2be5..3425f8f 100644
--- a/erpnext/selling/page/point_of_sale/point_of_sale.py
+++ b/erpnext/selling/page/point_of_sale/point_of_sale.py
@@ -160,3 +160,8 @@
where {condition} and (name like %(txt)s) limit {start}, {page_len}"""
.format(condition = cond, start=start, page_len= page_len),
{'txt': '%%%s%%' % txt})
+
+@frappe.whitelist()
+def get_pos_fields():
+ return frappe.get_all("POS Field", fields=["label", "fieldname",
+ "fieldtype", "default_value", "reqd", "read_only", "options"])
\ No newline at end of file
diff --git a/erpnext/selling/report/available_stock_for_packing_items/available_stock_for_packing_items.py b/erpnext/selling/report/available_stock_for_packing_items/available_stock_for_packing_items.py
index 32711b2..056492a 100644
--- a/erpnext/selling/report/available_stock_for_packing_items/available_stock_for_packing_items.py
+++ b/erpnext/selling/report/available_stock_for_packing_items/available_stock_for_packing_items.py
@@ -7,7 +7,7 @@
def execute(filters=None):
if not filters: filters = {}
-
+
columns = get_columns()
iwq_map = get_item_warehouse_quantity_map()
item_map = get_item_details()
@@ -15,22 +15,23 @@
for sbom, warehouse in iwq_map.items():
total = 0
total_qty = 0
-
+
for wh, item_qty in warehouse.items():
total += 1
- row = [sbom, item_map.get(sbom).item_name, item_map.get(sbom).description,
- item_map.get(sbom).stock_uom, wh]
- available_qty = item_qty
- total_qty += flt(available_qty)
- row += [available_qty]
-
- if available_qty:
- data.append(row)
- if (total == len(warehouse)):
- row = ["", "", "Total", "", "", total_qty]
+ if item_map.get(sbom):
+ row = [sbom, item_map.get(sbom).item_name, item_map.get(sbom).description,
+ item_map.get(sbom).stock_uom, wh]
+ available_qty = item_qty
+ total_qty += flt(available_qty)
+ row += [available_qty]
+
+ if available_qty:
data.append(row)
+ if (total == len(warehouse)):
+ row = ["", "", "Total", "", "", total_qty]
+ data.append(row)
return columns, data
-
+
def get_columns():
columns = ["Item Code:Link/Item:100", "Item Name::100", "Description::120", \
"UOM:Link/UOM:80", "Warehouse:Link/Warehouse:100", "Quantity::100"]
diff --git a/erpnext/selling/report/item_wise_sales_history/item_wise_sales_history.js b/erpnext/selling/report/item_wise_sales_history/item_wise_sales_history.js
new file mode 100644
index 0000000..daca2e3
--- /dev/null
+++ b/erpnext/selling/report/item_wise_sales_history/item_wise_sales_history.js
@@ -0,0 +1,37 @@
+// Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+/* eslint-disable */
+
+frappe.query_reports["Item-wise Sales History"] = {
+ "filters": [
+ {
+ fieldname:"company",
+ label: __("Company"),
+ fieldtype: "Link",
+ options: "Company",
+ default: frappe.defaults.get_user_default("Company"),
+ reqd: 1
+ },
+ {
+ fieldname:"item_group",
+ label: __("Item Group"),
+ fieldtype: "Link",
+ options: "Item Group"
+ },
+ {
+ fieldname:"from_date",
+ reqd: 1,
+ label: __("From Date"),
+ fieldtype: "Date",
+ default: frappe.datetime.add_months(frappe.datetime.get_today(), -1),
+ },
+ {
+ fieldname:"to_date",
+ reqd: 1,
+ default: frappe.datetime.get_today(),
+ label: __("To Date"),
+ fieldtype: "Date",
+ },
+
+ ]
+};
\ No newline at end of file
diff --git a/erpnext/selling/report/item_wise_sales_history/item_wise_sales_history.json b/erpnext/selling/report/item_wise_sales_history/item_wise_sales_history.json
index 88e6f27..a6dda28 100644
--- a/erpnext/selling/report/item_wise_sales_history/item_wise_sales_history.json
+++ b/erpnext/selling/report/item_wise_sales_history/item_wise_sales_history.json
@@ -1,34 +1,34 @@
{
- "add_total_row": 1,
- "creation": "2013-05-23 17:42:24",
- "disabled": 0,
- "docstatus": 0,
- "doctype": "Report",
- "idx": 3,
- "is_standard": "Yes",
- "modified": "2019-01-03 22:52:41.519890",
- "modified_by": "Administrator",
- "module": "Selling",
- "name": "Item-wise Sales History",
- "owner": "Administrator",
- "prepared_report": 0,
- "query": "select\n so_item.item_code as \"Item Code:Link/Item:120\",\n\tso_item.item_name as \"Item Name::120\",\n so_item.item_group as \"Item Group:Link/Item Group:120\",\n\tso_item.description as \"Description::150\",\n\tso_item.qty as \"Qty:Data:100\",\n\tso_item.uom as \"UOM:Link/UOM:80\",\n\tso_item.base_rate as \"Rate:Currency:120\",\n\tso_item.base_amount as \"Amount:Currency:120\",\n\tso.name as \"Sales Order:Link/Sales Order:120\",\n\tso.transaction_date as \"Transaction Date:Date:140\",\n\tso.customer as \"Customer:Link/Customer:130\",\n cu.customer_name as \"Customer Name::150\",\n\tcu.customer_group as \"Customer Group:Link/Customer Group:130\",\n\tso.territory as \"Territory:Link/Territory:130\",\n \tso.project as \"Project:Link/Project:130\",\n\tifnull(so_item.delivered_qty, 0) as \"Delivered Qty:Float:120\",\n\tifnull(so_item.billed_amt, 0) as \"Billed Amount:Currency:120\",\n\tso.company as \"Company:Link/Company:\"\nfrom\n\t`tabSales Order` so, `tabSales Order Item` so_item, `tabCustomer` cu\nwhere\n\tso.name = so_item.parent and so.customer=cu.name\n\tand so.docstatus = 1\norder by so.name desc",
- "ref_doctype": "Sales Order",
- "report_name": "Item-wise Sales History",
- "report_type": "Query Report",
+ "add_total_row": 1,
+ "creation": "2013-05-23 17:42:24",
+ "disable_prepared_report": 0,
+ "disabled": 0,
+ "docstatus": 0,
+ "doctype": "Report",
+ "idx": 3,
+ "is_standard": "Yes",
+ "modified": "2019-11-04 16:28:14.608904",
+ "modified_by": "Administrator",
+ "module": "Selling",
+ "name": "Item-wise Sales History",
+ "owner": "Administrator",
+ "prepared_report": 0,
+ "ref_doctype": "Sales Order",
+ "report_name": "Item-wise Sales History",
+ "report_type": "Script Report",
"roles": [
{
"role": "Sales User"
- },
+ },
{
"role": "Sales Manager"
- },
+ },
{
"role": "Maintenance User"
- },
+ },
{
"role": "Accounts User"
- },
+ },
{
"role": "Stock User"
}
diff --git a/erpnext/selling/report/item_wise_sales_history/item_wise_sales_history.py b/erpnext/selling/report/item_wise_sales_history/item_wise_sales_history.py
new file mode 100644
index 0000000..1fc3663
--- /dev/null
+++ b/erpnext/selling/report/item_wise_sales_history/item_wise_sales_history.py
@@ -0,0 +1,214 @@
+# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe import _
+from frappe.utils import flt
+from frappe.utils.nestedset import get_descendants_of
+
+def execute(filters=None):
+ filters = frappe._dict(filters or {})
+ columns = get_columns(filters)
+ data = get_data(filters)
+ return columns, data
+
+def get_columns(filters):
+ return [
+ {
+ "label": _("Item Code"),
+ "fieldtype": "Link",
+ "fieldname": "item_code",
+ "options": "Item",
+ "width": 120
+ },
+ {
+ "label": _("Item Name"),
+ "fieldtype": "Data",
+ "fieldname": "item_name",
+ "width": 140
+ },
+ {
+ "label": _("Item Group"),
+ "fieldtype": "Link",
+ "fieldname": "item_group",
+ "options": "Item Group",
+ "width": 120
+ },
+ {
+ "label": _("Description"),
+ "fieldtype": "Data",
+ "fieldname": "description",
+ "width": 150
+ },
+ {
+ "label": _("Quantity"),
+ "fieldtype": "Float",
+ "fieldname": "quantity",
+ "width": 150
+ },
+ {
+ "label": _("UOM"),
+ "fieldtype": "Link",
+ "fieldname": "uom",
+ "options": "UOM",
+ "width": 100
+ },
+ {
+ "label": _("Rate"),
+ "fieldname": "rate",
+ "options": "Currency",
+ "width": 120
+ },
+ {
+ "label": _("Amount"),
+ "fieldname": "amount",
+ "options": "Currency",
+ "width": 120
+ },
+ {
+ "label": _("Sales Order"),
+ "fieldtype": "Link",
+ "fieldname": "sales_order",
+ "options": "Sales Order",
+ "width": 100
+ },
+ {
+ "label": _("Transaction Date"),
+ "fieldtype": "Date",
+ "fieldname": "transaction_date",
+ "width": 90
+ },
+ {
+ "label": _("Customer"),
+ "fieldtype": "Link",
+ "fieldname": "customer",
+ "options": "Customer",
+ "width": 100
+ },
+ {
+ "label": _("Customer Name"),
+ "fieldtype": "Data",
+ "fieldname": "customer_name",
+ "width": 140
+ },
+ {
+ "label": _("Customer Group"),
+ "fieldtype": "Link",
+ "fieldname": "customer_group",
+ "options": "customer Group",
+ "width": 120
+ },
+ {
+ "label": _("Territory"),
+ "fieldtype": "Link",
+ "fieldname": "territory",
+ "options": "Territory",
+ "width": 100
+ },
+ {
+ "label": _("Project"),
+ "fieldtype": "Link",
+ "fieldname": "project",
+ "options": "Project",
+ "width": 100
+ },
+ {
+ "label": _("Delivered Quantity"),
+ "fieldtype": "Float",
+ "fieldname": "delivered_quantity",
+ "width": 150
+ },
+ {
+ "label": _("Billed Amount"),
+ "fieldname": "rate",
+ "options": "billed_amount",
+ "width": 120
+ },
+ {
+ "label": _("Company"),
+ "fieldtype": "Link",
+ "fieldname": "company",
+ "options": "Company",
+ "width": 100
+ }
+ ]
+
+def get_data(filters):
+
+ data = []
+
+ company_list = get_descendants_of("Company", filters.get("company"))
+ company_list.append(filters.get("company"))
+
+ customer_details = get_customer_details()
+ sales_order_records = get_sales_order_details(company_list, filters)
+
+ for record in sales_order_records:
+ customer_record = customer_details.get(record.customer)
+ row = {
+ "item_code": record.item_code,
+ "item_name": record.item_name,
+ "item_group": record.item_group,
+ "description": record.description,
+ "quantity": record.qty,
+ "uom": record.uom,
+ "rate": record.base_rate,
+ "amount": record.base_amount,
+ "sales_order": record.name,
+ "transaction_date": record.transaction_date,
+ "customer": record.customer,
+ "customer_name": customer_record.customer_name,
+ "customer_group": customer_record.customer_group,
+ "territory": record.territory,
+ "project": record.project,
+ "delivered_quantity": flt(record.delivered_qty),
+ "billed_amount": flt(record.billed_amt),
+ "company": record.company
+ }
+ data.append(row)
+
+ return data
+
+def get_conditions(filters):
+ conditions = ''
+ if filters.get('item_group'):
+ conditions += "AND so_item.item_group = %s" %frappe.db.escape(filters.item_group)
+
+ if filters.get('from_date'):
+ conditions += "AND so.transaction_date >= '%s'" %filters.from_date
+
+ if filters.get('to_date'):
+ conditions += "AND so.transaction_date <= '%s'" %filters.to_date
+
+ return conditions
+
+def get_customer_details():
+ details = frappe.get_all('Customer',
+ fields=['name', 'customer_name', "customer_group"])
+ customer_details = {}
+ for d in details:
+ customer_details.setdefault(d.name, frappe._dict({
+ "customer_name": d.customer_name,
+ "customer_group": d.customer_group
+ }))
+ return customer_details
+
+def get_sales_order_details(company_list, filters):
+ conditions = get_conditions(filters)
+
+ return frappe.db.sql("""
+ SELECT
+ so_item.item_code, so_item.item_name, so_item.item_group,
+ so_item.description, so_item.qty, so_item.uom,
+ so_item.base_rate, so_item.base_amount, so.name,
+ so.transaction_date, so.customer, so.territory,
+ so.project, so_item.delivered_qty,
+ so_item.billed_amt, so.company
+ FROM
+ `tabSales Order` so, `tabSales Order Item` so_item
+ WHERE
+ so.name = so_item.parent
+ AND so.company in ({0})
+ AND so.docstatus = 1 {1}
+ """.format(','.join(["%s"] * len(company_list)), conditions), tuple(company_list), as_dict=1)
diff --git a/erpnext/selling/sales_common.js b/erpnext/selling/sales_common.js
index e508476..8278745 100644
--- a/erpnext/selling/sales_common.js
+++ b/erpnext/selling/sales_common.js
@@ -84,6 +84,13 @@
return me.set_query_for_batch(doc, cdt, cdn)
});
}
+
+ if(this.frm.fields_dict["items"].grid.get_field('item_code')) {
+ this.frm.set_query("item_tax_template", "items", function(doc, cdt, cdn) {
+ return me.set_query_for_item_tax_template(doc, cdt, cdn)
+ });
+ }
+
},
refresh: function() {
@@ -309,7 +316,7 @@
child: item,
args: {
"batch_no": item.batch_no,
- "stock_qty": item.stock_qty,
+ "stock_qty": item.stock_qty || item.qty, //if stock_qty field is not available fetch qty (in case of Packed Items table)
"warehouse": item.warehouse,
"item_code": item.item_code,
"has_serial_no": has_serial_no
diff --git a/erpnext/setup/doctype/authorization_control/authorization_control.py b/erpnext/setup/doctype/authorization_control/authorization_control.py
index 7db703f..0c52b83 100644
--- a/erpnext/setup/doctype/authorization_control/authorization_control.py
+++ b/erpnext/setup/doctype/authorization_control/authorization_control.py
@@ -76,7 +76,7 @@
add_cond = ''
auth_value = av_dis
- if val == 1: add_cond += " and system_user = '"+session['user'].replace("'", "\\'")+"'"
+ if val == 1: add_cond += " and system_user = '"+ frappe.db.escape(session['user'])+"'"
elif val == 2: add_cond += " and system_role IN %s" % ("('"+"','".join(frappe.get_roles())+"')")
else: add_cond += " and ifnull(system_user,'') = '' and ifnull(system_role,'') = ''"
@@ -85,7 +85,7 @@
if doc_obj:
if doc_obj.doctype == 'Sales Invoice': customer = doc_obj.customer
else: customer = doc_obj.customer_name
- add_cond = " and master_name = '"+cstr(customer).replace("'", "\\'")+"'"
+ add_cond = " and master_name = '"+ frappe.db.escape(customer) +"'"
if based_on == 'Itemwise Discount':
if doc_obj:
for t in doc_obj.get("items"):
diff --git a/erpnext/setup/doctype/company/company.js b/erpnext/setup/doctype/company/company.js
index 313de67..be736d2 100644
--- a/erpnext/setup/doctype/company/company.js
+++ b/erpnext/setup/doctype/company/company.js
@@ -29,7 +29,8 @@
company_name: function(frm) {
if(frm.doc.__islocal) {
- let parts = frm.doc.company_name.split();
+ // add missing " " arg in split method
+ let parts = frm.doc.company_name.split(" ");
let abbr = $.map(parts, function (p) {
return p? p.substr(0, 1) : null;
}).join("");
diff --git a/erpnext/setup/doctype/company/company.json b/erpnext/setup/doctype/company/company.json
index bc34189..dd602ec 100644
--- a/erpnext/setup/doctype/company/company.json
+++ b/erpnext/setup/doctype/company/company.json
@@ -725,7 +725,7 @@
"icon": "fa fa-building",
"idx": 1,
"image_field": "company_logo",
- "modified": "2019-07-04 22:20:45.104307",
+ "modified": "2019-11-22 13:04:47.470768",
"modified_by": "Administrator",
"module": "Setup",
"name": "Company",
@@ -767,6 +767,18 @@
{
"read": 1,
"role": "Projects User"
+ },
+ {
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Accounts Manager",
+ "share": 1,
+ "write": 1
}
],
"show_name_in_global_search": 1,
diff --git a/erpnext/setup/doctype/company/company.py b/erpnext/setup/doctype/company/company.py
index 8b42b19..ff35154 100644
--- a/erpnext/setup/doctype/company/company.py
+++ b/erpnext/setup/doctype/company/company.py
@@ -14,6 +14,9 @@
from frappe.contacts.address_and_contact import load_address_and_contact
from frappe.utils.nestedset import NestedSet
+from past.builtins import cmp
+import functools
+
class Company(NestedSet):
nsm_parent_field = 'parent_company'
@@ -207,7 +210,7 @@
"default_expense_account": "Cost of Goods Sold"
})
- if self.update_default_account or frappe.flags.in_test:
+ if self.update_default_account:
for default_account in default_accounts:
self._set_default_account(default_account, default_accounts.get(default_account))
@@ -560,3 +563,26 @@
return json.loads(history) if history and '{' in history else {}
return date_to_value_dict
+
+@frappe.whitelist()
+def get_default_company_address(name, sort_key='is_primary_address', existing_address=None):
+ if sort_key not in ['is_shipping_address', 'is_primary_address']:
+ return None
+
+ out = frappe.db.sql(""" SELECT
+ addr.name, addr.%s
+ FROM
+ `tabAddress` addr, `tabDynamic Link` dl
+ WHERE
+ dl.parent = addr.name and dl.link_doctype = 'Company' and
+ dl.link_name = %s and ifnull(addr.disabled, 0) = 0
+ """ %(sort_key, '%s'), (name)) #nosec
+
+ if existing_address:
+ if existing_address in [d[0] for d in out]:
+ return existing_address
+
+ if out:
+ return sorted(out, key = functools.cmp_to_key(lambda x,y: cmp(y[1], x[1])))[0][0]
+ else:
+ return None
\ No newline at end of file
diff --git a/erpnext/setup/doctype/company/company_list.js b/erpnext/setup/doctype/company/company_list.js
new file mode 100644
index 0000000..0172865
--- /dev/null
+++ b/erpnext/setup/doctype/company/company_list.js
@@ -0,0 +1,10 @@
+frappe.listview_settings['Company'] = {
+ onload: () => {
+ frappe.breadcrumbs.add({
+ type: 'Custom',
+ module: __('Accounts'),
+ label: __('Accounts'),
+ route: '#modules/Accounts'
+ });
+ }
+}
\ No newline at end of file
diff --git a/erpnext/setup/doctype/company/delete_company_transactions.py b/erpnext/setup/doctype/company/delete_company_transactions.py
index 637e655..1503adb 100644
--- a/erpnext/setup/doctype/company/delete_company_transactions.py
+++ b/erpnext/setup/doctype/company/delete_company_transactions.py
@@ -106,7 +106,10 @@
frappe.db.sql("""update tabCustomer set lead_name=NULL where lead_name in ({leads})""".format(leads=",".join(leads)))
def delete_communications(doctype, company_name, company_fieldname):
- frappe.db.sql("""
- DELETE FROM `tabCommunication` WHERE reference_doctype = %s AND
- EXISTS (SELECT name FROM `tab{0}` WHERE {1} = %s AND `tabCommunication`.reference_name = name)
- """.format(doctype, company_fieldname), (doctype, company_name))
+ reference_docs = frappe.get_all(doctype, filters={company_fieldname:company_name})
+ reference_doc_names = [r.name for r in reference_docs]
+
+ communications = frappe.get_all("Communication", filters={"reference_doctype":doctype,"reference_name":["in", reference_doc_names]})
+ communication_names = [c.name for c in communications]
+
+ frappe.delete_doc("Communication", communication_names)
diff --git a/erpnext/setup/doctype/company/test_company.py b/erpnext/setup/doctype/company/test_company.py
index 8debef5..1664b66 100644
--- a/erpnext/setup/doctype/company/test_company.py
+++ b/erpnext/setup/doctype/company/test_company.py
@@ -22,7 +22,7 @@
company.create_chart_of_accounts_based_on = "Existing Company"
company.existing_company = "_Test Company"
company.save()
-
+
expected_results = {
"Debtors - CFEC": {
"account_type": "Receivable",
@@ -37,7 +37,7 @@
"parent_account": "Cash In Hand - CFEC"
}
}
-
+
for account, acc_property in expected_results.items():
acc = frappe.get_doc("Account", account)
for prop, val in acc_property.items():
@@ -50,14 +50,14 @@
countries = ["India", "Brazil", "United Arab Emirates", "Canada", "Germany", "France",
"Guatemala", "Indonesia", "Italy", "Mexico", "Nicaragua", "Netherlands", "Singapore",
"Brazil", "Argentina", "Hungary", "Taiwan"]
-
+
for country in countries:
templates = get_charts_for_country(country)
if len(templates) != 1 and "Standard" in templates:
templates.remove("Standard")
-
+
self.assertTrue(templates)
-
+
for template in templates:
try:
company = frappe.new_doc("Company")
@@ -67,11 +67,11 @@
company.create_chart_of_accounts_based_on = "Standard Template"
company.chart_of_accounts = template
company.save()
-
- account_types = ["Cost of Goods Sold", "Depreciation",
- "Expenses Included In Valuation", "Fixed Asset", "Payable", "Receivable",
+
+ account_types = ["Cost of Goods Sold", "Depreciation",
+ "Expenses Included In Valuation", "Fixed Asset", "Payable", "Receivable",
"Stock Adjustment", "Stock Received But Not Billed", "Bank", "Cash", "Stock"]
-
+
for account_type in account_types:
filters = {
"company": template,
@@ -88,6 +88,57 @@
self.delete_mode_of_payment(template)
frappe.delete_doc("Company", template)
+ def test_delete_communication(self):
+ from erpnext.setup.doctype.company.delete_company_transactions import delete_communications
+ company = create_child_company()
+ lead = create_test_lead_in_company(company)
+ communication = create_company_communication("Lead", lead)
+ delete_communications("Lead", "Test Company", "company")
+ self.assertFalse(frappe.db.exists("Communcation", communication))
+ self.assertFalse(frappe.db.exists({"doctype":"Comunication Link", "link_name": communication}))
+
def delete_mode_of_payment(self, company):
frappe.db.sql(""" delete from `tabMode of Payment Account`
where company =%s """, (company))
+
+def create_company_communication(doctype, docname):
+ comm = frappe.get_doc({
+ "doctype": "Communication",
+ "communication_type": "Communication",
+ "content": "Deduplication of Links",
+ "communication_medium": "Email",
+ "reference_doctype":doctype,
+ "reference_name":docname
+ })
+ comm.insert()
+
+def create_child_company():
+ child_company = frappe.db.exists("Company", "Test Company")
+ if not child_company:
+ child_company = frappe.get_doc({
+ "doctype":"Company",
+ "company_name":"Test Company",
+ "abbr":"test_company",
+ "default_currency":"INR"
+ })
+ child_company.insert()
+ else:
+ child_company = frappe.get_doc("Company", child_company)
+
+ return child_company.name
+
+def create_test_lead_in_company(company):
+ lead = frappe.db.exists("Lead", "Test Lead in new company")
+ if not lead:
+ lead = frappe.get_doc({
+ "doctype": "Lead",
+ "lead_name": "Test Lead in new company",
+ "scompany": company
+ })
+ lead.insert()
+ else:
+ lead = frappe.get_doc("Lead", lead)
+ lead.company = company
+ lead.save()
+ return lead.name
+
diff --git a/erpnext/setup/doctype/company/test_records.json b/erpnext/setup/doctype/company/test_records.json
index 58d8b5c..2130241 100644
--- a/erpnext/setup/doctype/company/test_records.json
+++ b/erpnext/setup/doctype/company/test_records.json
@@ -62,5 +62,16 @@
"domain": "Manufacturing",
"chart_of_accounts": "Standard",
"default_holiday_list": "_Test Holiday List"
+ },
+ {
+ "abbr": "TCP1",
+ "company_name": "_Test Company with perpetual inventory",
+ "country": "India",
+ "default_currency": "INR",
+ "doctype": "Company",
+ "domain": "Manufacturing",
+ "chart_of_accounts": "Standard",
+ "enable_perpetual_inventory": 1,
+ "default_holiday_list": "_Test Holiday List"
}
]
diff --git a/erpnext/setup/doctype/currency_exchange/currency_exchange.py b/erpnext/setup/doctype/currency_exchange/currency_exchange.py
index 4effb5a..6480f60 100644
--- a/erpnext/setup/doctype/currency_exchange/currency_exchange.py
+++ b/erpnext/setup/doctype/currency_exchange/currency_exchange.py
@@ -11,10 +11,19 @@
class CurrencyExchange(Document):
def autoname(self):
+ purpose = ""
if not self.date:
self.date = nowdate()
- self.name = '{0}-{1}-{2}'.format(formatdate(get_datetime_str(self.date), "yyyy-MM-dd"),
- self.from_currency, self.to_currency)
+
+ # If both selling and buying enabled
+ purpose = "Selling-Buying"
+ if cint(self.for_buying)==0 and cint(self.for_selling)==1:
+ purpose = "Selling"
+ if cint(self.for_buying)==1 and cint(self.for_selling)==0:
+ purpose = "Buying"
+
+ self.name = '{0}-{1}-{2}{3}'.format(formatdate(get_datetime_str(self.date), "yyyy-MM-dd"),
+ self.from_currency, self.to_currency, ("-" + purpose) if purpose else "")
def validate(self):
self.validate_value("exchange_rate", ">", 0)
@@ -23,4 +32,4 @@
throw(_("From Currency and To Currency cannot be same"))
if not cint(self.for_buying) and not cint(self.for_selling):
- throw(_("Currency Exchange must be applicable for Buying or for Selling."))
\ No newline at end of file
+ throw(_("Currency Exchange must be applicable for Buying or for Selling."))
diff --git a/erpnext/setup/doctype/currency_exchange/test_currency_exchange.py b/erpnext/setup/doctype/currency_exchange/test_currency_exchange.py
index c488b99..c5c01c5 100644
--- a/erpnext/setup/doctype/currency_exchange/test_currency_exchange.py
+++ b/erpnext/setup/doctype/currency_exchange/test_currency_exchange.py
@@ -4,15 +4,23 @@
import frappe, unittest
from frappe.utils import flt
from erpnext.setup.utils import get_exchange_rate
+from frappe.utils import cint
test_records = frappe.get_test_records('Currency Exchange')
def save_new_records(test_records):
for record in test_records:
+ # If both selling and buying enabled
+ purpose = "Selling-Buying"
+
+ if cint(record.get("for_buying"))==0 and cint(record.get("for_selling"))==1:
+ purpose = "Selling"
+ if cint(record.get("for_buying"))==1 and cint(record.get("for_selling"))==0:
+ purpose = "Buying"
kwargs = dict(
doctype=record.get("doctype"),
- docname=record.get("date") + '-' + record.get("from_currency") + '-' + record.get("to_currency"),
+ docname=record.get("date") + '-' + record.get("from_currency") + '-' + record.get("to_currency") + '-' + purpose,
fieldname="exchange_rate",
value=record.get("exchange_rate"),
)
@@ -25,6 +33,8 @@
curr_exchange.from_currency = record["from_currency"]
curr_exchange.to_currency = record["to_currency"]
curr_exchange.exchange_rate = record["exchange_rate"]
+ curr_exchange.for_buying = record["for_buying"]
+ curr_exchange.for_selling = record["for_selling"]
curr_exchange.insert()
@@ -44,18 +54,18 @@
frappe.db.set_value("Accounts Settings", None, "allow_stale", 1)
# Start with allow_stale is True
- exchange_rate = get_exchange_rate("USD", "INR", "2016-01-01")
+ exchange_rate = get_exchange_rate("USD", "INR", "2016-01-01", "for_buying")
self.assertEqual(flt(exchange_rate, 3), 60.0)
- exchange_rate = get_exchange_rate("USD", "INR", "2016-01-15")
+ exchange_rate = get_exchange_rate("USD", "INR", "2016-01-15", "for_buying")
self.assertEqual(exchange_rate, 65.1)
- exchange_rate = get_exchange_rate("USD", "INR", "2016-01-30")
+ exchange_rate = get_exchange_rate("USD", "INR", "2016-01-30", "for_selling")
self.assertEqual(exchange_rate, 62.9)
# Exchange rate as on 15th Dec, 2015, should be fetched from fixer.io
self.clear_cache()
- exchange_rate = get_exchange_rate("USD", "INR", "2015-12-15")
+ exchange_rate = get_exchange_rate("USD", "INR", "2015-12-15", "for_selling")
self.assertFalse(exchange_rate == 60)
self.assertEqual(flt(exchange_rate, 3), 66.894)
@@ -64,35 +74,35 @@
frappe.db.set_value("Accounts Settings", None, "allow_stale", 0)
frappe.db.set_value("Accounts Settings", None, "stale_days", 1)
- exchange_rate = get_exchange_rate("USD", "INR", "2016-01-01")
+ exchange_rate = get_exchange_rate("USD", "INR", "2016-01-01", "for_buying")
self.assertEqual(exchange_rate, 60.0)
# Will fetch from fixer.io
self.clear_cache()
- exchange_rate = get_exchange_rate("USD", "INR", "2016-01-15")
+ exchange_rate = get_exchange_rate("USD", "INR", "2016-01-15", "for_buying")
self.assertEqual(flt(exchange_rate, 3), 67.79)
- exchange_rate = get_exchange_rate("USD", "INR", "2016-01-30")
+ exchange_rate = get_exchange_rate("USD", "INR", "2016-01-30", "for_selling")
self.assertEqual(exchange_rate, 62.9)
# Exchange rate as on 15th Dec, 2015, should be fetched from fixer.io
self.clear_cache()
- exchange_rate = get_exchange_rate("USD", "INR", "2015-12-15")
+ exchange_rate = get_exchange_rate("USD", "INR", "2015-12-15", "for_buying")
self.assertEqual(flt(exchange_rate, 3), 66.894)
- exchange_rate = get_exchange_rate("INR", "NGN", "2016-01-10")
+ exchange_rate = get_exchange_rate("INR", "NGN", "2016-01-10", "for_selling")
self.assertEqual(exchange_rate, 65.1)
# NGN is not available on fixer.io so these should return 0
- exchange_rate = get_exchange_rate("INR", "NGN", "2016-01-09")
+ exchange_rate = get_exchange_rate("INR", "NGN", "2016-01-09", "for_selling")
self.assertEqual(exchange_rate, 0)
- exchange_rate = get_exchange_rate("INR", "NGN", "2016-01-11")
+ exchange_rate = get_exchange_rate("INR", "NGN", "2016-01-11", "for_selling")
self.assertEqual(exchange_rate, 0)
def test_exchange_rate_strict_switched(self):
# Start with allow_stale is True
- exchange_rate = get_exchange_rate("USD", "INR", "2016-01-15")
+ exchange_rate = get_exchange_rate("USD", "INR", "2016-01-15", "for_buying")
self.assertEqual(exchange_rate, 65.1)
frappe.db.set_value("Accounts Settings", None, "allow_stale", 0)
@@ -100,5 +110,5 @@
# Will fetch from fixer.io
self.clear_cache()
- exchange_rate = get_exchange_rate("USD", "INR", "2016-01-15")
- self.assertEqual(flt(exchange_rate, 3), 67.79)
\ No newline at end of file
+ exchange_rate = get_exchange_rate("USD", "INR", "2016-01-15", "for_buying")
+ self.assertEqual(flt(exchange_rate, 3), 67.79)
diff --git a/erpnext/setup/doctype/currency_exchange/test_records.json b/erpnext/setup/doctype/currency_exchange/test_records.json
index 0c9cfbb..152060e 100644
--- a/erpnext/setup/doctype/currency_exchange/test_records.json
+++ b/erpnext/setup/doctype/currency_exchange/test_records.json
@@ -1,44 +1,56 @@
[
- {
- "doctype": "Currency Exchange",
- "date": "2016-01-01",
- "exchange_rate": 60.0,
- "from_currency": "USD",
- "to_currency": "INR"
- },
- {
- "doctype": "Currency Exchange",
- "date": "2016-01-01",
- "exchange_rate": 0.773,
- "from_currency": "USD",
- "to_currency": "EUR"
- },
- {
- "doctype": "Currency Exchange",
- "date": "2016-01-01",
- "exchange_rate": 0.0167,
- "from_currency": "INR",
- "to_currency": "USD"
- },
- {
- "doctype": "Currency Exchange",
- "date": "2016-01-10",
- "exchange_rate": 65.1,
- "from_currency": "USD",
- "to_currency": "INR"
- },
+ {
+ "doctype": "Currency Exchange",
+ "date": "2016-01-01",
+ "exchange_rate": 60.0,
+ "from_currency": "USD",
+ "to_currency": "INR",
+ "for_buying": 1,
+ "for_selling": 0
+ },
{
- "doctype": "Currency Exchange",
- "date": "2016-01-30",
- "exchange_rate": 62.9,
- "from_currency": "USD",
- "to_currency": "INR"
- },
- {
- "doctype": "Currency Exchange",
- "date": "2016-01-10",
- "exchange_rate": 65.1,
- "from_currency": "INR",
- "to_currency": "NGN"
- }
-]
\ No newline at end of file
+ "doctype": "Currency Exchange",
+ "date": "2016-01-01",
+ "exchange_rate": 0.773,
+ "from_currency": "USD",
+ "to_currency": "EUR",
+ "for_buying": 0,
+ "for_selling": 1
+ },
+ {
+ "doctype": "Currency Exchange",
+ "date": "2016-01-01",
+ "exchange_rate": 0.0167,
+ "from_currency": "INR",
+ "to_currency": "USD",
+ "for_buying": 1,
+ "for_selling": 0
+ },
+ {
+ "doctype": "Currency Exchange",
+ "date": "2016-01-10",
+ "exchange_rate": 65.1,
+ "from_currency": "USD",
+ "to_currency": "INR",
+ "for_buying": 1,
+ "for_selling": 0
+ },
+ {
+ "doctype": "Currency Exchange",
+ "date": "2016-01-30",
+ "exchange_rate": 62.9,
+ "from_currency": "USD",
+ "to_currency": "INR",
+ "for_buying": 1,
+ "for_selling": 1
+ },
+ {
+ "doctype": "Currency Exchange",
+ "date": "2016-01-10",
+ "exchange_rate": 65.1,
+ "from_currency": "INR",
+ "to_currency": "NGN",
+ "for_buying": 1,
+ "for_selling": 1
+ }
+]
diff --git a/erpnext/setup/doctype/email_digest/email_digest.py b/erpnext/setup/doctype/email_digest/email_digest.py
index 1de5ccb..4d2d540 100644
--- a/erpnext/setup/doctype/email_digest/email_digest.py
+++ b/erpnext/setup/doctype/email_digest/email_digest.py
@@ -4,8 +4,8 @@
from __future__ import unicode_literals
import frappe
from frappe import _
-from frappe.utils import fmt_money, formatdate, format_time, now_datetime, \
- get_url_to_form, get_url_to_list, flt, get_link_to_report
+from frappe.utils import (fmt_money, formatdate, format_time, now_datetime,
+ get_url_to_form, get_url_to_list, flt, get_link_to_report, add_to_date, today)
from datetime import timedelta
from dateutil.relativedelta import relativedelta
from frappe.core.doctype.user.user import STANDARD_USERS
@@ -151,8 +151,9 @@
def get_calendar_events(self):
"""Get calendar events for given user"""
from frappe.desk.doctype.event.event import get_events
- events = get_events(self.future_from_date.strftime("%Y-%m-%d"),
- self.future_to_date.strftime("%Y-%m-%d")) or []
+ from_date, to_date = get_future_date_for_calendaer_event(self.frequency)
+
+ events = get_events(from_date, to_date)
event_count = 0
for i, e in enumerate(events):
@@ -282,7 +283,7 @@
card.value = card.value *-1
card.value = self.fmt_money(card.value,False if key in ("bank_balance", "credit_balance") else True)
- cache.setex(cache_key, card, 24 * 60 * 60)
+ cache.set_value(cache_key, card, expires_in_sec=24 * 60 * 60)
context.cards.append(card)
@@ -825,4 +826,14 @@
last_year_closing_count = get_count_on(account, fieldname, fy_start_date - timedelta(days=1))
count = count_on_to_date + (last_year_closing_count - count_before_from_date)
- return count
\ No newline at end of file
+ return count
+
+def get_future_date_for_calendaer_event(frequency):
+ from_date = to_date = today()
+
+ if frequency == "Weekly":
+ to_date = add_to_date(from_date, weeks=1)
+ elif frequency == "Monthly":
+ to_date = add_to_date(from_date, months=1)
+
+ return from_date, to_date
\ No newline at end of file
diff --git a/erpnext/setup/doctype/item_group/item_group.py b/erpnext/setup/doctype/item_group/item_group.py
index 5603f17..22375ae 100644
--- a/erpnext/setup/doctype/item_group/item_group.py
+++ b/erpnext/setup/doctype/item_group/item_group.py
@@ -39,6 +39,7 @@
invalidate_cache_for(self)
self.validate_name_with_item()
self.validate_one_root()
+ self.delete_child_item_groups_key()
def make_route(self):
'''Make website route'''
@@ -58,6 +59,7 @@
def on_trash(self):
NestedSet.on_trash(self)
WebsiteGenerator.on_trash(self)
+ self.delete_child_item_groups_key()
def validate_name_with_item(self):
if frappe.db.exists("Item", self.name):
@@ -83,6 +85,9 @@
return context
+ def delete_child_item_groups_key(self):
+ frappe.cache().hdel("child_item_groups", self.name)
+
@frappe.whitelist(allow_guest=True)
def get_product_list_for_group(product_group=None, start=0, limit=10, search=None):
if product_group:
@@ -136,6 +141,7 @@
fields = ['name', 'route', 'description', 'image'],
filters = dict(
show_in_website = 1,
+ parent_item_group = item_group.name,
lft = ('>', item_group.lft),
rgt = ('<', item_group.rgt),
),
@@ -167,6 +173,19 @@
from `tabItem Group` where lft>=%(lft)s and rgt<=%(rgt)s
and show_in_website = 1""", {"lft": item_group.lft, "rgt": item_group.rgt})
+def get_child_item_groups(item_group_name):
+ child_item_groups = frappe.cache().hget("child_item_groups", item_group_name)
+
+ if not child_item_groups:
+ item_group = frappe.get_cached_doc("Item Group", item_group_name)
+
+ child_item_groups = [d.name for d in frappe.get_all('Item Group',
+ filters= {'lft': ('>=', item_group.lft),'rgt': ('>=', item_group.rgt)})]
+
+ frappe.cache().hset("child_item_groups", item_group_name, child_item_groups)
+
+ return child_item_groups or {}
+
def get_item_for_list_in_html(context):
# add missing absolute link in files
# user may forget it during upload
diff --git a/erpnext/setup/doctype/setup_progress/__init__.py b/erpnext/setup/doctype/setup_progress/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/erpnext/setup/doctype/setup_progress/__init__.py
+++ /dev/null
diff --git a/erpnext/setup/doctype/setup_progress/setup_progress.js b/erpnext/setup/doctype/setup_progress/setup_progress.js
deleted file mode 100644
index 5c78bd5..0000000
--- a/erpnext/setup/doctype/setup_progress/setup_progress.js
+++ /dev/null
@@ -1,8 +0,0 @@
-// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
-// For license information, please see license.txt
-
-frappe.ui.form.on('Setup Progress', {
- refresh: function() {
-
- }
-});
diff --git a/erpnext/setup/doctype/setup_progress/setup_progress.json b/erpnext/setup/doctype/setup_progress/setup_progress.json
deleted file mode 100644
index 09072d4..0000000
--- a/erpnext/setup/doctype/setup_progress/setup_progress.json
+++ /dev/null
@@ -1,123 +0,0 @@
-{
- "allow_copy": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "beta": 0,
- "creation": "2017-08-27 21:01:42.032109",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "",
- "editable_grid": 1,
- "engine": "InnoDB",
- "fields": [
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "actions_sb",
- "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": "Actions",
- "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
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "actions",
- "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": "Actions",
- "length": 0,
- "no_copy": 0,
- "options": "Setup Progress Action",
- "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
- }
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 1,
- "is_submittable": 0,
- "issingle": 1,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2017-09-21 11:52:56.106659",
- "modified_by": "Administrator",
- "module": "Setup",
- "name": "Setup Progress",
- "name_case": "",
- "owner": "Administrator",
- "permissions": [
- {
- "amend": 0,
- "apply_user_permissions": 0,
- "cancel": 0,
- "create": 0,
- "delete": 0,
- "email": 1,
- "export": 0,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 0,
- "role": "All",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
- "write": 1
- }
- ],
- "quick_entry": 1,
- "read_only": 1,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1,
- "track_seen": 0
-}
\ No newline at end of file
diff --git a/erpnext/setup/doctype/setup_progress/setup_progress.py b/erpnext/setup/doctype/setup_progress/setup_progress.py
deleted file mode 100644
index e1402f5..0000000
--- a/erpnext/setup/doctype/setup_progress/setup_progress.py
+++ /dev/null
@@ -1,63 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
-# For license information, please see license.txt
-
-from __future__ import unicode_literals
-import frappe, json
-from frappe.model.document import Document
-
-class SetupProgress(Document):
- pass
-
-def get_setup_progress():
- if not getattr(frappe.local, "setup_progress", None):
- frappe.local.setup_progress = frappe.get_doc("Setup Progress", "Setup Progress")
-
- return frappe.local.setup_progress
-
-def get_action_completed_state(action_name):
- for d in get_setup_progress().actions:
- if d.action_name == action_name:
- return d.is_completed
-
-def update_action_completed_state(action_name):
- action_table_doc = [d for d in get_setup_progress().actions
- if d.action_name == action_name][0]
- update_action(action_table_doc)
-
-def update_action(doc):
- doctype = doc.action_doctype
- docname = doc.action_document
- field = doc.action_field
-
- if not doc.is_completed:
- if doc.min_doc_count:
- if frappe.db.count(doctype) >= doc.min_doc_count:
- doc.is_completed = 1
- doc.save()
- if docname and field:
- d = frappe.get_doc(doctype, docname)
- if d.get(field):
- doc.is_completed = 1
- doc.save()
-
-def update_domain_actions(domain):
- for d in get_setup_progress().actions:
- domains = json.loads(d.domains)
- if domains == [] or domain in domains:
- update_action(d)
-
-def get_domain_actions_state(domain):
- state = {}
- for d in get_setup_progress().actions:
- domains = json.loads(d.domains)
- if domains == [] or domain in domains:
- state[d.action_name] = d.is_completed
- return state
-
-@frappe.whitelist()
-def set_action_completed_state(action_name):
- action_table_doc = [d for d in get_setup_progress().actions
- if d.action_name == action_name][0]
- action_table_doc.is_completed = 1
- action_table_doc.save()
diff --git a/erpnext/setup/doctype/setup_progress/test_setup_progress.js b/erpnext/setup/doctype/setup_progress/test_setup_progress.js
deleted file mode 100644
index 9e84e0c..0000000
--- a/erpnext/setup/doctype/setup_progress/test_setup_progress.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Setup Progress", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Setup Progress
- () => frappe.tests.make('Setup Progress', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/setup/doctype/setup_progress/test_setup_progress.py b/erpnext/setup/doctype/setup_progress/test_setup_progress.py
deleted file mode 100644
index 8926219..0000000
--- a/erpnext/setup/doctype/setup_progress/test_setup_progress.py
+++ /dev/null
@@ -1,9 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors
-# See license.txt
-from __future__ import unicode_literals
-
-import unittest
-
-class TestSetupProgress(unittest.TestCase):
- pass
diff --git a/erpnext/setup/doctype/setup_progress_action/__init__.py b/erpnext/setup/doctype/setup_progress_action/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/erpnext/setup/doctype/setup_progress_action/__init__.py
+++ /dev/null
diff --git a/erpnext/setup/doctype/setup_progress_action/setup_progress_action.json b/erpnext/setup/doctype/setup_progress_action/setup_progress_action.json
deleted file mode 100644
index e9abcbc..0000000
--- a/erpnext/setup/doctype/setup_progress_action/setup_progress_action.json
+++ /dev/null
@@ -1,253 +0,0 @@
-{
- "allow_copy": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "beta": 0,
- "creation": "2017-08-27 21:00:40.715360",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "",
- "editable_grid": 1,
- "engine": "InnoDB",
- "fields": [
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "action_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": "Action Name",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "action_doctype",
- "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": "Action Doctype",
- "length": 0,
- "no_copy": 0,
- "options": "DocType",
- "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
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "action_document",
- "fieldtype": "Dynamic 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": "Action Document",
- "length": 0,
- "no_copy": 0,
- "options": "action_doctype",
- "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
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "action_field",
- "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": "Action Field",
- "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
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "min_doc_count",
- "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": "Min Doc Count",
- "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
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "domains",
- "fieldtype": "Code",
- "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": "Domains",
- "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
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "is_completed",
- "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 Completed",
- "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
- }
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 1,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 1,
- "max_attachments": 0,
- "modified": "2017-09-01 14:34:59.685730",
- "modified_by": "Administrator",
- "module": "Setup",
- "name": "Setup Progress Action",
- "name_case": "",
- "owner": "Administrator",
- "permissions": [],
- "quick_entry": 1,
- "read_only": 1,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1,
- "track_seen": 0
-}
\ No newline at end of file
diff --git a/erpnext/setup/doctype/setup_progress_action/setup_progress_action.py b/erpnext/setup/doctype/setup_progress_action/setup_progress_action.py
deleted file mode 100644
index 24af943..0000000
--- a/erpnext/setup/doctype/setup_progress_action/setup_progress_action.py
+++ /dev/null
@@ -1,9 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
-# For license information, please see license.txt
-
-from __future__ import unicode_literals
-from frappe.model.document import Document
-
-class SetupProgressAction(Document):
- pass
diff --git "a/erpnext/setup/onboarding_slide/welcome_back_to_erpnext\041/welcome_back_to_erpnext\041.json" "b/erpnext/setup/onboarding_slide/welcome_back_to_erpnext\041/welcome_back_to_erpnext\041.json"
new file mode 100644
index 0000000..f00dc94
--- /dev/null
+++ "b/erpnext/setup/onboarding_slide/welcome_back_to_erpnext\041/welcome_back_to_erpnext\041.json"
@@ -0,0 +1,23 @@
+{
+ "add_more_button": 0,
+ "app": "ERPNext",
+ "creation": "2019-12-04 19:21:39.995776",
+ "docstatus": 0,
+ "doctype": "Onboarding Slide",
+ "domains": [],
+ "help_links": [],
+ "idx": 0,
+ "image_src": "",
+ "is_completed": 0,
+ "max_count": 3,
+ "modified": "2019-12-09 17:53:53.849953",
+ "modified_by": "Administrator",
+ "name": "Welcome back to ERPNext!",
+ "owner": "Administrator",
+ "slide_desc": "<p>Let's continue where you left from!</p>",
+ "slide_fields": [],
+ "slide_module": "Setup",
+ "slide_order": 0,
+ "slide_title": "Welcome back to ERPNext!",
+ "slide_type": "Continue"
+}
\ No newline at end of file
diff --git "a/erpnext/setup/onboarding_slide/welcome_to_erpnext\041/welcome_to_erpnext\041.json" "b/erpnext/setup/onboarding_slide/welcome_to_erpnext\041/welcome_to_erpnext\041.json"
new file mode 100644
index 0000000..37eb67b
--- /dev/null
+++ "b/erpnext/setup/onboarding_slide/welcome_to_erpnext\041/welcome_to_erpnext\041.json"
@@ -0,0 +1,23 @@
+{
+ "add_more_button": 0,
+ "app": "ERPNext",
+ "creation": "2019-11-26 17:01:26.671859",
+ "docstatus": 0,
+ "doctype": "Onboarding Slide",
+ "domains": [],
+ "help_links": [],
+ "idx": 0,
+ "image_src": "",
+ "is_completed": 0,
+ "max_count": 0,
+ "modified": "2019-12-22 21:26:28.414597",
+ "modified_by": "Administrator",
+ "name": "Welcome to ERPNext!",
+ "owner": "Administrator",
+ "slide_desc": "<div class=\"text center\">Setting up an ERP can be overwhelming. But don't worry, we have got your back! This wizard will help you onboard to ERPNext in a short time!</div>",
+ "slide_fields": [],
+ "slide_module": "Setup",
+ "slide_order": 1,
+ "slide_title": "Welcome to ERPNext!",
+ "slide_type": "Information"
+}
\ No newline at end of file
diff --git a/erpnext/setup/setup_wizard/test_setup_wizard.py b/erpnext/setup/setup_wizard/test_setup_wizard.py
deleted file mode 100644
index a489133..0000000
--- a/erpnext/setup/setup_wizard/test_setup_wizard.py
+++ /dev/null
@@ -1,71 +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, time
-from frappe.utils.selenium_testdriver import TestDriver
-
-def run_setup_wizard_test():
- driver = TestDriver()
- frappe.db.set_default('in_selenium', '1')
- frappe.db.commit()
-
- driver.login('#page-setup-wizard')
- print('Running Setup Wizard Test...')
-
- # Language slide
- driver.wait_for_ajax(True)
- time.sleep(1)
-
- driver.set_select("language", "English (United States)")
- driver.wait_for_ajax(True)
- time.sleep(1)
- driver.click(".next-btn")
-
- # Region slide
- driver.wait_for_ajax(True)
- driver.set_select("country", "India")
- driver.wait_for_ajax(True)
- time.sleep(1)
- driver.click(".next-btn")
-
- # Profile slide
- driver.set_field("full_name", "Great Tester")
- driver.set_field("email", "great@example.com")
- driver.set_field("password", "test")
- driver.wait_for_ajax(True)
- time.sleep(1)
- driver.click(".next-btn")
- time.sleep(1)
-
- # domain slide
- driver.set_multicheck("domains", ["Manufacturing"])
- time.sleep(1)
- driver.click(".next-btn")
-
- # Org slide
- driver.set_field("company_name", "For Testing")
- time.sleep(1)
- driver.print_console()
- driver.click(".next-btn")
-
- driver.set_field("company_tagline", "Just for GST")
- driver.set_field("bank_account", "HDFC")
- time.sleep(3)
- driver.click(".complete-btn")
-
- # Wait for desktop
- driver.wait_for('#page-desktop', timeout=600)
-
- driver.print_console()
- time.sleep(3)
-
- frappe.db.set_default('in_selenium', None)
- frappe.db.set_value("Company", "For Testing", "write_off_account", "Write Off - FT")
- frappe.db.set_value("Company", "For Testing", "exchange_gain_loss_account", "Exchange Gain/Loss - FT")
- frappe.db.commit()
-
- driver.close()
-
- return True
diff --git a/erpnext/setup/utils.py b/erpnext/setup/utils.py
index d1c206d..1a86b79 100644
--- a/erpnext/setup/utils.py
+++ b/erpnext/setup/utils.py
@@ -106,7 +106,8 @@
# expire in 6 hours
response.raise_for_status()
value = response.json()["rates"][to_currency]
- cache.setex(key, value, 6 * 60 * 60)
+
+ cache.set_value(key, value, expires_in_sec=6 * 60 * 60)
return flt(value)
except:
frappe.log_error(title="Get Exchange Rate")
diff --git a/erpnext/shopping_cart/cart.py b/erpnext/shopping_cart/cart.py
index a4c10cf..813d0dd 100644
--- a/erpnext/shopping_cart/cart.py
+++ b/erpnext/shopping_cart/cart.py
@@ -11,6 +11,7 @@
from frappe.utils.nestedset import get_root_of
from erpnext.accounts.utils import get_account_name
from erpnext.utilities.product import get_qty_in_stock
+from frappe.contacts.doctype.contact.contact import get_contact_name
class WebsitePriceListMissingError(frappe.ValidationError):
@@ -65,6 +66,7 @@
from erpnext.selling.doctype.quotation.quotation import _make_sales_order
sales_order = frappe.get_doc(_make_sales_order(quotation.name, ignore_permissions=True))
+ sales_order.payment_schedule = []
if not cint(cart_settings.allow_items_not_in_stock):
for item in sales_order.get("items"):
@@ -371,7 +373,7 @@
if not user:
user = frappe.session.user
- contact_name = frappe.db.get_value("Contact", {"email_id": user})
+ contact_name = get_contact_name(user)
party = None
if contact_name:
@@ -417,7 +419,7 @@
contact = frappe.new_doc("Contact")
contact.update({
"first_name": fullname,
- "email_id": user
+ "email_ids": [{"email_id": user, "is_primary": 1}]
})
contact.append('links', dict(link_doctype='Customer', link_name=customer.name))
contact.flags.ignore_mandatory = True
@@ -504,7 +506,7 @@
if shipping_rules:
rule_label_map = frappe.db.get_values("Shipping Rule", shipping_rules, "label")
# we need this in sorted order as per the position of the rule in the settings page
- return [[rule, rule_label_map.get(rule)] for rule in shipping_rules]
+ return [[rule, rule] for rule in shipping_rules]
def get_shipping_rules(quotation=None, cart_settings=None):
if not quotation:
@@ -562,4 +564,4 @@
frappe.throw(_("Please enter valid coupon code !!"))
else:
frappe.throw(_("Please enter coupon code !!"))
- return quotation
\ No newline at end of file
+ return quotation
diff --git a/erpnext/stock/__init__.py b/erpnext/stock/__init__.py
index 32a03e7..a4d4cbd 100644
--- a/erpnext/stock/__init__.py
+++ b/erpnext/stock/__init__.py
@@ -21,7 +21,7 @@
filters['company'] = company
for d in frappe.get_all('Warehouse',
- fields = ["name", "account", "parent_warehouse", "company"],
+ fields = ["name", "account", "parent_warehouse", "company", "is_group"],
filters = filters,
order_by="lft, rgt"):
if not d.account:
diff --git a/erpnext/stock/doctype/batch/batch.py b/erpnext/stock/doctype/batch/batch.py
index f609a0b..8ae978e 100644
--- a/erpnext/stock/doctype/batch/batch.py
+++ b/erpnext/stock/doctype/batch/batch.py
@@ -185,9 +185,17 @@
def split_batch(batch_no, item_code, warehouse, qty, new_batch_id=None):
"""Split the batch into a new batch"""
batch = frappe.get_doc(dict(doctype='Batch', item=item_code, batch_id=new_batch_id)).insert()
+
+ company = frappe.db.get_value('Stock Ledger Entry', dict(
+ item_code=item_code,
+ batch_no=batch_no,
+ warehouse=warehouse
+ ), ['company'])
+
stock_entry = frappe.get_doc(dict(
doctype='Stock Entry',
purpose='Repack',
+ company=company,
items=[
dict(
item_code=item_code,
@@ -218,16 +226,14 @@
warehouse = d.get(warehouse_field, None)
if has_batch_no and warehouse and qty > 0:
if not d.batch_no:
- d.batch_no = get_batch_no(d.item_code, warehouse, qty, throw)
+ d.batch_no = get_batch_no(d.item_code, warehouse, qty, throw, d.serial_no)
else:
batch_qty = get_batch_qty(batch_no=d.batch_no, warehouse=warehouse)
if flt(batch_qty, d.precision("qty")) < flt(qty, d.precision("qty")):
frappe.throw(_("Row #{0}: The batch {1} has only {2} qty. Please select another batch which has {3} qty available or split the row into multiple rows, to deliver/issue from multiple batches").format(d.idx, d.batch_no, batch_qty, qty))
-
-
@frappe.whitelist()
-def get_batch_no(item_code, warehouse, qty=1, throw=False):
+def get_batch_no(item_code, warehouse, qty=1, throw=False, serial_no=None):
"""
Get batch number using First Expiring First Out method.
:param item_code: `item_code` of Item Document
@@ -237,7 +243,7 @@
"""
batch_no = None
- batches = get_batches(item_code, warehouse, qty, throw)
+ batches = get_batches(item_code, warehouse, qty, throw, serial_no)
for batch in batches:
if cint(qty) <= cint(batch.qty):
@@ -252,16 +258,31 @@
return batch_no
-def get_batches(item_code, warehouse, qty=1, throw=False):
- batches = frappe.db.sql(
- 'select batch_id, sum(actual_qty) as qty from `tabBatch` join `tabStock Ledger Entry` ignore index (item_code, warehouse) '
- 'on (`tabBatch`.batch_id = `tabStock Ledger Entry`.batch_no )'
- 'where `tabStock Ledger Entry`.item_code = %s and `tabStock Ledger Entry`.warehouse = %s '
- 'and (`tabBatch`.expiry_date >= CURDATE() or `tabBatch`.expiry_date IS NULL)'
- 'group by batch_id '
- 'order by `tabBatch`.expiry_date ASC, `tabBatch`.creation ASC',
- (item_code, warehouse),
- as_dict=True
- )
+def get_batches(item_code, warehouse, qty=1, throw=False, serial_no=None):
+ from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
+ cond = ''
+ if serial_no:
+ batch = frappe.get_all("Serial No",
+ fields = ["distinct batch_no"],
+ filters= {
+ "item_code": item_code,
+ "warehouse": warehouse,
+ "name": ("in", get_serial_nos(serial_no))
+ }
+ )
- return batches
+ if batch and len(batch) > 1:
+ return []
+
+ cond = " and `tabBatch`.name = %s" %(frappe.db.escape(batch[0].batch_no))
+
+ return frappe.db.sql("""
+ select batch_id, sum(`tabStock Ledger Entry`.actual_qty) as qty
+ from `tabBatch`
+ join `tabStock Ledger Entry` ignore index (item_code, warehouse)
+ on (`tabBatch`.batch_id = `tabStock Ledger Entry`.batch_no )
+ where `tabStock Ledger Entry`.item_code = %s and `tabStock Ledger Entry`.warehouse = %s
+ and (`tabBatch`.expiry_date >= CURDATE() or `tabBatch`.expiry_date IS NULL) {0}
+ group by batch_id
+ order by `tabBatch`.expiry_date ASC, `tabBatch`.creation ASC
+ """.format(cond), (item_code, warehouse), as_dict=True)
\ No newline at end of file
diff --git a/erpnext/stock/doctype/batch/test_batch.py b/erpnext/stock/doctype/batch/test_batch.py
index 56b4607..32445a6 100644
--- a/erpnext/stock/doctype/batch/test_batch.py
+++ b/erpnext/stock/doctype/batch/test_batch.py
@@ -8,10 +8,13 @@
from erpnext.stock.doctype.batch.batch import get_batch_qty, UnableToSelectBatchError, get_batch_no
from frappe.utils import cint
-
+from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory
class TestBatch(unittest.TestCase):
+ def setUp(self):
+ set_perpetual_inventory(0)
+
def test_item_has_batch_enabled(self):
self.assertRaises(ValidationError, frappe.get_doc({
"doctype": "Batch",
diff --git a/erpnext/stock/doctype/bin/bin.json b/erpnext/stock/doctype/bin/bin.json
index e17429b..04d624e 100644
--- a/erpnext/stock/doctype/bin/bin.json
+++ b/erpnext/stock/doctype/bin/bin.json
@@ -1,599 +1,200 @@
{
- "allow_copy": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "autoname": "MAT-BIN-.YYYY.-.#####",
- "beta": 0,
- "creation": "2013-01-10 16:34:25",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "editable_grid": 0,
- "engine": "InnoDB",
+ "autoname": "MAT-BIN-.YYYY.-.#####",
+ "creation": "2013-01-10 16:34:25",
+ "doctype": "DocType",
+ "engine": "InnoDB",
+ "field_order": [
+ "warehouse",
+ "item_code",
+ "reserved_qty",
+ "actual_qty",
+ "ordered_qty",
+ "indented_qty",
+ "planned_qty",
+ "projected_qty",
+ "reserved_qty_for_production",
+ "reserved_qty_for_sub_contract",
+ "ma_rate",
+ "stock_uom",
+ "fcfs_rate",
+ "valuation_rate",
+ "stock_value"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "warehouse",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 1,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 1,
- "label": "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": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "warehouse",
+ "fieldtype": "Link",
+ "in_filter": 1,
+ "in_list_view": 1,
+ "in_standard_filter": 1,
+ "label": "Warehouse",
+ "oldfieldname": "warehouse",
+ "oldfieldtype": "Link",
+ "options": "Warehouse",
+ "read_only": 1,
+ "search_index": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "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": 1,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 1,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "item_code",
+ "fieldtype": "Link",
+ "in_filter": 1,
+ "in_list_view": 1,
+ "in_standard_filter": 1,
+ "label": "Item Code",
+ "oldfieldname": "item_code",
+ "oldfieldtype": "Link",
+ "options": "Item",
+ "read_only": 1,
+ "search_index": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "0.00",
- "fieldname": "reserved_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": "Reserved Quantity",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "reserved_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,
- "translatable": 0,
- "unique": 0
- },
+ "default": "0.00",
+ "fieldname": "reserved_qty",
+ "fieldtype": "Float",
+ "in_list_view": 1,
+ "label": "Reserved Quantity",
+ "oldfieldname": "reserved_qty",
+ "oldfieldtype": "Currency",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "0.00",
- "fieldname": "actual_qty",
- "fieldtype": "Float",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 1,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Actual Quantity",
- "length": 0,
- "no_copy": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "default": "0.00",
+ "fieldname": "actual_qty",
+ "fieldtype": "Float",
+ "in_filter": 1,
+ "in_list_view": 1,
+ "label": "Actual Quantity",
+ "oldfieldname": "actual_qty",
+ "oldfieldtype": "Currency",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "0.00",
- "fieldname": "ordered_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": "Ordered Quantity",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "ordered_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,
- "translatable": 0,
- "unique": 0
- },
+ "default": "0.00",
+ "fieldname": "ordered_qty",
+ "fieldtype": "Float",
+ "in_list_view": 1,
+ "label": "Ordered Quantity",
+ "oldfieldname": "ordered_qty",
+ "oldfieldtype": "Currency",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "0.00",
- "fieldname": "indented_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": "Requested Quantity",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "indented_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,
- "translatable": 0,
- "unique": 0
- },
+ "default": "0.00",
+ "fieldname": "indented_qty",
+ "fieldtype": "Float",
+ "label": "Requested Quantity",
+ "oldfieldname": "indented_qty",
+ "oldfieldtype": "Currency",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "planned_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": "Planned Qty",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "planned_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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "planned_qty",
+ "fieldtype": "Float",
+ "label": "Planned Qty",
+ "oldfieldname": "planned_qty",
+ "oldfieldtype": "Currency",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "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": 0,
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "projected_qty",
+ "fieldtype": "Float",
+ "label": "Projected Qty",
+ "oldfieldname": "projected_qty",
+ "oldfieldtype": "Currency",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "reserved_qty_for_production",
- "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": "Reserved Qty for Production",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "reserved_qty_for_production",
+ "fieldtype": "Float",
+ "label": "Reserved Qty for Production",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "reserved_qty_for_sub_contract",
- "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": "Reserved Qty for sub contract",
- "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
- },
+ "fieldname": "reserved_qty_for_sub_contract",
+ "fieldtype": "Float",
+ "label": "Reserved Qty for sub contract"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "ma_rate",
- "fieldtype": "Float",
- "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": "Moving Average Rate",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "ma_rate",
- "oldfieldtype": "Currency",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 1,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "ma_rate",
+ "fieldtype": "Float",
+ "hidden": 1,
+ "label": "Moving Average Rate",
+ "oldfieldname": "ma_rate",
+ "oldfieldtype": "Currency",
+ "print_hide": 1,
+ "read_only": 1,
+ "report_hide": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "stock_uom",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 1,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "UOM",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "stock_uom",
- "oldfieldtype": "Data",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "stock_uom",
+ "fieldtype": "Link",
+ "in_filter": 1,
+ "label": "UOM",
+ "oldfieldname": "stock_uom",
+ "oldfieldtype": "Data",
+ "options": "UOM",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "fcfs_rate",
- "fieldtype": "Float",
- "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": "FCFS Rate",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "fcfs_rate",
- "oldfieldtype": "Currency",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 1,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "fcfs_rate",
+ "fieldtype": "Float",
+ "hidden": 1,
+ "label": "FCFS Rate",
+ "oldfieldname": "fcfs_rate",
+ "oldfieldtype": "Currency",
+ "print_hide": 1,
+ "read_only": 1,
+ "report_hide": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "valuation_rate",
- "fieldtype": "Float",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Valuation Rate",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "valuation_rate",
- "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,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "valuation_rate",
+ "fieldtype": "Float",
+ "label": "Valuation Rate",
+ "oldfieldname": "valuation_rate",
+ "oldfieldtype": "Currency",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "stock_value",
- "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": "Stock Value",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "stock_value",
- "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,
- "translatable": 0,
- "unique": 0
+ "fieldname": "stock_value",
+ "fieldtype": "Float",
+ "label": "Stock Value",
+ "oldfieldname": "stock_value",
+ "oldfieldtype": "Currency",
+ "read_only": 1
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 1,
- "idx": 1,
- "image_view": 0,
- "in_create": 1,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2018-08-21 16:15:39.356230",
- "modified_by": "Administrator",
- "module": "Stock",
- "name": "Bin",
- "owner": "Administrator",
+ ],
+ "hide_toolbar": 1,
+ "idx": 1,
+ "in_create": 1,
+ "modified": "2019-11-18 18:34:59.456882",
+ "modified_by": "Administrator",
+ "module": "Stock",
+ "name": "Bin",
+ "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 User",
- "set_user_permissions": 0,
- "share": 0,
- "submit": 0,
- "write": 0
- },
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Sales User"
+ },
{
- "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": "Purchase User",
- "set_user_permissions": 0,
- "share": 0,
- "submit": 0,
- "write": 0
- },
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Purchase User"
+ },
{
- "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": "Stock User",
- "set_user_permissions": 0,
- "share": 0,
- "submit": 0,
- "write": 0
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Stock User"
}
- ],
- "quick_entry": 1,
- "read_only": 0,
- "read_only_onload": 0,
- "search_fields": "item_code,warehouse",
- "show_name_in_global_search": 0,
- "sort_order": "ASC",
- "track_changes": 0,
- "track_seen": 0,
- "track_views": 0
+ ],
+ "quick_entry": 1,
+ "search_fields": "item_code,warehouse",
+ "sort_order": "ASC"
}
\ No newline at end of file
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.json b/erpnext/stock/doctype/delivery_note/delivery_note.json
index 3c6fb48..86200ba 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.json
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.json
@@ -1,4 +1,5 @@
{
+ "actions": [],
"allow_import": 1,
"autoname": "naming_series:",
"creation": "2013-05-24 19:29:09",
@@ -682,7 +683,7 @@
},
{
"fieldname": "other_charges_calculation",
- "fieldtype": "Text",
+ "fieldtype": "Long Text",
"label": "Taxes and Charges Calculation",
"no_copy": 1,
"oldfieldtype": "HTML",
@@ -1238,7 +1239,8 @@
"icon": "fa fa-truck",
"idx": 146,
"is_submittable": 1,
- "modified": "2019-09-27 14:24:20.269682",
+ "links": [],
+ "modified": "2019-12-30 19:17:13.122644",
"modified_by": "Administrator",
"module": "Stock",
"name": "Delivery Note",
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.py b/erpnext/stock/doctype/delivery_note/delivery_note.py
index c98dfe3..39aad2e 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.py
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.py
@@ -424,7 +424,12 @@
target.run_method("calculate_taxes_and_totals")
# set company address
- target.update(get_company_address(target.company))
+ if source.company_address:
+ target.update({'company_address': source.company_address})
+ else:
+ # set company address
+ target.update(get_company_address(target.company))
+
if target.company_address:
target.update(get_fetch_values("Sales Invoice", 'company_address', target.company_address))
diff --git a/erpnext/stock/doctype/delivery_note/regional/india.js b/erpnext/stock/doctype/delivery_note/regional/india.js
new file mode 100644
index 0000000..22f4716
--- /dev/null
+++ b/erpnext/stock/doctype/delivery_note/regional/india.js
@@ -0,0 +1,4 @@
+{% include "erpnext/regional/india/taxes.js" %}
+
+erpnext.setup_auto_gst_taxation('Delivery Note');
+
diff --git a/erpnext/stock/doctype/delivery_note/test_delivery_note.py b/erpnext/stock/doctype/delivery_note/test_delivery_note.py
index 91b6f4c..dc92c5c 100644
--- a/erpnext/stock/doctype/delivery_note/test_delivery_note.py
+++ b/erpnext/stock/doctype/delivery_note/test_delivery_note.py
@@ -20,18 +20,11 @@
import create_stock_reconciliation, set_valuation_method
from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order, create_dn_against_so
from erpnext.accounts.doctype.account.test_account import get_inventory_account, create_account
+from erpnext.stock.doctype.warehouse.test_warehouse import get_warehouse
class TestDeliveryNote(unittest.TestCase):
- def tearDown(self):
- target_warehouse = "_Test Warehouse 1 - _TC"
- company = "_Test Company"
- if not frappe.db.exists("Account", target_warehouse):
- parent_account = frappe.db.get_value('Account',
- {'company': company, 'is_group':1, 'account_type': 'Stock'},'name')
-
- account = create_account(account_name="_Test Warehouse 1", \
- account_type="Stock", parent_account= parent_account, company=company)
- frappe.db.set_value('Warehouse', target_warehouse, 'account', account)
+ def setUp(self):
+ set_perpetual_inventory(0)
def test_over_billing_against_dn(self):
frappe.db.set_value("Stock Settings", None, "allow_negative_stock", 1)
@@ -68,17 +61,16 @@
self.assertFalse(get_gl_entries("Delivery Note", dn.name))
def test_delivery_note_gl_entry(self):
- company = frappe.db.get_value('Warehouse', '_Test Warehouse - _TC', 'company')
- set_perpetual_inventory(1, company)
+ company = frappe.db.get_value('Warehouse', 'Stores - TCP1', 'company')
set_valuation_method("_Test Item", "FIFO")
- make_stock_entry(target="_Test Warehouse - _TC", qty=5, basic_rate=100)
+ make_stock_entry(target="Stores - TCP1", qty=5, basic_rate=100)
- stock_in_hand_account = get_inventory_account('_Test Company')
+ stock_in_hand_account = get_inventory_account('_Test Company with perpetual inventory')
prev_bal = get_balance_on(stock_in_hand_account)
- dn = create_delivery_note()
+ dn = create_delivery_note(company='_Test Company with perpetual inventory', warehouse='Stores - TCP1', cost_center = 'Main - TCP1', expense_account = "Cost of Goods Sold - TCP1")
gl_entries = get_gl_entries("Delivery Note", dn.name)
self.assertTrue(gl_entries)
@@ -88,7 +80,7 @@
expected_values = {
stock_in_hand_account: [0.0, stock_value_difference],
- "Cost of Goods Sold - _TC": [stock_value_difference, 0.0]
+ "Cost of Goods Sold - TCP1": [stock_value_difference, 0.0]
}
for i, gle in enumerate(gl_entries):
self.assertEqual([gle.debit, gle.credit], expected_values.get(gle.account))
@@ -98,7 +90,7 @@
self.assertEqual(bal, prev_bal - stock_value_difference)
# back dated incoming entry
- make_stock_entry(posting_date=add_days(nowdate(), -2), target="_Test Warehouse - _TC",
+ make_stock_entry(posting_date=add_days(nowdate(), -2), target="Stores - TCP1",
qty=5, basic_rate=100)
gl_entries = get_gl_entries("Delivery Note", dn.name)
@@ -109,27 +101,25 @@
expected_values = {
stock_in_hand_account: [0.0, stock_value_difference],
- "Cost of Goods Sold - _TC": [stock_value_difference, 0.0]
+ "Cost of Goods Sold - TCP1": [stock_value_difference, 0.0]
}
for i, gle in enumerate(gl_entries):
self.assertEqual([gle.debit, gle.credit], expected_values.get(gle.account))
dn.cancel()
self.assertFalse(get_gl_entries("Delivery Note", dn.name))
- set_perpetual_inventory(0, company)
def test_delivery_note_gl_entry_packing_item(self):
- company = frappe.db.get_value('Warehouse', '_Test Warehouse - _TC', 'company')
- set_perpetual_inventory(1, company)
+ company = frappe.db.get_value('Warehouse', 'Stores - TCP1', 'company')
- make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC", qty=10, basic_rate=100)
+ make_stock_entry(item_code="_Test Item", target="Stores - TCP1", qty=10, basic_rate=100)
make_stock_entry(item_code="_Test Item Home Desktop 100",
- target="_Test Warehouse - _TC", qty=10, basic_rate=100)
+ target="Stores - TCP1", qty=10, basic_rate=100)
- stock_in_hand_account = get_inventory_account('_Test Company')
+ stock_in_hand_account = get_inventory_account('_Test Company with perpetual inventory')
prev_bal = get_balance_on(stock_in_hand_account)
- dn = create_delivery_note(item_code="_Test Product Bundle Item")
+ dn = create_delivery_note(item_code="_Test Product Bundle Item", company='_Test Company with perpetual inventory', warehouse='Stores - TCP1', cost_center = 'Main - TCP1', expense_account = "Cost of Goods Sold - TCP1")
stock_value_diff_rm1 = abs(frappe.db.get_value("Stock Ledger Entry",
{"voucher_type": "Delivery Note", "voucher_no": dn.name, "item_code": "_Test Item"},
@@ -146,7 +136,7 @@
expected_values = {
stock_in_hand_account: [0.0, stock_value_diff],
- "Cost of Goods Sold - _TC": [stock_value_diff, 0.0]
+ "Cost of Goods Sold - TCP1": [stock_value_diff, 0.0]
}
for i, gle in enumerate(gl_entries):
self.assertEqual([gle.debit, gle.credit], expected_values.get(gle.account))
@@ -158,8 +148,6 @@
dn.cancel()
self.assertFalse(get_gl_entries("Delivery Note", dn.name))
- set_perpetual_inventory(0, company)
-
def test_serialized(self):
se = make_serialized_item()
serial_no = get_serial_nos(se.get("items")[0].serial_no)[0]
@@ -218,16 +206,16 @@
self.assertEqual(cstr(serial_no.get(field)), value)
def test_sales_return_for_non_bundled_items(self):
- company = frappe.db.get_value('Warehouse', '_Test Warehouse - _TC', 'company')
- set_perpetual_inventory(1, company)
+ company = frappe.db.get_value('Warehouse', 'Stores - TCP1', 'company')
- make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC", qty=50, basic_rate=100)
+ make_stock_entry(item_code="_Test Item", target="Stores - TCP1", qty=50, basic_rate=100)
- actual_qty_0 = get_qty_after_transaction()
+ actual_qty_0 = get_qty_after_transaction(warehouse="Stores - TCP1")
- dn = create_delivery_note(qty=5, rate=500)
+ dn = create_delivery_note(qty=5, rate=500, warehouse="Stores - TCP1", company=company,
+ expense_account="Cost of Goods Sold - TCP1", cost_center="Main - TCP1")
- actual_qty_1 = get_qty_after_transaction()
+ actual_qty_1 = get_qty_after_transaction(warehouse="Stores - TCP1")
self.assertEqual(actual_qty_0 - 5, actual_qty_1)
# outgoing_rate
@@ -235,9 +223,10 @@
"voucher_no": dn.name}, "stock_value_difference") / 5
# return entry
- dn1 = create_delivery_note(is_return=1, return_against=dn.name, qty=-2, rate=500)
+ dn1 = create_delivery_note(is_return=1, return_against=dn.name, qty=-2, rate=500,
+ company=company, warehouse="Stores - TCP1", expense_account="Cost of Goods Sold - TCP1", cost_center="Main - TCP1")
- actual_qty_2 = get_qty_after_transaction()
+ actual_qty_2 = get_qty_after_transaction(warehouse="Stores - TCP1")
self.assertEqual(actual_qty_1 + 2, actual_qty_2)
@@ -246,27 +235,29 @@
["incoming_rate", "stock_value_difference"])
self.assertEqual(flt(incoming_rate, 3), abs(flt(outgoing_rate, 3)))
- stock_in_hand_account = get_inventory_account('_Test Company', dn1.items[0].warehouse)
+ stock_in_hand_account = get_inventory_account(company, dn1.items[0].warehouse)
gle_warehouse_amount = frappe.db.get_value("GL Entry", {"voucher_type": "Delivery Note",
"voucher_no": dn1.name, "account": stock_in_hand_account}, "debit")
self.assertEqual(gle_warehouse_amount, stock_value_difference)
- set_perpetual_inventory(0, company)
-
def test_return_single_item_from_bundled_items(self):
- company = frappe.db.get_value('Warehouse', '_Test Warehouse - _TC', 'company')
- set_perpetual_inventory(1, company)
+ company = frappe.db.get_value('Warehouse', 'Stores - TCP1', 'company')
- create_stock_reconciliation(item_code="_Test Item", target="_Test Warehouse - _TC", qty=50, rate=100)
- create_stock_reconciliation(item_code="_Test Item Home Desktop 100", target="_Test Warehouse - _TC",
- qty=50, rate=100)
+ create_stock_reconciliation(item_code="_Test Item",
+ warehouse="Stores - TCP1", qty=50, rate=100,
+ company=company, expense_account = "Stock Adjustment - TCP1")
+ create_stock_reconciliation(item_code="_Test Item Home Desktop 100",
+ warehouse="Stores - TCP1", qty=50, rate=100,
+ company=company, expense_account = "Stock Adjustment - TCP1")
- dn = create_delivery_note(item_code="_Test Product Bundle Item", qty=5, rate=500)
+ dn = create_delivery_note(item_code="_Test Product Bundle Item", qty=5, rate=500,
+ company=company, warehouse="Stores - TCP1",
+ expense_account="Cost of Goods Sold - TCP1", cost_center="Main - TCP1")
# Qty after delivery
- actual_qty_1 = get_qty_after_transaction()
+ actual_qty_1 = get_qty_after_transaction(warehouse="Stores - TCP1")
self.assertEqual(actual_qty_1, 25)
# outgoing_rate
@@ -274,10 +265,12 @@
"voucher_no": dn.name, "item_code": "_Test Item"}, "stock_value_difference") / 25
# return 'test item' from packed items
- dn1 = create_delivery_note(is_return=1, return_against=dn.name, qty=-10, rate=500)
+ dn1 = create_delivery_note(is_return=1, return_against=dn.name, qty=-10, rate=500,
+ company=company, warehouse="Stores - TCP1",
+ expense_account="Cost of Goods Sold - TCP1", cost_center="Main - TCP1")
# qty after return
- actual_qty_2 = get_qty_after_transaction()
+ actual_qty_2 = get_qty_after_transaction(warehouse="Stores - TCP1")
self.assertEqual(actual_qty_2, 35)
# Check incoming rate for return entry
@@ -286,7 +279,7 @@
["incoming_rate", "stock_value_difference"])
self.assertEqual(flt(incoming_rate, 3), abs(flt(outgoing_rate, 3)))
- stock_in_hand_account = get_inventory_account('_Test Company', dn1.items[0].warehouse)
+ stock_in_hand_account = get_inventory_account(company, dn1.items[0].warehouse)
# Check gl entry for warehouse
gle_warehouse_amount = frappe.db.get_value("GL Entry", {"voucher_type": "Delivery Note",
@@ -294,33 +287,33 @@
self.assertEqual(gle_warehouse_amount, stock_value_difference)
- set_perpetual_inventory(0, company)
def test_return_entire_bundled_items(self):
- company = frappe.db.get_value('Warehouse', '_Test Warehouse - _TC', 'company')
- set_perpetual_inventory(1, company)
+ company = frappe.db.get_value('Warehouse', 'Stores - TCP1', 'company')
create_stock_reconciliation(item_code="_Test Item",
- target="_Test Warehouse - _TC", qty=50, rate=100)
+ warehouse="Stores - TCP1", qty=50, rate=100,
+ company=company, expense_account = "Stock Adjustment - TCP1")
create_stock_reconciliation(item_code="_Test Item Home Desktop 100",
- target="_Test Warehouse - _TC", qty=50, rate=100)
+ warehouse="Stores - TCP1", qty=50, rate=100,
+ company=company, expense_account = "Stock Adjustment - TCP1")
- actual_qty = get_qty_after_transaction()
+ actual_qty = get_qty_after_transaction(warehouse="Stores - TCP1")
self.assertEqual(actual_qty, 50)
dn = create_delivery_note(item_code="_Test Product Bundle Item",
- qty=5, rate=500)
+ qty=5, rate=500, company=company, warehouse="Stores - TCP1", expense_account="Cost of Goods Sold - TCP1", cost_center="Main - TCP1")
# qty after return
- actual_qty = get_qty_after_transaction()
+ actual_qty = get_qty_after_transaction(warehouse="Stores - TCP1")
self.assertEqual(actual_qty, 25)
# return bundled item
dn1 = create_delivery_note(item_code='_Test Product Bundle Item', is_return=1,
- return_against=dn.name, qty=-2, rate=500)
+ return_against=dn.name, qty=-2, rate=500, company=company, warehouse="Stores - TCP1", expense_account="Cost of Goods Sold - TCP1", cost_center="Main - TCP1")
# qty after return
- actual_qty = get_qty_after_transaction()
+ actual_qty = get_qty_after_transaction(warehouse="Stores - TCP1")
self.assertEqual(actual_qty, 35)
# Check incoming rate for return entry
@@ -337,8 +330,6 @@
self.assertEqual(gle_warehouse_amount, 1400)
- set_perpetual_inventory(0, company)
-
def test_return_for_serialized_items(self):
se = make_serialized_item()
serial_no = get_serial_nos(se.get("items")[0].serial_no)[0]
@@ -375,56 +366,44 @@
})
def test_delivery_of_bundled_items_to_target_warehouse(self):
- company = frappe.db.get_value('Warehouse', '_Test Warehouse - _TC', 'company')
- set_perpetual_inventory(1, company)
+ company = frappe.db.get_value('Warehouse', 'Stores - TCP1', 'company')
set_valuation_method("_Test Item", "FIFO")
set_valuation_method("_Test Item Home Desktop 100", "FIFO")
- for warehouse in ("_Test Warehouse - _TC", "_Test Warehouse 1 - _TC"):
- create_stock_reconciliation(item_code="_Test Item", target=warehouse,
- qty=100, rate=100)
- create_stock_reconciliation(item_code="_Test Item Home Desktop 100",
- target=warehouse, qty=100, rate=100)
+ target_warehouse=get_warehouse(company=company, abbr="TCP1",
+ warehouse_name="_Test Customer Warehouse").name
- opening_qty_test_warehouse_1 = get_qty_after_transaction(warehouse="_Test Warehouse 1 - _TC")
+ for warehouse in ("Stores - TCP1", target_warehouse):
+ create_stock_reconciliation(item_code="_Test Item", warehouse=warehouse, company = company,
+ expense_account = "Stock Adjustment - TCP1", qty=500, rate=100)
+ create_stock_reconciliation(item_code="_Test Item Home Desktop 100", company = company,
+ expense_account = "Stock Adjustment - TCP1", warehouse=warehouse, qty=500, rate=100)
+
dn = create_delivery_note(item_code="_Test Product Bundle Item",
- qty=5, rate=500, target_warehouse="_Test Warehouse 1 - _TC", do_not_submit=True)
+ company='_Test Company with perpetual inventory', cost_center = 'Main - TCP1',
+ expense_account = "Cost of Goods Sold - TCP1", do_not_submit=True, qty=5, rate=500,
+ warehouse="Stores - TCP1", target_warehouse=target_warehouse)
dn.submit()
# qty after delivery
- actual_qty = get_qty_after_transaction(warehouse="_Test Warehouse - _TC")
- self.assertEqual(actual_qty, 75)
+ actual_qty_at_source = get_qty_after_transaction(warehouse="Stores - TCP1")
+ self.assertEqual(actual_qty_at_source, 475)
- actual_qty = get_qty_after_transaction(warehouse="_Test Warehouse 1 - _TC")
- self.assertEqual(actual_qty, opening_qty_test_warehouse_1 + 25)
+ actual_qty_at_target = get_qty_after_transaction(warehouse=target_warehouse)
+ self.assertEqual(actual_qty_at_target, 525)
- # stock value diff for source warehouse
- # for "_Test Item"
+ # stock value diff for source warehouse for "_Test Item"
stock_value_difference = frappe.db.get_value("Stock Ledger Entry",
{"voucher_type": "Delivery Note", "voucher_no": dn.name,
- "item_code": "_Test Item", "warehouse": "_Test Warehouse - _TC"},
+ "item_code": "_Test Item", "warehouse": "Stores - TCP1"},
"stock_value_difference")
# stock value diff for target warehouse
stock_value_difference1 = frappe.db.get_value("Stock Ledger Entry",
{"voucher_type": "Delivery Note", "voucher_no": dn.name,
- "item_code": "_Test Item", "warehouse": "_Test Warehouse 1 - _TC"},
- "stock_value_difference")
-
- self.assertEqual(abs(stock_value_difference), stock_value_difference1)
-
- # for "_Test Item Home Desktop 100"
- stock_value_difference = frappe.db.get_value("Stock Ledger Entry",
- {"voucher_type": "Delivery Note", "voucher_no": dn.name,
- "item_code": "_Test Item Home Desktop 100", "warehouse": "_Test Warehouse - _TC"},
- "stock_value_difference")
-
- # stock value diff for target warehouse
- stock_value_difference1 = frappe.db.get_value("Stock Ledger Entry",
- {"voucher_type": "Delivery Note", "voucher_no": dn.name,
- "item_code": "_Test Item Home Desktop 100", "warehouse": "_Test Warehouse 1 - _TC"},
+ "item_code": "_Test Item", "warehouse": target_warehouse},
"stock_value_difference")
self.assertEqual(abs(stock_value_difference), stock_value_difference1)
@@ -435,21 +414,20 @@
stock_value_difference = abs(frappe.db.sql("""select sum(stock_value_difference)
from `tabStock Ledger Entry` where voucher_type='Delivery Note' and voucher_no=%s
- and warehouse='_Test Warehouse - _TC'""", dn.name)[0][0])
+ and warehouse='Stores - TCP1'""", dn.name)[0][0])
expected_values = {
- "Stock In Hand - _TC": [0.0, stock_value_difference],
- "_Test Warehouse 1 - _TC": [stock_value_difference, 0.0]
+ "Stock In Hand - TCP1": [0.0, stock_value_difference],
+ target_warehouse: [stock_value_difference, 0.0]
}
for i, gle in enumerate(gl_entries):
self.assertEqual([gle.debit, gle.credit], expected_values.get(gle.account))
- set_perpetual_inventory(0, company)
-
def test_closed_delivery_note(self):
from erpnext.stock.doctype.delivery_note.delivery_note import update_delivery_note_status
- dn = create_delivery_note(do_not_submit=True)
+ dn = create_delivery_note(company='_Test Company with perpetual inventory', warehouse='Stores - TCP1', cost_center = 'Main - TCP1', expense_account = "Cost of Goods Sold - TCP1", do_not_submit=True)
+
dn.submit()
update_delivery_note_status(dn.name, "Closed")
@@ -574,24 +552,23 @@
accounts_settings = frappe.get_doc('Accounts Settings', 'Accounts Settings')
accounts_settings.allow_cost_center_in_entry_of_bs_account = 1
accounts_settings.save()
- cost_center = "_Test Cost Center for BS Account - _TC"
- create_cost_center(cost_center_name="_Test Cost Center for BS Account", company="_Test Company")
+ cost_center = "_Test Cost Center for BS Account - TCP1"
+ create_cost_center(cost_center_name="_Test Cost Center for BS Account", company="_Test Company with perpetual inventory")
- company = frappe.db.get_value('Warehouse', '_Test Warehouse - _TC', 'company')
- set_perpetual_inventory(1, company)
+ company = frappe.db.get_value('Warehouse', 'Stores - TCP1', 'company')
set_valuation_method("_Test Item", "FIFO")
- make_stock_entry(target="_Test Warehouse - _TC", qty=5, basic_rate=100)
+ make_stock_entry(target="Stores - TCP1", qty=5, basic_rate=100)
- stock_in_hand_account = get_inventory_account('_Test Company')
- dn = create_delivery_note(cost_center=cost_center)
+ stock_in_hand_account = get_inventory_account('_Test Company with perpetual inventory')
+ dn = create_delivery_note(company='_Test Company with perpetual inventory', warehouse='Stores - TCP1', expense_account = "Cost of Goods Sold - TCP1", cost_center=cost_center)
gl_entries = get_gl_entries("Delivery Note", dn.name)
self.assertTrue(gl_entries)
expected_values = {
- "Cost of Goods Sold - _TC": {
+ "Cost of Goods Sold - TCP1": {
"cost_center": cost_center
},
stock_in_hand_account: {
@@ -600,8 +577,6 @@
}
for i, gle in enumerate(gl_entries):
self.assertEqual(expected_values[gle.account]["cost_center"], gle.cost_center)
-
- set_perpetual_inventory(0, company)
accounts_settings.allow_cost_center_in_entry_of_bs_account = 0
accounts_settings.save()
@@ -609,23 +584,22 @@
accounts_settings = frappe.get_doc('Accounts Settings', 'Accounts Settings')
accounts_settings.allow_cost_center_in_entry_of_bs_account = 0
accounts_settings.save()
- cost_center = "_Test Cost Center - _TC"
+ cost_center = "Main - TCP1"
- company = frappe.db.get_value('Warehouse', '_Test Warehouse - _TC', 'company')
- set_perpetual_inventory(1, company)
+ company = frappe.db.get_value('Warehouse', 'Stores - TCP1', 'company')
set_valuation_method("_Test Item", "FIFO")
- make_stock_entry(target="_Test Warehouse - _TC", qty=5, basic_rate=100)
+ make_stock_entry(target="Stores - TCP1", qty=5, basic_rate=100)
- stock_in_hand_account = get_inventory_account('_Test Company')
- dn = create_delivery_note()
+ stock_in_hand_account = get_inventory_account('_Test Company with perpetual inventory')
+ dn = create_delivery_note(company='_Test Company with perpetual inventory', warehouse='Stores - TCP1', cost_center = 'Main - TCP1', expense_account = "Cost of Goods Sold - TCP1")
gl_entries = get_gl_entries("Delivery Note", dn.name)
self.assertTrue(gl_entries)
expected_values = {
- "Cost of Goods Sold - _TC": {
+ "Cost of Goods Sold - TCP1": {
"cost_center": cost_center
},
stock_in_hand_account: {
@@ -635,8 +609,6 @@
for i, gle in enumerate(gl_entries):
self.assertEqual(expected_values[gle.account]["cost_center"], gle.cost_center)
- set_perpetual_inventory(0, company)
-
def test_make_sales_invoice_from_dn_for_returned_qty(self):
from erpnext.selling.doctype.sales_order.sales_order import make_delivery_note
from erpnext.stock.doctype.delivery_note.delivery_note import make_sales_invoice
@@ -702,7 +674,7 @@
"rate": args.rate or 100,
"conversion_factor": 1.0,
"allow_zero_valuation_rate": args.allow_zero_valuation_rate or 1,
- "expense_account": "Cost of Goods Sold - _TC",
+ "expense_account": args.expense_account or "Cost of Goods Sold - _TC",
"cost_center": args.cost_center or "_Test Cost Center - _TC",
"serial_no": args.serial_no,
"target_warehouse": args.target_warehouse
diff --git a/erpnext/stock/doctype/delivery_trip/delivery_trip.js b/erpnext/stock/doctype/delivery_trip/delivery_trip.js
index 6a7eecf..a025f06 100755
--- a/erpnext/stock/doctype/delivery_trip/delivery_trip.js
+++ b/erpnext/stock/doctype/delivery_trip/delivery_trip.js
@@ -79,6 +79,21 @@
}, () => {
frm.reload_doc();
});
+ },
+
+ driver: function (frm) {
+ if (frm.doc.driver) {
+ frappe.call({
+ method: "erpnext.stock.doctype.delivery_trip.delivery_trip.get_driver_email",
+ args: {
+ driver: frm.doc.driver
+ },
+ callback: (data) => {
+ frm.set_value("driver_email", data.message.email);
+ }
+ });
+ };
+ },
},
@@ -196,4 +211,4 @@
frappe.model.set_value(cdt, cdn, "customer_contact", "");
}
}
-});
\ No newline at end of file
+});
diff --git a/erpnext/stock/doctype/delivery_trip/delivery_trip.json b/erpnext/stock/doctype/delivery_trip/delivery_trip.json
index 0a52624..1bacf46 100644
--- a/erpnext/stock/doctype/delivery_trip/delivery_trip.json
+++ b/erpnext/stock/doctype/delivery_trip/delivery_trip.json
@@ -1,4 +1,5 @@
{
+ "actions": [],
"autoname": "naming_series:",
"creation": "2017-10-16 16:45:48.293335",
"doctype": "DocType",
@@ -13,6 +14,7 @@
"section_break_3",
"driver",
"driver_name",
+ "driver_email",
"driver_address",
"total_distance",
"uom",
@@ -167,10 +169,17 @@
"fieldtype": "Link",
"label": "Driver Address",
"options": "Address"
+ },
+ {
+ "fieldname": "driver_email",
+ "fieldtype": "Data",
+ "label": "Driver Email",
+ "read_only": 1
}
],
"is_submittable": 1,
- "modified": "2019-09-27 15:43:01.975139",
+ "links": [],
+ "modified": "2019-12-06 17:06:59.681952",
"modified_by": "Administrator",
"module": "Stock",
"name": "Delivery Trip",
diff --git a/erpnext/stock/doctype/delivery_trip/delivery_trip.py b/erpnext/stock/doctype/delivery_trip/delivery_trip.py
index 77d322e..e2c5b91 100644
--- a/erpnext/stock/doctype/delivery_trip/delivery_trip.py
+++ b/erpnext/stock/doctype/delivery_trip/delivery_trip.py
@@ -387,3 +387,9 @@
file_name="Delivery Note", print_format=dispatch_attachment)
return [attachments]
+
+@frappe.whitelist()
+def get_driver_email(driver):
+ employee = frappe.db.get_value("Driver", driver, "employee")
+ email = frappe.db.get_value("Employee", employee, "prefered_email")
+ return {"email": email}
diff --git a/erpnext/stock/doctype/item/item.js b/erpnext/stock/doctype/item/item.js
index bfc5e6d..253390a 100644
--- a/erpnext/stock/doctype/item/item.js
+++ b/erpnext/stock/doctype/item/item.js
@@ -25,7 +25,7 @@
},
refresh: function(frm) {
- if(frm.doc.is_stock_item) {
+ if (frm.doc.is_stock_item) {
frm.add_custom_button(__("Balance"), function() {
frappe.route_options = {
"item_code": frm.doc.name
@@ -46,10 +46,15 @@
}, __("View"));
}
- if(!frm.doc.is_fixed_asset) {
+ if (!frm.doc.is_fixed_asset) {
erpnext.item.make_dashboard(frm);
}
+ if (frm.doc.is_fixed_asset) {
+ frm.trigger('is_fixed_asset');
+ frm.trigger('auto_create_assets');
+ }
+
// clear intro
frm.set_intro();
@@ -131,7 +136,27 @@
frm.toggle_reqd('customer', frm.doc.is_customer_provided_item ? 1:0);
},
+ gst_hsn_code: function(frm) {
+ if(!frm.doc.taxes.length) {
+ frappe.db.get_doc("GST HSN Code", frm.doc.gst_hsn_code).then(hsn_doc => {
+ $.each(hsn_doc.taxes || [], function(i, tax) {
+ let a = frappe.model.add_child(cur_frm.doc, 'Item Tax', 'taxes');
+ a.item_tax_template = tax.item_tax_template;
+ a.tax_category = tax.tax_category;
+ a.valid_from = tax.valid_from;
+ frm.refresh_field('taxes');
+ });
+ });
+ }
+ },
+
is_fixed_asset: function(frm) {
+ // set serial no to false & toggles its visibility
+ frm.set_value('has_serial_no', 0);
+ frm.toggle_enable(['has_serial_no', 'serial_no_series'], !frm.doc.is_fixed_asset);
+ frm.toggle_reqd(['asset_category'], frm.doc.is_fixed_asset);
+ frm.toggle_display(['has_serial_no', 'serial_no_series'], !frm.doc.is_fixed_asset);
+
frm.call({
method: "set_asset_naming_series",
doc: frm.doc,
@@ -139,7 +164,9 @@
frm.set_value("is_stock_item", frm.doc.is_fixed_asset ? 0 : 1);
frm.trigger("set_asset_naming_series");
}
- })
+ });
+
+ frm.trigger('auto_create_assets');
},
set_asset_naming_series: function(frm) {
@@ -148,6 +175,11 @@
}
},
+ auto_create_assets: function(frm) {
+ frm.toggle_reqd(['asset_naming_series'], frm.doc.auto_create_assets);
+ frm.toggle_display(['asset_naming_series'], frm.doc.auto_create_assets);
+ },
+
page_name: frappe.utils.warn_page_name_change,
item_code: function(frm) {
diff --git a/erpnext/stock/doctype/item/item.json b/erpnext/stock/doctype/item/item.json
index 46efd4e..3503e7c 100644
--- a/erpnext/stock/doctype/item/item.json
+++ b/erpnext/stock/doctype/item/item.json
@@ -1,1105 +1,1110 @@
{
- "allow_guest_to_view": 1,
- "allow_import": 1,
- "allow_rename": 1,
- "autoname": "field:item_code",
- "creation": "2013-05-03 10:45:46",
- "description": "A Product or a Service that is bought, sold or kept in stock.",
- "doctype": "DocType",
- "document_type": "Setup",
- "editable_grid": 1,
- "engine": "InnoDB",
- "field_order": [
- "name_and_description_section",
- "naming_series",
- "item_code",
- "variant_of",
- "item_name",
- "item_group",
- "is_item_from_hub",
- "stock_uom",
- "column_break0",
- "disabled",
- "allow_alternative_item",
- "is_stock_item",
- "include_item_in_manufacturing",
- "opening_stock",
- "valuation_rate",
- "standard_rate",
- "is_fixed_asset",
- "asset_category",
- "asset_naming_series",
- "over_delivery_receipt_allowance",
- "over_billing_allowance",
- "image",
- "section_break_11",
- "brand",
- "description",
- "sb_barcodes",
- "barcodes",
- "inventory_section",
- "shelf_life_in_days",
- "end_of_life",
- "default_material_request_type",
- "valuation_method",
- "column_break1",
- "warranty_period",
- "weight_per_unit",
- "weight_uom",
- "reorder_section",
- "reorder_levels",
- "unit_of_measure_conversion",
- "uoms",
- "serial_nos_and_batches",
- "has_batch_no",
- "create_new_batch",
- "batch_number_series",
- "has_expiry_date",
- "retain_sample",
- "sample_quantity",
- "column_break_37",
- "has_serial_no",
- "serial_no_series",
- "variants_section",
- "has_variants",
- "variant_based_on",
- "attributes",
- "defaults",
- "item_defaults",
- "purchase_details",
- "is_purchase_item",
- "purchase_uom",
- "min_order_qty",
- "safety_stock",
- "purchase_details_cb",
- "lead_time_days",
- "last_purchase_rate",
- "is_customer_provided_item",
- "customer",
- "supplier_details",
- "delivered_by_supplier",
- "column_break2",
- "supplier_items",
- "foreign_trade_details",
- "country_of_origin",
- "column_break_59",
- "customs_tariff_number",
- "sales_details",
- "sales_uom",
- "is_sales_item",
- "column_break3",
- "max_discount",
- "deferred_revenue",
- "deferred_revenue_account",
- "enable_deferred_revenue",
- "column_break_85",
- "no_of_months",
- "deferred_expense_section",
- "deferred_expense_account",
- "enable_deferred_expense",
- "column_break_88",
- "no_of_months_exp",
- "customer_details",
- "customer_items",
- "item_tax_section_break",
- "taxes",
- "inspection_criteria",
- "inspection_required_before_purchase",
- "inspection_required_before_delivery",
- "quality_inspection_template",
- "manufacturing",
- "default_bom",
- "is_sub_contracted_item",
- "column_break_74",
- "customer_code",
- "website_section",
- "show_in_website",
- "show_variant_in_website",
- "route",
- "weightage",
- "slideshow",
- "website_image",
- "thumbnail",
- "cb72",
- "website_warehouse",
- "website_item_groups",
- "set_meta_tags",
- "sb72",
- "copy_from_item_group",
- "website_specifications",
- "web_long_description",
- "website_content",
- "total_projected_qty",
- "hub_publishing_sb",
- "publish_in_hub",
- "hub_category_to_publish",
- "hub_warehouse",
- "synced_with_hub"
- ],
- "fields": [
- {
- "fieldname": "name_and_description_section",
- "fieldtype": "Section Break",
- "oldfieldtype": "Section Break",
- "options": "fa fa-flag"
- },
- {
- "fieldname": "naming_series",
- "fieldtype": "Select",
- "label": "Series",
- "options": "STO-ITEM-.YYYY.-",
- "set_only_once": 1
- },
- {
- "bold": 1,
- "fieldname": "item_code",
- "fieldtype": "Data",
- "in_global_search": 1,
- "label": "Item Code",
- "oldfieldname": "item_code",
- "oldfieldtype": "Data",
- "unique": 1,
- "reqd": 1
- },
- {
- "depends_on": "variant_of",
- "description": "If item is a variant of another item then description, image, pricing, taxes etc will be set from the template unless explicitly specified",
- "fieldname": "variant_of",
- "fieldtype": "Link",
- "ignore_user_permissions": 1,
- "in_standard_filter": 1,
- "label": "Variant Of",
- "options": "Item",
- "read_only": 1,
- "search_index": 1,
- "set_only_once": 1
- },
- {
- "bold": 1,
- "fieldname": "item_name",
- "fieldtype": "Data",
- "in_global_search": 1,
- "label": "Item Name",
- "oldfieldname": "item_name",
- "oldfieldtype": "Data",
- "search_index": 1
- },
- {
- "fieldname": "item_group",
- "fieldtype": "Link",
- "in_list_view": 1,
- "in_preview": 1,
- "in_standard_filter": 1,
- "label": "Item Group",
- "oldfieldname": "item_group",
- "oldfieldtype": "Link",
- "options": "Item Group",
- "reqd": 1,
- "search_index": 1
- },
- {
- "default": "0",
- "fieldname": "is_item_from_hub",
- "fieldtype": "Check",
- "label": "Is Item from Hub",
- "read_only": 1
- },
- {
- "fieldname": "stock_uom",
- "fieldtype": "Link",
- "ignore_user_permissions": 1,
- "label": "Default Unit of Measure",
- "oldfieldname": "stock_uom",
- "oldfieldtype": "Link",
- "options": "UOM",
- "reqd": 1
- },
- {
- "fieldname": "column_break0",
- "fieldtype": "Column Break"
- },
- {
- "default": "0",
- "fieldname": "disabled",
- "fieldtype": "Check",
- "label": "Disabled"
- },
- {
- "default": "0",
- "fieldname": "allow_alternative_item",
- "fieldtype": "Check",
- "label": "Allow Alternative Item"
- },
- {
- "bold": 1,
- "default": "1",
- "fieldname": "is_stock_item",
- "fieldtype": "Check",
- "label": "Maintain Stock",
- "oldfieldname": "is_stock_item",
- "oldfieldtype": "Select"
- },
- {
- "default": "1",
- "fieldname": "include_item_in_manufacturing",
- "fieldtype": "Check",
- "label": "Include Item In Manufacturing"
- },
- {
- "bold": 1,
- "depends_on": "eval:(doc.__islocal&&doc.is_stock_item && !doc.has_serial_no && !doc.has_batch_no)",
- "fieldname": "opening_stock",
- "fieldtype": "Float",
- "label": "Opening Stock"
- },
- {
- "depends_on": "is_stock_item",
- "fieldname": "valuation_rate",
- "fieldtype": "Currency",
- "label": "Valuation Rate"
- },
- {
- "bold": 1,
- "depends_on": "eval:doc.__islocal",
- "fieldname": "standard_rate",
- "fieldtype": "Currency",
- "label": "Standard Selling Rate"
- },
- {
- "default": "0",
- "fieldname": "is_fixed_asset",
- "fieldtype": "Check",
- "label": "Is Fixed Asset",
- "set_only_once": 1
- },
- {
- "depends_on": "is_fixed_asset",
- "fieldname": "asset_category",
- "fieldtype": "Link",
- "label": "Asset Category",
- "options": "Asset Category"
- },
- {
- "depends_on": "is_fixed_asset",
- "fieldname": "asset_naming_series",
- "fieldtype": "Select",
- "label": "Asset Naming Series"
- },
- {
- "fieldname": "image",
- "fieldtype": "Attach Image",
- "hidden": 1,
- "in_preview": 1,
- "label": "Image",
- "options": "image",
- "print_hide": 1
- },
- {
- "collapsible": 1,
- "fieldname": "section_break_11",
- "fieldtype": "Section Break",
- "label": "Description"
- },
- {
- "fieldname": "brand",
- "fieldtype": "Link",
- "label": "Brand",
- "oldfieldname": "brand",
- "oldfieldtype": "Link",
- "options": "Brand",
- "print_hide": 1
- },
- {
- "fieldname": "description",
- "fieldtype": "Text Editor",
- "in_preview": 1,
- "label": "Description",
- "oldfieldname": "description",
- "oldfieldtype": "Text"
- },
- {
- "fieldname": "sb_barcodes",
- "fieldtype": "Section Break",
- "label": "Barcodes"
- },
- {
- "fieldname": "barcodes",
- "fieldtype": "Table",
- "label": "Barcodes",
- "options": "Item Barcode"
- },
- {
- "collapsible": 1,
- "collapsible_depends_on": "is_stock_item",
- "depends_on": "is_stock_item",
- "fieldname": "inventory_section",
- "fieldtype": "Section Break",
- "label": "Inventory",
- "oldfieldtype": "Section Break",
- "options": "fa fa-truck"
- },
- {
- "fieldname": "shelf_life_in_days",
- "fieldtype": "Int",
- "label": "Shelf Life In Days"
- },
- {
- "default": "2099-12-31",
- "depends_on": "is_stock_item",
- "fieldname": "end_of_life",
- "fieldtype": "Date",
- "label": "End of Life",
- "oldfieldname": "end_of_life",
- "oldfieldtype": "Date"
- },
- {
- "default": "Purchase",
- "fieldname": "default_material_request_type",
- "fieldtype": "Select",
- "label": "Default Material Request Type",
- "options": "Purchase\nMaterial Transfer\nMaterial Issue\nManufacture\nCustomer Provided"
- },
- {
- "depends_on": "is_stock_item",
- "fieldname": "valuation_method",
- "fieldtype": "Select",
- "label": "Valuation Method",
- "options": "\nFIFO\nMoving Average",
- "set_only_once": 1
- },
- {
- "depends_on": "is_stock_item",
- "fieldname": "column_break1",
- "fieldtype": "Column Break",
- "oldfieldtype": "Column Break",
- "width": "50%"
- },
- {
- "depends_on": "eval:doc.is_stock_item",
- "fieldname": "warranty_period",
- "fieldtype": "Data",
- "label": "Warranty Period (in days)",
- "oldfieldname": "warranty_period",
- "oldfieldtype": "Data"
- },
- {
- "depends_on": "is_stock_item",
- "fieldname": "weight_per_unit",
- "fieldtype": "Float",
- "label": "Weight Per Unit"
- },
- {
- "depends_on": "eval:doc.is_stock_item",
- "fieldname": "weight_uom",
- "fieldtype": "Link",
- "ignore_user_permissions": 1,
- "label": "Weight UOM",
- "options": "UOM"
- },
- {
- "collapsible": 1,
- "depends_on": "is_stock_item",
- "fieldname": "reorder_section",
- "fieldtype": "Section Break",
- "label": "Auto re-order",
- "options": "fa fa-rss"
- },
- {
- "description": "Will also apply for variants unless overrridden",
- "fieldname": "reorder_levels",
- "fieldtype": "Table",
- "label": "Reorder level based on Warehouse",
- "options": "Item Reorder"
- },
- {
- "collapsible": 1,
- "fieldname": "unit_of_measure_conversion",
- "fieldtype": "Section Break",
- "label": "Units of Measure"
- },
- {
- "description": "Will also apply for variants",
- "fieldname": "uoms",
- "fieldtype": "Table",
- "label": "UOMs",
- "oldfieldname": "uom_conversion_details",
- "oldfieldtype": "Table",
- "options": "UOM Conversion Detail"
- },
- {
- "collapsible": 1,
- "collapsible_depends_on": "eval:doc.has_batch_no || doc.has_serial_no || doc.is_fixed_asset",
- "depends_on": "eval:doc.is_stock_item || doc.is_fixed_asset",
- "fieldname": "serial_nos_and_batches",
- "fieldtype": "Section Break",
- "label": "Serial Nos and Batches"
- },
- {
- "default": "0",
- "depends_on": "eval:doc.is_stock_item",
- "fieldname": "has_batch_no",
- "fieldtype": "Check",
- "label": "Has Batch No",
- "no_copy": 1,
- "oldfieldname": "has_batch_no",
- "oldfieldtype": "Select"
- },
- {
- "default": "0",
- "depends_on": "has_batch_no",
- "fieldname": "create_new_batch",
- "fieldtype": "Check",
- "label": "Automatically Create New Batch"
- },
- {
- "depends_on": "eval:doc.has_batch_no==1 && doc.create_new_batch==1",
- "description": "Example: ABCD.#####. If series is set and Batch No is not mentioned in transactions, then automatic batch number will be created based on this series. If you always want to explicitly mention Batch No for this item, leave this blank. Note: this setting will take priority over the Naming Series Prefix in Stock Settings.",
- "fieldname": "batch_number_series",
- "fieldtype": "Data",
- "label": "Batch Number Series",
- "translatable": 1
- },
- {
- "default": "0",
- "depends_on": "has_batch_no",
- "fieldname": "has_expiry_date",
- "fieldtype": "Check",
- "label": "Has Expiry Date"
- },
- {
- "default": "0",
- "fieldname": "retain_sample",
- "fieldtype": "Check",
- "label": "Retain Sample"
- },
- {
- "depends_on": "eval: (doc.retain_sample && doc.has_batch_no)",
- "description": "Maximum sample quantity that can be retained",
- "fieldname": "sample_quantity",
- "fieldtype": "Int",
- "label": "Max Sample Quantity"
- },
- {
- "fieldname": "column_break_37",
- "fieldtype": "Column Break"
- },
- {
- "default": "0",
- "depends_on": "eval:doc.is_stock_item || doc.is_fixed_asset",
- "fieldname": "has_serial_no",
- "fieldtype": "Check",
- "label": "Has Serial No",
- "no_copy": 1,
- "oldfieldname": "has_serial_no",
- "oldfieldtype": "Select"
- },
- {
- "depends_on": "eval:doc.is_stock_item || doc.is_fixed_asset",
- "description": "Example: ABCD.#####\nIf series is set and Serial No is not mentioned in transactions, then automatic serial number will be created based on this series. If you always want to explicitly mention Serial Nos for this item. leave this blank.",
- "fieldname": "serial_no_series",
- "fieldtype": "Data",
- "label": "Serial Number Series"
- },
- {
- "collapsible": 1,
- "collapsible_depends_on": "attributes",
- "fieldname": "variants_section",
- "fieldtype": "Section Break",
- "label": "Variants"
- },
- {
- "default": "0",
- "depends_on": "eval:!doc.variant_of",
- "description": "If this item has variants, then it cannot be selected in sales orders etc.",
- "fieldname": "has_variants",
- "fieldtype": "Check",
- "in_standard_filter": 1,
- "label": "Has Variants",
- "no_copy": 1
- },
- {
- "default": "Item Attribute",
- "depends_on": "has_variants",
- "fieldname": "variant_based_on",
- "fieldtype": "Select",
- "label": "Variant Based On",
- "options": "Item Attribute\nManufacturer"
- },
- {
- "depends_on": "eval:(doc.has_variants || doc.variant_of) && doc.variant_based_on==='Item Attribute'",
- "fieldname": "attributes",
- "fieldtype": "Table",
- "hidden": 1,
- "label": "Attributes",
- "no_copy": 1,
- "options": "Item Variant Attribute"
- },
- {
- "fieldname": "defaults",
- "fieldtype": "Section Break",
- "label": "Sales, Purchase, Accounting Defaults"
- },
- {
- "fieldname": "item_defaults",
- "fieldtype": "Table",
- "label": "Item Defaults",
- "options": "Item Default"
- },
- {
- "collapsible": 1,
- "fieldname": "purchase_details",
- "fieldtype": "Section Break",
- "label": "Purchase, Replenishment Details",
- "oldfieldtype": "Section Break",
- "options": "fa fa-shopping-cart"
- },
- {
- "default": "1",
- "fieldname": "is_purchase_item",
- "fieldtype": "Check",
- "label": "Is Purchase Item"
- },
- {
- "fieldname": "purchase_uom",
- "fieldtype": "Link",
- "label": "Default Purchase Unit of Measure",
- "options": "UOM"
- },
- {
- "default": "0.00",
- "depends_on": "is_stock_item",
- "fieldname": "min_order_qty",
- "fieldtype": "Float",
- "label": "Minimum Order Qty",
- "oldfieldname": "min_order_qty",
- "oldfieldtype": "Currency"
- },
- {
- "fieldname": "safety_stock",
- "fieldtype": "Float",
- "label": "Safety Stock"
- },
- {
- "fieldname": "purchase_details_cb",
- "fieldtype": "Column Break"
- },
- {
- "description": "Average time taken by the supplier to deliver",
- "fieldname": "lead_time_days",
- "fieldtype": "Int",
- "label": "Lead Time in days",
- "oldfieldname": "lead_time_days",
- "oldfieldtype": "Int"
- },
- {
- "fieldname": "last_purchase_rate",
- "fieldtype": "Float",
- "label": "Last Purchase Rate",
- "no_copy": 1,
- "oldfieldname": "last_purchase_rate",
- "oldfieldtype": "Currency",
- "read_only": 1
- },
- {
- "default": "0",
- "fieldname": "is_customer_provided_item",
- "fieldtype": "Check",
- "label": "Is Customer Provided Item"
- },
- {
- "depends_on": "eval:doc.is_customer_provided_item==1",
- "fieldname": "customer",
- "fieldtype": "Link",
- "label": "Customer",
- "options": "Customer"
- },
- {
- "collapsible": 1,
- "fieldname": "supplier_details",
- "fieldtype": "Section Break",
- "label": "Supplier Details"
- },
- {
- "default": "0",
- "fieldname": "delivered_by_supplier",
- "fieldtype": "Check",
- "label": "Delivered by Supplier (Drop Ship)",
- "print_hide": 1
- },
- {
- "fieldname": "column_break2",
- "fieldtype": "Column Break",
- "oldfieldtype": "Column Break",
- "width": "50%"
- },
- {
- "fieldname": "supplier_items",
- "fieldtype": "Table",
- "label": "Supplier Items",
- "options": "Item Supplier"
- },
- {
- "collapsible": 1,
- "fieldname": "foreign_trade_details",
- "fieldtype": "Section Break",
- "label": "Foreign Trade Details"
- },
- {
- "fieldname": "country_of_origin",
- "fieldtype": "Link",
- "label": "Country of Origin",
- "options": "Country"
- },
- {
- "fieldname": "column_break_59",
- "fieldtype": "Column Break"
- },
- {
- "fieldname": "customs_tariff_number",
- "fieldtype": "Link",
- "label": "Customs Tariff Number",
- "options": "Customs Tariff Number"
- },
- {
- "collapsible": 1,
- "fieldname": "sales_details",
- "fieldtype": "Section Break",
- "label": "Sales Details",
- "oldfieldtype": "Section Break",
- "options": "fa fa-tag"
- },
- {
- "fieldname": "sales_uom",
- "fieldtype": "Link",
- "label": "Default Sales Unit of Measure",
- "options": "UOM"
- },
- {
- "default": "1",
- "fieldname": "is_sales_item",
- "fieldtype": "Check",
- "label": "Is Sales Item"
- },
- {
- "fieldname": "column_break3",
- "fieldtype": "Column Break",
- "oldfieldtype": "Column Break",
- "width": "50%"
- },
- {
- "fieldname": "max_discount",
- "fieldtype": "Float",
- "label": "Max Discount (%)",
- "oldfieldname": "max_discount",
- "oldfieldtype": "Currency"
- },
- {
- "collapsible": 1,
- "fieldname": "deferred_revenue",
- "fieldtype": "Section Break",
- "label": "Deferred Revenue"
- },
- {
- "depends_on": "enable_deferred_revenue",
- "fieldname": "deferred_revenue_account",
- "fieldtype": "Link",
- "ignore_user_permissions": 1,
- "label": "Deferred Revenue Account",
- "options": "Account"
- },
- {
- "default": "0",
- "fieldname": "enable_deferred_revenue",
- "fieldtype": "Check",
- "label": "Enable Deferred Revenue"
- },
- {
- "fieldname": "column_break_85",
- "fieldtype": "Column Break"
- },
- {
- "depends_on": "enable_deferred_revenue",
- "fieldname": "no_of_months",
- "fieldtype": "Int",
- "label": "No of Months"
- },
- {
- "collapsible": 1,
- "fieldname": "deferred_expense_section",
- "fieldtype": "Section Break",
- "label": "Deferred Expense"
- },
- {
- "depends_on": "enable_deferred_expense",
- "fieldname": "deferred_expense_account",
- "fieldtype": "Link",
- "ignore_user_permissions": 1,
- "label": "Deferred Expense Account",
- "options": "Account"
- },
- {
- "default": "0",
- "fieldname": "enable_deferred_expense",
- "fieldtype": "Check",
- "label": "Enable Deferred Expense"
- },
- {
- "fieldname": "column_break_88",
- "fieldtype": "Column Break"
- },
- {
- "depends_on": "enable_deferred_expense",
- "fieldname": "no_of_months_exp",
- "fieldtype": "Int",
- "label": "No of Months"
- },
- {
- "collapsible": 1,
- "fieldname": "customer_details",
- "fieldtype": "Section Break",
- "label": "Customer Details"
- },
- {
- "fieldname": "customer_items",
- "fieldtype": "Table",
- "label": "Customer Items",
- "options": "Item Customer Detail"
- },
- {
- "collapsible": 1,
- "collapsible_depends_on": "taxes",
- "fieldname": "item_tax_section_break",
- "fieldtype": "Section Break",
- "label": "Item Tax",
- "oldfieldtype": "Section Break",
- "options": "fa fa-money"
- },
- {
- "description": "Will also apply for variants",
- "fieldname": "taxes",
- "fieldtype": "Table",
- "label": "Taxes",
- "oldfieldname": "item_tax",
- "oldfieldtype": "Table",
- "options": "Item Tax"
- },
- {
- "collapsible": 1,
- "fieldname": "inspection_criteria",
- "fieldtype": "Section Break",
- "label": "Inspection Criteria",
- "oldfieldtype": "Section Break",
- "options": "fa fa-search"
- },
- {
- "default": "0",
- "fieldname": "inspection_required_before_purchase",
- "fieldtype": "Check",
- "label": "Inspection Required before Purchase",
- "oldfieldname": "inspection_required",
- "oldfieldtype": "Select"
- },
- {
- "default": "0",
- "fieldname": "inspection_required_before_delivery",
- "fieldtype": "Check",
- "label": "Inspection Required before Delivery"
- },
- {
- "depends_on": "eval:(doc.inspection_required_before_purchase || doc.inspection_required_before_delivery)",
- "fieldname": "quality_inspection_template",
- "fieldtype": "Link",
- "label": "Quality Inspection Template",
- "options": "Quality Inspection Template",
- "print_hide": 1
- },
- {
- "collapsible": 1,
- "depends_on": "is_stock_item",
- "fieldname": "manufacturing",
- "fieldtype": "Section Break",
- "label": "Manufacturing",
- "oldfieldtype": "Section Break",
- "options": "fa fa-cogs"
- },
- {
- "fieldname": "default_bom",
- "fieldtype": "Link",
- "ignore_user_permissions": 1,
- "label": "Default BOM",
- "no_copy": 1,
- "oldfieldname": "default_bom",
- "oldfieldtype": "Link",
- "options": "BOM",
- "read_only": 1
- },
- {
- "default": "0",
- "description": "If subcontracted to a vendor",
- "fieldname": "is_sub_contracted_item",
- "fieldtype": "Check",
- "label": "Supply Raw Materials for Purchase",
- "oldfieldname": "is_sub_contracted_item",
- "oldfieldtype": "Select"
- },
- {
- "fieldname": "column_break_74",
- "fieldtype": "Column Break"
- },
- {
- "fieldname": "customer_code",
- "fieldtype": "Data",
- "hidden": 1,
- "label": "Customer Code",
- "no_copy": 1,
- "print_hide": 1
- },
- {
- "collapsible": 1,
- "fieldname": "website_section",
- "fieldtype": "Section Break",
- "label": "Website",
- "options": "fa fa-globe"
- },
- {
- "default": "0",
- "depends_on": "eval:!doc.variant_of",
- "fieldname": "show_in_website",
- "fieldtype": "Check",
- "label": "Show in Website",
- "search_index": 1
- },
- {
- "default": "0",
- "depends_on": "variant_of",
- "fieldname": "show_variant_in_website",
- "fieldtype": "Check",
- "label": "Show in Website (Variant)",
- "search_index": 1
- },
- {
- "depends_on": "eval: doc.show_in_website || doc.show_variant_in_website",
- "fieldname": "route",
- "fieldtype": "Small Text",
- "label": "Route",
- "no_copy": 1
- },
- {
- "depends_on": "eval: doc.show_in_website || doc.show_variant_in_website",
- "description": "Items with higher weightage will be shown higher",
- "fieldname": "weightage",
- "fieldtype": "Int",
- "label": "Weightage"
- },
- {
- "depends_on": "eval: doc.show_in_website || doc.show_variant_in_website",
- "description": "Show a slideshow at the top of the page",
- "fieldname": "slideshow",
- "fieldtype": "Link",
- "label": "Slideshow",
- "options": "Website Slideshow"
- },
- {
- "depends_on": "eval: doc.show_in_website || doc.show_variant_in_website",
- "description": "Item Image (if not slideshow)",
- "fieldname": "website_image",
- "fieldtype": "Attach",
- "label": "Website Image"
- },
- {
- "fieldname": "thumbnail",
- "fieldtype": "Data",
- "label": "Thumbnail",
- "read_only": 1
- },
- {
- "fieldname": "cb72",
- "fieldtype": "Column Break"
- },
- {
- "depends_on": "eval: doc.show_in_website || doc.show_variant_in_website",
- "description": "Show \"In Stock\" or \"Not in Stock\" based on stock available in this warehouse.",
- "fieldname": "website_warehouse",
- "fieldtype": "Link",
- "ignore_user_permissions": 1,
- "label": "Website Warehouse",
- "options": "Warehouse"
- },
- {
- "depends_on": "eval: doc.show_in_website || doc.show_variant_in_website",
- "description": "List this Item in multiple groups on the website.",
- "fieldname": "website_item_groups",
- "fieldtype": "Table",
- "label": "Website Item Groups",
- "options": "Website Item Group"
- },
- {
- "depends_on": "eval: doc.show_in_website || doc.show_variant_in_website",
- "fieldname": "set_meta_tags",
- "fieldtype": "Button",
- "label": "Set Meta Tags"
- },
- {
- "collapsible": 1,
- "collapsible_depends_on": "website_specifications",
- "depends_on": "eval: doc.show_in_website || doc.show_variant_in_website",
- "fieldname": "sb72",
- "fieldtype": "Section Break",
- "label": "Website Specifications"
- },
- {
- "depends_on": "eval: doc.show_in_website || doc.show_variant_in_website",
- "fieldname": "copy_from_item_group",
- "fieldtype": "Button",
- "label": "Copy From Item Group"
- },
- {
- "depends_on": "eval: doc.show_in_website || doc.show_variant_in_website",
- "fieldname": "website_specifications",
- "fieldtype": "Table",
- "label": "Website Specifications",
- "options": "Item Website Specification"
- },
- {
- "depends_on": "eval: doc.show_in_website || doc.show_variant_in_website",
- "fieldname": "web_long_description",
- "fieldtype": "Text Editor",
- "label": "Website Description"
- },
- {
- "description": "You can use any valid Bootstrap 4 markup in this field. It will be shown on your Item Page.",
- "fieldname": "website_content",
- "fieldtype": "HTML Editor",
- "label": "Website Content"
- },
- {
- "fieldname": "total_projected_qty",
- "fieldtype": "Float",
- "hidden": 1,
- "label": "Total Projected Qty",
- "print_hide": 1,
- "read_only": 1
- },
- {
- "depends_on": "eval:(!doc.is_item_from_hub)",
- "fieldname": "hub_publishing_sb",
- "fieldtype": "Section Break",
- "label": "Hub Publishing Details"
- },
- {
- "default": "0",
- "description": "Publish Item to hub.erpnext.com",
- "fieldname": "publish_in_hub",
- "fieldtype": "Check",
- "label": "Publish in Hub"
- },
- {
- "fieldname": "hub_category_to_publish",
- "fieldtype": "Data",
- "label": "Hub Category to Publish",
- "read_only": 1
- },
- {
- "description": "Publish \"In Stock\" or \"Not in Stock\" on Hub based on stock available in this warehouse.",
- "fieldname": "hub_warehouse",
- "fieldtype": "Link",
- "ignore_user_permissions": 1,
- "label": "Hub Warehouse",
- "options": "Warehouse"
- },
- {
- "default": "0",
- "fieldname": "synced_with_hub",
- "fieldtype": "Check",
- "label": "Synced With Hub",
- "read_only": 1
- },
- {
- "fieldname": "manufacturers",
- "fieldtype": "Table",
- "label": "Manufacturers",
- "options": "Item Manufacturer"
- },
- {
- "depends_on": "eval:!doc.__islocal",
- "fieldname": "over_delivery_receipt_allowance",
- "fieldtype": "Float",
- "label": "Over Delivery/Receipt Allowance (%)",
- "oldfieldname": "tolerance",
- "oldfieldtype": "Currency"
- },
- {
- "fieldname": "over_billing_allowance",
- "fieldtype": "Float",
- "label": "Over Billing Allowance (%)",
- "depends_on": "eval:!doc.__islocal"
- }
- ],
- "has_web_view": 1,
- "icon": "fa fa-tag",
- "idx": 2,
- "image_field": "image",
- "max_attachments": 1,
- "modified": "2019-09-03 18:34:13.977931",
- "modified_by": "Administrator",
- "module": "Stock",
- "name": "Item",
- "owner": "Administrator",
- "permissions": [
- {
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "import": 1,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Item Manager",
- "share": 1,
- "write": 1
- },
- {
- "email": 1,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Stock Manager"
- },
- {
- "email": 1,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "Stock User"
- },
- {
- "read": 1,
- "role": "Sales User"
- },
- {
- "read": 1,
- "role": "Purchase User"
- },
- {
- "read": 1,
- "role": "Maintenance User"
- },
- {
- "read": 1,
- "role": "Accounts User"
- },
- {
- "read": 1,
- "role": "Manufacturing User"
- }
- ],
- "quick_entry": 1,
- "search_fields": "item_name,description,item_group,customer_code",
- "show_name_in_global_search": 1,
- "show_preview_popup": 1,
- "sort_field": "idx desc,modified desc",
- "sort_order": "DESC",
- "title_field": "item_name",
- "track_changes": 1
- }
+ "actions": [],
+ "allow_guest_to_view": 1,
+ "allow_import": 1,
+ "allow_rename": 1,
+ "autoname": "field:item_code",
+ "creation": "2013-05-03 10:45:46",
+ "description": "A Product or a Service that is bought, sold or kept in stock.",
+ "doctype": "DocType",
+ "document_type": "Setup",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "name_and_description_section",
+ "naming_series",
+ "item_code",
+ "variant_of",
+ "item_name",
+ "item_group",
+ "is_item_from_hub",
+ "stock_uom",
+ "column_break0",
+ "disabled",
+ "allow_alternative_item",
+ "is_stock_item",
+ "include_item_in_manufacturing",
+ "opening_stock",
+ "valuation_rate",
+ "standard_rate",
+ "is_fixed_asset",
+ "auto_create_assets",
+ "asset_category",
+ "asset_naming_series",
+ "over_delivery_receipt_allowance",
+ "over_billing_allowance",
+ "image",
+ "section_break_11",
+ "brand",
+ "description",
+ "sb_barcodes",
+ "barcodes",
+ "inventory_section",
+ "shelf_life_in_days",
+ "end_of_life",
+ "default_material_request_type",
+ "valuation_method",
+ "column_break1",
+ "warranty_period",
+ "weight_per_unit",
+ "weight_uom",
+ "reorder_section",
+ "reorder_levels",
+ "unit_of_measure_conversion",
+ "uoms",
+ "serial_nos_and_batches",
+ "has_batch_no",
+ "create_new_batch",
+ "batch_number_series",
+ "has_expiry_date",
+ "retain_sample",
+ "sample_quantity",
+ "column_break_37",
+ "has_serial_no",
+ "serial_no_series",
+ "variants_section",
+ "has_variants",
+ "variant_based_on",
+ "attributes",
+ "defaults",
+ "item_defaults",
+ "purchase_details",
+ "is_purchase_item",
+ "purchase_uom",
+ "min_order_qty",
+ "safety_stock",
+ "purchase_details_cb",
+ "lead_time_days",
+ "last_purchase_rate",
+ "is_customer_provided_item",
+ "customer",
+ "supplier_details",
+ "delivered_by_supplier",
+ "column_break2",
+ "supplier_items",
+ "foreign_trade_details",
+ "country_of_origin",
+ "column_break_59",
+ "customs_tariff_number",
+ "sales_details",
+ "sales_uom",
+ "is_sales_item",
+ "column_break3",
+ "max_discount",
+ "deferred_revenue",
+ "deferred_revenue_account",
+ "enable_deferred_revenue",
+ "column_break_85",
+ "no_of_months",
+ "deferred_expense_section",
+ "deferred_expense_account",
+ "enable_deferred_expense",
+ "column_break_88",
+ "no_of_months_exp",
+ "customer_details",
+ "customer_items",
+ "item_tax_section_break",
+ "taxes",
+ "inspection_criteria",
+ "inspection_required_before_purchase",
+ "inspection_required_before_delivery",
+ "quality_inspection_template",
+ "manufacturing",
+ "default_bom",
+ "is_sub_contracted_item",
+ "column_break_74",
+ "customer_code",
+ "website_section",
+ "show_in_website",
+ "show_variant_in_website",
+ "route",
+ "weightage",
+ "slideshow",
+ "website_image",
+ "thumbnail",
+ "cb72",
+ "website_warehouse",
+ "website_item_groups",
+ "set_meta_tags",
+ "sb72",
+ "copy_from_item_group",
+ "website_specifications",
+ "web_long_description",
+ "website_content",
+ "total_projected_qty",
+ "hub_publishing_sb",
+ "publish_in_hub",
+ "hub_category_to_publish",
+ "hub_warehouse",
+ "synced_with_hub"
+ ],
+ "fields": [
+ {
+ "fieldname": "name_and_description_section",
+ "fieldtype": "Section Break",
+ "oldfieldtype": "Section Break",
+ "options": "fa fa-flag"
+ },
+ {
+ "fieldname": "naming_series",
+ "fieldtype": "Select",
+ "label": "Series",
+ "options": "STO-ITEM-.YYYY.-",
+ "set_only_once": 1
+ },
+ {
+ "bold": 1,
+ "fieldname": "item_code",
+ "fieldtype": "Data",
+ "in_global_search": 1,
+ "label": "Item Code",
+ "oldfieldname": "item_code",
+ "oldfieldtype": "Data",
+ "reqd": 1,
+ "unique": 1
+ },
+ {
+ "depends_on": "variant_of",
+ "description": "If item is a variant of another item then description, image, pricing, taxes etc will be set from the template unless explicitly specified",
+ "fieldname": "variant_of",
+ "fieldtype": "Link",
+ "ignore_user_permissions": 1,
+ "in_standard_filter": 1,
+ "label": "Variant Of",
+ "options": "Item",
+ "read_only": 1,
+ "search_index": 1,
+ "set_only_once": 1
+ },
+ {
+ "bold": 1,
+ "fieldname": "item_name",
+ "fieldtype": "Data",
+ "in_global_search": 1,
+ "label": "Item Name",
+ "oldfieldname": "item_name",
+ "oldfieldtype": "Data",
+ "search_index": 1
+ },
+ {
+ "fieldname": "item_group",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "in_preview": 1,
+ "in_standard_filter": 1,
+ "label": "Item Group",
+ "oldfieldname": "item_group",
+ "oldfieldtype": "Link",
+ "options": "Item Group",
+ "reqd": 1,
+ "search_index": 1
+ },
+ {
+ "default": "0",
+ "fieldname": "is_item_from_hub",
+ "fieldtype": "Check",
+ "label": "Is Item from Hub",
+ "read_only": 1
+ },
+ {
+ "fieldname": "stock_uom",
+ "fieldtype": "Link",
+ "ignore_user_permissions": 1,
+ "label": "Default Unit of Measure",
+ "oldfieldname": "stock_uom",
+ "oldfieldtype": "Link",
+ "options": "UOM",
+ "reqd": 1
+ },
+ {
+ "fieldname": "column_break0",
+ "fieldtype": "Column Break"
+ },
+ {
+ "default": "0",
+ "fieldname": "disabled",
+ "fieldtype": "Check",
+ "label": "Disabled"
+ },
+ {
+ "default": "0",
+ "fieldname": "allow_alternative_item",
+ "fieldtype": "Check",
+ "label": "Allow Alternative Item"
+ },
+ {
+ "bold": 1,
+ "default": "1",
+ "fieldname": "is_stock_item",
+ "fieldtype": "Check",
+ "label": "Maintain Stock",
+ "oldfieldname": "is_stock_item",
+ "oldfieldtype": "Select"
+ },
+ {
+ "default": "1",
+ "fieldname": "include_item_in_manufacturing",
+ "fieldtype": "Check",
+ "label": "Include Item In Manufacturing"
+ },
+ {
+ "bold": 1,
+ "depends_on": "eval:(doc.__islocal&&doc.is_stock_item && !doc.has_serial_no && !doc.has_batch_no)",
+ "fieldname": "opening_stock",
+ "fieldtype": "Float",
+ "label": "Opening Stock"
+ },
+ {
+ "depends_on": "is_stock_item",
+ "fieldname": "valuation_rate",
+ "fieldtype": "Currency",
+ "label": "Valuation Rate"
+ },
+ {
+ "bold": 1,
+ "depends_on": "eval:doc.__islocal",
+ "fieldname": "standard_rate",
+ "fieldtype": "Currency",
+ "label": "Standard Selling Rate"
+ },
+ {
+ "default": "0",
+ "fieldname": "is_fixed_asset",
+ "fieldtype": "Check",
+ "label": "Is Fixed Asset",
+ "set_only_once": 1
+ },
+ {
+ "depends_on": "is_fixed_asset",
+ "fieldname": "asset_category",
+ "fieldtype": "Link",
+ "label": "Asset Category",
+ "options": "Asset Category"
+ },
+ {
+ "depends_on": "is_fixed_asset",
+ "fieldname": "asset_naming_series",
+ "fieldtype": "Select",
+ "label": "Asset Naming Series"
+ },
+ {
+ "fieldname": "image",
+ "fieldtype": "Attach Image",
+ "hidden": 1,
+ "in_preview": 1,
+ "label": "Image",
+ "options": "image",
+ "print_hide": 1
+ },
+ {
+ "collapsible": 1,
+ "fieldname": "section_break_11",
+ "fieldtype": "Section Break",
+ "label": "Description"
+ },
+ {
+ "fieldname": "brand",
+ "fieldtype": "Link",
+ "label": "Brand",
+ "oldfieldname": "brand",
+ "oldfieldtype": "Link",
+ "options": "Brand",
+ "print_hide": 1
+ },
+ {
+ "fieldname": "description",
+ "fieldtype": "Text Editor",
+ "in_preview": 1,
+ "label": "Description",
+ "oldfieldname": "description",
+ "oldfieldtype": "Text"
+ },
+ {
+ "fieldname": "sb_barcodes",
+ "fieldtype": "Section Break",
+ "label": "Barcodes"
+ },
+ {
+ "fieldname": "barcodes",
+ "fieldtype": "Table",
+ "label": "Barcodes",
+ "options": "Item Barcode"
+ },
+ {
+ "collapsible": 1,
+ "collapsible_depends_on": "is_stock_item",
+ "depends_on": "is_stock_item",
+ "fieldname": "inventory_section",
+ "fieldtype": "Section Break",
+ "label": "Inventory",
+ "oldfieldtype": "Section Break",
+ "options": "fa fa-truck"
+ },
+ {
+ "fieldname": "shelf_life_in_days",
+ "fieldtype": "Int",
+ "label": "Shelf Life In Days"
+ },
+ {
+ "default": "2099-12-31",
+ "depends_on": "is_stock_item",
+ "fieldname": "end_of_life",
+ "fieldtype": "Date",
+ "label": "End of Life",
+ "oldfieldname": "end_of_life",
+ "oldfieldtype": "Date"
+ },
+ {
+ "default": "Purchase",
+ "fieldname": "default_material_request_type",
+ "fieldtype": "Select",
+ "label": "Default Material Request Type",
+ "options": "Purchase\nMaterial Transfer\nMaterial Issue\nManufacture\nCustomer Provided"
+ },
+ {
+ "depends_on": "is_stock_item",
+ "fieldname": "valuation_method",
+ "fieldtype": "Select",
+ "label": "Valuation Method",
+ "options": "\nFIFO\nMoving Average",
+ "set_only_once": 1
+ },
+ {
+ "depends_on": "is_stock_item",
+ "fieldname": "column_break1",
+ "fieldtype": "Column Break",
+ "oldfieldtype": "Column Break",
+ "width": "50%"
+ },
+ {
+ "depends_on": "eval:doc.is_stock_item",
+ "fieldname": "warranty_period",
+ "fieldtype": "Data",
+ "label": "Warranty Period (in days)",
+ "oldfieldname": "warranty_period",
+ "oldfieldtype": "Data"
+ },
+ {
+ "depends_on": "is_stock_item",
+ "fieldname": "weight_per_unit",
+ "fieldtype": "Float",
+ "label": "Weight Per Unit"
+ },
+ {
+ "depends_on": "eval:doc.is_stock_item",
+ "fieldname": "weight_uom",
+ "fieldtype": "Link",
+ "ignore_user_permissions": 1,
+ "label": "Weight UOM",
+ "options": "UOM"
+ },
+ {
+ "collapsible": 1,
+ "depends_on": "is_stock_item",
+ "fieldname": "reorder_section",
+ "fieldtype": "Section Break",
+ "label": "Auto re-order",
+ "options": "fa fa-rss"
+ },
+ {
+ "description": "Will also apply for variants unless overrridden",
+ "fieldname": "reorder_levels",
+ "fieldtype": "Table",
+ "label": "Reorder level based on Warehouse",
+ "options": "Item Reorder"
+ },
+ {
+ "collapsible": 1,
+ "fieldname": "unit_of_measure_conversion",
+ "fieldtype": "Section Break",
+ "label": "Units of Measure"
+ },
+ {
+ "description": "Will also apply for variants",
+ "fieldname": "uoms",
+ "fieldtype": "Table",
+ "label": "UOMs",
+ "oldfieldname": "uom_conversion_details",
+ "oldfieldtype": "Table",
+ "options": "UOM Conversion Detail"
+ },
+ {
+ "collapsible": 1,
+ "collapsible_depends_on": "eval:doc.has_batch_no || doc.has_serial_no || doc.is_fixed_asset",
+ "depends_on": "eval:doc.is_stock_item || doc.is_fixed_asset",
+ "fieldname": "serial_nos_and_batches",
+ "fieldtype": "Section Break",
+ "label": "Serial Nos and Batches"
+ },
+ {
+ "default": "0",
+ "depends_on": "eval:doc.is_stock_item",
+ "fieldname": "has_batch_no",
+ "fieldtype": "Check",
+ "label": "Has Batch No",
+ "no_copy": 1,
+ "oldfieldname": "has_batch_no",
+ "oldfieldtype": "Select"
+ },
+ {
+ "default": "0",
+ "depends_on": "has_batch_no",
+ "fieldname": "create_new_batch",
+ "fieldtype": "Check",
+ "label": "Automatically Create New Batch"
+ },
+ {
+ "depends_on": "eval:doc.has_batch_no==1 && doc.create_new_batch==1",
+ "description": "Example: ABCD.#####. If series is set and Batch No is not mentioned in transactions, then automatic batch number will be created based on this series. If you always want to explicitly mention Batch No for this item, leave this blank. Note: this setting will take priority over the Naming Series Prefix in Stock Settings.",
+ "fieldname": "batch_number_series",
+ "fieldtype": "Data",
+ "label": "Batch Number Series",
+ "translatable": 1
+ },
+ {
+ "default": "0",
+ "depends_on": "has_batch_no",
+ "fieldname": "has_expiry_date",
+ "fieldtype": "Check",
+ "label": "Has Expiry Date"
+ },
+ {
+ "default": "0",
+ "fieldname": "retain_sample",
+ "fieldtype": "Check",
+ "label": "Retain Sample"
+ },
+ {
+ "depends_on": "eval: (doc.retain_sample && doc.has_batch_no)",
+ "description": "Maximum sample quantity that can be retained",
+ "fieldname": "sample_quantity",
+ "fieldtype": "Int",
+ "label": "Max Sample Quantity"
+ },
+ {
+ "fieldname": "column_break_37",
+ "fieldtype": "Column Break"
+ },
+ {
+ "default": "0",
+ "depends_on": "eval:doc.is_stock_item || doc.is_fixed_asset",
+ "fieldname": "has_serial_no",
+ "fieldtype": "Check",
+ "label": "Has Serial No",
+ "no_copy": 1,
+ "oldfieldname": "has_serial_no",
+ "oldfieldtype": "Select"
+ },
+ {
+ "depends_on": "eval:doc.is_stock_item || doc.is_fixed_asset",
+ "description": "Example: ABCD.#####\nIf series is set and Serial No is not mentioned in transactions, then automatic serial number will be created based on this series. If you always want to explicitly mention Serial Nos for this item. leave this blank.",
+ "fieldname": "serial_no_series",
+ "fieldtype": "Data",
+ "label": "Serial Number Series"
+ },
+ {
+ "collapsible": 1,
+ "collapsible_depends_on": "attributes",
+ "fieldname": "variants_section",
+ "fieldtype": "Section Break",
+ "label": "Variants"
+ },
+ {
+ "default": "0",
+ "depends_on": "eval:!doc.variant_of",
+ "description": "If this item has variants, then it cannot be selected in sales orders etc.",
+ "fieldname": "has_variants",
+ "fieldtype": "Check",
+ "in_standard_filter": 1,
+ "label": "Has Variants",
+ "no_copy": 1
+ },
+ {
+ "default": "Item Attribute",
+ "depends_on": "has_variants",
+ "fieldname": "variant_based_on",
+ "fieldtype": "Select",
+ "label": "Variant Based On",
+ "options": "Item Attribute\nManufacturer"
+ },
+ {
+ "depends_on": "eval:(doc.has_variants || doc.variant_of) && doc.variant_based_on==='Item Attribute'",
+ "fieldname": "attributes",
+ "fieldtype": "Table",
+ "hidden": 1,
+ "label": "Attributes",
+ "no_copy": 1,
+ "options": "Item Variant Attribute"
+ },
+ {
+ "fieldname": "defaults",
+ "fieldtype": "Section Break",
+ "label": "Sales, Purchase, Accounting Defaults"
+ },
+ {
+ "fieldname": "item_defaults",
+ "fieldtype": "Table",
+ "label": "Item Defaults",
+ "options": "Item Default"
+ },
+ {
+ "collapsible": 1,
+ "fieldname": "purchase_details",
+ "fieldtype": "Section Break",
+ "label": "Purchase, Replenishment Details",
+ "oldfieldtype": "Section Break",
+ "options": "fa fa-shopping-cart"
+ },
+ {
+ "default": "1",
+ "fieldname": "is_purchase_item",
+ "fieldtype": "Check",
+ "label": "Is Purchase Item"
+ },
+ {
+ "fieldname": "purchase_uom",
+ "fieldtype": "Link",
+ "label": "Default Purchase Unit of Measure",
+ "options": "UOM"
+ },
+ {
+ "default": "0.00",
+ "depends_on": "is_stock_item",
+ "description": "Minimum quantity should be as per Stock UOM",
+ "fieldname": "min_order_qty",
+ "fieldtype": "Float",
+ "label": "Minimum Order Qty",
+ "oldfieldname": "min_order_qty",
+ "oldfieldtype": "Currency"
+ },
+ {
+ "fieldname": "safety_stock",
+ "fieldtype": "Float",
+ "label": "Safety Stock"
+ },
+ {
+ "fieldname": "purchase_details_cb",
+ "fieldtype": "Column Break"
+ },
+ {
+ "description": "Average time taken by the supplier to deliver",
+ "fieldname": "lead_time_days",
+ "fieldtype": "Int",
+ "label": "Lead Time in days",
+ "oldfieldname": "lead_time_days",
+ "oldfieldtype": "Int"
+ },
+ {
+ "fieldname": "last_purchase_rate",
+ "fieldtype": "Float",
+ "label": "Last Purchase Rate",
+ "no_copy": 1,
+ "oldfieldname": "last_purchase_rate",
+ "oldfieldtype": "Currency",
+ "read_only": 1
+ },
+ {
+ "default": "0",
+ "fieldname": "is_customer_provided_item",
+ "fieldtype": "Check",
+ "label": "Is Customer Provided Item"
+ },
+ {
+ "depends_on": "eval:doc.is_customer_provided_item==1",
+ "fieldname": "customer",
+ "fieldtype": "Link",
+ "label": "Customer",
+ "options": "Customer"
+ },
+ {
+ "collapsible": 1,
+ "fieldname": "supplier_details",
+ "fieldtype": "Section Break",
+ "label": "Supplier Details"
+ },
+ {
+ "default": "0",
+ "fieldname": "delivered_by_supplier",
+ "fieldtype": "Check",
+ "label": "Delivered by Supplier (Drop Ship)",
+ "print_hide": 1
+ },
+ {
+ "fieldname": "column_break2",
+ "fieldtype": "Column Break",
+ "oldfieldtype": "Column Break",
+ "width": "50%"
+ },
+ {
+ "fieldname": "supplier_items",
+ "fieldtype": "Table",
+ "label": "Supplier Items",
+ "options": "Item Supplier"
+ },
+ {
+ "collapsible": 1,
+ "fieldname": "foreign_trade_details",
+ "fieldtype": "Section Break",
+ "label": "Foreign Trade Details"
+ },
+ {
+ "fieldname": "country_of_origin",
+ "fieldtype": "Link",
+ "label": "Country of Origin",
+ "options": "Country"
+ },
+ {
+ "fieldname": "column_break_59",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "customs_tariff_number",
+ "fieldtype": "Link",
+ "label": "Customs Tariff Number",
+ "options": "Customs Tariff Number"
+ },
+ {
+ "collapsible": 1,
+ "fieldname": "sales_details",
+ "fieldtype": "Section Break",
+ "label": "Sales Details",
+ "oldfieldtype": "Section Break",
+ "options": "fa fa-tag"
+ },
+ {
+ "fieldname": "sales_uom",
+ "fieldtype": "Link",
+ "label": "Default Sales Unit of Measure",
+ "options": "UOM"
+ },
+ {
+ "default": "1",
+ "fieldname": "is_sales_item",
+ "fieldtype": "Check",
+ "label": "Is Sales Item"
+ },
+ {
+ "fieldname": "column_break3",
+ "fieldtype": "Column Break",
+ "oldfieldtype": "Column Break",
+ "width": "50%"
+ },
+ {
+ "fieldname": "max_discount",
+ "fieldtype": "Float",
+ "label": "Max Discount (%)",
+ "oldfieldname": "max_discount",
+ "oldfieldtype": "Currency"
+ },
+ {
+ "collapsible": 1,
+ "fieldname": "deferred_revenue",
+ "fieldtype": "Section Break",
+ "label": "Deferred Revenue"
+ },
+ {
+ "depends_on": "enable_deferred_revenue",
+ "fieldname": "deferred_revenue_account",
+ "fieldtype": "Link",
+ "ignore_user_permissions": 1,
+ "label": "Deferred Revenue Account",
+ "options": "Account"
+ },
+ {
+ "default": "0",
+ "fieldname": "enable_deferred_revenue",
+ "fieldtype": "Check",
+ "label": "Enable Deferred Revenue"
+ },
+ {
+ "fieldname": "column_break_85",
+ "fieldtype": "Column Break"
+ },
+ {
+ "depends_on": "enable_deferred_revenue",
+ "fieldname": "no_of_months",
+ "fieldtype": "Int",
+ "label": "No of Months"
+ },
+ {
+ "collapsible": 1,
+ "fieldname": "deferred_expense_section",
+ "fieldtype": "Section Break",
+ "label": "Deferred Expense"
+ },
+ {
+ "depends_on": "enable_deferred_expense",
+ "fieldname": "deferred_expense_account",
+ "fieldtype": "Link",
+ "ignore_user_permissions": 1,
+ "label": "Deferred Expense Account",
+ "options": "Account"
+ },
+ {
+ "default": "0",
+ "fieldname": "enable_deferred_expense",
+ "fieldtype": "Check",
+ "label": "Enable Deferred Expense"
+ },
+ {
+ "fieldname": "column_break_88",
+ "fieldtype": "Column Break"
+ },
+ {
+ "depends_on": "enable_deferred_expense",
+ "fieldname": "no_of_months_exp",
+ "fieldtype": "Int",
+ "label": "No of Months"
+ },
+ {
+ "collapsible": 1,
+ "fieldname": "customer_details",
+ "fieldtype": "Section Break",
+ "label": "Customer Details"
+ },
+ {
+ "fieldname": "customer_items",
+ "fieldtype": "Table",
+ "label": "Customer Items",
+ "options": "Item Customer Detail"
+ },
+ {
+ "collapsible": 1,
+ "collapsible_depends_on": "taxes",
+ "fieldname": "item_tax_section_break",
+ "fieldtype": "Section Break",
+ "label": "Item Tax",
+ "oldfieldtype": "Section Break",
+ "options": "fa fa-money"
+ },
+ {
+ "description": "Will also apply for variants",
+ "fieldname": "taxes",
+ "fieldtype": "Table",
+ "label": "Taxes",
+ "oldfieldname": "item_tax",
+ "oldfieldtype": "Table",
+ "options": "Item Tax"
+ },
+ {
+ "collapsible": 1,
+ "fieldname": "inspection_criteria",
+ "fieldtype": "Section Break",
+ "label": "Inspection Criteria",
+ "oldfieldtype": "Section Break",
+ "options": "fa fa-search"
+ },
+ {
+ "default": "0",
+ "fieldname": "inspection_required_before_purchase",
+ "fieldtype": "Check",
+ "label": "Inspection Required before Purchase",
+ "oldfieldname": "inspection_required",
+ "oldfieldtype": "Select"
+ },
+ {
+ "default": "0",
+ "fieldname": "inspection_required_before_delivery",
+ "fieldtype": "Check",
+ "label": "Inspection Required before Delivery"
+ },
+ {
+ "depends_on": "eval:(doc.inspection_required_before_purchase || doc.inspection_required_before_delivery)",
+ "fieldname": "quality_inspection_template",
+ "fieldtype": "Link",
+ "label": "Quality Inspection Template",
+ "options": "Quality Inspection Template",
+ "print_hide": 1
+ },
+ {
+ "collapsible": 1,
+ "depends_on": "is_stock_item",
+ "fieldname": "manufacturing",
+ "fieldtype": "Section Break",
+ "label": "Manufacturing",
+ "oldfieldtype": "Section Break",
+ "options": "fa fa-cogs"
+ },
+ {
+ "fieldname": "default_bom",
+ "fieldtype": "Link",
+ "ignore_user_permissions": 1,
+ "label": "Default BOM",
+ "no_copy": 1,
+ "oldfieldname": "default_bom",
+ "oldfieldtype": "Link",
+ "options": "BOM",
+ "read_only": 1
+ },
+ {
+ "default": "0",
+ "description": "If subcontracted to a vendor",
+ "fieldname": "is_sub_contracted_item",
+ "fieldtype": "Check",
+ "label": "Supply Raw Materials for Purchase",
+ "oldfieldname": "is_sub_contracted_item",
+ "oldfieldtype": "Select"
+ },
+ {
+ "fieldname": "column_break_74",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "customer_code",
+ "fieldtype": "Data",
+ "hidden": 1,
+ "label": "Customer Code",
+ "no_copy": 1,
+ "print_hide": 1
+ },
+ {
+ "collapsible": 1,
+ "fieldname": "website_section",
+ "fieldtype": "Section Break",
+ "label": "Website",
+ "options": "fa fa-globe"
+ },
+ {
+ "default": "0",
+ "depends_on": "eval:!doc.variant_of",
+ "fieldname": "show_in_website",
+ "fieldtype": "Check",
+ "label": "Show in Website",
+ "search_index": 1
+ },
+ {
+ "default": "0",
+ "depends_on": "variant_of",
+ "fieldname": "show_variant_in_website",
+ "fieldtype": "Check",
+ "label": "Show in Website (Variant)",
+ "search_index": 1
+ },
+ {
+ "depends_on": "eval: doc.show_in_website || doc.show_variant_in_website",
+ "fieldname": "route",
+ "fieldtype": "Small Text",
+ "label": "Route",
+ "no_copy": 1
+ },
+ {
+ "depends_on": "eval: doc.show_in_website || doc.show_variant_in_website",
+ "description": "Items with higher weightage will be shown higher",
+ "fieldname": "weightage",
+ "fieldtype": "Int",
+ "label": "Weightage"
+ },
+ {
+ "depends_on": "eval: doc.show_in_website || doc.show_variant_in_website",
+ "description": "Show a slideshow at the top of the page",
+ "fieldname": "slideshow",
+ "fieldtype": "Link",
+ "label": "Slideshow",
+ "options": "Website Slideshow"
+ },
+ {
+ "depends_on": "eval: doc.show_in_website || doc.show_variant_in_website",
+ "description": "Item Image (if not slideshow)",
+ "fieldname": "website_image",
+ "fieldtype": "Attach",
+ "label": "Website Image"
+ },
+ {
+ "fieldname": "thumbnail",
+ "fieldtype": "Data",
+ "label": "Thumbnail",
+ "read_only": 1
+ },
+ {
+ "fieldname": "cb72",
+ "fieldtype": "Column Break"
+ },
+ {
+ "depends_on": "eval: doc.show_in_website || doc.show_variant_in_website",
+ "description": "Show \"In Stock\" or \"Not in Stock\" based on stock available in this warehouse.",
+ "fieldname": "website_warehouse",
+ "fieldtype": "Link",
+ "ignore_user_permissions": 1,
+ "label": "Website Warehouse",
+ "options": "Warehouse"
+ },
+ {
+ "depends_on": "eval: doc.show_in_website || doc.show_variant_in_website",
+ "description": "List this Item in multiple groups on the website.",
+ "fieldname": "website_item_groups",
+ "fieldtype": "Table",
+ "label": "Website Item Groups",
+ "options": "Website Item Group"
+ },
+ {
+ "depends_on": "eval: doc.show_in_website || doc.show_variant_in_website",
+ "fieldname": "set_meta_tags",
+ "fieldtype": "Button",
+ "label": "Set Meta Tags"
+ },
+ {
+ "collapsible": 1,
+ "collapsible_depends_on": "website_specifications",
+ "depends_on": "eval: doc.show_in_website || doc.show_variant_in_website",
+ "fieldname": "sb72",
+ "fieldtype": "Section Break",
+ "label": "Website Specifications"
+ },
+ {
+ "depends_on": "eval: doc.show_in_website || doc.show_variant_in_website",
+ "fieldname": "copy_from_item_group",
+ "fieldtype": "Button",
+ "label": "Copy From Item Group"
+ },
+ {
+ "depends_on": "eval: doc.show_in_website || doc.show_variant_in_website",
+ "fieldname": "website_specifications",
+ "fieldtype": "Table",
+ "label": "Website Specifications",
+ "options": "Item Website Specification"
+ },
+ {
+ "depends_on": "eval: doc.show_in_website || doc.show_variant_in_website",
+ "fieldname": "web_long_description",
+ "fieldtype": "Text Editor",
+ "label": "Website Description"
+ },
+ {
+ "description": "You can use any valid Bootstrap 4 markup in this field. It will be shown on your Item Page.",
+ "fieldname": "website_content",
+ "fieldtype": "HTML Editor",
+ "label": "Website Content"
+ },
+ {
+ "fieldname": "total_projected_qty",
+ "fieldtype": "Float",
+ "hidden": 1,
+ "label": "Total Projected Qty",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "depends_on": "eval:(!doc.is_item_from_hub)",
+ "fieldname": "hub_publishing_sb",
+ "fieldtype": "Section Break",
+ "label": "Hub Publishing Details"
+ },
+ {
+ "default": "0",
+ "description": "Publish Item to hub.erpnext.com",
+ "fieldname": "publish_in_hub",
+ "fieldtype": "Check",
+ "label": "Publish in Hub"
+ },
+ {
+ "fieldname": "hub_category_to_publish",
+ "fieldtype": "Data",
+ "label": "Hub Category to Publish",
+ "read_only": 1
+ },
+ {
+ "description": "Publish \"In Stock\" or \"Not in Stock\" on Hub based on stock available in this warehouse.",
+ "fieldname": "hub_warehouse",
+ "fieldtype": "Link",
+ "ignore_user_permissions": 1,
+ "label": "Hub Warehouse",
+ "options": "Warehouse"
+ },
+ {
+ "default": "0",
+ "fieldname": "synced_with_hub",
+ "fieldtype": "Check",
+ "label": "Synced With Hub",
+ "read_only": 1
+ },
+ {
+ "depends_on": "eval:!doc.__islocal",
+ "fieldname": "over_delivery_receipt_allowance",
+ "fieldtype": "Float",
+ "label": "Over Delivery/Receipt Allowance (%)",
+ "oldfieldname": "tolerance",
+ "oldfieldtype": "Currency"
+ },
+ {
+ "depends_on": "eval:!doc.__islocal",
+ "fieldname": "over_billing_allowance",
+ "fieldtype": "Float",
+ "label": "Over Billing Allowance (%)"
+ },
+ {
+ "default": "0",
+ "depends_on": "is_fixed_asset",
+ "fieldname": "auto_create_assets",
+ "fieldtype": "Check",
+ "label": "Auto Create Assets on Purchase"
+ }
+ ],
+ "has_web_view": 1,
+ "icon": "fa fa-tag",
+ "idx": 2,
+ "image_field": "image",
+ "links": [],
+ "max_attachments": 1,
+ "modified": "2020-01-02 19:13:59.295963",
+ "modified_by": "Administrator",
+ "module": "Stock",
+ "name": "Item",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "import": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Item Manager",
+ "share": 1,
+ "write": 1
+ },
+ {
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Stock Manager"
+ },
+ {
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Stock User"
+ },
+ {
+ "read": 1,
+ "role": "Sales User"
+ },
+ {
+ "read": 1,
+ "role": "Purchase User"
+ },
+ {
+ "read": 1,
+ "role": "Maintenance User"
+ },
+ {
+ "read": 1,
+ "role": "Accounts User"
+ },
+ {
+ "read": 1,
+ "role": "Manufacturing User"
+ }
+ ],
+ "quick_entry": 1,
+ "search_fields": "item_name,description,item_group,customer_code",
+ "show_name_in_global_search": 1,
+ "show_preview_popup": 1,
+ "sort_field": "idx desc,modified desc",
+ "sort_order": "DESC",
+ "title_field": "item_name",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py
index 164c659..a1f06b2 100644
--- a/erpnext/stock/doctype/item/item.py
+++ b/erpnext/stock/doctype/item/item.py
@@ -125,7 +125,6 @@
self.validate_auto_reorder_enabled_in_stock_settings()
self.cant_change()
self.update_show_in_website()
- self.validate_manufacturer()
if not self.get("__islocal"):
self.old_item_group = frappe.db.get_value(self.doctype, self.name, "item_group")
@@ -145,13 +144,6 @@
if cint(frappe.db.get_single_value('Stock Settings', 'clean_description_html')):
self.description = clean_html(self.description)
- def validate_manufacturer(self):
- list_man = [(x.manufacturer, x.manufacturer_part_no) for x in self.get('manufacturers')]
- set_man = set(list_man)
-
- if len(list_man) != len(set_man):
- frappe.throw(_("Duplicate entry in Manufacturers table"))
-
def validate_customer_provided_part(self):
if self.is_customer_provided_item:
if self.is_purchase_item:
@@ -559,7 +551,7 @@
"""select parent from `tabItem Barcode` where barcode = %s and parent != %s""", (item_barcode.barcode, self.name))
if duplicate:
frappe.throw(_("Barcode {0} already used in Item {1}").format(
- item_barcode.barcode, duplicate[0][0]), frappe.DuplicateEntryError)
+ item_barcode.barcode, duplicate[0][0]))
item_barcode.barcode_type = "" if item_barcode.barcode_type not in options else item_barcode.barcode_type
if item_barcode.barcode_type and item_barcode.barcode_type.upper() in ('EAN', 'UPC-A', 'EAN-13', 'EAN-8'):
@@ -645,7 +637,7 @@
json.dumps(item_wise_tax_detail), update_modified=False)
def set_last_purchase_rate(self, new_name):
- last_purchase_rate = get_last_purchase_details(new_name).get("base_rate", 0)
+ last_purchase_rate = get_last_purchase_details(new_name).get("base_net_rate", 0)
frappe.db.set_value("Item", new_name, "last_purchase_rate", last_purchase_rate)
def recalculate_bin_qty(self, new_name):
@@ -884,6 +876,54 @@
if not enabled:
frappe.msgprint(msg=_("You have to enable auto re-order in Stock Settings to maintain re-order levels."), title=_("Enable Auto Re-Order"), indicator="orange")
+ def create_onboarding_docs(self, args):
+ defaults = frappe.defaults.get_defaults()
+ for i in range(1, args.get('max_count')):
+ item = args.get('item_' + str(i))
+ if item:
+ default_warehouse = ''
+ default_warehouse = frappe.db.get_value('Warehouse', filters={
+ 'warehouse_name': _('Finished Goods'),
+ 'company': defaults.get('company_name')
+ })
+
+ try:
+ frappe.get_doc({
+ 'doctype': self.doctype,
+ 'item_code': item,
+ 'item_name': item,
+ 'description': item,
+ 'show_in_website': 1,
+ 'is_sales_item': 1,
+ 'is_purchase_item': 1,
+ 'is_stock_item': 1,
+ 'item_group': _('Products'),
+ 'stock_uom': _(args.get('item_uom_' + str(i))),
+ 'item_defaults': [{
+ 'default_warehouse': default_warehouse,
+ 'company': defaults.get('company_name')
+ }]
+ }).insert()
+
+ except frappe.NameError:
+ pass
+ else:
+ if args.get('item_price_' + str(i)):
+ item_price = flt(args.get('tem_price_' + str(i)))
+
+ price_list_name = frappe.db.get_value('Price List', {'selling': 1})
+ make_item_price(item, price_list_name, item_price)
+ price_list_name = frappe.db.get_value('Price List', {'buying': 1})
+ make_item_price(item, price_list_name, item_price)
+
+def make_item_price(item, price_list_name, item_price):
+ frappe.get_doc({
+ 'doctype': 'Item Price',
+ 'price_list': price_list_name,
+ 'item_code': item,
+ 'price_list_rate': item_price
+ }).insert()
+
def get_timeline_data(doctype, name):
'''returns timeline data based on stock ledger entry'''
out = {}
@@ -942,7 +982,7 @@
last_purchase_order = frappe.db.sql("""\
select po.name, po.transaction_date, po.conversion_rate,
po_item.conversion_factor, po_item.base_price_list_rate,
- po_item.discount_percentage, po_item.base_rate
+ po_item.discount_percentage, po_item.base_rate, po_item.base_net_rate
from `tabPurchase Order` po, `tabPurchase Order Item` po_item
where po.docstatus = 1 and po_item.item_code = %s and po.name != %s and
po.name = po_item.parent
@@ -953,7 +993,7 @@
last_purchase_receipt = frappe.db.sql("""\
select pr.name, pr.posting_date, pr.posting_time, pr.conversion_rate,
pr_item.conversion_factor, pr_item.base_price_list_rate, pr_item.discount_percentage,
- pr_item.base_rate
+ pr_item.base_rate, pr_item.base_net_rate
from `tabPurchase Receipt` pr, `tabPurchase Receipt Item` pr_item
where pr.docstatus = 1 and pr_item.item_code = %s and pr.name != %s and
pr.name = pr_item.parent
@@ -984,6 +1024,7 @@
out = frappe._dict({
"base_price_list_rate": flt(last_purchase.base_price_list_rate) / conversion_factor,
"base_rate": flt(last_purchase.base_rate) / conversion_factor,
+ "base_net_rate": flt(last_purchase.net_rate) / conversion_factor,
"discount_percentage": flt(last_purchase.discount_percentage),
"purchase_date": purchase_date
})
@@ -992,7 +1033,8 @@
out.update({
"price_list_rate": out.base_price_list_rate / conversion_rate,
"rate": out.base_rate / conversion_rate,
- "base_rate": out.base_rate
+ "base_rate": out.base_rate,
+ "base_net_rate": out.base_net_rate
})
return out
diff --git a/erpnext/stock/doctype/item_alternative/test_item_alternative.py b/erpnext/stock/doctype/item_alternative/test_item_alternative.py
index d5700fe..f045e4f 100644
--- a/erpnext/stock/doctype/item_alternative/test_item_alternative.py
+++ b/erpnext/stock/doctype/item_alternative/test_item_alternative.py
@@ -12,9 +12,11 @@
from erpnext.manufacturing.doctype.work_order.test_work_order import make_wo_order_test_record
from erpnext.buying.doctype.purchase_order.purchase_order import make_purchase_receipt, make_rm_stock_entry
import unittest
+from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory
class TestItemAlternative(unittest.TestCase):
def setUp(self):
+ set_perpetual_inventory(0)
make_items()
def test_alternative_item_for_subcontract_rm(self):
diff --git a/erpnext/stock/doctype/item_price/item_price.json b/erpnext/stock/doctype/item_price/item_price.json
index 9e29ad0..8456b58 100644
--- a/erpnext/stock/doctype/item_price/item_price.json
+++ b/erpnext/stock/doctype/item_price/item_price.json
@@ -1,981 +1,257 @@
{
- "allow_copy": 0,
- "allow_events_in_timeline": 0,
- "allow_guest_to_view": 0,
- "allow_import": 1,
- "allow_rename": 0,
- "autoname": "",
- "beta": 0,
- "creation": "2013-05-02 16:29:48",
- "custom": 0,
- "description": "Multiple Item prices.",
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "Setup",
- "editable_grid": 0,
- "engine": "InnoDB",
+ "actions": [],
+ "allow_import": 1,
+ "creation": "2013-05-02 16:29:48",
+ "description": "Multiple Item prices.",
+ "doctype": "DocType",
+ "document_type": "Setup",
+ "engine": "InnoDB",
+ "field_order": [
+ "item_code",
+ "uom",
+ "packing_unit",
+ "min_qty",
+ "column_break_17",
+ "item_name",
+ "brand",
+ "item_description",
+ "price_list_details",
+ "price_list",
+ "customer",
+ "supplier",
+ "column_break_3",
+ "buying",
+ "selling",
+ "item_details",
+ "currency",
+ "col_br_1",
+ "price_list_rate",
+ "section_break_15",
+ "valid_from",
+ "lead_time_days",
+ "column_break_18",
+ "valid_upto",
+ "section_break_24",
+ "note",
+ "reference"
+ ],
"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": "item_code",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 1,
- "in_global_search": 1,
- "in_list_view": 0,
- "in_standard_filter": 1,
- "label": "Item Code",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "price_list_name",
- "oldfieldtype": "Select",
- "options": "Item",
- "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": 1,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "item_code",
+ "fieldtype": "Link",
+ "in_filter": 1,
+ "in_global_search": 1,
+ "in_list_view": 1,
+ "in_standard_filter": 1,
+ "label": "Item Code",
+ "oldfieldname": "price_list_name",
+ "oldfieldtype": "Select",
+ "options": "Item",
+ "reqd": 1,
+ "search_index": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 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,
- "options": "UOM",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "uom",
+ "fieldtype": "Link",
+ "label": "UOM",
+ "options": "UOM"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "0",
- "description": "Quantity that must be bought or sold per UOM",
- "fetch_if_empty": 0,
- "fieldname": "packing_unit",
- "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": "Packing Unit",
- "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
- },
+ "default": "0",
+ "description": "Quantity that must be bought or sold per UOM",
+ "fieldname": "packing_unit",
+ "fieldtype": "Int",
+ "label": "Packing Unit"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "1",
- "fetch_if_empty": 0,
- "fieldname": "min_qty",
- "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": "Minimum Qty ",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "default": "1",
+ "fieldname": "min_qty",
+ "fieldtype": "Int",
+ "in_list_view": 1,
+ "label": "Minimum Qty "
+ },
{
- "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_17",
- "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
- },
+ "fieldname": "column_break_17",
+ "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,
- "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,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "item_name",
+ "fieldtype": "Data",
+ "in_list_view": 1,
+ "label": "Item Name",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_from": "item_code.brand",
- "fetch_if_empty": 0,
- "fieldname": "brand",
- "fieldtype": "Read Only",
- "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": "Brand",
- "length": 0,
- "no_copy": 0,
- "options": "",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fetch_from": "item_code.brand",
+ "fieldname": "brand",
+ "fieldtype": "Read Only",
+ "in_list_view": 1,
+ "label": "Brand",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "item_description",
- "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": "Item Description",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "item_description",
+ "fieldtype": "Text",
+ "label": "Item Description",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "price_list_details",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Price List",
- "length": 0,
- "no_copy": 0,
- "options": "fa fa-tags",
- "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
- },
+ "fieldname": "price_list_details",
+ "fieldtype": "Section Break",
+ "label": "Price List",
+ "options": "fa fa-tags"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "price_list",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 1,
- "in_list_view": 0,
- "in_standard_filter": 1,
- "label": "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": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "price_list",
+ "fieldtype": "Link",
+ "in_global_search": 1,
+ "in_standard_filter": 1,
+ "label": "Price List",
+ "options": "Price List",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 1,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:doc.selling == 1",
- "fetch_if_empty": 0,
- "fieldname": "customer",
- "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": "Customer",
- "length": 0,
- "no_copy": 0,
- "options": "Customer",
- "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
- },
+ "bold": 1,
+ "depends_on": "eval:doc.selling == 1",
+ "fieldname": "customer",
+ "fieldtype": "Link",
+ "label": "Customer",
+ "options": "Customer"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:doc.buying == 1",
- "fetch_if_empty": 0,
- "fieldname": "supplier",
- "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": "Supplier",
- "length": 0,
- "no_copy": 0,
- "options": "Supplier",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "depends_on": "eval:doc.buying == 1",
+ "fieldname": "supplier",
+ "fieldtype": "Link",
+ "label": "Supplier",
+ "options": "Supplier"
+ },
{
- "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
- },
+ "fieldname": "column_break_3",
+ "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,
- "fieldname": "buying",
- "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": "Buying",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "default": "0",
+ "fieldname": "buying",
+ "fieldtype": "Check",
+ "label": "Buying",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "selling",
- "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": "Selling",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "default": "0",
+ "fieldname": "selling",
+ "fieldtype": "Check",
+ "label": "Selling",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "item_details",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "",
- "length": 0,
- "no_copy": 0,
- "options": "fa fa-tag",
- "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
- },
+ "fieldname": "item_details",
+ "fieldtype": "Section Break",
+ "options": "fa fa-tag"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 1,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "currency",
- "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": "Currency",
- "length": 0,
- "no_copy": 0,
- "options": "Currency",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "bold": 1,
+ "fieldname": "currency",
+ "fieldtype": "Link",
+ "label": "Currency",
+ "options": "Currency",
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "col_br_1",
- "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
- },
+ "fieldname": "col_br_1",
+ "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,
- "fieldname": "price_list_rate",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 1,
- "in_global_search": 1,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Rate",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "ref_rate",
- "oldfieldtype": "Currency",
- "options": "currency",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "price_list_rate",
+ "fieldtype": "Currency",
+ "in_filter": 1,
+ "in_global_search": 1,
+ "in_list_view": 1,
+ "label": "Rate",
+ "oldfieldname": "ref_rate",
+ "oldfieldtype": "Currency",
+ "options": "currency",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "section_break_15",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "section_break_15",
+ "fieldtype": "Section Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "Today",
- "fetch_if_empty": 0,
- "fieldname": "valid_from",
- "fieldtype": "Date",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Valid From ",
- "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
- },
+ "default": "Today",
+ "fieldname": "valid_from",
+ "fieldtype": "Date",
+ "label": "Valid From "
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "0",
- "fetch_if_empty": 0,
- "fieldname": "lead_time_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": "Lead Time in 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
- },
+ "default": "0",
+ "fieldname": "lead_time_days",
+ "fieldtype": "Int",
+ "label": "Lead Time in 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": "column_break_18",
- "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
- },
+ "fieldname": "column_break_18",
+ "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,
- "fieldname": "valid_upto",
- "fieldtype": "Date",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Valid Upto ",
- "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
- },
+ "fieldname": "valid_upto",
+ "fieldtype": "Date",
+ "label": "Valid Upto "
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "section_break_24",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "section_break_24",
+ "fieldtype": "Section Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "note",
- "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": "Note",
- "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
- },
+ "fieldname": "note",
+ "fieldtype": "Text",
+ "label": "Note"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_if_empty": 0,
- "fieldname": "reference",
- "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": "Reference",
- "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
+ "fieldname": "reference",
+ "fieldtype": "Data",
+ "in_list_view": 1,
+ "label": "Reference"
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "icon": "fa fa-flag",
- "idx": 1,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2019-04-12 12:33:54.621527",
- "modified_by": "Administrator",
- "module": "Stock",
- "name": "Item Price",
- "name_case": "Title Case",
- "owner": "Administrator",
+ ],
+ "icon": "fa fa-flag",
+ "idx": 1,
+ "links": [],
+ "modified": "2019-12-31 03:11:09.702250",
+ "modified_by": "Administrator",
+ "module": "Stock",
+ "name": "Item Price",
+ "name_case": "Title Case",
+ "owner": "Administrator",
"permissions": [
{
- "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": 0,
- "share": 1,
- "submit": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "import": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Sales Master Manager",
+ "share": 1,
"write": 1
- },
+ },
{
- "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": "Purchase Master Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "import": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Purchase Master Manager",
+ "share": 1,
"write": 1
}
- ],
- "quick_entry": 1,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
- "sort_order": "ASC",
- "title_field": "item_code",
- "track_changes": 1,
- "track_seen": 0,
- "track_views": 0
+ ],
+ "quick_entry": 1,
+ "sort_order": "ASC",
+ "title_field": "item_name",
+ "track_changes": 1
}
\ No newline at end of file
diff --git a/erpnext/stock/doctype/item_tax/item_tax.json b/erpnext/stock/doctype/item_tax/item_tax.json
index 37daa29..a93e463 100644
--- a/erpnext/stock/doctype/item_tax/item_tax.json
+++ b/erpnext/stock/doctype/item_tax/item_tax.json
@@ -1,107 +1,50 @@
{
- "allow_copy": 0,
- "allow_events_in_timeline": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "beta": 0,
- "creation": "2013-02-22 01:28:01",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "editable_grid": 1,
+ "actions": [],
+ "creation": "2013-02-22 01:28:01",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "item_tax_template",
+ "tax_category",
+ "valid_from"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "item_tax_template",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Item Tax Template",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "tax_type",
- "oldfieldtype": "Link",
- "options": "Item Tax Template",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "item_tax_template",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Item Tax Template",
+ "oldfieldname": "tax_type",
+ "oldfieldtype": "Link",
+ "options": "Item Tax Template",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fetch_from": "",
- "fieldname": "tax_category",
- "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": "Tax Category",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "tax_rate",
- "oldfieldtype": "Currency",
- "options": "Tax Category",
- "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
+ "fieldname": "tax_category",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Tax Category",
+ "oldfieldname": "tax_rate",
+ "oldfieldtype": "Currency",
+ "options": "Tax Category"
+ },
+ {
+ "fieldname": "valid_from",
+ "fieldtype": "Date",
+ "in_list_view": 1,
+ "label": "Valid From"
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 1,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 1,
- "max_attachments": 0,
- "modified": "2018-12-21 23:52:40.798944",
- "modified_by": "Administrator",
- "module": "Stock",
- "name": "Item Tax",
- "owner": "Administrator",
- "permissions": [],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
- "track_changes": 0,
- "track_seen": 0,
- "track_views": 0
+ ],
+ "idx": 1,
+ "istable": 1,
+ "links": [],
+ "modified": "2019-12-28 21:54:40.807849",
+ "modified_by": "Administrator",
+ "module": "Stock",
+ "name": "Item Tax",
+ "owner": "Administrator",
+ "permissions": [],
+ "sort_field": "modified",
+ "sort_order": "DESC"
}
\ No newline at end of file
diff --git a/erpnext/stock/doctype/landed_cost_item/landed_cost_item.json b/erpnext/stock/doctype/landed_cost_item/landed_cost_item.json
index 66c33a1..90a392c 100644
--- a/erpnext/stock/doctype/landed_cost_item/landed_cost_item.json
+++ b/erpnext/stock/doctype/landed_cost_item/landed_cost_item.json
@@ -13,6 +13,7 @@
"qty",
"rate",
"amount",
+ "is_fixed_asset",
"applicable_charges",
"purchase_receipt_item",
"accounting_dimensions_section",
@@ -119,14 +120,25 @@
{
"fieldname": "dimension_col_break",
"fieldtype": "Column Break"
+ },
+ {
+ "default": "0",
+ "fetch_from": "item_code.is_fixed_asset",
+ "fieldname": "is_fixed_asset",
+ "fieldtype": "Check",
+ "hidden": 1,
+ "label": "Is Fixed Asset",
+ "read_only": 1
}
],
"idx": 1,
"istable": 1,
- "modified": "2019-05-26 09:48:15.569956",
+ "modified": "2019-11-12 15:41:21.053462",
"modified_by": "Administrator",
"module": "Stock",
"name": "Landed Cost Item",
"owner": "wasim@webnotestech.com",
- "permissions": []
+ "permissions": [],
+ "sort_field": "modified",
+ "sort_order": "DESC"
}
\ No newline at end of file
diff --git a/erpnext/stock/doctype/landed_cost_taxes_and_charges/landed_cost_taxes_and_charges.json b/erpnext/stock/doctype/landed_cost_taxes_and_charges/landed_cost_taxes_and_charges.json
index 1aaf73f..0cc243d 100644
--- a/erpnext/stock/doctype/landed_cost_taxes_and_charges/landed_cost_taxes_and_charges.json
+++ b/erpnext/stock/doctype/landed_cost_taxes_and_charges/landed_cost_taxes_and_charges.json
@@ -1,129 +1,51 @@
{
- "allow_copy": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "beta": 0,
- "creation": "2014-07-11 11:51:00.453717",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "",
- "editable_grid": 1,
- "engine": "InnoDB",
+ "creation": "2014-07-11 11:51:00.453717",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "expense_account",
+ "description",
+ "col_break3",
+ "amount"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "description",
- "fieldtype": "Small Text",
- "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,
- "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": "description",
+ "fieldtype": "Small Text",
+ "in_list_view": 1,
+ "label": "Description",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "col_break3",
- "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,
- "unique": 0,
+ "fieldname": "col_break3",
+ "fieldtype": "Column Break",
"width": "50%"
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "amount",
- "fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Amount",
- "length": 0,
- "no_copy": 0,
- "options": "Company:company:default_currency",
- "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": "amount",
+ "fieldtype": "Currency",
+ "in_list_view": 1,
+ "label": "Amount",
+ "options": "Company:company:default_currency",
+ "reqd": 1
+ },
+ {
+ "fieldname": "expense_account",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Expense Account",
+ "options": "Account",
+ "reqd": 1
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 1,
- "max_attachments": 0,
- "modified": "2017-11-15 19:27:59.542487",
- "modified_by": "Administrator",
- "module": "Stock",
- "name": "Landed Cost Taxes and Charges",
- "name_case": "",
- "owner": "Administrator",
- "permissions": [],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 0,
- "track_seen": 0
+ ],
+ "istable": 1,
+ "modified": "2019-09-30 18:28:32.070655",
+ "modified_by": "Administrator",
+ "module": "Stock",
+ "name": "Landed Cost Taxes and Charges",
+ "owner": "Administrator",
+ "permissions": [],
+ "sort_field": "modified",
+ "sort_order": "DESC"
}
\ No newline at end of file
diff --git a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.js b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.js
index edc3444..5de1352 100644
--- a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.js
+++ b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.js
@@ -30,6 +30,16 @@
this.frm.add_fetch("receipt_document", "posting_date", "posting_date");
this.frm.add_fetch("receipt_document", "base_grand_total", "grand_total");
+ this.frm.set_query("expense_account", "taxes", function() {
+ return {
+ query: "erpnext.controllers.queries.tax_account_query",
+ filters: {
+ "account_type": ["Tax", "Chargeable", "Income Account", "Expenses Included In Valuation", "Expenses Included In Asset Valuation"],
+ "company": me.frm.doc.company
+ }
+ };
+ });
+
},
refresh: function(frm) {
@@ -38,7 +48,7 @@
<table class="table table-bordered" style="background-color: #f9f9f9;">
<tr><td>
<h4>
- <i class="fa fa-hand-right"></i>
+ <i class="fa fa-hand-right"></i>
${__("Notes")}:
</h4>
<ul>
@@ -96,7 +106,7 @@
var me = this;
if(this.frm.doc.taxes.length) {
-
+
var total_item_cost = 0.0;
var based_on = this.frm.doc.distribute_charges_based_on.toLowerCase();
$.each(this.frm.doc.items || [], function(i, d) {
@@ -105,7 +115,7 @@
var total_charges = 0.0;
$.each(this.frm.doc.items || [], function(i, item) {
- item.applicable_charges = flt(item[based_on]) * flt(me.frm.doc.total_taxes_and_charges) / flt(total_item_cost)
+ item.applicable_charges = flt(item[based_on]) * flt(me.frm.doc.total_taxes_and_charges) / flt(total_item_cost)
item.applicable_charges = flt(item.applicable_charges, precision("applicable_charges", item))
total_charges += item.applicable_charges
});
@@ -119,6 +129,10 @@
},
distribute_charges_based_on: function (frm) {
this.set_applicable_charges_for_item();
+ },
+
+ items_remove: () => {
+ this.trigger('set_applicable_charges_for_item');
}
});
diff --git a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.json b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.json
index c2c6692..0149280 100644
--- a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.json
+++ b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.json
@@ -1,545 +1,149 @@
{
- "allow_copy": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "autoname": "naming_series:",
- "beta": 0,
- "creation": "2014-07-11 11:33:42.547339",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "Document",
- "editable_grid": 0,
- "engine": "InnoDB",
+ "autoname": "naming_series:",
+ "creation": "2014-07-11 11:33:42.547339",
+ "doctype": "DocType",
+ "document_type": "Document",
+ "engine": "InnoDB",
+ "field_order": [
+ "naming_series",
+ "company",
+ "purchase_receipts",
+ "purchase_receipt_items",
+ "get_items_from_purchase_receipts",
+ "items",
+ "sec_break1",
+ "taxes",
+ "section_break_9",
+ "total_taxes_and_charges",
+ "col_break1",
+ "distribute_charges_based_on",
+ "amended_from",
+ "sec_break2",
+ "landed_cost_help"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "",
- "fieldname": "naming_series",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Series",
- "length": 0,
- "no_copy": 1,
- "options": "MAT-LCV-.YYYY.-",
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "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": 1,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "naming_series",
+ "fieldtype": "Select",
+ "label": "Series",
+ "no_copy": 1,
+ "options": "MAT-LCV-.YYYY.-",
+ "print_hide": 1,
+ "reqd": 1,
+ "set_only_once": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "company",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 1,
- "label": "Company",
- "length": 0,
- "no_copy": 0,
- "options": "Company",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 1,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "in_standard_filter": 1,
+ "label": "Company",
+ "options": "Company",
+ "remember_last_selected_value": 1,
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "purchase_receipts",
- "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": "Purchase Receipts",
- "length": 0,
- "no_copy": 0,
- "options": "Landed Cost Purchase Receipt",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "purchase_receipts",
+ "fieldtype": "Table",
+ "label": "Purchase Receipts",
+ "options": "Landed Cost Purchase Receipt",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "purchase_receipt_items",
- "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": "Purchase Receipt Items",
- "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
- },
+ "fieldname": "purchase_receipt_items",
+ "fieldtype": "Section Break",
+ "label": "Purchase Receipt Items"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "get_items_from_purchase_receipts",
- "fieldtype": "Button",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Get Items From Purchase Receipts",
- "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
- },
+ "fieldname": "get_items_from_purchase_receipts",
+ "fieldtype": "Button",
+ "label": "Get Items From Purchase Receipts"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "items",
- "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": "Purchase Receipt Items",
- "length": 0,
- "no_copy": 1,
- "options": "Landed Cost Item",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "items",
+ "fieldtype": "Table",
+ "label": "Purchase Receipt Items",
+ "no_copy": 1,
+ "options": "Landed Cost Item",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "sec_break1",
- "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": "Additional Charges",
- "length": 0,
- "no_copy": 0,
- "options": "",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "sec_break1",
+ "fieldtype": "Section Break",
+ "label": "Applicable Charges"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "taxes",
- "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": "Taxes and Charges",
- "length": 0,
- "no_copy": 0,
- "options": "Landed Cost Taxes and Charges",
- "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
- },
+ "fieldname": "taxes",
+ "fieldtype": "Table",
+ "label": "Taxes and Charges",
+ "options": "Landed Cost Taxes and Charges",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "section_break_9",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "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
- },
+ "fieldname": "section_break_9",
+ "fieldtype": "Section Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "total_taxes_and_charges",
- "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": "Total Taxes and Charges",
- "length": 0,
- "no_copy": 0,
- "options": "Company:company:default_currency",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "total_taxes_and_charges",
+ "fieldtype": "Currency",
+ "label": "Total Taxes and Charges",
+ "options": "Company:company:default_currency",
+ "read_only": 1,
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "col_break1",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "col_break1",
+ "fieldtype": "Column Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "",
- "fieldname": "distribute_charges_based_on",
- "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": "Distribute Charges Based On",
- "length": 0,
- "no_copy": 0,
- "options": "\nQty\nAmount",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "distribute_charges_based_on",
+ "fieldtype": "Select",
+ "label": "Distribute Charges Based On",
+ "options": "Qty\nAmount",
+ "reqd": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "amended_from",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Amended From",
- "length": 0,
- "no_copy": 1,
- "options": "Landed Cost Voucher",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "amended_from",
+ "fieldtype": "Link",
+ "label": "Amended From",
+ "no_copy": 1,
+ "options": "Landed Cost Voucher",
+ "print_hide": 1,
+ "read_only": 1
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "sec_break2",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
+ "fieldname": "sec_break2",
+ "fieldtype": "Section Break"
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "landed_cost_help",
- "fieldtype": "HTML",
- "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": "Landed Cost Help",
- "length": 0,
- "no_copy": 0,
- "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
+ "fieldname": "landed_cost_help",
+ "fieldtype": "HTML",
+ "label": "Landed Cost Help"
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "icon": "icon-usd",
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 1,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2018-08-21 14:44:30.850736",
- "modified_by": "Administrator",
- "module": "Stock",
- "name": "Landed Cost Voucher",
- "name_case": "",
- "owner": "Administrator",
+ ],
+ "icon": "icon-usd",
+ "is_submittable": 1,
+ "modified": "2019-11-21 15:34:10.846093",
+ "modified_by": "Administrator",
+ "module": "Stock",
+ "name": "Landed Cost Voucher",
+ "owner": "Administrator",
"permissions": [
{
- "amend": 1,
- "cancel": 1,
- "create": 1,
- "delete": 1,
- "email": 0,
- "export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 0,
- "read": 1,
- "report": 1,
- "role": "Stock Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 1,
+ "amend": 1,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "export": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Stock Manager",
+ "share": 1,
+ "submit": 1,
"write": 1
}
- ],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 1,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 0,
- "track_seen": 0,
- "track_views": 0
+ ],
+ "show_name_in_global_search": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC"
}
\ No newline at end of file
diff --git a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py
index 3f37093..7df40fb 100644
--- a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py
+++ b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py
@@ -16,16 +16,13 @@
if pr.receipt_document_type and pr.receipt_document:
pr_items = frappe.db.sql("""select pr_item.item_code, pr_item.description,
pr_item.qty, pr_item.base_rate, pr_item.base_amount, pr_item.name,
- pr_item.cost_center, pr_item.asset
+ pr_item.cost_center, pr_item.is_fixed_asset
from `tab{doctype} Item` pr_item where parent = %s
and exists(select name from tabItem
where name = pr_item.item_code and (is_stock_item = 1 or is_fixed_asset=1))
""".format(doctype=pr.receipt_document_type), pr.receipt_document, as_dict=True)
for d in pr_items:
- if d.asset and frappe.db.get_value("Asset", d.asset, 'docstatus') == 1:
- continue
-
item = self.append("items")
item.item_code = d.item_code
item.description = d.description
@@ -37,15 +34,16 @@
item.receipt_document_type = pr.receipt_document_type
item.receipt_document = pr.receipt_document
item.purchase_receipt_item = d.name
+ item.is_fixed_asset = d.is_fixed_asset
def validate(self):
self.check_mandatory()
- self.validate_purchase_receipts()
- self.set_total_taxes_and_charges()
if not self.get("items"):
self.get_items_from_purchase_receipts()
else:
self.validate_applicable_charges_for_item()
+ self.validate_purchase_receipts()
+ self.set_total_taxes_and_charges()
def check_mandatory(self):
if not self.get("purchase_receipts"):
@@ -64,6 +62,7 @@
for item in self.get("items"):
if not item.receipt_document:
frappe.throw(_("Item must be added using 'Get Items from Purchase Receipts' button"))
+
elif item.receipt_document not in receipt_documents:
frappe.throw(_("Item Row {0}: {1} {2} does not exist in above '{1}' table")
.format(item.idx, item.receipt_document_type, item.receipt_document))
@@ -96,8 +95,6 @@
else:
frappe.throw(_("Total Applicable Charges in Purchase Receipt Items table must be same as Total Taxes and Charges"))
-
-
def on_submit(self):
self.update_landed_cost()
@@ -107,6 +104,9 @@
def update_landed_cost(self):
for d in self.get("purchase_receipts"):
doc = frappe.get_doc(d.receipt_document_type, d.receipt_document)
+
+ # check if there are {qty} assets created and linked to this receipt document
+ self.validate_asset_qty_and_status(d.receipt_document_type, doc)
# set landed cost voucher amount in pr item
doc.set_landed_cost_voucher_amount()
@@ -118,23 +118,41 @@
for item in doc.get("items"):
item.db_update()
+ # asset rate will be updated while creating asset gl entries from PI or PY
+
# update latest valuation rate in serial no
- self.update_rate_in_serial_no(doc)
+ self.update_rate_in_serial_no_for_non_asset_items(doc)
# update stock & gl entries for cancelled state of PR
doc.docstatus = 2
doc.update_stock_ledger(allow_negative_stock=True, via_landed_cost_voucher=True)
doc.make_gl_entries_on_cancel(repost_future_gle=False)
-
# update stock & gl entries for submit state of PR
doc.docstatus = 1
doc.update_stock_ledger(allow_negative_stock=True, via_landed_cost_voucher=True)
doc.make_gl_entries()
- def update_rate_in_serial_no(self, receipt_document):
+ def validate_asset_qty_and_status(self, receipt_document_type, receipt_document):
+ for item in self.get('items'):
+ if item.is_fixed_asset:
+ receipt_document_type = 'purchase_invoice' if item.receipt_document_type == 'Purchase Invoice' \
+ else 'purchase_receipt'
+ docs = frappe.db.get_all('Asset', filters={ receipt_document_type: item.receipt_document,
+ 'item_code': item.item_code }, fields=['name', 'docstatus'])
+ if not docs or len(docs) != item.qty:
+ frappe.throw(_('There are not enough asset created or linked to {0}. \
+ Please create or link {1} Assets with respective document.').format(item.receipt_document, item.qty))
+ if docs:
+ for d in docs:
+ if d.docstatus == 1:
+ frappe.throw(_('{2} <b>{0}</b> has submitted Assets.\
+ Remove Item <b>{1}</b> from table to continue.').format(
+ item.receipt_document, item.item_code, item.receipt_document_type))
+
+ def update_rate_in_serial_no_for_non_asset_items(self, receipt_document):
for item in receipt_document.get("items"):
- if item.serial_no:
+ if not item.is_fixed_asset and item.serial_no:
serial_nos = get_serial_nos(item.serial_no)
if serial_nos:
frappe.db.sql("update `tabSerial No` set purchase_rate=%s where name in ({0})"
diff --git a/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py b/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py
index c32f028..988cf52 100644
--- a/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py
+++ b/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py
@@ -14,15 +14,15 @@
class TestLandedCostVoucher(unittest.TestCase):
def test_landed_cost_voucher(self):
frappe.db.set_value("Buying Settings", None, "allow_multiple_items", 1)
- set_perpetual_inventory(1)
- pr = frappe.copy_doc(pr_test_records[0])
- pr.submit()
+
+ pr = make_purchase_receipt(company="_Test Company with perpetual inventory", warehouse = "Stores - TCP1", supplier_warehouse = "Work in Progress - TCP1", get_multiple_items = True, get_taxes_and_charges = True)
+
last_sle = frappe.db.get_value("Stock Ledger Entry", {
"voucher_type": pr.doctype,
"voucher_no": pr.name,
"item_code": "_Test Item",
- "warehouse": "_Test Warehouse - _TC"
+ "warehouse": "Stores - TCP1"
},
fieldname=["qty_after_transaction", "stock_value"], as_dict=1)
@@ -35,7 +35,7 @@
"voucher_type": pr.doctype,
"voucher_no": pr.name,
"item_code": "_Test Item",
- "warehouse": "_Test Warehouse - _TC"
+ "warehouse": "Stores - TCP1"
},
fieldname=["qty_after_transaction", "stock_value"], as_dict=1)
@@ -48,55 +48,57 @@
self.assertTrue(gl_entries)
stock_in_hand_account = get_inventory_account(pr.company, pr.get("items")[0].warehouse)
- fixed_asset_account = get_inventory_account(pr.company, pr.get("items")[1].warehouse)
+ fixed_asset_account = get_inventory_account(pr.company, pr.get("items")[1].warehouse)
if stock_in_hand_account == fixed_asset_account:
expected_values = {
stock_in_hand_account: [800.0, 0.0],
- "Stock Received But Not Billed - _TC": [0.0, 500.0],
- "Expenses Included In Valuation - _TC": [0.0, 300.0]
+ "Stock Received But Not Billed - TCP1": [0.0, 500.0],
+ "Expenses Included In Valuation - TCP1": [0.0, 50.0],
+ "_Test Account Customs Duty - TCP1": [0.0, 150],
+ "_Test Account Shipping Charges - TCP1": [0.0, 100.00]
}
-
else:
expected_values = {
stock_in_hand_account: [400.0, 0.0],
fixed_asset_account: [400.0, 0.0],
- "Stock Received But Not Billed - _TC": [0.0, 500.0],
- "Expenses Included In Valuation - _TC": [0.0, 300.0]
+ "Stock Received But Not Billed - TCP1": [0.0, 500.0],
+ "Expenses Included In Valuation - TCP1": [0.0, 300.0]
}
for gle in gl_entries:
self.assertEqual(expected_values[gle.account][0], gle.debit)
self.assertEqual(expected_values[gle.account][1], gle.credit)
- set_perpetual_inventory(0)
-
+
def test_landed_cost_voucher_against_purchase_invoice(self):
- set_perpetual_inventory(1)
-
+
pi = make_purchase_invoice(update_stock=1, posting_date=frappe.utils.nowdate(),
- posting_time=frappe.utils.nowtime())
+ posting_time=frappe.utils.nowtime(), cash_bank_account="Cash - TCP1",
+ company="_Test Company with perpetual inventory", supplier_warehouse="Work In Progress - TCP1",
+ warehouse= "Stores - TCP1", cost_center = "Main - TCP1",
+ expense_account ="_Test Account Cost for Goods Sold - TCP1")
last_sle = frappe.db.get_value("Stock Ledger Entry", {
"voucher_type": pi.doctype,
"voucher_no": pi.name,
"item_code": "_Test Item",
- "warehouse": "_Test Warehouse - _TC"
+ "warehouse": "Stores - TCP1"
},
fieldname=["qty_after_transaction", "stock_value"], as_dict=1)
submit_landed_cost_voucher("Purchase Invoice", pi.name)
-
- pi_lc_value = frappe.db.get_value("Purchase Invoice Item", {"parent": pi.name},
+
+ pi_lc_value = frappe.db.get_value("Purchase Invoice Item", {"parent": pi.name},
"landed_cost_voucher_amount")
-
+
self.assertEqual(pi_lc_value, 50.0)
last_sle_after_landed_cost = frappe.db.get_value("Stock Ledger Entry", {
"voucher_type": pi.doctype,
"voucher_no": pi.name,
"item_code": "_Test Item",
- "warehouse": "_Test Warehouse - _TC"
+ "warehouse": "Stores - TCP1"
},
fieldname=["qty_after_transaction", "stock_value"], as_dict=1)
@@ -111,21 +113,21 @@
expected_values = {
stock_in_hand_account: [300.0, 0.0],
- "Creditors - _TC": [0.0, 250.0],
- "Expenses Included In Valuation - _TC": [0.0, 50.0]
+ "Creditors - TCP1": [0.0, 250.0],
+ "Expenses Included In Valuation - TCP1": [0.0, 50.0]
}
for gle in gl_entries:
self.assertEqual(expected_values[gle.account][0], gle.debit)
self.assertEqual(expected_values[gle.account][1], gle.credit)
- set_perpetual_inventory(0)
-
- def test_landed_cost_voucher_for_serialized_item(self):
- set_perpetual_inventory(1)
- frappe.db.sql("delete from `tabSerial No` where name in ('SN001', 'SN002', 'SN003', 'SN004', 'SN005')")
- pr = frappe.copy_doc(pr_test_records[0])
+ def test_landed_cost_voucher_for_serialized_item(self):
+ frappe.db.sql("delete from `tabSerial No` where name in ('SN001', 'SN002', 'SN003', 'SN004', 'SN005')")
+ pr = make_purchase_receipt(company="_Test Company with perpetual inventory", warehouse = "Stores - TCP1",
+ supplier_warehouse = "Work in Progress - TCP1", get_multiple_items = True,
+ get_taxes_and_charges = True, do_not_submit = True)
+
pr.items[0].item_code = "_Test Serialized Item"
pr.items[0].serial_no = "SN001\nSN002\nSN003\nSN004\nSN005"
pr.submit()
@@ -138,39 +140,36 @@
["warehouse", "purchase_rate"], as_dict=1)
self.assertEqual(serial_no.purchase_rate - serial_no_rate, 5.0)
- self.assertEqual(serial_no.warehouse, "_Test Warehouse - _TC")
+ self.assertEqual(serial_no.warehouse, "Stores - TCP1")
- set_perpetual_inventory(0)
def test_landed_cost_voucher_for_odd_numbers (self):
- set_perpetual_inventory(1)
- pr = make_purchase_receipt(do_not_save=True)
- pr.items[0].cost_center = "_Test Company - _TC"
+ pr = make_purchase_receipt(company="_Test Company with perpetual inventory", warehouse = "Stores - TCP1", supplier_warehouse = "Work in Progress - TCP1", do_not_save=True)
+ pr.items[0].cost_center = "Main - TCP1"
for x in range(2):
pr.append("items", {
"item_code": "_Test Item",
- "warehouse": "_Test Warehouse - _TC",
- "cost_center": "_Test Company - _TC",
+ "warehouse": "Stores - TCP1",
+ "cost_center": "Main - TCP1",
"qty": 5,
"rate": 50
})
pr.submit()
lcv = submit_landed_cost_voucher("Purchase Receipt", pr.name, 123.22)
-
+
self.assertEqual(lcv.items[0].applicable_charges, 41.07)
- self.assertEqual(lcv.items[2].applicable_charges, 41.08)
-
- set_perpetual_inventory(0)
+ self.assertEqual(lcv.items[2].applicable_charges, 41.08)
+
def submit_landed_cost_voucher(receipt_document_type, receipt_document, charges=50):
ref_doc = frappe.get_doc(receipt_document_type, receipt_document)
-
+
lcv = frappe.new_doc("Landed Cost Voucher")
lcv.company = "_Test Company"
lcv.distribute_charges_based_on = 'Amount'
-
+
lcv.set("purchase_receipts", [{
"receipt_document_type": receipt_document_type,
"receipt_document": receipt_document,
@@ -178,21 +177,21 @@
"posting_date": ref_doc.posting_date,
"grand_total": ref_doc.base_grand_total
}])
-
+
lcv.set("taxes", [{
"description": "Insurance Charges",
- "account": "_Test Account Insurance Charges - _TC",
+ "expense_account": "Expenses Included In Valuation - TCP1",
"amount": charges
}])
lcv.insert()
-
+
distribute_landed_cost_on_items(lcv)
-
+
lcv.submit()
return lcv
-
+
def distribute_landed_cost_on_items(lcv):
based_on = lcv.distribute_charges_based_on.lower()
total = sum([flt(d.get(based_on)) for d in lcv.get("items")])
diff --git a/erpnext/stock/doctype/material_request/material_request.js b/erpnext/stock/doctype/material_request/material_request.js
index 99195c3..935d613 100644
--- a/erpnext/stock/doctype/material_request/material_request.js
+++ b/erpnext/stock/doctype/material_request/material_request.js
@@ -230,7 +230,8 @@
make_purchase_order: function(frm) {
frappe.prompt(
- {fieldname:'default_supplier', label: __('For Default Supplier (optional)'), fieldtype: 'Link', options: 'Supplier'},
+ {fieldname:'default_supplier', label: __('For Default Supplier (optional)'), description: __('Selected Supplier\
+ must be the Default Supplier of one of the items below.'), fieldtype: 'Link', options: 'Supplier'},
(values) => {
frappe.model.open_mapped_doc({
method: "erpnext.stock.doctype.material_request.material_request.make_purchase_order",
@@ -238,7 +239,8 @@
args: { default_supplier: values.default_supplier },
run_link_triggers: true
});
- }
+ },
+ __('Enter Supplier')
)
},
diff --git a/erpnext/stock/doctype/packed_item/packed_item.json b/erpnext/stock/doctype/packed_item/packed_item.json
index b089e75..2ac5c42 100644
--- a/erpnext/stock/doctype/packed_item/packed_item.json
+++ b/erpnext/stock/doctype/packed_item/packed_item.json
@@ -18,6 +18,7 @@
"serial_no",
"column_break_11",
"batch_no",
+ "actual_batch_qty",
"section_break_13",
"actual_qty",
"projected_qty",
@@ -189,15 +190,26 @@
"oldfieldtype": "Data",
"print_hide": 1,
"read_only": 1
+ },
+ {
+ "depends_on": "batch_no",
+ "fieldname": "actual_batch_qty",
+ "fieldtype": "Float",
+ "label": "Actual Batch Quantity",
+ "no_copy": 1,
+ "print_hide": 1,
+ "read_only": 1
}
],
"idx": 1,
"istable": 1,
- "modified": "2019-08-27 18:17:37.167512",
+ "modified": "2019-11-26 20:09:59.400960",
"modified_by": "Administrator",
"module": "Stock",
"name": "Packed Item",
"owner": "Administrator",
"permissions": [],
+ "sort_field": "modified",
+ "sort_order": "DESC",
"track_changes": 1
}
diff --git a/erpnext/stock/doctype/packed_item/packed_item.py b/erpnext/stock/doctype/packed_item/packed_item.py
index 831381c..5341f29 100644
--- a/erpnext/stock/doctype/packed_item/packed_item.py
+++ b/erpnext/stock/doctype/packed_item/packed_item.py
@@ -65,7 +65,7 @@
bin = get_bin_qty(packing_item_code, pi.warehouse)
pi.actual_qty = flt(bin.get("actual_qty"))
pi.projected_qty = flt(bin.get("projected_qty"))
- if old_packed_items_map:
+ if old_packed_items_map and old_packed_items_map.get((packing_item_code, main_item_row.item_code)):
pi.batch_no = old_packed_items_map.get((packing_item_code, main_item_row.item_code))[0].batch_no
pi.serial_no = old_packed_items_map.get((packing_item_code, main_item_row.item_code))[0].serial_no
pi.warehouse = old_packed_items_map.get((packing_item_code, main_item_row.item_code))[0].warehouse
diff --git a/erpnext/stock/doctype/pick_list/pick_list.js b/erpnext/stock/doctype/pick_list/pick_list.js
index 3f66743..2789711 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.js
+++ b/erpnext/stock/doctype/pick_list/pick_list.js
@@ -173,8 +173,10 @@
});
function get_item_details(item_code, uom=null) {
- return frappe.xcall('erpnext.stock.doctype.pick_list.pick_list.get_item_details', {
- item_code,
- uom
- });
+ if (item_code) {
+ return frappe.xcall('erpnext.stock.doctype.pick_list.pick_list.get_item_details', {
+ item_code,
+ uom
+ });
+ }
}
\ No newline at end of file
diff --git a/erpnext/stock/doctype/price_list/price_list.py b/erpnext/stock/doctype/price_list/price_list.py
index 8773b9c..33713fa 100644
--- a/erpnext/stock/doctype/price_list/price_list.py
+++ b/erpnext/stock/doctype/price_list/price_list.py
@@ -16,6 +16,7 @@
def on_update(self):
self.set_default_if_missing()
self.update_item_price()
+ self.delete_price_list_details_key()
def set_default_if_missing(self):
if cint(self.selling):
@@ -32,6 +33,8 @@
(self.currency, cint(self.buying), cint(self.selling), self.name))
def on_trash(self):
+ self.delete_price_list_details_key()
+
def _update_default_price_list(module):
b = frappe.get_doc(module + " Settings")
price_list_fieldname = module.lower() + "_price_list"
@@ -43,3 +46,20 @@
for module in ["Selling", "Buying"]:
_update_default_price_list(module)
+
+ def delete_price_list_details_key(self):
+ frappe.cache().hdel("price_list_details", self.name)
+
+def get_price_list_details(price_list):
+ price_list_details = frappe.cache().hget("price_list_details", price_list)
+
+ if not price_list_details:
+ price_list_details = frappe.get_cached_value("Price List", price_list,
+ ["currency", "price_not_uom_dependent", "enabled"], as_dict=1)
+
+ if not price_list_details or not price_list_details.get("enabled"):
+ throw(_("Price List {0} is disabled or does not exist").format(price_list))
+
+ frappe.cache().hset("price_list_details", price_list, price_list_details)
+
+ return price_list_details or {}
\ No newline at end of file
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js
index aef53ed..6b5e40e 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js
@@ -6,27 +6,41 @@
frappe.provide("erpnext.stock");
frappe.ui.form.on("Purchase Receipt", {
- setup: function(frm) {
+ setup: (frm) => {
+ frm.make_methods = {
+ 'Landed Cost Voucher': () => {
+ let lcv = frappe.model.get_new_doc('Landed Cost Voucher');
+ lcv.company = frm.doc.company;
+
+ let lcv_receipt = frappe.model.get_new_doc('Landed Cost Purchase Receipt');
+ lcv_receipt.receipt_document_type = 'Purchase Receipt';
+ lcv_receipt.receipt_document = frm.doc.name;
+ lcv_receipt.supplier = frm.doc.supplier;
+ lcv_receipt.grand_total = frm.doc.grand_total;
+ lcv.purchase_receipts = [lcv_receipt];
+
+ frappe.set_route("Form", lcv.doctype, lcv.name);
+ },
+ }
+
frm.custom_make_buttons = {
'Stock Entry': 'Return',
'Purchase Invoice': 'Invoice'
};
- frm.set_query("asset", "items", function() {
- return {
- filters: {
- "purchase_receipt": frm.doc.name
- }
- }
- });
-
frm.set_query("expense_account", "items", function() {
return {
query: "erpnext.controllers.queries.get_expense_account",
- filters: {'company': frm.doc.company}
+ filters: {'company': frm.doc.company }
}
});
+ frm.set_query("taxes_and_charges", function() {
+ return {
+ filters: {'company': frm.doc.company }
+ }
+ });
+
},
onload: function(frm) {
erpnext.queries.setup_queries(frm, "Warehouse", function() {
@@ -57,7 +71,7 @@
toggle_display_account_head: function(frm) {
var enabled = erpnext.is_perpetual_inventory_enabled(frm.doc.company)
frm.fields_dict["items"].grid.set_column_disp(["cost_center"], enabled);
- },
+ }
});
erpnext.stock.PurchaseReceiptController = erpnext.buying.BuyingController.extend({
@@ -288,4 +302,4 @@
}
});
}
-};
\ No newline at end of file
+};
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json
index d6bc1a9..63ef7ca 100755
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json
@@ -1,4 +1,5 @@
{
+ "actions": [],
"allow_import": 1,
"autoname": "naming_series:",
"creation": "2013-05-21 16:16:39",
@@ -305,6 +306,7 @@
"fieldname": "contact_email",
"fieldtype": "Small Text",
"label": "Contact Email",
+ "options": "Email",
"print_hide": 1,
"read_only": 1
},
@@ -614,7 +616,7 @@
},
{
"fieldname": "other_charges_calculation",
- "fieldtype": "Text",
+ "fieldtype": "Long Text",
"label": "Taxes and Charges Calculation",
"no_copy": 1,
"oldfieldtype": "HTML",
@@ -1056,7 +1058,8 @@
"icon": "fa fa-truck",
"idx": 261,
"is_submittable": 1,
- "modified": "2019-09-27 14:24:49.044505",
+ "links": [],
+ "modified": "2019-12-30 19:12:49.709711",
"modified_by": "Administrator",
"module": "Stock",
"name": "Purchase Receipt",
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
index fae4de3..691f92f 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
@@ -14,7 +14,7 @@
from frappe.desk.notifications import clear_doctype_notifications
from frappe.model.mapper import get_mapped_doc
from erpnext.buying.utils import check_on_hold_or_closed_status
-from erpnext.assets.doctype.asset.asset import get_asset_account, is_cwip_accounting_disabled
+from erpnext.assets.doctype.asset.asset import get_asset_account, is_cwip_accounting_enabled
from erpnext.assets.doctype.asset_category.asset_category import get_asset_category_account
from six import iteritems
@@ -82,12 +82,23 @@
self.validate_with_previous_doc()
self.validate_uom_is_integer("uom", ["qty", "received_qty"])
self.validate_uom_is_integer("stock_uom", "stock_qty")
+ self.validate_cwip_accounts()
self.check_on_hold_or_closed_status()
if getdate(self.posting_date) > getdate(nowdate()):
throw(_("Posting Date cannot be future date"))
+ def validate_cwip_accounts(self):
+ for item in self.get('items'):
+ if item.is_fixed_asset and is_cwip_accounting_enabled(item.asset_category):
+ # check cwip accounts before making auto assets
+ # Improves UX by not giving messages of "Assets Created" before throwing error of not finding arbnb account
+ arbnb_account = self.get_company_default("asset_received_but_not_billed")
+ cwip_account = get_asset_account("capital_work_in_progress_account", asset_category = item.asset_category, \
+ company = self.company)
+ break
+
def validate_with_previous_doc(self):
super(PurchaseReceipt, self).validate_with_previous_doc({
"Purchase Order": {
@@ -195,6 +206,7 @@
from erpnext.accounts.general_ledger import process_gl_map
stock_rbnb = self.get_company_default("stock_received_but_not_billed")
+ landed_cost_entries = get_item_account_wise_additional_cost(self.name)
expenses_included_in_valuation = self.get_company_default("expenses_included_in_valuation")
gl_entries = []
@@ -233,15 +245,16 @@
negative_expense_to_be_booked += flt(d.item_tax_amount)
# Amount added through landed-cost-voucher
- if flt(d.landed_cost_voucher_amount):
- gl_entries.append(self.get_gl_dict({
- "account": expenses_included_in_valuation,
- "against": warehouse_account[d.warehouse]["account"],
- "cost_center": d.cost_center,
- "remarks": self.get("remarks") or _("Accounting Entry for Stock"),
- "credit": flt(d.landed_cost_voucher_amount),
- "project": d.project
- }, item=d))
+ if d.landed_cost_voucher_amount and landed_cost_entries:
+ for account, amount in iteritems(landed_cost_entries[(d.item_code, d.name)]):
+ gl_entries.append(self.get_gl_dict({
+ "account": account,
+ "against": warehouse_account[d.warehouse]["account"],
+ "cost_center": d.cost_center,
+ "remarks": self.get("remarks") or _("Accounting Entry for Stock"),
+ "credit": flt(amount),
+ "project": d.project
+ }, item=d))
# sub-contracting warehouse
if flt(d.rm_supp_cost) and warehouse_account.get(self.supplier_warehouse):
@@ -279,15 +292,15 @@
d.rejected_warehouse not in warehouse_with_no_account:
warehouse_with_no_account.append(d.warehouse)
- self.get_asset_gl_entry(gl_entries, expenses_included_in_valuation)
+ self.get_asset_gl_entry(gl_entries)
# Cost center-wise amount breakup for other charges included for valuation
valuation_tax = {}
for tax in self.get("taxes"):
if tax.category in ("Valuation", "Valuation and Total") and flt(tax.base_tax_amount_after_discount_amount):
if not tax.cost_center:
frappe.throw(_("Cost Center is required in row {0} in Taxes table for type {1}").format(tax.idx, _(tax.category)))
- valuation_tax.setdefault(tax.cost_center, 0)
- valuation_tax[tax.cost_center] += \
+ valuation_tax.setdefault(tax.name, 0)
+ valuation_tax[tax.name] += \
(tax.add_deduct_tax == "Add" and 1 or -1) * flt(tax.base_tax_amount_after_discount_amount)
if negative_expense_to_be_booked and valuation_tax:
@@ -295,37 +308,42 @@
# If expenses_included_in_valuation account has been credited in against PI
# and charges added via Landed Cost Voucher,
# post valuation related charges on "Stock Received But Not Billed"
+ # introduced in 2014 for backward compatibility of expenses already booked in expenses_included_in_valuation account
negative_expense_booked_in_pi = frappe.db.sql("""select name from `tabPurchase Invoice Item` pi
where docstatus = 1 and purchase_receipt=%s
and exists(select name from `tabGL Entry` where voucher_type='Purchase Invoice'
and voucher_no=pi.parent and account=%s)""", (self.name, expenses_included_in_valuation))
- if negative_expense_booked_in_pi:
- expenses_included_in_valuation = stock_rbnb
-
against_account = ", ".join([d.account for d in gl_entries if flt(d.debit) > 0])
total_valuation_amount = sum(valuation_tax.values())
amount_including_divisional_loss = negative_expense_to_be_booked
i = 1
- for cost_center, amount in iteritems(valuation_tax):
- if i == len(valuation_tax):
- applicable_amount = amount_including_divisional_loss
- else:
- applicable_amount = negative_expense_to_be_booked * (amount / total_valuation_amount)
- amount_including_divisional_loss -= applicable_amount
+ for tax in self.get("taxes"):
+ if valuation_tax.get(tax.name):
- gl_entries.append(
- self.get_gl_dict({
- "account": expenses_included_in_valuation,
- "cost_center": cost_center,
- "credit": applicable_amount,
- "remarks": self.remarks or _("Accounting Entry for Stock"),
- "against": against_account
- })
- )
+ if negative_expense_booked_in_pi:
+ account = stock_rbnb
+ else:
+ account = tax.account_head
- i += 1
+ if i == len(valuation_tax):
+ applicable_amount = amount_including_divisional_loss
+ else:
+ applicable_amount = negative_expense_to_be_booked * (valuation_tax[tax.name] / total_valuation_amount)
+ amount_including_divisional_loss -= applicable_amount
+
+ gl_entries.append(
+ self.get_gl_dict({
+ "account": account,
+ "cost_center": tax.cost_center,
+ "credit": applicable_amount,
+ "remarks": self.remarks or _("Accounting Entry for Stock"),
+ "against": against_account
+ }, item=tax)
+ )
+
+ i += 1
if warehouse_with_no_account:
frappe.msgprint(_("No accounting entries for the following warehouses") + ": \n" +
@@ -333,82 +351,87 @@
return process_gl_map(gl_entries)
- def get_asset_gl_entry(self, gl_entries, expenses_included_in_valuation=None):
- arbnb_account, cwip_account = None, None
-
- cwip_disabled = is_cwip_accounting_disabled()
-
- if not expenses_included_in_valuation:
- expenses_included_in_valuation = self.get_company_default("expenses_included_in_valuation")
-
- for d in self.get("items"):
- if d.is_fixed_asset and not (arbnb_account and cwip_account):
- arbnb_account = self.get_company_default("asset_received_but_not_billed")
-
- # CWIP entry
- cwip_account = get_asset_account("capital_work_in_progress_account", d.asset,
- company = self.company)
-
- if d.is_fixed_asset and not cwip_disabled:
-
- asset_amount = flt(d.net_amount) + flt(d.item_tax_amount/self.conversion_rate)
- base_asset_amount = flt(d.base_net_amount + d.item_tax_amount)
-
- cwip_account_currency = get_account_currency(cwip_account)
- gl_entries.append(self.get_gl_dict({
- "account": cwip_account,
- "against": arbnb_account,
- "cost_center": d.cost_center,
- "remarks": self.get("remarks") or _("Accounting Entry for Asset"),
- "debit": base_asset_amount,
- "debit_in_account_currency": (base_asset_amount
- if cwip_account_currency == self.company_currency else asset_amount)
- }, item=d))
-
- # Asset received but not billed
- asset_rbnb_currency = get_account_currency(arbnb_account)
- gl_entries.append(self.get_gl_dict({
- "account": arbnb_account,
- "against": cwip_account,
- "cost_center": d.cost_center,
- "remarks": self.get("remarks") or _("Accounting Entry for Asset"),
- "credit": base_asset_amount,
- "credit_in_account_currency": (base_asset_amount
- if asset_rbnb_currency == self.company_currency else asset_amount)
- }, item=d))
-
- if d.is_fixed_asset and flt(d.landed_cost_voucher_amount):
- asset_account = (get_asset_category_account(d.asset, 'fixed_asset_account',
- company = self.company) if cwip_disabled else cwip_account)
-
- gl_entries.append(self.get_gl_dict({
- "account": expenses_included_in_valuation,
- "against": asset_account,
- "cost_center": d.cost_center,
- "remarks": self.get("remarks") or _("Accounting Entry for Stock"),
- "credit": flt(d.landed_cost_voucher_amount),
- "project": d.project
- }, item=d))
-
- gl_entries.append(self.get_gl_dict({
- "account": asset_account,
- "against": expenses_included_in_valuation,
- "cost_center": d.cost_center,
- "remarks": self.get("remarks") or _("Accounting Entry for Stock"),
- "debit": flt(d.landed_cost_voucher_amount),
- "project": d.project
- }, item=d))
-
- if d.asset:
- doc = frappe.get_doc("Asset", d.asset)
- frappe.db.set_value("Asset", d.asset, "gross_purchase_amount",
- doc.gross_purchase_amount + flt(d.landed_cost_voucher_amount))
-
- frappe.db.set_value("Asset", d.asset, "purchase_receipt_amount",
- doc.purchase_receipt_amount + flt(d.landed_cost_voucher_amount))
-
+ def get_asset_gl_entry(self, gl_entries):
+ for item in self.get("items"):
+ if item.is_fixed_asset:
+ if is_cwip_accounting_enabled(item.asset_category):
+ self.add_asset_gl_entries(item, gl_entries)
+ if flt(item.landed_cost_voucher_amount):
+ self.add_lcv_gl_entries(item, gl_entries)
+ # update assets gross amount by its valuation rate
+ # valuation rate is total of net rate, raw mat supp cost, tax amount, lcv amount per item
+ self.update_assets(item, item.valuation_rate)
return gl_entries
+ def add_asset_gl_entries(self, item, gl_entries):
+ arbnb_account = self.get_company_default("asset_received_but_not_billed")
+ # This returns category's cwip account if not then fallback to company's default cwip account
+ cwip_account = get_asset_account("capital_work_in_progress_account", asset_category = item.asset_category, \
+ company = self.company)
+
+ asset_amount = flt(item.net_amount) + flt(item.item_tax_amount/self.conversion_rate)
+ base_asset_amount = flt(item.base_net_amount + item.item_tax_amount)
+
+ cwip_account_currency = get_account_currency(cwip_account)
+ # debit cwip account
+ gl_entries.append(self.get_gl_dict({
+ "account": cwip_account,
+ "against": arbnb_account,
+ "cost_center": item.cost_center,
+ "remarks": self.get("remarks") or _("Accounting Entry for Asset"),
+ "debit": base_asset_amount,
+ "debit_in_account_currency": (base_asset_amount
+ if cwip_account_currency == self.company_currency else asset_amount)
+ }, item=item))
+
+ asset_rbnb_currency = get_account_currency(arbnb_account)
+ # credit arbnb account
+ gl_entries.append(self.get_gl_dict({
+ "account": arbnb_account,
+ "against": cwip_account,
+ "cost_center": item.cost_center,
+ "remarks": self.get("remarks") or _("Accounting Entry for Asset"),
+ "credit": base_asset_amount,
+ "credit_in_account_currency": (base_asset_amount
+ if asset_rbnb_currency == self.company_currency else asset_amount)
+ }, item=item))
+
+ def add_lcv_gl_entries(self, item, gl_entries):
+ expenses_included_in_asset_valuation = self.get_company_default("expenses_included_in_asset_valuation")
+ if not is_cwip_accounting_enabled(item.asset_category):
+ asset_account = get_asset_category_account(asset_category=item.asset_category, \
+ fieldname='fixed_asset_account', company=self.company)
+ else:
+ # This returns company's default cwip account
+ asset_account = get_asset_account("capital_work_in_progress_account", company=self.company)
+
+ gl_entries.append(self.get_gl_dict({
+ "account": expenses_included_in_asset_valuation,
+ "against": asset_account,
+ "cost_center": item.cost_center,
+ "remarks": self.get("remarks") or _("Accounting Entry for Stock"),
+ "credit": flt(item.landed_cost_voucher_amount),
+ "project": item.project
+ }, item=item))
+
+ gl_entries.append(self.get_gl_dict({
+ "account": asset_account,
+ "against": expenses_included_in_asset_valuation,
+ "cost_center": item.cost_center,
+ "remarks": self.get("remarks") or _("Accounting Entry for Stock"),
+ "debit": flt(item.landed_cost_voucher_amount),
+ "project": item.project
+ }, item=item))
+
+ def update_assets(self, item, valuation_rate):
+ assets = frappe.db.get_all('Asset',
+ filters={ 'purchase_receipt': self.name, 'item_code': item.item_code }
+ )
+
+ for asset in assets:
+ frappe.db.set_value("Asset", asset.name, "gross_purchase_amount", flt(valuation_rate))
+ frappe.db.set_value("Asset", asset.name, "purchase_receipt_amount", flt(valuation_rate))
+
def update_status(self, status):
self.set_status(update=True, status = status)
self.notify_update()
@@ -515,7 +538,8 @@
"purchase_order_item": "po_detail",
"purchase_order": "purchase_order",
"is_fixed_asset": "is_fixed_asset",
- "asset": "asset",
+ "asset_location": "asset_location",
+ "asset_category": 'asset_category'
},
"postprocess": update_item,
"filter": lambda d: get_pending_qty(d)[0] <= 0 if not doc.get("is_return") else get_pending_qty(d)[0] > 0
@@ -584,3 +608,38 @@
}, target_doc, set_missing_values)
return doclist
+
+def get_item_account_wise_additional_cost(purchase_document):
+ landed_cost_vouchers = frappe.get_all("Landed Cost Purchase Receipt", fields=["parent"],
+ filters = {"receipt_document": purchase_document, "docstatus": 1})
+
+ if not landed_cost_vouchers:
+ return
+
+ total_item_cost = 0
+ item_account_wise_cost = {}
+ item_cost_allocated = []
+
+ for lcv in landed_cost_vouchers:
+ landed_cost_voucher_doc = frappe.get_cached_doc("Landed Cost Voucher", lcv.parent)
+ based_on_field = frappe.scrub(landed_cost_voucher_doc.distribute_charges_based_on)
+
+ for item in landed_cost_voucher_doc.items:
+ if item.purchase_receipt_item not in item_cost_allocated:
+ total_item_cost += item.get(based_on_field)
+ item_cost_allocated.append(item.purchase_receipt_item)
+
+ for lcv in landed_cost_vouchers:
+ landed_cost_voucher_doc = frappe.get_cached_doc("Landed Cost Voucher", lcv.parent)
+ based_on_field = frappe.scrub(landed_cost_voucher_doc.distribute_charges_based_on)
+
+ for item in landed_cost_voucher_doc.items:
+ if item.receipt_document == purchase_document:
+ for account in landed_cost_voucher_doc.taxes:
+ item_account_wise_cost.setdefault((item.item_code, item.purchase_receipt_item), {})
+ item_account_wise_cost[(item.item_code, item.purchase_receipt_item)].setdefault(account.expense_account, 0.0)
+ item_account_wise_cost[(item.item_code, item.purchase_receipt_item)][account.expense_account] += \
+ account.amount * item.get(based_on_field) / total_item_cost
+
+ return item_account_wise_cost
+
diff --git a/erpnext/stock/doctype/purchase_receipt/regional/india.js b/erpnext/stock/doctype/purchase_receipt/regional/india.js
new file mode 100644
index 0000000..b4f1201
--- /dev/null
+++ b/erpnext/stock/doctype/purchase_receipt/regional/india.js
@@ -0,0 +1,3 @@
+{% include "erpnext/regional/india/taxes.js" %}
+
+erpnext.setup_auto_gst_taxation('Purchase Receipt');
\ No newline at end of file
diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
index ab9311b..c80b9bd 100644
--- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
@@ -14,6 +14,7 @@
from six import iteritems
class TestPurchaseReceipt(unittest.TestCase):
def setUp(self):
+ set_perpetual_inventory(0)
frappe.db.set_value("Buying Settings", None, "allow_multiple_items", 1)
def test_make_purchase_invoice(self):
@@ -32,7 +33,6 @@
def test_purchase_receipt_no_gl_entry(self):
company = frappe.db.get_value('Warehouse', '_Test Warehouse - _TC', 'company')
- set_perpetual_inventory(0, company)
existing_bin_stock_value = frappe.db.get_value("Bin", {"item_code": "_Test Item",
"warehouse": "_Test Warehouse - _TC"}, "stock_value")
@@ -52,33 +52,30 @@
self.assertFalse(get_gl_entries("Purchase Receipt", pr.name))
def test_purchase_receipt_gl_entry(self):
- pr = frappe.copy_doc(test_records[0])
- set_perpetual_inventory(1, pr.company)
+ pr = make_purchase_receipt(company="_Test Company with perpetual inventory", warehouse = "Stores - TCP1", supplier_warehouse = "Work in Progress - TCP1", get_multiple_items = True, get_taxes_and_charges = True)
self.assertEqual(cint(erpnext.is_perpetual_inventory_enabled(pr.company)), 1)
- pr.insert()
- pr.submit()
gl_entries = get_gl_entries("Purchase Receipt", pr.name)
self.assertTrue(gl_entries)
- stock_in_hand_account = get_inventory_account(pr.company, pr.get("items")[0].warehouse)
- fixed_asset_account = get_inventory_account(pr.company, pr.get("items")[1].warehouse)
+ stock_in_hand_account = get_inventory_account(pr.company, pr.items[0].warehouse)
+ fixed_asset_account = get_inventory_account(pr.company, pr.items[1].warehouse)
if stock_in_hand_account == fixed_asset_account:
expected_values = {
stock_in_hand_account: [750.0, 0.0],
- "Stock Received But Not Billed - _TC": [0.0, 500.0],
- "Expenses Included In Valuation - _TC": [0.0, 250.0]
+ "Stock Received But Not Billed - TCP1": [0.0, 500.0],
+ "_Test Account Shipping Charges - TCP1": [0.0, 100.0],
+ "_Test Account Customs Duty - TCP1": [0.0, 150.0]
}
else:
expected_values = {
stock_in_hand_account: [375.0, 0.0],
fixed_asset_account: [375.0, 0.0],
- "Stock Received But Not Billed - _TC": [0.0, 500.0],
- "Expenses Included In Valuation - _TC": [0.0, 250.0]
+ "Stock Received But Not Billed - TCP1": [0.0, 500.0],
+ "_Test Account Shipping Charges - TCP1": [0.0, 250.0]
}
-
for gle in gl_entries:
self.assertEqual(expected_values[gle.account][0], gle.debit)
self.assertEqual(expected_values[gle.account][1], gle.credit)
@@ -86,8 +83,6 @@
pr.cancel()
self.assertFalse(get_gl_entries("Purchase Receipt", pr.name))
- set_perpetual_inventory(0, pr.company)
-
def test_subcontracting(self):
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
@@ -132,11 +127,10 @@
pr.get("items")[0].rejected_warehouse)
def test_purchase_return(self):
- set_perpetual_inventory()
- pr = make_purchase_receipt()
+ pr = make_purchase_receipt(company="_Test Company with perpetual inventory", warehouse = "Stores - TCP1", supplier_warehouse = "Work in Progress - TCP1")
- return_pr = make_purchase_receipt(is_return=1, return_against=pr.name, qty=-2)
+ return_pr = make_purchase_receipt(company="_Test Company with perpetual inventory", warehouse = "Stores - TCP1", supplier_warehouse = "Work in Progress - TCP1", is_return=1, return_against=pr.name, qty=-2)
# check sle
outgoing_rate = frappe.db.get_value("Stock Ledger Entry", {"voucher_type": "Purchase Receipt",
@@ -153,28 +147,28 @@
expected_values = {
stock_in_hand_account: [0.0, 100.0],
- "Stock Received But Not Billed - _TC": [100.0, 0.0],
+ "Stock Received But Not Billed - TCP1": [100.0, 0.0],
}
for gle in gl_entries:
self.assertEqual(expected_values[gle.account][0], gle.debit)
self.assertEqual(expected_values[gle.account][1], gle.credit)
- set_perpetual_inventory(0)
def test_purchase_return_for_rejected_qty(self):
- set_perpetual_inventory()
+ from erpnext.stock.doctype.warehouse.test_warehouse import get_warehouse
- pr = make_purchase_receipt(received_qty=4, qty=2)
+ rejected_warehouse=get_warehouse(company = "_Test Company with perpetual inventory", abbr = " - TCP1", warehouse_name = "_Test Rejected Warehouse").name
+ print(rejected_warehouse)
+ pr = make_purchase_receipt(company="_Test Company with perpetual inventory", warehouse = "Stores - TCP1", supplier_warehouse = "Work in Progress - TCP1", received_qty=4, qty=2, rejected_warehouse=rejected_warehouse)
- return_pr = make_purchase_receipt(is_return=1, return_against=pr.name, received_qty = -4, qty=-2)
+ return_pr = make_purchase_receipt(company="_Test Company with perpetual inventory", warehouse = "Stores - TCP1", supplier_warehouse = "Work in Progress - TCP1", is_return=1, return_against=pr.name, received_qty = -4, qty=-2, rejected_warehouse=rejected_warehouse)
actual_qty = frappe.db.get_value("Stock Ledger Entry", {"voucher_type": "Purchase Receipt",
"voucher_no": return_pr.name, 'warehouse': return_pr.items[0].rejected_warehouse}, "actual_qty")
self.assertEqual(actual_qty, -2)
- set_perpetual_inventory(0)
def test_purchase_return_for_serialized_items(self):
def _check_serial_no_values(serial_no, field_values):
@@ -288,8 +282,8 @@
serial_no=serial_no, basic_rate=100, do_not_submit=True)
self.assertRaises(SerialNoDuplicateError, se.submit)
- def test_serialized_asset_item(self):
- asset_item = "Test Serialized Asset Item"
+ def test_auto_asset_creation(self):
+ asset_item = "Test Asset Item"
if not frappe.db.exists('Item', asset_item):
asset_category = frappe.get_all('Asset Category')
@@ -315,38 +309,25 @@
asset_category = doc.name
item_data = make_item(asset_item, {'is_stock_item':0,
- 'stock_uom': 'Box', 'is_fixed_asset': 1, 'has_serial_no': 1,
- 'asset_category': asset_category, 'serial_no_series': 'ABC.###'})
+ 'stock_uom': 'Box', 'is_fixed_asset': 1, 'auto_create_assets': 1,
+ 'asset_category': asset_category, 'asset_naming_series': 'ABC.###'})
asset_item = item_data.item_code
pr = make_purchase_receipt(item_code=asset_item, qty=3)
- asset = frappe.db.get_value('Asset', {'purchase_receipt': pr.name}, 'name')
- asset_movement = frappe.db.get_value('Asset Movement', {'reference_name': pr.name}, 'name')
- serial_nos = frappe.get_all('Serial No', {'asset': asset}, 'name')
+ assets = frappe.db.get_all('Asset', filters={'purchase_receipt': pr.name})
- self.assertEquals(len(serial_nos), 3)
+ self.assertEquals(len(assets), 3)
- location = frappe.db.get_value('Serial No', serial_nos[0].name, 'location')
+ location = frappe.db.get_value('Asset', assets[0].name, 'location')
self.assertEquals(location, "Test Location")
- frappe.db.set_value("Asset", asset, "purchase_receipt", "")
- frappe.db.set_value("Purchase Receipt Item", pr.items[0].name, "asset", "")
-
- pr.load_from_db()
-
- pr.cancel()
- serial_nos = frappe.get_all('Serial No', {'asset': asset}, 'name') or []
- self.assertEquals(len(serial_nos), 0)
- #frappe.db.sql("delete from `tabLocation")
- frappe.db.sql("delete from `tabAsset`")
-
def test_purchase_receipt_for_enable_allow_cost_center_in_entry_of_bs_account(self):
from erpnext.accounts.doctype.cost_center.test_cost_center import create_cost_center
accounts_settings = frappe.get_doc('Accounts Settings', 'Accounts Settings')
accounts_settings.allow_cost_center_in_entry_of_bs_account = 1
accounts_settings.save()
- cost_center = "_Test Cost Center for BS Account - _TC"
- create_cost_center(cost_center_name="_Test Cost Center for BS Account", company="_Test Company")
+ cost_center = "_Test Cost Center for BS Account - TCP1"
+ create_cost_center(cost_center_name="_Test Cost Center for BS Account", company="_Test Company with perpetual inventory")
if not frappe.db.exists('Location', 'Test Location'):
frappe.get_doc({
@@ -354,8 +335,7 @@
'location_name': 'Test Location'
}).insert()
- set_perpetual_inventory(1, "_Test Company")
- pr = make_purchase_receipt(cost_center=cost_center)
+ pr = make_purchase_receipt(cost_center=cost_center, company="_Test Company with perpetual inventory", warehouse = "Stores - TCP1", supplier_warehouse = "Work in Progress - TCP1")
stock_in_hand_account = get_inventory_account(pr.company, pr.get("items")[0].warehouse)
gl_entries = get_gl_entries("Purchase Receipt", pr.name)
@@ -363,7 +343,7 @@
self.assertTrue(gl_entries)
expected_values = {
- "Stock Received But Not Billed - _TC": {
+ "Stock Received But Not Billed - TCP1": {
"cost_center": cost_center
},
stock_in_hand_account: {
@@ -373,7 +353,6 @@
for i, gle in enumerate(gl_entries):
self.assertEqual(expected_values[gle.account]["cost_center"], gle.cost_center)
- set_perpetual_inventory(0, pr.company)
accounts_settings.allow_cost_center_in_entry_of_bs_account = 0
accounts_settings.save()
@@ -387,9 +366,7 @@
'doctype': 'Location',
'location_name': 'Test Location'
}).insert()
-
- set_perpetual_inventory(1, "_Test Company")
- pr = make_purchase_receipt()
+ pr = make_purchase_receipt(company="_Test Company with perpetual inventory", warehouse = "Stores - TCP1", supplier_warehouse = "Work in Progress - TCP1")
stock_in_hand_account = get_inventory_account(pr.company, pr.get("items")[0].warehouse)
gl_entries = get_gl_entries("Purchase Receipt", pr.name)
@@ -397,7 +374,7 @@
self.assertTrue(gl_entries)
expected_values = {
- "Stock Received But Not Billed - _TC": {
+ "Stock Received But Not Billed - TCP1": {
"cost_center": None
},
stock_in_hand_account: {
@@ -407,8 +384,6 @@
for i, gle in enumerate(gl_entries):
self.assertEqual(expected_values[gle.account]["cost_center"], gle.cost_center)
- set_perpetual_inventory(0, pr.company)
-
def test_make_purchase_invoice_from_pr_for_returned_qty(self):
from erpnext.buying.doctype.purchase_order.test_purchase_order import create_purchase_order, create_pr_against_po
@@ -452,6 +427,78 @@
from `tabGL Entry` where voucher_type=%s and voucher_no=%s
order by account desc""", (voucher_type, voucher_no), as_dict=1)
+def get_taxes(**args):
+
+ args = frappe._dict(args)
+
+ return [{'account_head': '_Test Account Shipping Charges - TCP1',
+ 'add_deduct_tax': 'Add',
+ 'category': 'Valuation and Total',
+ 'charge_type': 'Actual',
+ 'cost_center': args.cost_center or 'Main - TCP1',
+ 'description': 'Shipping Charges',
+ 'doctype': 'Purchase Taxes and Charges',
+ 'parentfield': 'taxes',
+ 'rate': 100.0,
+ 'tax_amount': 100.0},
+ {'account_head': '_Test Account VAT - TCP1',
+ 'add_deduct_tax': 'Add',
+ 'category': 'Total',
+ 'charge_type': 'Actual',
+ 'cost_center': args.cost_center or 'Main - TCP1',
+ 'description': 'VAT',
+ 'doctype': 'Purchase Taxes and Charges',
+ 'parentfield': 'taxes',
+ 'rate': 120.0,
+ 'tax_amount': 120.0},
+ {'account_head': '_Test Account Customs Duty - TCP1',
+ 'add_deduct_tax': 'Add',
+ 'category': 'Valuation',
+ 'charge_type': 'Actual',
+ 'cost_center': args.cost_center or 'Main - TCP1',
+ 'description': 'Customs Duty',
+ 'doctype': 'Purchase Taxes and Charges',
+ 'parentfield': 'taxes',
+ 'rate': 150.0,
+ 'tax_amount': 150.0}]
+
+def get_items(**args):
+ args = frappe._dict(args)
+ return [{
+ "base_amount": 250.0,
+ "conversion_factor": 1.0,
+ "description": "_Test Item",
+ "doctype": "Purchase Receipt Item",
+ "item_code": "_Test Item",
+ "item_name": "_Test Item",
+ "parentfield": "items",
+ "qty": 5.0,
+ "rate": 50.0,
+ "received_qty": 5.0,
+ "rejected_qty": 0.0,
+ "stock_uom": "_Test UOM",
+ "uom": "_Test UOM",
+ "warehouse": args.warehouse or "_Test Warehouse - _TC",
+ "cost_center": args.cost_center or "Main - _TC"
+ },
+ {
+ "base_amount": 250.0,
+ "conversion_factor": 1.0,
+ "description": "_Test Item Home Desktop 100",
+ "doctype": "Purchase Receipt Item",
+ "item_code": "_Test Item Home Desktop 100",
+ "item_name": "_Test Item Home Desktop 100",
+ "parentfield": "items",
+ "qty": 5.0,
+ "rate": 50.0,
+ "received_qty": 5.0,
+ "rejected_qty": 0.0,
+ "stock_uom": "_Test UOM",
+ "uom": "_Test UOM",
+ "warehouse": args.warehouse or "_Test Warehouse 1 - _TC",
+ "cost_center": args.cost_center or "Main - _TC"
+ }]
+
def make_purchase_receipt(**args):
if not frappe.db.exists('Location', 'Test Location'):
frappe.get_doc({
@@ -468,7 +515,7 @@
pr.company = args.company or "_Test Company"
pr.supplier = args.supplier or "_Test Supplier"
pr.is_subcontracted = args.is_subcontracted or "No"
- pr.supplier_warehouse = "_Test Warehouse 1 - _TC"
+ pr.supplier_warehouse = args.supplier_warehouse or "_Test Warehouse 1 - _TC"
pr.currency = args.currency or "INR"
pr.is_return = args.is_return
pr.return_against = args.return_against
@@ -476,8 +523,10 @@
received_qty = args.received_qty or qty
rejected_qty = args.rejected_qty or flt(received_qty) - flt(qty)
+ item_code = args.item or args.item_code or "_Test Item"
+ uom = args.uom or frappe.db.get_value("Item", item_code, "stock_uom") or "_Test UOM"
pr.append("items", {
- "item_code": args.item or args.item_code or "_Test Item",
+ "item_code": item_code,
"warehouse": args.warehouse or "_Test Warehouse - _TC",
"qty": qty,
"received_qty": received_qty,
@@ -487,11 +536,21 @@
"conversion_factor": args.conversion_factor or 1.0,
"serial_no": args.serial_no,
"stock_uom": args.stock_uom or "_Test UOM",
- "uom": args.uom or "_Test UOM",
+ "uom": uom,
"cost_center": args.cost_center or frappe.get_cached_value('Company', pr.company, 'cost_center'),
"asset_location": args.location or "Test Location"
})
+ if args.get_multiple_items:
+ pr.items = []
+ for item in get_items(warehouse= args.warehouse, cost_center = args.cost_center or frappe.get_cached_value('Company', pr.company, 'cost_center')):
+ pr.append("items", item)
+
+
+ if args.get_taxes_and_charges:
+ for tax in get_taxes():
+ pr.append("taxes", tax)
+
if not args.do_not_save:
pr.insert()
if not args.do_not_submit:
diff --git a/erpnext/stock/doctype/purchase_receipt/test_records.json b/erpnext/stock/doctype/purchase_receipt/test_records.json
index 7c20991..e7ea9af 100644
--- a/erpnext/stock/doctype/purchase_receipt/test_records.json
+++ b/erpnext/stock/doctype/purchase_receipt/test_records.json
@@ -83,39 +83,5 @@
}
],
"supplier": "_Test Supplier"
- },
-
-
- {
- "buying_price_list": "_Test Price List",
- "company": "_Test Company",
- "conversion_rate": 1.0,
- "currency": "INR",
- "doctype": "Purchase Receipt",
- "base_grand_total": 5000.0,
- "is_subcontracted": "Yes",
- "base_net_total": 5000.0,
- "posting_date": "2013-02-12",
- "items": [
- {
- "base_amount": 5000.0,
- "conversion_factor": 1.0,
- "description": "_Test FG Item",
- "doctype": "Purchase Receipt Item",
- "item_code": "_Test FG Item",
- "item_name": "_Test FG Item",
- "parentfield": "items",
- "qty": 10.0,
- "rate": 500.0,
- "received_qty": 10.0,
- "rejected_qty": 0.0,
- "stock_uom": "_Test UOM",
- "uom": "_Test UOM",
- "warehouse": "_Test Warehouse - _TC",
- "cost_center": "Main - _TC"
- }
- ],
- "supplier": "_Test Supplier",
- "supplier_warehouse": "_Test Warehouse - _TC"
}
]
\ No newline at end of file
diff --git a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json
index 446a488..16ec8db 100644
--- a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json
+++ b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json
@@ -67,26 +67,26 @@
"warehouse_and_reference",
"warehouse",
"rejected_warehouse",
- "quality_inspection",
"purchase_order",
"material_request",
- "purchase_order_item",
- "material_request_item",
"column_break_40",
"is_fixed_asset",
- "asset",
"asset_location",
+ "asset_category",
"schedule_date",
+ "quality_inspection",
"stock_qty",
+ "purchase_order_item",
+ "material_request_item",
"section_break_45",
+ "allow_zero_valuation_rate",
+ "bom",
+ "col_break5",
"serial_no",
"batch_no",
"column_break_48",
"rejected_serial_no",
"expense_account",
- "col_break5",
- "allow_zero_valuation_rate",
- "bom",
"include_exploded_items",
"item_tax_rate",
"accounting_dimensions_section",
@@ -501,21 +501,6 @@
"read_only": 1
},
{
- "depends_on": "is_fixed_asset",
- "fieldname": "asset",
- "fieldtype": "Link",
- "label": "Asset",
- "no_copy": 1,
- "options": "Asset"
- },
- {
- "depends_on": "is_fixed_asset",
- "fieldname": "asset_location",
- "fieldtype": "Link",
- "label": "Asset Location",
- "options": "Location"
- },
- {
"fieldname": "purchase_order",
"fieldtype": "Link",
"label": "Purchase Order",
@@ -553,6 +538,7 @@
"fieldtype": "Section Break"
},
{
+ "depends_on": "eval:!doc.is_fixed_asset",
"fieldname": "serial_no",
"fieldtype": "Small Text",
"in_list_view": 1,
@@ -562,10 +548,11 @@
"oldfieldtype": "Text"
},
{
+ "depends_on": "eval:!doc.is_fixed_asset",
"fieldname": "batch_no",
"fieldtype": "Link",
"in_list_view": 1,
- "label": "Batch No",
+ "label": "Batch No!",
"no_copy": 1,
"oldfieldname": "batch_no",
"oldfieldtype": "Link",
@@ -577,6 +564,7 @@
"fieldtype": "Column Break"
},
{
+ "depends_on": "eval:!doc.is_fixed_asset",
"fieldname": "rejected_serial_no",
"fieldtype": "Small Text",
"label": "Rejected Serial No",
@@ -814,11 +802,28 @@
"fieldtype": "Data",
"label": "Manufacturer Part Number",
"read_only": 1
+ },
+ {
+ "depends_on": "is_fixed_asset",
+ "fieldname": "asset_location",
+ "fieldtype": "Link",
+ "label": "Asset Location",
+ "options": "Location"
+ },
+ {
+ "depends_on": "is_fixed_asset",
+ "fetch_from": "item_code.asset_category",
+ "fieldname": "asset_category",
+ "fieldtype": "Link",
+ "in_preview": 1,
+ "label": "Asset Category",
+ "options": "Asset Category",
+ "read_only": 1
}
],
"idx": 1,
"istable": 1,
- "modified": "2019-09-17 22:33:01.109004",
+ "modified": "2019-10-14 16:03:25.499557",
"modified_by": "Administrator",
"module": "Stock",
"name": "Purchase Receipt Item",
diff --git a/erpnext/stock/doctype/quality_inspection/quality_inspection.py b/erpnext/stock/doctype/quality_inspection/quality_inspection.py
index 738c63c..37ab807 100644
--- a/erpnext/stock/doctype/quality_inspection/quality_inspection.py
+++ b/erpnext/stock/doctype/quality_inspection/quality_inspection.py
@@ -6,6 +6,7 @@
from frappe.model.document import Document
from erpnext.stock.doctype.quality_inspection_template.quality_inspection_template \
import get_template_details
+from frappe.model.mapper import get_mapped_doc
class QualityInspection(Document):
def validate(self):
@@ -84,3 +85,37 @@
parent=filters.get('parent'), cond = cond, mcond = mcond, start = start,
page_len = page_len, qi_condition = qi_condition),
{'parent': filters.get('parent'), 'txt': "%%%s%%" % txt})
+
+def quality_inspection_query(doctype, txt, searchfield, start, page_len, filters):
+ return frappe.get_all('Quality Inspection',
+ limit_start=start,
+ limit_page_length=page_len,
+ filters = {
+ 'docstatus': 1,
+ 'name': ('like', '%%%s%%' % txt),
+ 'item_code': filters.get("item_code"),
+ 'reference_name': ('in', [filters.get("reference_name", ''), ''])
+ }, as_list=1)
+
+@frappe.whitelist()
+def make_quality_inspection(source_name, target_doc=None):
+ def postprocess(source, doc):
+ doc.inspected_by = frappe.session.user
+ doc.get_quality_inspection_template()
+
+ doc = get_mapped_doc("BOM", source_name, {
+ 'BOM': {
+ "doctype": "Quality Inspection",
+ "validation": {
+ "docstatus": ["=", 1]
+ },
+ "field_map": {
+ "name": "bom_no",
+ "item": "item_code",
+ "stock_uom": "uom",
+ "stock_qty": "qty"
+ },
+ }
+ }, target_doc, postprocess)
+
+ return doc
\ No newline at end of file
diff --git a/erpnext/stock/doctype/quick_stock_balance/quick_stock_balance.js b/erpnext/stock/doctype/quick_stock_balance/quick_stock_balance.js
index a6f7343..f261fd9 100644
--- a/erpnext/stock/doctype/quick_stock_balance/quick_stock_balance.js
+++ b/erpnext/stock/doctype/quick_stock_balance/quick_stock_balance.js
@@ -16,7 +16,7 @@
frm.add_custom_button(__('Stock Balance Report'), () => {
frappe.set_route('query-report', 'Stock Balance',
{ 'item_code': frm.doc.item, 'warehouse': frm.doc.warehouse });
- }).addClass("btn-primary");
+ });
}
},
diff --git a/erpnext/stock/doctype/serial_no/serial_no.py b/erpnext/stock/doctype/serial_no/serial_no.py
index 19eb398..23d00da 100644
--- a/erpnext/stock/doctype/serial_no/serial_no.py
+++ b/erpnext/stock/doctype/serial_no/serial_no.py
@@ -353,17 +353,19 @@
def auto_make_serial_nos(args):
serial_nos = get_serial_nos(args.get('serial_no'))
created_numbers = []
+ voucher_type = args.get('voucher_type')
+ item_code = args.get('item_code')
for serial_no in serial_nos:
if frappe.db.exists("Serial No", serial_no):
sr = frappe.get_doc("Serial No", serial_no)
sr.via_stock_ledger = True
- sr.item_code = args.get('item_code')
+ sr.item_code = item_code
sr.warehouse = args.get('warehouse') if args.get('actual_qty', 0) > 0 else None
sr.batch_no = args.get('batch_no')
sr.location = args.get('location')
sr.company = args.get('company')
sr.supplier = args.get('supplier')
- if sr.sales_order and args.get('voucher_type') == "Stock Entry" \
+ if sr.sales_order and voucher_type == "Stock Entry" \
and not args.get('actual_qty', 0) > 0:
sr.sales_order = None
sr.save(ignore_permissions=True)
@@ -371,10 +373,28 @@
created_numbers.append(make_serial_no(serial_no, args))
form_links = list(map(lambda d: frappe.utils.get_link_to_form('Serial No', d), created_numbers))
+
+ # Setting up tranlated title field for all cases
+ singular_title = _("Serial Number Created")
+ multiple_title = _("Serial Numbers Created")
+
+ if voucher_type:
+ multiple_title = singular_title = _("{0} Created").format(voucher_type)
+
if len(form_links) == 1:
- frappe.msgprint(_("Serial No {0} created").format(form_links[0]))
+ frappe.msgprint(_("Serial No {0} Created").format(form_links[0]), singular_title)
elif len(form_links) > 0:
- frappe.msgprint(_("The following serial numbers were created: <br> {0}").format(', '.join(form_links)))
+ message = _("The following serial numbers were created: <br><br> {0}").format(get_items_html(form_links, item_code))
+ frappe.msgprint(message, multiple_title)
+
+def get_items_html(serial_nos, item_code):
+ body = ', '.join(serial_nos)
+ return '''<details><summary>
+ <b>{0}:</b> {1} Serial Numbers <span class="caret"></span>
+ </summary>
+ <div class="small">{2}</div></details>
+ '''.format(item_code, len(serial_nos), body)
+
def get_item_details(item_code):
return frappe.db.sql("""select name, has_batch_no, docstatus,
@@ -397,7 +417,7 @@
sr.via_stock_ledger = args.get('via_stock_ledger') or True
sr.asset = args.get('asset')
sr.location = args.get('location')
-
+
if args.get('purchase_document_type'):
sr.purchase_document_type = args.get('purchase_document_type')
diff --git a/erpnext/stock/doctype/serial_no/serial_no_list.js b/erpnext/stock/doctype/serial_no/serial_no_list.js
new file mode 100644
index 0000000..5b1e312
--- /dev/null
+++ b/erpnext/stock/doctype/serial_no/serial_no_list.js
@@ -0,0 +1,14 @@
+frappe.listview_settings['Serial No'] = {
+ add_fields: ["is_cancelled", "item_code", "warehouse", "warranty_expiry_date", "delivery_document_type"],
+ get_indicator: (doc) => {
+ if (doc.is_cancelled) {
+ return [__("Cancelled"), "red", "is_cancelled,=,Yes"];
+ } else if (doc.delivery_document_type) {
+ return [__("Delivered"), "green", "delivery_document_type,is,set|is_cancelled,=,No"];
+ } else if (doc.warranty_expiry_date && frappe.datetime.get_diff(doc.warranty_expiry_date, frappe.datetime.nowdate()) <= 0) {
+ return [__("Expired"), "red", "warranty_expiry_date,not in,|warranty_expiry_date,<=,Today|delivery_document_type,is,not set|is_cancelled,=,No"];
+ } else {
+ return [__("Active"), "green", "delivery_document_type,is,not set|is_cancelled,=,No"];
+ }
+ }
+};
diff --git a/erpnext/stock/doctype/serial_no/test_serial_no.py b/erpnext/stock/doctype/serial_no/test_serial_no.py
index ed70790..ab06107 100644
--- a/erpnext/stock/doctype/serial_no/test_serial_no.py
+++ b/erpnext/stock/doctype/serial_no/test_serial_no.py
@@ -12,6 +12,7 @@
from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse
+from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory
test_dependencies = ["Item"]
test_records = frappe.get_test_records('Serial No')
@@ -37,6 +38,8 @@
self.assertTrue(SerialNoCannotCannotChangeError, sr.save)
def test_inter_company_transfer(self):
+ set_perpetual_inventory(0, "_Test Company 1")
+ set_perpetual_inventory(0)
se = make_serialized_item(target_warehouse="_Test Warehouse - _TC")
serial_nos = get_serial_nos(se.get("items")[0].serial_no)
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.js b/erpnext/stock/doctype/stock_entry/stock_entry.js
index 0b02302..38e1bc4 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.js
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.js
@@ -68,6 +68,16 @@
}
});
+ frm.set_query("expense_account", "additional_costs", function() {
+ return {
+ query: "erpnext.controllers.queries.tax_account_query",
+ filters: {
+ "account_type": ["Tax", "Chargeable", "Income Account", "Expenses Included In Valuation", "Expenses Included In Asset Valuation"],
+ "company": frm.doc.company
+ }
+ };
+ });
+
frm.add_fetch("bom_no", "inspection_required", "inspection_required");
},
@@ -92,11 +102,12 @@
frm.set_query("quality_inspection", "items", function(doc, cdt, cdn) {
var d = locals[cdt][cdn];
+
return {
+ query:"erpnext.stock.doctype.quality_inspection.quality_inspection.quality_inspection_query",
filters: {
- docstatus: 1,
- item_code: d.item_code,
- reference_name: doc.name
+ 'item_code': d.item_code,
+ 'reference_name': doc.name
}
}
});
@@ -238,6 +249,8 @@
}, __("Get items from"));
}
+ frm.events.show_bom_custom_button(frm);
+
if (frm.doc.company) {
frm.trigger("toggle_display_account_head");
}
@@ -251,6 +264,11 @@
frm.trigger("setup_quality_inspection");
},
+ stock_entry_type: function(frm){
+ frm.remove_custom_button('Bill of Materials', "Get items from");
+ frm.events.show_bom_custom_button(frm);
+ },
+
purpose: function(frm) {
frm.trigger('validate_purpose_consumption');
frm.fields_dict.items.grid.refresh();
@@ -387,6 +405,85 @@
}
},
+ show_bom_custom_button: function(frm){
+ if (frm.doc.docstatus === 0 &&
+ ['Material Issue', 'Material Receipt', 'Material Transfer', 'Send to Subcontractor'].includes(frm.doc.purpose)) {
+ frm.add_custom_button(__('Bill of Materials'), function() {
+ frm.events.get_items_from_bom(frm);
+ }, __("Get items from"));
+ }
+ },
+
+ get_items_from_bom: function(frm) {
+ let filters = function(){
+ return {filters: { docstatus:1 }};
+ }
+
+ let fields = [
+ {"fieldname":"bom", "fieldtype":"Link", "label":__("BOM"),
+ options:"BOM", reqd: 1, get_query: filters()},
+ {"fieldname":"source_warehouse", "fieldtype":"Link", "label":__("Source Warehouse"),
+ options:"Warehouse"},
+ {"fieldname":"target_warehouse", "fieldtype":"Link", "label":__("Target Warehouse"),
+ options:"Warehouse"},
+ {"fieldname":"qty", "fieldtype":"Float", "label":__("Quantity"),
+ reqd: 1, "default": 1},
+ {"fieldname":"fetch_exploded", "fieldtype":"Check",
+ "label":__("Fetch exploded BOM (including sub-assemblies)"), "default":1},
+ {"fieldname":"fetch", "label":__("Get Items from BOM"), "fieldtype":"Button"}
+ ]
+
+ // Exclude field 'Target Warehouse' in case of Material Issue
+ if (frm.doc.purpose == 'Material Issue'){
+ fields.splice(2,1);
+ }
+ // Exclude field 'Source Warehouse' in case of Material Receipt
+ else if(frm.doc.purpose == 'Material Receipt'){
+ fields.splice(1,1);
+ }
+
+ let d = new frappe.ui.Dialog({
+ title: __("Get Items from BOM"),
+ fields: fields
+ });
+ d.get_input("fetch").on("click", function() {
+ let values = d.get_values();
+ if(!values) return;
+ values["company"] = frm.doc.company;
+ if(!frm.doc.company) frappe.throw(__("Company field is required"));
+ frappe.call({
+ method: "erpnext.manufacturing.doctype.bom.bom.get_bom_items",
+ args: values,
+ callback: function(r) {
+ if (!r.message) {
+ frappe.throw(__("BOM does not contain any stock item"));
+ } else {
+ erpnext.utils.remove_empty_first_row(frm, "items");
+ $.each(r.message, function(i, item) {
+ let d = frappe.model.add_child(cur_frm.doc, "Stock Entry Detail", "items");
+ d.item_code = item.item_code;
+ d.item_name = item.item_name;
+ d.item_group = item.item_group;
+ d.s_warehouse = values.source_warehouse;
+ d.t_warehouse = values.target_warehouse;
+ d.uom = item.stock_uom;
+ d.stock_uom = item.stock_uom;
+ d.conversion_factor = item.conversion_factor ? item.conversion_factor : 1;
+ d.qty = item.qty;
+ d.expense_account = item.expense_account;
+ d.project = item.project;
+ frm.events.set_basic_rate(frm, d.doctype, d.name);
+ });
+ }
+ d.hide();
+ refresh_field("items");
+ }
+ });
+
+ });
+ d.show();
+ },
+
calculate_basic_amount: function(frm, item) {
item.basic_amount = flt(flt(item.transfer_qty) * flt(item.basic_rate),
precision("basic_amount", item));
@@ -525,7 +622,7 @@
if(r.message) {
var d = locals[cdt][cdn];
$.each(r.message, function(k, v) {
- d[k] = v;
+ frappe.model.set_value(cdt, cdn, k, v); // qty and it's subsequent fields weren't triggered
});
refresh_field("items");
erpnext.stock.select_batch_and_serial_no(frm, d);
@@ -727,7 +824,8 @@
return frappe.call({
method: "erpnext.stock.doctype.stock_entry.stock_entry.get_work_order_details",
args: {
- work_order: me.frm.doc.work_order
+ work_order: me.frm.doc.work_order,
+ company: me.frm.doc.company
},
callback: function(r) {
if (!r.exc) {
@@ -743,6 +841,8 @@
if (me.frm.doc.purpose == "Manufacture") {
if (!me.frm.doc.to_warehouse) me.frm.set_value("to_warehouse", r.message["fg_warehouse"]);
if (r.message["additional_costs"].length) {
+ me.frm.clear_table("additional_costs");
+
$.each(r.message["additional_costs"], function(i, row) {
me.frm.add_child("additional_costs", row);
})
@@ -822,8 +922,6 @@
this.frm.toggle_enable("from_warehouse", doc.purpose!='Material Receipt');
this.frm.toggle_enable("to_warehouse", doc.purpose!='Material Issue');
- this.frm.fields_dict["items"].grid.set_column_disp("s_warehouse", doc.purpose!='Material Receipt');
- this.frm.fields_dict["items"].grid.set_column_disp("t_warehouse", doc.purpose!='Material Issue');
this.frm.fields_dict["items"].grid.set_column_disp("retain_sample", doc.purpose=='Material Receipt');
this.frm.fields_dict["items"].grid.set_column_disp("sample_quantity", doc.purpose=='Material Receipt');
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py
index 55e02a4..1c9d4c0 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.py
@@ -75,6 +75,7 @@
set_batch_nos(self, 's_warehouse')
self.set_incoming_rate()
+ self.validate_serialized_batch()
self.set_actual_qty()
self.calculate_rate_and_amount(update_finished_item_rate=False)
@@ -91,6 +92,7 @@
self.update_cost_in_project()
self.validate_reserved_serial_no_consumption()
self.update_transferred_qty()
+ self.update_quality_inspection()
if self.work_order and self.purpose == "Manufacture":
self.update_so_in_serial_number()
@@ -101,13 +103,13 @@
if self.work_order and self.purpose == "Material Consumption for Manufacture":
self.validate_work_order_status()
- else:
- self.update_work_order()
+ self.update_work_order()
self.update_stock_ledger()
self.make_gl_entries_on_cancel()
self.update_cost_in_project()
self.update_transferred_qty()
+ self.update_quality_inspection()
def set_job_card_data(self):
if self.job_card and not self.work_order:
@@ -370,7 +372,7 @@
elif d.t_warehouse and not d.basic_rate:
d.basic_rate = get_valuation_rate(d.item_code, d.t_warehouse,
self.doctype, self.name, d.allow_zero_valuation_rate,
- currency=erpnext.get_company_currency(self.company))
+ currency=erpnext.get_company_currency(self.company), company=self.company)
def set_actual_qty(self):
allow_negative_stock = cint(frappe.db.get_value("Stock Settings", None, "allow_negative_stock"))
@@ -476,10 +478,16 @@
def set_basic_rate_for_finished_goods(self, raw_material_cost, scrap_material_cost):
if self.purpose in ["Manufacture", "Repack"]:
for d in self.get("items"):
- if d.transfer_qty and (d.bom_no or d.t_warehouse) and (getattr(self, "pro_doc", frappe._dict()).scrap_warehouse != d.t_warehouse):
+ if (d.transfer_qty and (d.bom_no or d.t_warehouse) and raw_material_cost
+ and (getattr(self, "pro_doc", frappe._dict()).scrap_warehouse != d.t_warehouse)):
d.basic_rate = flt((raw_material_cost - scrap_material_cost) / flt(d.transfer_qty), d.precision("basic_rate"))
d.basic_amount = flt((raw_material_cost - scrap_material_cost), d.precision("basic_amount"))
+ if (not d.basic_rate and self.work_order and
+ frappe.db.get_single_value("Manufacturing Settings", "material_consumption")):
+ d.basic_rate = get_valuation_rate_for_finished_good_entry(self.work_order) or 0
+ d.basic_amount = d.basic_rate * d.qty
+
def distribute_additional_costs(self):
if self.purpose == "Material Issue":
self.additional_costs = []
@@ -583,12 +591,18 @@
def validate_finished_goods(self):
"""validation: finished good quantity should be same as manufacturing quantity"""
+ if not self.work_order: return
+
items_with_target_warehouse = []
allowance_percentage = flt(frappe.db.get_single_value("Manufacturing Settings",
"overproduction_percentage_for_work_order"))
+ production_item, wo_qty = frappe.db.get_value("Work Order",
+ self.work_order, ["production_item", "qty"])
+
for d in self.get('items'):
- if self.purpose != "Send to Subcontractor" and d.bom_no and flt(d.transfer_qty) > flt(self.fg_completed_qty) and (d.t_warehouse != getattr(self, "pro_doc", frappe._dict()).scrap_warehouse):
+ if (self.purpose != "Send to Subcontractor" and d.bom_no
+ and flt(d.transfer_qty) > flt(self.fg_completed_qty) and d.item_code == production_item):
frappe.throw(_("Quantity in row {0} ({1}) must be same as manufactured quantity {2}"). \
format(d.idx, d.transfer_qty, self.fg_completed_qty))
@@ -596,9 +610,6 @@
items_with_target_warehouse.append(d.item_code)
if self.work_order and self.purpose == "Manufacture":
- production_item, wo_qty = frappe.db.get_value("Work Order",
- self.work_order, ["production_item", "qty"])
-
allowed_qty = wo_qty + (allowance_percentage/100 * wo_qty)
if self.fg_completed_qty > allowed_qty:
frappe.throw(_("For quantity {0} should not be grater than work order quantity {1}")
@@ -644,28 +655,46 @@
self.make_sl_entries(sl_entries, self.amended_from and 'Yes' or 'No')
def get_gl_entries(self, warehouse_account):
- expenses_included_in_valuation = self.get_company_default("expenses_included_in_valuation")
-
gl_entries = super(StockEntry, self).get_gl_entries(warehouse_account)
- for d in self.get("items"):
- additional_cost = flt(d.additional_cost, d.precision("additional_cost"))
- if additional_cost:
- gl_entries.append(self.get_gl_dict({
- "account": expenses_included_in_valuation,
- "against": d.expense_account,
- "cost_center": d.cost_center,
- "remarks": self.get("remarks") or _("Accounting Entry for Stock"),
- "credit": additional_cost
- }, item=d))
+ total_basic_amount = sum([flt(t.basic_amount) for t in self.get("items") if t.t_warehouse])
+ divide_based_on = total_basic_amount
- gl_entries.append(self.get_gl_dict({
- "account": d.expense_account,
- "against": expenses_included_in_valuation,
- "cost_center": d.cost_center,
- "remarks": self.get("remarks") or _("Accounting Entry for Stock"),
- "credit": -1 * additional_cost # put it as negative credit instead of debit purposefully
- }, item=d))
+ if self.get("additional_costs") and not total_basic_amount:
+ # if total_basic_amount is 0, distribute additional charges based on qty
+ divide_based_on = sum(item.qty for item in list(self.get("items")))
+
+ item_account_wise_additional_cost = {}
+
+ for t in self.get("additional_costs"):
+ for d in self.get("items"):
+ if d.t_warehouse:
+ item_account_wise_additional_cost.setdefault((d.item_code, d.name), {})
+ item_account_wise_additional_cost[(d.item_code, d.name)].setdefault(t.expense_account, 0.0)
+
+ multiply_based_on = d.basic_amount if total_basic_amount else d.qty
+
+ item_account_wise_additional_cost[(d.item_code, d.name)][t.expense_account] += \
+ (t.amount * multiply_based_on) / divide_based_on
+
+ if item_account_wise_additional_cost:
+ for d in self.get("items"):
+ for account, amount in iteritems(item_account_wise_additional_cost.get((d.item_code, d.name), {})):
+ gl_entries.append(self.get_gl_dict({
+ "account": account,
+ "against": d.expense_account,
+ "cost_center": d.cost_center,
+ "remarks": self.get("remarks") or _("Accounting Entry for Stock"),
+ "credit": amount
+ }, item=d))
+
+ gl_entries.append(self.get_gl_dict({
+ "account": d.expense_account,
+ "against": account,
+ "cost_center": d.cost_center,
+ "remarks": self.get("remarks") or _("Accounting Entry for Stock"),
+ "credit": -1 * amount # put it as negative credit instead of debit purposefully
+ }, item=d))
return gl_entries
@@ -788,26 +817,27 @@
if self.bom_no:
+ backflush_based_on = frappe.db.get_single_value("Manufacturing Settings",
+ "backflush_raw_materials_based_on")
+
if self.purpose in ["Material Issue", "Material Transfer", "Manufacture", "Repack",
"Send to Subcontractor", "Material Transfer for Manufacture", "Material Consumption for Manufacture"]:
if self.work_order and self.purpose == "Material Transfer for Manufacture":
- item_dict = self.get_pending_raw_materials()
+ item_dict = self.get_pending_raw_materials(backflush_based_on)
if self.to_warehouse and self.pro_doc:
for item in itervalues(item_dict):
item["to_warehouse"] = self.pro_doc.wip_warehouse
self.add_to_stock_entry_detail(item_dict)
elif (self.work_order and (self.purpose == "Manufacture" or self.purpose == "Material Consumption for Manufacture")
- and not self.pro_doc.skip_transfer and frappe.db.get_single_value("Manufacturing Settings",
- "backflush_raw_materials_based_on")== "Material Transferred for Manufacture"):
+ and not self.pro_doc.skip_transfer and backflush_based_on == "Material Transferred for Manufacture"):
self.get_transfered_raw_materials()
- elif self.work_order and (self.purpose == "Manufacture" or self.purpose == "Material Consumption for Manufacture") and \
- frappe.db.get_single_value("Manufacturing Settings", "backflush_raw_materials_based_on")== "BOM" and \
- frappe.db.get_single_value("Manufacturing Settings", "material_consumption")== 1:
+ elif (self.work_order and backflush_based_on== "BOM" and
+ (self.purpose == "Manufacture" or self.purpose == "Material Consumption for Manufacture")
+ and frappe.db.get_single_value("Manufacturing Settings", "material_consumption")== 1):
self.get_unconsumed_raw_materials()
-
else:
if not self.fg_completed_qty:
frappe.throw(_("Manufacturing Quantity is mandatory"))
@@ -824,7 +854,7 @@
and po.name = %s""",self.purchase_order))
for item in itervalues(item_dict):
- if self.pro_doc and (cint(self.pro_doc.from_wip_warehouse) or not self.pro_doc.skip_transfer):
+ if self.pro_doc and cint(self.pro_doc.from_wip_warehouse):
item["from_warehouse"] = self.pro_doc.wip_warehouse
#Get Reserve Warehouse from PO
if self.purchase_order and self.purpose=="Send to Subcontractor":
@@ -1014,10 +1044,6 @@
filters={'parent': self.work_order, 'item_code': item_code},
fields=["required_qty", "consumed_qty"]
)
- if not req_items:
- frappe.msgprint(_("Did not found transfered item {0} in Work Order {1}, the item not added in Stock Entry")
- .format(item_code, self.work_order))
- continue
req_qty = flt(req_items[0].required_qty)
req_qty_each = flt(req_qty / manufacturing_qty)
@@ -1065,18 +1091,20 @@
}
})
- def get_pending_raw_materials(self):
+ def get_pending_raw_materials(self, backflush_based_on=None):
"""
issue (item quantity) that is pending to issue or desire to transfer,
whichever is less
"""
- item_dict = self.get_pro_order_required_items()
+ item_dict = self.get_pro_order_required_items(backflush_based_on)
+
max_qty = flt(self.pro_doc.qty)
for item, item_details in iteritems(item_dict):
pending_to_issue = flt(item_details.required_qty) - flt(item_details.transferred_qty)
desire_to_transfer = flt(self.fg_completed_qty) * flt(item_details.required_qty) / max_qty
- if desire_to_transfer <= pending_to_issue:
+ if (desire_to_transfer <= pending_to_issue or
+ (desire_to_transfer > 0 and backflush_based_on == "Material Transferred for Manufacture")):
item_dict[item]["qty"] = desire_to_transfer
elif pending_to_issue > 0:
item_dict[item]["qty"] = pending_to_issue
@@ -1094,7 +1122,7 @@
return item_dict
- def get_pro_order_required_items(self):
+ def get_pro_order_required_items(self, backflush_based_on=None):
item_dict = frappe._dict()
pro_order = frappe.get_doc("Work Order", self.work_order)
if not frappe.db.get_value("Warehouse", pro_order.wip_warehouse, "is_group"):
@@ -1103,7 +1131,8 @@
wip_warehouse = None
for d in pro_order.get("required_items"):
- if (flt(d.required_qty) > flt(d.transferred_qty) and
+ if ( ((flt(d.required_qty) > flt(d.transferred_qty)) or
+ (backflush_based_on == "Material Transferred for Manufacture")) and
(d.include_item_in_manufacturing or self.purpose != "Material Transfer for Manufacture")):
item_row = d.as_dict()
if d.source_warehouse and not frappe.db.get_value("Warehouse", d.source_warehouse, "is_group"):
@@ -1127,20 +1156,17 @@
se_child.s_warehouse = item_dict[d].get("from_warehouse")
se_child.t_warehouse = item_dict[d].get("to_warehouse")
se_child.item_code = item_dict[d].get('item_code') or cstr(d)
- se_child.item_name = item_dict[d]["item_name"]
- se_child.description = item_dict[d]["description"]
se_child.uom = item_dict[d]["uom"] if item_dict[d].get("uom") else stock_uom
se_child.stock_uom = stock_uom
se_child.qty = flt(item_dict[d]["qty"], se_child.precision("qty"))
- se_child.expense_account = item_dict[d].get("expense_account")
se_child.cost_center = item_dict[d].get("cost_center") or cost_center
se_child.allow_alternative_item = item_dict[d].get("allow_alternative_item", 0)
se_child.subcontracted_item = item_dict[d].get("main_item_code")
- se_child.original_item = item_dict[d].get("original_item")
- se_child.po_detail = item_dict[d].get("po_detail")
- if item_dict[d].get("idx"):
- se_child.idx = item_dict[d].get("idx")
+ for field in ["idx", "po_detail", "original_item",
+ "expense_account", "description", "item_name"]:
+ if item_dict[d].get(field):
+ se_child.set(field, item_dict[d].get(field))
if se_child.s_warehouse==None:
se_child.s_warehouse = self.from_warehouse
@@ -1276,6 +1302,20 @@
self._update_percent_field_in_targets(args, update_modified=True)
+ def update_quality_inspection(self):
+ if self.inspection_required:
+ reference_type = reference_name = ''
+ if self.docstatus == 1:
+ reference_name = self.name
+ reference_type = 'Stock Entry'
+
+ for d in self.items:
+ if d.quality_inspection:
+ frappe.db.set_value("Quality Inspection", d.quality_inspection, {
+ 'reference_type': reference_type,
+ 'reference_name': reference_name
+ })
+
@frappe.whitelist()
def move_sample_to_retention_warehouse(company, items):
if isinstance(items, string_types):
@@ -1349,7 +1389,7 @@
return doclist
@frappe.whitelist()
-def get_work_order_details(work_order):
+def get_work_order_details(work_order, company):
work_order = frappe.get_doc("Work Order", work_order)
pending_qty_to_produce = flt(work_order.qty) - flt(work_order.produced_qty)
@@ -1360,14 +1400,17 @@
"wip_warehouse": work_order.wip_warehouse,
"fg_warehouse": work_order.fg_warehouse,
"fg_completed_qty": pending_qty_to_produce,
- "additional_costs": get_additional_costs(work_order, fg_qty=pending_qty_to_produce)
+ "additional_costs": get_additional_costs(work_order, fg_qty=pending_qty_to_produce, company=company)
}
-def get_additional_costs(work_order=None, bom_no=None, fg_qty=None):
+def get_additional_costs(work_order=None, bom_no=None, fg_qty=None, company=None):
additional_costs = []
operating_cost_per_unit = get_operating_cost_per_unit(work_order, bom_no)
+ expenses_included_in_valuation = frappe.get_cached_value("Company", company, "expenses_included_in_valuation")
+
if operating_cost_per_unit:
additional_costs.append({
+ "expense_account": expenses_included_in_valuation,
"description": "Operating Cost as per Work Order / BOM",
"amount": operating_cost_per_unit * flt(fg_qty)
})
@@ -1377,6 +1420,7 @@
flt(work_order.additional_operating_cost) / flt(work_order.qty)
additional_costs.append({
+ "expense_account": expenses_included_in_valuation,
"description": "Additional Operating Cost",
"amount": additional_operating_cost_per_unit * flt(fg_qty)
})
@@ -1427,6 +1471,24 @@
return used_alternative_items
+def get_valuation_rate_for_finished_good_entry(work_order):
+ work_order_qty = flt(frappe.get_cached_value("Work Order",
+ work_order, 'material_transferred_for_manufacturing'))
+
+ field = "(SUM(total_outgoing_value) / %s) as valuation_rate" % (work_order_qty)
+
+ stock_data = frappe.get_all("Stock Entry",
+ fields = field,
+ filters = {
+ "docstatus": 1,
+ "purpose": "Material Transfer for Manufacture",
+ "work_order": work_order
+ }
+ )
+
+ if stock_data:
+ return stock_data[0].valuation_rate
+
@frappe.whitelist()
def get_uom_details(item_code, uom, qty):
"""Returns dict `{"conversion_factor": [value], "transfer_qty": qty * [value]}`
diff --git a/erpnext/stock/doctype/stock_entry/test_stock_entry.py b/erpnext/stock/doctype/stock_entry/test_stock_entry.py
index 3fa815d..ee5f237 100644
--- a/erpnext/stock/doctype/stock_entry/test_stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/test_stock_entry.py
@@ -16,7 +16,6 @@
from erpnext.accounts.doctype.account.test_account import get_inventory_account
from erpnext.stock.doctype.stock_entry.stock_entry import move_sample_to_retention_warehouse, make_stock_in_entry
from erpnext.stock.doctype.stock_reconciliation.stock_reconciliation import OpeningEntryAccountError
-
from six import iteritems
def get_sle(**args):
@@ -132,20 +131,19 @@
self.assertTrue(item_code in items)
def test_material_receipt_gl_entry(self):
- company = frappe.db.get_value('Warehouse', '_Test Warehouse - _TC', 'company')
- set_perpetual_inventory(1, company)
+ company = frappe.db.get_value('Warehouse', 'Stores - TCP1', 'company')
- mr = make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC",
- qty=50, basic_rate=100, expense_account="Stock Adjustment - _TC")
+ mr = make_stock_entry(item_code="_Test Item", target="Stores - TCP1", company= company,
+ qty=50, basic_rate=100, expense_account="Stock Adjustment - TCP1")
stock_in_hand_account = get_inventory_account(mr.company, mr.get("items")[0].t_warehouse)
self.check_stock_ledger_entries("Stock Entry", mr.name,
- [["_Test Item", "_Test Warehouse - _TC", 50.0]])
+ [["_Test Item", "Stores - TCP1", 50.0]])
self.check_gl_entries("Stock Entry", mr.name,
sorted([
[stock_in_hand_account, 5000.0, 0.0],
- ["Stock Adjustment - _TC", 0.0, 5000.0]
+ ["Stock Adjustment - TCP1", 0.0, 5000.0]
])
)
@@ -158,29 +156,26 @@
where voucher_type='Stock Entry' and voucher_no=%s""", mr.name))
def test_material_issue_gl_entry(self):
- company = frappe.db.get_value('Warehouse', '_Test Warehouse - _TC', 'company')
- set_perpetual_inventory(1, company)
+ company = frappe.db.get_value('Warehouse', 'Stores - TCP1', 'company')
+ make_stock_entry(item_code="_Test Item", target="Stores - TCP1", company= company,
+ qty=50, basic_rate=100, expense_account="Stock Adjustment - TCP1")
- make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC",
- qty=50, basic_rate=100, expense_account="Stock Adjustment - _TC")
-
- mi = make_stock_entry(item_code="_Test Item", source="_Test Warehouse - _TC",
- qty=40, expense_account="Stock Adjustment - _TC")
+ mi = make_stock_entry(item_code="_Test Item", source="Stores - TCP1", company=company,
+ qty=40, expense_account="Stock Adjustment - TCP1")
self.check_stock_ledger_entries("Stock Entry", mi.name,
- [["_Test Item", "_Test Warehouse - _TC", -40.0]])
+ [["_Test Item", "Stores - TCP1", -40.0]])
- stock_in_hand_account = get_inventory_account(mi.company, "_Test Warehouse - _TC")
+ stock_in_hand_account = get_inventory_account(mi.company, "Stores - TCP1")
stock_value_diff = abs(frappe.db.get_value("Stock Ledger Entry", {"voucher_type": "Stock Entry",
"voucher_no": mi.name}, "stock_value_difference"))
self.check_gl_entries("Stock Entry", mi.name,
sorted([
[stock_in_hand_account, 0.0, stock_value_diff],
- ["Stock Adjustment - _TC", stock_value_diff, 0.0]
+ ["Stock Adjustment - TCP1", stock_value_diff, 0.0]
])
)
-
mi.cancel()
self.assertFalse(frappe.db.sql("""select name from `tabStock Ledger Entry`
@@ -190,16 +185,15 @@
where voucher_type='Stock Entry' and voucher_no=%s""", mi.name))
def test_material_transfer_gl_entry(self):
- company = frappe.db.get_value('Warehouse', '_Test Warehouse - _TC', 'company')
- set_perpetual_inventory(1, company)
+ company = frappe.db.get_value('Warehouse', 'Stores - TCP1', 'company')
create_stock_reconciliation(qty=100, rate=100)
- mtn = make_stock_entry(item_code="_Test Item", source="_Test Warehouse - _TC",
- target="_Test Warehouse 1 - _TC", qty=45)
+ mtn = make_stock_entry(item_code="_Test Item", source="Stores - TCP1",
+ target="Finished Goods - TCP1", qty=45)
self.check_stock_ledger_entries("Stock Entry", mtn.name,
- [["_Test Item", "_Test Warehouse - _TC", -45.0], ["_Test Item", "_Test Warehouse 1 - _TC", 45.0]])
+ [["_Test Item", "Stores - TCP1", -45.0], ["_Test Item", "Finished Goods - TCP1", 45.0]])
stock_in_hand_account = get_inventory_account(mtn.company, mtn.get("items")[0].s_warehouse)
@@ -212,7 +206,7 @@
else:
stock_value_diff = abs(frappe.db.get_value("Stock Ledger Entry", {"voucher_type": "Stock Entry",
- "voucher_no": mtn.name, "warehouse": "_Test Warehouse - _TC"}, "stock_value_difference"))
+ "voucher_no": mtn.name, "warehouse": "Stores - TCP1"}, "stock_value_difference"))
self.check_gl_entries("Stock Entry", mtn.name,
sorted([
@@ -255,21 +249,32 @@
set_perpetual_inventory(0, repack.company)
def test_repack_with_additional_costs(self):
- company = frappe.db.get_value('Warehouse', '_Test Warehouse - _TC', 'company')
- set_perpetual_inventory(1, company)
+ company = frappe.db.get_value('Warehouse', 'Stores - TCP1', 'company')
- make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC", qty=50, basic_rate=100)
- repack = frappe.copy_doc(test_records[3])
+ make_stock_entry(item_code="_Test Item", target="Stores - TCP1", company= company,
+ qty=50, basic_rate=100, expense_account="Stock Adjustment - TCP1")
+
+
+ repack = make_stock_entry(company = company, purpose="Repack", do_not_save=True)
repack.posting_date = nowdate()
repack.posting_time = nowtime()
+ expenses_included_in_valuation = frappe.get_value("Company", company, "expenses_included_in_valuation")
+
+ items = get_multiple_items()
+ repack.items = []
+ for item in items:
+ repack.append("items", item)
+
repack.set("additional_costs", [
{
- "description": "Actual Oerating Cost",
+ "expense_account": expenses_included_in_valuation,
+ "description": "Actual Operating Cost",
"amount": 1000
},
{
- "description": "additional operating costs",
+ "expense_account": expenses_included_in_valuation,
+ "description": "Additional Operating Cost",
"amount": 200
},
])
@@ -292,13 +297,12 @@
self.check_gl_entries("Stock Entry", repack.name,
sorted([
[stock_in_hand_account, 1200, 0.0],
- ["Expenses Included In Valuation - _TC", 0.0, 1200.0]
+ ["Expenses Included In Valuation - TCP1", 0.0, 1200.0]
])
)
- set_perpetual_inventory(0, repack.company)
def check_stock_ledger_entries(self, voucher_type, voucher_no, expected_sle):
- expected_sle.sort(key=lambda x: x[0])
+ expected_sle.sort(key=lambda x: x[1])
# check stock ledger entries
sle = frappe.db.sql("""select item_code, warehouse, actual_qty
@@ -306,7 +310,7 @@
and voucher_no = %s order by item_code, warehouse, actual_qty""",
(voucher_type, voucher_no), as_list=1)
self.assertTrue(sle)
- sle.sort(key=lambda x: x[0])
+ sle.sort(key=lambda x: x[1])
for i, sle in enumerate(sle):
self.assertEqual(expected_sle[i][0], sle[0])
@@ -773,14 +777,12 @@
self.assertEqual(doc.per_transferred, 100)
def test_gle_for_opening_stock_entry(self):
- set_perpetual_inventory(1)
-
- mr = make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC",
- qty=50, basic_rate=100, expense_account="Stock Adjustment - _TC", is_opening="Yes", do_not_save=True)
+ mr = make_stock_entry(item_code="_Test Item", target="Stores - TCP1", company="_Test Company with perpetual inventory",qty=50, basic_rate=100, expense_account="Stock Adjustment - TCP1", is_opening="Yes", do_not_save=True)
self.assertRaises(OpeningEntryAccountError, mr.save)
- mr.items[0].expense_account = "Temporary Opening - _TC"
+ mr.items[0].expense_account = "Temporary Opening - TCP1"
+
mr.save()
mr.submit()
@@ -788,6 +790,50 @@
filters={"voucher_type": "Stock Entry", "voucher_no": mr.name}, fieldname="is_opening")
self.assertEqual(is_opening, "Yes")
+ def test_total_basic_amount_zero(self):
+ se = frappe.get_doc({"doctype":"Stock Entry",
+ "purpose":"Material Receipt",
+ "stock_entry_type":"Material Receipt",
+ "posting_date": nowdate(),
+ "company":"_Test Company with perpetual inventory",
+ "items":[
+ {
+ "item_code":"Basil Leaves",
+ "description":"Basil Leaves",
+ "qty": 1,
+ "basic_rate": 0,
+ "uom":"Nos",
+ "t_warehouse": "Stores - TCP1",
+ "allow_zero_valuation_rate": 1,
+ "cost_center": "Main - TCP1"
+ },
+ {
+ "item_code":"Basil Leaves",
+ "description":"Basil Leaves",
+ "qty": 2,
+ "basic_rate": 0,
+ "uom":"Nos",
+ "t_warehouse": "Stores - TCP1",
+ "allow_zero_valuation_rate": 1,
+ "cost_center": "Main - TCP1"
+ },
+ ],
+ "additional_costs":[
+ {"expense_account":"Miscellaneous Expenses - TCP1",
+ "amount":100,
+ "description": "miscellanous"}
+ ]
+ })
+ se.insert()
+ se.submit()
+
+ self.check_gl_entries("Stock Entry", se.name,
+ sorted([
+ ["Stock Adjustment - TCP1", 100.0, 0.0],
+ ["Miscellaneous Expenses - TCP1", 0.0, 100.0]
+ ])
+ )
+
def make_serialized_item(item_code=None, serial_no=None, target_warehouse=None):
se = frappe.copy_doc(test_records[0])
se.get("items")[0].item_code = item_code or "_Test Serialized Item With Series"
@@ -805,14 +851,42 @@
def get_qty_after_transaction(**args):
args = frappe._dict(args)
-
last_sle = get_previous_sle({
"item_code": args.item_code or "_Test Item",
"warehouse": args.warehouse or "_Test Warehouse - _TC",
"posting_date": args.posting_date or nowdate(),
"posting_time": args.posting_time or nowtime()
})
-
return flt(last_sle.get("qty_after_transaction"))
+def get_multiple_items():
+ return [
+ {
+ "conversion_factor": 1.0,
+ "cost_center": "Main - TCP1",
+ "doctype": "Stock Entry Detail",
+ "expense_account": "Stock Adjustment - TCP1",
+ "basic_rate": 100,
+ "item_code": "_Test Item",
+ "qty": 50.0,
+ "s_warehouse": "Stores - TCP1",
+ "stock_uom": "_Test UOM",
+ "transfer_qty": 50.0,
+ "uom": "_Test UOM"
+ },
+ {
+ "conversion_factor": 1.0,
+ "cost_center": "Main - TCP1",
+ "doctype": "Stock Entry Detail",
+ "expense_account": "Stock Adjustment - TCP1",
+ "basic_rate": 5000,
+ "item_code": "_Test Item Home Desktop 100",
+ "qty": 1,
+ "stock_uom": "_Test UOM",
+ "t_warehouse": "Stores - TCP1",
+ "transfer_qty": 1,
+ "uom": "_Test UOM"
+ }
+ ]
+
test_records = frappe.get_test_records('Stock Entry')
diff --git a/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.json b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.json
index 947f948..c9eba71 100644
--- a/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.json
+++ b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.json
@@ -1,874 +1,299 @@
{
"allow_copy": 1,
- "allow_events_in_timeline": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
"autoname": "MAT-SLE-.YYYY.-.#####",
- "beta": 0,
"creation": "2013-01-29 19:25:42",
- "custom": 0,
- "docstatus": 0,
"doctype": "DocType",
"document_type": "Other",
- "editable_grid": 0,
"engine": "InnoDB",
+ "field_order": [
+ "item_code",
+ "serial_no",
+ "batch_no",
+ "warehouse",
+ "posting_date",
+ "posting_time",
+ "voucher_type",
+ "voucher_no",
+ "voucher_detail_no",
+ "actual_qty",
+ "incoming_rate",
+ "outgoing_rate",
+ "stock_uom",
+ "qty_after_transaction",
+ "valuation_rate",
+ "stock_value",
+ "stock_value_difference",
+ "stock_queue",
+ "project",
+ "company",
+ "fiscal_year",
+ "is_cancelled",
+ "to_rename"
+ ],
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "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": 1,
- "in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 1,
"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,
"print_width": "100px",
"read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
"search_index": 1,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
"width": "100px"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "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,
+ "fieldtype": "Long Text",
"in_list_view": 1,
- "in_standard_filter": 0,
"label": "Serial No",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
"print_width": "100px",
"read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
"width": "100px"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "batch_no",
"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": "Batch No",
- "length": 0,
- "no_copy": 0,
"oldfieldname": "batch_no",
"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,
- "translatable": 0,
- "unique": 0
+ "read_only": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "warehouse",
"fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
"in_filter": 1,
- "in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 1,
"label": "Warehouse",
- "length": 0,
- "no_copy": 0,
"oldfieldname": "warehouse",
"oldfieldtype": "Link",
"options": "Warehouse",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
"print_width": "100px",
"read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
"search_index": 1,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
"width": "100px"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "posting_date",
"fieldtype": "Date",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
"in_filter": 1,
- "in_global_search": 0,
"in_list_view": 1,
- "in_standard_filter": 0,
"label": "Posting Date",
- "length": 0,
- "no_copy": 0,
"oldfieldname": "posting_date",
"oldfieldtype": "Date",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
"print_width": "100px",
"read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
"search_index": 1,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
"width": "100px"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "posting_time",
"fieldtype": "Time",
- "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": "Posting Time",
- "length": 0,
- "no_copy": 0,
"oldfieldname": "posting_time",
"oldfieldtype": "Time",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
"print_width": "100px",
"read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
"width": "100px"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "voucher_type",
"fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
"in_filter": 1,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Voucher Type",
- "length": 0,
- "no_copy": 0,
"oldfieldname": "voucher_type",
"oldfieldtype": "Data",
"options": "DocType",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
"print_width": "150px",
"read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
"width": "150px"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "voucher_no",
"fieldtype": "Dynamic Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
"in_filter": 1,
- "in_global_search": 0,
- "in_list_view": 0,
"in_standard_filter": 1,
"label": "Voucher No",
- "length": 0,
- "no_copy": 0,
"oldfieldname": "voucher_no",
"oldfieldtype": "Data",
"options": "voucher_type",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
"print_width": "150px",
"read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
"width": "150px"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "voucher_detail_no",
"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": "Voucher Detail No",
- "length": 0,
- "no_copy": 0,
"oldfieldname": "voucher_detail_no",
"oldfieldtype": "Data",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
"print_width": "150px",
"read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
"width": "150px"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "actual_qty",
"fieldtype": "Float",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
"in_filter": 1,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Actual Quantity",
- "length": 0,
- "no_copy": 0,
"oldfieldname": "actual_qty",
"oldfieldtype": "Currency",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
"print_width": "150px",
"read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
"width": "150px"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "incoming_rate",
"fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Incoming Rate",
- "length": 0,
- "no_copy": 0,
"oldfieldname": "incoming_rate",
"oldfieldtype": "Currency",
"options": "Company:company:default_currency",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "read_only": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "outgoing_rate",
"fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Outgoing Rate",
- "length": 0,
- "no_copy": 0,
"options": "Company:company:default_currency",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "read_only": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "stock_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": "Stock UOM",
- "length": 0,
- "no_copy": 0,
"oldfieldname": "stock_uom",
"oldfieldtype": "Data",
"options": "UOM",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
"print_width": "150px",
"read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
"width": "150px"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "qty_after_transaction",
"fieldtype": "Float",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
"in_filter": 1,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Actual Qty After Transaction",
- "length": 0,
- "no_copy": 0,
"oldfieldname": "bin_aqat",
"oldfieldtype": "Currency",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
"print_width": "150px",
"read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
"width": "150px"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "valuation_rate",
"fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Valuation Rate",
- "length": 0,
- "no_copy": 0,
"oldfieldname": "valuation_rate",
"oldfieldtype": "Currency",
"options": "Company:company:default_currency",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
"print_width": "150px",
"read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
"width": "150px"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "stock_value",
"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": "Stock Value",
- "length": 0,
- "no_copy": 0,
"oldfieldname": "stock_value",
"oldfieldtype": "Currency",
"options": "Company:company:default_currency",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "read_only": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "stock_value_difference",
"fieldtype": "Currency",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Stock Value Difference",
- "length": 0,
- "no_copy": 0,
"options": "Company:company:default_currency",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "read_only": 1
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "stock_queue",
"fieldtype": "Text",
"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": "Stock Queue (FIFO)",
- "length": 0,
- "no_copy": 0,
"oldfieldname": "fcfs_stack",
"oldfieldtype": "Text",
- "permlevel": 0,
"print_hide": 1,
- "print_hide_if_no_value": 0,
"read_only": 1,
- "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": "project",
"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": "Project",
- "length": 0,
- "no_copy": 0,
- "options": "Project",
- "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": "Project"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "company",
"fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
"in_filter": 1,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Company",
- "length": 0,
- "no_copy": 0,
"oldfieldname": "company",
"oldfieldtype": "Data",
"options": "Company",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
"print_width": "150px",
"read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
"width": "150px"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "fiscal_year",
"fieldtype": "Data",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
"in_filter": 1,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
"label": "Fiscal Year",
- "length": 0,
- "no_copy": 0,
"oldfieldname": "fiscal_year",
"oldfieldtype": "Data",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
"print_width": "150px",
"read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0,
"width": "150px"
},
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "is_cancelled",
"fieldtype": "Select",
"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": "Is Cancelled",
- "length": 0,
- "no_copy": 0,
"options": "\nNo\nYes",
- "permlevel": 0,
- "print_hide": 0,
- "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,
"default": "1",
"fieldname": "to_rename",
"fieldtype": "Check",
"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": "To Rename",
- "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": 1,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
+ "search_index": 1
}
],
- "has_web_view": 0,
- "hide_heading": 0,
"hide_toolbar": 1,
"icon": "fa fa-list",
"idx": 1,
- "image_view": 0,
"in_create": 1,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2019-01-07 07:04:37.523024",
+ "modified": "2019-11-27 12:17:31.522675",
"modified_by": "Administrator",
"module": "Stock",
"name": "Stock Ledger Entry",
"owner": "Administrator",
"permissions": [
{
- "amend": 0,
- "cancel": 0,
- "create": 0,
- "delete": 0,
- "email": 0,
"export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
- "role": "Stock User",
- "set_user_permissions": 0,
- "share": 0,
- "submit": 0,
- "write": 0
+ "role": "Stock User"
},
{
- "amend": 0,
- "cancel": 0,
- "create": 0,
- "delete": 0,
- "email": 0,
"export": 1,
- "if_owner": 0,
- "import": 0,
- "permlevel": 0,
- "print": 0,
"read": 1,
"report": 1,
- "role": "Accounts Manager",
- "set_user_permissions": 0,
- "share": 0,
- "submit": 0,
- "write": 0
+ "role": "Accounts Manager"
}
],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
"sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 0,
- "track_seen": 0,
- "track_views": 0
+ "sort_order": "DESC"
}
\ No newline at end of file
diff --git a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
index 98a8c59..ca2741c 100644
--- a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
+++ b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
@@ -52,9 +52,10 @@
def _changed(item):
item_dict = get_stock_balance_for(item.item_code, item.warehouse,
self.posting_date, self.posting_time, batch_no=item.batch_no)
- if (((item.qty is None or item.qty==item_dict.get("qty")) and
- (item.valuation_rate is None or item.valuation_rate==item_dict.get("rate")) and not item.serial_no)
- or (item.serial_no and item.serial_no == item_dict.get("serial_nos"))):
+
+ if ((item.qty is None or item.qty==item_dict.get("qty")) and
+ (item.valuation_rate is None or item.valuation_rate==item_dict.get("rate")) and
+ (not item.serial_no or (item.serial_no == item_dict.get("serial_nos")) )):
return False
else:
# set default as current rates
@@ -182,9 +183,11 @@
from erpnext.stock.stock_ledger import get_previous_sle
sl_entries = []
+ has_serial_no = False
for row in self.items:
item = frappe.get_doc("Item", row.item_code)
if item.has_serial_no or item.has_batch_no:
+ has_serial_no = True
self.get_sle_for_serialized_items(row, sl_entries)
else:
previous_sle = get_previous_sle({
@@ -212,8 +215,14 @@
sl_entries.append(self.get_sle_for_items(row))
if sl_entries:
+ if has_serial_no:
+ sl_entries = self.merge_similar_item_serial_nos(sl_entries)
+
self.make_sl_entries(sl_entries)
+ if has_serial_no and sl_entries:
+ self.update_valuation_rate_for_serial_no()
+
def get_sle_for_serialized_items(self, row, sl_entries):
from erpnext.stock.stock_ledger import get_previous_sle
@@ -275,8 +284,18 @@
# update valuation rate
self.update_valuation_rate_for_serial_nos(row, serial_nos)
+ def update_valuation_rate_for_serial_no(self):
+ for d in self.items:
+ if not d.serial_no: continue
+
+ serial_nos = get_serial_nos(d.serial_no)
+ self.update_valuation_rate_for_serial_nos(d, serial_nos)
+
def update_valuation_rate_for_serial_nos(self, row, serial_nos):
valuation_rate = row.valuation_rate if self.docstatus == 1 else row.current_valuation_rate
+ if valuation_rate is None:
+ return
+
for d in serial_nos:
frappe.db.set_value("Serial No", d, 'purchase_rate', valuation_rate)
@@ -321,11 +340,17 @@
where voucher_type=%s and voucher_no=%s""", (self.doctype, self.name))
sl_entries = []
+
+ has_serial_no = False
for row in self.items:
if row.serial_no or row.batch_no or row.current_serial_no:
+ has_serial_no = True
self.get_sle_for_serialized_items(row, sl_entries)
if sl_entries:
+ if has_serial_no:
+ sl_entries = self.merge_similar_item_serial_nos(sl_entries)
+
sl_entries.reverse()
allow_negative_stock = frappe.db.get_value("Stock Settings", None, "allow_negative_stock")
self.make_sl_entries(sl_entries, allow_negative_stock=allow_negative_stock)
@@ -339,6 +364,35 @@
"posting_time": self.posting_time
})
+ def merge_similar_item_serial_nos(self, sl_entries):
+ # If user has put the same item in multiple row with different serial no
+ new_sl_entries = []
+ merge_similar_entries = {}
+
+ for d in sl_entries:
+ if not d.serial_no or d.actual_qty < 0:
+ new_sl_entries.append(d)
+ continue
+
+ key = (d.item_code, d.warehouse)
+ if key not in merge_similar_entries:
+ merge_similar_entries[key] = d
+ elif d.serial_no:
+ data = merge_similar_entries[key]
+ data.actual_qty += d.actual_qty
+ data.qty_after_transaction += d.qty_after_transaction
+
+ data.valuation_rate = (data.valuation_rate + d.valuation_rate) / data.actual_qty
+ data.serial_no += '\n' + d.serial_no
+
+ if data.incoming_rate:
+ data.incoming_rate = (data.incoming_rate + d.incoming_rate) / data.actual_qty
+
+ for key, value in merge_similar_entries.items():
+ new_sl_entries.append(value)
+
+ return new_sl_entries
+
def get_gl_entries(self, warehouse_account=None):
if not self.cost_center:
msgprint(_("Please enter Cost Center"), raise_exception=1)
@@ -456,7 +510,7 @@
}
serial_nos_list = [serial_no.get("name")
- for serial_no in get_available_serial_nos(item_code, warehouse)]
+ for serial_no in get_available_serial_nos(args)]
qty = len(serial_nos_list)
serial_nos = '\n'.join(serial_nos_list)
diff --git a/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py
index cd05929..e6d7e3f 100644
--- a/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py
+++ b/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py
@@ -7,7 +7,7 @@
from __future__ import unicode_literals
import frappe, unittest
from frappe.utils import flt, nowdate, nowtime
-from erpnext.accounts.utils import get_stock_and_account_difference
+from erpnext.accounts.utils import get_stock_and_account_balance
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory
from erpnext.stock.stock_ledger import get_previous_sle, update_entries_after
from erpnext.stock.doctype.stock_reconciliation.stock_reconciliation import EmptyStockReconciliationItemsError, get_items
@@ -21,7 +21,6 @@
def setUpClass(self):
create_batch_or_serial_no_items()
frappe.db.set_value("Stock Settings", None, "allow_negative_stock", 1)
- insert_existing_sle()
def test_reco_for_fifo(self):
self._test_reco_sle_gle("FIFO")
@@ -30,7 +29,8 @@
self._test_reco_sle_gle("Moving Average")
def _test_reco_sle_gle(self, valuation_method):
- set_perpetual_inventory()
+ insert_existing_sle(warehouse='Stores - TCP1')
+ company = frappe.db.get_value('Warehouse', 'Stores - TCP1', 'company')
# [[qty, valuation_rate, posting_date,
# posting_time, expected_stock_value, bin_qty, bin_valuation]]
input_data = [
@@ -46,14 +46,15 @@
last_sle = get_previous_sle({
"item_code": "_Test Item",
- "warehouse": "_Test Warehouse - _TC",
+ "warehouse": "Stores - TCP1",
"posting_date": d[2],
"posting_time": d[3]
})
# submit stock reconciliation
stock_reco = create_stock_reconciliation(qty=d[0], rate=d[1],
- posting_date=d[2], posting_time=d[3])
+ posting_date=d[2], posting_time=d[3], warehouse="Stores - TCP1",
+ company=company, expense_account = "Stock Adjustment - TCP1")
# check stock value
sle = frappe.db.sql("""select * from `tabStock Ledger Entry`
@@ -73,17 +74,18 @@
# no gl entries
self.assertTrue(frappe.db.get_value("Stock Ledger Entry",
{"voucher_type": "Stock Reconciliation", "voucher_no": stock_reco.name}))
- self.assertFalse(get_stock_and_account_difference(["_Test Account Stock In Hand - _TC"]))
- stock_reco.cancel()
+ acc_bal, stock_bal, wh_list = get_stock_and_account_balance("Stock In Hand - TCP1",
+ stock_reco.posting_date, stock_reco.company)
+ self.assertEqual(acc_bal, stock_bal)
- self.assertFalse(frappe.db.get_value("Stock Ledger Entry",
- {"voucher_type": "Stock Reconciliation", "voucher_no": stock_reco.name}))
+ stock_reco.cancel()
- self.assertFalse(frappe.db.get_value("GL Entry",
- {"voucher_type": "Stock Reconciliation", "voucher_no": stock_reco.name}))
+ self.assertFalse(frappe.db.get_value("Stock Ledger Entry",
+ {"voucher_type": "Stock Reconciliation", "voucher_no": stock_reco.name}))
- set_perpetual_inventory(0)
+ self.assertFalse(frappe.db.get_value("GL Entry",
+ {"voucher_type": "Stock Reconciliation", "voucher_no": stock_reco.name}))
def test_get_items(self):
create_warehouse("_Test Warehouse Group 1", {"is_group": 1})
@@ -203,17 +205,17 @@
stock_doc.cancel()
-def insert_existing_sle():
+def insert_existing_sle(warehouse):
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
make_stock_entry(posting_date="2012-12-15", posting_time="02:00", item_code="_Test Item",
- target="_Test Warehouse - _TC", qty=10, basic_rate=700)
+ target=warehouse, qty=10, basic_rate=700)
make_stock_entry(posting_date="2012-12-25", posting_time="03:00", item_code="_Test Item",
- source="_Test Warehouse - _TC", qty=15)
+ source=warehouse, qty=15)
make_stock_entry(posting_date="2013-01-05", posting_time="07:00", item_code="_Test Item",
- target="_Test Warehouse - _TC", qty=15, basic_rate=1200)
+ target=warehouse, qty=15, basic_rate=1200)
def create_batch_or_serial_no_items():
create_warehouse("_Test Warehouse for Stock Reco1",
@@ -244,7 +246,10 @@
sr.company = args.company or "_Test Company"
sr.expense_account = args.expense_account or \
("Stock Adjustment - _TC" if frappe.get_all("Stock Ledger Entry") else "Temporary Opening - _TC")
- sr.cost_center = args.cost_center or "_Test Cost Center - _TC"
+ sr.cost_center = args.cost_center \
+ or frappe.get_cached_value("Company", sr.company, "cost_center") \
+ or "_Test Cost Center - _TC"
+
sr.append("items", {
"item_code": args.item_code or "_Test Item",
"warehouse": args.warehouse or "_Test Warehouse - _TC",
diff --git a/erpnext/stock/doctype/warehouse/test_records.json b/erpnext/stock/doctype/warehouse/test_records.json
index 014cf3e..e128558 100644
--- a/erpnext/stock/doctype/warehouse/test_records.json
+++ b/erpnext/stock/doctype/warehouse/test_records.json
@@ -1,42 +1,36 @@
[
{
"company": "_Test Company",
- "create_account_under": "Stock Assets - _TC",
"doctype": "Warehouse",
"warehouse_name": "_Test Warehouse",
"is_group": 0
},
{
"company": "_Test Company",
- "create_account_under": "Stock Assets - _TC",
"doctype": "Warehouse",
"warehouse_name": "_Test Scrap Warehouse",
"is_group": 0
},
{
"company": "_Test Company",
- "create_account_under": "Fixed Assets - _TC",
"doctype": "Warehouse",
"warehouse_name": "_Test Warehouse 1",
"is_group": 0
},
{
"company": "_Test Company",
- "create_account_under": "Fixed Assets - _TC",
"doctype": "Warehouse",
"warehouse_name": "_Test Warehouse 2",
"is_group": 0
},
{
"company": "_Test Company",
- "create_account_under": "Stock Assets - _TC",
"doctype": "Warehouse",
"warehouse_name": "_Test Rejected Warehouse",
"is_group": 0
},
{
"company": "_Test Company 1",
- "create_account_under": "Stock Assets - _TC1",
"doctype": "Warehouse",
"warehouse_name": "_Test Warehouse 2",
"is_group": 0
diff --git a/erpnext/stock/doctype/warehouse/test_warehouse.py b/erpnext/stock/doctype/warehouse/test_warehouse.py
index e0483d3..3101e8a 100644
--- a/erpnext/stock/doctype/warehouse/test_warehouse.py
+++ b/erpnext/stock/doctype/warehouse/test_warehouse.py
@@ -105,8 +105,7 @@
w.warehouse_name = warehouse_name
w.parent_warehouse = "_Test Warehouse Group - _TC"
w.company = company
- make_account_for_warehouse(warehouse_name, w)
- w.account = warehouse_id
+ w.account = get_warehouse_account(warehouse_name, company)
if properties:
w.update(properties)
w.save()
@@ -114,9 +113,40 @@
else:
return warehouse_id
-def make_account_for_warehouse(warehouse_name, warehouse_obj):
- if not frappe.db.exists("Account", warehouse_name + " - _TC"):
- parent_account = frappe.db.get_value('Account',
- {'company': warehouse_obj.company, 'is_group':1, 'account_type': 'Stock'},'name')
- account = create_account(account_name=warehouse_name, \
- account_type="Stock", parent_account= parent_account, company=warehouse_obj.company)
\ No newline at end of file
+def get_warehouse(**args):
+ args = frappe._dict(args)
+ if(frappe.db.exists("Warehouse", args.warehouse_name + " - " + args.abbr)):
+ return frappe.get_doc("Warehouse", args.warehouse_name + " - " + args.abbr)
+ else:
+ w = frappe.get_doc({
+ "company": args.company or "_Test Company",
+ "doctype": "Warehouse",
+ "warehouse_name": args.warehouse_name,
+ "is_group": 0,
+ "account": get_warehouse_account(args.warehouse_name, args.company, args.abbr)
+ })
+ w.insert()
+ return w
+
+def get_warehouse_account(warehouse_name, company, company_abbr=None):
+ if not company_abbr:
+ company_abbr = frappe.get_cached_value("Company", company, 'abbr')
+
+ if not frappe.db.exists("Account", warehouse_name + " - " + company_abbr):
+ return create_account(
+ account_name=warehouse_name,
+ parent_account=get_group_stock_account(company, company_abbr),
+ account_type='Stock',
+ company=company)
+ else:
+ return warehouse_name + " - " + company_abbr
+
+
+def get_group_stock_account(company, company_abbr=None):
+ group_stock_account = frappe.db.get_value("Account",
+ filters={'account_type': 'Stock', 'is_group': 1, 'company': company}, fieldname='name')
+ if not group_stock_account:
+ if not company_abbr:
+ company_abbr = frappe.get_cached_value("Company", company, 'abbr')
+ group_stock_account = "Current Assets - " + company_abbr
+ return group_stock_account
\ No newline at end of file
diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py
index 7c2e09e..b80f99d 100644
--- a/erpnext/stock/get_item_details.py
+++ b/erpnext/stock/get_item_details.py
@@ -4,7 +4,7 @@
from __future__ import unicode_literals
import frappe
from frappe import _, throw
-from frappe.utils import flt, cint, add_days, cstr, add_months
+from frappe.utils import flt, cint, add_days, cstr, add_months, getdate
import json, copy
from erpnext.accounts.doctype.pricing_rule.pricing_rule import get_pricing_rule_for_item, set_transaction_type
from erpnext.setup.utils import get_exchange_rate
@@ -12,6 +12,7 @@
from erpnext.stock.doctype.batch.batch import get_batch_no
from erpnext import get_company_currency
from erpnext.stock.doctype.item.item import get_item_defaults, get_uom_conv_factor
+from erpnext.stock.doctype.price_list.price_list import get_price_list_details
from erpnext.setup.doctype.item_group.item_group import get_item_group_defaults
from erpnext.setup.doctype.brand.brand import get_brand_defaults
from erpnext.stock.doctype.item_manufacturer.item_manufacturer import get_item_manufacturer_part_no
@@ -22,7 +23,7 @@
purchase_doctypes = ['Material Request', 'Supplier Quotation', 'Purchase Order', 'Purchase Receipt', 'Purchase Invoice']
@frappe.whitelist()
-def get_item_details(args, doc=None, overwrite_warehouse=True):
+def get_item_details(args, doc=None, for_validate=False, overwrite_warehouse=True):
"""
args = {
"item_code": "",
@@ -51,6 +52,16 @@
out = get_basic_details(args, item, overwrite_warehouse)
+ if isinstance(doc, string_types):
+ doc = json.loads(doc)
+
+ if doc and doc.get('doctype') == 'Purchase Invoice':
+ args['bill_date'] = doc.get('bill_date')
+
+ if doc:
+ args['posting_date'] = doc.get('posting_date')
+ args['transaction_date'] = doc.get('transaction_date')
+
get_item_tax_template(args, item, out)
out["item_tax_rate"] = get_item_tax_map(args.company, args.get("item_tax_template") if out.get("item_tax_template") is None \
else out.get("item_tax_template"), as_json=True)
@@ -74,7 +85,9 @@
if args.get(key) is None:
args[key] = value
- data = get_pricing_rule_for_item(args, out.price_list_rate, doc)
+ data = get_pricing_rule_for_item(args, out.price_list_rate,
+ doc, for_validate=for_validate)
+
out.update(data)
update_stock(args, out)
@@ -210,7 +223,8 @@
project: "",
qty: "",
stock_qty: "",
- conversion_factor: ""
+ conversion_factor: "",
+ against_blanket_order: 0/1
}
:param item: `item_code` of Item object
:return: frappe._dict
@@ -251,6 +265,12 @@
args['material_request_type'] = frappe.db.get_value('Material Request',
args.get('name'), 'material_request_type', cache=True)
+ expense_account = None
+
+ if args.get('doctype') == 'Purchase Invoice' and item.is_fixed_asset:
+ from erpnext.assets.doctype.asset_category.asset_category import get_asset_category_account
+ expense_account = get_asset_category_account(fieldname = "fixed_asset_account", item = args.item_code, company= args.company)
+
#Set the UOM to the Default Sales UOM or Default Purchase UOM if configured in the Item Master
if not args.uom:
if args.get('doctype') in sales_doctypes:
@@ -268,7 +288,7 @@
"image": cstr(item.image).strip(),
"warehouse": warehouse,
"income_account": get_default_income_account(args, item_defaults, item_group_defaults, brand_defaults),
- "expense_account": get_default_expense_account(args, item_defaults, item_group_defaults, brand_defaults),
+ "expense_account": expense_account or get_default_expense_account(args, item_defaults, item_group_defaults, brand_defaults) ,
"cost_center": get_default_cost_center(args, item_defaults, item_group_defaults, brand_defaults),
'has_serial_no': item.has_serial_no,
'has_batch_no': item.has_batch_no,
@@ -293,7 +313,8 @@
"weight_per_unit":item.weight_per_unit,
"weight_uom":item.weight_uom,
"last_purchase_rate": item.last_purchase_rate if args.get("doctype") in ["Purchase Order"] else 0,
- "transaction_date": args.get("transaction_date")
+ "transaction_date": args.get("transaction_date"),
+ "against_blanket_order": args.get("against_blanket_order")
})
if item.get("enable_deferred_revenue") or item.get("enable_deferred_expense"):
@@ -384,7 +405,34 @@
item_tax_template = _get_item_tax_template(args, item_group_doc.taxes, out)
item_group = item_group_doc.parent_item_group
-def _get_item_tax_template(args, taxes, out):
+def _get_item_tax_template(args, taxes, out={}, for_validate=False):
+ taxes_with_validity = []
+ taxes_with_no_validity = []
+
+ for tax in taxes:
+ if tax.valid_from:
+ # In purchase Invoice first preference will be given to supplier invoice date
+ # if supplier date is not present then posting date
+ validation_date = args.get('transaction_date') or args.get('bill_date') or args.get('posting_date')
+
+ if getdate(tax.valid_from) <= getdate(validation_date):
+ taxes_with_validity.append(tax)
+ else:
+ taxes_with_no_validity.append(tax)
+
+ if taxes_with_validity:
+ taxes = sorted(taxes_with_validity, key = lambda i: i.valid_from, reverse=True)
+ else:
+ taxes = taxes_with_no_validity
+
+ if for_validate:
+ return [tax.item_tax_template for tax in taxes if (cstr(tax.tax_category) == cstr(args.get('tax_category')) \
+ and (tax.item_tax_template not in taxes))]
+
+ # all templates have validity and no template is valid
+ if not taxes_with_validity and (not taxes_with_no_validity):
+ return None
+
for tax in taxes:
if cstr(tax.tax_category) == cstr(args.get("tax_category")):
out["item_tax_template"] = tax.item_tax_template
@@ -479,7 +527,6 @@
if meta.get_field("currency") or args.get('currency'):
pl_details = get_price_list_currency_and_exchange_rate(args)
args.update(pl_details)
- validate_price_list(args)
if meta.get_field("currency"):
validate_conversion_rate(args, meta)
@@ -563,7 +610,7 @@
return frappe.db.sql(""" select name, price_list_rate, uom
from `tabItem Price` {conditions}
- order by uom desc, min_qty desc """.format(conditions=conditions), args)
+ order by uom desc, min_qty desc, valid_from desc """.format(conditions=conditions), args)
def get_price_list_rate_for(args, item_code):
"""
@@ -596,10 +643,15 @@
if desired_qty and check_packing_list(price_list_rate[0][0], desired_qty, item_code):
item_price_data = price_list_rate
else:
- for field in ["customer", "supplier", "min_qty"]:
+ for field in ["customer", "supplier"]:
del item_price_args[field]
general_price_list_rate = get_item_price(item_price_args, item_code, ignore_party=args.get("ignore_party"))
+
+ if not general_price_list_rate:
+ del item_price_args["min_qty"]
+ general_price_list_rate = get_item_price(item_price_args, item_code, ignore_party=args.get("ignore_party"))
+
if not general_price_list_rate and args.get("uom") != args.get("stock_uom"):
item_price_args["uom"] = args.get("stock_uom")
general_price_list_rate = get_item_price(item_price_args, item_code, ignore_party=args.get("ignore_party"))
@@ -634,14 +686,6 @@
return flag
-def validate_price_list(args):
- if args.get("price_list"):
- if not frappe.db.get_value("Price List",
- {"name": args.price_list, args.transaction_type: 1, "enabled": 1}):
- throw(_("Price List {0} is disabled or does not exist").format(args.price_list))
- elif args.get("customer"):
- throw(_("Price List not selected"))
-
def validate_conversion_rate(args, meta):
from erpnext.controllers.accounts_controller import validate_conversion_rate
@@ -905,27 +949,6 @@
return item_details
-def get_price_list_currency(price_list):
- if price_list:
- result = frappe.db.get_value("Price List", {"name": price_list,
- "enabled": 1}, ["name", "currency"], as_dict=True)
-
- if not result:
- throw(_("Price List {0} is disabled or does not exist").format(price_list))
-
- return result.currency
-
-def get_price_list_uom_dependant(price_list):
- if price_list:
- result = frappe.db.get_value("Price List", {"name": price_list,
- "enabled": 1}, ["name", "price_not_uom_dependent"], as_dict=True)
-
- if not result:
- throw(_("Price List {0} is disabled or does not exist").format(price_list))
-
- return not result.price_not_uom_dependent
-
-
def get_price_list_currency_and_exchange_rate(args):
if not args.price_list:
return {}
@@ -935,8 +958,11 @@
elif args.doctype in ['Purchase Order', 'Purchase Receipt', 'Purchase Invoice']:
args.update({"exchange_rate": "for_buying"})
- price_list_currency = get_price_list_currency(args.price_list)
- price_list_uom_dependant = get_price_list_uom_dependant(args.price_list)
+ price_list_details = get_price_list_details(args.price_list)
+
+ price_list_currency = price_list_details.get("currency")
+ price_list_uom_dependant = price_list_details.get("price_list_uom_dependant")
+
plc_conversion_rate = args.plc_conversion_rate
company_currency = get_company_currency(args.company)
@@ -1014,9 +1040,10 @@
def update_party_blanket_order(args, out):
- blanket_order_details = get_blanket_order_details(args)
- if blanket_order_details:
- out.update(blanket_order_details)
+ if out["against_blanket_order"]:
+ blanket_order_details = get_blanket_order_details(args)
+ if blanket_order_details:
+ out.update(blanket_order_details)
@frappe.whitelist()
def get_blanket_order_details(args):
diff --git a/erpnext/stock/onboarding_slide/add_a_few_products_you_buy_or_sell/add_a_few_products_you_buy_or_sell.json b/erpnext/stock/onboarding_slide/add_a_few_products_you_buy_or_sell/add_a_few_products_you_buy_or_sell.json
new file mode 100644
index 0000000..5ee3167
--- /dev/null
+++ b/erpnext/stock/onboarding_slide/add_a_few_products_you_buy_or_sell/add_a_few_products_you_buy_or_sell.json
@@ -0,0 +1,52 @@
+{
+ "add_more_button": 1,
+ "app": "ERPNext",
+ "creation": "2019-11-15 14:41:12.007359",
+ "docstatus": 0,
+ "doctype": "Onboarding Slide",
+ "domains": [],
+ "help_links": [],
+ "idx": 0,
+ "image_src": "",
+ "is_completed": 0,
+ "max_count": 3,
+ "modified": "2019-12-09 17:54:09.602885",
+ "modified_by": "Administrator",
+ "name": "Add A Few Products You Buy Or Sell",
+ "owner": "Administrator",
+ "ref_doctype": "Item",
+ "slide_desc": "",
+ "slide_fields": [
+ {
+ "align": "",
+ "fieldname": "item",
+ "fieldtype": "Data",
+ "label": "Item",
+ "placeholder": "Product Name",
+ "reqd": 1
+ },
+ {
+ "align": "",
+ "fieldname": "item_price",
+ "fieldtype": "Currency",
+ "label": "Item Price",
+ "reqd": 1
+ },
+ {
+ "align": "",
+ "fieldtype": "Column Break",
+ "reqd": 0
+ },
+ {
+ "align": "",
+ "fieldname": "uom",
+ "fieldtype": "Link",
+ "label": "UOM",
+ "options": "UOM",
+ "reqd": 1
+ }
+ ],
+ "slide_order": 30,
+ "slide_title": "Add A Few Products You Buy Or Sell",
+ "slide_type": "Create"
+}
\ No newline at end of file
diff --git a/erpnext/stock/report/batch_wise_balance_history/batch_wise_balance_history.js b/erpnext/stock/report/batch_wise_balance_history/batch_wise_balance_history.js
index b23c908..23700c9 100644
--- a/erpnext/stock/report/batch_wise_balance_history/batch_wise_balance_history.js
+++ b/erpnext/stock/report/batch_wise_balance_history/batch_wise_balance_history.js
@@ -16,6 +16,29 @@
"fieldtype": "Date",
"width": "80",
"default": frappe.datetime.get_today()
+ },
+ {
+ "fieldname": "item",
+ "label": __("Item"),
+ "fieldtype": "Link",
+ "options": "Item",
+ "width": "80"
}
- ]
+ ],
+ "formatter": function (value, row, column, data, default_formatter) {
+ if (column.fieldname == "Batch" && data && !!data["Batch"]) {
+ value = data["Batch"];
+ column.link_onclick = "frappe.query_reports['Batch-Wise Balance History'].set_batch_route_to_stock_ledger(" + JSON.stringify(data) + ")";
+ }
+
+ value = default_formatter(value, row, column, data);
+ return value;
+ },
+ "set_batch_route_to_stock_ledger": function (data) {
+ frappe.route_options = {
+ "batch_no": data["Batch"]
+ };
+
+ frappe.set_route("query-report", "Stock Ledger");
+ }
}
\ No newline at end of file
diff --git a/erpnext/stock/report/batch_wise_balance_history/batch_wise_balance_history.py b/erpnext/stock/report/batch_wise_balance_history/batch_wise_balance_history.py
index 7f7835f..2c95084 100644
--- a/erpnext/stock/report/batch_wise_balance_history/batch_wise_balance_history.py
+++ b/erpnext/stock/report/batch_wise_balance_history/batch_wise_balance_history.py
@@ -2,9 +2,11 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
from frappe import _
-from frappe.utils import flt, cint, getdate
+from frappe.utils import cint, flt, getdate
+
def execute(filters=None):
if not filters: filters = {}
@@ -17,29 +19,31 @@
data = []
for item in sorted(iwb_map):
- for wh in sorted(iwb_map[item]):
- for batch in sorted(iwb_map[item][wh]):
- qty_dict = iwb_map[item][wh][batch]
- if qty_dict.opening_qty or qty_dict.in_qty or qty_dict.out_qty or qty_dict.bal_qty:
- data.append([item, item_map[item]["item_name"], item_map[item]["description"], wh, batch,
- flt(qty_dict.opening_qty, float_precision), flt(qty_dict.in_qty, float_precision),
- flt(qty_dict.out_qty, float_precision), flt(qty_dict.bal_qty, float_precision),
- item_map[item]["stock_uom"]
- ])
+ if not filters.get("item") or filters.get("item") == item:
+ for wh in sorted(iwb_map[item]):
+ for batch in sorted(iwb_map[item][wh]):
+ qty_dict = iwb_map[item][wh][batch]
+ if qty_dict.opening_qty or qty_dict.in_qty or qty_dict.out_qty or qty_dict.bal_qty:
+ data.append([item, item_map[item]["item_name"], item_map[item]["description"], wh, batch,
+ flt(qty_dict.opening_qty, float_precision), flt(qty_dict.in_qty, float_precision),
+ flt(qty_dict.out_qty, float_precision), flt(qty_dict.bal_qty, float_precision),
+ item_map[item]["stock_uom"]
+ ])
return columns, data
+
def get_columns(filters):
"""return columns based on filters"""
columns = [_("Item") + ":Link/Item:100"] + [_("Item Name") + "::150"] + [_("Description") + "::150"] + \
- [_("Warehouse") + ":Link/Warehouse:100"] + [_("Batch") + ":Link/Batch:100"] + [_("Opening Qty") + ":Float:90"] + \
- [_("In Qty") + ":Float:80"] + [_("Out Qty") + ":Float:80"] + [_("Balance Qty") + ":Float:90"] + \
- [_("UOM") + "::90"]
-
+ [_("Warehouse") + ":Link/Warehouse:100"] + [_("Batch") + ":Link/Batch:100"] + [_("Opening Qty") + ":Float:90"] + \
+ [_("In Qty") + ":Float:80"] + [_("Out Qty") + ":Float:80"] + [_("Balance Qty") + ":Float:90"] + \
+ [_("UOM") + "::90"]
return columns
+
def get_conditions(filters):
conditions = ""
if not filters.get("from_date"):
@@ -52,7 +56,8 @@
return conditions
-#get all details
+
+# get all details
def get_stock_ledger_entries(filters):
conditions = get_conditions(filters)
return frappe.db.sql("""
@@ -63,6 +68,7 @@
order by item_code, warehouse""" %
conditions, as_dict=1)
+
def get_item_warehouse_batch_map(filters, float_precision):
sle = get_stock_ledger_entries(filters)
iwb_map = {}
@@ -90,6 +96,7 @@
return iwb_map
+
def get_item_details(filters):
item_map = {}
for d in frappe.db.sql("select name, item_name, description, stock_uom from tabItem", as_dict=1):
diff --git a/erpnext/stock/report/purchase_order_items_to_be_received_or_billed/purchase_order_items_to_be_received_or_billed.json b/erpnext/stock/report/purchase_order_items_to_be_received_or_billed/purchase_order_items_to_be_received_or_billed.json
index caf7eb8..48c0f42 100644
--- a/erpnext/stock/report/purchase_order_items_to_be_received_or_billed/purchase_order_items_to_be_received_or_billed.json
+++ b/erpnext/stock/report/purchase_order_items_to_be_received_or_billed/purchase_order_items_to_be_received_or_billed.json
@@ -15,7 +15,7 @@
"prepared_report": 0,
"query": "SELECT\n\t`poi_pri`.`purchase_order` as \"Purchase Order:Link/Purchase Order:120\",\n\t`poi_pri`.`status` as \"Status:Data:120\",\n\t`poi_pri`.`transaction_date` as \"Date:Date:100\",\n\t`poi_pri`.`schedule_date` as \"Reqd by Date:Date:110\",\n\t`poi_pri`.`supplier` as \"Supplier:Link/Supplier:120\",\n\t`poi_pri`.`supplier_name` as \"Supplier Name::150\",\n\t`poi_pri`.`item_code` as \"Item Code:Link/Item:120\",\n\t`poi_pri`.`qty` as \"Qty:Float:100\",\n\t`poi_pri`.`base_amount` as \"Base Amount:Currency:100\",\n\t`poi_pri`.`received_qty` as \"Received Qty:Float:100\",\n\t`poi_pri`.`received_amount` as \"Received Qty Amount:Currency:100\",\n\t`poi_pri`.`qty_to_receive` as \"Qty to Receive:Float:100\",\n\t`poi_pri`.`amount_to_be_received` as \"Amount to Receive:Currency:100\",\n\t`poi_pri`.`billed_amount` as \"Billed Amount:Currency:100\",\n\t`poi_pri`.`amount_to_be_billed` as \"Amount To Be Billed:Currency:100\",\n\tSUM(`pii`.`qty`) AS \"Billed Qty:Float:100\",\n\t`poi_pri`.qty - SUM(`pii`.`qty`) AS \"Qty To Be Billed:Float:100\",\n\t`poi_pri`.`warehouse` as \"Warehouse:Link/Warehouse:150\",\n\t`poi_pri`.`item_name` as \"Item Name::150\",\n\t`poi_pri`.`description` as \"Description::200\",\n\t`poi_pri`.`brand` as \"Brand::100\",\n\t`poi_pri`.`project` as \"Project\",\n\t`poi_pri`.`company` as \"Company:Link/Company:\"\nFROM\n\t(SELECT\n\t\t`po`.`name` AS 'purchase_order',\n\t\t`po`.`status`,\n\t\t`po`.`company`,\n\t\t`poi`.`warehouse`,\n\t\t`poi`.`brand`,\n\t\t`poi`.`description`,\n\t\t`po`.`transaction_date`,\n\t\t`poi`.`schedule_date`,\n\t\t`po`.`supplier`,\n\t\t`po`.`supplier_name`,\n\t\t`poi`.`project`,\n\t\t`poi`.`item_code`,\n\t\t`poi`.`item_name`,\n\t\t`poi`.`qty`,\n\t\t`poi`.`base_amount`,\n\t\t`poi`.`received_qty`,\n\t\t(`poi`.billed_amt * ifnull(`po`.conversion_rate, 1)) as billed_amount,\n\t\t(`poi`.base_amount - (`poi`.billed_amt * ifnull(`po`.conversion_rate, 1))) as amount_to_be_billed,\n\t\t`poi`.`qty` - IFNULL(`poi`.`received_qty`, 0) AS 'qty_to_receive',\n\t\t(`poi`.`qty` - IFNULL(`poi`.`received_qty`, 0)) * `poi`.`rate` AS 'amount_to_be_received',\n\t\tSUM(`pri`.`amount`) AS 'received_amount',\n\t\t`poi`.`name` AS 'poi_name',\n\t\t`pri`.`name` AS 'pri_name'\n\tFROM\n\t\t`tabPurchase Order` po\n\t\tLEFT JOIN `tabPurchase Order Item` poi\n\t\tON `poi`.`parent` = `po`.`name`\n\t\tLEFT JOIN `tabPurchase Receipt Item` pri\n\t\tON `pri`.`purchase_order_item` = `poi`.`name`\n\t\t\tAND `pri`.`docstatus`=1\n\tWHERE\n\t\t`po`.`status` not in ('Stopped', 'Closed')\n\t\tAND `po`.`docstatus` = 1\n\t\tAND IFNULL(`poi`.`received_qty`, 0) < IFNULL(`poi`.`qty`, 0)\n\tGROUP BY `poi`.`name`\n\tORDER BY `po`.`transaction_date` ASC\n\t) poi_pri\n\tLEFT JOIN `tabPurchase Invoice Item` pii\n\tON `pii`.`po_detail` = `poi_pri`.`poi_name`\n\t\tAND `pii`.`docstatus`=1\nGROUP BY `poi_pri`.`poi_name`",
"ref_doctype": "Purchase Order",
- "report_name": "Purchase Order Items To Be Received or Billed1",
+ "report_name": "Purchase Order Items To Be Received or Billed",
"report_type": "Query Report",
"roles": [
{
diff --git a/erpnext/stock/report/stock_balance/stock_balance.py b/erpnext/stock/report/stock_balance/stock_balance.py
index 68b8b50..ccba8b0 100644
--- a/erpnext/stock/report/stock_balance/stock_balance.py
+++ b/erpnext/stock/report/stock_balance/stock_balance.py
@@ -55,7 +55,7 @@
'item_code': item,
'warehouse': warehouse,
'company': company,
- 'reorder_level': item_reorder_qty,
+ 'reorder_level': item_reorder_level,
'reorder_qty': item_reorder_qty,
}
report_data.update(item_map[item])
@@ -292,7 +292,7 @@
if not (filters.get("item_code") or filters.get("warehouse")):
sle_count = flt(frappe.db.sql("""select count(name) from `tabStock Ledger Entry`""")[0][0])
if sle_count > 500000:
- frappe.throw(_("Please set filter based on Item or Warehouse"))
+ frappe.throw(_("Please set filter based on Item or Warehouse due to a large amount of entries."))
def get_variants_attributes():
'''Return all item variant attributes.'''
diff --git a/erpnext/stock/report/stock_ledger/stock_ledger.js b/erpnext/stock/report/stock_ledger/stock_ledger.js
index 3fab327..df3bba5 100644
--- a/erpnext/stock/report/stock_ledger/stock_ledger.js
+++ b/erpnext/stock/report/stock_ledger/stock_ledger.js
@@ -77,7 +77,15 @@
"fieldtype": "Link",
"options": "UOM"
}
- ]
+ ],
+ "formatter": function (value, row, column, data, default_formatter) {
+ value = default_formatter(value, row, column, data);
+ if (column.fieldname == "out_qty" && data.out_qty < 0) {
+ value = "<span style='color:red'>" + value + "</span>";
+ }
+
+ return value;
+ },
}
// $(function() {
diff --git a/erpnext/stock/report/stock_ledger/stock_ledger.py b/erpnext/stock/report/stock_ledger/stock_ledger.py
index 5bdbca2..fc49db5 100644
--- a/erpnext/stock/report/stock_ledger/stock_ledger.py
+++ b/erpnext/stock/report/stock_ledger/stock_ledger.py
@@ -2,9 +2,11 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
+
import frappe
-from frappe import _
from erpnext.stock.utils import update_included_uom_in_report
+from frappe import _
+
def execute(filters=None):
include_uom = filters.get("include_uom")
@@ -19,10 +21,41 @@
if opening_row:
data.append(opening_row)
+ actual_qty = stock_value = 0
+
for sle in sl_entries:
item_detail = item_details[sle.item_code]
sle.update(item_detail)
+
+ if filters.get("batch_no"):
+ actual_qty += sle.actual_qty
+ stock_value += sle.stock_value_difference
+
+ if sle.voucher_type == 'Stock Reconciliation':
+ actual_qty = sle.qty_after_transaction
+ stock_value = sle.stock_value
+
+ sle.update({
+ "qty_after_transaction": actual_qty,
+ "stock_value": stock_value,
+ "in_qty": max(sle.actual_qty, 0),
+ "out_qty": min(sle.actual_qty, 0)
+ })
+
+ # get the name of the item that was produced using this item
+ if sle.voucher_type == "Stock Entry":
+ purpose, work_order, fg_completed_qty = frappe.db.get_value(sle.voucher_type, sle.voucher_no, ["purpose", "work_order", "fg_completed_qty"])
+
+ if purpose == "Manufacture" and work_order:
+ finished_product = frappe.db.get_value("Work Order", work_order, "item_name")
+ finished_qty = fg_completed_qty
+
+ sle.update({
+ "finished_product": finished_product,
+ "finished_qty": finished_qty,
+ })
+
data.append(sle)
if include_uom:
@@ -31,53 +64,74 @@
update_included_uom_in_report(columns, data, include_uom, conversion_factors)
return columns, data
+
def get_columns():
columns = [
- {"label": _("Date"), "fieldname": "date", "fieldtype": "Datetime", "width": 95},
- {"label": _("Item"), "fieldname": "item_code", "fieldtype": "Link", "options": "Item", "width": 130},
+ {"label": _("Date"), "fieldname": "date", "fieldtype": "Datetime", "width": 150},
+ {"label": _("Item"), "fieldname": "item_code", "fieldtype": "Link", "options": "Item", "width": 100},
{"label": _("Item Name"), "fieldname": "item_name", "width": 100},
+ {"label": _("Stock UOM"), "fieldname": "stock_uom", "fieldtype": "Link", "options": "UOM", "width": 90},
+ {"label": _("In Qty"), "fieldname": "in_qty", "fieldtype": "Float", "width": 80, "convertible": "qty"},
+ {"label": _("Out Qty"), "fieldname": "out_qty", "fieldtype": "Float", "width": 80, "convertible": "qty"},
+ {"label": _("Balance Qty"), "fieldname": "qty_after_transaction", "fieldtype": "Float", "width": 100, "convertible": "qty"},
+ {"label": _("Finished Product"), "fieldname": "finished_product", "width": 100},
+ {"label": _("Finished Qty"), "fieldname": "finished_qty", "fieldtype": "Float", "width": 100, "convertible": "qty"},
+ {"label": _("Voucher #"), "fieldname": "voucher_no", "fieldtype": "Dynamic Link", "options": "voucher_type", "width": 150},
+ {"label": _("Warehouse"), "fieldname": "warehouse", "fieldtype": "Link", "options": "Warehouse", "width": 150},
{"label": _("Item Group"), "fieldname": "item_group", "fieldtype": "Link", "options": "Item Group", "width": 100},
{"label": _("Brand"), "fieldname": "brand", "fieldtype": "Link", "options": "Brand", "width": 100},
{"label": _("Description"), "fieldname": "description", "width": 200},
- {"label": _("Warehouse"), "fieldname": "warehouse", "fieldtype": "Link", "options": "Warehouse", "width": 100},
- {"label": _("Stock UOM"), "fieldname": "stock_uom", "fieldtype": "Link", "options": "UOM", "width": 100},
- {"label": _("Qty"), "fieldname": "actual_qty", "fieldtype": "Float", "width": 50, "convertible": "qty"},
- {"label": _("Balance Qty"), "fieldname": "qty_after_transaction", "fieldtype": "Float", "width": 100, "convertible": "qty"},
- {"label": _("Incoming Rate"), "fieldname": "incoming_rate", "fieldtype": "Currency", "width": 110,
- "options": "Company:company:default_currency", "convertible": "rate"},
- {"label": _("Valuation Rate"), "fieldname": "valuation_rate", "fieldtype": "Currency", "width": 110,
- "options": "Company:company:default_currency", "convertible": "rate"},
- {"label": _("Balance Value"), "fieldname": "stock_value", "fieldtype": "Currency", "width": 110,
- "options": "Company:company:default_currency"},
+ {"label": _("Incoming Rate"), "fieldname": "incoming_rate", "fieldtype": "Currency", "width": 110, "options": "Company:company:default_currency", "convertible": "rate"},
+ {"label": _("Valuation Rate"), "fieldname": "valuation_rate", "fieldtype": "Currency", "width": 110, "options": "Company:company:default_currency", "convertible": "rate"},
+ {"label": _("Balance Value"), "fieldname": "stock_value", "fieldtype": "Currency", "width": 110, "options": "Company:company:default_currency"},
{"label": _("Voucher Type"), "fieldname": "voucher_type", "width": 110},
{"label": _("Voucher #"), "fieldname": "voucher_no", "fieldtype": "Dynamic Link", "options": "voucher_type", "width": 100},
{"label": _("Batch"), "fieldname": "batch_no", "fieldtype": "Link", "options": "Batch", "width": 100},
- {"label": _("Serial #"), "fieldname": "serial_no", "width": 100},
+ {"label": _("Serial #"), "fieldname": "serial_no", "fieldtype": "Link", "options": "Serial No", "width": 100},
{"label": _("Project"), "fieldname": "project", "fieldtype": "Link", "options": "Project", "width": 100},
{"label": _("Company"), "fieldname": "company", "fieldtype": "Link", "options": "Company", "width": 110}
]
return columns
+
def get_stock_ledger_entries(filters, items):
item_conditions_sql = ''
if items:
item_conditions_sql = 'and sle.item_code in ({})'\
.format(', '.join([frappe.db.escape(i) for i in items]))
- return frappe.db.sql("""select concat_ws(" ", posting_date, posting_time) as date,
- item_code, warehouse, actual_qty, qty_after_transaction, incoming_rate, valuation_rate,
- stock_value, voucher_type, voucher_no, batch_no, serial_no, company, project
- from `tabStock Ledger Entry` sle
- where company = %(company)s and
- posting_date between %(from_date)s and %(to_date)s
- {sle_conditions}
- {item_conditions_sql}
- order by posting_date asc, posting_time asc, creation asc"""\
- .format(
- sle_conditions=get_sle_conditions(filters),
- item_conditions_sql = item_conditions_sql
- ), filters, as_dict=1)
+ sl_entries = frappe.db.sql("""
+ SELECT
+ concat_ws(" ", posting_date, posting_time) AS date,
+ item_code,
+ warehouse,
+ actual_qty,
+ qty_after_transaction,
+ incoming_rate,
+ valuation_rate,
+ stock_value,
+ voucher_type,
+ voucher_no,
+ batch_no,
+ serial_no,
+ company,
+ project,
+ stock_value_difference
+ FROM
+ `tabStock Ledger Entry` sle
+ WHERE
+ company = %(company)s
+ AND posting_date BETWEEN %(from_date)s AND %(to_date)s
+ {sle_conditions}
+ {item_conditions_sql}
+ ORDER BY
+ posting_date asc, posting_time asc, creation asc
+ """.format(sle_conditions=get_sle_conditions(filters), item_conditions_sql=item_conditions_sql),
+ filters, as_dict=1)
+
+ return sl_entries
+
def get_items(filters):
conditions = []
@@ -95,6 +149,7 @@
.format(" and ".join(conditions)), filters)
return items
+
def get_item_details(items, sl_entries, include_uom):
item_details = {}
if not items:
@@ -106,8 +161,8 @@
cf_field = cf_join = ""
if include_uom:
cf_field = ", ucd.conversion_factor"
- cf_join = "left join `tabUOM Conversion Detail` ucd on ucd.parent=item.name and ucd.uom='%s'" \
- % (include_uom)
+ cf_join = "left join `tabUOM Conversion Detail` ucd on ucd.parent=item.name and ucd.uom=%s" \
+ % frappe.db.escape(include_uom)
res = frappe.db.sql("""
select
@@ -124,6 +179,7 @@
return item_details
+
def get_sle_conditions(filters):
conditions = []
if filters.get("warehouse"):
@@ -139,6 +195,7 @@
return "and {}".format(" and ".join(conditions)) if conditions else ""
+
def get_opening_balance(filters, columns):
if not (filters.item_code and filters.warehouse and filters.from_date):
return
@@ -150,13 +207,17 @@
"posting_date": filters.from_date,
"posting_time": "00:00:00"
})
- row = {}
- row["item_code"] = _("'Opening'")
- for dummy, v in ((9, 'qty_after_transaction'), (11, 'valuation_rate'), (12, 'stock_value')):
- row[v] = last_entry.get(v, 0)
+
+ row = {
+ "item_code": _("'Opening'"),
+ "qty_after_transaction": last_entry.get("qty_after_transaction", 0),
+ "valuation_rate": last_entry.get("valuation_rate", 0),
+ "stock_value": last_entry.get("stock_value", 0)
+ }
return row
+
def get_warehouse_condition(warehouse):
warehouse_details = frappe.db.get_value("Warehouse", warehouse, ["lft", "rgt"], as_dict=1)
if warehouse_details:
@@ -166,6 +227,7 @@
return ''
+
def get_item_group_condition(item_group):
item_group_details = frappe.db.get_value("Item Group", item_group, ["lft", "rgt"], as_dict=1)
if item_group_details:
diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py
index 69a4b94..b100f45 100644
--- a/erpnext/stock/stock_ledger.py
+++ b/erpnext/stock/stock_ledger.py
@@ -212,7 +212,7 @@
def get_serialized_values(self, sle):
incoming_rate = flt(sle.incoming_rate)
actual_qty = flt(sle.actual_qty)
- serial_no = cstr(sle.serial_no).split("\n")
+ serial_nos = cstr(sle.serial_no).split("\n")
if incoming_rate < 0:
# wrong incoming rate
@@ -224,9 +224,8 @@
elif actual_qty < 0:
# In case of delivery/stock issue, get average purchase rate
# of serial nos of current entry
- stock_value_change = -1 * flt(frappe.get_all("Serial No",
- fields=["sum(purchase_rate)"],
- filters = {'name': ('in', serial_no)}, as_list=1)[0][0])
+ outgoing_value = self.get_incoming_value_for_serial_nos(sle, serial_nos)
+ stock_value_change = -1 * outgoing_value
new_stock_qty = self.qty_after_transaction + actual_qty
@@ -244,6 +243,36 @@
sle.voucher_type, sle.voucher_no, self.allow_zero_rate,
currency=erpnext.get_company_currency(sle.company))
+ def get_incoming_value_for_serial_nos(self, sle, serial_nos):
+ # get rate from serial nos within same company
+ all_serial_nos = frappe.get_all("Serial No",
+ fields=["purchase_rate", "name", "company"],
+ filters = {'name': ('in', serial_nos)})
+
+ incoming_values = sum([flt(d.purchase_rate) for d in all_serial_nos if d.company==sle.company])
+
+ # Get rate for serial nos which has been transferred to other company
+ invalid_serial_nos = [d.name for d in all_serial_nos if d.company!=sle.company]
+ for serial_no in invalid_serial_nos:
+ incoming_rate = frappe.db.sql("""
+ select incoming_rate
+ from `tabStock Ledger Entry`
+ where
+ company = %s
+ and actual_qty > 0
+ and (serial_no = %s
+ or serial_no like %s
+ or serial_no like %s
+ or serial_no like %s
+ )
+ order by posting_date desc
+ limit 1
+ """, (sle.company, serial_no, serial_no+'\n%', '%\n'+serial_no, '%\n'+serial_no+'\n%'))
+
+ incoming_values += flt(incoming_rate[0][0]) if incoming_rate else 0
+
+ return incoming_values
+
def get_moving_average_values(self, sle):
actual_qty = flt(sle.actual_qty)
new_stock_qty = flt(self.qty_after_transaction) + actual_qty
diff --git a/erpnext/stock/utils.py b/erpnext/stock/utils.py
index 2ac0bae..2c6c953 100644
--- a/erpnext/stock/utils.py
+++ b/erpnext/stock/utils.py
@@ -271,6 +271,7 @@
'fieldtype': 'Currency' if d.get("convertible") == 'rate' else 'Float'
})
+ update_dict_values = []
for row_idx, row in enumerate(result):
data = row.items() if is_dict_obj else enumerate(row)
for key, value in data:
@@ -286,11 +287,17 @@
row.insert(key+1, new_value)
else:
new_key = "{0}_{1}".format(key, frappe.scrub(include_uom))
- row[new_key] = new_value
+ update_dict_values.append([row, new_key, new_value])
-def get_available_serial_nos(item_code, warehouse):
- return frappe.get_all("Serial No", filters = {'item_code': item_code,
- 'warehouse': warehouse, 'delivery_document_no': ''}) or []
+ for data in update_dict_values:
+ row, key, value = data
+ row[key] = value
+
+def get_available_serial_nos(args):
+ return frappe.db.sql(""" SELECT name from `tabSerial No`
+ WHERE item_code = %(item_code)s and warehouse = %(warehouse)s
+ and timestamp(purchase_date, purchase_time) <= timestamp(%(posting_date)s, %(posting_time)s)
+ """, args, as_dict=1)
def add_additional_uom_columns(columns, result, include_uom, conversion_factors):
if not include_uom or not conversion_factors:
diff --git a/erpnext/support/doctype/issue_priority/issue_priority.py b/erpnext/support/doctype/issue_priority/issue_priority.py
index cecaaaa..7c8925e 100644
--- a/erpnext/support/doctype/issue_priority/issue_priority.py
+++ b/erpnext/support/doctype/issue_priority/issue_priority.py
@@ -8,7 +8,4 @@
from frappe.model.document import Document
class IssuePriority(Document):
-
- def validate(self):
- if frappe.db.exists("Issue Priority", {"name": self.name}):
- frappe.throw(_("Issue Priority Already Exists"))
+ pass
\ No newline at end of file
diff --git a/erpnext/support/web_form/issues/issues.json b/erpnext/support/web_form/issues/issues.json
index 652114f..9b904ad 100644
--- a/erpnext/support/web_form/issues/issues.json
+++ b/erpnext/support/web_form/issues/issues.json
@@ -18,7 +18,7 @@
"is_standard": 1,
"login_required": 1,
"max_attachment_size": 0,
- "modified": "2019-06-27 22:58:49.609672",
+ "modified": "2019-12-10 13:48:19.894186",
"modified_by": "Administrator",
"module": "Support",
"name": "issues",
diff --git a/erpnext/templates/emails/confirm_appointment.html b/erpnext/templates/emails/confirm_appointment.html
new file mode 100644
index 0000000..6c9b28b
--- /dev/null
+++ b/erpnext/templates/emails/confirm_appointment.html
@@ -0,0 +1,10 @@
+<p>{{_("Dear")}} {{ full_name }}{% if last_name %} {{ last_name}}{% endif %},</p>
+<p>{{_("A new appointment has been created for you with {0}").format(site_url)}}.</p>
+<p>{{_("Click on the link below to verify your email and confirm the appointment")}}.</p>
+
+<p style="margin: 30px 0px;">
+ <a href="{{ link }}" rel="nofollow" style="padding: 8px 20px; background-color: #7575ff; color: #fff; border-radius: 4px; text-decoration: none; line-height: 1; border-bottom: 3px solid rgba(0, 0, 0, 0.2); font-size: 14px; font-weight: 200;">{{ _("Verify Email") }}</a>
+</p>
+
+<br>
+<p style="font-size: 85%;">{{_("You can also copy-paste this link in your browser")}} <a href="{{ link }}">{{ link }}</a></p>
diff --git a/erpnext/templates/includes/cart/cart_address.html b/erpnext/templates/includes/cart/cart_address.html
index fe53f34..f7f3548 100644
--- a/erpnext/templates/includes/cart/cart_address.html
+++ b/erpnext/templates/includes/cart/cart_address.html
@@ -65,16 +65,6 @@
reqd: 1
},
{
- label: __('Address Type'),
- fieldname: 'address_type',
- fieldtype: 'Select',
- options: [
- 'Billing',
- 'Shipping'
- ],
- reqd: 1
- },
- {
label: __('Address Line 1'),
fieldname: 'address_line1',
fieldtype: 'Data',
@@ -97,15 +87,36 @@
fieldtype: 'Data'
},
{
+ label: __('Country'),
+ fieldname: 'country',
+ fieldtype: 'Link',
+ options: 'Country',
+ reqd: 1
+ },
+ {
+ fieldname: "column_break0",
+ fieldtype: "Column Break",
+ width: "50%"
+ },
+ {
+ label: __('Address Type'),
+ fieldname: 'address_type',
+ fieldtype: 'Select',
+ options: [
+ 'Billing',
+ 'Shipping'
+ ],
+ reqd: 1
+ },
+ {
label: __('Pin Code'),
fieldname: 'pincode',
fieldtype: 'Data'
},
{
- label: __('Country'),
- fieldname: 'country',
- fieldtype: 'Link',
- reqd: 1
+ fieldname: "phone",
+ fieldtype: "Data",
+ label: "Phone"
},
],
primary_action_label: __('Save'),
diff --git a/erpnext/templates/includes/timesheet/timesheet_row.html b/erpnext/templates/includes/timesheet/timesheet_row.html
index e9cfcda..4852f59 100644
--- a/erpnext/templates/includes/timesheet/timesheet_row.html
+++ b/erpnext/templates/includes/timesheet/timesheet_row.html
@@ -1,13 +1,14 @@
-<div class="web-list-item">
- <a href="/timesheets?name={{ doc.name | urlencode }}" class="no-decoration">
- <div class="row">
- <div class="col-xs-3">
- <span class="indicator {{ "red" if doc.status=="Cancelled" else "green" if doc.status=="Billed" else "blue" if doc.status=="Submitted" else "darkgrey" }}">{{ doc.name }}</span>
- </div>
- <div class="col-xs-3"> Billable Hours: {{ doc.total_billable_hours}} </div>
- <div class="col-xs-2"> {{ _(doc.sales_invoice) }} </div>
- <div class="col-xs-2"> {{ _(doc.project) }} </div>
- <div class="col-xs-2"> {{ _(doc.activity_type) }} </div>
+<div class="web-list-item transaction-list-item">
+ <div class="row">
+ <div class="col-xs-3">
+ <span class='indicator {{ "red" if doc.status=="Cancelled" else "green" if doc.status=="Billed" else "blue" if doc.status=="Submitted" else "darkgrey" }} small'>
+ {{ doc.name }}
+ </span>
</div>
- </a>
+ <div class="col-xs-2 small"> {{ doc.total_billable_hours }} </div>
+ <div class="col-xs-2 small"> {{ doc.project or '' }} </div>
+ <div class="col-xs-2 small"> {{ doc.sales_invoice or '' }} </div>
+ <div class="col-xs-2 small"> {{ _(doc.activity_type) }} </div>
+ </div>
+ <!-- <a href="/timesheets?name={{ doc.name | urlencode }}" class="transaction-item-link">Link</a> -->
</div>
diff --git a/erpnext/templates/pages/cart.html b/erpnext/templates/pages/cart.html
index b301fc0..912702e 100644
--- a/erpnext/templates/pages/cart.html
+++ b/erpnext/templates/pages/cart.html
@@ -83,12 +83,10 @@
</div>
{% endif %}
- {% if cart_settings.enable_checkout %}
<div class="cart-addresses mt-5">
{% include "templates/includes/cart/cart_address.html" %}
</div>
{% endif %}
- {% endif %}
</div>
<div class="row mt-5">
diff --git a/erpnext/tests/test_woocommerce.py b/erpnext/tests/test_woocommerce.py
index fc850d5..ce0f47d 100644
--- a/erpnext/tests/test_woocommerce.py
+++ b/erpnext/tests/test_woocommerce.py
@@ -18,6 +18,7 @@
woo_settings.api_consumer_key = "ck_fd43ff5756a6abafd95fadb6677100ce95a758a1"
woo_settings.api_consumer_secret = "cs_94360a1ad7bef7fa420a40cf284f7b3e0788454e"
woo_settings.enable_sync = 1
+ woo_settings.company = "Woocommerce"
woo_settings.tax_account = "Sales Expenses - W"
woo_settings.f_n_f_account = "Expenses - W"
woo_settings.creation_user = "Administrator"
diff --git a/erpnext/translations/de.csv b/erpnext/translations/de.csv
index 2e25a12..954f6db 100644
--- a/erpnext/translations/de.csv
+++ b/erpnext/translations/de.csv
@@ -304,7 +304,7 @@
DocType: BOM,Total Cost,Gesamtkosten
apps/erpnext/erpnext/hr/doctype/leave_allocation/leave_allocation.js,Allocation Expired!,Zuteilung abgelaufen!
DocType: Soil Analysis,Ca/K,Ca / K
-DocType: Leave Type,Maximum Carry Forwarded Leaves,Maximale Anzahl weitergeleiteter Blätter
+DocType: Leave Type,Maximum Carry Forwarded Leaves,Obergrenze für übertragbaren Urlaub erreicht
DocType: Salary Slip,Employee Loan,MItarbeiterdarlehen
DocType: Additional Salary,HR-ADS-.YY.-.MM.-,HR-ADS-.YY .-. MM.-
DocType: Fee Schedule,Send Payment Request Email,Zahlungaufforderung per E-Mail versenden
@@ -893,7 +893,7 @@
DocType: Vital Signs,Blood Pressure (systolic),Blutdruck (systolisch)
apps/erpnext/erpnext/controllers/buying_controller.py,{0} {1} is {2},{0} {1} ist {2}
DocType: Item Price,Valid Upto,Gültig bis
-DocType: Leave Type,Expire Carry Forwarded Leaves (Days),Verfallsdatum für weitergeleitete Blätter (Tage)
+DocType: Leave Type,Expire Carry Forwarded Leaves (Days),Verfallsdatum für übertragenen Urlaub (Tage)
DocType: Training Event,Workshop,Werkstatt
DocType: Supplier Scorecard Scoring Standing,Warn Purchase Orders,Warnung Bestellungen
apps/erpnext/erpnext/utilities/user_progress.py,List a few of your customers. They could be organizations or individuals.,Bitte ein paar Kunden angeben. Dies können Firmen oder Einzelpersonen sein.
@@ -1103,7 +1103,7 @@
DocType: Payroll Entry,Select Payment Account to make Bank Entry,Wählen Sie ein Zahlungskonto für die Buchung
apps/erpnext/erpnext/config/accounting.py,Opening and Closing,Öffnen und Schließen
DocType: Hotel Settings,Default Invoice Naming Series,Standard-Rechnungsnummernkreis
-apps/erpnext/erpnext/utilities/activation.py,"Create Employee records to manage leaves, expense claims and payroll","Erstellen Sie Mitarbeiterdaten Blätter, Spesenabrechnung und Gehaltsabrechnung zu verwalten"
+apps/erpnext/erpnext/utilities/activation.py,"Create Employee records to manage leaves, expense claims and payroll","Erstellen Sie Mitarbeiterdaten für Urlaubs, Spesenabrechnung und Gehaltsabrechnung zu verwalten"
apps/erpnext/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js,An error occurred during the update process,Während des Aktualisierungsprozesses ist ein Fehler aufgetreten
DocType: Restaurant Reservation,Restaurant Reservation,Restaurant Reservierung
apps/erpnext/erpnext/public/js/hub/Sidebar.vue,Your Items,Ihre Artikel
@@ -1329,7 +1329,7 @@
apps/erpnext/erpnext/utilities/transaction_base.py,Invalid Posting Time,Ungültige Buchungszeit
DocType: Salary Component,Condition and Formula,Zustand und Formel
DocType: Lead,Campaign Name,Kampagnenname
-apps/erpnext/erpnext/setup/default_energy_point_rules.py,On Task Completion,Bei Abschluss der Aufgabe
+apps/erpnext/erpnext/setup/default_energy_point_rules.py,On Task Completion,Bei Abschluss des Vorgangs
apps/erpnext/erpnext/hr/doctype/compensatory_leave_request/compensatory_leave_request.py,There is no leave period in between {0} and {1},Es gibt keinen Urlaub zwischen {0} und {1}
DocType: Fee Validity,Healthcare Practitioner,praktischer Arzt
DocType: Hotel Room,Capacity,Kapazität
@@ -1353,7 +1353,7 @@
apps/erpnext/erpnext/erpnext_integrations/doctype/gocardless_settings/gocardless_settings.py,Payment Cancelled. Please check your GoCardless Account for more details,Zahlung abgebrochen. Bitte überprüfen Sie Ihr GoCardless Konto für weitere Details
DocType: Work Order,Skip Material Transfer to WIP Warehouse,Überspringen Sie die Materialübertragung in das WIP-Lager
DocType: Contract,N/A,nicht verfügbar
-DocType: Task Type,Task Type,Aufgabentyp
+DocType: Task Type,Task Type,Vorgangstyp
DocType: Topic,Topic Content,Themeninhalt
DocType: Delivery Settings,Send with Attachment,Senden mit Anhang
DocType: Service Level,Priorities,Prioritäten
@@ -1548,7 +1548,7 @@
apps/erpnext/erpnext/accounts/doctype/journal_entry/journal_entry.py,{0} against Bill {1} dated {2},{0} zu Rechnung {1} vom {2}
apps/erpnext/erpnext/regional/report/eway_bill/eway_bill.py,From State,Aus dem Staat
apps/erpnext/erpnext/utilities/user_progress.py,Setup Institution,Einrichtung Einrichtung
-apps/erpnext/erpnext/hr/doctype/leave_period/leave_period.py,Allocating leaves...,Blätter zuordnen...
+apps/erpnext/erpnext/hr/doctype/leave_period/leave_period.py,Allocating leaves...,Urlaub zuordnen...
DocType: Program Enrollment,Vehicle/Bus Number,Fahrzeug / Bus Nummer
apps/erpnext/erpnext/public/js/call_popup/call_popup.js,Create New Contact,Neuen Kontakt erstellen
apps/erpnext/erpnext/education/doctype/course/course.js,Course Schedule,Kurstermine
@@ -1806,7 +1806,7 @@
DocType: Salary Component Account,Default Bank / Cash account will be automatically updated in Salary Journal Entry when this mode is selected.,"Standard Bank / Geldkonto wird automatisch in Gehalts Journal Entry aktualisiert werden, wenn dieser Modus ausgewählt ist."
DocType: Quiz,Latest Attempt,Letzter Versuch
DocType: Quiz Result,Quiz Result,Quiz-Ergebnis
-apps/erpnext/erpnext/hr/doctype/leave_allocation/leave_allocation.py,Total leaves allocated is mandatory for Leave Type {0},Die Gesamtzahl der zugewiesenen Blätter ist für Abwesenheitsart {0} erforderlich.
+apps/erpnext/erpnext/hr/doctype/leave_allocation/leave_allocation.py,Total leaves allocated is mandatory for Leave Type {0},Die Gesamtzahl der zugewiesenen Urlaube ist für Abwesenheitsart {0} erforderlich.
apps/erpnext/erpnext/controllers/sales_and_purchase_return.py,Row # {0}: Rate cannot be greater than the rate used in {1} {2},"Row # {0}: Die Rate kann nicht größer sein als die Rate, die in {1} {2}"
apps/erpnext/erpnext/utilities/user_progress.py,Meter,Meter
DocType: Workstation,Electricity Cost,Stromkosten
@@ -1916,7 +1916,7 @@
apps/erpnext/erpnext/templates/pages/order.js,Pay Remaining,Verbleibende Bezahlung
DocType: Purchase Invoice Item,Manufacturer,Hersteller
DocType: Landed Cost Item,Purchase Receipt Item,Kaufbeleg-Artikel
-DocType: Leave Allocation,Total Leaves Encashed,Insgesamt Blätter umkränzt
+DocType: Leave Allocation,Total Leaves Encashed,Summe ausbezahlter Urlaubstage
DocType: POS Profile,Sales Invoice Payment,Ausgangsrechnung-Zahlungen
DocType: Quality Inspection Template,Quality Inspection Template Name,Name der Qualitätsinspektionsvorlage
DocType: Project,First Email,Erste E-Mail
@@ -2449,7 +2449,7 @@
DocType: Asset,Depreciation Schedules,Abschreibungen Termine
apps/erpnext/erpnext/projects/doctype/timesheet/timesheet.js,Create Sales Invoice,Verkaufsrechnung erstellen
apps/erpnext/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.html,Ineligible ITC,Nicht förderfähiges ITC
-DocType: Task,Dependent Tasks,Abhängige Aufgaben
+DocType: Task,Dependent Tasks,Abhängige Vorgänge
apps/erpnext/erpnext/regional/report/gstr_1/gstr_1.py,Following accounts might be selected in GST Settings:,In den GST-Einstellungen können folgende Konten ausgewählt werden:
apps/erpnext/erpnext/manufacturing/report/bom_stock_report/bom_stock_report.js,Quantity to Produce,Menge zu produzieren
apps/erpnext/erpnext/hr/doctype/leave_application/leave_application.py,Application period cannot be outside leave allocation period,Beantragter Zeitraum kann nicht außerhalb der beantragten Urlaubszeit liegen
@@ -2540,7 +2540,7 @@
apps/erpnext/erpnext/hr/doctype/employee/employee.py,Employee cannot report to himself.,Mitarbeiter können nicht an sich selbst Bericht erstatten
apps/erpnext/erpnext/templates/pages/order.html,Rate:,Bewertung:
DocType: Bank Account,Change this date manually to setup the next synchronization start date,"Ändern Sie dieses Datum manuell, um das nächste Startdatum für die Synchronisierung festzulegen"
-DocType: Leave Type,Max Leaves Allowed,Max Blätter erlaubt
+DocType: Leave Type,Max Leaves Allowed,Höchstzahl erlaubter Urlaubstage
DocType: Account,"If the account is frozen, entries are allowed to restricted users.","Wenn das Konto gesperrt ist, sind einem eingeschränkten Benutzerkreis Buchungen erlaubt."
DocType: Email Digest,Bank Balance,Kontostand
apps/erpnext/erpnext/controllers/accounts_controller.py,Accounting Entry for {0}: {1} can only be made in currency: {2},Eine Buchung für {0}: {1} kann nur in der Währung: {2} vorgenommen werden
@@ -2846,7 +2846,7 @@
DocType: Purchase Invoice,03-Deficiency in services,03-Mangel an Dienstleistungen
DocType: Healthcare Settings,Default Medical Code Standard,Default Medical Code Standard
DocType: Purchase Invoice Item,HSN/SAC,HSN / SAC
-DocType: Project Template Task,Project Template Task,Projektvorlagenaufgabe
+DocType: Project Template Task,Project Template Task,Projektvorgangsvorlage
DocType: Accounts Settings,Over Billing Allowance (%),Mehr als Abrechnungsbetrag (%)
apps/erpnext/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py,Purchase Receipt {0} is not submitted,Kaufbeleg {0} wurde nicht übertragen
DocType: Company,Default Payable Account,Standard-Verbindlichkeitenkonto
@@ -2990,7 +2990,7 @@
apps/erpnext/erpnext/config/support.py,Single unit of an Item.,Einzelnes Element eines Artikels
DocType: Fee Category,Fee Category,Gebührenkategorie
DocType: Agriculture Task,Next Business Day,Nächster Arbeitstag
-apps/erpnext/erpnext/hr/doctype/leave_application/leave_application_dashboard.html,Allocated Leaves,Zugewiesene Blätter
+apps/erpnext/erpnext/hr/doctype/leave_application/leave_application_dashboard.html,Allocated Leaves,Genehmigter Urlaub
DocType: Drug Prescription,Dosage by time interval,Dosierung nach Zeitintervall
apps/erpnext/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.html,Total Taxable Value,Steuerpflichtiger Gesamtwert
DocType: Cash Flow Mapper,Section Header,Abschnitt Kopfzeile
@@ -3323,7 +3323,7 @@
,Qty to Order,Zu bestellende Menge
DocType: Period Closing Voucher,"The account head under Liability or Equity, in which Profit/Loss will be booked","Der Kontenkopf unter Eigen- oder Fremdkapital, in dem Gewinn / Verlust verbucht wird"
apps/erpnext/erpnext/accounts/doctype/budget/budget.py,Another Budget record '{0}' already exists against {1} '{2}' and account '{3}' for fiscal year {4},Ein weiterer Budgeteintrag '{0}' existiert bereits für {1} '{2}' und für '{3}' für das Geschäftsjahr {4}
-apps/erpnext/erpnext/config/projects.py,Gantt chart of all tasks.,Gantt-Diagramm aller Aufgaben
+apps/erpnext/erpnext/config/projects.py,Gantt chart of all tasks.,Gantt-Diagramm aller Vorgänge
DocType: Opportunity,Mins to First Response,Minuten zum First Response
DocType: Pricing Rule,Margin Type,Margenart
apps/erpnext/erpnext/projects/doctype/project/project_dashboard.html,{0} hours,{0} Stunden
@@ -3774,10 +3774,10 @@
DocType: Quality Inspection,Sample Size,Stichprobenumfang
apps/erpnext/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py,Please enter Receipt Document,Bitte geben Sie Eingangsbeleg
apps/erpnext/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py,All items have already been invoiced,Alle Artikel sind bereits abgerechnet
-apps/erpnext/erpnext/hr/report/employee_leave_balance_summary/employee_leave_balance_summary.py,Leaves Taken,Blätter genommen
+apps/erpnext/erpnext/hr/report/employee_leave_balance_summary/employee_leave_balance_summary.py,Leaves Taken,Urlaubstage genommen
apps/erpnext/erpnext/stock/doctype/packing_slip/packing_slip.py,Please specify a valid 'From Case No.',"Bitte eine eine gültige ""Von Fall Nr."" angeben"
apps/erpnext/erpnext/accounts/doctype/cost_center/cost_center_tree.js,Further cost centers can be made under Groups but entries can be made against non-Groups,"Weitere Kostenstellen können unter Gruppen angelegt werden, aber Buchungen können zu nicht-Gruppen erstellt werden"
-apps/erpnext/erpnext/hr/doctype/leave_allocation/leave_allocation.py,Total allocated leaves are more days than maximum allocation of {0} leave type for employee {1} in the period,Die insgesamt zugewiesenen Blätter sind mehr Tage als die maximale Zuweisung von {0} Abwesenheitsart für den Mitarbeiter {1} in der Periode
+apps/erpnext/erpnext/hr/doctype/leave_allocation/leave_allocation.py,Total allocated leaves are more days than maximum allocation of {0} leave type for employee {1} in the period,Die insgesamt zugewiesenen Urlaubstage sind mehr Tage als die maximale Zuweisung von {0} Abwesenheitsart für den Mitarbeiter {1} in der Periode
DocType: Branch,Branch,Betrieb
apps/erpnext/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.html,"Other outward supplies(Nil rated,Exempted)","Sonstige Auslandslieferungen (ohne Rating, ausgenommen)"
DocType: Soil Analysis,Ca/(K+Ca+Mg),Ca / (K + Ca + Mg)
@@ -3961,7 +3961,7 @@
apps/erpnext/erpnext/education/doctype/student/student_dashboard.py,Student LMS Activity,Student LMS Aktivität
DocType: POS Profile,Applicable for Users,Anwendbar für Benutzer
DocType: Supplier Quotation,PUR-SQTN-.YYYY.-,PUR-SQTN-.JJJJ.-
-apps/erpnext/erpnext/projects/doctype/project/project.js,Set Project and all Tasks to status {0}?,Projekt und alle Aufgaben auf Status {0} setzen?
+apps/erpnext/erpnext/projects/doctype/project/project.js,Set Project and all Tasks to status {0}?,Projekt und alle Vorgänge auf Status {0} setzen?
DocType: Purchase Invoice,Set Advances and Allocate (FIFO),Vorschüsse setzen und zuordnen (FIFO)
apps/erpnext/erpnext/manufacturing/doctype/production_plan/production_plan.py,No Work Orders created,Keine Arbeitsaufträge erstellt
apps/erpnext/erpnext/hr/doctype/salary_slip/salary_slip.py,Salary Slip of employee {0} already created for this period,Gehaltsabrechnung der Mitarbeiter {0} für diesen Zeitraum bereits erstellt
@@ -4097,7 +4097,7 @@
DocType: Cash Flow Mapping,Is Finance Cost Adjustment,Ist Finanzkostenanpassung
DocType: BOM,Operating Cost (Company Currency),Betriebskosten (Gesellschaft Währung)
DocType: Authorization Rule,Applicable To (Role),Anwenden auf (Rolle)
-apps/erpnext/erpnext/hr/doctype/leave_application/leave_application_dashboard.html,Pending Leaves,Ausstehende Blätter
+apps/erpnext/erpnext/hr/doctype/leave_application/leave_application_dashboard.html,Pending Leaves,Schwebende Urlaubstage
DocType: BOM Update Tool,Replace BOM,Erstelle Stückliste
apps/erpnext/erpnext/healthcare/doctype/lab_test_template/lab_test_template.py,Code {0} already exist,Code {0} existiert bereits
DocType: Patient Encounter,Procedures,Verfahren
@@ -4342,7 +4342,7 @@
DocType: Sales Invoice,Is Return (Credit Note),ist Rücklieferung (Gutschrift)
apps/erpnext/erpnext/manufacturing/doctype/job_card/job_card.js,Start Job,Job starten
apps/erpnext/erpnext/assets/doctype/asset_movement/asset_movement.py,Serial no is required for the asset {0},Für Vermögenswert {0} ist eine Seriennr. Erforderlich.
-DocType: Leave Control Panel,Allocate Leaves,Blätter zuweisen
+DocType: Leave Control Panel,Allocate Leaves,Urlaubstage zuweisen
apps/erpnext/erpnext/accounts/doctype/sales_taxes_and_charges_template/sales_taxes_and_charges_template.py,Disabled template must not be default template,Deaktivierte Vorlage darf nicht Standardvorlage sein
DocType: Pricing Rule,Price or Product Discount,Preis- oder Produktrabatt
apps/erpnext/erpnext/manufacturing/doctype/production_plan/production_plan.py,For row {0}: Enter planned qty,Für Zeile {0}: Geben Sie die geplante Menge ein
@@ -4418,7 +4418,7 @@
DocType: Hotel Room,Hotels,Hotels
apps/erpnext/erpnext/accounts/doctype/cost_center/cost_center_tree.js,New Cost Center Name,Neuer Kostenstellenname
DocType: Leave Control Panel,Leave Control Panel,Urlaubsverwaltung
-DocType: Project,Task Completion,Aufgabenerledigung
+DocType: Project,Task Completion,Vorgangserfüllung
apps/erpnext/erpnext/templates/generators/item/item_add_to_cart.html,Not in Stock,Nicht lagernd
DocType: Volunteer,Volunteer Skills,Freiwillige Fähigkeiten
DocType: Additional Salary,HR User,Nutzer Personalabteilung
@@ -4440,7 +4440,7 @@
DocType: Crop,Scientific Name,Wissenschaftlicher Name
DocType: Healthcare Service Unit,Service Unit Type,Serviceeinheitstyp
DocType: Bank Account,Branch Code,Bankleitzahl / BIC
-apps/erpnext/erpnext/hr/report/monthly_attendance_sheet/monthly_attendance_sheet.py,Total Leaves,insgesamt Blätter
+apps/erpnext/erpnext/hr/report/monthly_attendance_sheet/monthly_attendance_sheet.py,Total Leaves,summe der Urlaubstage
DocType: Customer,"Reselect, if the chosen contact is edited after save","Wählen Sie erneut, wenn der ausgewählte Kontakt nach dem Speichern bearbeitet wird"
DocType: Quality Procedure,Parent Procedure,Übergeordnetes Verfahren
DocType: Patient Encounter,In print,in Druckbuchstaben
@@ -5197,7 +5197,7 @@
apps/erpnext/erpnext/accounts/report/general_ledger/general_ledger.py,Account {0} does not exists,Konto {0} existiert nicht
apps/erpnext/erpnext/accounts/doctype/sales_invoice/sales_invoice.js,Select Loyalty Program,Wählen Sie Treueprogramm
DocType: Project,Project Type,Projekttyp
-apps/erpnext/erpnext/projects/doctype/task/task.py,Child Task exists for this Task. You can not delete this Task.,Für diese Aufgabe existiert eine untergeordnete Aufgabe. Sie können diese Aufgabe daher nicht löschen.
+apps/erpnext/erpnext/projects/doctype/task/task.py,Child Task exists for this Task. You can not delete this Task.,Für diesen Vorgang existiert ein untergeordneter Vorgang. Sie können diese Aufgabe daher nicht löschen.
apps/erpnext/erpnext/setup/doctype/sales_person/sales_person.py,Either target qty or target amount is mandatory.,Entweder Zielstückzahl oder Zielmenge ist zwingend erforderlich.
apps/erpnext/erpnext/config/projects.py,Cost of various activities,Aufwendungen für verschiedene Tätigkeiten
apps/erpnext/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py,"Setting Events to {0}, since the Employee attached to the below Sales Persons does not have a User ID{1}","Einstellen Events auf {0}, da die Mitarbeiter auf die beigefügten unter Verkaufs Personen keine Benutzer-ID {1}"
@@ -5597,7 +5597,7 @@
apps/erpnext/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py,{0} is not a valid Batch Number for Item {1},{0} ist keine gültige Chargennummer für Artikel {1}
apps/erpnext/erpnext/shopping_cart/cart.py,Please enter valid coupon code !!,Bitte geben Sie einen gültigen Gutscheincode ein !!
apps/erpnext/erpnext/hr/doctype/leave_application/leave_application.py,Note: There is not enough leave balance for Leave Type {0},Hinweis: Es gibt nicht genügend Urlaubsguthaben für Abwesenheitstyp {0}
-DocType: Task,Task Description,Aufgabenbeschreibung
+DocType: Task,Task Description,Vorgangsbeschreibung
DocType: Training Event,Seminar,Seminar
DocType: Program Enrollment Fee,Program Enrollment Fee,Programm Einschreibegebühr
DocType: Item,Supplier Items,Lieferantenartikel
@@ -5658,7 +5658,7 @@
DocType: Depreciation Schedule,Finance Book Id,Finanzbuch-ID
DocType: Item,Safety Stock,Sicherheitsbestand
DocType: Healthcare Settings,Healthcare Settings,Gesundheitswesen
-apps/erpnext/erpnext/hr/doctype/leave_application/leave_application_dashboard.html,Total Allocated Leaves,Insgesamt zugeteilte Blätter
+apps/erpnext/erpnext/hr/doctype/leave_application/leave_application_dashboard.html,Total Allocated Leaves,Insgesamt zugeteilte Urlaubstage
apps/erpnext/erpnext/projects/doctype/task/task.py,Progress % for a task cannot be more than 100.,Fortschritt-% eines Vorgangs darf nicht größer 100 sein.
DocType: Stock Reconciliation Item,Before reconciliation,Vor Ausgleich
apps/erpnext/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.py,To {0},An {0}
@@ -5754,7 +5754,7 @@
DocType: Lost Reason Detail,Lost Reason Detail,Verlorene Begründung Detail
apps/erpnext/erpnext/hr/utils.py,Please set leave policy for employee {0} in Employee / Grade record,Legen Sie die Abwesenheitsrichtlinie für den Mitarbeiter {0} im Mitarbeiter- / Notensatz fest
apps/erpnext/erpnext/public/js/controllers/transaction.js,Invalid Blanket Order for the selected Customer and Item,Ungültiger Blankoauftrag für den ausgewählten Kunden und Artikel
-apps/erpnext/erpnext/projects/doctype/task/task_tree.js,Add Multiple Tasks,Mehrere Aufgaben hinzufügen
+apps/erpnext/erpnext/projects/doctype/task/task_tree.js,Add Multiple Tasks,Mehrere Vorgänge hinzufügen
DocType: Purchase Invoice,Items,Artikel
apps/erpnext/erpnext/crm/doctype/contract/contract.py,End Date cannot be before Start Date.,Das Enddatum darf nicht vor dem Startdatum liegen.
apps/erpnext/erpnext/education/doctype/course_enrollment/course_enrollment.py,Student is already enrolled.,Student ist bereits eingetragen sind.
@@ -5769,7 +5769,7 @@
DocType: Normal Test Items,Normal Test Items,Normale Testartikel
DocType: QuickBooks Migrator,Company Settings,Unternehmenseinstellungen
DocType: Additional Salary,Overwrite Salary Structure Amount,Gehaltsstruktur überschreiben
-DocType: Leave Ledger Entry,Leaves,Blätter
+DocType: Leave Ledger Entry,Leaves,Urlaubstage
DocType: Student Language,Student Language,Student Sprache
DocType: Cash Flow Mapping,Is Working Capital,Ist Arbeitskapital
apps/erpnext/erpnext/hr/doctype/employee_tax_exemption_declaration/employee_tax_exemption_declaration.js,Submit Proof,Nachweis einreichen
@@ -6362,7 +6362,7 @@
DocType: Sales Partner,Contact Desc,Kontakt-Beschr.
DocType: Email Digest,Send regular summary reports via Email.,Regelmäßig zusammenfassende Berichte per E-Mail senden.
apps/erpnext/erpnext/hr/doctype/expense_claim/expense_claim.py,Please set default account in Expense Claim Type {0},Bitte setzen Sie Standardkonto in Kostenabrechnung Typ {0}
-apps/erpnext/erpnext/hr/doctype/leave_application/leave_application_dashboard.html,Available Leaves,Verfügbare Blätter
+apps/erpnext/erpnext/hr/doctype/leave_application/leave_application_dashboard.html,Available Leaves,Verfügbare Urlaubstage
DocType: Assessment Result,Student Name,Name des Studenten
DocType: Hub Tracked Item,Item Manager,Artikel-Manager
apps/erpnext/erpnext/accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts_with_account_number.py,Payroll Payable,Payroll Kreditoren
@@ -7508,7 +7508,7 @@
apps/erpnext/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py,Item {0} must be a stock Item,Artikel {0} muss ein Lagerartikel sein
DocType: Manufacturing Settings,Default Work In Progress Warehouse,Standard-Fertigungslager
apps/erpnext/erpnext/healthcare/doctype/practitioner_schedule/practitioner_schedule.js,"Schedules for {0} overlaps, do you want to proceed after skiping overlaped slots ?","Schedules für {0} Überlappungen, möchten Sie nach Überlappung überlappender Slots fortfahren?"
-apps/erpnext/erpnext/hr/doctype/leave_period/leave_period.js,Grant Leaves,Grant Blätter
+apps/erpnext/erpnext/hr/doctype/leave_period/leave_period.js,Grant Leaves,Urlaubstage gewähren
DocType: Restaurant,Default Tax Template,Standardsteuervorlage
apps/erpnext/erpnext/education/doctype/program_enrollment_tool/program_enrollment_tool.py,{0} Students have been enrolled,{0} Studenten wurden angemeldet
DocType: Fees,Student Details,Studenten Details
diff --git a/erpnext/utilities/transaction_base.py b/erpnext/utilities/transaction_base.py
index f845cef..2099810 100644
--- a/erpnext/utilities/transaction_base.py
+++ b/erpnext/utilities/transaction_base.py
@@ -164,8 +164,8 @@
qty_fields = [qty_fields]
distinct_uoms = list(set([d.get(uom_field) for d in doc.get_all_children()]))
- integer_uoms = filter(lambda uom: frappe.db.get_value("UOM", uom,
- "must_be_whole_number", cache=True) or None, distinct_uoms)
+ integer_uoms = list(filter(lambda uom: frappe.db.get_value("UOM", uom,
+ "must_be_whole_number", cache=True) or None, distinct_uoms))
if not integer_uoms:
return
diff --git a/erpnext/utilities/user_progress.py b/erpnext/utilities/user_progress.py
deleted file mode 100644
index 5cec3ca..0000000
--- a/erpnext/utilities/user_progress.py
+++ /dev/null
@@ -1,287 +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, erpnext
-from frappe import _
-from erpnext.setup.doctype.setup_progress.setup_progress import get_action_completed_state
-
-def get_slide_settings():
- defaults = frappe.defaults.get_defaults()
- domain = frappe.get_cached_value('Company', erpnext.get_default_company(), 'domain')
- company = defaults.get("company") or ''
- currency = defaults.get("currency") or ''
-
- doc = frappe.get_doc("Setup Progress")
- item = [d for d in doc.get("actions") if d.action_name == "Set Sales Target"]
-
- if len(item):
- item = item[0]
- if not item.action_document:
- item.action_document = company
- doc.save()
-
- # Initial state of slides
- return [
- frappe._dict(
- action_name='Add Company',
- title=_("Setup Company") if domain != 'Education' else _("Setup Institution"),
- help=_('Setup your ' + ('company' if domain != 'Education' else 'institution') + ' and brand.'),
- # image_src="/assets/erpnext/images/illustrations/shop.jpg",
- fields=[],
- done_state_title=_("You added " + company),
- done_state_title_route=["Form", "Company", company],
- help_links=[
- {
- "label": _("Chart of Accounts"),
- "url": ["https://erpnext.com/docs/user/manual/en/accounts/chart-of-accounts"]
- },
- {
- "label": _("Opening Balances"),
- "video_id": "U5wPIvEn-0c"
- }
- ]
- ),
- frappe._dict(
- action_name='Set Sales Target',
- domains=('Manufacturing', 'Services', 'Retail', 'Distribution'),
- title=_("Set a Target"),
- help=_("Set a sales goal you'd like to achieve for your company."),
- fields=[
- {"fieldtype":"Currency", "fieldname":"monthly_sales_target",
- "label":_("Monthly Sales Target (" + currency + ")"), "reqd":1},
- ],
- submit_method="erpnext.utilities.user_progress_utils.set_sales_target",
- done_state_title=_("Go to " + company),
- done_state_title_route=["Form", "Company", company],
- help_links=[
- {
- "label": _('Learn More'),
- "url": ["https://erpnext.com/docs/user/manual/en/setting-up/setting-company-sales-goal"]
- }
- ]
- ),
- frappe._dict(
- action_name='Add Customers',
- domains=('Manufacturing', 'Services', 'Retail', 'Distribution'),
- title=_("Add Customers"),
- help=_("List a few of your customers. They could be organizations or individuals."),
- fields=[
- {"fieldtype":"Section Break"},
- {"fieldtype":"Data", "fieldname":"customer", "label":_("Customer"),
- "placeholder":_("Customer Name")},
- {"fieldtype":"Column Break"},
- {"fieldtype":"Data", "fieldname":"customer_contact",
- "label":_("Contact Name"), "placeholder":_("Contact Name")}
- ],
- add_more=1, max_count=3, mandatory_entry=1,
- submit_method="erpnext.utilities.user_progress_utils.create_customers",
- done_state_title=_("Go to Customers"),
- done_state_title_route=["List", "Customer"],
- help_links=[
- {
- "label": _('Learn More'),
- "url": ["https://erpnext.com/docs/user/manual/en/CRM/customer.html"]
- }
- ]
- ),
-
- frappe._dict(
- action_name='Add Letterhead',
- domains=('Manufacturing', 'Services', 'Retail', 'Distribution', 'Education'),
- title=_("Add Letterhead"),
- help=_("Upload your letter head (Keep it web friendly as 900px by 100px)"),
- fields=[
- {"fieldtype":"Attach Image", "fieldname":"letterhead",
- "is_private": 0,
- "align": "center"
- },
- ],
- mandatory_entry=1,
- submit_method="erpnext.utilities.user_progress_utils.create_letterhead",
- done_state_title=_("Go to Letterheads"),
- done_state_title_route=["List", "Letter Head"]
- ),
-
- frappe._dict(
- action_name='Add Suppliers',
- domains=('Manufacturing', 'Services', 'Retail', 'Distribution'),
- icon="fa fa-group",
- title=_("Your Suppliers"),
- help=_("List a few of your suppliers. They could be organizations or individuals."),
- fields=[
- {"fieldtype":"Section Break"},
- {"fieldtype":"Data", "fieldname":"supplier", "label":_("Supplier"),
- "placeholder":_("Supplier Name")},
- {"fieldtype":"Column Break"},
- {"fieldtype":"Data", "fieldname":"supplier_contact",
- "label":_("Contact Name"), "placeholder":_("Contact Name")},
- ],
- add_more=1, max_count=3, mandatory_entry=1,
- submit_method="erpnext.utilities.user_progress_utils.create_suppliers",
- done_state_title=_("Go to Suppliers"),
- done_state_title_route=["List", "Supplier"],
- help_links=[
- {
- "label": _('Learn More'),
- "url": ["https://erpnext.com/docs/user/manual/en/buying/supplier"]
- },
- {
- "label": _('Customers and Suppliers'),
- "video_id": "zsrrVDk6VBs"
- },
- ]
- ),
- frappe._dict(
- action_name='Add Products',
- domains=['Manufacturing', 'Services', 'Retail', 'Distribution'],
- icon="fa fa-barcode",
- title=_("Your Products or Services"),
- help=_("List your products or services that you buy or sell."),
- fields=[
- {"fieldtype":"Section Break", "show_section_border": 1},
- {"fieldtype":"Data", "fieldname":"item", "label":_("Item"),
- "placeholder":_("A Product")},
- {"fieldtype":"Column Break"},
- {"fieldtype":"Select", "fieldname":"item_uom", "label":_("UOM"),
- "options":[_("Unit"), _("Nos"), _("Box"), _("Pair"), _("Kg"), _("Set"),
- _("Hour"), _("Minute"), _("Litre"), _("Meter"), _("Gram")],
- "default": _("Unit"), "static": 1},
- {"fieldtype":"Column Break"},
- {"fieldtype":"Currency", "fieldname":"item_price", "label":_("Rate"), "static": 1}
- ],
- add_more=1, max_count=3, mandatory_entry=1,
- submit_method="erpnext.utilities.user_progress_utils.create_items",
- done_state_title=_("Go to Items"),
- done_state_title_route=["List", "Item"],
- help_links=[
- {
- "label": _("Explore Sales Cycle"),
- "video_id": "1eP90MWoDQM"
- },
- ]
- ),
-
- # Education slides begin
- frappe._dict(
- action_name='Add Programs',
- domains=("Education"),
- title=_("Program"),
- help=_("Example: Masters in Computer Science"),
- fields=[
- {"fieldtype":"Section Break", "show_section_border": 1},
- {"fieldtype":"Data", "fieldname":"program", "label":_("Program"), "placeholder": _("Program Name")},
- ],
- add_more=1, max_count=3, mandatory_entry=1,
- submit_method="erpnext.utilities.user_progress_utils.create_program",
- done_state_title=_("Go to Programs"),
- done_state_title_route=["List", "Program"],
- help_links=[
- {
- "label": _("Student Application"),
- "video_id": "l8PUACusN3E"
- },
- ]
-
- ),
- frappe._dict(
- action_name='Add Courses',
- domains=["Education"],
- title=_("Course"),
- help=_("Example: Basic Mathematics"),
- fields=[
- {"fieldtype":"Section Break", "show_section_border": 1},
- {"fieldtype":"Data", "fieldname":"course", "label":_("Course"), "placeholder": _("Course Name")},
- ],
- add_more=1, max_count=3, mandatory_entry=1,
- submit_method="erpnext.utilities.user_progress_utils.create_course",
- done_state_title=_("Go to Courses"),
- done_state_title_route=["List", "Course"],
- help_links=[
- {
- "label": _('Add Students'),
- "route": ["List", "Student"]
- }
- ]
- ),
- frappe._dict(
- action_name='Add Instructors',
- domains=["Education"],
- title=_("Instructor"),
- help=_("People who teach at your organisation"),
- fields=[
- {"fieldtype":"Section Break", "show_section_border": 1},
- {"fieldtype":"Data", "fieldname":"instructor", "label":_("Instructor"), "placeholder": _("Instructor Name")},
- ],
- add_more=1, max_count=3, mandatory_entry=1,
- submit_method="erpnext.utilities.user_progress_utils.create_instructor",
- done_state_title=_("Go to Instructors"),
- done_state_title_route=["List", "Instructor"],
- help_links=[
- {
- "label": _('Student Batches'),
- "route": ["List", "Student Batch"]
- }
- ]
- ),
- frappe._dict(
- action_name='Add Rooms',
- domains=["Education"],
- title=_("Room"),
- help=_("Classrooms/ Laboratories etc where lectures can be scheduled."),
- fields=[
- {"fieldtype":"Section Break", "show_section_border": 1},
- {"fieldtype":"Data", "fieldname":"room", "label":_("Room")},
- {"fieldtype":"Column Break"},
- {"fieldtype":"Int", "fieldname":"room_capacity", "label":_("Room Capacity"), "static": 1},
- ],
- add_more=1, max_count=3, mandatory_entry=1,
- submit_method="erpnext.utilities.user_progress_utils.create_room",
- done_state_title=_("Go to Rooms"),
- done_state_title_route=["List", "Room"],
- help_links=[]
- ),
- # Education slides end
-
- frappe._dict(
- action_name='Add Users',
- title=_("Add Users"),
- help=_("Add users to your organization, other than yourself."),
- fields=[
- {"fieldtype":"Section Break"},
- {"fieldtype":"Data", "fieldname":"user_email", "label":_("Email ID"),
- "placeholder":_("user@example.com"), "options": "Email", "static": 1},
- {"fieldtype":"Column Break"},
- {"fieldtype":"Data", "fieldname":"user_fullname",
- "label":_("Full Name"), "static": 1},
- ],
- add_more=1, max_count=3, mandatory_entry=1,
- submit_method="erpnext.utilities.user_progress_utils.create_users",
- done_state_title=_("Go to Users"),
- done_state_title_route=["List", "User"],
- help_links=[
- {
- "label": _('Learn More'),
- "url": ["https://erpnext.com/docs/user/manual/en/setting-up/users-and-permissions"]
- },
- {
- "label": _('Users and Permissions'),
- "video_id": "8Slw1hsTmUI"
- },
- ]
- )
- ]
-
-def get_user_progress_slides():
- slides = []
- slide_settings = get_slide_settings()
-
- domains = frappe.get_active_domains()
- for s in slide_settings:
- if not s.domains or any(d in domains for d in s.domains):
- s.mark_as_done_method = "erpnext.setup.doctype.setup_progress.setup_progress.set_action_completed_state"
- s.done = get_action_completed_state(s.action_name) or 0
- slides.append(s)
-
- return slides
-
diff --git a/erpnext/utilities/user_progress_utils.py b/erpnext/utilities/user_progress_utils.py
deleted file mode 100644
index b7c24a7..0000000
--- a/erpnext/utilities/user_progress_utils.py
+++ /dev/null
@@ -1,240 +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, erpnext
-
-import json
-from frappe import _
-from frappe.utils import flt
-from erpnext.setup.doctype.setup_progress.setup_progress import update_domain_actions, get_domain_actions_state
-
-@frappe.whitelist()
-def set_sales_target(args_data):
- args = json.loads(args_data)
- defaults = frappe.defaults.get_defaults()
- frappe.db.set_value("Company", defaults.get("company"), "monthly_sales_target", args.get('monthly_sales_target'))
-
-@frappe.whitelist()
-def create_customers(args_data):
- args = json.loads(args_data)
- defaults = frappe.defaults.get_defaults()
- for i in range(1,4):
- customer = args.get("customer_" + str(i))
- if customer:
- try:
- doc = frappe.get_doc({
- "doctype":"Customer",
- "customer_name": customer,
- "customer_type": "Company",
- "customer_group": _("Commercial"),
- "territory": defaults.get("country"),
- "company": defaults.get("company")
- }).insert()
-
- if args.get("customer_contact_" + str(i)):
- create_contact(args.get("customer_contact_" + str(i)),
- "Customer", doc.name)
- except frappe.NameError:
- pass
-
-@frappe.whitelist()
-def create_letterhead(args_data):
- args = json.loads(args_data)
- letterhead = args.get("letterhead")
- if letterhead:
- try:
- frappe.get_doc({
- "doctype":"Letter Head",
- "content":"""<div><img src="{0}" style='max-width: 100%%;'><br></div>""".format(letterhead.encode('utf-8')),
- "letter_head_name": _("Standard"),
- "is_default": 1
- }).insert()
- except frappe.NameError:
- pass
-
-@frappe.whitelist()
-def create_suppliers(args_data):
- args = json.loads(args_data)
- defaults = frappe.defaults.get_defaults()
- for i in range(1,4):
- supplier = args.get("supplier_" + str(i))
- if supplier:
- try:
- doc = frappe.get_doc({
- "doctype":"Supplier",
- "supplier_name": supplier,
- "supplier_group": _("Local"),
- "company": defaults.get("company")
- }).insert()
-
- if args.get("supplier_contact_" + str(i)):
- create_contact(args.get("supplier_contact_" + str(i)),
- "Supplier", doc.name)
- except frappe.NameError:
- pass
-
-def create_contact(contact, party_type, party):
- """Create contact based on given contact name"""
- contact = contact .split(" ")
-
- contact = frappe.get_doc({
- "doctype":"Contact",
- "first_name":contact[0],
- "last_name": len(contact) > 1 and contact[1] or ""
- })
- contact.append('links', dict(link_doctype=party_type, link_name=party))
- contact.insert()
-
-@frappe.whitelist()
-def create_items(args_data):
- args = json.loads(args_data)
- defaults = frappe.defaults.get_defaults()
- for i in range(1,4):
- item = args.get("item_" + str(i))
- if item:
- default_warehouse = ""
- default_warehouse = frappe.db.get_value("Warehouse", filters={
- "warehouse_name": _("Finished Goods"),
- "company": defaults.get("company_name")
- })
-
- try:
- frappe.get_doc({
- "doctype":"Item",
- "item_code": item,
- "item_name": item,
- "description": item,
- "show_in_website": 1,
- "is_sales_item": 1,
- "is_purchase_item": 1,
- "is_stock_item": 1,
- "item_group": _("Products"),
- "stock_uom": _(args.get("item_uom_" + str(i))),
- "item_defaults": [{
- "default_warehouse": default_warehouse,
- "company": defaults.get("company_name")
- }]
- }).insert()
-
- except frappe.NameError:
- pass
- else:
- if args.get("item_price_" + str(i)):
- item_price = flt(args.get("item_price_" + str(i)))
-
- price_list_name = frappe.db.get_value("Price List", {"selling": 1})
- make_item_price(item, price_list_name, item_price)
- price_list_name = frappe.db.get_value("Price List", {"buying": 1})
- make_item_price(item, price_list_name, item_price)
-
-
-def make_item_price(item, price_list_name, item_price):
- frappe.get_doc({
- "doctype": "Item Price",
- "price_list": price_list_name,
- "item_code": item,
- "price_list_rate": item_price
- }).insert()
-
-# Education
-@frappe.whitelist()
-def create_program(args_data):
- args = json.loads(args_data)
- for i in range(1,4):
- if args.get("program_" + str(i)):
- program = frappe.new_doc("Program")
- program.program_code = args.get("program_" + str(i))
- program.program_name = args.get("program_" + str(i))
- try:
- program.save()
- except frappe.DuplicateEntryError:
- pass
-
-@frappe.whitelist()
-def create_course(args_data):
- args = json.loads(args_data)
- for i in range(1,4):
- if args.get("course_" + str(i)):
- course = frappe.new_doc("Course")
- course.course_code = args.get("course_" + str(i))
- course.course_name = args.get("course_" + str(i))
- try:
- course.save()
- except frappe.DuplicateEntryError:
- pass
-
-@frappe.whitelist()
-def create_instructor(args_data):
- args = json.loads(args_data)
- for i in range(1,4):
- if args.get("instructor_" + str(i)):
- instructor = frappe.new_doc("Instructor")
- instructor.instructor_name = args.get("instructor_" + str(i))
- try:
- instructor.save()
- except frappe.DuplicateEntryError:
- pass
-
-@frappe.whitelist()
-def create_room(args_data):
- args = json.loads(args_data)
- for i in range(1,4):
- if args.get("room_" + str(i)):
- room = frappe.new_doc("Room")
- room.room_name = args.get("room_" + str(i))
- room.seating_capacity = args.get("room_capacity_" + str(i))
- try:
- room.save()
- except frappe.DuplicateEntryError:
- pass
-
-@frappe.whitelist()
-def create_users(args_data):
- if frappe.session.user == 'Administrator':
- return
- args = json.loads(args_data)
- defaults = frappe.defaults.get_defaults()
- for i in range(1,4):
- email = args.get("user_email_" + str(i))
- fullname = args.get("user_fullname_" + str(i))
- if email:
- if not fullname:
- fullname = email.split("@")[0]
-
- parts = fullname.split(" ", 1)
-
- user = frappe.get_doc({
- "doctype": "User",
- "email": email,
- "first_name": parts[0],
- "last_name": parts[1] if len(parts) > 1 else "",
- "enabled": 1,
- "user_type": "System User"
- })
-
- # default roles
- user.append_roles("Projects User", "Stock User", "Support Team")
- user.flags.delay_emails = True
-
- if not frappe.db.get_value("User", email):
- user.insert(ignore_permissions=True)
-
- # create employee
- emp = frappe.get_doc({
- "doctype": "Employee",
- "employee_name": fullname,
- "user_id": email,
- "status": "Active",
- "company": defaults.get("company")
- })
- emp.flags.ignore_mandatory = True
- emp.insert(ignore_permissions = True)
-
-# Ennumerate the setup hooks you're going to need, apart from the slides
-
-@frappe.whitelist()
-def update_default_domain_actions_and_get_state():
- domain = frappe.get_cached_value('Company', erpnext.get_default_company(), 'domain')
- update_domain_actions(domain)
- return get_domain_actions_state(domain)
diff --git a/erpnext/assets/doctype/asset_settings/__init__.py b/erpnext/www/book_appointment/__init__.py
similarity index 100%
copy from erpnext/assets/doctype/asset_settings/__init__.py
copy to erpnext/www/book_appointment/__init__.py
diff --git a/erpnext/www/book_appointment/index.css b/erpnext/www/book_appointment/index.css
new file mode 100644
index 0000000..6c49fde
--- /dev/null
+++ b/erpnext/www/book_appointment/index.css
@@ -0,0 +1,53 @@
+.time-slot {
+ margin-bottom: 2em;
+ margin-left: 0.5em;
+ margin-right: 0.5em;
+ border-radius: 0.4em;
+ cursor: pointer;
+ border: 0.5px solid #cccccc;
+ min-height: 75px;
+ padding: 0.5em 1em;
+}
+
+@media (max-width: 768px) {
+ #submit-button-area {
+ display: grid;
+ grid-template-areas:
+ "submit"
+ "back";
+ }
+}
+#customer-form{
+ border-color: black;
+}
+#customer-form ::placeholder{
+ color: #ddd;
+}
+#timeslot-container{
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: center;
+}
+
+.time-slot:hover {
+ background: #ddd;
+}
+
+.time-slot.unavailable {
+ background: #CBD5E0;
+ cursor: not-allowed;
+ color: #718096
+}
+
+.time-slot.unavailable .text-muted {
+ color: #718096
+}
+
+.time-slot.selected {
+ color: white;
+ background: #5e64ff;
+}
+
+.time-slot.selected .text-muted {
+ color: #EDF2F7 !important;
+}
diff --git a/erpnext/www/book_appointment/index.html b/erpnext/www/book_appointment/index.html
new file mode 100644
index 0000000..f242f43
--- /dev/null
+++ b/erpnext/www/book_appointment/index.html
@@ -0,0 +1,66 @@
+{% extends "templates/web.html" %}
+
+{% block title %}{{ _("Book Appointment") }}{% endblock %}
+
+{% block script %}
+<script src="assets/js/moment-bundle.min.js"></script>
+<script src="book_appointment/index.js"></script>
+{% endblock %}
+
+{% block page_content %}
+<div class="container">
+ <!-- title: Book an appointment -->
+ <div id="select-date-time">
+ <div class="text-center mt-5">
+ <h3>Book an appointment</h3>
+ <p class="lead text-muted" id="lead-text">Select the date and your timezone</p>
+ </div>
+ <div class="row justify-content-center mt-3">
+ <div class="col-md-6 align-self-center ">
+ <div class="row">
+ <input type="date" oninput="on_date_or_timezone_select()" name="appointment-date"
+ id="appointment-date" class="form-control mt-3 col-md m-3">
+ <select name="appointment-timezone" oninput="on_date_or_timezone_select()" id="appointment-timezone"
+ class="form-control m-3 col-md">
+ </select>
+ </div>
+ </div>
+ </div>
+ <div class="mt-3" id="timeslot-container">
+
+ </div>
+ <div class="row justify-content-center mt-3">
+ <div class="col-md-4 mb-3">
+ <button class="btn btn-primary form-control" id="next-button">Next</button>
+ </div>
+ </div>
+ </div>
+</div>
+<!--Enter Details-->
+<div id="enter-details" class="mb-5">
+ <div class="text-center mt-5">
+ <h3>Add details</h3>
+ <p class="lead text-muted">Selected date is <span class="date-span"></span> at <span class="time-span">
+ </span></p>
+ </div>
+ <div class="row justify-content-center mt-3">
+ <div class="col-md-4 align-items-center">
+ <form id="customer-form" action='#'>
+ <input class="form-control mt-3" type="text" name="customer_name" id="customer_name" placeholder="Your Name (required)" required>
+ <input class="form-control mt-3" type="tel" name="customer_number" id="customer_number" placeholder="+910000000000">
+ <input class="form-control mt-3" type="text" name="customer_skype" id="customer_skype" placeholder="Skype">
+ <input class="form-control mt-3"type="email" name="customer_email" id="customer_email" placeholder="Email Address (required)" required>
+
+ <textarea class="form-control mt-3" name="customer_notes" id="customer_notes" cols="30" rows="10"
+ placeholder="Notes"></textarea>
+ </form>
+ <div class="row mt-3 " id="submit-button-area">
+ <div class="col-md mt-3" style="grid-area: back;"><button class="btn btn-dark form-control" onclick="initialise_select_date()">Go back</button></div>
+ <div class="col-md mt-3" style="grid-area: submit;"><button class="btn btn-primary form-control " onclick="submit()" id="submit-button">Submit</button></div>
+ </div>
+ </div>
+ </div>
+</div>
+</div>
+
+{% endblock %}
\ No newline at end of file
diff --git a/erpnext/www/book_appointment/index.js b/erpnext/www/book_appointment/index.js
new file mode 100644
index 0000000..262e31b
--- /dev/null
+++ b/erpnext/www/book_appointment/index.js
@@ -0,0 +1,231 @@
+frappe.ready(async () => {
+ initialise_select_date();
+})
+
+window.holiday_list = [];
+
+async function initialise_select_date() {
+ navigate_to_page(1);
+ await get_global_variables();
+ setup_date_picker();
+ setup_timezone_selector();
+ hide_next_button();
+}
+
+async function get_global_variables() {
+ // Using await through this file instead of then.
+ window.appointment_settings = (await frappe.call({
+ method: 'erpnext.www.book_appointment.index.get_appointment_settings'
+ })).message;
+ window.timezones = (await frappe.call({
+ method:'erpnext.www.book_appointment.index.get_timezones'
+ })).message;
+ window.holiday_list = window.appointment_settings.holiday_list;
+}
+
+function setup_timezone_selector() {
+ let timezones_element = document.getElementById('appointment-timezone');
+ let local_timezone = moment.tz.guess()
+ window.timezones.forEach(timezone => {
+ let opt = document.createElement('option');
+ opt.value = timezone;
+ if (timezone == local_timezone) {
+ opt.selected = true;
+ }
+ opt.innerHTML = timezone;
+ timezones_element.appendChild(opt)
+ });
+}
+
+function setup_date_picker() {
+ let date_picker = document.getElementById('appointment-date');
+ let today = new Date();
+ date_picker.min = today.toISOString().substr(0, 10);
+ today.setDate(today.getDate() + window.appointment_settings.advance_booking_days);
+ date_picker.max = today.toISOString().substr(0, 10);
+}
+
+function hide_next_button() {
+ let next_button = document.getElementById('next-button');
+ next_button.disabled = true;
+ next_button.onclick = () => frappe.msgprint("Please select a date and time");
+}
+
+function show_next_button() {
+ let next_button = document.getElementById('next-button');
+ next_button.disabled = false;
+ next_button.onclick = setup_details_page;
+}
+
+function on_date_or_timezone_select() {
+ let date_picker = document.getElementById('appointment-date');
+ let timezone = document.getElementById('appointment-timezone');
+ if (date_picker.value === '') {
+ clear_time_slots();
+ hide_next_button();
+ frappe.throw('Please select a date');
+ }
+ window.selected_date = date_picker.value;
+ window.selected_timezone = timezone.value;
+ update_time_slots(date_picker.value, timezone.value);
+ let lead_text = document.getElementById('lead-text');
+ lead_text.innerHTML = "Select Time"
+}
+
+async function get_time_slots(date, timezone) {
+ let slots = (await frappe.call({
+ method: 'erpnext.www.book_appointment.index.get_appointment_slots',
+ args: {
+ date: date,
+ timezone: timezone
+ }
+ })).message;
+ return slots;
+}
+
+async function update_time_slots(selected_date, selected_timezone) {
+ let timeslot_container = document.getElementById('timeslot-container');
+ window.slots = await get_time_slots(selected_date, selected_timezone);
+ clear_time_slots();
+ if (window.slots.length <= 0) {
+ let message_div = document.createElement('p');
+ message_div.innerHTML = "There are no slots available on this date";
+ timeslot_container.appendChild(message_div);
+ return
+ }
+ window.slots.forEach((slot, index) => {
+ // Get and append timeslot div
+ let timeslot_div = get_timeslot_div_layout(slot)
+ timeslot_container.appendChild(timeslot_div);
+ });
+ set_default_timeslot();
+}
+
+function get_timeslot_div_layout(timeslot) {
+ let start_time = new Date(timeslot.time)
+ let timeslot_div = document.createElement('div');
+ timeslot_div.classList.add('time-slot');
+ if (!timeslot.availability) {
+ timeslot_div.classList.add('unavailable')
+ }
+ timeslot_div.innerHTML = get_slot_layout(start_time);
+ timeslot_div.id = timeslot.time.substring(11, 19);
+ timeslot_div.addEventListener('click', select_time);
+ return timeslot_div
+}
+
+function clear_time_slots() {
+ // Clear any existing divs in timeslot container
+ let timeslot_container = document.getElementById('timeslot-container');
+ while (timeslot_container.firstChild) {
+ timeslot_container.removeChild(timeslot_container.firstChild);
+ }
+}
+
+function get_slot_layout(time) {
+ let timezone = document.getElementById("appointment-timezone").value;
+ time = new Date(time);
+ let start_time_string = moment(time).tz(timezone).format("LT");
+ let end_time = moment(time).tz(timezone).add(window.appointment_settings.appointment_duration, 'minutes');
+ let end_time_string = end_time.format("LT");
+ return `<span style="font-size: 1.2em;">${start_time_string}</span><br><span class="text-muted small">to ${end_time_string}</span>`;
+}
+
+function select_time() {
+ if (this.classList.contains('unavailable')) {
+ return;
+ }
+ let selected_element = document.getElementsByClassName('selected');
+ if (!(selected_element.length > 0)) {
+ this.classList.add('selected');
+ show_next_button();
+ return;
+ }
+ selected_element = selected_element[0]
+ window.selected_time = this.id;
+ selected_element.classList.remove('selected');
+ this.classList.add('selected');
+ show_next_button();
+}
+
+function set_default_timeslot() {
+ let timeslots = document.getElementsByClassName('time-slot')
+ // Can't use a forEach here since, we need to break the loop after a timeslot is selected
+ for (let i = 0; i < timeslots.length; i++) {
+ const timeslot = timeslots[i];
+ if (!timeslot.classList.contains('unavailable')) {
+ timeslot.classList.add('selected');
+ break;
+ }
+ }
+}
+
+function navigate_to_page(page_number) {
+ let page1 = document.getElementById('select-date-time');
+ let page2 = document.getElementById('enter-details');
+ switch (page_number) {
+ case 1:
+ page1.style.display = 'block';
+ page2.style.display = 'none';
+ break;
+ case 2:
+ page1.style.display = 'none';
+ page2.style.display = 'block';
+ break;
+ default:
+ break;
+ }
+}
+
+function setup_details_page() {
+ navigate_to_page(2)
+ let date_container = document.getElementsByClassName('date-span')[0];
+ let time_container = document.getElementsByClassName('time-span')[0];
+ date_container.innerHTML = moment(window.selected_date).format("MMM Do YYYY");
+ time_container.innerHTML = moment(window.selected_time, "HH:mm:ss").format("LT");
+}
+
+async function submit() {
+ let button = document.getElementById('submit-button');
+ button.disabled = true;
+ let form = document.querySelector('#customer-form');
+ if (!form.checkValidity()) {
+ form.reportValidity();
+ button.disabled = false;
+ return;
+ }
+ let contact = get_form_data();
+ let appointment = frappe.call({
+ method: 'erpnext.www.book_appointment.index.create_appointment',
+ args: {
+ 'date': window.selected_date,
+ 'time': window.selected_time,
+ 'contact': contact,
+ 'tz':window.selected_timezone
+ },
+ callback: (response)=>{
+ if (response.message.status == "Unverified") {
+ frappe.show_alert("Please check your email to confirm the appointment")
+ } else {
+ frappe.show_alert("Appointment Created Successfully");
+ }
+ setTimeout(()=>{
+ let redirect_url = "/";
+ if (window.appointment_settings.success_redirect_url){
+ redirect_url += window.appointment_settings.success_redirect_url;
+ }
+ window.location.href = redirect_url;},5000)
+ },
+ error: (err)=>{
+ frappe.show_alert("Something went wrong please try again");
+ button.disabled = false;
+ }
+ });
+}
+
+function get_form_data() {
+ contact = {};
+ let inputs = ['name', 'skype', 'number', 'notes', 'email'];
+ inputs.forEach((id) => contact[id] = document.getElementById(`customer_${id}`).value)
+ return contact
+}
diff --git a/erpnext/www/book_appointment/index.py b/erpnext/www/book_appointment/index.py
new file mode 100644
index 0000000..7bfac89
--- /dev/null
+++ b/erpnext/www/book_appointment/index.py
@@ -0,0 +1,149 @@
+import frappe
+import datetime
+import json
+import pytz
+
+
+WEEKDAYS = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]
+
+no_cache = 1
+
+
+def get_context(context):
+ is_enabled = frappe.db.get_single_value('Appointment Booking Settings', 'enable_scheduling')
+ if is_enabled:
+ return context
+ else:
+ frappe.local.flags.redirect_location = '/404'
+ raise frappe.Redirect
+
+@frappe.whitelist(allow_guest=True)
+def get_appointment_settings():
+ settings = frappe.get_doc('Appointment Booking Settings')
+ settings.holiday_list = frappe.get_doc('Holiday List', settings.holiday_list)
+ return settings
+
+@frappe.whitelist(allow_guest=True)
+def get_timezones():
+ import pytz
+ return pytz.all_timezones
+
+@frappe.whitelist(allow_guest=True)
+def get_appointment_slots(date, timezone):
+ # Convert query to local timezones
+ format_string = '%Y-%m-%d %H:%M:%S'
+ query_start_time = datetime.datetime.strptime(date + ' 00:00:00', format_string)
+ query_end_time = datetime.datetime.strptime(date + ' 23:59:59', format_string)
+ query_start_time = convert_to_system_timezone(timezone, query_start_time)
+ query_end_time = convert_to_system_timezone(timezone, query_end_time)
+ now = convert_to_guest_timezone(timezone, datetime.datetime.now())
+
+ # Database queries
+ settings = frappe.get_doc('Appointment Booking Settings')
+ holiday_list = frappe.get_doc('Holiday List', settings.holiday_list)
+ timeslots = get_available_slots_between(query_start_time, query_end_time, settings)
+
+ # Filter and convert timeslots
+ converted_timeslots = []
+ for timeslot in timeslots:
+ converted_timeslot = convert_to_guest_timezone(timezone, timeslot)
+ # Check if holiday
+ if _is_holiday(converted_timeslot.date(), holiday_list):
+ converted_timeslots.append(dict(time=converted_timeslot, availability=False))
+ continue
+ # Check availability
+ if check_availabilty(timeslot, settings) and converted_timeslot >= now:
+ converted_timeslots.append(dict(time=converted_timeslot, availability=True))
+ else:
+ converted_timeslots.append(dict(time=converted_timeslot, availability=False))
+ date_required = datetime.datetime.strptime(date + ' 00:00:00', format_string).date()
+ converted_timeslots = filter_timeslots(date_required, converted_timeslots)
+ return converted_timeslots
+
+def get_available_slots_between(query_start_time, query_end_time, settings):
+ records = _get_records(query_start_time, query_end_time, settings)
+ timeslots = []
+ appointment_duration = datetime.timedelta(
+ minutes=settings.appointment_duration)
+ for record in records:
+ if record.day_of_week == WEEKDAYS[query_start_time.weekday()]:
+ current_time = _deltatime_to_datetime(query_start_time, record.from_time)
+ end_time = _deltatime_to_datetime(query_start_time, record.to_time)
+ else:
+ current_time = _deltatime_to_datetime(query_end_time, record.from_time)
+ end_time = _deltatime_to_datetime(query_end_time, record.to_time)
+ while current_time + appointment_duration <= end_time:
+ timeslots.append(current_time)
+ current_time += appointment_duration
+ return timeslots
+
+
+@frappe.whitelist(allow_guest=True)
+def create_appointment(date, time, tz, contact):
+ format_string = '%Y-%m-%d %H:%M:%S'
+ scheduled_time = datetime.datetime.strptime(date + " " + time, format_string)
+ # Strip tzinfo from datetime objects since it's handled by the doctype
+ scheduled_time = scheduled_time.replace(tzinfo = None)
+ scheduled_time = convert_to_system_timezone(tz, scheduled_time)
+ scheduled_time = scheduled_time.replace(tzinfo = None)
+ # Create a appointment document from form
+ appointment = frappe.new_doc('Appointment')
+ appointment.scheduled_time = scheduled_time
+ contact = json.loads(contact)
+ appointment.customer_name = contact.get('name', None)
+ appointment.customer_phone_number = contact.get('number', None)
+ appointment.customer_skype = contact.get('skype', None)
+ appointment.customer_details = contact.get('notes', None)
+ appointment.customer_email = contact.get('email', None)
+ appointment.status = 'Open'
+ appointment.insert()
+ return appointment
+
+# Helper Functions
+def filter_timeslots(date, timeslots):
+ filtered_timeslots = []
+ for timeslot in timeslots:
+ if(timeslot['time'].date() == date):
+ filtered_timeslots.append(timeslot)
+ return filtered_timeslots
+
+def convert_to_guest_timezone(guest_tz, datetimeobject):
+ guest_tz = pytz.timezone(guest_tz)
+ local_timezone = pytz.timezone(frappe.utils.get_time_zone())
+ datetimeobject = local_timezone.localize(datetimeobject)
+ datetimeobject = datetimeobject.astimezone(guest_tz)
+ return datetimeobject
+
+def convert_to_system_timezone(guest_tz,datetimeobject):
+ guest_tz = pytz.timezone(guest_tz)
+ datetimeobject = guest_tz.localize(datetimeobject)
+ system_tz = pytz.timezone(frappe.utils.get_time_zone())
+ datetimeobject = datetimeobject.astimezone(system_tz)
+ return datetimeobject
+
+def check_availabilty(timeslot, settings):
+ return frappe.db.count('Appointment', {'scheduled_time': timeslot}) < settings.number_of_agents
+
+def _is_holiday(date, holiday_list):
+ for holiday in holiday_list.holidays:
+ if holiday.holiday_date == date:
+ return True
+ return False
+
+
+def _get_records(start_time, end_time, settings):
+ records = []
+ for record in settings.availability_of_slots:
+ if record.day_of_week == WEEKDAYS[start_time.weekday()] or record.day_of_week == WEEKDAYS[end_time.weekday()]:
+ records.append(record)
+ return records
+
+
+def _deltatime_to_datetime(date, deltatime):
+ time = (datetime.datetime.min + deltatime).time()
+ return datetime.datetime.combine(date.date(), time)
+
+
+def _datetime_to_deltatime(date_time):
+ midnight = datetime.datetime.combine(date_time.date(), datetime.time.min)
+ return (date_time-midnight)
\ No newline at end of file
diff --git a/erpnext/assets/doctype/asset_settings/__init__.py b/erpnext/www/book_appointment/verify/__init__.py
similarity index 100%
copy from erpnext/assets/doctype/asset_settings/__init__.py
copy to erpnext/www/book_appointment/verify/__init__.py
diff --git a/erpnext/www/book_appointment/verify/index.html b/erpnext/www/book_appointment/verify/index.html
new file mode 100644
index 0000000..ebb65b1
--- /dev/null
+++ b/erpnext/www/book_appointment/verify/index.html
@@ -0,0 +1,18 @@
+{% extends "templates/web.html" %}
+
+{% block title %}
+{{ _("Verify Email") }}
+{% endblock%}
+
+{% block page_content %}
+
+ {% if success==True %}
+ <div class="alert alert-success">
+ Your email has been verified and your appointment has been scheduled
+ </div>
+ {% else %}
+ <div class="alert alert-danger">
+ Verification failed please check the link
+ </div>
+ {% endif %}
+{% endblock%}
\ No newline at end of file
diff --git a/erpnext/www/book_appointment/verify/index.py b/erpnext/www/book_appointment/verify/index.py
new file mode 100644
index 0000000..d4478ae
--- /dev/null
+++ b/erpnext/www/book_appointment/verify/index.py
@@ -0,0 +1,20 @@
+import frappe
+
+from frappe.utils.verified_command import verify_request
+@frappe.whitelist(allow_guest=True)
+def get_context(context):
+ if not verify_request():
+ context.success = False
+ return context
+
+ email = frappe.form_dict['email']
+ appointment_name = frappe.form_dict['appointment']
+
+ if email and appointment_name:
+ appointment = frappe.get_doc('Appointment',appointment_name)
+ appointment.set_verified(email)
+ context.success = True
+ return context
+ else:
+ context.success = False
+ return context
\ No newline at end of file
diff --git a/requirements.txt b/requirements.txt
index 28ba9f6..c277545 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,10 +1,10 @@
+braintree==3.57.1
frappe
-unidecode
-pygithub
-googlemaps
-python-stdnum
-braintree
-gocardless_pro
-woocommerce
-pandas
-plaid-python
\ No newline at end of file
+gocardless-pro==1.11.0
+googlemaps==3.1.1
+pandas==0.24.2
+plaid-python==3.4.0
+PyGithub==1.44.1
+python-stdnum==1.12
+Unidecode==1.1.1
+WooCommerce==2.1.1