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 8856c8cc90..a8afb55df6 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/chart_of_accounts_importer/chart_of_accounts_importer.py b/erpnext/accounts/doctype/chart_of_accounts_importer/chart_of_accounts_importer.py
index 9bf5887b38..34070b01ae 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 @@ def validate_account_types(accounts):
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 584e11c53f..0294e78111 100644
--- a/erpnext/accounts/doctype/cost_center/cost_center.py
+++ b/erpnext/accounts/doctype/cost_center/cost_center.py
@@ -18,6 +18,7 @@ class CostCenter(NestedSet):
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 @@ class CostCenter(NestedSet):
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 c4fad75375..8f23d90676 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/purchase_invoice/purchase_invoice.js b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
index e4e2c7b10f..d7e64cf36f 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
@@ -330,23 +330,6 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
frm: cur_frm
})
},
-
- item_code: function(frm, cdt, cdn) {
- var row = locals[cdt][cdn];
- if(row.item_code) {
- frappe.call({
- method: "erpnext.assets.doctype.asset_category.asset_category.get_asset_category_account",
- args: {
- "item": row.item_code,
- "fieldname": "fixed_asset_account",
- "company": frm.doc.company
- },
- callback: function(r, rt) {
- frappe.model.set_value(cdt, cdn, "expense_account", r.message);
- }
- })
- }
- }
});
cur_frm.script_manager.make(erpnext.accounts.PurchaseInvoice);
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
index 3c85210663..2ea74f6d85 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
@@ -789,22 +789,21 @@ frappe.ui.form.on('Sales Invoice', {
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.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index 70a80ca184..def671c19b 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -1048,13 +1048,18 @@ class SalesInvoice(SellingController):
continue
for serial_no in item.serial_no.split("\n"):
- sales_invoice, item_code = frappe.db.get_value("Serial No", serial_no,
- ["sales_invoice", "item_code"])
- if sales_invoice and item_code == item.item_code 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:
diff --git a/erpnext/accounts/doctype/shipping_rule/shipping_rule.py b/erpnext/accounts/doctype/shipping_rule/shipping_rule.py
index a20f5c0872..8c4efbebe8 100644
--- a/erpnext/accounts/doctype/shipping_rule/shipping_rule.py
+++ b/erpnext/accounts/doctype/shipping_rule/shipping_rule.py
@@ -70,7 +70,7 @@ class ShippingRule(Document):
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/general_ledger.py b/erpnext/accounts/general_ledger.py
index 2ba319d05e..feb598a2e5 100644
--- a/erpnext/accounts/general_ledger.py
+++ b/erpnext/accounts/general_ledger.py
@@ -162,33 +162,34 @@ def validate_account_for_perpetual_inventory(gl_map):
frappe.throw(_("Account: {0} can only be updated via Stock Transactions")
.format(account), StockAccountInvalidTransaction)
- 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"))
+ # 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")
+ # 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')
+ # 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) }]
- }
+ # 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}
{1}
""".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
- })
+ # frappe.msgprint(msg="""{0}
{1}
""".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):
cwip_enabled = any([cint(ac.enable_cwip_accounting) for ac in frappe.db.get_all("Asset Category","enable_cwip_accounting")])
diff --git a/erpnext/accounts/report/accounts_payable/accounts_payable.js b/erpnext/accounts/report/accounts_payable/accounts_payable.js
index 8eb670de51..b1f427ca7f 100644
--- a/erpnext/accounts/report/accounts_payable/accounts_payable.js
+++ b/erpnext/accounts/report/accounts_payable/accounts_payable.js
@@ -100,6 +100,11 @@ frappe.query_reports["Accounts Payable"] = {
"fieldtype": "Link",
"options": "Supplier Group"
},
+ {
+ "fieldname":"based_on_payment_terms",
+ "label": __("Based On Payment Terms"),
+ "fieldtype": "Check",
+ },
{
"fieldname":"tax_id",
"label": __("Tax Id"),
diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
index 14906f2c2e..41989bf863 100755
--- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
+++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
@@ -318,7 +318,7 @@ class ReceivablePayableReport(object):
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)
diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py
index 94697be02f..89c8467da2 100644
--- a/erpnext/accounts/utils.py
+++ b/erpnext/accounts/utils.py
@@ -569,7 +569,7 @@ def get_stock_and_account_balance(account=None, posting_date=None, company=None)
warehouse_account = get_warehouse_account_map(company)
- account_balance = get_balance_on(account, posting_date, in_account_currency=False)
+ account_balance = get_balance_on(account, posting_date, in_account_currency=False, ignore_account_permission=True)
related_warehouses = [wh for wh, wh_details in warehouse_account.items()
if wh_details.account == account and not wh_details.is_group]
diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py
index 40f1e1efc9..d32f834f0f 100644
--- a/erpnext/assets/doctype/asset/asset.py
+++ b/erpnext/assets/doctype/asset/asset.py
@@ -517,15 +517,18 @@ def update_maintenance_status():
asset.set_status('Out of Order')
def make_post_gl_entry():
- if not is_cwip_accounting_enabled(self.asset_category):
- 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')
diff --git a/erpnext/assets/doctype/asset_category/asset_category.py b/erpnext/assets/doctype/asset_category/asset_category.py
index 2a42894623..fc08841be9 100644
--- a/erpnext/assets/doctype/asset_category/asset_category.py
+++ b/erpnext/assets/doctype/asset_category/asset_category.py
@@ -29,7 +29,8 @@ def get_asset_category_account(fieldname, item=None, asset=None, account=None, a
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/buying/doctype/purchase_order/purchase_order.js b/erpnext/buying/doctype/purchase_order/purchase_order.js
index c5fa98da09..7b5e5c5cca 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.js
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.js
@@ -18,6 +18,7 @@ frappe.ui.form.on("Purchase Order", {
return {
filters: {
"company": frm.doc.company,
+ "name": ['!=', frm.doc.supplier_warehouse],
"is_group": 0
}
}
@@ -283,6 +284,8 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
})
}
+ 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/test_purchase_order.py b/erpnext/buying/doctype/purchase_order/test_purchase_order.py
index 4506db6405..a0a1e8ed5c 100644
--- a/erpnext/buying/doctype/purchase_order/test_purchase_order.py
+++ b/erpnext/buying/doctype/purchase_order/test_purchase_order.py
@@ -519,47 +519,62 @@ class TestPurchaseOrder(unittest.TestCase):
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(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)
- self.assertEquals(se_items, supplied_items)
update_backflush_based_on("BOM")
def test_advance_payment_entry_unlink_against_purchase_order(self):
diff --git a/erpnext/buying/doctype/supplier/supplier.py b/erpnext/buying/doctype/supplier/supplier.py
index b6d588ed96..62a04f37b1 100644
--- a/erpnext/buying/doctype/supplier/supplier.py
+++ b/erpnext/buying/doctype/supplier/supplier.py
@@ -56,3 +56,23 @@ class Supplier(TransactionBase):
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/setup_wizard_slide/add_a_few_suppliers/add_a_few_suppliers.json b/erpnext/buying/setup_wizard_slide/add_a_few_suppliers/add_a_few_suppliers.json
new file mode 100644
index 0000000000..006d139eb0
--- /dev/null
+++ b/erpnext/buying/setup_wizard_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": "Setup Wizard Slide",
+ "domains": [],
+ "help_links": [
+ {
+ "label": "Supplier",
+ "video_id": "zsrrVDk6VBs"
+ }
+ ],
+ "idx": 0,
+ "image_src": "/assets/erpnext/images/illustrations/supplier.png",
+ "max_count": 3,
+ "modified": "2019-11-26 18:26:25.498325",
+ "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",
+ "submit_method": ""
+}
\ No newline at end of file
diff --git a/erpnext/config/accounts.py b/erpnext/config/accounts.py
index ab75f211c0..08711fc09e 100644
--- a/erpnext/config/accounts.py
+++ b/erpnext/config/accounts.py
@@ -197,6 +197,11 @@ def get_data():
"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/stock.py b/erpnext/config/stock.py
index 441a3ab4ec..e24d7b88df 100644
--- a/erpnext/config/stock.py
+++ b/erpnext/config/stock.py
@@ -241,6 +241,10 @@ def get_data():
"type": "doctype",
"name": "Quality Inspection Template",
},
+ {
+ "type": "doctype",
+ "name": "Quick Stock Balance",
+ },
]
},
{
diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py
index d12643af82..3ec7aff9cb 100644
--- a/erpnext/controllers/buying_controller.py
+++ b/erpnext/controllers/buying_controller.py
@@ -221,7 +221,7 @@ class BuyingController(StockController):
"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"]:
@@ -241,41 +241,95 @@ class BuyingController(StockController):
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)
+
+ raw_material_data = backflushed_raw_materials_map.get(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_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:
+ 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
@@ -387,9 +441,11 @@ class BuyingController(StockController):
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
@@ -722,28 +778,72 @@ def get_items_from_bom(item_code, bom, exploded_item=1):
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 = {}
@@ -776,3 +876,125 @@ def validate_item_type(doc, fieldname, message):
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/education/doctype/program_enrollment/program_enrollment.py b/erpnext/education/doctype/program_enrollment/program_enrollment.py
index d5348ffd06..7536172891 100644
--- a/erpnext/education/doctype/program_enrollment/program_enrollment.py
+++ b/erpnext/education/doctype/program_enrollment/program_enrollment.py
@@ -71,7 +71,7 @@ class ProgramEnrollment(Document):
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/healthcare/doctype/clinical_procedure_template/clinical_procedure_template.py b/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template.py
index 141329b3db..7cec362200 100644
--- a/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template.py
+++ b/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template.py
@@ -63,10 +63,11 @@ def updating_rate(self):
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 c107cd7335..835b38bedf 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 @@ class InpatientRecord(Document):
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 1fb4c2b596..ed5bf9b5d8 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -40,8 +40,6 @@ after_install = "erpnext.setup.install.after_install"
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"
diff --git a/erpnext/hr/doctype/repayment_schedule/repayment_schedule.json b/erpnext/hr/doctype/repayment_schedule/repayment_schedule.json
index a1161851d0..5bb2d370fa 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/manufacturing/doctype/bom_update_tool/bom_update_tool.py b/erpnext/manufacturing/doctype/bom_update_tool/bom_update_tool.py
index 2ca4d16a07..31a9fdb28a 100644
--- a/erpnext/manufacturing/doctype/bom_update_tool/bom_update_tool.py
+++ b/erpnext/manufacturing/doctype/bom_update_tool/bom_update_tool.py
@@ -9,6 +9,7 @@ from frappe import _
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):
@@ -17,7 +18,8 @@ class BOMUpdateTool(Document):
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_cached_doc('BOM', bom)
diff --git a/erpnext/manufacturing/report/bom_explorer/bom_explorer.py b/erpnext/manufacturing/report/bom_explorer/bom_explorer.py
index 875d1152de..48907adc5f 100644
--- a/erpnext/manufacturing/report/bom_explorer/bom_explorer.py
+++ b/erpnext/manufacturing/report/bom_explorer/bom_explorer.py
@@ -14,7 +14,7 @@ def execute(filters=None):
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 @@ def get_exploded_items(bom, data, indent=0):
'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/patches/v8_9/add_setup_progress_actions.py b/erpnext/patches/v8_9/add_setup_progress_actions.py
index fe123111bc..77501073cf 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 @@ from frappe import _
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 b262c4640c..bf5c4025a0 100644
--- a/erpnext/portal/doctype/homepage/test_homepage.py
+++ b/erpnext/portal/doctype/homepage/test_homepage.py
@@ -5,7 +5,7 @@ from __future__ import unicode_literals
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 c52b7a96c6..5b3196def2 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 @@ from __future__ import unicode_literals
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 a534e5f838..97042dba92 100644
--- a/erpnext/portal/product_configurator/test_product_configurator.py
+++ b/erpnext/portal/product_configurator/test_product_configurator.py
@@ -2,7 +2,7 @@ from __future__ import unicode_literals
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/public/images/illustrations/collaboration.png b/erpnext/public/images/illustrations/collaboration.png
new file mode 100644
index 0000000000..12c67e394c
Binary files /dev/null and b/erpnext/public/images/illustrations/collaboration.png differ
diff --git a/erpnext/public/images/illustrations/customer.png b/erpnext/public/images/illustrations/customer.png
new file mode 100644
index 0000000000..b2ddbf3bb4
Binary files /dev/null and b/erpnext/public/images/illustrations/customer.png differ
diff --git a/erpnext/public/images/illustrations/letterhead.png b/erpnext/public/images/illustrations/letterhead.png
new file mode 100644
index 0000000000..37df6d7f6f
Binary files /dev/null and b/erpnext/public/images/illustrations/letterhead.png differ
diff --git a/erpnext/public/images/illustrations/onboard.png b/erpnext/public/images/illustrations/onboard.png
new file mode 100644
index 0000000000..094aa3f8dd
Binary files /dev/null and b/erpnext/public/images/illustrations/onboard.png differ
diff --git a/erpnext/public/images/illustrations/product.png b/erpnext/public/images/illustrations/product.png
new file mode 100644
index 0000000000..f864b7af60
Binary files /dev/null and b/erpnext/public/images/illustrations/product.png differ
diff --git a/erpnext/public/images/illustrations/supplier.png b/erpnext/public/images/illustrations/supplier.png
new file mode 100644
index 0000000000..87f7789600
Binary files /dev/null and b/erpnext/public/images/illustrations/supplier.png differ
diff --git a/erpnext/public/images/illustrations/user.png b/erpnext/public/images/illustrations/user.png
new file mode 100644
index 0000000000..7dd7db210d
Binary files /dev/null and b/erpnext/public/images/illustrations/user.png differ
diff --git a/erpnext/public/less/erpnext.less b/erpnext/public/less/erpnext.less
index 8ed5f1adb0..abe48685f0 100644
--- a/erpnext/public/less/erpnext.less
+++ b/erpnext/public/less/erpnext.less
@@ -426,7 +426,7 @@ body[data-route="pos"] {
.collapse-btn {
cursor: pointer;
}
-
+
@media (max-width: @screen-xs) {
.page-actions {
max-width: 110px;
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 e7cc91952d..7ff4de4863 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 '+frm.doc.name+'.',
+ 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 2a2145c7f7..06dab3726d 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 9637c2e502..fa2cb1299a 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,22 @@ from frappe.model.document import Document
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})
+ item_to_be_updated.save()
\ No newline at end of file
diff --git a/erpnext/regional/report/datev/datev.py b/erpnext/regional/report/datev/datev.py
index ee8735fb1f..bd70639ef2 100644
--- a/erpnext/regional/report/datev/datev.py
+++ b/erpnext/regional/report/datev/datev.py
@@ -10,17 +10,26 @@ Provide a report and downloadable CSV according to the German DATEV format.
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 @@ def validate(filters):
except frappe.DoesNotExistError:
frappe.throw(_('Please create DATEV Settings for Company {}.').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 @@ def get_gl_entries(filters, as_dict):
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 @@ def get_gl_entries(filters, as_dict):
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 @@ def get_gl_entries(filters, as_dict):
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 @@ def get_datev_csv(data, filters):
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 @@ def get_datev_csv(data, filters):
# 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 @@ def get_datev_csv(data, filters):
# 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 @@ def get_datev_csv(data, filters):
# 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 @@ def download_datev_csv(filters=None):
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 0000000000..1c9bd23ee1
--- /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 0000000000..3cc65fe9d3
--- /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 9682768280..ce559218cb 100644
--- a/erpnext/regional/report/gstr_1/gstr_1.js
+++ b/erpnext/regional/report/gstr_1/gstr_1.js
@@ -52,7 +52,7 @@ frappe.query_reports["GSTR-1"] = {
],
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 = {
diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py
index 67e20b1e89..57308cea41 100644
--- a/erpnext/selling/doctype/customer/customer.py
+++ b/erpnext/selling/doctype/customer/customer.py
@@ -204,6 +204,40 @@ class Customer(TransactionBase):
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 get_loyalty_programs(doc):
''' returns applicable loyalty programs for a customer '''
diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py
index e12b359bdf..e97a4ee461 100755
--- a/erpnext/selling/doctype/sales_order/sales_order.py
+++ b/erpnext/selling/doctype/sales_order/sales_order.py
@@ -834,6 +834,10 @@ def make_purchase_order(source_name, for_supplier=None, selected_items=[], targe
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:
diff --git a/erpnext/selling/setup_wizard_slide/add_a_few_customers/add_a_few_customers.json b/erpnext/selling/setup_wizard_slide/add_a_few_customers/add_a_few_customers.json
new file mode 100644
index 0000000000..a0bb6fe26d
--- /dev/null
+++ b/erpnext/selling/setup_wizard_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": "Setup Wizard Slide",
+ "domains": [],
+ "help_links": [
+ {
+ "label": "Customers",
+ "video_id": "zsrrVDk6VBs"
+ }
+ ],
+ "idx": 0,
+ "image_src": "/assets/erpnext/images/illustrations/customer.png",
+ "max_count": 3,
+ "modified": "2019-11-26 18:26:15.888794",
+ "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",
+ "submit_method": ""
+}
\ No newline at end of file
diff --git a/erpnext/setup/doctype/setup_progress/__init__.py b/erpnext/setup/doctype/setup_progress/__init__.py
deleted file mode 100644
index e69de29bb2..0000000000
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 5c78bd5075..0000000000
--- 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 09072d4665..0000000000
--- 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 e1402f5844..0000000000
--- 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 9e84e0cb15..0000000000
--- 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 8926219143..0000000000
--- 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 e69de29bb2..0000000000
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 e9abcbcd1a..0000000000
--- 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 24af94347e..0000000000
--- 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/setup_wizard/test_setup_wizard.py b/erpnext/setup/setup_wizard/test_setup_wizard.py
deleted file mode 100644
index a489133aba..0000000000
--- 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/setup_wizard_slide/welcome_to_erpnext!/welcome_to_erpnext!.json b/erpnext/setup/setup_wizard_slide/welcome_to_erpnext!/welcome_to_erpnext!.json
new file mode 100644
index 0000000000..1da9dd44e2
--- /dev/null
+++ b/erpnext/setup/setup_wizard_slide/welcome_to_erpnext!/welcome_to_erpnext!.json
@@ -0,0 +1,22 @@
+{
+ "add_more_button": 0,
+ "app": "ERPNext",
+ "creation": "2019-11-26 17:01:26.671859",
+ "docstatus": 0,
+ "doctype": "Setup Wizard Slide",
+ "domains": [],
+ "help_links": [],
+ "idx": 0,
+ "image_src": "/assets/erpnext/images/illustrations/onboard.png",
+ "max_count": 0,
+ "modified": "2019-11-26 17:17:29.813299",
+ "modified_by": "Administrator",
+ "name": "Welcome to ERPNext!",
+ "owner": "Administrator",
+ "slide_desc": "Setting up an ERP can be overwhelming. But don't worry, we have got your back!
\nLet's setup your company.\nThis wizard will help you onboard to ERPNext in a short time!",
+ "slide_fields": [],
+ "slide_module": "Setup",
+ "slide_order": 10,
+ "slide_title": "Welcome to ERPNext!",
+ "slide_type": "Information"
+}
\ No newline at end of file
diff --git a/erpnext/shopping_cart/cart.py b/erpnext/shopping_cart/cart.py
index 1236ade45f..813d0dd196 100644
--- a/erpnext/shopping_cart/cart.py
+++ b/erpnext/shopping_cart/cart.py
@@ -66,6 +66,7 @@ def place_order():
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"):
diff --git a/erpnext/stock/doctype/item/item.js b/erpnext/stock/doctype/item/item.js
index 410d9f1b45..e3d356f93b 100644
--- a/erpnext/stock/doctype/item/item.js
+++ b/erpnext/stock/doctype/item/item.js
@@ -136,6 +136,20 @@ frappe.ui.form.on("Item", {
frm.toggle_reqd('customer', frm.doc.is_customer_provided_item ? 1:0);
},
+ gst_hsn_code: function(frm){
+ if(!frm.doc.taxes){
+ frappe.db.get_doc("GST HSN Code", frm.doc.gst_hsn_code).then(hsn_doc=>{
+ frm.doc.taxes = [];
+ $.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;
+ frm.refresh_field('taxes');
+ });
+ });
+ }
+ },
+
is_fixed_asset: function(frm) {
// set serial no to false & toggles its visibility
frm.set_value('has_serial_no', 0);
diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py
index 7495dffec2..189261cb2d 100644
--- a/erpnext/stock/doctype/item/item.py
+++ b/erpnext/stock/doctype/item/item.py
@@ -884,6 +884,54 @@ class Item(WebsiteGenerator):
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 = {}
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js
index d5914f9b28..6b5e40e628 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js
@@ -34,6 +34,12 @@ frappe.ui.form.on("Purchase Receipt", {
filters: {'company': frm.doc.company }
}
});
+
+ frm.set_query("taxes_and_charges", function() {
+ return {
+ filters: {'company': frm.doc.company }
+ }
+ });
},
onload: function(frm) {
@@ -296,4 +302,4 @@ var validate_sample_quantity = function(frm, cdt, cdn) {
}
});
}
-};
\ 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 a6f7343388..f261fd9979 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 @@ frappe.ui.form.on('Quick Stock Balance', {
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/stock_ledger_entry/stock_ledger_entry.json b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.json
index 947f94853e..c9eba71b0d 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/get_item_details.py b/erpnext/stock/get_item_details.py
index 9f47edc774..55f4be136b 100644
--- a/erpnext/stock/get_item_details.py
+++ b/erpnext/stock/get_item_details.py
@@ -254,6 +254,12 @@ def get_basic_details(args, item, overwrite_warehouse=True):
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:
@@ -271,7 +277,7 @@ def get_basic_details(args, item, overwrite_warehouse=True):
"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,
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 caf7eb8863..48c0f423fd 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_ledger/stock_ledger.py b/erpnext/stock/report/stock_ledger/stock_ledger.py
index db7f6ad1b9..d757ecb293 100644
--- a/erpnext/stock/report/stock_ledger/stock_ledger.py
+++ b/erpnext/stock/report/stock_ledger/stock_ledger.py
@@ -122,8 +122,8 @@ def get_item_details(items, sl_entries, include_uom):
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
diff --git a/erpnext/stock/setup_wizard_slide/add_a_few_products_you_buy_or_sell/add_a_few_products_you_buy_or_sell.json b/erpnext/stock/setup_wizard_slide/add_a_few_products_you_buy_or_sell/add_a_few_products_you_buy_or_sell.json
new file mode 100644
index 0000000000..c536f7b2ca
--- /dev/null
+++ b/erpnext/stock/setup_wizard_slide/add_a_few_products_you_buy_or_sell/add_a_few_products_you_buy_or_sell.json
@@ -0,0 +1,57 @@
+{
+ "add_more_button": 1,
+ "app": "ERPNext",
+ "creation": "2019-11-15 14:41:12.007359",
+ "docstatus": 0,
+ "doctype": "Setup Wizard Slide",
+ "domains": [],
+ "help_links": [],
+ "idx": 0,
+ "image_src": "/assets/erpnext/images/illustrations/product.png",
+ "max_count": 3,
+ "modified": "2019-11-26 18:26:35.305755",
+ "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": "",
+ "fieldtype": "Column Break",
+ "reqd": 1
+ },
+ {
+ "align": "",
+ "fieldname": "uom",
+ "fieldtype": "Link",
+ "label": "UOM",
+ "options": "UOM",
+ "reqd": 1
+ },
+ {
+ "align": "",
+ "fieldtype": "Column Break",
+ "reqd": 0
+ },
+ {
+ "align": "",
+ "fieldname": "item_price",
+ "fieldtype": "Currency",
+ "label": "Item Price",
+ "reqd": 1
+ }
+ ],
+ "slide_order": 30,
+ "slide_title": "Add A Few Products You Buy Or Sell",
+ "slide_type": "Create",
+ "submit_method": ""
+}
\ No newline at end of file
diff --git a/erpnext/translations/de.csv b/erpnext/translations/de.csv
index 2e25a127d8..cdff3ff422 100644
--- a/erpnext/translations/de.csv
+++ b/erpnext/translations/de.csv
@@ -1329,7 +1329,7 @@ apps/erpnext/erpnext/hr/doctype/job_offer/job_offer.js,Create Employee,Mitarbeit
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 @@ DocType: Payment Entry,Received Amount (Company Currency),Erhaltene Menge (Gesel
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
@@ -2449,7 +2449,7 @@ apps/erpnext/erpnext/public/js/utils/serial_no_batch_selector.js,Please select b
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
@@ -2846,7 +2846,7 @@ DocType: Loan,Applicant Type,Bewerbertyp
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
@@ -3323,7 +3323,7 @@ DocType: Soil Texture,Silt,Schlick
,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
@@ -3961,7 +3961,7 @@ apps/erpnext/erpnext/selling/doctype/sales_order/sales_order.py,Maintenance Sche
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
@@ -4418,7 +4418,7 @@ DocType: Normal Test Items,Result Value,Ergebnis Wert
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
@@ -5197,7 +5197,7 @@ DocType: Work Order,Material Transferred for Manufacturing,Material zur Herstell
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/accounts/doctype/purchase_invoice/purchase_invoice.py,Paid
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
@@ -5754,7 +5754,7 @@ apps/erpnext/erpnext/accounts/doctype/sales_invoice/pos.py,All Territories,Alle
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.
diff --git a/erpnext/utilities/user_progress.py b/erpnext/utilities/user_progress.py
deleted file mode 100644
index 5cec3ca384..0000000000
--- 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 b7c24a71ba..0000000000
--- 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":"""