Merge branch 'develop' into set-request-util

This commit is contained in:
Nabin Hait 2019-11-29 18:49:34 +05:30 committed by GitHub
commit d1b1156b8c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
70 changed files with 2124 additions and 2596 deletions

View File

@ -63,6 +63,7 @@ install:
- tar -xf /tmp/wkhtmltox.tar.xz -C /tmp - tar -xf /tmp/wkhtmltox.tar.xz -C /tmp
- sudo mv /tmp/wkhtmltox/bin/wkhtmltopdf /usr/local/bin/wkhtmltopdf - sudo mv /tmp/wkhtmltox/bin/wkhtmltopdf /usr/local/bin/wkhtmltopdf
- sudo chmod o+x /usr/local/bin/wkhtmltopdf - sudo chmod o+x /usr/local/bin/wkhtmltopdf
- sudo apt-get install libcups2-dev
- cd ~/frappe-bench - cd ~/frappe-bench

View File

@ -1,465 +1,466 @@
{ {
"country_code": "ae", "country_code": "ae",
"name": "U.A.E - Chart of Accounts", "name": "U.A.E - Chart of Accounts",
"tree": { "tree": {
"Assets": { "Assets": {
"Current Assets": { "Current Assets": {
"Accounts Receivable": { "Accounts Receivable": {
"Corporate Credit Cards": { "Corporate Credit Cards": {
"account_type": "Receivable" "account_type": "Receivable"
}, },
"Other Receivable": { "Other Receivable": {
"Accrued Rebates Due from Suppliers": { "Accrued Rebates Due from Suppliers": {
"account_type": "Receivable" "account_type": "Receivable"
}, },
"Accrued Income from Suppliers": { "Accrued Income from Suppliers": {
"account_type": "Receivable" "account_type": "Receivable"
}, },
"Other Debtors": { "Other Debtors": {
"account_type": "Receivable" "account_type": "Receivable"
}, },
"account_type": "Receivable" "account_type": "Receivable"
}, },
"Post Dated Cheques Received": { "Post Dated Cheques Received": {
"account_type": "Receivable" "account_type": "Receivable"
}, },
"Staff Receivable": { "Staff Receivable": {
"account_type": "Receivable" "account_type": "Receivable"
}, },
"Trade Receivable": { "Trade Receivable": {
"account_type": "Receivable" "account_type": "Receivable"
}, },
"Trade in Opening Fees": { "Trade in Opening Fees": {
"account_type": "Receivable" "account_type": "Receivable"
}, },
"account_type": "Receivable" "account_type": "Receivable"
}, },
"Cash in Hand & Banks": { "Cash in Hand & Banks": {
"Banks": { "Banks": {
"Bank Margin On LC & LG": {}, "Bank Margin On LC & LG": {},
"Banks Blocked Deposits": {}, "Banks Blocked Deposits": {},
"Banks Call Deposit Accounts": {}, "Banks Call Deposit Accounts": {},
"Banks Current Accounts": { "Banks Current Accounts": {
"account_type": "Bank" "account_type": "Bank"
}, },
"account_type": "Bank" "account_type": "Bank"
}, },
"Cash in Hand": { "Cash in Hand": {
"Cash in Safe": { "Cash in Safe": {
"Main Safe": { "Main Safe": {
"account_type": "Cash" "account_type": "Cash"
}, },
"Main Safe - Foreign Currency": { "Main Safe - Foreign Currency": {
"account_type": "Cash" "account_type": "Cash"
} }
}, },
"Petty Cash": { "Petty Cash": {
"Petty Cash - Administration": { "Petty Cash - Administration": {
"account_type": "Cash" "account_type": "Cash"
}, },
"Petty Cash - Others": { "Petty Cash - Others": {
"account_type": "Cash" "account_type": "Cash"
} }
}, },
"account_type": "Cash" "account_type": "Cash"
}, },
"Cash in Transit": { "Cash in Transit": {
"Credit Cards": { "Credit Cards": {
"Gateway Credit Cards": { "Gateway Credit Cards": {
"account_type": "Bank" "account_type": "Bank"
}, },
"Manual Visa & Master Cards": { "Manual Visa & Master Cards": {
"account_type": "Bank" "account_type": "Bank"
}, },
"PayPal Account": { "PayPal Account": {
"account_type": "Bank" "account_type": "Bank"
}, },
"Visa & Master Credit Cards": { "Visa & Master Credit Cards": {
"account_type": "Bank" "account_type": "Bank"
} }
} }
} }
}, },
"Inventory": { "Inventory": {
"Consigned Stock": { "Consigned Stock": {
"Handling Difference in Inventory": { "Handling Difference in Inventory": {},
"account_type": "Stock Adjustment"
},
"Items Delivered to Customs on temporary Base": {} "Items Delivered to Customs on temporary Base": {}
}, },
"Stock in Hand": { "Stock in Hand": {
"account_type": "Stock" "account_type": "Stock"
} }
}, },
"Preliminary and Preoperating Expenses": { "Preliminary and Preoperating Expenses": {
"Preoperating Expenses": {} "Preoperating Expenses": {}
}, },
"Prepayments & Deposits": { "Prepayments & Deposits": {
"Deposits": { "Deposits": {
"Deposit - Office Rent": {}, "Deposit - Office Rent": {},
"Deposit Others": {}, "Deposit Others": {},
"Deposit to Immigration (Visa)": {}, "Deposit to Immigration (Visa)": {},
"Deposits - Customs": {} "Deposits - Customs": {}
}, },
"Prepaid Taxes": { "Prepaid Taxes": {
"Sales Taxes Receivables": {}, "Sales Taxes Receivables": {},
"Withholding Tax Receivables": {} "Withholding Tax Receivables": {}
}, },
"Prepayments": { "Prepayments": {
"Other Prepayments": {}, "Other Prepayments": {},
"PrePaid Advertisement Expenses": {}, "PrePaid Advertisement Expenses": {},
"Prepaid Bank Guarantee": {}, "Prepaid Bank Guarantee": {},
"Prepaid Consultancy Fees": {}, "Prepaid Consultancy Fees": {},
"Prepaid Employees Housing": {}, "Prepaid Employees Housing": {},
"Prepaid Finance charge for Loans": {}, "Prepaid Finance charge for Loans": {},
"Prepaid Legal Fees": {}, "Prepaid Legal Fees": {},
"Prepaid License Fees": {}, "Prepaid License Fees": {},
"Prepaid Life Insurance": {}, "Prepaid Life Insurance": {},
"Prepaid Maintenance": {}, "Prepaid Maintenance": {},
"Prepaid Medical Insurance": {}, "Prepaid Medical Insurance": {},
"Prepaid Office Rent": {}, "Prepaid Office Rent": {},
"Prepaid Other Insurance": {}, "Prepaid Other Insurance": {},
"Prepaid Schooling Fees": {}, "Prepaid Schooling Fees": {},
"Prepaid Site Hosting Fees": {}, "Prepaid Site Hosting Fees": {},
"Prepaid Sponsorship Fees": {} "Prepaid Sponsorship Fees": {}
} }
} }
}, },
"Long Term Assets": { "Long Term Assets": {
"Fixed Assets": { "Fixed Assets": {
"Accumulated Depreciation": { "Accumulated Depreciation": {
"Acc. Depreciation of Motor Vehicles": { "Acc. Depreciation of Motor Vehicles": {
"account_type": "Accumulated Depreciation" "account_type": "Accumulated Depreciation"
}, },
"Acc. Deprn.Computer Hardware & Software": { "Acc. Deprn.Computer Hardware & Software": {
"account_type": "Accumulated Depreciation" "account_type": "Accumulated Depreciation"
}, },
"Acc.Deprn.of Furniture & Office Equipment": { "Acc.Deprn.of Furniture & Office Equipment": {
"account_type": "Accumulated Depreciation" "account_type": "Accumulated Depreciation"
}, },
"Amortisation on Leasehold Improvement": { "Amortisation on Leasehold Improvement": {
"account_type": "Accumulated Depreciation" "account_type": "Accumulated Depreciation"
}, },
"account_type": "Accumulated Depreciation" "account_type": "Accumulated Depreciation"
}, },
"Fixed Assets (Cost Price)": { "Fixed Assets (Cost Price)": {
"Computer Hardware & Software": { "Computer Hardware & Software": {
"account_type": "Fixed Asset" "account_type": "Fixed Asset"
}, },
"Furniture and Equipment": { "Furniture and Equipment": {
"account_type": "Fixed Asset" "account_type": "Fixed Asset"
}, },
"Leasehold Improvement": {}, "Leasehold Improvement": {},
"Motor Vehicles": { "Motor Vehicles": {
"account_type": "Fixed Asset" "account_type": "Fixed Asset"
}, },
"Work In Progress": {}, "Work In Progress": {},
"account_type": "Fixed Asset" "account_type": "Fixed Asset"
} }
}, },
"Intangible Assets": { "Intangible Assets": {
"Computer Card Renewal": {}, "Computer Card Renewal": {},
"Disposal of Outlets": {}, "Disposal of Outlets": {},
"Registration of Trademarks": {} "Registration of Trademarks": {}
}, },
"Intercompany Accounts": {}, "Intercompany Accounts": {},
"Investments": { "Investments": {
"Investments in Subsidiaries": {} "Investments in Subsidiaries": {}
} }
}, },
"root_type": "Asset" "root_type": "Asset"
}, },
"Closing And Temporary Accounts": { "Closing And Temporary Accounts": {
"Closing Accounts": { "Closing Accounts": {
"Closing Account": {} "Closing Account": {}
}, },
"root_type": "Liability" "root_type": "Liability"
}, },
"Expenses": { "Expenses": {
"Commercial Expenses": { "Commercial Expenses": {
"Consultancy Fees": {}, "Consultancy Fees": {},
"Provision for Doubtful Debts": {} "Provision for Doubtful Debts": {}
}, },
"Cost of Sale": { "Cost of Sale": {
"Cost Of Goods Sold": { "Cost Of Goods Sold": {
"Cost Of Goods Sold I/C Sales": {}, "Cost Of Goods Sold I/C Sales": {},
"Cost of Goods Sold in Trading": { "Cost of Goods Sold in Trading": {
"account_type": "Cost of Goods Sold" "account_type": "Cost of Goods Sold"
}, },
"account_type": "Cost of Goods Sold" "account_type": "Cost of Goods Sold"
}, },
"Expenses Included In Valuation": { "Expenses Included In Valuation": {
"account_type": "Expenses Included In Valuation" "account_type": "Expenses Included In Valuation"
},
"Stock Adjustment": {
"account_type": "Stock Adjustment"
} }
}, },
"Depreciation": { "Depreciation": {
"Depreciation & Amortization": { "Depreciation & Amortization": {
"Amortization on Leasehold Improvement": {}, "Amortization on Leasehold Improvement": {},
"Depreciation Of Computer Hard & Soft": { "Depreciation Of Computer Hard & Soft": {
"account_type": "Depreciation" "account_type": "Depreciation"
}, },
"Depreciation Of Furniture & Office Equipment\n\t\t\t": { "Depreciation Of Furniture & Office Equipment\n\t\t\t": {
"account_type": "Depreciation" "account_type": "Depreciation"
}, },
"Depreciation Of Motor Vehicles": { "Depreciation Of Motor Vehicles": {
"account_type": "Depreciation" "account_type": "Depreciation"
} }
} }
}, },
"Direct Expenses": { "Direct Expenses": {
"Financial Charges": { "Financial Charges": {
"Air Miles Card Charges": {}, "Air Miles Card Charges": {},
"Amex Credit Cards Charges": {}, "Amex Credit Cards Charges": {},
"Bank Finance & Loan Charges": {}, "Bank Finance & Loan Charges": {},
"Credit Card Charges": {}, "Credit Card Charges": {},
"Credit Card Swipe Charges": {}, "Credit Card Swipe Charges": {},
"PayPal Charges": {} "PayPal Charges": {}
} }
}, },
"MISC Charges": { "MISC Charges": {
"Other Charges": { "Other Charges": {
"Capital Loss": { "Capital Loss": {
"Disposal of Business Branch": {}, "Disposal of Business Branch": {},
"Loss On Fixed Assets Disposal": {}, "Loss On Fixed Assets Disposal": {},
"Loss on Difference on Exchange": {} "Loss on Difference on Exchange": {}
}, },
"Other Non Operating Exp": { "Other Non Operating Exp": {
"Other Non Operating Expenses": {} "Other Non Operating Expenses": {}
}, },
"Previous Year Adjustments": { "Previous Year Adjustments": {
"Previous Year Adjustments Account": {} "Previous Year Adjustments Account": {}
}, },
"Royalty Fees": { "Royalty Fees": {
"Royalty to Parent Co.": {} "Royalty to Parent Co.": {}
}, },
"Tax / Zakat Expenses": { "Tax / Zakat Expenses": {
"Income Tax": { "Income Tax": {
"account_type": "Tax" "account_type": "Tax"
}, },
"Zakat": {}, "Zakat": {},
"account_type": "Tax" "account_type": "Tax"
} }
} }
}, },
"Share Resources": { "Share Resources": {
"Share Resource Expenses Account": {} "Share Resource Expenses Account": {}
}, },
"Store Operating Expenses": { "Store Operating Expenses": {
"Selling, General & Admin Expenses": { "Selling, General & Admin Expenses": {
"Advertising Expenses": { "Advertising Expenses": {
"Other - Advertising Expenses": {} "Other - Advertising Expenses": {}
}, },
"Bank & Finance Charges": { "Bank & Finance Charges": {
"Other Bank Charges": {} "Other Bank Charges": {}
}, },
"Communications": { "Communications": {
"Courier": {}, "Courier": {},
"Others - Communication": {}, "Others - Communication": {},
"Telephone": {}, "Telephone": {},
"Web Site Hosting Fees": {} "Web Site Hosting Fees": {}
}, },
"Office & Various Expenses": { "Office & Various Expenses": {
"Cleaning": {}, "Cleaning": {},
"Conveyance Expenses": {}, "Conveyance Expenses": {},
"Gifts & Donations": {}, "Gifts & Donations": {},
"Insurance": {}, "Insurance": {},
"Kitchen and Buffet Expenses": {}, "Kitchen and Buffet Expenses": {},
"Maintenance": {}, "Maintenance": {},
"Others - Office Various Expenses": {}, "Others - Office Various Expenses": {},
"Security & Guard": {}, "Security & Guard": {},
"Stationary From Suppliers": {}, "Stationary From Suppliers": {},
"Stationary Out Of Stock": {}, "Stationary Out Of Stock": {},
"Subscriptions": {}, "Subscriptions": {},
"Training": {}, "Training": {},
"Vehicle Expenses": {} "Vehicle Expenses": {}
}, },
"Personnel Cost": { "Personnel Cost": {
"Basic Salary": {}, "Basic Salary": {},
"End Of Service Indemnity": {}, "End Of Service Indemnity": {},
"Housing Allowance": {}, "Housing Allowance": {},
"Leave Salary": {}, "Leave Salary": {},
"Leave Ticket": {}, "Leave Ticket": {},
"Life Insurance": {}, "Life Insurance": {},
"Medical Insurance": {}, "Medical Insurance": {},
"Personnel Cost Others": {}, "Personnel Cost Others": {},
"Sales Commission": {}, "Sales Commission": {},
"Staff School Allowances": {}, "Staff School Allowances": {},
"Transportation Allowance": {}, "Transportation Allowance": {},
"Uniform": {}, "Uniform": {},
"Visa Expenses": {} "Visa Expenses": {}
}, },
"Professional & Legal Fees": { "Professional & Legal Fees": {
"Audit Fees": {}, "Audit Fees": {},
"Legal fees": {}, "Legal fees": {},
"Others - Professional Fees": {}, "Others - Professional Fees": {},
"Sponsorship Fees": {}, "Sponsorship Fees": {},
"Trade License Fees": {} "Trade License Fees": {}
}, },
"Provision & Write Off": { "Provision & Write Off": {
"Amortisation of Preoperating Expenses": {}, "Amortisation of Preoperating Expenses": {},
"Cash Shortage": {}, "Cash Shortage": {},
"Others - Provision & Write off": {}, "Others - Provision & Write off": {},
"Write Off Inventory": {}, "Write Off Inventory": {},
"Write Off Receivables & Payables": {} "Write Off Receivables & Payables": {}
}, },
"Rent Expenses": { "Rent Expenses": {
"Office Rent": {}, "Office Rent": {},
"Warehouse Rent": {} "Warehouse Rent": {}
}, },
"Travel Expenses": { "Travel Expenses": {
"Air tickets": {}, "Air tickets": {},
"Hotel": {}, "Hotel": {},
"Meals": {}, "Meals": {},
"Others": {}, "Others": {},
"Per Diem": {} "Per Diem": {}
}, },
"Utilities": { "Utilities": {
"Other Utility Cahrges": {}, "Other Utility Cahrges": {},
"Water & Electricity": {} "Water & Electricity": {}
} }
} }
}, },
"root_type": "Expense" "root_type": "Expense"
}, },
"Liabilities": { "Liabilities": {
"Current Liabilities": { "Current Liabilities": {
"Accounts Payable": { "Accounts Payable": {
"Payables": { "Payables": {
"Advance Payable to Suppliers": { "Advance Payable to Suppliers": {
"account_type": "Payable" "account_type": "Payable"
}, },
"Consigned Payable": { "Consigned Payable": {
"account_type": "Payable" "account_type": "Payable"
}, },
"Other Payable": { "Other Payable": {
"account_type": "Payable" "account_type": "Payable"
}, },
"Post Dated Cheques Paid": { "Post Dated Cheques Paid": {
"account_type": "Payable" "account_type": "Payable"
}, },
"Staff Payable": {}, "Staff Payable": {},
"Suppliers Price Protection": { "Suppliers Price Protection": {
"account_type": "Payable" "account_type": "Payable"
}, },
"Trade Payable": { "Trade Payable": {
"account_type": "Payable" "account_type": "Payable"
}, },
"account_type": "Payable" "account_type": "Payable"
} }
}, },
"Accruals & Provisions": { "Accruals & Provisions": {
"Accruals": { "Accruals": {
"Accrued Personnel Cost": { "Accrued Personnel Cost": {
"Accrued - Commissions": {}, "Accrued - Commissions": {},
"Accrued - Leave Salary": {}, "Accrued - Leave Salary": {},
"Accrued - Leave Tickets": {}, "Accrued - Leave Tickets": {},
"Accrued - Salaries": {}, "Accrued - Salaries": {},
"Accrued Other Personnel Cost": {}, "Accrued Other Personnel Cost": {},
"Accrued Salaries Increment": {}, "Accrued Salaries Increment": {},
"Accrued-Staff Bonus": {} "Accrued-Staff Bonus": {}
} }
}, },
"Accrued Expenses": { "Accrued Expenses": {
"Accrued Other Expenses": { "Accrued Other Expenses": {
"Accrued - Audit Fees": {}, "Accrued - Audit Fees": {},
"Accrued - Office Rent": {}, "Accrued - Office Rent": {},
"Accrued - Sponsorship": {}, "Accrued - Sponsorship": {},
"Accrued - Telephone": {}, "Accrued - Telephone": {},
"Accrued - Utilities": {}, "Accrued - Utilities": {},
"Accrued Others": {} "Accrued Others": {}
} }
}, },
"Other Current Liabilities": { "Other Current Liabilities": {
"Accrued Dubai Customs": {}, "Accrued Dubai Customs": {},
"Deferred income": {}, "Deferred income": {},
"Shipping & Handling": {} "Shipping & Handling": {}
}, },
"Provisions": { "Provisions": {
"Tax Payables": { "Tax Payables": {
"Income Tax Payable": {}, "Income Tax Payable": {},
"Sales Tax Payable": {}, "Sales Tax Payable": {},
"Withholding Tax Payable": {} "Withholding Tax Payable": {}
} }
}, },
"Short Term Loan": {} "Short Term Loan": {}
}, },
"Duties and Taxes": { "Duties and Taxes": {
"account_type": "Tax", "account_type": "Tax",
"is_group": 1 "is_group": 1
}, },
"Reservations & Credit Notes": { "Reservations & Credit Notes": {
"Credit Notes": { "Credit Notes": {
"Credit Notes to Customers": {}, "Credit Notes to Customers": {},
"Reservations": {} "Reservations": {}
} }
}, },
"Stock Liabilities": { "Stock Liabilities": {
"Stock Received But Not Billed": { "Stock Received But Not Billed": {
"account_type": "Stock Received But Not Billed" "account_type": "Stock Received But Not Billed"
} }
}, },
"Unearned Income": {} "Unearned Income": {}
}, },
"Long Term Liabilities": { "Long Term Liabilities": {
"Long Term Loans & Provisions": {} "Long Term Loans & Provisions": {}
}, },
"root_type": "Liability" "root_type": "Liability"
}, },
"Revenue": { "Revenue": {
"Direct Revenue": { "Direct Revenue": {
"Other Direct Revenue": { "Other Direct Revenue": {
"Other Revenue - Operating": { "Other Revenue - Operating": {
"Advertising Income": {}, "Advertising Income": {},
"Branding Income": {}, "Branding Income": {},
"Early Setmt Margin from Suppliers": {}, "Early Setmt Margin from Suppliers": {},
"Marketing Rebate from Suppliers": {}, "Marketing Rebate from Suppliers": {},
"Rebate from Suppliers": {}, "Rebate from Suppliers": {},
"Service Income": {}, "Service Income": {},
"Space Rental Income": {} "Space Rental Income": {}
} }
} }
}, },
"Indirect Revenue": { "Indirect Revenue": {
"Other Indirect Revenue": { "Other Indirect Revenue": {
"Capital Gain": {}, "Capital Gain": {},
"Excess In Till": {}, "Excess In Till": {},
"Gain On Difference Of Exchange": {}, "Gain On Difference Of Exchange": {},
"Management Consultancy Fees": {}, "Management Consultancy Fees": {},
"Other Income": {} "Other Income": {}
}, },
"Other Revenue - Non Operating": { "Other Revenue - Non Operating": {
"Interest Revenue": {}, "Interest Revenue": {},
"Interest from FD": {}, "Interest from FD": {},
"Products Listing Fees from Suppliers": {}, "Products Listing Fees from Suppliers": {},
"Trade Opening Fees from suppliers": {} "Trade Opening Fees from suppliers": {}
} }
}, },
"Sales": { "Sales": {
"Sales from Other Regions": { "Sales from Other Regions": {
"Sales from Other Region": {} "Sales from Other Region": {}
}, },
"Sales of same region": { "Sales of same region": {
"Management Consultancy Fees 1": {}, "Management Consultancy Fees 1": {},
"Sales Account": {}, "Sales Account": {},
"Sales of I/C": {} "Sales of I/C": {}
} }
}, },
"root_type": "Income" "root_type": "Income"
}, },
"Share Holder Equity": { "Share Holder Equity": {
"Capital": { "Capital": {
"Contributed Capital": {}, "Contributed Capital": {},
"Share Capital": {}, "Share Capital": {},
"Shareholders Current A/c": {}, "Shareholders Current A/c": {},
"Sub Ordinated Loan": {}, "Sub Ordinated Loan": {},
"Treasury Stocks": {} "Treasury Stocks": {}
}, },
"Retained Earnings": { "Retained Earnings": {
"Current Year Results": {}, "Current Year Results": {},
"Dividends Paid": {}, "Dividends Paid": {},
"Previous Years Results": {} "Previous Years Results": {}
}, },
"account_type": "Equity", "account_type": "Equity",
"root_type": "Equity" "root_type": "Equity"
} }
} }

View File

@ -185,7 +185,8 @@ def validate_account_types(accounts):
return _("Please identify/create Account (Ledger) for type - {0}").format(' , '.join(missing)) return _("Please identify/create Account (Ledger) for type - {0}").format(' , '.join(missing))
account_types_for_group = ["Bank", "Cash", "Stock"] 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)) missing = list(set(account_types_for_group) - set(account_groups))
if missing: if missing:

View File

@ -18,6 +18,7 @@ class CostCenter(NestedSet):
def validate(self): def validate(self):
self.validate_mandatory() self.validate_mandatory()
self.validate_parent_cost_center()
def validate_mandatory(self): def validate_mandatory(self):
if self.cost_center_name != self.company and not self.parent_cost_center: 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: elif self.cost_center_name == self.company and self.parent_cost_center:
frappe.throw(_("Root cannot have a 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): def convert_group_to_ledger(self):
if self.check_if_child_exists(): if self.check_if_child_exists():
frappe.throw(_("Cannot convert Cost Center to ledger as it has child nodes")) frappe.throw(_("Cannot convert Cost Center to ledger as it has child nodes"))

View File

@ -1,12 +1,26 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt # License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals from __future__ import unicode_literals
import unittest
import frappe import frappe
test_records = frappe.get_test_records('Cost Center') 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): def create_cost_center(**args):
args = frappe._dict(args) args = frappe._dict(args)

View File

@ -330,23 +330,6 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
frm: cur_frm 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); cur_frm.script_manager.make(erpnext.accounts.PurchaseInvoice);

View File

@ -789,22 +789,21 @@ frappe.ui.form.on('Sales Invoice', {
method: "frappe.client.get_value", method: "frappe.client.get_value",
args:{ args:{
doctype: "Patient", doctype: "Patient",
filters: {"name": frm.doc.patient}, filters: {
"name": frm.doc.patient
},
fieldname: "customer" fieldname: "customer"
}, },
callback:function(patient_customer) { callback:function(r) {
if(patient_customer){ if(r && r.message.customer){
frm.set_value("customer", patient_customer.message.customer); frm.set_value("customer", r.message.customer);
frm.refresh_fields();
} }
} }
}); });
} }
else{
frm.set_value("customer", '');
}
} }
}, },
refresh: function(frm) { refresh: function(frm) {
if (frappe.boot.active_domains.includes("Healthcare")){ if (frappe.boot.active_domains.includes("Healthcare")){
frm.set_df_property("patient", "hidden", 0); frm.set_df_property("patient", "hidden", 0);

View File

@ -1048,13 +1048,18 @@ class SalesInvoice(SellingController):
continue continue
for serial_no in item.serial_no.split("\n"): for serial_no in item.serial_no.split("\n"):
sales_invoice, item_code = frappe.db.get_value("Serial No", serial_no, serial_no_details = frappe.db.get_value("Serial No", serial_no,
["sales_invoice", "item_code"]) ["sales_invoice", "item_code"], as_dict=1)
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") 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: if sales_invoice_company == self.company:
frappe.throw(_("Serial Number: {0} is already referenced in Sales Invoice: {1}" 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): def update_project(self):
if self.project: if self.project:

View File

@ -70,7 +70,7 @@ class ShippingRule(Document):
def get_shipping_amount_from_rules(self, value): def get_shipping_amount_from_rules(self, value):
for condition in self.get("conditions"): 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 condition.shipping_amount
return 0.0 return 0.0

View File

@ -162,33 +162,34 @@ def validate_account_for_perpetual_inventory(gl_map):
frappe.throw(_("Account: {0} can only be updated via Stock Transactions") frappe.throw(_("Account: {0} can only be updated via Stock Transactions")
.format(account), StockAccountInvalidTransaction) .format(account), StockAccountInvalidTransaction)
elif account_bal != stock_bal: # This has been comment for a temporary, will add this code again on release of immutable ledger
precision = get_field_precision(frappe.get_meta("GL Entry").get_field("debit"), # elif account_bal != stock_bal:
currency=frappe.get_cached_value('Company', gl_map[0].company, "default_currency")) # 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) # 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( # 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)) # stock_bal, account_bal, frappe.bold(account))
error_resolution = _("Please create adjustment Journal Entry for amount {0} ").format(frappe.bold(diff)) # 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") # 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_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_stock_adjustment_account = ('debit_in_account_currency' if diff < 0 else 'credit_in_account_currency')
journal_entry_args = { # journal_entry_args = {
'accounts':[ # 'accounts':[
{'account': account, db_or_cr_warehouse_account : abs(diff)}, # {'account': account, db_or_cr_warehouse_account : abs(diff)},
{'account': stock_adjustment_account, db_or_cr_stock_adjustment_account : abs(diff) }] # {'account': stock_adjustment_account, db_or_cr_stock_adjustment_account : abs(diff) }]
} # }
frappe.msgprint(msg="""{0}<br></br>{1}<br></br>""".format(error_reason, error_resolution), # frappe.msgprint(msg="""{0}<br></br>{1}<br></br>""".format(error_reason, error_resolution),
raise_exception=StockValueAndAccountBalanceOutOfSync, # raise_exception=StockValueAndAccountBalanceOutOfSync,
title=_('Values Out Of Sync'), # title=_('Values Out Of Sync'),
primary_action={ # primary_action={
'label': _('Make Journal Entry'), # 'label': _('Make Journal Entry'),
'client_action': 'erpnext.route_to_adjustment_jv', # 'client_action': 'erpnext.route_to_adjustment_jv',
'args': journal_entry_args # 'args': journal_entry_args
}) # })
def validate_cwip_accounts(gl_map): 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")]) cwip_enabled = any([cint(ac.enable_cwip_accounting) for ac in frappe.db.get_all("Asset Category","enable_cwip_accounting")])

View File

@ -100,6 +100,11 @@ frappe.query_reports["Accounts Payable"] = {
"fieldtype": "Link", "fieldtype": "Link",
"options": "Supplier Group" "options": "Supplier Group"
}, },
{
"fieldname":"based_on_payment_terms",
"label": __("Based On Payment Terms"),
"fieldtype": "Check",
},
{ {
"fieldname":"tax_id", "fieldname":"tax_id",
"label": __("Tax Id"), "label": __("Tax Id"),

View File

@ -318,7 +318,7 @@ class ReceivablePayableReport(object):
self.append_payment_term(row, d, term) self.append_payment_term(row, d, term)
def append_payment_term(self, 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 invoiced = d.payment_amount
else: else:
invoiced = flt(flt(d.payment_amount) * flt(d.conversion_rate), self.currency_precision) invoiced = flt(flt(d.payment_amount) * flt(d.conversion_rate), self.currency_precision)

View File

@ -569,7 +569,7 @@ def get_stock_and_account_balance(account=None, posting_date=None, company=None)
warehouse_account = get_warehouse_account_map(company) 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() related_warehouses = [wh for wh, wh_details in warehouse_account.items()
if wh_details.account == account and not wh_details.is_group] if wh_details.account == account and not wh_details.is_group]

View File

@ -29,7 +29,8 @@ def get_asset_category_account(fieldname, item=None, asset=None, account=None, a
account=None account=None
if not account: 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", account = frappe.db.get_value("Asset Category Account",
filters={"parent": asset_category, "company_name": company}, fieldname=fieldname) filters={"parent": asset_category, "company_name": company}, fieldname=fieldname)

View File

@ -18,6 +18,7 @@ frappe.ui.form.on("Purchase Order", {
return { return {
filters: { filters: {
"company": frm.doc.company, "company": frm.doc.company,
"name": ['!=', frm.doc.supplier_warehouse],
"is_group": 0 "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() me.dialog.show()
this.dialog.set_primary_action(__('Transfer'), function() { this.dialog.set_primary_action(__('Transfer'), function() {
me.values = me.dialog.get_values(); me.values = me.dialog.get_values();

View File

@ -519,47 +519,62 @@ class TestPurchaseOrder(unittest.TestCase):
def test_backflush_based_on_stock_entry(self): def test_backflush_based_on_stock_entry(self):
item_code = "_Test Subcontracted FG Item 1" item_code = "_Test Subcontracted FG Item 1"
make_subcontracted_item(item_code) 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") 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") 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", make_stock_entry(target="_Test Warehouse - _TC",
item_code="_Test Item Home Desktop 100", qty=10, basic_rate=100) item_code="_Test Item Home Desktop 100", qty=10, basic_rate=100)
make_stock_entry(target="_Test Warehouse - _TC", make_stock_entry(target="_Test Warehouse - _TC",
item_code = "Test Extra Item 1", qty=100, basic_rate=100) item_code = "Test Extra Item 1", qty=100, basic_rate=100)
make_stock_entry(target="_Test Warehouse - _TC", make_stock_entry(target="_Test Warehouse - _TC",
item_code = "Test Extra Item 2", qty=10, basic_rate=100) 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 = [ rm_items = [
{"item_code":item_code,"rm_item_code":"_Test Item","item_name":"_Test Item", {"item_code":item_code,"rm_item_code":"Sub Contracted Raw Material 1","item_name":"_Test Item",
"qty":1,"warehouse":"_Test Warehouse - _TC","rate":100,"amount":100,"stock_uom":"Nos"}, "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", {"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", {"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 = 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() se.submit()
pr = make_purchase_receipt(po.name) pr = make_purchase_receipt(po.name)
received_qty = 2
# partial receipt
pr.get('items')[0].qty = received_qty
pr.save() pr.save()
pr.submit() pr.submit()
se_items = sorted([d.item_code for d in se.get('items')]) transferred_items = sorted([d.item_code for d in se.get('items') if se.purchase_order == po.name])
supplied_items = sorted([d.rm_item_code for d in pr.get('supplied_items')]) 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") update_backflush_based_on("BOM")
def test_advance_payment_entry_unlink_against_purchase_order(self): def test_advance_payment_entry_unlink_against_purchase_order(self):

View File

@ -56,3 +56,23 @@ class Supplier(TransactionBase):
def after_rename(self, olddn, newdn, merge=False): def after_rename(self, olddn, newdn, merge=False):
if frappe.defaults.get_global_default('supp_master_name') == 'Supplier Name': if frappe.defaults.get_global_default('supp_master_name') == 'Supplier Name':
frappe.db.set(self, "supplier_name", newdn) 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

View File

@ -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": ""
}

View File

@ -197,6 +197,11 @@ def get_data():
"name": "Bank Reconciliation Statement", "name": "Bank Reconciliation Statement",
"is_query_report": True, "is_query_report": True,
"doctype": "Journal Entry" "doctype": "Journal Entry"
},{
"type": "page",
"name": "bank-reconciliation",
"label": _("Bank Reconciliation"),
"icon": "fa fa-bar-chart"
}, },
{ {
"type": "report", "type": "report",

View File

@ -241,6 +241,10 @@ def get_data():
"type": "doctype", "type": "doctype",
"name": "Quality Inspection Template", "name": "Quality Inspection Template",
}, },
{
"type": "doctype",
"name": "Quick Stock Balance",
},
] ]
}, },
{ {

View File

@ -221,7 +221,7 @@ class BuyingController(StockController):
"backflush_raw_materials_of_subcontract_based_on") "backflush_raw_materials_of_subcontract_based_on")
if (self.doctype == 'Purchase Receipt' and if (self.doctype == 'Purchase Receipt' and
backflush_raw_materials_based_on != 'BOM'): 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: else:
for item in self.get("items"): for item in self.get("items"):
if self.doctype in ["Purchase Receipt", "Purchase Invoice"]: 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"): if self.is_subcontracted == "No" and self.get("supplied_items"):
self.set('supplied_items', []) self.set('supplied_items', [])
def update_raw_materials_supplied_based_on_stock_entries(self, raw_material_table): def update_raw_materials_supplied_based_on_stock_entries(self):
self.set(raw_material_table, []) self.set('supplied_items', [])
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)
for d in items: purchase_orders = set([d.purchase_order for d in self.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
# get raw materials rate # qty of raw materials backflushed (for each item per purchase order)
from erpnext.stock.utils import get_incoming_rate backflushed_raw_materials_map = get_backflushed_subcontracted_raw_materials(purchase_orders)
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)
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): def update_raw_materials_supplied_based_on_bom(self, item, raw_material_table):
exploded_item = 1 exploded_item = 1
@ -387,9 +441,11 @@ class BuyingController(StockController):
item_codes = list(set(item.item_code for item in item_codes = list(set(item.item_code for item in
self.get("items"))) self.get("items")))
if item_codes: if item_codes:
self._sub_contracted_items = [r[0] for r in frappe.db.sql("""select name items = frappe.get_all('Item', filters={
from `tabItem` where name in (%s) and is_sub_contracted_item=1""" % \ 'name': ['in', item_codes],
(", ".join((["%s"]*len(item_codes))),), item_codes)] 'is_sub_contracted_item': 1
})
self._sub_contracted_items = [item.name for item in items]
return self._sub_contracted_items return self._sub_contracted_items
@ -722,28 +778,72 @@ def get_items_from_bom(item_code, bom, exploded_item=1):
return bom_items return bom_items
def get_subcontracted_raw_materials_from_se(purchase_orders): def get_subcontracted_raw_materials_from_se(purchase_order, fg_item):
return frappe.db.sql(""" common_query = """
select SELECT
sed.item_name, sed.item_code, sum(sed.qty) as qty, sed.description, sed.item_code AS rm_item_code,
sed.stock_uom, sed.subcontracted_item as main_item_code, sed.serial_no, sed.batch_no SUM(sed.qty) AS qty,
from `tabStock Entry` se,`tabStock Entry Detail` sed sed.description,
where sed.stock_uom,
se.name = sed.parent and se.docstatus=1 and se.purpose='Send to Subcontractor' sed.subcontracted_item AS main_item_code,
and se.purchase_order in (%s) and ifnull(sed.t_warehouse, '') != '' {serial_no_concat_syntax} AS serial_nos,
group by sed.item_code, sed.t_warehouse {batch_no_concat_syntax} AS batch_nos
""" % (','.join(['%s'] * len(purchase_orders))), tuple(purchase_orders), as_dict=1) 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 raw_materials
return frappe._dict(frappe.db.sql("""
select def get_backflushed_subcontracted_raw_materials(purchase_orders):
prsi.rm_item_code as item_code, sum(prsi.consumed_qty) as qty common_query = """
from `tabPurchase Receipt` pr, `tabPurchase Receipt Item` pri, `tabPurchase Receipt Item Supplied` prsi SELECT
where CONCAT(prsi.rm_item_code, pri.purchase_order) AS item_key,
pr.name = pri.parent and pr.name = prsi.parent and pri.purchase_order in (%s) SUM(prsi.consumed_qty) AS qty,
and pri.item_code = prsi.main_item_code and pr.name != '%s' and pr.docstatus = 1 {serial_no_concat_syntax} AS serial_nos,
group by prsi.rm_item_code {batch_no_concat_syntax} AS batch_nos
""" % (','.join(['%s'] * len(purchase_orders)), purchase_receipt), tuple(purchase_orders))) 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): def get_asset_item_details(asset_items):
asset_items_data = {} 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)) 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) 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

View File

@ -71,7 +71,7 @@ class ProgramEnrollment(Document):
def create_course_enrollments(self): def create_course_enrollments(self):
student = frappe.get_doc("Student", self.student) student = frappe.get_doc("Student", self.student)
program = frappe.get_doc("Program", self.program) 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: for course_name in course_list:
student.enroll_in_course(course_name=course_name, program_enrollment=self.name) student.enroll_in_course(course_name=course_name, program_enrollment=self.name)

View File

@ -63,10 +63,11 @@ def updating_rate(self):
item_code=%s""",(self.template, self.rate, self.item)) item_code=%s""",(self.template, self.rate, self.item))
def create_item_from_template(doc): def create_item_from_template(doc):
disabled = 1
if(doc.is_billable == 1): if(doc.is_billable == 1):
disabled = 0 disabled = 0
else:
disabled = 1
#insert item #insert item
item = frappe.get_doc({ item = frappe.get_doc({
"doctype": "Item", "doctype": "Item",

View File

@ -5,7 +5,7 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import frappe import frappe
from frappe import _ 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.model.document import Document
from frappe.desk.reportview import get_match_cond 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) frappe.db.set_value("Patient", self.patient, "inpatient_record", self.name)
def validate(self): def validate(self):
self.validate_dates()
self.validate_already_scheduled_or_admitted() self.validate_already_scheduled_or_admitted()
if self.status == "Discharged": if self.status == "Discharged":
frappe.db.set_value("Patient", self.patient, "inpatient_status", None) frappe.db.set_value("Patient", self.patient, "inpatient_status", None)
frappe.db.set_value("Patient", self.patient, "inpatient_record", 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): def validate_already_scheduled_or_admitted(self):
query = """ query = """
select name, status select name, status

View File

@ -40,8 +40,6 @@ after_install = "erpnext.setup.install.after_install"
boot_session = "erpnext.startup.boot.boot_session" boot_session = "erpnext.startup.boot.boot_session"
notification_config = "erpnext.startup.notifications.get_notification_config" notification_config = "erpnext.startup.notifications.get_notification_config"
get_help_messages = "erpnext.utilities.activation.get_help_messages" 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" leaderboards = "erpnext.startup.leaderboard.get_leaderboards"
@ -302,7 +300,7 @@ scheduler_events = {
"erpnext.support.doctype.service_level_agreement.service_level_agreement.check_agreement_status", "erpnext.support.doctype.service_level_agreement.service_level_agreement.check_agreement_status",
"erpnext.crm.doctype.email_campaign.email_campaign.send_email_to_leads_or_contacts", "erpnext.crm.doctype.email_campaign.email_campaign.send_email_to_leads_or_contacts",
"erpnext.crm.doctype.email_campaign.email_campaign.set_email_campaign_status", "erpnext.crm.doctype.email_campaign.email_campaign.set_email_campaign_status",
"erpnext.selling.doctype.quotation.set_expired_status" "erpnext.selling.doctype.quotation.quotation.set_expired_status"
], ],
"daily_long": [ "daily_long": [
"erpnext.setup.doctype.email_digest.email_digest.send", "erpnext.setup.doctype.email_digest.email_digest.send",

View File

@ -1,231 +1,82 @@
{ {
"allow_copy": 0, "creation": "2016-12-20 15:32:25.078334",
"allow_guest_to_view": 0, "doctype": "DocType",
"allow_import": 0, "editable_grid": 1,
"allow_rename": 0, "engine": "InnoDB",
"beta": 0, "field_order": [
"creation": "2016-12-20 15:32:25.078334", "payment_date",
"custom": 0, "principal_amount",
"docstatus": 0, "interest_amount",
"doctype": "DocType", "total_payment",
"document_type": "", "balance_loan_amount",
"editable_grid": 1, "paid"
"engine": "InnoDB", ],
"fields": [ "fields": [
{ {
"allow_bulk_edit": 0, "allow_on_submit": 1,
"allow_on_submit": 0, "columns": 2,
"bold": 0, "fieldname": "payment_date",
"collapsible": 0, "fieldtype": "Date",
"columns": 2, "in_list_view": 1,
"fieldname": "payment_date", "label": "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_bulk_edit": 0, "columns": 2,
"allow_on_submit": 0, "fieldname": "principal_amount",
"bold": 0, "fieldtype": "Currency",
"collapsible": 0, "in_list_view": 1,
"columns": 2, "label": "Principal Amount",
"fieldname": "principal_amount", "no_copy": 1,
"fieldtype": "Currency", "options": "Company:company:default_currency",
"hidden": 0, "read_only": 1
"ignore_user_permissions": 0, },
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "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
},
{ {
"allow_bulk_edit": 0, "columns": 2,
"allow_on_submit": 0, "fieldname": "interest_amount",
"bold": 0, "fieldtype": "Currency",
"collapsible": 0, "in_list_view": 1,
"columns": 2, "label": "Interest Amount",
"fieldname": "interest_amount", "no_copy": 1,
"fieldtype": "Currency", "options": "Company:company:default_currency",
"hidden": 0, "read_only": 1
"ignore_user_permissions": 0, },
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "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
},
{ {
"allow_bulk_edit": 0, "columns": 2,
"allow_on_submit": 0, "fieldname": "total_payment",
"bold": 0, "fieldtype": "Currency",
"collapsible": 0, "in_list_view": 1,
"columns": 2, "label": "Total Payment",
"fieldname": "total_payment", "options": "Company:company:default_currency",
"fieldtype": "Currency", "read_only": 1
"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
},
{ {
"allow_bulk_edit": 0, "columns": 2,
"allow_on_submit": 0, "fieldname": "balance_loan_amount",
"bold": 0, "fieldtype": "Currency",
"collapsible": 0, "in_list_view": 1,
"columns": 2, "label": "Balance Loan Amount",
"fieldname": "balance_loan_amount", "no_copy": 1,
"fieldtype": "Currency", "options": "Company:company:default_currency",
"hidden": 0, "read_only": 1
"ignore_user_permissions": 0, },
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "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
},
{ {
"allow_bulk_edit": 0, "default": "0",
"allow_on_submit": 0, "fieldname": "paid",
"bold": 0, "fieldtype": "Check",
"collapsible": 0, "in_list_view": 1,
"columns": 0, "label": "Paid",
"fieldname": "paid", "read_only": 1
"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
} }
], ],
"has_web_view": 0, "istable": 1,
"hide_heading": 0, "modified": "2019-10-29 11:45:10.694557",
"hide_toolbar": 0, "modified_by": "Administrator",
"idx": 0, "module": "HR",
"image_view": 0, "name": "Repayment Schedule",
"in_create": 0, "owner": "Administrator",
"is_submittable": 0, "permissions": [],
"issingle": 0, "quick_entry": 1,
"istable": 1, "sort_field": "modified",
"max_attachments": 0, "sort_order": "DESC",
"modified": "2018-03-30 17:37:31.834792", "track_changes": 1
"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
} }

View File

@ -9,6 +9,7 @@ from frappe import _
from six import string_types from six import string_types
from erpnext.manufacturing.doctype.bom.bom import get_boms_in_bottom_up_order from erpnext.manufacturing.doctype.bom.bom import get_boms_in_bottom_up_order
from frappe.model.document import Document from frappe.model.document import Document
import click
class BOMUpdateTool(Document): class BOMUpdateTool(Document):
def replace_bom(self): def replace_bom(self):
@ -17,7 +18,8 @@ class BOMUpdateTool(Document):
frappe.cache().delete_key('bom_children') frappe.cache().delete_key('bom_children')
bom_list = self.get_parent_boms(self.new_bom) bom_list = self.get_parent_boms(self.new_bom)
updated_bom = [] updated_bom = []
with click.progressbar(bom_list) as bom_list:
pass
for bom in bom_list: for bom in bom_list:
try: try:
bom_obj = frappe.get_cached_doc('BOM', bom) bom_obj = frappe.get_cached_doc('BOM', bom)

View File

@ -14,7 +14,7 @@ def execute(filters=None):
def get_data(filters, data): def get_data(filters, data):
get_exploded_items(filters.bom, 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", exploded_items = frappe.get_all("BOM Item",
filters={"parent": bom}, filters={"parent": bom},
fields= ['qty','bom_no','qty','scrap','item_code','item_name','description','uom']) 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, 'item_name': item.item_name,
'indent': indent, 'indent': indent,
'bom': item.bom_no, 'bom': item.bom_no,
'qty': item.qty, 'qty': item.qty * qty,
'uom': item.uom, 'uom': item.uom,
'description': item.description, 'description': item.description,
'scrap': item.scrap 'scrap': item.scrap
}) })
if item.bom_no: 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(): def get_columns():
return [ return [

View File

@ -5,6 +5,9 @@ from frappe import _
def execute(): def execute():
"""Add setup progress actions""" """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")
frappe.reload_doc("setup", "doctype", "setup_progress_action") frappe.reload_doc("setup", "doctype", "setup_progress_action")

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

View File

@ -426,7 +426,7 @@ body[data-route="pos"] {
.collapse-btn { .collapse-btn {
cursor: pointer; cursor: pointer;
} }
@media (max-width: @screen-xs) { @media (max-width: @screen-xs) {
.page-actions { .page-actions {
max-width: 110px; max-width: 110px;

View File

@ -3,6 +3,26 @@
frappe.ui.form.on('GST HSN Code', { frappe.ui.form.on('GST HSN Code', {
refresh: function(frm) { refresh: function(frm) {
if(! frm.doc.__islocal && frm.doc.taxes.length){
frm.add_custom_button(__('Update Taxes for Items'), function(){
frappe.confirm(
'Are you sure? It will overwrite taxes for all items with HSN Code <b>'+frm.doc.name+'</b>.',
function(){
frappe.call({
args:{
taxes: frm.doc.taxes,
hsn_code: frm.doc.name
},
method: 'erpnext.regional.doctype.gst_hsn_code.gst_hsn_code.update_taxes_in_item_master',
callback: function(r) {
if(r.message){
frappe.show_alert(__('Item taxes updated'));
}
}
});
}
);
});
}
} }
}); });

View File

@ -1,104 +1,46 @@
{ {
"allow_copy": 0, "autoname": "field:hsn_code",
"allow_guest_to_view": 0, "creation": "2017-06-21 10:48:56.422086",
"allow_import": 0, "doctype": "DocType",
"allow_rename": 0, "editable_grid": 1,
"autoname": "field:hsn_code", "engine": "InnoDB",
"beta": 0, "field_order": [
"creation": "2017-06-21 10:48:56.422086", "hsn_code",
"custom": 0, "description",
"docstatus": 0, "taxes"
"doctype": "DocType", ],
"document_type": "",
"editable_grid": 1,
"engine": "InnoDB",
"fields": [ "fields": [
{ {
"allow_bulk_edit": 0, "fieldname": "hsn_code",
"allow_on_submit": 0, "fieldtype": "Data",
"bold": 0, "in_list_view": 1,
"collapsible": 0, "label": "HSN Code",
"columns": 0, "reqd": 1,
"fieldname": "hsn_code", "unique": 1
"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
},
{ {
"allow_bulk_edit": 0, "fieldname": "description",
"allow_on_submit": 0, "fieldtype": "Small Text",
"bold": 0, "in_list_view": 1,
"collapsible": 0, "label": "Description"
"columns": 0, },
"fieldname": "description", {
"fieldtype": "Small Text", "fieldname": "taxes",
"hidden": 0, "fieldtype": "Table",
"ignore_user_permissions": 0, "label": "Taxes",
"ignore_xss_filter": 0, "options": "Item Tax"
"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
} }
], ],
"has_web_view": 0, "modified": "2019-11-01 11:18:59.556931",
"hide_heading": 0, "modified_by": "Administrator",
"hide_toolbar": 0, "module": "Regional",
"idx": 0, "name": "GST HSN Code",
"image_view": 0, "owner": "Administrator",
"in_create": 0, "permissions": [],
"is_submittable": 0, "quick_entry": 1,
"issingle": 0, "search_fields": "hsn_code, description",
"istable": 0, "sort_field": "modified",
"max_attachments": 0, "sort_order": "DESC",
"modified": "2017-09-29 14:38:52.220743", "title_field": "hsn_code",
"modified_by": "Administrator", "track_changes": 1
"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
} }

View File

@ -8,3 +8,22 @@ from frappe.model.document import Document
class GSTHSNCode(Document): class GSTHSNCode(Document):
pass 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()

View File

@ -10,17 +10,26 @@ Provide a report and downloadable CSV according to the German DATEV format.
from __future__ import unicode_literals from __future__ import unicode_literals
import datetime import datetime
import json import json
import zlib
import zipfile
import six
from six import BytesIO
from six import string_types from six import string_types
import frappe import frappe
from frappe import _ from frappe import _
import pandas as pd 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): def execute(filters=None):
"""Entry point for frappe.""" """Entry point for frappe."""
validate(filters) validate(filters)
result = get_gl_entries(filters, as_dict=0) result = get_transactions(filters, as_dict=0)
columns = get_columns() columns = QUERY_REPORT_COLUMNS
return columns, result return columns, result
@ -41,65 +50,8 @@ def validate(filters):
except frappe.DoesNotExistError: except frappe.DoesNotExistError:
frappe.throw(_('Please create <b>DATEV Settings</b> for Company <b>{}</b>.').format(filters.get('company'))) frappe.throw(_('Please create <b>DATEV Settings</b> for Company <b>{}</b>.').format(filters.get('company')))
def get_columns():
"""Return the list of columns that will be shown in query report."""
columns = [
{
"label": "Umsatz (ohne Soll/Haben-Kz)",
"fieldname": "Umsatz (ohne Soll/Haben-Kz)",
"fieldtype": "Currency",
},
{
"label": "Soll/Haben-Kennzeichen",
"fieldname": "Soll/Haben-Kennzeichen",
"fieldtype": "Data",
},
{
"label": "Kontonummer",
"fieldname": "Kontonummer",
"fieldtype": "Data",
},
{
"label": "Gegenkonto (ohne BU-Schlüssel)",
"fieldname": "Gegenkonto (ohne BU-Schlüssel)",
"fieldtype": "Data",
},
{
"label": "Belegdatum",
"fieldname": "Belegdatum",
"fieldtype": "Date",
},
{
"label": "Buchungstext",
"fieldname": "Buchungstext",
"fieldtype": "Text",
},
{
"label": "Beleginfo - Art 1",
"fieldname": "Beleginfo - Art 1",
"fieldtype": "Data",
},
{
"label": "Beleginfo - Inhalt 1",
"fieldname": "Beleginfo - Inhalt 1",
"fieldtype": "Data",
},
{
"label": "Beleginfo - Art 2",
"fieldname": "Beleginfo - Art 2",
"fieldtype": "Data",
},
{
"label": "Beleginfo - Inhalt 2",
"fieldname": "Beleginfo - Inhalt 2",
"fieldtype": "Data",
}
]
return columns def get_transactions(filters, as_dict=1):
def get_gl_entries(filters, as_dict):
""" """
Get a list of accounting entries. 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] as_dict -- return as list of dicts [0,1]
""" """
gl_entries = frappe.db.sql(""" gl_entries = frappe.db.sql("""
select SELECT
/* either debit or credit amount; always positive */ /* 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)', 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_type as 'Beleginfo - Art 2',
gl.against_voucher as 'Beleginfo - Inhalt 2' gl.against_voucher as 'Beleginfo - Inhalt 2'
from `tabGL Entry` gl FROM `tabGL Entry` gl
/* Statistisches Konto (Debitoren/Kreditoren) */ /* Statistisches Konto (Debitoren/Kreditoren) */
left join `tabParty Account` pa left join `tabParty Account` pa
@ -155,15 +107,127 @@ def get_gl_entries(filters, as_dict):
left join `tabAccount` acc_against_pa left join `tabAccount` acc_against_pa
on pa.account = acc_against_pa.name on pa.account = acc_against_pa.name
where gl.company = %(company)s WHERE gl.company = %(company)s
and DATE(gl.posting_date) >= %(from_date)s AND DATE(gl.posting_date) >= %(from_date)s
and DATE(gl.posting_date) <= %(to_date)s AND DATE(gl.posting_date) <= %(to_date)s
order by 'Belegdatum', gl.voucher_no""", filters, as_dict=as_dict) ORDER BY 'Belegdatum', gl.voucher_no""", filters, as_dict=as_dict, as_utf8=1)
return gl_entries 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. Fill in missing columns and return a CSV in DATEV Format.
@ -174,7 +238,46 @@ def get_datev_csv(data, filters):
Arguments: Arguments:
data -- array of dictionaries data -- array of dictionaries
filters -- dict 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 = [ header = [
# A = DATEV format # A = DATEV format
# DTVF = created by DATEV software, # DTVF = created by DATEV software,
@ -185,18 +288,8 @@ def get_datev_csv(data, filters):
# 510 = 5.10, # 510 = 5.10,
# 720 = 7.20 # 720 = 7.20
"510", "510",
# C = Data category csv_class.DATA_CATEGORY,
# 21 = Transaction batch (Buchungsstapel), csv_class.FORMAT_NAME,
# 67 = Buchungstextkonstanten,
# 16 = Debitors/Creditors,
# 20 = Account names (Kontenbeschriftungen)
"21",
# D = Format name
# Buchungsstapel,
# Buchungstextkonstanten,
# Debitoren/Kreditoren,
# Kontenbeschriftungen
"Buchungsstapel",
# E = Format version (regarding format name) # E = Format version (regarding format name)
"", "",
# F = Generated on # F = Generated on
@ -224,16 +317,17 @@ def get_datev_csv(data, filters):
# P = Transaction batch end date (YYYYMMDD) # P = Transaction batch end date (YYYYMMDD)
frappe.utils.formatdate(filters.get('to_date'), "yyyyMMdd"), frappe.utils.formatdate(filters.get('to_date'), "yyyyMMdd"),
# Q = Description (for example, "January - February 2019 Transactions") # Q = Description (for example, "January - February 2019 Transactions")
"{} - {} Buchungsstapel".format( "{} - {} {}".format(
frappe.utils.formatdate(filters.get('from_date'), "MMMM yyyy"), frappe.utils.formatdate(filters.get('from_date'), "MMMM yyyy"),
frappe.utils.formatdate(filters.get('to_date'), "MMMM yyyy") frappe.utils.formatdate(filters.get('to_date'), "MMMM yyyy"),
csv_class.FORMAT_NAME
), ),
# R = Diktatkürzel # R = Diktatkürzel
"", "",
# S = Buchungstyp # S = Buchungstyp
# 1 = Transaction batch (Buchungsstapel), # 1 = Transaction batch (Buchungsstapel),
# 2 = Annual financial statement (Jahresabschluss) # 2 = Annual financial statement (Jahresabschluss)
"1", "1" if csv_class.DATA_CATEGORY == DataCategory.TRANSACTIONS else "",
# T = Rechnungslegungszweck # T = Rechnungslegungszweck
"", "",
# U = Festschreibung # U = Festschreibung
@ -241,185 +335,8 @@ def get_datev_csv(data, filters):
# V = Kontoführungs-Währungskennzeichen des Geldkontos # V = Kontoführungs-Währungskennzeichen des Geldkontos
frappe.get_value("Company", filters.get("company"), "default_currency") frappe.get_value("Company", filters.get("company"), "default_currency")
] ]
columns = [ return header
# 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"
]
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() @frappe.whitelist()
def download_datev_csv(filters=None): def download_datev_csv(filters=None):
@ -438,8 +355,31 @@ def download_datev_csv(filters=None):
filters = json.loads(filters) filters = json.loads(filters)
validate(filters) validate(filters)
data = get_gl_entries(filters, as_dict=1)
frappe.response['result'] = get_datev_csv(data, filters) # This is where my zip will be written
frappe.response['doctype'] = 'EXTF_Buchungsstapel' zip_buffer = BytesIO()
frappe.response['type'] = 'csv' # 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'

View File

@ -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

View File

@ -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))

View File

@ -52,7 +52,7 @@ frappe.query_reports["GSTR-1"] = {
], ],
onload: function (report) { 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(); var filters = report.get_values();
const args = { const args = {

View File

@ -204,6 +204,40 @@ class Customer(TransactionBase):
else: else:
frappe.msgprint(_("Multiple Loyalty Program found for the Customer. Please select manually.")) 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() @frappe.whitelist()
def get_loyalty_programs(doc): def get_loyalty_programs(doc):
''' returns applicable loyalty programs for a customer ''' ''' returns applicable loyalty programs for a customer '''

View File

@ -834,6 +834,10 @@ def make_purchase_order(source_name, for_supplier=None, selected_items=[], targe
for item in sales_order.items: for item in sales_order.items:
if item.supplier and item.supplier not in suppliers: if item.supplier and item.supplier not in suppliers:
suppliers.append(item.supplier) 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: for supplier in suppliers:
po =frappe.get_list("Purchase Order", filters={"sales_order":source_name, "supplier":supplier, "docstatus": ("<", "2")}) po =frappe.get_list("Purchase Order", filters={"sales_order":source_name, "supplier":supplier, "docstatus": ("<", "2")})
if len(po) == 0: if len(po) == 0:

View File

@ -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": ""
}

View File

@ -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() {
}
});

View File

@ -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
}

View File

@ -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()

View File

@ -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()
]);
});

View File

@ -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

View File

@ -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
}

View File

@ -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

View File

@ -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!<br>\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"
}

View File

@ -66,6 +66,7 @@ def place_order():
from erpnext.selling.doctype.quotation.quotation import _make_sales_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 = 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): if not cint(cart_settings.allow_items_not_in_stock):
for item in sales_order.get("items"): for item in sales_order.get("items"):

View File

@ -136,6 +136,20 @@ frappe.ui.form.on("Item", {
frm.toggle_reqd('customer', frm.doc.is_customer_provided_item ? 1:0); 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) { is_fixed_asset: function(frm) {
// set serial no to false & toggles its visibility // set serial no to false & toggles its visibility
frm.set_value('has_serial_no', 0); frm.set_value('has_serial_no', 0);

View File

@ -884,6 +884,54 @@ class Item(WebsiteGenerator):
if not enabled: 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") 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): def get_timeline_data(doctype, name):
'''returns timeline data based on stock ledger entry''' '''returns timeline data based on stock ledger entry'''
out = {} out = {}

View File

@ -34,6 +34,12 @@ frappe.ui.form.on("Purchase Receipt", {
filters: {'company': frm.doc.company } filters: {'company': frm.doc.company }
} }
}); });
frm.set_query("taxes_and_charges", function() {
return {
filters: {'company': frm.doc.company }
}
});
}, },
onload: function(frm) { onload: function(frm) {
@ -296,4 +302,4 @@ var validate_sample_quantity = function(frm, cdt, cdn) {
} }
}); });
} }
}; };

View File

@ -16,7 +16,7 @@ frappe.ui.form.on('Quick Stock Balance', {
frm.add_custom_button(__('Stock Balance Report'), () => { frm.add_custom_button(__('Stock Balance Report'), () => {
frappe.set_route('query-report', 'Stock Balance', frappe.set_route('query-report', 'Stock Balance',
{ 'item_code': frm.doc.item, 'warehouse': frm.doc.warehouse }); { 'item_code': frm.doc.item, 'warehouse': frm.doc.warehouse });
}).addClass("btn-primary"); });
} }
}, },

View File

@ -1,874 +1,299 @@
{ {
"allow_copy": 1, "allow_copy": 1,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"autoname": "MAT-SLE-.YYYY.-.#####", "autoname": "MAT-SLE-.YYYY.-.#####",
"beta": 0,
"creation": "2013-01-29 19:25:42", "creation": "2013-01-29 19:25:42",
"custom": 0,
"docstatus": 0,
"doctype": "DocType", "doctype": "DocType",
"document_type": "Other", "document_type": "Other",
"editable_grid": 0,
"engine": "InnoDB", "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": [ "fields": [
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "item_code", "fieldname": "item_code",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 1, "in_filter": 1,
"in_global_search": 0,
"in_list_view": 1, "in_list_view": 1,
"in_standard_filter": 1, "in_standard_filter": 1,
"label": "Item Code", "label": "Item Code",
"length": 0,
"no_copy": 0,
"oldfieldname": "item_code", "oldfieldname": "item_code",
"oldfieldtype": "Link", "oldfieldtype": "Link",
"options": "Item", "options": "Item",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"print_width": "100px", "print_width": "100px",
"read_only": 1, "read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 1, "search_index": 1,
"set_only_once": 0,
"translatable": 0,
"unique": 0,
"width": "100px" "width": "100px"
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "serial_no", "fieldname": "serial_no",
"fieldtype": "Text", "fieldtype": "Long Text",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1, "in_list_view": 1,
"in_standard_filter": 0,
"label": "Serial No", "label": "Serial No",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"print_width": "100px", "print_width": "100px",
"read_only": 1, "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" "width": "100px"
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "batch_no", "fieldname": "batch_no",
"fieldtype": "Data", "fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1, "in_list_view": 1,
"in_standard_filter": 0,
"label": "Batch No", "label": "Batch No",
"length": 0,
"no_copy": 0,
"oldfieldname": "batch_no", "oldfieldname": "batch_no",
"oldfieldtype": "Data", "oldfieldtype": "Data",
"permlevel": 0, "read_only": 1
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "warehouse", "fieldname": "warehouse",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 1, "in_filter": 1,
"in_global_search": 0,
"in_list_view": 1, "in_list_view": 1,
"in_standard_filter": 1, "in_standard_filter": 1,
"label": "Warehouse", "label": "Warehouse",
"length": 0,
"no_copy": 0,
"oldfieldname": "warehouse", "oldfieldname": "warehouse",
"oldfieldtype": "Link", "oldfieldtype": "Link",
"options": "Warehouse", "options": "Warehouse",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"print_width": "100px", "print_width": "100px",
"read_only": 1, "read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 1, "search_index": 1,
"set_only_once": 0,
"translatable": 0,
"unique": 0,
"width": "100px" "width": "100px"
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "posting_date", "fieldname": "posting_date",
"fieldtype": "Date", "fieldtype": "Date",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 1, "in_filter": 1,
"in_global_search": 0,
"in_list_view": 1, "in_list_view": 1,
"in_standard_filter": 0,
"label": "Posting Date", "label": "Posting Date",
"length": 0,
"no_copy": 0,
"oldfieldname": "posting_date", "oldfieldname": "posting_date",
"oldfieldtype": "Date", "oldfieldtype": "Date",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"print_width": "100px", "print_width": "100px",
"read_only": 1, "read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 1, "search_index": 1,
"set_only_once": 0,
"translatable": 0,
"unique": 0,
"width": "100px" "width": "100px"
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "posting_time", "fieldname": "posting_time",
"fieldtype": "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", "label": "Posting Time",
"length": 0,
"no_copy": 0,
"oldfieldname": "posting_time", "oldfieldname": "posting_time",
"oldfieldtype": "Time", "oldfieldtype": "Time",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"print_width": "100px", "print_width": "100px",
"read_only": 1, "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" "width": "100px"
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "voucher_type", "fieldname": "voucher_type",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 1, "in_filter": 1,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Voucher Type", "label": "Voucher Type",
"length": 0,
"no_copy": 0,
"oldfieldname": "voucher_type", "oldfieldname": "voucher_type",
"oldfieldtype": "Data", "oldfieldtype": "Data",
"options": "DocType", "options": "DocType",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"print_width": "150px", "print_width": "150px",
"read_only": 1, "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" "width": "150px"
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "voucher_no", "fieldname": "voucher_no",
"fieldtype": "Dynamic Link", "fieldtype": "Dynamic Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 1, "in_filter": 1,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 1, "in_standard_filter": 1,
"label": "Voucher No", "label": "Voucher No",
"length": 0,
"no_copy": 0,
"oldfieldname": "voucher_no", "oldfieldname": "voucher_no",
"oldfieldtype": "Data", "oldfieldtype": "Data",
"options": "voucher_type", "options": "voucher_type",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"print_width": "150px", "print_width": "150px",
"read_only": 1, "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" "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", "fieldname": "voucher_detail_no",
"fieldtype": "Data", "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", "label": "Voucher Detail No",
"length": 0,
"no_copy": 0,
"oldfieldname": "voucher_detail_no", "oldfieldname": "voucher_detail_no",
"oldfieldtype": "Data", "oldfieldtype": "Data",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"print_width": "150px", "print_width": "150px",
"read_only": 1, "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" "width": "150px"
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "actual_qty", "fieldname": "actual_qty",
"fieldtype": "Float", "fieldtype": "Float",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 1, "in_filter": 1,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Actual Quantity", "label": "Actual Quantity",
"length": 0,
"no_copy": 0,
"oldfieldname": "actual_qty", "oldfieldname": "actual_qty",
"oldfieldtype": "Currency", "oldfieldtype": "Currency",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"print_width": "150px", "print_width": "150px",
"read_only": 1, "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" "width": "150px"
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "incoming_rate", "fieldname": "incoming_rate",
"fieldtype": "Currency", "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", "label": "Incoming Rate",
"length": 0,
"no_copy": 0,
"oldfieldname": "incoming_rate", "oldfieldname": "incoming_rate",
"oldfieldtype": "Currency", "oldfieldtype": "Currency",
"options": "Company:company:default_currency", "options": "Company:company:default_currency",
"permlevel": 0, "read_only": 1
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "outgoing_rate", "fieldname": "outgoing_rate",
"fieldtype": "Currency", "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", "label": "Outgoing Rate",
"length": 0,
"no_copy": 0,
"options": "Company:company:default_currency", "options": "Company:company:default_currency",
"permlevel": 0, "read_only": 1
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "stock_uom", "fieldname": "stock_uom",
"fieldtype": "Link", "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", "label": "Stock UOM",
"length": 0,
"no_copy": 0,
"oldfieldname": "stock_uom", "oldfieldname": "stock_uom",
"oldfieldtype": "Data", "oldfieldtype": "Data",
"options": "UOM", "options": "UOM",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"print_width": "150px", "print_width": "150px",
"read_only": 1, "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" "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", "fieldname": "qty_after_transaction",
"fieldtype": "Float", "fieldtype": "Float",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 1, "in_filter": 1,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Actual Qty After Transaction", "label": "Actual Qty After Transaction",
"length": 0,
"no_copy": 0,
"oldfieldname": "bin_aqat", "oldfieldname": "bin_aqat",
"oldfieldtype": "Currency", "oldfieldtype": "Currency",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"print_width": "150px", "print_width": "150px",
"read_only": 1, "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" "width": "150px"
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "valuation_rate", "fieldname": "valuation_rate",
"fieldtype": "Currency", "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", "label": "Valuation Rate",
"length": 0,
"no_copy": 0,
"oldfieldname": "valuation_rate", "oldfieldname": "valuation_rate",
"oldfieldtype": "Currency", "oldfieldtype": "Currency",
"options": "Company:company:default_currency", "options": "Company:company:default_currency",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"print_width": "150px", "print_width": "150px",
"read_only": 1, "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" "width": "150px"
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "stock_value", "fieldname": "stock_value",
"fieldtype": "Currency", "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", "label": "Stock Value",
"length": 0,
"no_copy": 0,
"oldfieldname": "stock_value", "oldfieldname": "stock_value",
"oldfieldtype": "Currency", "oldfieldtype": "Currency",
"options": "Company:company:default_currency", "options": "Company:company:default_currency",
"permlevel": 0, "read_only": 1
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "stock_value_difference", "fieldname": "stock_value_difference",
"fieldtype": "Currency", "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", "label": "Stock Value Difference",
"length": 0,
"no_copy": 0,
"options": "Company:company:default_currency", "options": "Company:company:default_currency",
"permlevel": 0, "read_only": 1
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "stock_queue", "fieldname": "stock_queue",
"fieldtype": "Text", "fieldtype": "Text",
"hidden": 1, "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)", "label": "Stock Queue (FIFO)",
"length": 0,
"no_copy": 0,
"oldfieldname": "fcfs_stack", "oldfieldname": "fcfs_stack",
"oldfieldtype": "Text", "oldfieldtype": "Text",
"permlevel": 0,
"print_hide": 1, "print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 1, "read_only": 1,
"remember_last_selected_value": 0, "report_hide": 1
"report_hide": 1,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "project", "fieldname": "project",
"fieldtype": "Link", "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", "label": "Project",
"length": 0, "options": "Project"
"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
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "company", "fieldname": "company",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 1, "in_filter": 1,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Company", "label": "Company",
"length": 0,
"no_copy": 0,
"oldfieldname": "company", "oldfieldname": "company",
"oldfieldtype": "Data", "oldfieldtype": "Data",
"options": "Company", "options": "Company",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"print_width": "150px", "print_width": "150px",
"read_only": 1, "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" "width": "150px"
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "fiscal_year", "fieldname": "fiscal_year",
"fieldtype": "Data", "fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 1, "in_filter": 1,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Fiscal Year", "label": "Fiscal Year",
"length": 0,
"no_copy": 0,
"oldfieldname": "fiscal_year", "oldfieldname": "fiscal_year",
"oldfieldtype": "Data", "oldfieldtype": "Data",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"print_width": "150px", "print_width": "150px",
"read_only": 1, "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" "width": "150px"
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "is_cancelled", "fieldname": "is_cancelled",
"fieldtype": "Select", "fieldtype": "Select",
"hidden": 1, "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", "label": "Is Cancelled",
"length": 0,
"no_copy": 0,
"options": "\nNo\nYes", "options": "\nNo\nYes",
"permlevel": 0, "report_hide": 1
"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
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "1", "default": "1",
"fieldname": "to_rename", "fieldname": "to_rename",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 1, "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", "label": "To Rename",
"length": 0, "search_index": 1
"no_copy": 0,
"permlevel": 0,
"precision": "",
"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
} }
], ],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 1, "hide_toolbar": 1,
"icon": "fa fa-list", "icon": "fa fa-list",
"idx": 1, "idx": 1,
"image_view": 0,
"in_create": 1, "in_create": 1,
"is_submittable": 0, "modified": "2019-11-27 12:17:31.522675",
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2019-01-07 07:04:37.523024",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Stock", "module": "Stock",
"name": "Stock Ledger Entry", "name": "Stock Ledger Entry",
"owner": "Administrator", "owner": "Administrator",
"permissions": [ "permissions": [
{ {
"amend": 0,
"cancel": 0,
"create": 0,
"delete": 0,
"email": 0,
"export": 1, "export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1, "print": 1,
"read": 1, "read": 1,
"report": 1, "report": 1,
"role": "Stock User", "role": "Stock User"
"set_user_permissions": 0,
"share": 0,
"submit": 0,
"write": 0
}, },
{ {
"amend": 0,
"cancel": 0,
"create": 0,
"delete": 0,
"email": 0,
"export": 1, "export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 0,
"read": 1, "read": 1,
"report": 1, "report": 1,
"role": "Accounts Manager", "role": "Accounts Manager"
"set_user_permissions": 0,
"share": 0,
"submit": 0,
"write": 0
} }
], ],
"quick_entry": 0,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 0,
"sort_field": "modified", "sort_field": "modified",
"sort_order": "DESC", "sort_order": "DESC"
"track_changes": 0,
"track_seen": 0,
"track_views": 0
} }

View File

@ -254,6 +254,12 @@ def get_basic_details(args, item, overwrite_warehouse=True):
args['material_request_type'] = frappe.db.get_value('Material Request', args['material_request_type'] = frappe.db.get_value('Material Request',
args.get('name'), 'material_request_type', cache=True) 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 #Set the UOM to the Default Sales UOM or Default Purchase UOM if configured in the Item Master
if not args.uom: if not args.uom:
if args.get('doctype') in sales_doctypes: 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(), "image": cstr(item.image).strip(),
"warehouse": warehouse, "warehouse": warehouse,
"income_account": get_default_income_account(args, item_defaults, item_group_defaults, brand_defaults), "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), "cost_center": get_default_cost_center(args, item_defaults, item_group_defaults, brand_defaults),
'has_serial_no': item.has_serial_no, 'has_serial_no': item.has_serial_no,
'has_batch_no': item.has_batch_no, 'has_batch_no': item.has_batch_no,

View File

@ -15,7 +15,7 @@
"prepared_report": 0, "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`", "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", "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", "report_type": "Query Report",
"roles": [ "roles": [
{ {

View File

@ -122,8 +122,8 @@ def get_item_details(items, sl_entries, include_uom):
cf_field = cf_join = "" cf_field = cf_join = ""
if include_uom: if include_uom:
cf_field = ", ucd.conversion_factor" cf_field = ", ucd.conversion_factor"
cf_join = "left join `tabUOM Conversion Detail` ucd on ucd.parent=item.name and ucd.uom='%s'" \ cf_join = "left join `tabUOM Conversion Detail` ucd on ucd.parent=item.name and ucd.uom=%s" \
% (include_uom) % frappe.db.escape(include_uom)
res = frappe.db.sql(""" res = frappe.db.sql("""
select select

View File

@ -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": ""
}

View File

@ -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

View File

@ -1,240 +0,0 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
import frappe, erpnext
import json
from frappe import _
from frappe.utils import flt
from erpnext.setup.doctype.setup_progress.setup_progress import update_domain_actions, get_domain_actions_state
@frappe.whitelist()
def set_sales_target(args_data):
args = json.loads(args_data)
defaults = frappe.defaults.get_defaults()
frappe.db.set_value("Company", defaults.get("company"), "monthly_sales_target", args.get('monthly_sales_target'))
@frappe.whitelist()
def create_customers(args_data):
args = json.loads(args_data)
defaults = frappe.defaults.get_defaults()
for i in range(1,4):
customer = args.get("customer_" + str(i))
if customer:
try:
doc = frappe.get_doc({
"doctype":"Customer",
"customer_name": customer,
"customer_type": "Company",
"customer_group": _("Commercial"),
"territory": defaults.get("country"),
"company": defaults.get("company")
}).insert()
if args.get("customer_contact_" + str(i)):
create_contact(args.get("customer_contact_" + str(i)),
"Customer", doc.name)
except frappe.NameError:
pass
@frappe.whitelist()
def create_letterhead(args_data):
args = json.loads(args_data)
letterhead = args.get("letterhead")
if letterhead:
try:
frappe.get_doc({
"doctype":"Letter Head",
"content":"""<div><img src="{0}" style='max-width: 100%%;'><br></div>""".format(letterhead.encode('utf-8')),
"letter_head_name": _("Standard"),
"is_default": 1
}).insert()
except frappe.NameError:
pass
@frappe.whitelist()
def create_suppliers(args_data):
args = json.loads(args_data)
defaults = frappe.defaults.get_defaults()
for i in range(1,4):
supplier = args.get("supplier_" + str(i))
if supplier:
try:
doc = frappe.get_doc({
"doctype":"Supplier",
"supplier_name": supplier,
"supplier_group": _("Local"),
"company": defaults.get("company")
}).insert()
if args.get("supplier_contact_" + str(i)):
create_contact(args.get("supplier_contact_" + str(i)),
"Supplier", doc.name)
except frappe.NameError:
pass
def create_contact(contact, party_type, party):
"""Create contact based on given contact name"""
contact = contact .split(" ")
contact = frappe.get_doc({
"doctype":"Contact",
"first_name":contact[0],
"last_name": len(contact) > 1 and contact[1] or ""
})
contact.append('links', dict(link_doctype=party_type, link_name=party))
contact.insert()
@frappe.whitelist()
def create_items(args_data):
args = json.loads(args_data)
defaults = frappe.defaults.get_defaults()
for i in range(1,4):
item = args.get("item_" + str(i))
if item:
default_warehouse = ""
default_warehouse = frappe.db.get_value("Warehouse", filters={
"warehouse_name": _("Finished Goods"),
"company": defaults.get("company_name")
})
try:
frappe.get_doc({
"doctype":"Item",
"item_code": item,
"item_name": item,
"description": item,
"show_in_website": 1,
"is_sales_item": 1,
"is_purchase_item": 1,
"is_stock_item": 1,
"item_group": _("Products"),
"stock_uom": _(args.get("item_uom_" + str(i))),
"item_defaults": [{
"default_warehouse": default_warehouse,
"company": defaults.get("company_name")
}]
}).insert()
except frappe.NameError:
pass
else:
if args.get("item_price_" + str(i)):
item_price = flt(args.get("item_price_" + str(i)))
price_list_name = frappe.db.get_value("Price List", {"selling": 1})
make_item_price(item, price_list_name, item_price)
price_list_name = frappe.db.get_value("Price List", {"buying": 1})
make_item_price(item, price_list_name, item_price)
def make_item_price(item, price_list_name, item_price):
frappe.get_doc({
"doctype": "Item Price",
"price_list": price_list_name,
"item_code": item,
"price_list_rate": item_price
}).insert()
# Education
@frappe.whitelist()
def create_program(args_data):
args = json.loads(args_data)
for i in range(1,4):
if args.get("program_" + str(i)):
program = frappe.new_doc("Program")
program.program_code = args.get("program_" + str(i))
program.program_name = args.get("program_" + str(i))
try:
program.save()
except frappe.DuplicateEntryError:
pass
@frappe.whitelist()
def create_course(args_data):
args = json.loads(args_data)
for i in range(1,4):
if args.get("course_" + str(i)):
course = frappe.new_doc("Course")
course.course_code = args.get("course_" + str(i))
course.course_name = args.get("course_" + str(i))
try:
course.save()
except frappe.DuplicateEntryError:
pass
@frappe.whitelist()
def create_instructor(args_data):
args = json.loads(args_data)
for i in range(1,4):
if args.get("instructor_" + str(i)):
instructor = frappe.new_doc("Instructor")
instructor.instructor_name = args.get("instructor_" + str(i))
try:
instructor.save()
except frappe.DuplicateEntryError:
pass
@frappe.whitelist()
def create_room(args_data):
args = json.loads(args_data)
for i in range(1,4):
if args.get("room_" + str(i)):
room = frappe.new_doc("Room")
room.room_name = args.get("room_" + str(i))
room.seating_capacity = args.get("room_capacity_" + str(i))
try:
room.save()
except frappe.DuplicateEntryError:
pass
@frappe.whitelist()
def create_users(args_data):
if frappe.session.user == 'Administrator':
return
args = json.loads(args_data)
defaults = frappe.defaults.get_defaults()
for i in range(1,4):
email = args.get("user_email_" + str(i))
fullname = args.get("user_fullname_" + str(i))
if email:
if not fullname:
fullname = email.split("@")[0]
parts = fullname.split(" ", 1)
user = frappe.get_doc({
"doctype": "User",
"email": email,
"first_name": parts[0],
"last_name": parts[1] if len(parts) > 1 else "",
"enabled": 1,
"user_type": "System User"
})
# default roles
user.append_roles("Projects User", "Stock User", "Support Team")
user.flags.delay_emails = True
if not frappe.db.get_value("User", email):
user.insert(ignore_permissions=True)
# create employee
emp = frappe.get_doc({
"doctype": "Employee",
"employee_name": fullname,
"user_id": email,
"status": "Active",
"company": defaults.get("company")
})
emp.flags.ignore_mandatory = True
emp.insert(ignore_permissions = True)
# Ennumerate the setup hooks you're going to need, apart from the slides
@frappe.whitelist()
def update_default_domain_actions_and_get_state():
domain = frappe.get_cached_value('Company', erpnext.get_default_company(), 'domain')
update_domain_actions(domain)
return get_domain_actions_state(domain)

View File

@ -1,10 +1,10 @@
braintree==3.57.1
frappe frappe
unidecode gocardless-pro==1.11.0
pygithub googlemaps==3.1.1
googlemaps pandas==0.24.2
python-stdnum plaid-python==3.4.0
braintree PyGithub==1.44.1
gocardless_pro python-stdnum==1.12
woocommerce Unidecode==1.1.1
pandas WooCommerce==2.1.1
plaid-python